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