]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
ml-dsa(fips): add ML-DSA key generation self test
authorPauli <ppzgs1@gmail.com>
Fri, 24 Jan 2025 02:58:54 +0000 (13:58 +1100)
committerTomas Mraz <tomas@openssl.org>
Fri, 14 Feb 2025 09:46:04 +0000 (10:46 +0100)
Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26548)

include/openssl/self_test.h
providers/fips/self_test_data.inc
providers/fips/self_test_kats.c

index faec83ae3adb05191d42c6f7a1a50187488eb0b3..e66d40282cb03b52491cf0ef2d2779ecb7466d09 100644 (file)
@@ -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);
index f67a1bfea45a5c6a7d1d304efebed1c40ad69481..940d5b8d48ec9be13e1e436a2ff29957f1937f55 100644 (file)
@@ -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 */
index b46ee252c729ba12308bde18d0b3b93557d218bf..6377693de3ee9cd54ddb762a4d08b4d225512637 100644 (file)
@@ -13,6 +13,7 @@
 #include <openssl/core_names.h>
 #include <openssl/param_build.h>
 #include <openssl/rand.h>
+#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;