Skip to content

Commit 03699c7

Browse files
dkosticclaude
andcommitted
feat(ssl): support ML-DSA as a TLS 1.3 signature scheme
Wire up draft-ietf-tls-mldsa (IANA code points 0x0904/0x0905/0x0906 for MLDSA44/65/87) through AWS-LC's libssl, backed by the existing PQDSA EVP_PKEY support in libcrypto. ML-DSA is TLS 1.3 only and is advertised in the default signing and verification sigalg lists; the per-sigalg gate in pkey_supports_algorithm keeps these entries from being selected on earlier protocol versions. - Add SSL_SIGN_MLDSA44/65/87 to the public header. - Add a new SSL_PKEY_PQDSA certificate slot. - Extend SSL_SIGNATURE_ALGORITHM with param_nid (replacing the EC-only curve field) so sigalg rows can constrain both EC curves and ML-DSA parameter sets. - Gate PQDSA to TLS 1.3 in pkey_supports_algorithm, and require the sigalg's param_nid to match EVP_PKEY_pqdsa_get_type(pkey). - Route PQDSA through the existing EVP_DigestSign/Verify path, which dispatches to sign_message/verify_message in pure mode. - Add MLDSA44/65/87 to kVerifySignatureAlgorithms and kSignSignatureAlgorithms so they're negotiated by default. Tests: - Add MLDSA test fixtures (cert + seed private key) from the IETF LAMPS WG examples accompanying draft-ietf-lamps-dilithium-certificates, and parameterized handshake tests covering success, TLS 1.2 rejection, and cross-variant sigalg mismatch. - Regenerate the golden ClientHello byte vectors in ssl_test.cc and bump kKeyShare1Offset by the corresponding 6 bytes. - Relax SSLTest.Padding to skip version/session combinations whose baseline ClientHello is now pushed past the 0xff boundary by the larger sigalg list. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7830af6 commit 03699c7

15 files changed

Lines changed: 963 additions & 20 deletions

include/openssl/ssl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,9 @@ OPENSSL_EXPORT int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response,
11491149
#define SSL_SIGN_RSA_PSS_RSAE_SHA384 0x0805
11501150
#define SSL_SIGN_RSA_PSS_RSAE_SHA512 0x0806
11511151
#define SSL_SIGN_ED25519 0x0807
1152+
#define SSL_SIGN_MLDSA44 0x0904
1153+
#define SSL_SIGN_MLDSA65 0x0905
1154+
#define SSL_SIGN_MLDSA87 0x0906
11521155

11531156
// SSL_SIGN_RSA_PKCS1_MD5_SHA1 is an internal signature algorithm used to
11541157
// specify raw RSASSA-PKCS1-v1_5 with an MD5/SHA-1 concatenation, as used in TLS

ssl/extensions.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,12 @@ static const uint16_t kVerifySignatureAlgorithms[] = {
299299
SSL_SIGN_RSA_PSS_RSAE_SHA512,
300300
SSL_SIGN_RSA_PKCS1_SHA512,
301301

302+
// ML-DSA (TLS 1.3 only; ignored in earlier versions by
303+
// pkey_supports_algorithm).
304+
SSL_SIGN_MLDSA44,
305+
SSL_SIGN_MLDSA65,
306+
SSL_SIGN_MLDSA87,
307+
302308
// For now, SHA-1 is still accepted but least preferable.
303309
SSL_SIGN_RSA_PKCS1_SHA1,
304310
};
@@ -323,6 +329,12 @@ static const uint16_t kSignSignatureAlgorithms[] = {
323329
SSL_SIGN_RSA_PSS_RSAE_SHA512,
324330
SSL_SIGN_RSA_PKCS1_SHA512,
325331

332+
// ML-DSA (TLS 1.3 only; ignored in earlier versions by
333+
// pkey_supports_algorithm).
334+
SSL_SIGN_MLDSA44,
335+
SSL_SIGN_MLDSA65,
336+
SSL_SIGN_MLDSA87,
337+
326338
// If the peer supports nothing else, sign with SHA-1.
327339
SSL_SIGN_ECDSA_SHA1,
328340
SSL_SIGN_RSA_PKCS1_SHA1,

ssl/internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2504,7 +2504,8 @@ bool tls12_check_peer_sigalg(const SSL_HANDSHAKE *hs, uint8_t *out_alert,
25042504
#define SSL_PKEY_RSA 0
25052505
#define SSL_PKEY_ECC 1
25062506
#define SSL_PKEY_ED25519 2
2507-
#define SSL_PKEY_SIZE 3
2507+
#define SSL_PKEY_PQDSA 3
2508+
#define SSL_PKEY_SIZE 4
25082509

25092510
struct CERT_PKEY {
25102511
UniquePtr<EVP_PKEY> privatekey;

ssl/ssl_cipher.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,8 @@ int ssl_get_certificate_slot_index(const EVP_PKEY *pkey) {
13281328
return SSL_PKEY_ECC;
13291329
case EVP_PKEY_ED25519:
13301330
return SSL_PKEY_ED25519;
1331+
case EVP_PKEY_PQDSA:
1332+
return SSL_PKEY_PQDSA;
13311333
default:
13321334
return -1;
13331335
}

ssl/ssl_common_test.cc

Lines changed: 409 additions & 0 deletions
Large diffs are not rendered by default.

ssl/ssl_common_test.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@ UniquePtr<X509> GetLeafRoot();
119119
UniquePtr<X509> GetED25519TestCertificate();
120120
UniquePtr<EVP_PKEY> GetED25519TestKey();
121121

122+
// Test fixtures sourced from draft-ietf-lamps-dilithium-certificates examples
123+
// (https://github.com/lamps-wg/dilithium-certificates/tree/main/examples).
124+
UniquePtr<X509> GetMLDSA44TestCertificate();
125+
UniquePtr<EVP_PKEY> GetMLDSA44TestKey();
126+
UniquePtr<X509> GetMLDSA65TestCertificate();
127+
UniquePtr<EVP_PKEY> GetMLDSA65TestKey();
128+
UniquePtr<X509> GetMLDSA87TestCertificate();
129+
UniquePtr<EVP_PKEY> GetMLDSA87TestKey();
130+
122131
bool ExpectSingleError(int lib, int reason);
123132

124133
UniquePtr<X509> X509FromBuffer(UniquePtr<CRYPTO_BUFFER> buffer);

ssl/ssl_encoding_test.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,14 @@ TEST(SSLTest, Padding) {
406406
GetClientHelloLen(versions.max_version, versions.session_version, 1);
407407
ASSERT_NE(base_len, 0u) << "Baseline length could not be sampled";
408408

409+
// If the baseline ClientHello is already in or past the padding range,
410+
// we cannot exercise the padding thresholds below. This happens when
411+
// the default extensions (e.g. sigalgs including ML-DSA) push the
412+
// unpadded ClientHello above 0xff bytes.
413+
if (base_len > kPaddingTests[0].input_len) {
414+
continue;
415+
}
416+
409417
for (const PaddingTest &test : kPaddingTests) {
410418
SCOPED_TRACE(test.input_len);
411419
ASSERT_LE(base_len, test.input_len) << "Baseline ClientHello too long";

ssl/ssl_privkey.cc

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ BSSL_NAMESPACE_BEGIN
2121

2222
bool ssl_is_key_type_supported(int key_type) {
2323
return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC ||
24-
key_type == EVP_PKEY_ED25519;
24+
key_type == EVP_PKEY_ED25519 || key_type == EVP_PKEY_PQDSA;
2525
}
2626

2727
static bool ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) {
@@ -61,7 +61,10 @@ static bool ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) {
6161
typedef struct {
6262
uint16_t sigalg;
6363
int pkey_type;
64-
int curve;
64+
// param_nid identifies the parameter set required for this algorithm: the EC
65+
// curve NID for ECDSA, or the ML-DSA parameter-set NID (NID_MLDSA44/65/87)
66+
// for PQDSA. NID_undef means no parameter-set constraint.
67+
int param_nid;
6568
const EVP_MD *(*digest_func)(void);
6669
bool is_rsa_pss;
6770
} SSL_SIGNATURE_ALGORITHM;
@@ -87,6 +90,10 @@ static const SSL_SIGNATURE_ALGORITHM kSignatureAlgorithms[] = {
8790
false},
8891

8992
{SSL_SIGN_ED25519, EVP_PKEY_ED25519, NID_undef, nullptr, false},
93+
94+
{SSL_SIGN_MLDSA44, EVP_PKEY_PQDSA, NID_MLDSA44, nullptr, false},
95+
{SSL_SIGN_MLDSA65, EVP_PKEY_PQDSA, NID_MLDSA65, nullptr, false},
96+
{SSL_SIGN_MLDSA87, EVP_PKEY_PQDSA, NID_MLDSA87, nullptr, false},
9097
};
9198

9299
static const SSL_SIGNATURE_ALGORITHM *get_signature_algorithm(uint16_t sigalg) {
@@ -141,9 +148,18 @@ static bool pkey_supports_algorithm(const SSL *ssl, EVP_PKEY *pkey,
141148

142149
// EC keys have a curve requirement.
143150
if (alg->pkey_type == EVP_PKEY_EC &&
144-
(alg->curve == NID_undef ||
151+
(alg->param_nid == NID_undef ||
145152
EC_GROUP_get_curve_name(
146-
EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) != alg->curve)) {
153+
EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey))) != alg->param_nid)) {
154+
return false;
155+
}
156+
}
157+
158+
// ML-DSA is only defined for TLS 1.3. The parameter-set NID on |alg| must
159+
// match the variant of the PQDSA key.
160+
if (alg->pkey_type == EVP_PKEY_PQDSA) {
161+
if (ssl_protocol_version(ssl) < TLS1_3_VERSION ||
162+
EVP_PKEY_pqdsa_get_type(pkey) != alg->param_nid) {
147163
return false;
148164
}
149165
}
@@ -603,6 +619,9 @@ static const SignatureAlgorithmName kSignatureAlgorithmNames[] = {
603619
{SSL_SIGN_RSA_PSS_RSAE_SHA384, "rsa_pss_rsae_sha384"},
604620
{SSL_SIGN_RSA_PSS_RSAE_SHA512, "rsa_pss_rsae_sha512"},
605621
{SSL_SIGN_ED25519, "ed25519"},
622+
{SSL_SIGN_MLDSA44, "mldsa44"},
623+
{SSL_SIGN_MLDSA65, "mldsa65"},
624+
{SSL_SIGN_MLDSA87, "mldsa87"},
606625
};
607626

608627
const char *SSL_get_signature_algorithm_name(uint16_t sigalg,

ssl/ssl_test.cc

Lines changed: 121 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -593,20 +593,21 @@ TEST(SSLTest, ClientHello) {
593593
0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00,
594594
0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00}},
595595
{TLS1_2_VERSION,
596-
{0x16, 0x03, 0x01, 0x00, 0x88, 0x01, 0x00, 0x00, 0x84, 0x03, 0x03, 0x00,
596+
{0x16, 0x03, 0x01, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x8a, 0x03, 0x03, 0x00,
597597
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598598
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599599
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0xcc, 0xa9,
600600
0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30, 0xc0, 0x09,
601601
0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x28, 0x00, 0x9c,
602-
0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x01, 0x00, 0x00, 0x39,
602+
0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x01, 0x00, 0x00, 0x3f,
603603
0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00,
604604
0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0b, 0x00,
605-
0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00,
606-
0x14, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05,
607-
0x01, 0x06, 0x03, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01}},
605+
0x02, 0x01, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00,
606+
0x1a, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05,
607+
0x01, 0x06, 0x03, 0x08, 0x06, 0x06, 0x01, 0x09, 0x04, 0x09, 0x05, 0x09,
608+
0x06, 0x02, 0x01}},
608609
{TLS1_3_VERSION,
609-
{0x16, 0x03, 0x01, 0x05, 0xb5, 0x01, 0x00, 0x05, 0xb1, 0x03, 0x03, 0x00,
610+
{0x16, 0x03, 0x01, 0x05, 0xbb, 0x01, 0x00, 0x05, 0xb7, 0x03, 0x03, 0x00,
610611
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611612
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612613
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -616,13 +617,13 @@ TEST(SSLTest, ClientHello) {
616617
0xcc, 0xa9, 0xcc, 0xa8, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x2c, 0xc0, 0x30,
617618
0xc0, 0x09, 0xc0, 0x13, 0xc0, 0x27, 0xc0, 0x0a, 0xc0, 0x14, 0xc0, 0x28,
618619
0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x35, 0x01, 0x00,
619-
0x05, 0x40, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00,
620+
0x05, 0x46, 0x00, 0x17, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00,
620621
0x0a, 0x00, 0x0e, 0x00, 0x0c, 0x11, 0xec, 0x11, 0xeb, 0x11, 0xed, 0x00,
621622
0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00,
622-
0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x08,
623+
0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, 0x04, 0x03, 0x08,
623624
0x04, 0x04, 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x06, 0x03, 0x08,
624-
0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x33, 0x04, 0xea, 0x04, 0xe8, 0x11,
625-
0xec, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625+
0x06, 0x06, 0x01, 0x09, 0x04, 0x09, 0x05, 0x09, 0x06, 0x02, 0x01, 0x00,
626+
0x33, 0x04, 0xea, 0x04, 0xe8, 0x11, 0xec, 0x04, 0xc0, 0x00, 0x00, 0x00,
626627
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
627628
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
628629
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -723,12 +724,12 @@ TEST(SSLTest, ClientHello) {
723724
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
724725
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
725726
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
726-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x20, 0x00,
727727
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
728+
0x00, 0x00, 0x1d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
728729
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
729-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x02, 0x01,
730-
0x01, 0x00, 0x2b, 0x00, 0x09, 0x08, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02,
731-
0x03, 0x01}},
730+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
731+
0x00, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x2b, 0x00, 0x09, 0x08,
732+
0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x03, 0x01}},
732733
};
733734

734735
for (const auto &t : kTests) {
@@ -757,7 +758,7 @@ TEST(SSLTest, ClientHello) {
757758
1 + 3 + // handshake message header
758759
2; // client_version
759760

760-
constexpr size_t kKeyShare1Offset = 195;
761+
constexpr size_t kKeyShare1Offset = 201;
761762
constexpr size_t kKeyShare1Size = 32 + MLKEM768_PUBLIC_KEY_BYTES;
762763
constexpr size_t kKeyShare2Offset = kKeyShare1Offset + kKeyShare1Size
763764
+ 2 // KeyShare 2 IANA ID
@@ -1934,6 +1935,111 @@ TEST_P(MultipleCertificateSlotTest, MissingPrivateKey) {
19341935
}
19351936

19361937

1938+
// ML-DSA TLS 1.3 signature-scheme tests (draft-ietf-tls-mldsa). These
1939+
// exercise the plumbing in ssl_privkey.cc / ssl_cipher.cc that wires
1940+
// EVP_PKEY_PQDSA into TLS 1.3 handshake signing and verification.
1941+
1942+
struct MLDSATestParams {
1943+
const char name[16];
1944+
uint16_t sigalg;
1945+
bssl::UniquePtr<X509> (*certificate)();
1946+
bssl::UniquePtr<EVP_PKEY> (*key)();
1947+
};
1948+
1949+
static const MLDSATestParams kMLDSATests[] = {
1950+
{"MLDSA44", SSL_SIGN_MLDSA44, GetMLDSA44TestCertificate,
1951+
GetMLDSA44TestKey},
1952+
{"MLDSA65", SSL_SIGN_MLDSA65, GetMLDSA65TestCertificate,
1953+
GetMLDSA65TestKey},
1954+
{"MLDSA87", SSL_SIGN_MLDSA87, GetMLDSA87TestCertificate,
1955+
GetMLDSA87TestKey},
1956+
};
1957+
1958+
class MLDSAHandshakeTest : public testing::TestWithParam<MLDSATestParams> {};
1959+
1960+
INSTANTIATE_TEST_SUITE_P(
1961+
MLDSA, MLDSAHandshakeTest, testing::ValuesIn(kMLDSATests),
1962+
[](const testing::TestParamInfo<MLDSATestParams> &info) {
1963+
return info.param.name;
1964+
});
1965+
1966+
TEST_P(MLDSAHandshakeTest, HandshakeSucceeds) {
1967+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
1968+
bssl::UniquePtr<SSL_CTX> server_ctx(
1969+
CreateContextWithCertificate(TLS_method(), GetParam().certificate(),
1970+
GetParam().key()));
1971+
ASSERT_TRUE(client_ctx);
1972+
ASSERT_TRUE(server_ctx);
1973+
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_3_VERSION));
1974+
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
1975+
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_3_VERSION));
1976+
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
1977+
1978+
const uint16_t sigalgs[] = {GetParam().sigalg};
1979+
ASSERT_TRUE(SSL_CTX_set_signing_algorithm_prefs(server_ctx.get(), sigalgs,
1980+
OPENSSL_ARRAY_SIZE(sigalgs)));
1981+
ASSERT_TRUE(SSL_CTX_set_verify_algorithm_prefs(client_ctx.get(), sigalgs,
1982+
OPENSSL_ARRAY_SIZE(sigalgs)));
1983+
1984+
bssl::UniquePtr<SSL> client, server;
1985+
ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(),
1986+
server_ctx.get()));
1987+
EXPECT_EQ(SSL_get_peer_signature_algorithm(client.get()), GetParam().sigalg);
1988+
}
1989+
1990+
TEST_P(MLDSAHandshakeTest, RejectedInTLS12) {
1991+
// ML-DSA is only defined for TLS 1.3. Forcing a TLS 1.2 handshake with an
1992+
// ML-DSA sigalg preference must not succeed.
1993+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
1994+
bssl::UniquePtr<SSL_CTX> server_ctx(
1995+
CreateContextWithCertificate(TLS_method(), GetParam().certificate(),
1996+
GetParam().key()));
1997+
ASSERT_TRUE(client_ctx);
1998+
ASSERT_TRUE(server_ctx);
1999+
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_2_VERSION));
2000+
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_2_VERSION));
2001+
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_2_VERSION));
2002+
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_2_VERSION));
2003+
2004+
const uint16_t sigalgs[] = {GetParam().sigalg};
2005+
ASSERT_TRUE(SSL_CTX_set_signing_algorithm_prefs(server_ctx.get(), sigalgs,
2006+
OPENSSL_ARRAY_SIZE(sigalgs)));
2007+
ASSERT_TRUE(SSL_CTX_set_verify_algorithm_prefs(client_ctx.get(), sigalgs,
2008+
OPENSSL_ARRAY_SIZE(sigalgs)));
2009+
2010+
bssl::UniquePtr<SSL> client, server;
2011+
EXPECT_FALSE(ConnectClientAndServer(&client, &server, client_ctx.get(),
2012+
server_ctx.get()));
2013+
}
2014+
2015+
TEST(MLDSAHandshakeTest, CrossVariantMismatchFails) {
2016+
// Server has an MLDSA-44 cert/key, but the client only advertises
2017+
// MLDSA-65 / MLDSA-87 for verification. No common sigalg => handshake
2018+
// must fail.
2019+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
2020+
bssl::UniquePtr<SSL_CTX> server_ctx(CreateContextWithCertificate(
2021+
TLS_method(), GetMLDSA44TestCertificate(), GetMLDSA44TestKey()));
2022+
ASSERT_TRUE(client_ctx);
2023+
ASSERT_TRUE(server_ctx);
2024+
ASSERT_TRUE(SSL_CTX_set_min_proto_version(client_ctx.get(), TLS1_3_VERSION));
2025+
ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION));
2026+
ASSERT_TRUE(SSL_CTX_set_min_proto_version(server_ctx.get(), TLS1_3_VERSION));
2027+
ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION));
2028+
2029+
const uint16_t server_sigalgs[] = {SSL_SIGN_MLDSA44};
2030+
ASSERT_TRUE(SSL_CTX_set_signing_algorithm_prefs(
2031+
server_ctx.get(), server_sigalgs, OPENSSL_ARRAY_SIZE(server_sigalgs)));
2032+
2033+
const uint16_t client_sigalgs[] = {SSL_SIGN_MLDSA65, SSL_SIGN_MLDSA87};
2034+
ASSERT_TRUE(SSL_CTX_set_verify_algorithm_prefs(
2035+
client_ctx.get(), client_sigalgs, OPENSSL_ARRAY_SIZE(client_sigalgs)));
2036+
2037+
bssl::UniquePtr<SSL> client, server;
2038+
EXPECT_FALSE(ConnectClientAndServer(&client, &server, client_ctx.get(),
2039+
server_ctx.get()));
2040+
}
2041+
2042+
19372043
struct MultiTransferReadWriteTestParams {
19382044
const char suite[50];
19392045
bool tls13;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MDQCAQAwCwYJYIZIAWUDBAMRBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
3+
GhscHR4f
4+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)