diff options
Diffstat (limited to 'src/lib/libssl/tls12_record_layer.c')
-rw-r--r-- | src/lib/libssl/tls12_record_layer.c | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/src/lib/libssl/tls12_record_layer.c b/src/lib/libssl/tls12_record_layer.c new file mode 100644 index 0000000000..5e7a3a610c --- /dev/null +++ b/src/lib/libssl/tls12_record_layer.c | |||
@@ -0,0 +1,533 @@ | |||
1 | /* $OpenBSD: tls12_record_layer.c,v 1.1 2020/08/30 15:40:20 jsing Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2020 Joel Sing <jsing@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <stdlib.h> | ||
19 | |||
20 | #include <openssl/evp.h> | ||
21 | |||
22 | #include "ssl_locl.h" | ||
23 | |||
24 | struct tls12_record_layer { | ||
25 | uint16_t version; | ||
26 | int dtls; | ||
27 | |||
28 | uint16_t read_epoch; | ||
29 | uint16_t write_epoch; | ||
30 | |||
31 | int read_stream_mac; | ||
32 | int write_stream_mac; | ||
33 | |||
34 | /* | ||
35 | * XXX - for now these are just pointers to externally managed | ||
36 | * structs/memory. These should eventually be owned by the record layer. | ||
37 | */ | ||
38 | SSL_AEAD_CTX *read_aead_ctx; | ||
39 | SSL_AEAD_CTX *write_aead_ctx; | ||
40 | |||
41 | EVP_CIPHER_CTX *read_cipher_ctx; | ||
42 | EVP_MD_CTX *read_hash_ctx; | ||
43 | EVP_CIPHER_CTX *write_cipher_ctx; | ||
44 | EVP_MD_CTX *write_hash_ctx; | ||
45 | |||
46 | uint8_t *read_seq_num; | ||
47 | uint8_t *write_seq_num; | ||
48 | }; | ||
49 | |||
50 | struct tls12_record_layer * | ||
51 | tls12_record_layer_new(void) | ||
52 | { | ||
53 | struct tls12_record_layer *rl; | ||
54 | |||
55 | if ((rl = calloc(1, sizeof(struct tls12_record_layer))) == NULL) | ||
56 | return NULL; | ||
57 | |||
58 | return rl; | ||
59 | } | ||
60 | |||
61 | void | ||
62 | tls12_record_layer_free(struct tls12_record_layer *rl) | ||
63 | { | ||
64 | freezero(rl, sizeof(struct tls12_record_layer)); | ||
65 | } | ||
66 | |||
67 | void | ||
68 | tls12_record_layer_set_version(struct tls12_record_layer *rl, uint16_t version) | ||
69 | { | ||
70 | rl->version = version; | ||
71 | rl->dtls = (version == DTLS1_VERSION); | ||
72 | } | ||
73 | |||
74 | void | ||
75 | tls12_record_layer_set_read_epoch(struct tls12_record_layer *rl, uint16_t epoch) | ||
76 | { | ||
77 | rl->read_epoch = epoch; | ||
78 | } | ||
79 | |||
80 | void | ||
81 | tls12_record_layer_set_write_epoch(struct tls12_record_layer *rl, uint16_t epoch) | ||
82 | { | ||
83 | rl->write_epoch = epoch; | ||
84 | } | ||
85 | |||
86 | static void | ||
87 | tls12_record_layer_set_read_state(struct tls12_record_layer *rl, | ||
88 | SSL_AEAD_CTX *aead_ctx, EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *hash_ctx, | ||
89 | int stream_mac) | ||
90 | { | ||
91 | rl->read_aead_ctx = aead_ctx; | ||
92 | |||
93 | rl->read_cipher_ctx = cipher_ctx; | ||
94 | rl->read_hash_ctx = hash_ctx; | ||
95 | rl->read_stream_mac = stream_mac; | ||
96 | } | ||
97 | |||
98 | static void | ||
99 | tls12_record_layer_set_write_state(struct tls12_record_layer *rl, | ||
100 | SSL_AEAD_CTX *aead_ctx, EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *hash_ctx, | ||
101 | int stream_mac) | ||
102 | { | ||
103 | rl->write_aead_ctx = aead_ctx; | ||
104 | |||
105 | rl->write_cipher_ctx = cipher_ctx; | ||
106 | rl->write_hash_ctx = hash_ctx; | ||
107 | rl->write_stream_mac = stream_mac; | ||
108 | } | ||
109 | |||
110 | void | ||
111 | tls12_record_layer_clear_read_state(struct tls12_record_layer *rl) | ||
112 | { | ||
113 | tls12_record_layer_set_read_state(rl, NULL, NULL, NULL, 0); | ||
114 | rl->read_seq_num = NULL; | ||
115 | } | ||
116 | |||
117 | void | ||
118 | tls12_record_layer_clear_write_state(struct tls12_record_layer *rl) | ||
119 | { | ||
120 | tls12_record_layer_set_write_state(rl, NULL, NULL, NULL, 0); | ||
121 | rl->write_seq_num = NULL; | ||
122 | } | ||
123 | |||
124 | void | ||
125 | tls12_record_layer_set_read_seq_num(struct tls12_record_layer *rl, | ||
126 | uint8_t *seq_num) | ||
127 | { | ||
128 | rl->read_seq_num = seq_num; | ||
129 | } | ||
130 | |||
131 | void | ||
132 | tls12_record_layer_set_write_seq_num(struct tls12_record_layer *rl, | ||
133 | uint8_t *seq_num) | ||
134 | { | ||
135 | rl->write_seq_num = seq_num; | ||
136 | } | ||
137 | |||
138 | int | ||
139 | tls12_record_layer_set_read_aead(struct tls12_record_layer *rl, | ||
140 | SSL_AEAD_CTX *aead_ctx) | ||
141 | { | ||
142 | tls12_record_layer_set_read_state(rl, aead_ctx, NULL, NULL, 0); | ||
143 | |||
144 | return 1; | ||
145 | } | ||
146 | |||
147 | int | ||
148 | tls12_record_layer_set_write_aead(struct tls12_record_layer *rl, | ||
149 | SSL_AEAD_CTX *aead_ctx) | ||
150 | { | ||
151 | tls12_record_layer_set_write_state(rl, aead_ctx, NULL, NULL, 0); | ||
152 | |||
153 | return 1; | ||
154 | } | ||
155 | |||
156 | int | ||
157 | tls12_record_layer_set_read_cipher_hash(struct tls12_record_layer *rl, | ||
158 | EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *hash_ctx, int stream_mac) | ||
159 | { | ||
160 | tls12_record_layer_set_read_state(rl, NULL, cipher_ctx, hash_ctx, | ||
161 | stream_mac); | ||
162 | |||
163 | return 1; | ||
164 | } | ||
165 | |||
166 | int | ||
167 | tls12_record_layer_set_write_cipher_hash(struct tls12_record_layer *rl, | ||
168 | EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *hash_ctx, int stream_mac) | ||
169 | { | ||
170 | tls12_record_layer_set_write_state(rl, NULL, cipher_ctx, hash_ctx, | ||
171 | stream_mac); | ||
172 | |||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | static int | ||
177 | tls12_record_layer_build_seq_num(struct tls12_record_layer *rl, CBB *cbb, | ||
178 | uint16_t epoch, uint8_t *seq_num, size_t seq_num_len) | ||
179 | { | ||
180 | CBS seq; | ||
181 | |||
182 | CBS_init(&seq, seq_num, seq_num_len); | ||
183 | |||
184 | if (rl->dtls) { | ||
185 | if (!CBB_add_u16(cbb, epoch)) | ||
186 | return 0; | ||
187 | if (!CBS_skip(&seq, 2)) | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | return CBB_add_bytes(cbb, CBS_data(&seq), CBS_len(&seq)); | ||
192 | } | ||
193 | |||
194 | static int | ||
195 | tls12_record_layer_pseudo_header(struct tls12_record_layer *rl, | ||
196 | uint8_t content_type, uint16_t record_len, uint16_t epoch, uint8_t *seq_num, | ||
197 | size_t seq_num_len, uint8_t **out, size_t *out_len) | ||
198 | { | ||
199 | CBB cbb; | ||
200 | |||
201 | *out = NULL; | ||
202 | *out_len = 0; | ||
203 | |||
204 | /* Build the pseudo-header used for MAC/AEAD. */ | ||
205 | if (!CBB_init(&cbb, 13)) | ||
206 | goto err; | ||
207 | |||
208 | if (!tls12_record_layer_build_seq_num(rl, &cbb, epoch, | ||
209 | seq_num, seq_num_len)) | ||
210 | goto err; | ||
211 | if (!CBB_add_u8(&cbb, content_type)) | ||
212 | goto err; | ||
213 | if (!CBB_add_u16(&cbb, rl->version)) | ||
214 | goto err; | ||
215 | if (!CBB_add_u16(&cbb, record_len)) | ||
216 | goto err; | ||
217 | |||
218 | if (!CBB_finish(&cbb, out, out_len)) | ||
219 | goto err; | ||
220 | |||
221 | return 1; | ||
222 | |||
223 | err: | ||
224 | CBB_cleanup(&cbb); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int | ||
230 | tls12_record_layer_write_mac(struct tls12_record_layer *rl, CBB *cbb, | ||
231 | uint8_t content_type, const uint8_t *content, size_t content_len, | ||
232 | size_t *out_len) | ||
233 | { | ||
234 | EVP_MD_CTX *mac_ctx = NULL; | ||
235 | uint8_t *header = NULL; | ||
236 | size_t header_len; | ||
237 | size_t mac_len; | ||
238 | uint8_t *mac; | ||
239 | int ret = 0; | ||
240 | |||
241 | if ((mac_ctx = EVP_MD_CTX_new()) == NULL) | ||
242 | goto err; | ||
243 | if (!EVP_MD_CTX_copy(mac_ctx, rl->write_hash_ctx)) | ||
244 | goto err; | ||
245 | |||
246 | if (!tls12_record_layer_pseudo_header(rl, content_type, content_len, | ||
247 | rl->write_epoch, rl->write_seq_num, SSL3_SEQUENCE_SIZE, | ||
248 | &header, &header_len)) | ||
249 | goto err; | ||
250 | |||
251 | if (EVP_DigestSignUpdate(mac_ctx, header, header_len) <= 0) | ||
252 | goto err; | ||
253 | if (EVP_DigestSignUpdate(mac_ctx, content, content_len) <= 0) | ||
254 | goto err; | ||
255 | if (EVP_DigestSignFinal(mac_ctx, NULL, &mac_len) <= 0) | ||
256 | goto err; | ||
257 | if (!CBB_add_space(cbb, &mac, mac_len)) | ||
258 | goto err; | ||
259 | if (EVP_DigestSignFinal(mac_ctx, mac, &mac_len) <= 0) | ||
260 | goto err; | ||
261 | |||
262 | if (rl->write_stream_mac) { | ||
263 | if (!EVP_MD_CTX_copy(rl->write_hash_ctx, mac_ctx)) | ||
264 | goto err; | ||
265 | } | ||
266 | |||
267 | *out_len = mac_len; | ||
268 | |||
269 | ret = 1; | ||
270 | |||
271 | err: | ||
272 | EVP_MD_CTX_free(mac_ctx); | ||
273 | free(header); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | static int | ||
279 | tls12_record_layer_seal_record_plaintext(struct tls12_record_layer *rl, | ||
280 | uint8_t content_type, const uint8_t *content, size_t content_len, CBB *out) | ||
281 | { | ||
282 | if (rl->write_aead_ctx != NULL || rl->write_cipher_ctx != NULL) | ||
283 | return 0; | ||
284 | |||
285 | return CBB_add_bytes(out, content, content_len); | ||
286 | } | ||
287 | |||
288 | static int | ||
289 | tls12_record_layer_aead_concat_nonce(struct tls12_record_layer *rl, | ||
290 | const SSL_AEAD_CTX *aead, uint8_t *seq_num, uint8_t **out, size_t *out_len) | ||
291 | { | ||
292 | CBB cbb; | ||
293 | |||
294 | if (aead->variable_nonce_len > SSL3_SEQUENCE_SIZE) | ||
295 | return 0; | ||
296 | |||
297 | /* Fixed nonce and variable nonce (sequence number) are concatenated. */ | ||
298 | if (!CBB_init(&cbb, 16)) | ||
299 | goto err; | ||
300 | if (!CBB_add_bytes(&cbb, aead->fixed_nonce, | ||
301 | aead->fixed_nonce_len)) | ||
302 | goto err; | ||
303 | if (!CBB_add_bytes(&cbb, seq_num, aead->variable_nonce_len)) | ||
304 | goto err; | ||
305 | if (!CBB_finish(&cbb, out, out_len)) | ||
306 | goto err; | ||
307 | |||
308 | return 1; | ||
309 | |||
310 | err: | ||
311 | CBB_cleanup(&cbb); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int | ||
317 | tls12_record_layer_aead_xored_nonce(struct tls12_record_layer *rl, | ||
318 | const SSL_AEAD_CTX *aead, uint8_t *seq_num, uint8_t **out, size_t *out_len) | ||
319 | { | ||
320 | uint8_t *nonce = NULL; | ||
321 | size_t nonce_len = 0; | ||
322 | uint8_t *pad; | ||
323 | CBB cbb; | ||
324 | int i; | ||
325 | |||
326 | if (aead->variable_nonce_len > SSL3_SEQUENCE_SIZE) | ||
327 | return 0; | ||
328 | if (aead->fixed_nonce_len < aead->variable_nonce_len) | ||
329 | return 0; | ||
330 | |||
331 | /* | ||
332 | * Variable nonce (sequence number) is right padded, before the fixed | ||
333 | * nonce is XOR'd in. | ||
334 | */ | ||
335 | if (!CBB_init(&cbb, 16)) | ||
336 | goto err; | ||
337 | if (!CBB_add_space(&cbb, &pad, | ||
338 | aead->fixed_nonce_len - aead->variable_nonce_len)) | ||
339 | goto err; | ||
340 | if (!CBB_add_bytes(&cbb, seq_num, aead->variable_nonce_len)) | ||
341 | goto err; | ||
342 | if (!CBB_finish(&cbb, &nonce, &nonce_len)) | ||
343 | goto err; | ||
344 | |||
345 | for (i = 0; i < aead->fixed_nonce_len; i++) | ||
346 | nonce[i] ^= aead->fixed_nonce[i]; | ||
347 | |||
348 | *out = nonce; | ||
349 | *out_len = nonce_len; | ||
350 | |||
351 | return 1; | ||
352 | |||
353 | err: | ||
354 | CBB_cleanup(&cbb); | ||
355 | freezero(nonce, nonce_len); | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int | ||
361 | tls12_record_layer_seal_record_protected_aead(struct tls12_record_layer *rl, | ||
362 | uint8_t content_type, const uint8_t *content, size_t content_len, CBB *out) | ||
363 | { | ||
364 | const SSL_AEAD_CTX *aead = rl->write_aead_ctx; | ||
365 | uint8_t *header = NULL, *nonce = NULL; | ||
366 | size_t header_len = 0, nonce_len = 0; | ||
367 | size_t enc_record_len, out_len; | ||
368 | uint16_t epoch = 0; | ||
369 | uint8_t *enc_data; | ||
370 | int ret = 0; | ||
371 | |||
372 | /* XXX - move to nonce allocated in record layer, matching TLSv1.3 */ | ||
373 | if (aead->xor_fixed_nonce) { | ||
374 | if (!tls12_record_layer_aead_xored_nonce(rl, aead, | ||
375 | rl->write_seq_num, &nonce, &nonce_len)) | ||
376 | goto err; | ||
377 | } else { | ||
378 | if (!tls12_record_layer_aead_concat_nonce(rl, aead, | ||
379 | rl->write_seq_num, &nonce, &nonce_len)) | ||
380 | goto err; | ||
381 | } | ||
382 | |||
383 | if (aead->variable_nonce_in_record) { | ||
384 | /* XXX - length check? */ | ||
385 | if (!CBB_add_bytes(out, rl->write_seq_num, aead->variable_nonce_len)) | ||
386 | goto err; | ||
387 | } | ||
388 | |||
389 | if (!tls12_record_layer_pseudo_header(rl, content_type, content_len, | ||
390 | epoch, rl->write_seq_num, SSL3_SEQUENCE_SIZE, &header, &header_len)) | ||
391 | goto err; | ||
392 | |||
393 | /* XXX EVP_AEAD_max_tag_len vs EVP_AEAD_CTX_tag_len. */ | ||
394 | enc_record_len = content_len + aead->tag_len; | ||
395 | if (enc_record_len > SSL3_RT_MAX_ENCRYPTED_LENGTH) | ||
396 | goto err; | ||
397 | if (!CBB_add_space(out, &enc_data, enc_record_len)) | ||
398 | goto err; | ||
399 | |||
400 | if (!EVP_AEAD_CTX_seal(&aead->ctx, enc_data, &out_len, enc_record_len, | ||
401 | nonce, nonce_len, content, content_len, header, header_len)) | ||
402 | goto err; | ||
403 | |||
404 | if (out_len != enc_record_len) | ||
405 | goto err; | ||
406 | |||
407 | ret = 1; | ||
408 | |||
409 | err: | ||
410 | freezero(header, header_len); | ||
411 | freezero(nonce, nonce_len); | ||
412 | |||
413 | return ret; | ||
414 | } | ||
415 | |||
416 | static int | ||
417 | tls12_record_layer_seal_record_protected_cipher(struct tls12_record_layer *rl, | ||
418 | uint8_t content_type, const uint8_t *content, size_t content_len, CBB *out) | ||
419 | { | ||
420 | EVP_CIPHER_CTX *enc = rl->write_cipher_ctx; | ||
421 | size_t mac_len, pad_len; | ||
422 | int block_size, eiv_len; | ||
423 | uint8_t *enc_data, *eiv, *pad, pad_val; | ||
424 | uint8_t *plain = NULL; | ||
425 | size_t plain_len = 0; | ||
426 | int ret = 0; | ||
427 | CBB cbb; | ||
428 | |||
429 | if (!CBB_init(&cbb, SSL3_RT_MAX_PLAIN_LENGTH)) | ||
430 | goto err; | ||
431 | |||
432 | /* Add explicit IV if necessary. */ | ||
433 | eiv_len = 0; | ||
434 | if (rl->version != TLS1_VERSION && | ||
435 | EVP_CIPHER_CTX_mode(enc) == EVP_CIPH_CBC_MODE) | ||
436 | eiv_len = EVP_CIPHER_CTX_iv_length(enc); | ||
437 | if (eiv_len < 0 || eiv_len > EVP_MAX_IV_LENGTH) | ||
438 | goto err; | ||
439 | if (eiv_len > 0) { | ||
440 | if (!CBB_add_space(&cbb, &eiv, eiv_len)) | ||
441 | goto err; | ||
442 | arc4random_buf(eiv, eiv_len); | ||
443 | } | ||
444 | |||
445 | if (!CBB_add_bytes(&cbb, content, content_len)) | ||
446 | goto err; | ||
447 | |||
448 | mac_len = 0; | ||
449 | if (rl->write_hash_ctx != NULL) { | ||
450 | if (!tls12_record_layer_write_mac(rl, &cbb, content_type, | ||
451 | content, content_len, &mac_len)) | ||
452 | goto err; | ||
453 | } | ||
454 | |||
455 | plain_len = (size_t)eiv_len + content_len + mac_len; | ||
456 | |||
457 | /* Add padding to block size, if necessary. */ | ||
458 | block_size = EVP_CIPHER_CTX_block_size(enc); | ||
459 | if (block_size < 0 || block_size > EVP_MAX_BLOCK_LENGTH) | ||
460 | return 0; | ||
461 | if (block_size > 1) { | ||
462 | pad_len = block_size - (plain_len % block_size); | ||
463 | pad_val = pad_len - 1; | ||
464 | |||
465 | if (pad_len > 255) | ||
466 | goto err; | ||
467 | if (!CBB_add_space(&cbb, &pad, pad_len)) | ||
468 | goto err; | ||
469 | memset(pad, pad_val, pad_len); | ||
470 | } | ||
471 | |||
472 | if (!CBB_finish(&cbb, &plain, &plain_len)) | ||
473 | goto err; | ||
474 | |||
475 | if (plain_len % block_size != 0) | ||
476 | goto err; | ||
477 | if (plain_len > SSL3_RT_MAX_ENCRYPTED_LENGTH) | ||
478 | goto err; | ||
479 | |||
480 | if (!CBB_add_space(out, &enc_data, plain_len)) | ||
481 | goto err; | ||
482 | if (!EVP_Cipher(enc, enc_data, plain, plain_len)) | ||
483 | goto err; | ||
484 | |||
485 | ret = 1; | ||
486 | |||
487 | err: | ||
488 | CBB_cleanup(&cbb); | ||
489 | freezero(plain, plain_len); | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | |||
494 | int | ||
495 | tls12_record_layer_seal_record(struct tls12_record_layer *rl, | ||
496 | uint8_t content_type, const uint8_t *content, size_t content_len, CBB *cbb) | ||
497 | { | ||
498 | CBB fragment; | ||
499 | |||
500 | if (!CBB_add_u8(cbb, content_type)) | ||
501 | return 0; | ||
502 | if (!CBB_add_u16(cbb, rl->version)) | ||
503 | return 0; | ||
504 | if (rl->dtls) { | ||
505 | if (!tls12_record_layer_build_seq_num(rl, cbb, | ||
506 | rl->write_epoch, rl->write_seq_num, | ||
507 | SSL3_SEQUENCE_SIZE)) | ||
508 | return 0; | ||
509 | } | ||
510 | if (!CBB_add_u16_length_prefixed(cbb, &fragment)) | ||
511 | return 0; | ||
512 | |||
513 | if (rl->write_aead_ctx != NULL) { | ||
514 | if (!tls12_record_layer_seal_record_protected_aead(rl, | ||
515 | content_type, content, content_len, &fragment)) | ||
516 | return 0; | ||
517 | } else if (rl->write_cipher_ctx != NULL) { | ||
518 | if (!tls12_record_layer_seal_record_protected_cipher(rl, | ||
519 | content_type, content, content_len, &fragment)) | ||
520 | return 0; | ||
521 | } else { | ||
522 | if (!tls12_record_layer_seal_record_plaintext(rl, | ||
523 | content_type, content, content_len, &fragment)) | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | if (!CBB_flush(cbb)) | ||
528 | return 0; | ||
529 | |||
530 | tls1_record_sequence_increment(rl->write_seq_num); | ||
531 | |||
532 | return 1; | ||
533 | } | ||