blob: 1b9dcd2c6135cea59253252e6f0b6ab5627475fe [file] [log] [blame]
Adam Langleyf4e42722015-06-04 17:45:09 -07001/* Copyright (c) 2015, 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
Kenny Rootb8494592015-09-25 02:29:14 +000015#include <openssl/ssl.h>
16
Adam Langleyf4e42722015-06-04 17:45:09 -070017#include <assert.h>
18#include <string.h>
19
20#include <openssl/aead.h>
21#include <openssl/err.h>
22#include <openssl/rand.h>
23#include <openssl/type_check.h>
24
Robert Sloan69939df2017-01-09 10:53:07 -080025#include "../crypto/internal.h"
Adam Langleyf4e42722015-06-04 17:45:09 -070026#include "internal.h"
27
28
Adam Langleyf4e42722015-06-04 17:45:09 -070029SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
Robert Sloan8ff03552017-06-14 12:40:58 -070030 uint16_t version, int is_dtls,
31 const SSL_CIPHER *cipher, const uint8_t *enc_key,
32 size_t enc_key_len, const uint8_t *mac_key,
33 size_t mac_key_len, const uint8_t *fixed_iv,
34 size_t fixed_iv_len) {
Adam Langleyf4e42722015-06-04 17:45:09 -070035 const EVP_AEAD *aead;
Steven Valdez909b19f2016-11-21 15:35:44 -050036 size_t expected_mac_key_len, expected_fixed_iv_len;
37 if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len,
Robert Sloan8ff03552017-06-14 12:40:58 -070038 &expected_fixed_iv_len, cipher, version,
39 is_dtls) ||
Steven Valdez909b19f2016-11-21 15:35:44 -050040 /* Ensure the caller returned correct key sizes. */
41 expected_fixed_iv_len != fixed_iv_len ||
42 expected_mac_key_len != mac_key_len) {
Kenny Rootb8494592015-09-25 02:29:14 +000043 OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
Adam Langleyf4e42722015-06-04 17:45:09 -070044 return 0;
45 }
46
47 uint8_t merged_key[EVP_AEAD_MAX_KEY_LENGTH];
48 if (mac_key_len > 0) {
49 /* This is a "stateful" AEAD (for compatibility with pre-AEAD cipher
50 * suites). */
51 if (mac_key_len + enc_key_len + fixed_iv_len > sizeof(merged_key)) {
Kenny Rootb8494592015-09-25 02:29:14 +000052 OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
Adam Langleyf4e42722015-06-04 17:45:09 -070053 return 0;
54 }
Robert Sloan69939df2017-01-09 10:53:07 -080055 OPENSSL_memcpy(merged_key, mac_key, mac_key_len);
56 OPENSSL_memcpy(merged_key + mac_key_len, enc_key, enc_key_len);
57 OPENSSL_memcpy(merged_key + mac_key_len + enc_key_len, fixed_iv,
58 fixed_iv_len);
Adam Langleyf4e42722015-06-04 17:45:09 -070059 enc_key = merged_key;
60 enc_key_len += mac_key_len;
61 enc_key_len += fixed_iv_len;
62 }
63
David Benjamin4969cc92016-04-22 15:02:23 -040064 SSL_AEAD_CTX *aead_ctx = OPENSSL_malloc(sizeof(SSL_AEAD_CTX));
Adam Langleyf4e42722015-06-04 17:45:09 -070065 if (aead_ctx == NULL) {
Kenny Rootb8494592015-09-25 02:29:14 +000066 OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
Adam Langleyf4e42722015-06-04 17:45:09 -070067 return NULL;
68 }
Robert Sloan69939df2017-01-09 10:53:07 -080069 OPENSSL_memset(aead_ctx, 0, sizeof(SSL_AEAD_CTX));
Adam Langleyf4e42722015-06-04 17:45:09 -070070 aead_ctx->cipher = cipher;
Robert Sloan1c9db532017-03-13 08:03:59 -070071 aead_ctx->version = version;
Adam Langleyf4e42722015-06-04 17:45:09 -070072
73 if (!EVP_AEAD_CTX_init_with_direction(
74 &aead_ctx->ctx, aead, enc_key, enc_key_len,
75 EVP_AEAD_DEFAULT_TAG_LENGTH, direction)) {
76 OPENSSL_free(aead_ctx);
77 return NULL;
78 }
79
80 assert(EVP_AEAD_nonce_length(aead) <= EVP_AEAD_MAX_NONCE_LENGTH);
David Benjaminf31229b2017-01-25 14:08:15 -050081 OPENSSL_COMPILE_ASSERT(EVP_AEAD_MAX_NONCE_LENGTH < 256,
82 variable_nonce_len_doesnt_fit_in_uint8_t);
Adam Langleyf4e42722015-06-04 17:45:09 -070083 aead_ctx->variable_nonce_len = (uint8_t)EVP_AEAD_nonce_length(aead);
84 if (mac_key_len == 0) {
Adam Langley4139edb2016-01-13 15:00:54 -080085 assert(fixed_iv_len <= sizeof(aead_ctx->fixed_nonce));
Robert Sloan69939df2017-01-09 10:53:07 -080086 OPENSSL_memcpy(aead_ctx->fixed_nonce, fixed_iv, fixed_iv_len);
Adam Langleyf4e42722015-06-04 17:45:09 -070087 aead_ctx->fixed_nonce_len = fixed_iv_len;
Adam Langley4139edb2016-01-13 15:00:54 -080088
89 if (cipher->algorithm_enc & SSL_CHACHA20POLY1305) {
90 /* The fixed nonce into the actual nonce (the sequence number). */
91 aead_ctx->xor_fixed_nonce = 1;
92 aead_ctx->variable_nonce_len = 8;
93 } else {
94 /* The fixed IV is prepended to the nonce. */
95 assert(fixed_iv_len <= aead_ctx->variable_nonce_len);
96 aead_ctx->variable_nonce_len -= fixed_iv_len;
97 }
98
Kenny Rootb8494592015-09-25 02:29:14 +000099 /* AES-GCM uses an explicit nonce. */
100 if (cipher->algorithm_enc & (SSL_AES128GCM | SSL_AES256GCM)) {
101 aead_ctx->variable_nonce_included_in_record = 1;
102 }
David Benjamind316cba2016-06-02 16:17:39 -0400103
104 /* The TLS 1.3 construction XORs the fixed nonce into the sequence number
105 * and omits the additional data. */
106 if (version >= TLS1_3_VERSION) {
107 aead_ctx->xor_fixed_nonce = 1;
108 aead_ctx->variable_nonce_len = 8;
109 aead_ctx->variable_nonce_included_in_record = 0;
110 aead_ctx->omit_ad = 1;
David Benjaminc895d6b2016-08-11 13:26:41 -0400111 assert(fixed_iv_len >= aead_ctx->variable_nonce_len);
David Benjamind316cba2016-06-02 16:17:39 -0400112 }
Adam Langleyf4e42722015-06-04 17:45:09 -0700113 } else {
David Benjaminc895d6b2016-08-11 13:26:41 -0400114 assert(version < TLS1_3_VERSION);
Adam Langleyf4e42722015-06-04 17:45:09 -0700115 aead_ctx->variable_nonce_included_in_record = 1;
116 aead_ctx->random_variable_nonce = 1;
117 aead_ctx->omit_length_in_ad = 1;
118 aead_ctx->omit_version_in_ad = (version == SSL3_VERSION);
119 }
120
121 return aead_ctx;
122}
123
124void SSL_AEAD_CTX_free(SSL_AEAD_CTX *aead) {
125 if (aead == NULL) {
126 return;
127 }
128 EVP_AEAD_CTX_cleanup(&aead->ctx);
129 OPENSSL_free(aead);
130}
131
David Benjaminf31229b2017-01-25 14:08:15 -0500132size_t SSL_AEAD_CTX_explicit_nonce_len(const SSL_AEAD_CTX *aead) {
David Benjamin4969cc92016-04-22 15:02:23 -0400133#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
134 aead = NULL;
135#endif
136
Adam Langleyf4e42722015-06-04 17:45:09 -0700137 if (aead != NULL && aead->variable_nonce_included_in_record) {
138 return aead->variable_nonce_len;
139 }
140 return 0;
141}
142
David Benjaminf31229b2017-01-25 14:08:15 -0500143size_t SSL_AEAD_CTX_max_overhead(const SSL_AEAD_CTX *aead) {
David Benjamin4969cc92016-04-22 15:02:23 -0400144#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
145 aead = NULL;
146#endif
147
Adam Langleyf4e42722015-06-04 17:45:09 -0700148 if (aead == NULL) {
149 return 0;
150 }
151 return EVP_AEAD_max_overhead(aead->ctx.aead) +
David Benjamin4969cc92016-04-22 15:02:23 -0400152 SSL_AEAD_CTX_explicit_nonce_len(aead);
Adam Langleyf4e42722015-06-04 17:45:09 -0700153}
154
155/* ssl_aead_ctx_get_ad writes the additional data for |aead| into |out| and
156 * returns the number of bytes written. */
157static size_t ssl_aead_ctx_get_ad(SSL_AEAD_CTX *aead, uint8_t out[13],
158 uint8_t type, uint16_t wire_version,
159 const uint8_t seqnum[8],
160 size_t plaintext_len) {
David Benjamind316cba2016-06-02 16:17:39 -0400161 if (aead->omit_ad) {
162 return 0;
163 }
164
Robert Sloan69939df2017-01-09 10:53:07 -0800165 OPENSSL_memcpy(out, seqnum, 8);
Adam Langleyf4e42722015-06-04 17:45:09 -0700166 size_t len = 8;
167 out[len++] = type;
168 if (!aead->omit_version_in_ad) {
169 out[len++] = (uint8_t)(wire_version >> 8);
170 out[len++] = (uint8_t)wire_version;
171 }
172 if (!aead->omit_length_in_ad) {
173 out[len++] = (uint8_t)(plaintext_len >> 8);
174 out[len++] = (uint8_t)plaintext_len;
175 }
176 return len;
177}
178
David Benjamin6e899c72016-06-09 18:02:18 -0400179int SSL_AEAD_CTX_open(SSL_AEAD_CTX *aead, CBS *out, uint8_t type,
180 uint16_t wire_version, const uint8_t seqnum[8],
181 uint8_t *in, size_t in_len) {
David Benjamin4969cc92016-04-22 15:02:23 -0400182#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
183 aead = NULL;
184#endif
185
Adam Langleyf4e42722015-06-04 17:45:09 -0700186 if (aead == NULL) {
187 /* Handle the initial NULL cipher. */
David Benjamin6e899c72016-06-09 18:02:18 -0400188 CBS_init(out, in, in_len);
Adam Langleyf4e42722015-06-04 17:45:09 -0700189 return 1;
190 }
191
192 /* TLS 1.2 AEADs include the length in the AD and are assumed to have fixed
193 * overhead. Otherwise the parameter is unused. */
194 size_t plaintext_len = 0;
195 if (!aead->omit_length_in_ad) {
196 size_t overhead = SSL_AEAD_CTX_max_overhead(aead);
197 if (in_len < overhead) {
198 /* Publicly invalid. */
Kenny Rootb8494592015-09-25 02:29:14 +0000199 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
Adam Langleyf4e42722015-06-04 17:45:09 -0700200 return 0;
201 }
202 plaintext_len = in_len - overhead;
203 }
204 uint8_t ad[13];
205 size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum,
206 plaintext_len);
207
208 /* Assemble the nonce. */
209 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
210 size_t nonce_len = 0;
Adam Langley4139edb2016-01-13 15:00:54 -0800211
212 /* Prepend the fixed nonce, or left-pad with zeros if XORing. */
213 if (aead->xor_fixed_nonce) {
214 nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len;
Robert Sloan69939df2017-01-09 10:53:07 -0800215 OPENSSL_memset(nonce, 0, nonce_len);
Adam Langley4139edb2016-01-13 15:00:54 -0800216 } else {
Robert Sloan69939df2017-01-09 10:53:07 -0800217 OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
Adam Langley4139edb2016-01-13 15:00:54 -0800218 nonce_len += aead->fixed_nonce_len;
219 }
220
221 /* Add the variable nonce. */
Adam Langleyf4e42722015-06-04 17:45:09 -0700222 if (aead->variable_nonce_included_in_record) {
223 if (in_len < aead->variable_nonce_len) {
224 /* Publicly invalid. */
Kenny Rootb8494592015-09-25 02:29:14 +0000225 OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_PACKET_LENGTH);
Adam Langleyf4e42722015-06-04 17:45:09 -0700226 return 0;
227 }
Robert Sloan69939df2017-01-09 10:53:07 -0800228 OPENSSL_memcpy(nonce + nonce_len, in, aead->variable_nonce_len);
Adam Langleyf4e42722015-06-04 17:45:09 -0700229 in += aead->variable_nonce_len;
230 in_len -= aead->variable_nonce_len;
231 } else {
232 assert(aead->variable_nonce_len == 8);
Robert Sloan69939df2017-01-09 10:53:07 -0800233 OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
Adam Langleyf4e42722015-06-04 17:45:09 -0700234 }
235 nonce_len += aead->variable_nonce_len;
236
Adam Langley4139edb2016-01-13 15:00:54 -0800237 /* XOR the fixed nonce, if necessary. */
238 if (aead->xor_fixed_nonce) {
239 assert(nonce_len == aead->fixed_nonce_len);
David Benjamin7c0d06c2016-08-11 13:26:41 -0400240 for (size_t i = 0; i < aead->fixed_nonce_len; i++) {
Adam Langley4139edb2016-01-13 15:00:54 -0800241 nonce[i] ^= aead->fixed_nonce[i];
242 }
243 }
244
David Benjamin6e899c72016-06-09 18:02:18 -0400245 /* Decrypt in-place. */
246 size_t len;
247 if (!EVP_AEAD_CTX_open(&aead->ctx, in, &len, in_len, nonce, nonce_len,
248 in, in_len, ad, ad_len)) {
249 return 0;
250 }
251 CBS_init(out, in, len);
252 return 1;
Adam Langleyf4e42722015-06-04 17:45:09 -0700253}
254
255int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *aead, uint8_t *out, size_t *out_len,
256 size_t max_out, uint8_t type, uint16_t wire_version,
257 const uint8_t seqnum[8], const uint8_t *in,
258 size_t in_len) {
David Benjamin4969cc92016-04-22 15:02:23 -0400259#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
260 aead = NULL;
261#endif
262
Adam Langleyf4e42722015-06-04 17:45:09 -0700263 if (aead == NULL) {
264 /* Handle the initial NULL cipher. */
265 if (in_len > max_out) {
Kenny Rootb8494592015-09-25 02:29:14 +0000266 OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
Adam Langleyf4e42722015-06-04 17:45:09 -0700267 return 0;
268 }
Robert Sloan69939df2017-01-09 10:53:07 -0800269 OPENSSL_memmove(out, in, in_len);
Adam Langleyf4e42722015-06-04 17:45:09 -0700270 *out_len = in_len;
271 return 1;
272 }
273
274 uint8_t ad[13];
275 size_t ad_len = ssl_aead_ctx_get_ad(aead, ad, type, wire_version, seqnum,
276 in_len);
277
278 /* Assemble the nonce. */
279 uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
280 size_t nonce_len = 0;
Adam Langley4139edb2016-01-13 15:00:54 -0800281
282 /* Prepend the fixed nonce, or left-pad with zeros if XORing. */
283 if (aead->xor_fixed_nonce) {
284 nonce_len = aead->fixed_nonce_len - aead->variable_nonce_len;
Robert Sloan69939df2017-01-09 10:53:07 -0800285 OPENSSL_memset(nonce, 0, nonce_len);
Adam Langley4139edb2016-01-13 15:00:54 -0800286 } else {
Robert Sloan69939df2017-01-09 10:53:07 -0800287 OPENSSL_memcpy(nonce, aead->fixed_nonce, aead->fixed_nonce_len);
Adam Langley4139edb2016-01-13 15:00:54 -0800288 nonce_len += aead->fixed_nonce_len;
289 }
290
291 /* Select the variable nonce. */
Adam Langleyf4e42722015-06-04 17:45:09 -0700292 if (aead->random_variable_nonce) {
293 assert(aead->variable_nonce_included_in_record);
294 if (!RAND_bytes(nonce + nonce_len, aead->variable_nonce_len)) {
295 return 0;
296 }
297 } else {
298 /* When sending we use the sequence number as the variable part of the
299 * nonce. */
300 assert(aead->variable_nonce_len == 8);
Robert Sloan69939df2017-01-09 10:53:07 -0800301 OPENSSL_memcpy(nonce + nonce_len, seqnum, aead->variable_nonce_len);
Adam Langleyf4e42722015-06-04 17:45:09 -0700302 }
303 nonce_len += aead->variable_nonce_len;
304
305 /* Emit the variable nonce if included in the record. */
306 size_t extra_len = 0;
307 if (aead->variable_nonce_included_in_record) {
Adam Langley4139edb2016-01-13 15:00:54 -0800308 assert(!aead->xor_fixed_nonce);
Adam Langleyf4e42722015-06-04 17:45:09 -0700309 if (max_out < aead->variable_nonce_len) {
Kenny Rootb8494592015-09-25 02:29:14 +0000310 OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
Adam Langleyf4e42722015-06-04 17:45:09 -0700311 return 0;
312 }
313 if (out < in + in_len && in < out + aead->variable_nonce_len) {
Kenny Rootb8494592015-09-25 02:29:14 +0000314 OPENSSL_PUT_ERROR(SSL, SSL_R_OUTPUT_ALIASES_INPUT);
Adam Langleyf4e42722015-06-04 17:45:09 -0700315 return 0;
316 }
Robert Sloan69939df2017-01-09 10:53:07 -0800317 OPENSSL_memcpy(out, nonce + aead->fixed_nonce_len,
318 aead->variable_nonce_len);
Adam Langleyf4e42722015-06-04 17:45:09 -0700319 extra_len = aead->variable_nonce_len;
320 out += aead->variable_nonce_len;
321 max_out -= aead->variable_nonce_len;
322 }
323
Adam Langley4139edb2016-01-13 15:00:54 -0800324 /* XOR the fixed nonce, if necessary. */
325 if (aead->xor_fixed_nonce) {
326 assert(nonce_len == aead->fixed_nonce_len);
David Benjamin7c0d06c2016-08-11 13:26:41 -0400327 for (size_t i = 0; i < aead->fixed_nonce_len; i++) {
Adam Langley4139edb2016-01-13 15:00:54 -0800328 nonce[i] ^= aead->fixed_nonce[i];
329 }
330 }
331
Adam Langleyf4e42722015-06-04 17:45:09 -0700332 if (!EVP_AEAD_CTX_seal(&aead->ctx, out, out_len, max_out, nonce, nonce_len,
333 in, in_len, ad, ad_len)) {
334 return 0;
335 }
336 *out_len += extra_len;
337 return 1;
338}