Skip to content

Commit f3e0e8d

Browse files
committed
feature: support for ML-DSA handshake signatures
1 parent def0552 commit f3e0e8d

11 files changed

+159
-15
lines changed

crypto/s2n_mldsa.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
#include "crypto/s2n_pkey.h"
1919
#include "utils/s2n_result.h"
2020

21+
#if S2N_LIBCRYPTO_SUPPORTS_MLDSA
22+
#define S2N_NID_MLDSA44 NID_MLDSA44
23+
#define S2N_NID_MLDSA65 NID_MLDSA65
24+
#define S2N_NID_MLDSA87 NID_MLDSA87
25+
#else
26+
#define S2N_NID_MLDSA44 NID_undef
27+
#define S2N_NID_MLDSA65 NID_undef
28+
#define S2N_NID_MLDSA87 NID_undef
29+
#endif
30+
2131
/*
2232
* The draft ML-DSA PKI RFC
2333
* (https://www.ietf.org/archive/id/draft-ietf-lamps-dilithium-certificates-07.html)

tests/features/S2N_LIBCRYPTO_SUPPORTS_MLDSA.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
int main()
1919
{
2020
int evp_pkey_id = EVP_PKEY_PQDSA;
21+
int nids[] = { NID_MLDSA44, NID_MLDSA65, NID_MLDSA87 };
2122
/* Required to calculate the mu hash for ML-DSA */
2223
EVP_PKEY_get_raw_public_key(NULL, NULL, NULL);
2324
return 0;

tests/testlib/s2n_testlib.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ S2N_RESULT s2n_connection_set_test_master_secret(struct s2n_connection *conn, co
116116
#define S2N_RSA_PSS_2048_SHA256_LEAF_KEY "../pems/rsa_pss_2048_sha256_leaf_key.pem"
117117
#define S2N_RSA_PSS_2048_SHA256_LEAF_CERT "../pems/rsa_pss_2048_sha256_leaf_cert.pem"
118118

119+
#define S2N_MLDSA87_KEY "../pems/mldsa/ML-DSA-87-seed.priv"
120+
#define S2N_MLDSA87_CERT "../pems/mldsa/ML-DSA-87.crt"
121+
119122
#define S2N_RSA_2048_SHA256_CLIENT_CERT "../pems/rsa_2048_sha256_client_cert.pem"
120123

121124
#define S2N_RSA_2048_SHA256_NO_DNS_SANS_CERT "../pems/rsa_2048_sha256_no_dns_sans_cert.pem"

tests/unit/s2n_auth_selection_test.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ int main(int argc, char **argv)
294294
EXPECT_SUCCESS(s2n_is_cert_type_valid_for_auth(conn, S2N_PKEY_TYPE_RSA));
295295
EXPECT_SUCCESS(s2n_is_cert_type_valid_for_auth(conn, S2N_PKEY_TYPE_RSA_PSS));
296296
EXPECT_SUCCESS(s2n_is_cert_type_valid_for_auth(conn, S2N_PKEY_TYPE_ECDSA));
297-
EXPECT_FAILURE(s2n_is_cert_type_valid_for_auth(conn, S2N_PKEY_TYPE_UNKNOWN));
297+
EXPECT_SUCCESS(s2n_is_cert_type_valid_for_auth(conn, S2N_PKEY_TYPE_UNKNOWN));
298298

299299
EXPECT_SUCCESS(s2n_connection_free(conn));
300300
}

tests/unit/s2n_handshake_test.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include "api/s2n.h"
2626
#include "crypto/s2n_fips.h"
27+
#include "crypto/s2n_mldsa.h"
2728
#include "crypto/s2n_rsa_pss.h"
2829
#include "s2n_test.h"
2930
#include "testlib/s2n_testlib.h"
@@ -44,6 +45,11 @@ struct s2n_async_pkey_op *pkey_op = NULL;
4445
int async_pkey_op_called = 0;
4546
int async_pkey_op_performed = 0;
4647

48+
static uint8_t s2n_trust_all_verify_host(const char *host_name, size_t len, void *data)
49+
{
50+
return 1;
51+
}
52+
4753
static int handle_async(struct s2n_connection *server_conn)
4854
{
4955
s2n_blocked_status server_blocked;
@@ -432,6 +438,69 @@ int main(int argc, char **argv)
432438

433439
s2n_disable_tls13_in_test();
434440
}
441+
442+
s2n_reset_tls13_in_test();
443+
444+
/* Test: ML-DSA cert */
445+
if (s2n_mldsa_is_supported()) {
446+
for (size_t verify = 0; verify <= 1; verify++) {
447+
for (size_t client_auth = 0; client_auth <= 1; client_auth++) {
448+
DEFER_CLEANUP(struct s2n_cert_chain_and_key *chain_and_key = NULL,
449+
s2n_cert_chain_and_key_ptr_free);
450+
EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&chain_and_key,
451+
S2N_MLDSA87_CERT, S2N_MLDSA87_KEY));
452+
453+
DEFER_CLEANUP(struct s2n_config *server_config = s2n_config_new(),
454+
s2n_config_ptr_free);
455+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(
456+
server_config, chain_and_key));
457+
EXPECT_SUCCESS(s2n_config_set_verify_host_callback(server_config,
458+
s2n_trust_all_verify_host, NULL));
459+
EXPECT_SUCCESS(s2n_config_set_verification_ca_location(server_config,
460+
S2N_MLDSA87_CERT, NULL));
461+
462+
DEFER_CLEANUP(struct s2n_config *client_config = s2n_config_new(),
463+
s2n_config_ptr_free);
464+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(
465+
client_config, chain_and_key));
466+
EXPECT_SUCCESS(s2n_config_set_verify_host_callback(client_config,
467+
s2n_trust_all_verify_host, NULL));
468+
EXPECT_SUCCESS(s2n_config_set_verification_ca_location(client_config,
469+
S2N_MLDSA87_CERT, NULL));
470+
471+
/* ML-DSA is only usable with TLS1.3 */
472+
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(server_config,
473+
"test_all_tls13"));
474+
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(client_config,
475+
"test_all_tls13"));
476+
477+
/* The hashing path for verify_after_sign is subtly different.
478+
* Make sure we test both paths.
479+
*/
480+
if (verify) {
481+
EXPECT_SUCCESS(s2n_config_set_verify_after_sign(server_config,
482+
S2N_VERIFY_AFTER_SIGN_ENABLED));
483+
}
484+
485+
/* Test both the async and sync paths */
486+
if (test_type == TEST_TYPE_ASYNC) {
487+
EXPECT_SUCCESS(s2n_config_set_async_pkey_callback(
488+
server_config, async_pkey_fn));
489+
}
490+
491+
/* Also test the client side use of ML-DSA */
492+
if (client_auth) {
493+
EXPECT_SUCCESS(s2n_config_set_client_auth_type(server_config,
494+
S2N_CERT_AUTH_REQUIRED));
495+
EXPECT_SUCCESS(s2n_config_set_client_auth_type(client_config,
496+
S2N_CERT_AUTH_REQUIRED));
497+
}
498+
499+
EXPECT_SUCCESS(test_cipher_preferences(server_config, client_config,
500+
chain_and_key, S2N_SIGNATURE_MLDSA));
501+
}
502+
}
503+
}
435504
}
436505

437506
/* Ensure that a handshake can be performed after all file descriptors are closed */

tls/s2n_auth_selection.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,14 +187,16 @@ int s2n_is_cert_type_valid_for_auth(struct s2n_connection *conn, s2n_pkey_type c
187187
POSIX_ENSURE_REF(conn);
188188
POSIX_ENSURE_REF(conn->secure);
189189
POSIX_ENSURE_REF(conn->secure->cipher_suite);
190+
s2n_authentication_method conn_auth_method = conn->secure->cipher_suite->auth_method;
190191

191-
s2n_authentication_method auth_method;
192-
POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type, &auth_method));
193-
194-
if (conn->secure->cipher_suite->auth_method != S2N_AUTHENTICATION_METHOD_SENTINEL) {
195-
S2N_ERROR_IF(auth_method != conn->secure->cipher_suite->auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED);
192+
/* TLS1.3 cipher suites do not specify an auth type */
193+
if (conn_auth_method == S2N_AUTHENTICATION_METHOD_SENTINEL) {
194+
return S2N_SUCCESS;
196195
}
197196

197+
s2n_authentication_method cert_auth_method = 0;
198+
POSIX_GUARD(s2n_get_auth_method_for_cert_type(cert_type, &cert_auth_method));
199+
POSIX_ENSURE(cert_auth_method == conn_auth_method, S2N_ERR_CERT_TYPE_UNSUPPORTED);
198200
return S2N_SUCCESS;
199201
}
200202

tls/s2n_security_policies.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,17 @@ const struct s2n_security_policy security_policy_test_all_rsa_kex = {
12151215
};
12161216

12171217
const struct s2n_security_policy security_policy_test_all_tls13 = {
1218+
.minimum_protocol_version = S2N_SSLv3,
1219+
.cipher_preferences = &cipher_preferences_test_all_tls13,
1220+
.kem_preferences = &kem_preferences_null,
1221+
.signature_preferences = &s2n_signature_preferences_all,
1222+
.ecc_preferences = &s2n_ecc_preferences_test_all,
1223+
.rules = {
1224+
[S2N_PERFECT_FORWARD_SECRECY] = true,
1225+
},
1226+
};
1227+
1228+
const struct s2n_security_policy security_policy_20200207 = {
12181229
.minimum_protocol_version = S2N_SSLv3,
12191230
.cipher_preferences = &cipher_preferences_test_all_tls13,
12201231
.kem_preferences = &kem_preferences_null,
@@ -1349,7 +1360,7 @@ struct s2n_security_policy_selection security_policy_selection[] = {
13491360
{ .version = "20190122", .security_policy = &security_policy_20190122, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
13501361
{ .version = "20190801", .security_policy = &security_policy_20190801, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
13511362
{ .version = "20190802", .security_policy = &security_policy_20190802, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
1352-
{ .version = "20200207", .security_policy = &security_policy_test_all_tls13, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
1363+
{ .version = "20200207", .security_policy = &security_policy_20200207, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
13531364
{ .version = "20201021", .security_policy = &security_policy_20201021, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
13541365
{ .version = "20210816", .security_policy = &security_policy_20210816, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },
13551366
{ .version = "20210816_GCM", .security_policy = &security_policy_20210816_gcm, .ecc_extension_required = 0, .pq_kem_extension_required = 0 },

tls/s2n_signature_scheme.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "api/s2n.h"
1919
#include "crypto/s2n_ecc_evp.h"
2020
#include "crypto/s2n_hash.h"
21+
#include "crypto/s2n_mldsa.h"
2122
#include "crypto/s2n_signature.h"
2223
#include "tls/s2n_connection.h"
2324
#include "utils/s2n_safety.h"
@@ -204,6 +205,35 @@ const struct s2n_signature_scheme s2n_rsa_pss_pss_sha512 = {
204205
.minimum_protocol_version = S2N_TLS12,
205206
};
206207

208+
/* ML-DSA: post-quantum signature schemes */
209+
210+
const struct s2n_signature_scheme s2n_mldsa44 = {
211+
.iana_value = TLS_SIGNATURE_SCHEME_MLDSA44,
212+
.iana_name = "mldsa44",
213+
.hash_alg = S2N_HASH_SHAKE256_64,
214+
.sig_alg = S2N_SIGNATURE_MLDSA,
215+
.libcrypto_nid = S2N_NID_MLDSA44,
216+
.minimum_protocol_version = S2N_TLS13,
217+
};
218+
219+
const struct s2n_signature_scheme s2n_mldsa65 = {
220+
.iana_value = TLS_SIGNATURE_SCHEME_MLDSA65,
221+
.iana_name = "mldsa65",
222+
.hash_alg = S2N_HASH_SHAKE256_64,
223+
.sig_alg = S2N_SIGNATURE_MLDSA,
224+
.libcrypto_nid = S2N_NID_MLDSA65,
225+
.minimum_protocol_version = S2N_TLS13,
226+
};
227+
228+
const struct s2n_signature_scheme s2n_mldsa87 = {
229+
.iana_value = TLS_SIGNATURE_SCHEME_MLDSA87,
230+
.iana_name = "mldsa87",
231+
.hash_alg = S2N_HASH_SHAKE256_64,
232+
.sig_alg = S2N_SIGNATURE_MLDSA,
233+
.libcrypto_nid = S2N_NID_MLDSA87,
234+
.minimum_protocol_version = S2N_TLS13,
235+
};
236+
207237
/* ALL signature schemes, including the legacy default s2n_rsa_pkcs1_md5_sha1 scheme.
208238
* New signature schemes must be added to this list.
209239
*/
@@ -225,6 +255,9 @@ const struct s2n_signature_scheme* const s2n_sig_scheme_pref_list_all[] = {
225255
&s2n_rsa_pss_pss_sha256,
226256
&s2n_rsa_pss_pss_sha384,
227257
&s2n_rsa_pss_pss_sha512,
258+
&s2n_mldsa44,
259+
&s2n_mldsa65,
260+
&s2n_mldsa87,
228261
};
229262

230263
const struct s2n_signature_preferences s2n_signature_preferences_all = {

tls/s2n_signature_scheme.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ extern const struct s2n_signature_scheme s2n_rsa_pss_rsae_sha256;
7070
extern const struct s2n_signature_scheme s2n_rsa_pss_rsae_sha384;
7171
extern const struct s2n_signature_scheme s2n_rsa_pss_rsae_sha512;
7272

73+
/* ML-DSA: post-quantum signature schemes */
74+
extern const struct s2n_signature_scheme s2n_mldsa44;
75+
extern const struct s2n_signature_scheme s2n_mldsa65;
76+
extern const struct s2n_signature_scheme s2n_mldsa87;
77+
7378
extern const struct s2n_signature_preferences s2n_signature_preferences_20240501;
7479
extern const struct s2n_signature_preferences s2n_signature_preferences_20230317;
7580
extern const struct s2n_signature_preferences s2n_signature_preferences_20140601;

tls/s2n_tls13_certificate_verify.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ int s2n_tls13_write_cert_verify_signature(struct s2n_connection *conn,
8585
POSIX_GUARD(s2n_hash_new(&message_hash));
8686
POSIX_GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg));
8787

88+
const struct s2n_pkey *pkey = conn->handshake_params.our_chain_and_key->private_key;
89+
POSIX_GUARD_RESULT(s2n_pkey_init_hash(pkey, chosen_sig_scheme->sig_alg, &message_hash));
90+
8891
DEFER_CLEANUP(struct s2n_stuffer unsigned_content = { 0 }, s2n_stuffer_free);
8992
POSIX_GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, conn->mode));
9093

@@ -184,17 +187,19 @@ int s2n_tls13_cert_read_and_verify_signature(struct s2n_connection *conn,
184187
POSIX_GUARD(s2n_tls13_generate_unsigned_cert_verify_content(conn, &unsigned_content, S2N_CLIENT));
185188
}
186189

187-
POSIX_GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg));
188-
POSIX_GUARD(s2n_hash_update(&message_hash, unsigned_content.blob.data,
189-
s2n_stuffer_data_available(&unsigned_content)));
190-
190+
struct s2n_pkey *pkey = NULL;
191191
if (conn->mode == S2N_CLIENT) {
192-
POSIX_GUARD(s2n_pkey_verify(&conn->handshake_params.server_public_key, chosen_sig_scheme->sig_alg,
193-
&message_hash, &signed_content));
192+
pkey = &conn->handshake_params.server_public_key;
194193
} else {
195-
POSIX_GUARD(s2n_pkey_verify(&conn->handshake_params.client_public_key, chosen_sig_scheme->sig_alg,
196-
&message_hash, &signed_content));
194+
pkey = &conn->handshake_params.client_public_key;
197195
}
198196

197+
POSIX_GUARD(s2n_hash_init(&message_hash, chosen_sig_scheme->hash_alg));
198+
POSIX_GUARD_RESULT(s2n_pkey_init_hash(pkey, chosen_sig_scheme->sig_alg, &message_hash));
199+
POSIX_GUARD(s2n_hash_update(&message_hash, unsigned_content.blob.data,
200+
s2n_stuffer_data_available(&unsigned_content)));
201+
202+
POSIX_GUARD(s2n_pkey_verify(pkey, chosen_sig_scheme->sig_alg,
203+
&message_hash, &signed_content));
199204
return 0;
200205
}

tls/s2n_tls_parameters.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@
158158
#define TLS_SIGNATURE_SCHEME_RSA_PSS_PSS_SHA384 0x080A
159159
#define TLS_SIGNATURE_SCHEME_RSA_PSS_PSS_SHA512 0x080B
160160

161+
/* ML-DSA: post-quantum signature schemes */
162+
#define TLS_SIGNATURE_SCHEME_MLDSA44 0x0904
163+
#define TLS_SIGNATURE_SCHEME_MLDSA65 0x0905
164+
#define TLS_SIGNATURE_SCHEME_MLDSA87 0x0906
165+
161166
#define TLS_SIGNATURE_SCHEME_LEN 2
162167
#define TLS_SIGNATURE_SCHEME_LIST_MAX_LEN 128
163168

0 commit comments

Comments
 (0)