• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* Copyright 2014 The BoringSSL Authors
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/aead.h>
16
17#include <assert.h>
18#include <string.h>
19
20#include <openssl/cipher.h>
21#include <openssl/err.h>
22#include <openssl/mem.h>
23
24#include "../../internal.h"
25#include "internal.h"
26
27
28size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; }
29
30size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; }
31
32size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; }
33
34size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; }
35
36void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) {
37  OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX));
38}
39
40EVP_AEAD_CTX *EVP_AEAD_CTX_new(const EVP_AEAD *aead, const uint8_t *key,
41                               size_t key_len, size_t tag_len) {
42  EVP_AEAD_CTX *ctx =
43      reinterpret_cast<EVP_AEAD_CTX *>(OPENSSL_malloc(sizeof(EVP_AEAD_CTX)));
44  if (!ctx) {
45    return NULL;
46  }
47  EVP_AEAD_CTX_zero(ctx);
48
49  if (EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, NULL)) {
50    return ctx;
51  }
52
53  EVP_AEAD_CTX_free(ctx);
54  return NULL;
55}
56
57void EVP_AEAD_CTX_free(EVP_AEAD_CTX *ctx) {
58  if (ctx == NULL) {
59    return;
60  }
61  EVP_AEAD_CTX_cleanup(ctx);
62  OPENSSL_free(ctx);
63}
64
65int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
66                      const uint8_t *key, size_t key_len, size_t tag_len,
67                      ENGINE *impl) {
68  if (!aead->init) {
69    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET);
70    ctx->aead = NULL;
71    return 0;
72  }
73  return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len,
74                                          evp_aead_open);
75}
76
77int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
78                                     const uint8_t *key, size_t key_len,
79                                     size_t tag_len,
80                                     enum evp_aead_direction_t dir) {
81  if (key_len != aead->key_len) {
82    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE);
83    ctx->aead = NULL;
84    return 0;
85  }
86
87  ctx->aead = aead;
88
89  int ok;
90  if (aead->init) {
91    ok = aead->init(ctx, key, key_len, tag_len);
92  } else {
93    ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir);
94  }
95
96  if (!ok) {
97    ctx->aead = NULL;
98  }
99
100  return ok;
101}
102
103void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) {
104  if (ctx->aead == NULL) {
105    return;
106  }
107  ctx->aead->cleanup(ctx);
108  ctx->aead = NULL;
109}
110
111// check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If
112// |in| and |out| alias, we require that |in| == |out|.
113static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out,
114                       size_t out_len) {
115  if (!buffers_alias(in, in_len, out, out_len)) {
116    return 1;
117  }
118
119  return in == out;
120}
121
122int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
123                      size_t max_out_len, const uint8_t *nonce,
124                      size_t nonce_len, const uint8_t *in, size_t in_len,
125                      const uint8_t *ad, size_t ad_len) {
126  if (in_len + ctx->aead->overhead < in_len /* overflow */) {
127    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
128    goto error;
129  }
130
131  if (max_out_len < in_len) {
132    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
133    goto error;
134  }
135
136  if (!check_alias(in, in_len, out, max_out_len)) {
137    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
138    goto error;
139  }
140
141  size_t out_tag_len;
142  if (ctx->aead->seal_scatter(ctx, out, out + in_len, &out_tag_len,
143                              max_out_len - in_len, nonce, nonce_len, in,
144                              in_len, NULL, 0, ad, ad_len)) {
145    *out_len = in_len + out_tag_len;
146    return 1;
147  }
148
149error:
150  // In the event of an error, clear the output buffer so that a caller
151  // that doesn't check the return value doesn't send raw data.
152  OPENSSL_memset(out, 0, max_out_len);
153  *out_len = 0;
154  return 0;
155}
156
157int EVP_AEAD_CTX_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
158                              uint8_t *out_tag, size_t *out_tag_len,
159                              size_t max_out_tag_len, const uint8_t *nonce,
160                              size_t nonce_len, const uint8_t *in,
161                              size_t in_len, const uint8_t *extra_in,
162                              size_t extra_in_len, const uint8_t *ad,
163                              size_t ad_len) {
164  // |in| and |out| may alias exactly, |out_tag| may not alias.
165  if (!check_alias(in, in_len, out, in_len) ||
166      buffers_alias(out, in_len, out_tag, max_out_tag_len) ||
167      buffers_alias(in, in_len, out_tag, max_out_tag_len)) {
168    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
169    goto error;
170  }
171
172  if (!ctx->aead->seal_scatter_supports_extra_in && extra_in_len) {
173    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION);
174    goto error;
175  }
176
177  if (ctx->aead->seal_scatter(ctx, out, out_tag, out_tag_len, max_out_tag_len,
178                              nonce, nonce_len, in, in_len, extra_in,
179                              extra_in_len, ad, ad_len)) {
180    return 1;
181  }
182
183error:
184  // In the event of an error, clear the output buffer so that a caller
185  // that doesn't check the return value doesn't send raw data.
186  OPENSSL_memset(out, 0, in_len);
187  OPENSSL_memset(out_tag, 0, max_out_tag_len);
188  *out_tag_len = 0;
189  return 0;
190}
191
192int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
193                      size_t max_out_len, const uint8_t *nonce,
194                      size_t nonce_len, const uint8_t *in, size_t in_len,
195                      const uint8_t *ad, size_t ad_len) {
196  size_t plaintext_len;
197  if (!check_alias(in, in_len, out, max_out_len)) {
198    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
199    goto error;
200  }
201
202  if (ctx->aead->open) {
203    if (!ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in,
204                         in_len, ad, ad_len)) {
205      goto error;
206    }
207    return 1;
208  }
209
210  // AEADs that use the default implementation of open() must set |tag_len| at
211  // initialization time.
212  assert(ctx->tag_len);
213
214  if (in_len < ctx->tag_len) {
215    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
216    goto error;
217  }
218
219  plaintext_len = in_len - ctx->tag_len;
220  if (max_out_len < plaintext_len) {
221    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
222    goto error;
223  }
224  if (EVP_AEAD_CTX_open_gather(ctx, out, nonce, nonce_len, in, plaintext_len,
225                               in + plaintext_len, ctx->tag_len, ad, ad_len)) {
226    *out_len = plaintext_len;
227    return 1;
228  }
229
230error:
231  // In the event of an error, clear the output buffer so that a caller
232  // that doesn't check the return value doesn't try and process bad
233  // data.
234  OPENSSL_memset(out, 0, max_out_len);
235  *out_len = 0;
236  return 0;
237}
238
239int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
240                             const uint8_t *nonce, size_t nonce_len,
241                             const uint8_t *in, size_t in_len,
242                             const uint8_t *in_tag, size_t in_tag_len,
243                             const uint8_t *ad, size_t ad_len) {
244  if (!check_alias(in, in_len, out, in_len)) {
245    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
246    goto error;
247  }
248
249  if (!ctx->aead->open_gather) {
250    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
251    goto error;
252  }
253
254  if (ctx->aead->open_gather(ctx, out, nonce, nonce_len, in, in_len, in_tag,
255                             in_tag_len, ad, ad_len)) {
256    return 1;
257  }
258
259error:
260  // In the event of an error, clear the output buffer so that a caller
261  // that doesn't check the return value doesn't try and process bad
262  // data.
263  OPENSSL_memset(out, 0, in_len);
264  return 0;
265}
266
267const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; }
268
269int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
270                        size_t *out_len) {
271  if (ctx->aead->get_iv == NULL) {
272    OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
273    return 0;
274  }
275
276  return ctx->aead->get_iv(ctx, out_iv, out_len);
277}
278
279int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len,
280                         const size_t in_len, const size_t extra_in_len) {
281  assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len);
282
283  if (ctx->aead->tag_len) {
284    *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len);
285    return 1;
286  }
287
288  if (extra_in_len + ctx->tag_len < extra_in_len) {
289    OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
290    *out_tag_len = 0;
291    return 0;
292  }
293  *out_tag_len = extra_in_len + ctx->tag_len;
294  return 1;
295}
296