From: Pauli Date: Fri, 24 Jan 2025 02:58:54 +0000 (+1100) Subject: ml-dsa(fips): add ML-DSA key generation self test X-Git-Tag: openssl-3.5.0-alpha1~576 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=756527b89ccc82eabb7db3012e63f84e52da07ca;p=thirdparty%2Fopenssl.git ml-dsa(fips): add ML-DSA key generation self test Reviewed-by: Tim Hudson Reviewed-by: Shane Lontis Reviewed-by: Viktor Dukhovni (Merged from https://github.com/openssl/openssl/pull/26548) --- diff --git a/include/openssl/self_test.h b/include/openssl/self_test.h index faec83ae3ad..e66d40282cb 100644 --- a/include/openssl/self_test.h +++ b/include/openssl/self_test.h @@ -34,6 +34,7 @@ extern "C" { # define OSSL_SELF_TEST_TYPE_KAT_INTEGRITY "KAT_Integrity" # define OSSL_SELF_TEST_TYPE_KAT_CIPHER "KAT_Cipher" # define OSSL_SELF_TEST_TYPE_KAT_ASYM_CIPHER "KAT_AsymmetricCipher" +# define OSSL_SELF_TEST_TYPE_KAT_ASYM_KEYGEN "KAT_AsymmetricKeyGeneration" # define OSSL_SELF_TEST_TYPE_KAT_DIGEST "KAT_Digest" # define OSSL_SELF_TEST_TYPE_KAT_SIGNATURE "KAT_Signature" # define OSSL_SELF_TEST_TYPE_PCT_SIGNATURE "PCT_Signature" @@ -80,6 +81,7 @@ extern "C" { # define OSSL_SELF_TEST_DESC_KDF_TLS13_EXTRACT "TLS13_KDF_EXTRACT" # define OSSL_SELF_TEST_DESC_KDF_TLS13_EXPAND "TLS13_KDF_EXPAND" # define OSSL_SELF_TEST_DESC_RNG "RNG" +# define OSSL_SELF_TEST_DESC_KEYGEN_ML_DSA "ML-DSA" void OSSL_SELF_TEST_set_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK *cb, void *cbarg); diff --git a/providers/fips/self_test_data.inc b/providers/fips/self_test_data.inc index f67a1bfea45..940d5b8d48e 100644 --- a/providers/fips/self_test_data.inc +++ b/providers/fips/self_test_data.inc @@ -147,6 +147,13 @@ typedef struct st_kat_asym_cipher_st { size_t expected_len; } ST_KAT_ASYM_CIPHER; +typedef struct st_kat_keygen_st { + const char *desc; + const char *algorithm; + const ST_KAT_PARAM *keygen_params; + const ST_KAT_PARAM *expected_params; +} ST_KAT_ASYM_KEYGEN; + /*- DIGEST SELF TEST DATA */ static const unsigned char sha512_pt[] = "abc"; static const unsigned char sha512_digest[] = { @@ -2804,6 +2811,8 @@ static const unsigned char ml_dsa_65_sig[] = { * it fails the h_ones rejection test on iteration three * it successfully generates the signature on iteration four * Thus, it is an optimal self test in terms of iterations and coverage. + * + * Refer to FIPS 140-3 IG 10.3.A.15 for details of the testing requirements. */ static const unsigned char ml_dsa_65_msg[] = { 0x23, 0x37, 0x34, 0x37, 0x36, 0x38, 0x23 @@ -2920,3 +2929,20 @@ static const ST_KAT_SIGN st_kat_sign_tests[] = { }, #endif /* OPENSSL_NO_ML_DSA */ }; + + +#if !defined(OPENSSL_NO_ML_DSA) +static const ST_KAT_PARAM ml_dsa_keygen_params[] = { + ST_KAT_PARAM_OCTET(OSSL_PKEY_PARAM_ML_DSA_SEED, sig_kat_entropyin), + ST_KAT_PARAM_END() +}; + +static const ST_KAT_ASYM_KEYGEN st_kat_asym_keygen_tests[] = { + { + OSSL_SELF_TEST_DESC_KEYGEN_ML_DSA, + "ML-DSA-65", + ml_dsa_keygen_params, + ml_dsa_key + }, +}; +#endif /* !OPENSSL_NO_ML_DSA */ diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c index b46ee252c72..6377693de3e 100644 --- a/providers/fips/self_test_kats.c +++ b/providers/fips/self_test_kats.c @@ -13,6 +13,7 @@ #include #include #include +#include "crypto/ml_dsa.h" #include "crypto/rand.h" #include "internal/cryptlib.h" #include "internal/nelem.h" @@ -456,7 +457,7 @@ static int self_test_digest_sign(const ST_KAT_SIGN *t, EVP_PKEY_CTX *ctx = NULL; EVP_PKEY_CTX *fromctx = NULL; EVP_PKEY *pkey = NULL; - unsigned char sig[5000]; + unsigned char sig[MAX_ML_DSA_SIG_LEN]; BN_CTX *bnctx = NULL; size_t siglen = sizeof(sig); int digested = 0; @@ -566,6 +567,61 @@ err: return ret; } +/* + * Test that a deterministic key generation produces the correct key + */ +static int self_test_asym_keygen(const ST_KAT_ASYM_KEYGEN *t, OSSL_SELF_TEST *st, + OSSL_LIB_CTX *libctx) +{ + int ret = 0; + const ST_KAT_PARAM *expected; + OSSL_PARAM *key_params = NULL; + OSSL_PARAM_BLD *key_bld = NULL; + EVP_PKEY_CTX *key_ctx = NULL; + EVP_PKEY *key = NULL; + uint8_t out[MAX_ML_DSA_PRIV_LEN]; + size_t out_len = 0; + + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_KAT_ASYM_KEYGEN, t->desc); + + key_ctx = EVP_PKEY_CTX_new_from_name(libctx, t->algorithm, NULL); + if (key_ctx == NULL) + goto err; + if (t->keygen_params != NULL) { + key_bld = OSSL_PARAM_BLD_new(); + if (key_bld == NULL + || !add_params(key_bld, t->keygen_params, NULL)) + goto err; + key_params = OSSL_PARAM_BLD_to_param(key_bld); + if (key_params == NULL) + goto err; + } + if (EVP_PKEY_keygen_init(key_ctx) != 1 + || EVP_PKEY_CTX_set_params(key_ctx, key_params) != 1 + || EVP_PKEY_generate(key_ctx, &key) != 1) + goto err; + + for (expected = t->expected_params; expected->data != NULL; ++expected) { + if (expected->type != OSSL_PARAM_OCTET_STRING + || !EVP_PKEY_get_octet_string_param(key, expected->name, + out, sizeof(out), &out_len)) + goto err; + OSSL_SELF_TEST_oncorrupt_byte(st, out); + /* Check the KAT */ + if (out_len != expected->data_len + || memcmp(out, expected->data, expected->data_len) != 0) + goto err; + } + ret = 1; +err: + EVP_PKEY_free(key); + EVP_PKEY_CTX_free(key_ctx); + OSSL_PARAM_free(key_params); + OSSL_PARAM_BLD_free(key_bld); + OSSL_SELF_TEST_onend(st, ret); + return ret; +} + /* * Test a data driven list of KAT's for digest algorithms. * All tests are run regardless of if they fail or not. @@ -781,6 +837,17 @@ static int setup_main_random(OSSL_LIB_CTX *libctx) return 0; } +static int self_test_asym_keygens(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_asym_keygen_tests); ++i) { + if (!self_test_asym_keygen(&st_kat_asym_keygen_tests[i], st, libctx)) + ret = 0; + } + return ret; +} + /* * Run the algorithm KAT's. * Return 1 is successful, otherwise return 0. @@ -813,6 +880,8 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx) ret = 0; if (!self_test_kas(st, libctx)) ret = 0; + if (!self_test_asym_keygens(st, libctx)) + ret = 0; RAND_set0_private(libctx, saved_rand); return ret;