summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libssl/ssl_clnt.c10
-rw-r--r--src/lib/libssl/ssl_srvr.c10
-rw-r--r--src/lib/libssl/ssl_tlsext.c8
-rw-r--r--src/lib/libssl/tls13_client.c6
-rw-r--r--src/lib/libssl/tls13_server.c4
-rw-r--r--src/lib/libssl/tls_internal.h9
-rw-r--r--src/lib/libssl/tls_key_share.c327
-rw-r--r--src/regress/lib/libssl/tlsext/tlsexttest.c10
8 files changed, 353 insertions, 31 deletions
diff --git a/src/lib/libssl/ssl_clnt.c b/src/lib/libssl/ssl_clnt.c
index 0d3dcf78af..22469ce346 100644
--- a/src/lib/libssl/ssl_clnt.c
+++ b/src/lib/libssl/ssl_clnt.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_clnt.c,v 1.169 2025/03/09 15:53:36 tb Exp $ */ 1/* $OpenBSD: ssl_clnt.c,v 1.170 2025/12/04 21:03:42 beck Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -1195,7 +1195,7 @@ ssl3_get_server_kex_dhe(SSL *s, CBS *cbs)
1195 } 1195 }
1196 goto err; 1196 goto err;
1197 } 1197 }
1198 if (!tls_key_share_peer_public(s->s3->hs.key_share, cbs, 1198 if (!tls_key_share_client_peer_public(s->s3->hs.key_share, cbs,
1199 &decode_error, &invalid_key)) { 1199 &decode_error, &invalid_key)) {
1200 if (decode_error) { 1200 if (decode_error) {
1201 SSLerror(s, SSL_R_BAD_PACKET_LENGTH); 1201 SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
@@ -1264,7 +1264,7 @@ ssl3_get_server_kex_ecdhe(SSL *s, CBS *cbs)
1264 if ((s->s3->hs.key_share = tls_key_share_new(group_id)) == NULL) 1264 if ((s->s3->hs.key_share = tls_key_share_new(group_id)) == NULL)
1265 goto err; 1265 goto err;
1266 1266
1267 if (!tls_key_share_peer_public(s->s3->hs.key_share, &public, 1267 if (!tls_key_share_client_peer_public(s->s3->hs.key_share, &public,
1268 &decode_error, NULL)) { 1268 &decode_error, NULL)) {
1269 if (decode_error) 1269 if (decode_error)
1270 goto decode_err; 1270 goto decode_err;
@@ -1859,7 +1859,7 @@ ssl3_send_client_kex_dhe(SSL *s, CBB *cbb)
1859 goto err; 1859 goto err;
1860 } 1860 }
1861 1861
1862 if (!tls_key_share_generate(s->s3->hs.key_share)) 1862 if (!tls_key_share_client_generate(s->s3->hs.key_share))
1863 goto err; 1863 goto err;
1864 if (!tls_key_share_public(s->s3->hs.key_share, cbb)) 1864 if (!tls_key_share_public(s->s3->hs.key_share, cbb))
1865 goto err; 1865 goto err;
@@ -1898,7 +1898,7 @@ ssl3_send_client_kex_ecdhe(SSL *s, CBB *cbb)
1898 goto err; 1898 goto err;
1899 } 1899 }
1900 1900
1901 if (!tls_key_share_generate(s->s3->hs.key_share)) 1901 if (!tls_key_share_client_generate(s->s3->hs.key_share))
1902 goto err; 1902 goto err;
1903 1903
1904 if (!CBB_add_u8_length_prefixed(cbb, &public)) 1904 if (!CBB_add_u8_length_prefixed(cbb, &public))
diff --git a/src/lib/libssl/ssl_srvr.c b/src/lib/libssl/ssl_srvr.c
index db4ba38b51..ef93e283de 100644
--- a/src/lib/libssl/ssl_srvr.c
+++ b/src/lib/libssl/ssl_srvr.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_srvr.c,v 1.166 2025/03/09 15:53:36 tb Exp $ */ 1/* $OpenBSD: ssl_srvr.c,v 1.167 2025/12/04 21:03:42 beck Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -1357,7 +1357,7 @@ ssl3_send_server_kex_dhe(SSL *s, CBB *cbb)
1357 goto err; 1357 goto err;
1358 } 1358 }
1359 1359
1360 if (!tls_key_share_generate(s->s3->hs.key_share)) 1360 if (!tls_key_share_server_generate(s->s3->hs.key_share))
1361 goto err; 1361 goto err;
1362 1362
1363 if (!tls_key_share_params(s->s3->hs.key_share, cbb)) 1363 if (!tls_key_share_params(s->s3->hs.key_share, cbb))
@@ -1393,7 +1393,7 @@ ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb)
1393 if ((s->s3->hs.key_share = tls_key_share_new_nid(nid)) == NULL) 1393 if ((s->s3->hs.key_share = tls_key_share_new_nid(nid)) == NULL)
1394 goto err; 1394 goto err;
1395 1395
1396 if (!tls_key_share_generate(s->s3->hs.key_share)) 1396 if (!tls_key_share_server_generate(s->s3->hs.key_share))
1397 goto err; 1397 goto err;
1398 1398
1399 /* 1399 /*
@@ -1744,7 +1744,7 @@ ssl3_get_client_kex_dhe(SSL *s, CBS *cbs)
1744 goto err; 1744 goto err;
1745 } 1745 }
1746 1746
1747 if (!tls_key_share_peer_public(s->s3->hs.key_share, cbs, 1747 if (!tls_key_share_server_peer_public(s->s3->hs.key_share, cbs,
1748 &decode_error, &invalid_key)) { 1748 &decode_error, &invalid_key)) {
1749 if (decode_error) { 1749 if (decode_error) {
1750 SSLerror(s, SSL_R_BAD_PACKET_LENGTH); 1750 SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
@@ -1792,7 +1792,7 @@ ssl3_get_client_kex_ecdhe(SSL *s, CBS *cbs)
1792 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); 1792 ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
1793 goto err; 1793 goto err;
1794 } 1794 }
1795 if (!tls_key_share_peer_public(s->s3->hs.key_share, &public, 1795 if (!tls_key_share_server_peer_public(s->s3->hs.key_share, &public,
1796 &decode_error, NULL)) { 1796 &decode_error, NULL)) {
1797 if (decode_error) { 1797 if (decode_error) {
1798 SSLerror(s, SSL_R_BAD_PACKET_LENGTH); 1798 SSLerror(s, SSL_R_BAD_PACKET_LENGTH);
diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c
index 12ede899e8..dcd9a31205 100644
--- a/src/lib/libssl/ssl_tlsext.c
+++ b/src/lib/libssl/ssl_tlsext.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_tlsext.c,v 1.157 2025/10/16 14:42:21 jsing Exp $ */ 1/* $OpenBSD: ssl_tlsext.c,v 1.158 2025/12/04 21:03:42 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -1523,7 +1523,7 @@ tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
1523 *alert = SSL_AD_INTERNAL_ERROR; 1523 *alert = SSL_AD_INTERNAL_ERROR;
1524 return 0; 1524 return 0;
1525 } 1525 }
1526 if (!tls_key_share_peer_public(s->s3->hs.key_share, 1526 if (!tls_key_share_server_peer_public(s->s3->hs.key_share,
1527 &key_exchange, &decode_error, NULL)) { 1527 &key_exchange, &decode_error, NULL)) {
1528 if (!decode_error) 1528 if (!decode_error)
1529 *alert = SSL_AD_INTERNAL_ERROR; 1529 *alert = SSL_AD_INTERNAL_ERROR;
@@ -1614,7 +1614,7 @@ tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
1614 *alert = SSL_AD_INTERNAL_ERROR; 1614 *alert = SSL_AD_INTERNAL_ERROR;
1615 return 0; 1615 return 0;
1616 } 1616 }
1617 if (!tls_key_share_peer_public(s->s3->hs.key_share, 1617 if (!tls_key_share_server_peer_public(s->s3->hs.key_share,
1618 &key_exchange, &decode_error, NULL)) { 1618 &key_exchange, &decode_error, NULL)) {
1619 if (!decode_error) 1619 if (!decode_error)
1620 *alert = SSL_AD_INTERNAL_ERROR; 1620 *alert = SSL_AD_INTERNAL_ERROR;
@@ -1691,7 +1691,7 @@ tlsext_keyshare_client_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert)
1691 *alert = SSL_AD_INTERNAL_ERROR; 1691 *alert = SSL_AD_INTERNAL_ERROR;
1692 return 0; 1692 return 0;
1693 } 1693 }
1694 if (!tls_key_share_peer_public(s->s3->hs.key_share, 1694 if (!tls_key_share_client_peer_public(s->s3->hs.key_share,
1695 &key_exchange, &decode_error, NULL)) { 1695 &key_exchange, &decode_error, NULL)) {
1696 if (!decode_error) 1696 if (!decode_error)
1697 *alert = SSL_AD_INTERNAL_ERROR; 1697 *alert = SSL_AD_INTERNAL_ERROR;
diff --git a/src/lib/libssl/tls13_client.c b/src/lib/libssl/tls13_client.c
index 901b38f860..b0a285694d 100644
--- a/src/lib/libssl/tls13_client.c
+++ b/src/lib/libssl/tls13_client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls13_client.c,v 1.104 2024/07/22 14:47:15 jsing Exp $ */ 1/* $OpenBSD: tls13_client.c,v 1.105 2025/12/04 21:03:42 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2018, 2019 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -53,7 +53,7 @@ tls13_client_init(struct tls13_ctx *ctx)
53 return 0; 53 return 0;
54 if ((ctx->hs->key_share = tls_key_share_new(groups[0])) == NULL) 54 if ((ctx->hs->key_share = tls_key_share_new(groups[0])) == NULL)
55 return 0; 55 return 0;
56 if (!tls_key_share_generate(ctx->hs->key_share)) 56 if (!tls_key_share_client_generate(ctx->hs->key_share))
57 return 0; 57 return 0;
58 58
59 arc4random_buf(s->s3->client_random, SSL3_RANDOM_SIZE); 59 arc4random_buf(s->s3->client_random, SSL3_RANDOM_SIZE);
@@ -450,7 +450,7 @@ tls13_client_hello_retry_send(struct tls13_ctx *ctx, CBB *cbb)
450 if ((ctx->hs->key_share = 450 if ((ctx->hs->key_share =
451 tls_key_share_new(ctx->hs->tls13.server_group)) == NULL) 451 tls_key_share_new(ctx->hs->tls13.server_group)) == NULL)
452 return 0; 452 return 0;
453 if (!tls_key_share_generate(ctx->hs->key_share)) 453 if (!tls_key_share_client_generate(ctx->hs->key_share))
454 return 0; 454 return 0;
455 455
456 if (!tls13_client_hello_build(ctx, cbb)) 456 if (!tls13_client_hello_build(ctx, cbb))
diff --git a/src/lib/libssl/tls13_server.c b/src/lib/libssl/tls13_server.c
index fa56db9563..604dab4cba 100644
--- a/src/lib/libssl/tls13_server.c
+++ b/src/lib/libssl/tls13_server.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls13_server.c,v 1.111 2025/10/25 12:31:44 tb Exp $ */ 1/* $OpenBSD: tls13_server.c,v 1.112 2025/12/04 21:03:42 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2019, 2020 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2019, 2020 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 4 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
@@ -502,7 +502,7 @@ tls13_server_hello_send(struct tls13_ctx *ctx, CBB *cbb)
502{ 502{
503 if (ctx->hs->key_share == NULL) 503 if (ctx->hs->key_share == NULL)
504 return 0; 504 return 0;
505 if (!tls_key_share_generate(ctx->hs->key_share)) 505 if (!tls_key_share_server_generate(ctx->hs->key_share))
506 return 0; 506 return 0;
507 if (!tls13_servername_process(ctx)) 507 if (!tls13_servername_process(ctx))
508 return 0; 508 return 0;
diff --git a/src/lib/libssl/tls_internal.h b/src/lib/libssl/tls_internal.h
index 84edde8474..3d8d6aa940 100644
--- a/src/lib/libssl/tls_internal.h
+++ b/src/lib/libssl/tls_internal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_internal.h,v 1.10 2022/11/10 18:06:37 jsing Exp $ */ 1/* $OpenBSD: tls_internal.h,v 1.11 2025/12/04 21:03:42 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2018, 2019, 2021 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2018, 2019, 2021 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -85,12 +85,15 @@ int tls_key_share_nid(struct tls_key_share *ks);
85void tls_key_share_set_key_bits(struct tls_key_share *ks, size_t key_bits); 85void tls_key_share_set_key_bits(struct tls_key_share *ks, size_t key_bits);
86int tls_key_share_set_dh_params(struct tls_key_share *ks, DH *dh_params); 86int tls_key_share_set_dh_params(struct tls_key_share *ks, DH *dh_params);
87int tls_key_share_peer_pkey(struct tls_key_share *ks, EVP_PKEY *pkey); 87int tls_key_share_peer_pkey(struct tls_key_share *ks, EVP_PKEY *pkey);
88int tls_key_share_generate(struct tls_key_share *ks); 88int tls_key_share_client_generate(struct tls_key_share *ks);
89int tls_key_share_server_generate(struct tls_key_share *ks);
89int tls_key_share_params(struct tls_key_share *ks, CBB *cbb); 90int tls_key_share_params(struct tls_key_share *ks, CBB *cbb);
90int tls_key_share_public(struct tls_key_share *ks, CBB *cbb); 91int tls_key_share_public(struct tls_key_share *ks, CBB *cbb);
91int tls_key_share_peer_params(struct tls_key_share *ks, CBS *cbs, 92int tls_key_share_peer_params(struct tls_key_share *ks, CBS *cbs,
92 int *decode_error, int *invalid_params); 93 int *decode_error, int *invalid_params);
93int tls_key_share_peer_public(struct tls_key_share *ks, CBS *cbs, 94int tls_key_share_server_peer_public(struct tls_key_share *ks, CBS *cbs,
95 int *decode_error, int *invalid_key);
96int tls_key_share_client_peer_public(struct tls_key_share *ks, CBS *cbs,
94 int *decode_error, int *invalid_key); 97 int *decode_error, int *invalid_key);
95int tls_key_share_derive(struct tls_key_share *ks, uint8_t **shared_key, 98int tls_key_share_derive(struct tls_key_share *ks, uint8_t **shared_key,
96 size_t *shared_key_len); 99 size_t *shared_key_len);
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}
diff --git a/src/regress/lib/libssl/tlsext/tlsexttest.c b/src/regress/lib/libssl/tlsext/tlsexttest.c
index 68584998ce..4c3701a63d 100644
--- a/src/regress/lib/libssl/tlsext/tlsexttest.c
+++ b/src/regress/lib/libssl/tlsext/tlsexttest.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tlsexttest.c,v 1.94 2025/05/03 08:37:28 tb Exp $ */ 1/* $OpenBSD: tlsexttest.c,v 1.95 2025/12/04 21:03:42 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2017 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2017 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -3665,7 +3665,7 @@ test_tlsext_keyshare_client(void)
3665 if ((ssl->s3->hs.key_share = 3665 if ((ssl->s3->hs.key_share =
3666 tls_key_share_new_nid(NID_X25519)) == NULL) 3666 tls_key_share_new_nid(NID_X25519)) == NULL)
3667 errx(1, "failed to create key share"); 3667 errx(1, "failed to create key share");
3668 if (!tls_key_share_generate(ssl->s3->hs.key_share)) 3668 if (!tls_key_share_client_generate(ssl->s3->hs.key_share))
3669 errx(1, "failed to generate key share"); 3669 errx(1, "failed to generate key share");
3670 3670
3671 ssl->s3->hs.our_max_tls_version = TLS1_2_VERSION; 3671 ssl->s3->hs.our_max_tls_version = TLS1_2_VERSION;
@@ -3890,14 +3890,14 @@ test_tlsext_keyshare_server(void)
3890 goto done; 3890 goto done;
3891 } 3891 }
3892 3892
3893 if (!tls_key_share_generate(ssl->s3->hs.key_share)) { 3893 if (!tls_key_share_server_generate(ssl->s3->hs.key_share)) {
3894 FAIL("failed to generate key share"); 3894 FAIL("failed to generate key share");
3895 goto done; 3895 goto done;
3896 } 3896 }
3897 3897
3898 CBS_init(&cbs, bogokey, sizeof(bogokey)); 3898 CBS_init(&cbs, bogokey, sizeof(bogokey));
3899 3899
3900 if (!tls_key_share_peer_public(ssl->s3->hs.key_share, &cbs, 3900 if (!tls_key_share_server_peer_public(ssl->s3->hs.key_share, &cbs,
3901 &decode_error, NULL)) { 3901 &decode_error, NULL)) {
3902 FAIL("failed to load peer public key\n"); 3902 FAIL("failed to load peer public key\n");
3903 goto done; 3903 goto done;
@@ -3926,7 +3926,7 @@ test_tlsext_keyshare_server(void)
3926 FAIL("failed to create key share"); 3926 FAIL("failed to create key share");
3927 goto done; 3927 goto done;
3928 } 3928 }
3929 if (!tls_key_share_generate(ssl->s3->hs.key_share)) { 3929 if (!tls_key_share_server_generate(ssl->s3->hs.key_share)) {
3930 FAIL("failed to generate key share"); 3930 FAIL("failed to generate key share");
3931 goto done; 3931 goto done;
3932 } 3932 }