From 2ead3ab8ca7b9f50194bd79dcf422260f9af00db Mon Sep 17 00:00:00 2001 From: Pauli Date: Thu, 14 Aug 2025 14:57:19 +1000 Subject: [PATCH] slh-dsa: add a PCT for key import when in FIPS mode Fixes #28182 Co-Authored-By: slontis Reviewed-by: Neil Horman Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/28276) (cherry picked from commit 79037022801d6496bb8e1a8a29c21236084c8588) --- crypto/slh_dsa/slh_dsa_key.c | 24 +++++++-- include/crypto/slh_dsa.h | 2 + .../implementations/keymgmt/slh_dsa_kmgmt.c | 49 ++++++++++++++++--- test/slh_dsa_test.c | 24 ++++++--- 4 files changed, 80 insertions(+), 19 deletions(-) diff --git a/crypto/slh_dsa/slh_dsa_key.c b/crypto/slh_dsa/slh_dsa_key.c index d71d55c2582..73c538acca7 100644 --- a/crypto/slh_dsa/slh_dsa_key.c +++ b/crypto/slh_dsa/slh_dsa_key.c @@ -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; } diff --git a/include/crypto/slh_dsa.h b/include/crypto/slh_dsa.h index cf1e21215f9..75b92863830 100644 --- a/include/crypto/slh_dsa.h +++ b/include/crypto/slh_dsa.h @@ -23,9 +23,11 @@ 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); diff --git a/providers/implementations/keymgmt/slh_dsa_kmgmt.c b/providers/implementations/keymgmt/slh_dsa_kmgmt.c index cd2ebea72ab..ee6aba0883a 100644 --- a/providers/implementations/keymgmt/slh_dsa_kmgmt.c +++ b/providers/implementations/keymgmt/slh_dsa_kmgmt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "crypto/slh_dsa.h" #include "internal/fips.h" #include "internal/param_build_set.h" @@ -18,6 +19,11 @@ #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; } diff --git a/test/slh_dsa_test.c b/test/slh_dsa_test.c index eff9071937a..7b57787a1a1 100644 --- a/test/slh_dsa_test.c +++ b/test/slh_dsa_test.c @@ -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); -- 2.47.3