]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
slh-dsa: add a PCT for key import when in FIPS mode
authorPauli <ppzgs1@gmail.com>
Thu, 14 Aug 2025 04:57:19 +0000 (14:57 +1000)
committerNeil Horman <nhorman@openssl.org>
Fri, 29 Aug 2025 18:39:14 +0000 (14:39 -0400)
Fixes #28182

Co-Authored-By: slontis <shane.lontis@oracle.com>
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/28276)

(cherry picked from commit 79037022801d6496bb8e1a8a29c21236084c8588)

crypto/slh_dsa/slh_dsa_key.c
include/crypto/slh_dsa.h
providers/implementations/keymgmt/slh_dsa_kmgmt.c
test/slh_dsa_test.c

index d71d55c258292cf8727ec86c9279bdad3566e5c4..73c538acca7503351bdde5436c6d097ec1f31114 100644 (file)
@@ -76,6 +76,17 @@ static void slh_dsa_key_hash_dup(SLH_DSA_KEY *dst, const SLH_DSA_KEY *src)
         EVP_MAC_up_ref(src->hmac);
 }
 
+/**
+ * @brief Return the libctx associated with a SLH_DSA_KEY object
+ *
+ * @param key A SLH_DSA_KEY to extract the libctx from.
+ * @returns The new OSSL_LIB_CTX object on success, or NULL failure
+ */
+OSSL_LIB_CTX *ossl_slh_dsa_key_get0_libctx(const SLH_DSA_KEY *key)
+{
+    return key != NULL ? key->libctx : NULL;
+}
+
 /**
  * @brief Create a new SLH_DSA_KEY object
  *
@@ -235,6 +246,15 @@ int ossl_slh_dsa_key_pairwise_check(const SLH_DSA_KEY *key)
     return ret;
 }
 
+void ossl_slh_dsa_key_reset(SLH_DSA_KEY *key)
+{
+    key->pub = NULL;
+    if (key->has_priv) {
+        key->has_priv = 0;
+        OPENSSL_cleanse(key->priv, sizeof(key->priv));
+    }
+}
+
 /**
  * @brief Load a SLH_DSA key from raw data.
  *
@@ -293,9 +313,7 @@ int ossl_slh_dsa_key_fromdata(SLH_DSA_KEY *key, const OSSL_PARAM params[],
     key->pub = p;
     return 1;
  err:
-    key->pub = NULL;
-    key->has_priv = 0;
-    OPENSSL_cleanse(key->priv, priv_len);
+    ossl_slh_dsa_key_reset(key);
     return 0;
 }
 
index cf1e21215f9e7e2ba98432494a14c7eaf9e010d7..75b9286383093a753562a08d68cd659d06f90fc9 100644 (file)
 typedef struct slh_dsa_hash_ctx_st SLH_DSA_HASH_CTX;
 typedef struct slh_dsa_key_st SLH_DSA_KEY;
 
+__owur OSSL_LIB_CTX *ossl_slh_dsa_key_get0_libctx(const SLH_DSA_KEY *key);
 __owur SLH_DSA_KEY *ossl_slh_dsa_key_new(OSSL_LIB_CTX *libctx, const char *propq,
                                          const char *alg);
 void ossl_slh_dsa_key_free(SLH_DSA_KEY *key);
+void ossl_slh_dsa_key_reset(SLH_DSA_KEY *key);
 __owur SLH_DSA_KEY *ossl_slh_dsa_key_dup(const SLH_DSA_KEY *src, int selection);
 __owur int ossl_slh_dsa_key_equal(const SLH_DSA_KEY *key1, const SLH_DSA_KEY *key2,
                                   int selection);
index cd2ebea72abbfcbd2d8fe472f1779f7d4015452f..ee6aba0883a1e5d59898a30365718b91e1209904 100644 (file)
@@ -11,6 +11,7 @@
 #include <openssl/core_names.h>
 #include <openssl/param_build.h>
 #include <openssl/self_test.h>
+#include <openssl/proverr.h>
 #include "crypto/slh_dsa.h"
 #include "internal/fips.h"
 #include "internal/param_build_set.h"
 #include "prov/providercommon.h"
 #include "prov/provider_ctx.h"
 
+#ifdef FIPS_MODULE
+static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key,
+                                         SLH_DSA_HASH_CTX *ctx);
+#endif  /* FIPS_MODULE */
+
 static OSSL_FUNC_keymgmt_free_fn slh_dsa_free_key;
 static OSSL_FUNC_keymgmt_has_fn slh_dsa_has;
 static OSSL_FUNC_keymgmt_match_fn slh_dsa_match;
@@ -104,7 +110,7 @@ static int slh_dsa_validate(const void *key_data, int selection, int check_type)
 static int slh_dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
     SLH_DSA_KEY *key = keydata;
-    int include_priv;
+    int include_priv, res;
 
     if (!ossl_prov_is_running() || key == NULL)
         return 0;
@@ -113,7 +119,23 @@ static int slh_dsa_import(void *keydata, int selection, const OSSL_PARAM params[
         return 0;
 
     include_priv = ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0);
-    return ossl_slh_dsa_key_fromdata(key, params, include_priv);
+    res = ossl_slh_dsa_key_fromdata(key, params, include_priv);
+#ifdef FIPS_MODULE
+    /*
+     * FIPS 140-3 IG 10.3.A additional comment 1 mandates that a pairwise
+     * consistency check be undertaken on key import.  The required test
+     * is described in SP 800-56Ar3 5.6.2.1.4.
+     */
+    if (res > 0 && ossl_slh_dsa_key_has(key, OSSL_KEYMGMT_SELECT_KEYPAIR) > 0)
+        if (!slh_dsa_fips140_pairwise_test(key, NULL)) {
+            ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
+                           "explicit %s public key does not match private",
+                           ossl_slh_dsa_key_get_name(key));
+            ossl_slh_dsa_key_reset(key);
+            res = 0;
+        }
+#endif  /* FIPS_MODULE */
+    return res;
 }
 
 #define SLH_DSA_IMEXPORTABLE_PARAMETERS \
@@ -281,9 +303,8 @@ static void *slh_dsa_gen_init(void *provctx, int selection,
  * Refer to FIPS 140-3 IG 10.3.A Additional Comment 1
  * Perform a pairwise test for SLH_DSA by signing and verifying a signature.
  */
-static int slh_dsa_fips140_pairwise_test(SLH_DSA_HASH_CTX *ctx,
-                                         const SLH_DSA_KEY *key,
-                                         OSSL_LIB_CTX *lib_ctx)
+static int slh_dsa_fips140_pairwise_test(const SLH_DSA_KEY *key,
+                                         SLH_DSA_HASH_CTX *ctx)
 {
     int ret = 0;
     OSSL_SELF_TEST *st = NULL;
@@ -293,15 +314,25 @@ static int slh_dsa_fips140_pairwise_test(SLH_DSA_HASH_CTX *ctx,
     size_t msg_len = sizeof(msg);
     uint8_t *sig = NULL;
     size_t sig_len;
+    OSSL_LIB_CTX *lib_ctx;
+    int alloc_ctx = 0;
 
     /* During self test, it is a waste to do this test */
     if (ossl_fips_self_testing())
         return 1;
 
+    if (ctx == NULL) {
+        ctx = ossl_slh_dsa_hash_ctx_new(key);
+        if (ctx == NULL)
+            return 0;
+        alloc_ctx = 1;
+    }
+    lib_ctx = ossl_slh_dsa_key_get0_libctx(key);
+
     OSSL_SELF_TEST_get_callback(lib_ctx, &cb, &cb_arg);
     st = OSSL_SELF_TEST_new(cb, cb_arg);
     if (st == NULL)
-        return 0;
+        goto err;
 
     OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT,
                            OSSL_SELF_TEST_DESC_PCT_SLH_DSA);
@@ -322,6 +353,8 @@ static int slh_dsa_fips140_pairwise_test(SLH_DSA_HASH_CTX *ctx,
 
     ret = 1;
 err:
+    if (alloc_ctx)
+        ossl_slh_dsa_hash_ctx_free(ctx);
     OPENSSL_free(sig);
     OSSL_SELF_TEST_onend(st, ret);
     OSSL_SELF_TEST_free(st);
@@ -342,12 +375,12 @@ static void *slh_dsa_gen(void *genctx, const char *alg)
         return NULL;
     ctx = ossl_slh_dsa_hash_ctx_new(key);
     if (ctx == NULL)
-        return NULL;
+        goto err;
     if (!ossl_slh_dsa_generate_key(ctx, key, gctx->libctx,
                                    gctx->entropy, gctx->entropy_len))
         goto err;
 #ifdef FIPS_MODULE
-    if (!slh_dsa_fips140_pairwise_test(ctx, key, gctx->libctx)) {
+    if (!slh_dsa_fips140_pairwise_test(key, ctx)) {
         ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
         goto err;
     }
index eff9071937a26e7ae747802f267cb20e03f2183b..7b57787a1a1633f3297b01302ad8a5b130286fad 100644 (file)
@@ -183,14 +183,22 @@ static int slh_dsa_key_validate_failure_test(void)
      * Loading 128s private key data into a 128f algorithm will have an incorrect
      * public key.
      */
-    if (!TEST_ptr(key = slh_dsa_key_from_data("SLH-DSA-SHA2-128f",
-                                              slh_dsa_sha2_128s_0_keygen_priv,
-                                              sizeof(slh_dsa_sha2_128s_0_keygen_priv), 0)))
-        return 0;
-    if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL)))
-        goto end;
-    if (!TEST_int_eq(EVP_PKEY_pairwise_check(vctx), 0))
-        goto end;
+    key = slh_dsa_key_from_data("SLH-DSA-SHA2-128f",
+                                slh_dsa_sha2_128s_0_keygen_priv,
+                                sizeof(slh_dsa_sha2_128s_0_keygen_priv), 0);
+    if (OSSL_PROVIDER_available(lib_ctx, "fips")
+            && fips_provider_version_match(lib_ctx, ">3.5.2")) {
+        /* The new pairwise test should fail in fips mode */
+        if (!TEST_ptr_null(key))
+            goto end;
+    } else {
+        if (!TEST_ptr(key))
+            goto end;
+        if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(lib_ctx, key, NULL)))
+            goto end;
+        if (!TEST_int_eq(EVP_PKEY_pairwise_check(vctx), 0))
+            goto end;
+    }
     ret = 1;
 end:
     EVP_PKEY_CTX_free(vctx);