1- From e45854b34aa48b1fdefad81906cdb9931e697bbc Mon Sep 17 00:00:00 2001
1+ From fc01a66ac146778c4e6651d6fc6d62c7e12bfb32 Mon Sep 17 00:00:00 2001
22From: Christopher Patton <cpatton@cloudflare.com>
3- Date: Tue, 21 Apr 2026 15:45:09 -0700
3+ Date: Wed, 27 May 2026 09:55:52 -0700
44Subject: [PATCH] Add additional post-quantum key agreement
55
66This patch adds:
@@ -16,8 +16,6 @@ This patch adds:
1616 non post-quantum and a post-quantum keyshare if available. These
1717 functions allow one to change the behaviour to only send a single
1818 keyshare.
19-
20-
2119---
2220 crypto/obj/obj_dat.h | 6 +-
2321 crypto/obj/obj_mac.num | 1 +
@@ -40,54 +38,54 @@ This patch adds:
4038 18 files changed, 249 insertions(+), 43 deletions(-)
4139
4240diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h
43- index 10ad9bb14..3fe6fdec6 100644
41+ index feb8f2d1e..7ca28d9f5 100644
4442--- a/crypto/obj/obj_dat.h
4543+++ b/crypto/obj/obj_dat.h
4644@@ -16,7 +16,7 @@
4745
4846
4947 BSSL_NAMESPACE_BEGIN
50- - #define NUM_NID 971
51- + #define NUM_NID 972
48+ - #define NUM_NID 973
49+ + #define NUM_NID 974
5250
5351 static const uint8_t kObjectData[] = {
5452 /* NID_rsadsi */
55- @@ -8800,6 +8800,8 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
56- {"id-ml-dsa-87", "ML-DSA-87", NID_ML_DSA_87, 9, &kObjectData[6223], 0},
57- {"id-alg-ml-kem-768", "ML-KEM-768", NID_ML_KEM_768, 9, &kObjectData[6232],
53+ @@ -8802,6 +8802,8 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
5854 0},
55+ {NULL, NULL, NID_undef, 0, NULL, 0},
56+ {"X-Wing", "X-Wing", NID_X_Wing, 0, NULL, 0},
5957+ {"P256Kyber768Draft00", "P256Kyber768Draft00", NID_P256Kyber768Draft00, 0,
6058+ NULL, 0},
6159 };
6260
6361 static const uint16_t kNIDsInShortNameOrder[] = {
64- @@ -8932 ,6 +8934 ,7 @@ static const uint16_t kNIDsInShortNameOrder[] = {
62+ @@ -8934 ,6 +8936 ,7 @@ static const uint16_t kNIDsInShortNameOrder[] = {
6563 18 /* OU */,
6664 749 /* Oakley-EC2N-3 */,
6765 750 /* Oakley-EC2N-4 */,
68- + 971 /* P256Kyber768Draft00 */,
66+ + 973 /* P256Kyber768Draft00 */,
6967 9 /* PBE-MD2-DES */,
7068 168 /* PBE-MD2-RC2-64 */,
7169 10 /* PBE-MD5-DES */,
72- @@ -9855 ,6 +9858 ,7 @@ static const uint16_t kNIDsInLongNameOrder[] = {
70+ @@ -9858 ,6 +9861 ,7 @@ static const uint16_t kNIDsInLongNameOrder[] = {
7371 366 /* OCSP Nonce */,
7472 371 /* OCSP Service Locator */,
7573 180 /* OCSP Signing */,
76- + 971 /* P256Kyber768Draft00 */,
74+ + 973 /* P256Kyber768Draft00 */,
7775 161 /* PBES2 */,
7876 69 /* PBKDF2 */,
7977 162 /* PBMAC1 */,
8078diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num
81- index ae863e29d..7231b9a58 100644
79+ index 7b8bd2ead..dc7b2878f 100644
8280--- a/crypto/obj/obj_mac.num
8381+++ b/crypto/obj/obj_mac.num
84- @@ -958,3 +958,4 @@ ML_DSA_44 967
85- ML_DSA_65 968
82+ @@ -959,3 +959,4 @@ ML_DSA_65 968
8683 ML_DSA_87 969
8784 ML_KEM_768 970
88- + P256Kyber768Draft00 971
85+ X_Wing 972
86+ + P256Kyber768Draft00 973
8987diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt
90- index 1e0cb76db..e8b249dfd 100644
88+ index 67b9ade43..384b25753 100644
9189--- a/crypto/obj/objects.txt
9290+++ b/crypto/obj/objects.txt
9391@@ -1340,6 +1340,7 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
@@ -97,34 +95,34 @@ index 1e0cb76db..e8b249dfd 100644
9795+ : P256Kyber768Draft00
9896 : X25519MLKEM768
9997
100- # See RFC 8410 .
98+ # NIDs for PQ/T hybrid KEMs (no corresponding OIDs) .
10199diff --git a/include/openssl/nid.h b/include/openssl/nid.h
102- index 83a1cf592..7265f15f6 100644
100+ index 6b3bb4506..068fc5977 100644
103101--- a/include/openssl/nid.h
104102+++ b/include/openssl/nid.h
105- @@ -5508 ,6 +5508 ,9 @@ extern "C" {
106- #define OBJ_ML_KEM_768 2L, 16L, 840L, 1L, 101L, 3L, 4L, 4L, 2L
107- #define OBJ_ENC_ML_KEM_768 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x02
103+ @@ -5511 ,6 +5511 ,9 @@ extern "C" {
104+ #define SN_X_Wing "X-Wing"
105+ #define NID_X_Wing 972
108106
109107+ #define SN_P256Kyber768Draft00 "P256Kyber768Draft00"
110- + #define NID_P256Kyber768Draft00 971
108+ + #define NID_P256Kyber768Draft00 973
111109+
112110
113111 #if defined(__cplusplus)
114112 } /* extern C */
115113diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
116- index 3a2e6dc50..300848e0f 100644
114+ index 055b3e025..09d6508f4 100644
117115--- a/include/openssl/ssl.h
118116+++ b/include/openssl/ssl.h
119- @@ -2579 ,6 +2579 ,7 @@ OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx);
117+ @@ -2586 ,6 +2586 ,7 @@ OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx);
120118 #define SSL_GROUP_X25519_MLKEM768 0x11ec
121119 #define SSL_GROUP_X25519_KYBER768_DRAFT00 0x6399
122120 #define SSL_GROUP_MLKEM1024 0x0202
123121+ #define SSL_GROUP_P256_KYBER768_DRAFT00 0xfe32
124122
125123 // SSL_CTX_set1_group_ids sets the preferred groups for |ctx| to |group_ids|.
126124 // Each element of |group_ids| should be a unique one of the |SSL_GROUP_*|
127- @@ -6195 ,6 +6196 ,20 @@ OPENSSL_EXPORT int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves);
125+ @@ -6241 ,6 +6242 ,20 @@ OPENSSL_EXPORT int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves);
128126 // SSL_set1_curves_list calls |SSL_set1_groups_list|.
129127 OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves);
130128
@@ -146,18 +144,18 @@ index 3a2e6dc50..300848e0f 100644
146144 // |SSL_get_negotiated_group| to return an unrecognized group. BoringSSL never
147145 // returns this value, but we define this constant for compatibility.
148146diff --git a/ssl/extensions.cc b/ssl/extensions.cc
149- index 529226876..e2ed74d5f 100644
147+ index db1a29139..05c8c1e16 100644
150148--- a/ssl/extensions.cc
151149+++ b/ssl/extensions.cc
152- @@ -106 ,6 +106 ,7 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) {
150+ @@ -107 ,6 +107 ,7 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) {
153151 static bool is_post_quantum_group(uint16_t id) {
154152 switch (id) {
155153 case SSL_GROUP_X25519_KYBER768_DRAFT00:
156154+ case SSL_GROUP_P256_KYBER768_DRAFT00:
157155 case SSL_GROUP_X25519_MLKEM768:
158156 case SSL_GROUP_MLKEM1024:
159157 return true;
160- @@ -2413 ,18 +2414 ,21 @@ bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id) {
158+ @@ -2418 ,18 +2419 ,21 @@ bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id) {
161159 if (!default_key_shares.TryPushBack(supported_group_list[0])) {
162160 return false;
163161 }
@@ -191,7 +189,7 @@ index 529226876..e2ed74d5f 100644
191189 selected_key_shares.emplace(default_key_shares);
192190 }
193191diff --git a/ssl/internal.h b/ssl/internal.h
194- index 4d86a6170..1c0d9f2fd 100644
192+ index 2bea8f62d..47b688bf4 100644
195193--- a/ssl/internal.h
196194+++ b/ssl/internal.h
197195@@ -913,7 +913,7 @@ struct NamedGroup {
@@ -203,7 +201,7 @@ index 4d86a6170..1c0d9f2fd 100644
203201
204202 // DefaultSupportedGroupIds returns the list of IDs for the default groups that
205203 // are supported when the caller hasn't explicitly configured supported groups.
206- @@ -3512 ,6 +3512 ,11 @@ struct SSL_CONFIG {
204+ @@ -3531 ,6 +3531 ,11 @@ struct SSL_CONFIG {
207205 // permute_extensions is whether to permute extensions when sending messages.
208206 bool permute_extensions : 1;
209207
@@ -215,7 +213,7 @@ index 4d86a6170..1c0d9f2fd 100644
215213 // aes_hw_override if set indicates we should override checking for aes
216214 // hardware support, and use the value in aes_hw_override_value instead.
217215 bool aes_hw_override : 1;
218- @@ -4149 ,6 +4154 ,11 @@ struct ssl_ctx_st : public bssl::RefCounted<ssl_ctx_st> {
216+ @@ -4172 ,6 +4177 ,11 @@ struct ssl_ctx_st : public bssl::RefCounted<ssl_ctx_st> {
219217 // permute_extensions is whether to permute extensions when sending messages.
220218 bool permute_extensions : 1;
221219
@@ -373,7 +371,7 @@ index d155b5527..4fb08906b 100644
373371 return nullptr;
374372 }
375373diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
376- index de4e79efc..4ca2e799d 100644
374+ index 89702eaaf..a7505841c 100644
377375--- a/ssl/ssl_lib.cc
378376+++ b/ssl/ssl_lib.cc
379377@@ -385,6 +385,7 @@ ssl_ctx_st::ssl_ctx_st(const SSL_METHOD *ssl_method)
@@ -397,10 +395,10 @@ index de4e79efc..4ca2e799d 100644
397395 quic_use_legacy_codepoint(false),
398396 permute_extensions(false),
399397+ disable_second_keyshare(false),
400- alps_use_new_codepoint(true) {
398+ alps_use_new_codepoint(true),
399+ server_padding_enabled(false) {
401400 assert(ssl);
402- }
403- @@ -3372,6 +3375,15 @@ int SSL_set1_curves_list(SSL *ssl, const char *curves) {
401+ @@ -3390,6 +3393,15 @@ int SSL_set1_curves_list(SSL *ssl, const char *curves) {
404402 return SSL_set1_groups_list(ssl, curves);
405403 }
406404
@@ -416,7 +414,7 @@ index de4e79efc..4ca2e799d 100644
416414 namespace fips202205 {
417415
418416 // (References are to SP 800-52r2):
419- @@ -3383 ,7 +3395 ,9 @@ namespace fips202205 {
417+ @@ -3401 ,7 +3413 ,9 @@ namespace fips202205 {
420418 // Section 3.3.1
421419 // "The server shall be configured to only use cipher suites that are
422420 // composed entirely of NIST approved algorithms"
@@ -428,10 +426,10 @@ index de4e79efc..4ca2e799d 100644
428426 static const uint16_t kSigAlgs[] = {
429427 SSL_SIGN_RSA_PKCS1_SHA256,
430428diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
431- index 49adcaf72..6427ecf5d 100644
429+ index a91a6268c..3999ad61b 100644
432430--- a/ssl/ssl_test.cc
433431+++ b/ssl/ssl_test.cc
434- @@ -520 ,6 +520 ,14 @@ static const CurveTest kCurveTests[] = {
432+ @@ -522 ,6 +522 ,14 @@ static const CurveTest kCurveTests[] = {
435433 "MLKEM1024:X25519MLKEM768",
436434 {SSL_GROUP_MLKEM1024, SSL_GROUP_X25519_MLKEM768},
437435 },
@@ -446,7 +444,7 @@ index 49adcaf72..6427ecf5d 100644
446444
447445 {
448446 "P-256:P-384:P-521:X25519",
449- @@ -681 ,7 +689 ,9 @@ TEST(SSLTest, CurveRules) {
447+ @@ -683 ,7 +691 ,9 @@ TEST(SSLTest, CurveRules) {
450448 }
451449
452450 TEST(SSLTest, DefaultCurves) {
@@ -457,7 +455,7 @@ index 49adcaf72..6427ecf5d 100644
457455 SSL_GROUP_SECP384R1};
458456
459457 // Test the group ID APIs.
460- @@ -1641 ,6 +1651 ,9 @@ static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
458+ @@ -1643 ,6 +1653 ,9 @@ static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
461459 static size_t GetClientHelloLen(uint16_t max_version, uint16_t session_version,
462460 size_t ticket_len) {
463461 bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
@@ -467,7 +465,7 @@ index 49adcaf72..6427ecf5d 100644
467465 bssl::UniquePtr<SSL_SESSION> session =
468466 CreateSessionWithTicket(session_version, ticket_len);
469467 if (!ctx || !session) {
470- @@ -2315 ,7 +2328 ,10 @@ TEST(SSLTest, SetGroupIdsWithEqualPreference) {
468+ @@ -2317 ,7 +2330 ,10 @@ TEST(SSLTest, SetGroupIdsWithEqualPreference) {
471469 // Test that the SSL group flags are defaulted to zero when zero groups are set
472470 // (i.e. using the default groups).
473471 TEST(SSLTest, SetGroupIdsWithFlags_DefaultGroups) {
@@ -479,7 +477,7 @@ index 49adcaf72..6427ecf5d 100644
479477 SSL_GROUP_SECP384R1};
480478 const uint32_t kBogusFlags[] = {SSL_GROUP_FLAG_EQUAL_PREFERENCE_WITH_NEXT,
481479 SSL_GROUP_FLAG_EQUAL_PREFERENCE_WITH_NEXT, 0};
482- @@ -7052 ,7 +7068 ,9 @@ TEST(SSLTest, ApplyHandoffRemovesUnsupportedCurves) {
480+ @@ -7112 ,7 +7128 ,9 @@ TEST(SSLTest, ApplyHandoffRemovesUnsupportedCurves) {
483481
484482 // The default list of groups is used before applying the handoff.
485483 EXPECT_THAT(server->config->supported_group_list,
@@ -491,7 +489,7 @@ index 49adcaf72..6427ecf5d 100644
491489 ASSERT_TRUE(SSL_apply_handoff(server.get(), handoff));
492490 EXPECT_EQ(1u, server->config->supported_group_list.size());
493491diff --git a/ssl/test/runner/basic_tests.go b/ssl/test/runner/basic_tests.go
494- index dfd17d5f1..054241404 100644
492+ index 54d49637b..5887c715a 100644
495493--- a/ssl/test/runner/basic_tests.go
496494+++ b/ssl/test/runner/basic_tests.go
497495@@ -132,6 +132,7 @@ read alert 1 0
@@ -502,7 +500,7 @@ index dfd17d5f1..054241404 100644
502500 read hs 2
503501 read hs 11
504502 read hs 12
505- @@ -1975 ,6 +1976 ,7 @@ read alert 1 0
503+ @@ -2003 ,6 +2004 ,7 @@ read alert 1 0
506504 write hs 2
507505 write hs 8
508506 write hs 11
@@ -532,10 +530,10 @@ index 6f49d12af..5e970b2b5 100644
532530 })
533531 }
534532diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
535- index 2d174832f..5056444de 100644
533+ index c241c418e..9ffafa248 100644
536534--- a/ssl/test/runner/common.go
537535+++ b/ssl/test/runner/common.go
538- @@ -2172 ,7 +2172 ,7 @@ type ProtocolBugs struct {
536+ @@ -2186 ,7 +2186 ,7 @@ type ProtocolBugs struct {
539537 FailIfHelloRetryRequested bool
540538
541539 // FailIfPostQuantumOffered will cause a server to reject a ClientHello if
@@ -545,10 +543,10 @@ index 2d174832f..5056444de 100644
545543
546544 // ExpectKeyShares, if not nil, lists (in order) the curves that a ClientHello
547545diff --git a/ssl/test/runner/curve_tests.go b/ssl/test/runner/curve_tests.go
548- index 9bc13115e..0d11da734 100644
546+ index 956a73203..d04a1531d 100644
549547--- a/ssl/test/runner/curve_tests.go
550548+++ b/ssl/test/runner/curve_tests.go
551- @@ -581 ,17 +581 ,6 @@ func addCurveTests() {
549+ @@ -582 ,17 +582 ,6 @@ func addCurveTests() {
552550 })
553551 }
554552
@@ -566,7 +564,7 @@ index 9bc13115e..0d11da734 100644
566564 for _, curve := range testCurves {
567565 if !isMLKEMGroup(curve.id) {
568566 continue
569- @@ -681 ,18 +670 ,19 @@ func addCurveTests() {
567+ @@ -682 ,18 +671 ,19 @@ func addCurveTests() {
570568 })
571569 }
572570
@@ -644,7 +642,7 @@ index 2cd3c10d3..f19d8d20a 100644
644642 clientAndServerHelloInitial += "write ccs\n"
645643 }
646644diff --git a/ssl/test/runner/extension_tests.go b/ssl/test/runner/extension_tests.go
647- index 3087efe37..61a036d8b 100644
645+ index ab9b0b02d..834da257f 100644
648646--- a/ssl/test/runner/extension_tests.go
649647+++ b/ssl/test/runner/extension_tests.go
650648@@ -16,6 +16,7 @@ package runner
@@ -655,7 +653,7 @@ index 3087efe37..61a036d8b 100644
655653 )
656654
657655 func addExtensionTests() {
658- @@ -1967 ,7 +1968 ,7 @@ func addExtensionTests() {
656+ @@ -2001 ,7 +2002 ,7 @@ func addExtensionTests() {
659657 // This hostname just needs to be long enough to push the
660658 // ClientHello into F5's danger zone between 256 and 511 bytes
661659 // long.
0 commit comments