summaryrefslogtreecommitdiff
path: root/src/lib/libssl/tls_key_share.c
diff options
context:
space:
mode:
authorbeck <>2025-12-04 21:03:42 +0000
committerbeck <>2025-12-04 21:03:42 +0000
commitf8fcf556caab3fb1fb9d9b496d2724345c90a3eb (patch)
treee39a46d0520e4b766125513ea7a2a2e6521f7cf6 /src/lib/libssl/tls_key_share.c
parent25e047ad935a9d585bc84fe9aae3de40dbad3e72 (diff)
downloadopenbsd-f8fcf556caab3fb1fb9d9b496d2724345c90a3eb.tar.gz
openbsd-f8fcf556caab3fb1fb9d9b496d2724345c90a3eb.tar.bz2
openbsd-f8fcf556caab3fb1fb9d9b496d2724345c90a3eb.zip
Add a MLKEM768_X25519 hybrid key share.
This implements the currently in use MLKEM768_X25519 hybrid key share as outlined in https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/ This commit does not yet wire this up to anything, that is done in follow on changes. ok tb@ jsing@ kenjiro@
Diffstat (limited to 'src/lib/libssl/tls_key_share.c')
-rw-r--r--src/lib/libssl/tls_key_share.c327
1 files changed, 323 insertions, 4 deletions
diff --git a/src/lib/libssl/tls_key_share.c b/src/lib/libssl/tls_key_share.c
index cf7b1da262..3f4c44f558 100644
--- a/src/lib/libssl/tls_key_share.c
+++ b/src/lib/libssl/tls_key_share.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_key_share.c,v 1.8 2022/11/26 16:08:56 tb Exp $ */ 1/* $OpenBSD: tls_key_share.c,v 1.9 2025/12/04 21:03:42 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020, 2021 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2020, 2021 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -21,6 +21,7 @@
21#include <openssl/dh.h> 21#include <openssl/dh.h>
22#include <openssl/ec.h> 22#include <openssl/ec.h>
23#include <openssl/evp.h> 23#include <openssl/evp.h>
24#include <openssl/mlkem.h>
24 25
25#include "bytestring.h" 26#include "bytestring.h"
26#include "ssl_local.h" 27#include "ssl_local.h"
@@ -40,6 +41,19 @@ struct tls_key_share {
40 uint8_t *x25519_public; 41 uint8_t *x25519_public;
41 uint8_t *x25519_private; 42 uint8_t *x25519_private;
42 uint8_t *x25519_peer_public; 43 uint8_t *x25519_peer_public;
44
45 uint8_t *mlkem_public;
46 size_t mlkem_public_len;
47 MLKEM_private_key *mlkem_private;
48 MLKEM_public_key *mlkem_peer_public;
49
50 /* The ciphertext from MLKEM_encap. */
51 uint8_t *mlkem_encap;
52 size_t mlkem_encap_len;
53
54 /* The shared secret from an ML-KEM encapsulation. */
55 uint8_t *mlkem_shared_secret;
56 size_t mlkem_shared_secret_len;
43}; 57};
44 58
45static struct tls_key_share * 59static struct tls_key_share *
@@ -96,6 +110,12 @@ tls_key_share_free(struct tls_key_share *ks)
96 freezero(ks->x25519_private, X25519_KEY_LENGTH); 110 freezero(ks->x25519_private, X25519_KEY_LENGTH);
97 freezero(ks->x25519_peer_public, X25519_KEY_LENGTH); 111 freezero(ks->x25519_peer_public, X25519_KEY_LENGTH);
98 112
113 freezero(ks->mlkem_public, ks->mlkem_public_len);
114 MLKEM_private_key_free(ks->mlkem_private);
115 MLKEM_public_key_free(ks->mlkem_peer_public);
116 freezero(ks->mlkem_encap, ks->mlkem_encap_len);
117 freezero(ks->mlkem_shared_secret, ks->mlkem_shared_secret_len);
118
99 freezero(ks, sizeof(*ks)); 119 freezero(ks, sizeof(*ks));
100} 120}
101 121
@@ -230,7 +250,73 @@ tls_key_share_generate_x25519(struct tls_key_share *ks)
230 return ret; 250 return ret;
231} 251}
232 252
233int 253static int
254tls_key_share_generate_mlkem(struct tls_key_share *ks, int rank)
255{
256 MLKEM_private_key *private = NULL;
257 uint8_t *public = NULL;
258 size_t p_len = 0;
259 int ret = 0;
260
261 if (ks->mlkem_public != NULL || ks->mlkem_private != NULL)
262 goto err;
263
264 if ((private = MLKEM_private_key_new(rank)) == NULL)
265 goto err;
266
267 if (!MLKEM_generate_key(private, &public, &p_len, NULL, NULL))
268 goto err;
269
270 ks->mlkem_public = public;
271 ks->mlkem_public_len = p_len;
272 ks->mlkem_private = private;
273 public = NULL;
274 private = NULL;
275
276 ret = 1;
277
278 err:
279 freezero(public, p_len);
280 MLKEM_private_key_free(private);
281
282 return ret;
283}
284
285static int
286tls_key_share_client_generate_mlkem768x25519(struct tls_key_share *ks)
287{
288 if (!tls_key_share_generate_mlkem(ks, RANK768))
289 return 0;
290
291 if (!tls_key_share_generate_x25519(ks))
292 return 0;
293
294 return 1;
295}
296
297static int
298tls_key_share_server_generate_mlkem768x25519(struct tls_key_share *ks)
299{
300 if (ks->mlkem_private != NULL)
301 return 0;
302
303 /* The server side needs the client's parsed share */
304
305 if (ks->x25519_peer_public == NULL)
306 return 0;
307
308 if (ks->mlkem_peer_public == NULL)
309 return 0;
310
311 if (!tls_key_share_generate_x25519(ks))
312 return 0;
313
314 return MLKEM_encap(ks->mlkem_peer_public, &ks->mlkem_encap,
315 &ks->mlkem_encap_len, &ks->mlkem_shared_secret,
316 &ks->mlkem_shared_secret_len);
317}
318
319static int
234tls_key_share_generate(struct tls_key_share *ks) 320tls_key_share_generate(struct tls_key_share *ks)
235{ 321{
236 if (ks->nid == NID_dhKeyAgreement) 322 if (ks->nid == NID_dhKeyAgreement)
@@ -242,6 +328,24 @@ tls_key_share_generate(struct tls_key_share *ks)
242 return tls_key_share_generate_ecdhe_ecp(ks); 328 return tls_key_share_generate_ecdhe_ecp(ks);
243} 329}
244 330
331int
332tls_key_share_client_generate(struct tls_key_share *ks)
333{
334 if (ks->nid == NID_X25519MLKEM768)
335 return tls_key_share_client_generate_mlkem768x25519(ks);
336
337 return tls_key_share_generate(ks);
338}
339
340int
341tls_key_share_server_generate(struct tls_key_share *ks)
342{
343 if (ks->nid == NID_X25519MLKEM768)
344 return tls_key_share_server_generate_mlkem768x25519(ks);
345
346 return tls_key_share_generate(ks);
347}
348
245static int 349static int
246tls_key_share_params_dhe(struct tls_key_share *ks, CBB *cbb) 350tls_key_share_params_dhe(struct tls_key_share *ks, CBB *cbb)
247{ 351{
@@ -287,6 +391,47 @@ tls_key_share_public_x25519(struct tls_key_share *ks, CBB *cbb)
287 return CBB_add_bytes(cbb, ks->x25519_public, X25519_KEY_LENGTH); 391 return CBB_add_bytes(cbb, ks->x25519_public, X25519_KEY_LENGTH);
288} 392}
289 393
394static int
395tls_key_share_public_mlkem768x25519(struct tls_key_share *ks, CBB *cbb)
396{
397 uint8_t *mlkem_part;
398 size_t mlkem_part_len;
399
400 if (ks->x25519_public == NULL)
401 return 0;
402
403 /*
404 * https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/
405 * Section 3.1.2:
406 * The server's key exchange value is the concatenation of an
407 * ML-KEM ciphertext returned from encapsulation to the client's
408 * encapsulation key, and the server's ephemeral X25519 share.
409 */
410 mlkem_part = ks->mlkem_encap;
411 mlkem_part_len = ks->mlkem_encap_len;
412
413 /*
414 * https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/
415 * Section 3.1.1:
416 * The client's key_exchange value is the concatenation of the
417 * client's ML-KEM-768 encapsulation key and the client's X25519
418 * ephemeral share.
419 */
420 if (mlkem_part == NULL) {
421 mlkem_part = ks->mlkem_public;
422 mlkem_part_len = ks->mlkem_public_len;
423 }
424
425 if (mlkem_part == NULL)
426 return 0;
427
428 if (!CBB_add_bytes(cbb, mlkem_part, mlkem_part_len))
429 return 0;
430
431 /* Both the client and server send their x25519 public keys. */
432 return CBB_add_bytes(cbb, ks->x25519_public, X25519_KEY_LENGTH);
433}
434
290int 435int
291tls_key_share_public(struct tls_key_share *ks, CBB *cbb) 436tls_key_share_public(struct tls_key_share *ks, CBB *cbb)
292{ 437{
@@ -296,6 +441,9 @@ tls_key_share_public(struct tls_key_share *ks, CBB *cbb)
296 if (ks->nid == NID_X25519) 441 if (ks->nid == NID_X25519)
297 return tls_key_share_public_x25519(ks, cbb); 442 return tls_key_share_public_x25519(ks, cbb);
298 443
444 if (ks->nid == NID_X25519MLKEM768)
445 return tls_key_share_public_mlkem768x25519(ks, cbb);
446
299 return tls_key_share_public_ecdhe_ecp(ks, cbb); 447 return tls_key_share_public_ecdhe_ecp(ks, cbb);
300} 448}
301 449
@@ -325,7 +473,7 @@ tls_key_share_peer_params(struct tls_key_share *ks, CBS *cbs,
325 return 0; 473 return 0;
326 474
327 return tls_key_share_peer_params_dhe(ks, cbs, decode_error, 475 return tls_key_share_peer_params_dhe(ks, cbs, decode_error,
328 invalid_params); 476 invalid_params);
329} 477}
330 478
331static int 479static int
@@ -383,7 +531,91 @@ tls_key_share_peer_public_x25519(struct tls_key_share *ks, CBS *cbs,
383 return CBS_stow(cbs, &ks->x25519_peer_public, &out_len); 531 return CBS_stow(cbs, &ks->x25519_peer_public, &out_len);
384} 532}
385 533
386int 534static int
535tls_key_share_client_peer_public_mlkem768x25519(struct tls_key_share *ks,
536 CBS *cbs, int *decode_error)
537{
538 CBS x25519_cbs, mlkem_ciphertext_cbs;
539 size_t out_len;
540
541 if (ks->mlkem_shared_secret != NULL)
542 return 0;
543
544 if (ks->mlkem_private == NULL)
545 return 0;
546
547 if (!CBS_get_bytes(cbs, &mlkem_ciphertext_cbs,
548 MLKEM_private_key_ciphertext_length(ks->mlkem_private)))
549 return 0;
550
551 if (!CBS_get_bytes(cbs, &x25519_cbs, X25519_KEY_LENGTH))
552 return 0;
553
554 if (CBS_len(cbs) != 0)
555 return 0;
556
557 if (!CBS_stow(&x25519_cbs, &ks->x25519_peer_public, &out_len))
558 return 0;
559
560 if (!CBS_stow(&mlkem_ciphertext_cbs, &ks->mlkem_encap, &ks->mlkem_encap_len))
561 return 0;
562
563 return 1;
564}
565
566static int
567tls_key_share_server_peer_public_mlkem768x25519(struct tls_key_share *ks,
568 CBS *cbs, int *decode_error)
569{
570 CBS x25519_cbs, mlkem768_cbs;
571 size_t out_len;
572
573 *decode_error = 0;
574
575 /* The server should not have an mlkem private key */
576 if (ks->mlkem_private != NULL)
577 return 0;
578
579 if (ks->mlkem_shared_secret != NULL)
580 return 0;
581
582 if (ks->mlkem_peer_public != NULL)
583 return 0;
584
585 if (ks->x25519_peer_public != NULL)
586 return 0;
587
588 /* Nein, ist nur normal (1024 ist gigantisch) */
589 if ((ks->mlkem_peer_public = MLKEM_public_key_new(RANK768)) == NULL)
590 goto err;
591
592 if (!CBS_get_bytes(cbs, &mlkem768_cbs,
593 MLKEM_public_key_encoded_length(ks->mlkem_peer_public)))
594 goto err;
595
596 if (!CBS_get_bytes(cbs, &x25519_cbs, X25519_KEY_LENGTH))
597 goto err;
598
599 if (CBS_len(cbs) != 0)
600 goto err;
601
602 if (!CBS_stow(&x25519_cbs, &ks->x25519_peer_public, &out_len))
603 goto err;
604
605 /* Poetische */
606 if (!MLKEM_parse_public_key(ks->mlkem_peer_public,
607 CBS_data(&mlkem768_cbs), CBS_len(&mlkem768_cbs)))
608 goto err;
609
610 return 1;
611
612 err:
613 *decode_error = 1;
614
615 return 0;
616}
617
618static int
387tls_key_share_peer_public(struct tls_key_share *ks, CBS *cbs, int *decode_error, 619tls_key_share_peer_public(struct tls_key_share *ks, CBS *cbs, int *decode_error,
388 int *invalid_key) 620 int *invalid_key)
389{ 621{
@@ -402,6 +634,30 @@ tls_key_share_peer_public(struct tls_key_share *ks, CBS *cbs, int *decode_error,
402 return tls_key_share_peer_public_ecdhe_ecp(ks, cbs); 634 return tls_key_share_peer_public_ecdhe_ecp(ks, cbs);
403} 635}
404 636
637/* Called from client to process a server peer */
638int
639tls_key_share_client_peer_public(struct tls_key_share *ks, CBS *cbs,
640 int *decode_error, int *invalid_key)
641{
642 if (ks->nid == NID_X25519MLKEM768)
643 return tls_key_share_client_peer_public_mlkem768x25519(ks, cbs,
644 decode_error);
645
646 return tls_key_share_peer_public(ks, cbs, decode_error, invalid_key);
647}
648
649/* Called from server to process a client peer */
650int
651tls_key_share_server_peer_public(struct tls_key_share *ks, CBS *cbs,
652 int *decode_error, int *invalid_key)
653{
654 if (ks->nid == NID_X25519MLKEM768)
655 return tls_key_share_server_peer_public_mlkem768x25519(ks, cbs,
656 decode_error);
657
658 return tls_key_share_peer_public(ks, cbs, decode_error, invalid_key);
659}
660
405static int 661static int
406tls_key_share_derive_dhe(struct tls_key_share *ks, 662tls_key_share_derive_dhe(struct tls_key_share *ks,
407 uint8_t **shared_key, size_t *shared_key_len) 663 uint8_t **shared_key, size_t *shared_key_len)
@@ -451,6 +707,65 @@ tls_key_share_derive_x25519(struct tls_key_share *ks,
451 return ret; 707 return ret;
452} 708}
453 709
710/*
711 * https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/
712 * Section 3.1.3:
713 * For X25519MLKEM768, the shared secret is the concatenation of the ML-KEM
714 * shared secret and the X25519 shared secret.
715 */
716static int
717tls_key_share_derive_mlkem768x25519(struct tls_key_share *ks,
718 uint8_t **out_shared_key, size_t *out_shared_key_len)
719{
720 uint8_t *x25519_shared_key;
721 CBB cbb;
722
723 memset(&cbb, 0, sizeof(cbb));
724
725 if (ks->x25519_private == NULL)
726 goto err;
727
728 if (ks->x25519_peer_public == NULL)
729 goto err;
730
731 if (ks->mlkem_shared_secret == NULL) {
732 if (ks->mlkem_private == NULL)
733 goto err;
734
735 if (ks->mlkem_encap == NULL)
736 goto err;
737
738 if (!MLKEM_decap(ks->mlkem_private, ks->mlkem_encap,
739 MLKEM_private_key_ciphertext_length(ks->mlkem_private),
740 &ks->mlkem_shared_secret, &ks->mlkem_shared_secret_len))
741 goto err;
742 }
743
744 if (!CBB_init(&cbb, ks->mlkem_shared_secret_len + X25519_KEY_LENGTH))
745 goto err;
746
747 if (!CBB_add_bytes(&cbb, ks->mlkem_shared_secret,
748 ks->mlkem_shared_secret_len))
749 goto err;
750
751 if (!CBB_add_space(&cbb, &x25519_shared_key, X25519_KEY_LENGTH))
752 goto err;
753
754 if (!X25519(x25519_shared_key, ks->x25519_private,
755 ks->x25519_peer_public))
756 goto err;
757
758 if (!CBB_finish(&cbb, out_shared_key, out_shared_key_len))
759 goto err;
760
761 return 1;
762
763 err:
764 CBB_cleanup(&cbb);
765
766 return 0;
767}
768
454int 769int
455tls_key_share_derive(struct tls_key_share *ks, uint8_t **shared_key, 770tls_key_share_derive(struct tls_key_share *ks, uint8_t **shared_key,
456 size_t *shared_key_len) 771 size_t *shared_key_len)
@@ -468,6 +783,10 @@ tls_key_share_derive(struct tls_key_share *ks, uint8_t **shared_key,
468 return tls_key_share_derive_x25519(ks, shared_key, 783 return tls_key_share_derive_x25519(ks, shared_key,
469 shared_key_len); 784 shared_key_len);
470 785
786 if (ks->nid == NID_X25519MLKEM768)
787 return tls_key_share_derive_mlkem768x25519(ks, shared_key,
788 shared_key_len);
789
471 return tls_key_share_derive_ecdhe_ecp(ks, shared_key, 790 return tls_key_share_derive_ecdhe_ecp(ks, shared_key,
472 shared_key_len); 791 shared_key_len);
473} 792}