/src/boringssl/crypto/fipsmodule/cipher/aead.c.inc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2014, Google Inc. |
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 | | |
28 | 102 | size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } |
29 | | |
30 | 184 | size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; } |
31 | | |
32 | 102 | size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } |
33 | | |
34 | 102 | size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } |
35 | | |
36 | 1.09k | void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) { |
37 | 1.09k | OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX)); |
38 | 1.09k | } |
39 | | |
40 | | EVP_AEAD_CTX *EVP_AEAD_CTX_new(const EVP_AEAD *aead, const uint8_t *key, |
41 | 1.09k | size_t key_len, size_t tag_len) { |
42 | 1.09k | EVP_AEAD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_AEAD_CTX)); |
43 | 1.09k | EVP_AEAD_CTX_zero(ctx); |
44 | | |
45 | 1.09k | if (EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, NULL)) { |
46 | 929 | return ctx; |
47 | 929 | } |
48 | | |
49 | 164 | EVP_AEAD_CTX_free(ctx); |
50 | 164 | return NULL; |
51 | 1.09k | } |
52 | | |
53 | 1.25k | void EVP_AEAD_CTX_free(EVP_AEAD_CTX *ctx) { |
54 | 1.25k | if (ctx == NULL) { |
55 | 164 | return; |
56 | 164 | } |
57 | 1.09k | EVP_AEAD_CTX_cleanup(ctx); |
58 | 1.09k | OPENSSL_free(ctx); |
59 | 1.09k | } |
60 | | |
61 | | int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, |
62 | | const uint8_t *key, size_t key_len, size_t tag_len, |
63 | 1.09k | ENGINE *impl) { |
64 | 1.09k | if (!aead->init) { |
65 | 16 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET); |
66 | 16 | ctx->aead = NULL; |
67 | 16 | return 0; |
68 | 16 | } |
69 | 1.07k | return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len, |
70 | 1.07k | evp_aead_open); |
71 | 1.09k | } |
72 | | |
73 | | int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, |
74 | | const uint8_t *key, size_t key_len, |
75 | | size_t tag_len, |
76 | 1.07k | enum evp_aead_direction_t dir) { |
77 | 1.07k | if (key_len != aead->key_len) { |
78 | 41 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE); |
79 | 41 | ctx->aead = NULL; |
80 | 41 | return 0; |
81 | 41 | } |
82 | | |
83 | 1.03k | ctx->aead = aead; |
84 | | |
85 | 1.03k | int ok; |
86 | 1.03k | if (aead->init) { |
87 | 1.03k | ok = aead->init(ctx, key, key_len, tag_len); |
88 | 1.03k | } else { |
89 | 0 | ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir); |
90 | 0 | } |
91 | | |
92 | 1.03k | if (!ok) { |
93 | 107 | ctx->aead = NULL; |
94 | 107 | } |
95 | | |
96 | 1.03k | return ok; |
97 | 1.07k | } |
98 | | |
99 | 1.09k | void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { |
100 | 1.09k | if (ctx->aead == NULL) { |
101 | 164 | return; |
102 | 164 | } |
103 | 929 | ctx->aead->cleanup(ctx); |
104 | 929 | ctx->aead = NULL; |
105 | 929 | } |
106 | | |
107 | | // check_alias returns 1 if |out| is compatible with |in| and 0 otherwise. If |
108 | | // |in| and |out| alias, we require that |in| == |out|. |
109 | | static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out, |
110 | 1.39k | size_t out_len) { |
111 | 1.39k | if (!buffers_alias(in, in_len, out, out_len)) { |
112 | 1.39k | return 1; |
113 | 1.39k | } |
114 | | |
115 | 0 | return in == out; |
116 | 1.39k | } |
117 | | |
118 | | int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, |
119 | | size_t max_out_len, const uint8_t *nonce, |
120 | | size_t nonce_len, const uint8_t *in, size_t in_len, |
121 | 456 | const uint8_t *ad, size_t ad_len) { |
122 | 456 | if (in_len + ctx->aead->overhead < in_len /* overflow */) { |
123 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); |
124 | 0 | goto error; |
125 | 0 | } |
126 | | |
127 | 456 | if (max_out_len < in_len) { |
128 | 3 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); |
129 | 3 | goto error; |
130 | 3 | } |
131 | | |
132 | 453 | if (!check_alias(in, in_len, out, max_out_len)) { |
133 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
134 | 0 | goto error; |
135 | 0 | } |
136 | | |
137 | 453 | size_t out_tag_len; |
138 | 453 | if (ctx->aead->seal_scatter(ctx, out, out + in_len, &out_tag_len, |
139 | 453 | max_out_len - in_len, nonce, nonce_len, in, |
140 | 453 | in_len, NULL, 0, ad, ad_len)) { |
141 | 371 | *out_len = in_len + out_tag_len; |
142 | 371 | return 1; |
143 | 371 | } |
144 | | |
145 | 85 | error: |
146 | | // In the event of an error, clear the output buffer so that a caller |
147 | | // that doesn't check the return value doesn't send raw data. |
148 | 85 | OPENSSL_memset(out, 0, max_out_len); |
149 | 85 | *out_len = 0; |
150 | 85 | return 0; |
151 | 453 | } |
152 | | |
153 | | int EVP_AEAD_CTX_seal_scatter( |
154 | | const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag, size_t |
155 | | *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce, size_t |
156 | | nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in, |
157 | 0 | size_t extra_in_len, const uint8_t *ad, size_t ad_len) { |
158 | | // |in| and |out| may alias exactly, |out_tag| may not alias. |
159 | 0 | if (!check_alias(in, in_len, out, in_len) || |
160 | 0 | buffers_alias(out, in_len, out_tag, max_out_tag_len) || |
161 | 0 | buffers_alias(in, in_len, out_tag, max_out_tag_len)) { |
162 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
163 | 0 | goto error; |
164 | 0 | } |
165 | | |
166 | 0 | if (!ctx->aead->seal_scatter_supports_extra_in && extra_in_len) { |
167 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); |
168 | 0 | goto error; |
169 | 0 | } |
170 | | |
171 | 0 | if (ctx->aead->seal_scatter(ctx, out, out_tag, out_tag_len, max_out_tag_len, |
172 | 0 | nonce, nonce_len, in, in_len, extra_in, |
173 | 0 | extra_in_len, ad, ad_len)) { |
174 | 0 | return 1; |
175 | 0 | } |
176 | | |
177 | 0 | error: |
178 | | // In the event of an error, clear the output buffer so that a caller |
179 | | // that doesn't check the return value doesn't send raw data. |
180 | 0 | OPENSSL_memset(out, 0, in_len); |
181 | 0 | OPENSSL_memset(out_tag, 0, max_out_tag_len); |
182 | 0 | *out_tag_len = 0; |
183 | 0 | return 0; |
184 | 0 | } |
185 | | |
186 | | int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, |
187 | | size_t max_out_len, const uint8_t *nonce, |
188 | | size_t nonce_len, const uint8_t *in, size_t in_len, |
189 | 473 | const uint8_t *ad, size_t ad_len) { |
190 | 473 | if (!check_alias(in, in_len, out, max_out_len)) { |
191 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
192 | 0 | goto error; |
193 | 0 | } |
194 | | |
195 | 473 | if (ctx->aead->open) { |
196 | 0 | if (!ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in, |
197 | 0 | in_len, ad, ad_len)) { |
198 | 0 | goto error; |
199 | 0 | } |
200 | 0 | return 1; |
201 | 0 | } |
202 | | |
203 | | // AEADs that use the default implementation of open() must set |tag_len| at |
204 | | // initialization time. |
205 | 473 | assert(ctx->tag_len); |
206 | | |
207 | 473 | if (in_len < ctx->tag_len) { |
208 | 1 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); |
209 | 1 | goto error; |
210 | 1 | } |
211 | | |
212 | 472 | size_t plaintext_len = in_len - ctx->tag_len; |
213 | 472 | if (max_out_len < plaintext_len) { |
214 | 1 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); |
215 | 1 | goto error; |
216 | 1 | } |
217 | 471 | if (EVP_AEAD_CTX_open_gather(ctx, out, nonce, nonce_len, in, plaintext_len, |
218 | 471 | in + plaintext_len, ctx->tag_len, ad, ad_len)) { |
219 | 254 | *out_len = plaintext_len; |
220 | 254 | return 1; |
221 | 254 | } |
222 | | |
223 | 219 | error: |
224 | | // In the event of an error, clear the output buffer so that a caller |
225 | | // that doesn't check the return value doesn't try and process bad |
226 | | // data. |
227 | 219 | OPENSSL_memset(out, 0, max_out_len); |
228 | 219 | *out_len = 0; |
229 | 219 | return 0; |
230 | 471 | } |
231 | | |
232 | | int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out, |
233 | | const uint8_t *nonce, size_t nonce_len, |
234 | | const uint8_t *in, size_t in_len, |
235 | | const uint8_t *in_tag, size_t in_tag_len, |
236 | 471 | const uint8_t *ad, size_t ad_len) { |
237 | 471 | if (!check_alias(in, in_len, out, in_len)) { |
238 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); |
239 | 0 | goto error; |
240 | 0 | } |
241 | | |
242 | 471 | if (!ctx->aead->open_gather) { |
243 | 0 | OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED); |
244 | 0 | goto error; |
245 | 0 | } |
246 | | |
247 | 471 | if (ctx->aead->open_gather(ctx, out, nonce, nonce_len, in, in_len, in_tag, |
248 | 471 | in_tag_len, ad, ad_len)) { |
249 | 254 | return 1; |
250 | 254 | } |
251 | | |
252 | 217 | error: |
253 | | // In the event of an error, clear the output buffer so that a caller |
254 | | // that doesn't check the return value doesn't try and process bad |
255 | | // data. |
256 | 217 | OPENSSL_memset(out, 0, in_len); |
257 | 217 | return 0; |
258 | 471 | } |
259 | | |
260 | 0 | const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; } |
261 | | |
262 | | int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv, |
263 | 0 | size_t *out_len) { |
264 | 0 | if (ctx->aead->get_iv == NULL) { |
265 | 0 | OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
266 | 0 | return 0; |
267 | 0 | } |
268 | | |
269 | 0 | return ctx->aead->get_iv(ctx, out_iv, out_len); |
270 | 0 | } |
271 | | |
272 | | int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len, |
273 | 153 | const size_t in_len, const size_t extra_in_len) { |
274 | 153 | assert(ctx->aead->seal_scatter_supports_extra_in || !extra_in_len); |
275 | | |
276 | 153 | if (ctx->aead->tag_len) { |
277 | 0 | *out_tag_len = ctx->aead->tag_len(ctx, in_len, extra_in_len); |
278 | 0 | return 1; |
279 | 0 | } |
280 | | |
281 | 153 | if (extra_in_len + ctx->tag_len < extra_in_len) { |
282 | 0 | OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW); |
283 | 0 | *out_tag_len = 0; |
284 | 0 | return 0; |
285 | 0 | } |
286 | 153 | *out_tag_len = extra_in_len + ctx->tag_len; |
287 | 153 | return 1; |
288 | 153 | } |