kex: Implement remaining hybrid ML-KEM methods

This builds on top of a9c8f94. The pure ML-KEM
code is now separated from the hybrid parts,
with the hybrid implementation generalized to
support NIST curves.

Signed-off-by: Pavol Žáčik <pzacik@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Pavol Žáčik
2025-11-18 13:36:25 +01:00
committed by Jakub Jelen
parent 7911580304
commit 0ef79018b3
21 changed files with 1494 additions and 793 deletions

View File

@@ -184,7 +184,8 @@ if (SSH_EXECUTABLE)
diffie-hellman-group1-sha1 diffie-hellman-group14-sha1 diffie-hellman-group14-sha256
diffie-hellman-group16-sha512 diffie-hellman-group18-sha512 diffie-hellman-group-exchange-sha1
diffie-hellman-group-exchange-sha256 ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521
sntrup761x25519-sha512@openssh.com sntrup761x25519-sha512 mlkem768x25519-sha256
sntrup761x25519-sha512@openssh.com sntrup761x25519-sha512
mlkem768x25519-sha256 mlkem768nistp256-sha256 mlkem1024nistp384-sha384
curve25519-sha256 curve25519-sha256@libssh.org
ssh-ed25519 ssh-ed25519-cert-v01@openssh.com ssh-rsa
ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521

View File

@@ -768,6 +768,38 @@ static void torture_algorithms_ecdh_mlkem768x25519_sha256(void **state)
}
#endif /* HAVE_MLKEM && defined(OPENSSH_MLKEM768X25519_SHA256) */
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM768NISTP256_SHA256)
static void torture_algorithms_ecdh_mlkem768nistp256_sha256(void **state)
{
struct torture_state *s = *state;
if (ssh_fips_mode()) {
skip();
}
test_algorithm(s->ssh.session,
"mlkem768nistp256-sha256",
NULL /*cipher*/,
NULL /*hmac*/);
}
#endif /* HAVE_MLKEM && defined(OPENSSH_MLKEM768NISTP256_SHA256) */
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM1024NISTP384_SHA384)
static void torture_algorithms_ecdh_mlkem1024nistp384_sha384(void **state)
{
struct torture_state *s = *state;
if (ssh_fips_mode()) {
skip();
}
test_algorithm(s->ssh.session,
"mlkem1024nistp384-sha384",
NULL /*cipher*/,
NULL /*hmac*/);
}
#endif /* HAVE_MLKEM && defined(OPENSSH_MLKEM1024NISTP384_SHA384) */
static void torture_algorithms_dh_group1(void **state) {
struct torture_state *s = *state;
@@ -1050,6 +1082,16 @@ int torture_run_tests(void) {
session_setup,
session_teardown),
#endif /* HAVE_MLKEM && defined(OPENSSH_MLKEM768X25519_SHA256) */
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM768NISTP256_SHA256)
cmocka_unit_test_setup_teardown(torture_algorithms_ecdh_mlkem768nistp256_sha256,
session_setup,
session_teardown),
#endif /* defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM768NISTP256_SHA256) */
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM1024NISTP384_SHA384)
cmocka_unit_test_setup_teardown(torture_algorithms_ecdh_mlkem1024nistp384_sha384,
session_setup,
session_teardown),
#endif /* defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM1024NISTP384_SHA384) */
#if defined(HAVE_ECC)
cmocka_unit_test_setup_teardown(torture_algorithms_ecdh_sha2_nistp256,
session_setup,

View File

@@ -307,21 +307,45 @@ static int torture_pkd_setup_ecdsa_521(void **state) {
#endif
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM768X25519_SHA256)
#define PKDTESTS_KEX_MLKEM768(f, client, kexcmd) \
#define PKDTESTS_KEX_MLKEM768X25519(f, client, kexcmd) \
f(client, rsa_mlkem768x25519_sha256, kexcmd("mlkem768x25519-sha256"), setup_rsa, teardown) \
f(client, ecdsa_256_mlkem768x25519_sha256, kexcmd("mlkem768x25519-sha256"), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_mlkem768x25519_sha256, kexcmd("mlkem768x25519-sha256"), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_mlkem768x25519_sha256, kexcmd("mlkem768x25519-sha256"), setup_ecdsa_521, teardown) \
f(client, ed25519_mlkem768x25519_sha256, kexcmd("mlkem768x25519-sha256"), setup_ed25519, teardown)
#else
#define PKDTESTS_KEX_MLKEM768(f, client, kexcmd)
#define PKDTESTS_KEX_MLKEM768X25519(f, client, kexcmd)
#endif
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM768NISTP256_SHA256)
#define PKDTESTS_KEX_MLKEM768NISTP256(f, client, kexcmd) \
f(client, rsa_mlkem768nistp256_sha256, kexcmd("mlkem768nistp256-sha256"), setup_rsa, teardown) \
f(client, ecdsa_256_mlkem768nistp256_sha256, kexcmd("mlkem768nistp256-sha256"), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_mlkem768nistp256_sha256, kexcmd("mlkem768nistp256-sha256"), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_mlkem768nistp256_sha256, kexcmd("mlkem768nistp256-sha256"), setup_ecdsa_521, teardown) \
f(client, ed25519_mlkem768nistp256_sha256, kexcmd("mlkem768nistp256-sha256"), setup_ed25519, teardown)
#else
#define PKDTESTS_KEX_MLKEM768NISTP256(f, client, kexcmd)
#endif
#if defined(HAVE_MLKEM) && defined(OPENSSH_MLKEM1024NISTP384_SHA384)
#define PKDTESTS_KEX_MLKEM1024NISTP384(f, client, kexcmd) \
f(client, rsa_mlkem1024nistp384_sha384, kexcmd("mlkem1024nistp384-sha384"), setup_rsa, teardown) \
f(client, ecdsa_256_mlkem1024nistp384_sha384, kexcmd("mlkem1024nistp384-sha384"), setup_ecdsa_256, teardown) \
f(client, ecdsa_384_mlkem1024nistp384_sha384, kexcmd("mlkem1024nistp384-sha384"), setup_ecdsa_384, teardown) \
f(client, ecdsa_521_mlkem1024nistp384_sha384, kexcmd("mlkem1024nistp384-sha384"), setup_ecdsa_521, teardown) \
f(client, ed25519_mlkem1024nistp384_sha384, kexcmd("mlkem1024nistp384-sha384"), setup_ed25519, teardown)
#else
#define PKDTESTS_KEX_MLKEM1024NISTP384(f, client, kexcmd)
#endif
#define PKDTESTS_KEX_COMMON(f, client, kexcmd) \
PKDTESTS_KEX_FIPS(f, client, kexcmd) \
PKDTESTS_KEX_SNTRUP761(f, client, kexcmd) \
PKDTESTS_KEX_SNTRUP761_OPENSSH(f, client, kexcmd) \
PKDTESTS_KEX_MLKEM768(f, client, kexcmd) \
PKDTESTS_KEX_MLKEM768X25519(f, client, kexcmd) \
PKDTESTS_KEX_MLKEM768NISTP256(f, client, kexcmd) \
PKDTESTS_KEX_MLKEM1024NISTP384(f, client, kexcmd) \
f(client, rsa_curve25519_sha256, kexcmd("curve25519-sha256"), setup_rsa, teardown) \
f(client, rsa_curve25519_sha256_libssh_org, kexcmd("curve25519-sha256@libssh.org"), setup_rsa, teardown) \
f(client, rsa_diffie_hellman_group14_sha1, kexcmd("diffie-hellman-group14-sha1"), setup_rsa, teardown) \

View File

@@ -339,6 +339,71 @@ static void torture_algorithm_aes128gcm_with_no_hmac_overlap(void **state)
test_algorithm_no_hmac_overlap(state, "aes128-gcm@openssh.com");
}
#ifdef HAVE_MLKEM
/*
* Check the self-compatibility of a given key exchange method.
*/
static void test_kex_self_compat(void **state, const char *kex)
{
struct test_server_st *tss = *state;
struct torture_state *s = NULL;
ssh_session session = NULL;
int rc;
assert_non_null(tss);
s = tss->state;
assert_non_null(s);
rc = start_server(state);
assert_int_equal(rc, 0);
rc = session_setup(state);
assert_int_equal(rc, 0);
session = s->ssh.session;
assert_non_null(session);
rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, kex);
assert_int_equal(rc, SSH_OK);
rc = ssh_connect(session);
assert_int_equal(rc, SSH_OK);
rc = ssh_userauth_publickey_auto(session, NULL, NULL);
assert_ssh_return_code(session, rc);
rc = session_teardown(state);
assert_int_equal(rc, 0);
rc = stop_server(state);
assert_int_equal(rc, 0);
}
static void torture_algorithm_mlkem768x25119_self_compat(void **state)
{
if (ssh_fips_mode()) {
skip();
}
test_kex_self_compat(state, "mlkem768x25519-sha256");
}
static void torture_algorithm_mlkem768nistp256_self_compat(void **state)
{
if (ssh_fips_mode()) {
skip();
}
test_kex_self_compat(state, "mlkem768nistp256-sha256");
}
static void torture_algorithm_mlkem1024nistp384_self_compat(void **state)
{
if (ssh_fips_mode()) {
skip();
}
test_kex_self_compat(state, "mlkem1024nistp384-sha384");
}
#endif /* HAVE_MLKEM */
int torture_run_tests(void)
{
int rc;
@@ -349,6 +414,14 @@ int torture_run_tests(void)
setup_temp_dir, teardown_temp_dir),
cmocka_unit_test_setup_teardown(torture_algorithm_aes128gcm_with_no_hmac_overlap,
setup_temp_dir, teardown_temp_dir),
#ifdef HAVE_MLKEM
cmocka_unit_test_setup_teardown(torture_algorithm_mlkem768x25119_self_compat,
setup_temp_dir, teardown_temp_dir),
cmocka_unit_test_setup_teardown(torture_algorithm_mlkem768nistp256_self_compat,
setup_temp_dir, teardown_temp_dir),
cmocka_unit_test_setup_teardown(torture_algorithm_mlkem1024nistp384_self_compat,
setup_temp_dir, teardown_temp_dir),
#endif /* HAVE_MLKEM */
};
ssh_init();

View File

@@ -53,6 +53,8 @@
#cmakedefine OPENSSH_SNTRUP761X25519_SHA512 1
#cmakedefine OPENSSH_SNTRUP761X25519_SHA512_OPENSSH_COM 1
#cmakedefine OPENSSH_MLKEM768X25519_SHA256 1
#cmakedefine OPENSSH_MLKEM768NISTP256_SHA256 1
#cmakedefine OPENSSH_MLKEM1024NISTP384_SHA384 1
#cmakedefine OPENSSH_SSH_ED25519 1
#cmakedefine OPENSSH_SSH_ED25519_CERT_V01_OPENSSH_COM 1
#cmakedefine OPENSSH_SSH_RSA 1

View File

@@ -284,6 +284,8 @@ static void torture_options_get_key_exchange(void **state)
#ifdef HAVE_MLKEM
assert_string_equal(value,
"mlkem768x25519-sha256,"
"mlkem768nistp256-sha256,"
"mlkem1024nistp384-sha384,"
"sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,"
"curve25519-sha256,curve25519-sha256@libssh.org,"
"ecdh-sha2-nistp256,ecdh-sha2-nistp384,"