1- From cb5689e091f515fc8a42ceaff08d702333e505ed Mon Sep 17 00:00:00 2001
2- From: Anthony Ramine <aramine @cloudflare.com>
3- Date: Wed, 3 Dec 2025 11:10:16 +0100
4- Subject: [PATCH] Add additional post-quantum key agreements
1+ From e45854b34aa48b1fdefad81906cdb9931e697bbc Mon Sep 17 00:00:00 2001
2+ From: Christopher Patton <cpatton @cloudflare.com>
3+ Date: Tue, 21 Apr 2026 15:45:09 -0700
4+ Subject: [PATCH] Add additional post-quantum key agreement
55
66This patch adds:
77
@@ -16,6 +16,8 @@ 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+
1921---
2022 crypto/obj/obj_dat.h | 6 +-
2123 crypto/obj/obj_mac.num | 1 +
@@ -26,7 +28,7 @@ This patch adds:
2628 ssl/internal.h | 12 ++-
2729 ssl/ssl_key_share.cc | 111 +++++++++++++++++++++++++++-
2830 ssl/ssl_lib.cc | 16 +++-
29- ssl/ssl_test.cc | 19 ++++-
31+ ssl/ssl_test.cc | 24 + ++++-
3032 ssl/test/runner/basic_tests.go | 2 +
3133 ssl/test/runner/cbc_tests.go | 3 +
3234 ssl/test/runner/common.go | 2 +-
@@ -35,22 +37,22 @@ This patch adds:
3537 ssl/test/runner/extension_tests.go | 3 +-
3638 ssl/test/runner/key_update_tests.go | 6 +-
3739 tool/client.cc | 9 +++
38- 18 files changed, 245 insertions(+), 42 deletions(-)
40+ 18 files changed, 249 insertions(+), 43 deletions(-)
3941
4042diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h
41- index d8b86dcd2..6dd49ec36 100644
43+ index 10ad9bb14..3fe6fdec6 100644
4244--- a/crypto/obj/obj_dat.h
4345+++ b/crypto/obj/obj_dat.h
44- @@ -15,7 +15,7 @@
45- // This file is generated by crypto/obj/objects.go.
46+ @@ -16,7 +16,7 @@
4647
4748
49+ BSSL_NAMESPACE_BEGIN
4850- #define NUM_NID 971
4951+ #define NUM_NID 972
5052
5153 static const uint8_t kObjectData[] = {
5254 /* NID_rsadsi */
53- @@ -8799 ,6 +8799 ,8 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
55+ @@ -8800 ,6 +8800 ,8 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
5456 {"id-ml-dsa-87", "ML-DSA-87", NID_ML_DSA_87, 9, &kObjectData[6223], 0},
5557 {"id-alg-ml-kem-768", "ML-KEM-768", NID_ML_KEM_768, 9, &kObjectData[6232],
5658 0},
@@ -59,15 +61,15 @@ index d8b86dcd2..6dd49ec36 100644
5961 };
6062
6163 static const uint16_t kNIDsInShortNameOrder[] = {
62- @@ -8931 ,6 +8933 ,7 @@ static const uint16_t kNIDsInShortNameOrder[] = {
64+ @@ -8932 ,6 +8934 ,7 @@ static const uint16_t kNIDsInShortNameOrder[] = {
6365 18 /* OU */,
6466 749 /* Oakley-EC2N-3 */,
6567 750 /* Oakley-EC2N-4 */,
6668+ 971 /* P256Kyber768Draft00 */,
6769 9 /* PBE-MD2-DES */,
6870 168 /* PBE-MD2-RC2-64 */,
6971 10 /* PBE-MD5-DES */,
70- @@ -9854 ,6 +9857 ,7 @@ static const uint16_t kNIDsInLongNameOrder[] = {
72+ @@ -9855 ,6 +9858 ,7 @@ static const uint16_t kNIDsInLongNameOrder[] = {
7173 366 /* OCSP Nonce */,
7274 371 /* OCSP Service Locator */,
7375 180 /* OCSP Signing */,
@@ -111,18 +113,18 @@ index 83a1cf592..7265f15f6 100644
111113 #if defined(__cplusplus)
112114 } /* extern C */
113115diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
114- index ff68ba69e..0730e769a 100644
116+ index 3a2e6dc50..300848e0f 100644
115117--- a/include/openssl/ssl.h
116118+++ b/include/openssl/ssl.h
117- @@ -2550 ,6 +2550 ,7 @@ OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx);
119+ @@ -2579 ,6 +2579 ,7 @@ OPENSSL_EXPORT size_t SSL_CTX_get_num_tickets(const SSL_CTX *ctx);
118120 #define SSL_GROUP_X25519_MLKEM768 0x11ec
119121 #define SSL_GROUP_X25519_KYBER768_DRAFT00 0x6399
120122 #define SSL_GROUP_MLKEM1024 0x0202
121123+ #define SSL_GROUP_P256_KYBER768_DRAFT00 0xfe32
122124
123125 // SSL_CTX_set1_group_ids sets the preferred groups for |ctx| to |group_ids|.
124126 // Each element of |group_ids| should be a unique one of the |SSL_GROUP_*|
125- @@ -5964 ,6 +5965 ,20 @@ OPENSSL_EXPORT int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves);
127+ @@ -6195 ,6 +6196 ,20 @@ OPENSSL_EXPORT int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves);
126128 // SSL_set1_curves_list calls |SSL_set1_groups_list|.
127129 OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves);
128130
@@ -144,18 +146,18 @@ index ff68ba69e..0730e769a 100644
144146 // |SSL_get_negotiated_group| to return an unrecognized group. BoringSSL never
145147 // returns this value, but we define this constant for compatibility.
146148diff --git a/ssl/extensions.cc b/ssl/extensions.cc
147- index c5f90688c..e0514fed3 100644
149+ index 529226876..e2ed74d5f 100644
148150--- a/ssl/extensions.cc
149151+++ b/ssl/extensions.cc
150- @@ -101 ,6 +101 ,7 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) {
152+ @@ -106 ,6 +106 ,7 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) {
151153 static bool is_post_quantum_group(uint16_t id) {
152154 switch (id) {
153155 case SSL_GROUP_X25519_KYBER768_DRAFT00:
154156+ case SSL_GROUP_P256_KYBER768_DRAFT00:
155157 case SSL_GROUP_X25519_MLKEM768:
156158 case SSL_GROUP_MLKEM1024:
157159 return true;
158- @@ -2241 ,18 +2242 ,21 @@ bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id) {
160+ @@ -2413 ,18 +2414 ,21 @@ bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id) {
159161 if (!default_key_shares.TryPushBack(supported_group_list[0])) {
160162 return false;
161163 }
@@ -189,10 +191,10 @@ index c5f90688c..e0514fed3 100644
189191 selected_key_shares.emplace(default_key_shares);
190192 }
191193diff --git a/ssl/internal.h b/ssl/internal.h
192- index a69505b47..1f5ce51e6 100644
194+ index 4d86a6170..1c0d9f2fd 100644
193195--- a/ssl/internal.h
194196+++ b/ssl/internal.h
195- @@ -955 ,7 +955 ,7 @@ struct NamedGroup {
197+ @@ -913 ,7 +913 ,7 @@ struct NamedGroup {
196198 Span<const NamedGroup> NamedGroups();
197199
198200 // kNumNamedGroups is the number of supported groups.
@@ -201,7 +203,7 @@ index a69505b47..1f5ce51e6 100644
201203
202204 // DefaultSupportedGroupIds returns the list of IDs for the default groups that
203205 // are supported when the caller hasn't explicitly configured supported groups.
204- @@ -3388 ,6 +3388 ,11 @@ struct SSL_CONFIG {
206+ @@ -3512 ,6 +3512 ,11 @@ struct SSL_CONFIG {
205207 // permute_extensions is whether to permute extensions when sending messages.
206208 bool permute_extensions : 1;
207209
@@ -213,7 +215,7 @@ index a69505b47..1f5ce51e6 100644
213215 // aes_hw_override if set indicates we should override checking for aes
214216 // hardware support, and use the value in aes_hw_override_value instead.
215217 bool aes_hw_override : 1;
216- @@ -4015 ,6 +4020 ,11 @@ struct ssl_ctx_st : public bssl::RefCounted<ssl_ctx_st> {
218+ @@ -4149 ,6 +4154 ,11 @@ struct ssl_ctx_st : public bssl::RefCounted<ssl_ctx_st> {
217219 // permute_extensions is whether to permute extensions when sending messages.
218220 bool permute_extensions : 1;
219221
@@ -371,34 +373,34 @@ index d155b5527..4fb08906b 100644
371373 return nullptr;
372374 }
373375diff --git a/ssl/ssl_lib.cc b/ssl/ssl_lib.cc
374- index f64b103fb..fe5bb9bc7 100644
376+ index de4e79efc..4ca2e799d 100644
375377--- a/ssl/ssl_lib.cc
376378+++ b/ssl/ssl_lib.cc
377- @@ -397 ,6 +397 ,7 @@ ssl_ctx_st::ssl_ctx_st(const SSL_METHOD *ssl_method)
379+ @@ -385 ,6 +385 ,7 @@ ssl_ctx_st::ssl_ctx_st(const SSL_METHOD *ssl_method)
378380 channel_id_enabled(false),
379381 grease_enabled(false),
380382 permute_extensions(false),
381383+ disable_second_keyshare(false),
382384 allow_unknown_alpn_protos(false),
383385 false_start_allowed_without_alpn(false),
384386 handoff(false),
385- @@ -527 ,6 +528 ,7 @@ SSL *SSL_new(SSL_CTX *ctx) {
387+ @@ -517 ,6 +518 ,7 @@ SSL *SSL_new(SSL_CTX *ctx) {
386388 ssl->config->retain_only_sha256_of_client_certs =
387389 ctx->retain_only_sha256_of_client_certs;
388390 ssl->config->permute_extensions = ctx->permute_extensions;
389391+ ssl->config->disable_second_keyshare = ctx->disable_second_keyshare;
390392 ssl->config->aes_hw_override = ctx->aes_hw_override;
391393 ssl->config->aes_hw_override_value = ctx->aes_hw_override_value;
392394 ssl->config->compliance_policy = ctx->compliance_policy;
393- @@ -586 ,6 +588 ,7 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg)
395+ @@ -582 ,6 +584 ,7 @@ SSL_CONFIG::SSL_CONFIG(SSL *ssl_arg)
394396 jdk11_workaround(false),
395397 quic_use_legacy_codepoint(false),
396398 permute_extensions(false),
397399+ disable_second_keyshare(false),
398400 alps_use_new_codepoint(true) {
399401 assert(ssl);
400402 }
401- @@ -3331 ,6 +3334 ,15 @@ int SSL_set1_curves_list(SSL *ssl, const char *curves) {
403+ @@ -3372 ,6 +3375 ,15 @@ int SSL_set1_curves_list(SSL *ssl, const char *curves) {
402404 return SSL_set1_groups_list(ssl, curves);
403405 }
404406
@@ -414,7 +416,7 @@ index f64b103fb..fe5bb9bc7 100644
414416 namespace fips202205 {
415417
416418 // (References are to SP 800-52r2):
417- @@ -3342 ,7 +3354 ,9 @@ namespace fips202205 {
419+ @@ -3383 ,7 +3395 ,9 @@ namespace fips202205 {
418420 // Section 3.3.1
419421 // "The server shall be configured to only use cipher suites that are
420422 // composed entirely of NIST approved algorithms"
@@ -426,10 +428,10 @@ index f64b103fb..fe5bb9bc7 100644
426428 static const uint16_t kSigAlgs[] = {
427429 SSL_SIGN_RSA_PKCS1_SHA256,
428430diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc
429- index 779a2c37a..36a0cab3b 100644
431+ index 49adcaf72..6427ecf5d 100644
430432--- a/ssl/ssl_test.cc
431433+++ b/ssl/ssl_test.cc
432- @@ -506 ,6 +506 ,14 @@ static const CurveTest kCurveTests[] = {
434+ @@ -520 ,6 +520 ,14 @@ static const CurveTest kCurveTests[] = {
433435 "MLKEM1024:X25519MLKEM768",
434436 {SSL_GROUP_MLKEM1024, SSL_GROUP_X25519_MLKEM768},
435437 },
@@ -444,7 +446,7 @@ index 779a2c37a..36a0cab3b 100644
444446
445447 {
446448 "P-256:P-384:P-521:X25519",
447- @@ -668 ,7 +676 ,9 @@ TEST(SSLTest, CurveRules) {
449+ @@ -681 ,7 +689 ,9 @@ TEST(SSLTest, CurveRules) {
448450 }
449451
450452 TEST(SSLTest, DefaultCurves) {
@@ -455,7 +457,7 @@ index 779a2c37a..36a0cab3b 100644
455457 SSL_GROUP_SECP384R1};
456458
457459 // Test the group ID APIs.
458- @@ -1522 ,6 +1532 ,9 @@ static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
460+ @@ -1641 ,6 +1651 ,9 @@ static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
459461 static size_t GetClientHelloLen(uint16_t max_version, uint16_t session_version,
460462 size_t ticket_len) {
461463 bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
@@ -465,7 +467,19 @@ index 779a2c37a..36a0cab3b 100644
465467 bssl::UniquePtr<SSL_SESSION> session =
466468 CreateSessionWithTicket(session_version, ticket_len);
467469 if (!ctx || !session) {
468- @@ -6815,7 +6828,9 @@ TEST(SSLTest, ApplyHandoffRemovesUnsupportedCurves) {
470+ @@ -2315,7 +2328,10 @@ TEST(SSLTest, SetGroupIdsWithEqualPreference) {
471+ // Test that the SSL group flags are defaulted to zero when zero groups are set
472+ // (i.e. using the default groups).
473+ TEST(SSLTest, SetGroupIdsWithFlags_DefaultGroups) {
474+ - const uint16_t kDefaultGroups[] = {SSL_GROUP_X25519, SSL_GROUP_SECP256R1,
475+ + const uint16_t kDefaultGroups[] = {SSL_GROUP_X25519_MLKEM768,
476+ + SSL_GROUP_P256_KYBER768_DRAFT00,
477+ + SSL_GROUP_X25519,
478+ + SSL_GROUP_SECP256R1,
479+ SSL_GROUP_SECP384R1};
480+ const uint32_t kBogusFlags[] = {SSL_GROUP_FLAG_EQUAL_PREFERENCE_WITH_NEXT,
481+ SSL_GROUP_FLAG_EQUAL_PREFERENCE_WITH_NEXT, 0};
482+ @@ -7052,7 +7068,9 @@ TEST(SSLTest, ApplyHandoffRemovesUnsupportedCurves) {
469483
470484 // The default list of groups is used before applying the handoff.
471485 EXPECT_THAT(server->config->supported_group_list,
@@ -477,18 +491,18 @@ index 779a2c37a..36a0cab3b 100644
477491 ASSERT_TRUE(SSL_apply_handoff(server.get(), handoff));
478492 EXPECT_EQ(1u, server->config->supported_group_list.size());
479493diff --git a/ssl/test/runner/basic_tests.go b/ssl/test/runner/basic_tests.go
480- index 08de8fa5f..dd945fa49 100644
494+ index dfd17d5f1..054241404 100644
481495--- a/ssl/test/runner/basic_tests.go
482496+++ b/ssl/test/runner/basic_tests.go
483- @@ -129 ,6 +129 ,7 @@ read alert 1 0
497+ @@ -132 ,6 +132 ,7 @@ read alert 1 0
484498 `write hs 1
485499 read hs 3
486500 write hs 1
487501+ write hs 1
488502 read hs 2
489503 read hs 11
490504 read hs 12
491- @@ -1956 ,6 +1957 ,7 @@ read alert 1 0
505+ @@ -1975 ,6 +1976 ,7 @@ read alert 1 0
492506 write hs 2
493507 write hs 8
494508 write hs 11
@@ -518,10 +532,10 @@ index 6f49d12af..5e970b2b5 100644
518532 })
519533 }
520534diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
521- index 7dbde72c9..9d18d9d45 100644
535+ index 2d174832f..5056444de 100644
522536--- a/ssl/test/runner/common.go
523537+++ b/ssl/test/runner/common.go
524- @@ -2095 ,7 +2095 ,7 @@ type ProtocolBugs struct {
538+ @@ -2172 ,7 +2172 ,7 @@ type ProtocolBugs struct {
525539 FailIfHelloRetryRequested bool
526540
527541 // FailIfPostQuantumOffered will cause a server to reject a ClientHello if
@@ -531,10 +545,10 @@ index 7dbde72c9..9d18d9d45 100644
531545
532546 // ExpectKeyShares, if not nil, lists (in order) the curves that a ClientHello
533547diff --git a/ssl/test/runner/curve_tests.go b/ssl/test/runner/curve_tests.go
534- index 8e7b0a45b..556bf314d 100644
548+ index 9bc13115e..0d11da734 100644
535549--- a/ssl/test/runner/curve_tests.go
536550+++ b/ssl/test/runner/curve_tests.go
537- @@ -579 ,17 +579 ,6 @@ func addCurveTests() {
551+ @@ -581 ,17 +581 ,6 @@ func addCurveTests() {
538552 })
539553 }
540554
@@ -552,7 +566,7 @@ index 8e7b0a45b..556bf314d 100644
552566 for _, curve := range testCurves {
553567 if !isMLKEMGroup(curve.id) {
554568 continue
555- @@ -679 ,18 +668 ,19 @@ func addCurveTests() {
569+ @@ -681 ,18 +670 ,19 @@ func addCurveTests() {
556570 })
557571 }
558572
@@ -630,7 +644,7 @@ index 2cd3c10d3..f19d8d20a 100644
630644 clientAndServerHelloInitial += "write ccs\n"
631645 }
632646diff --git a/ssl/test/runner/extension_tests.go b/ssl/test/runner/extension_tests.go
633- index d6adb7759..4eb80aa8e 100644
647+ index 3087efe37..61a036d8b 100644
634648--- a/ssl/test/runner/extension_tests.go
635649+++ b/ssl/test/runner/extension_tests.go
636650@@ -16,6 +16,7 @@ package runner
@@ -651,7 +665,7 @@ index d6adb7759..4eb80aa8e 100644
651665
652666 // Test that illegal extensions in TLS 1.3 are rejected by the client if
653667diff --git a/ssl/test/runner/key_update_tests.go b/ssl/test/runner/key_update_tests.go
654- index 0a9053038..5ce709589 100644
668+ index f98528265..2068b1102 100644
655669--- a/ssl/test/runner/key_update_tests.go
656670+++ b/ssl/test/runner/key_update_tests.go
657671@@ -14,7 +14,10 @@
@@ -675,10 +689,10 @@ index 0a9053038..5ce709589 100644
675689
676690 // Test that shim responds to KeyUpdate requests.
677691diff --git a/tool/client.cc b/tool/client.cc
678- index 0839d4880..be9b79259 100644
692+ index 1653af8da..cab725d40 100644
679693--- a/tool/client.cc
680694+++ b/tool/client.cc
681- @@ -125 ,6 +125 ,11 @@ static const struct argument kArguments[] = {
695+ @@ -156 ,6 +156 ,11 @@ static const struct argument kArguments[] = {
682696 kBooleanArgument,
683697 "Permute extensions in handshake messages",
684698 },
@@ -688,19 +702,19 @@ index 0839d4880..be9b79259 100644
688702+ "Do not send a second keyshare",
689703+ },
690704 {
691- "-test-resumption", kBooleanArgument,
692- "Connect to the server twice. The first connection is closed once a "
693- @@ -538 ,6 +543 ,10 @@ bool Client(const std::vector<std::string> &args) {
705+ "-test-resumption",
706+ kBooleanArgument,
707+ @@ -637 ,6 +642 ,10 @@ bool Client(const std::vector<std::string> &args) {
694708 SSL_CTX_set_permute_extensions(ctx.get(), 1);
695709 }
696710
697711+ if (args_map.count("-disable-second-keyshare") != 0) {
698712+ SSL_CTX_use_second_keyshare(ctx.get(), 0);
699713+ }
700714+
715+ // Configure accepted roots.
701716 if (args_map.count("-root-certs") != 0) {
702717 if (!SSL_CTX_load_verify_locations(
703- ctx.get(), args_map["-root-certs"].c_str(), nullptr)) {
704718- -
705- 2.40.0
719+ 2.50.1 (Apple Git-155)
706720
0 commit comments