From 52246c81217d2e0f1c126d1aa836925241fb654d Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Wed, 28 Oct 2026 08:30:18 +0800 Subject: [PATCH 1/3] Use NIST vector for FFDH FIPS self-test Add libspdm_dh_set_priv_key() to allow a fixed-key KAT (previously a pairwise-consistency test only). Vector from NIST ACVP-Server: KAS-FFC-SSC-Sp800-56Ar3 (ffdhe2048 domain parameters, RFC 7919). Signed-off-by: Jiewen Yao Assisted-by: GitHub Copilot:Claude Sonnet 5 Assisted-by: Claude Code:claude-sonnet-5-5 --- include/hal/library/cryptlib/cryptlib_dh.h | 16 ++ .../fips/libspdm_selftest_ffdh.c | 170 +++++++++++++----- os_stub/cryptlib_mbedtls/pk/dh.c | 58 +++++- os_stub/cryptlib_null/pk/dh.c | 18 ++ os_stub/cryptlib_openssl/pk/dh.c | 112 ++++++++++++ 5 files changed, 329 insertions(+), 45 deletions(-) diff --git a/include/hal/library/cryptlib/cryptlib_dh.h b/include/hal/library/cryptlib/cryptlib_dh.h index 778083ef68c..89756ac69d8 100644 --- a/include/hal/library/cryptlib/cryptlib_dh.h +++ b/include/hal/library/cryptlib/cryptlib_dh.h @@ -31,6 +31,22 @@ extern void *libspdm_dh_new_by_nid(size_t nid); **/ extern void libspdm_dh_free(void *dh_context); +#if LIBSPDM_FIPS_MODE +/** + * Sets the private key component into the established DH context. This API can be used for + * FIPS test. + * + * @param[in, out] dh_context Pointer to DH context being set. + * @param[in] priv_key Pointer to the private key buffer. + * @param[in] priv_key_size The size of private key buffer in bytes. + * + * @retval true DH private key component was set successfully. + * @retval false Invalid DH private key component. + **/ +extern bool libspdm_dh_set_priv_key(void *dh_context, const uint8_t *priv_key, + size_t priv_key_size); +#endif /* LIBSPDM_FIPS_MODE */ + /** * Generates DH public key. * diff --git a/library/spdm_crypt_lib/fips/libspdm_selftest_ffdh.c b/library/spdm_crypt_lib/fips/libspdm_selftest_ffdh.c index a33f86adae7..e8b789c0b2c 100644 --- a/library/spdm_crypt_lib/fips/libspdm_selftest_ffdh.c +++ b/library/spdm_crypt_lib/fips/libspdm_selftest_ffdh.c @@ -28,84 +28,166 @@ void libspdm_fips_selftest_ffdh(void *fips_selftest_context) } void *dh1; - void *dh2; - uint8_t ff_public_key1[256]; - size_t ff_public_key1_length; - uint8_t ff_public_key2[256]; - size_t ff_public_key2_length; uint8_t ff_key1[256]; size_t ff_key1_length; - uint8_t ff_key2[256]; - size_t ff_key2_length; - ff_public_key1_length = sizeof(ff_public_key1); - ff_public_key2_length = sizeof(ff_public_key2); ff_key1_length = sizeof(ff_key1); - ff_key2_length = sizeof(ff_key2); + + /* Test vector (private key, peer public key and shared secret) from the NIST + * ACVP-Server: KAS-FFC-SSC-Sp800-56Ar3/internalProjection.json, tgId 1 + * (domainParameterGenerationMode = ffdhe2048, scheme = dhEphem), tcId 1. + * The ffdhe2048 domain parameters are from RFC 7919. + * https://github.com/usnistgov/ACVP-Server/tree/master/gen-val/json-files/KAS-FFC-SSC-Sp800-56Ar3 + */ + /* self private key*/ + const uint8_t self_privkey[] = { + 0x71, 0x38, 0x0e, 0x69, 0x93, 0x3d, 0x9b, 0x7f, + 0x45, 0xf1, 0xca, 0x91, 0x89, 0x46, 0xee, 0x38, + 0xca, 0xf1, 0x2d, 0xba, 0xea, 0xe8, 0xab, 0x16, + 0x9b, 0x20, 0x5f, 0x2e, 0xbd, 0x9f, 0x43, 0x81, + 0x53, 0x79, 0x1c, 0x5c, 0x76, 0x84, 0x54, 0xbb, + 0x28, 0x0c, 0xd2, 0xcd, 0x9c, 0x73, 0x77, 0x79, + 0x47, 0xc9, 0x51, 0x56, 0x2e, 0x68, 0x52, 0x9f, + 0xd3, 0x21, 0xc3, 0x33, 0xc0, 0x00, 0x55, 0xb0, + 0xf5, 0xfe, 0xff, 0xd1, 0xb0, 0xa0, 0xa2, 0xcc, + 0xc5, 0x13, 0xe9, 0x74, 0x13, 0x32, 0xce, 0x9a, + 0x38, 0xe6, 0x45, 0x01, 0x93, 0x95, 0x16, 0x41, + 0x62, 0x46, 0x7e, 0x41, 0xc0, 0x80, 0xe5, 0x99, + 0xbd, 0x23, 0xf2, 0x9d, 0xf9, 0x8c, 0xe5, 0xba, + 0x18, 0x85, 0x8d, 0xb7, 0x05, 0x36, 0x3a, 0x6a, + 0x5a, 0x2f, 0x4e, 0xf7, 0x7a, 0x20, 0x52, 0x17, + 0x54, 0x6e, 0xaa, 0x29, 0x58, 0x35, 0x31, 0xda, + 0xde, 0xdc, 0xdd, 0x21, 0x87, 0x29, 0x63, 0x2c, + 0x43, 0xa1, 0x35, 0x40, 0x91, 0x3f, 0xdf, 0xa1, + 0x08, 0xca, 0x8f, 0x0c, 0xbb, 0xb0, 0xb9, 0x58, + 0x08, 0x1b, 0x40, 0xae, 0x20, 0xd6, 0x43, 0x71, + 0x93, 0xb8, 0x7e, 0x21, 0x0c, 0x8a, 0x22, 0x75, + 0xa1, 0x22, 0xe0, 0xee, 0xb9, 0xe2, 0xb2, 0x28, + 0xed, 0x16, 0xf0, 0x69, 0xc5, 0xe5, 0x90, 0xb7, + 0x34, 0x73, 0x12, 0xb2, 0x85, 0xf8, 0xbb, 0xea, + 0x79, 0x10, 0xe7, 0xb7, 0xee, 0xef, 0x72, 0x02, + 0x53, 0x94, 0x67, 0xd7, 0x69, 0xb4, 0xa8, 0x32, + 0xda, 0x59, 0x3c, 0x25, 0x4e, 0xce, 0xe9, 0xb4, + 0x40, 0xa3, 0xa8, 0x2b, 0xf7, 0xf2, 0xee, 0x44, + 0xb6, 0x90, 0x5c, 0xda, 0x7f, 0xdf, 0xd6, 0xe3, + 0x52, 0xa2, 0xd5, 0xac, 0xd3, 0x92, 0x46, 0x18, + 0x38, 0x80, 0x40, 0x71, 0x2d, 0x5b, 0xdb, 0xcb, + 0xc5, 0xfe, 0x5a, 0x20, 0x04, 0x8e, 0xf0, 0x5c + }; + + /* peer public key*/ + const uint8_t peer_public[] = { + 0xd1, 0x5b, 0x21, 0x74, 0xdc, 0x6b, 0x2d, 0x45, + 0xf0, 0xd5, 0xef, 0x1d, 0xe4, 0xd9, 0x09, 0x74, + 0x95, 0x01, 0x87, 0x06, 0x32, 0xf1, 0xd4, 0x1b, + 0x6a, 0x48, 0x3a, 0x57, 0x03, 0x3c, 0x37, 0x87, + 0x2b, 0xd5, 0x8c, 0x47, 0xd8, 0x40, 0x58, 0x83, + 0xea, 0x95, 0x67, 0x37, 0xea, 0xef, 0xff, 0xa3, + 0x66, 0x96, 0x2a, 0x60, 0x82, 0xc7, 0x21, 0x48, + 0xa7, 0xca, 0x52, 0x1d, 0x9e, 0xbc, 0xb8, 0xf2, + 0xe6, 0x1b, 0x3c, 0xa1, 0x72, 0x0e, 0x0b, 0x08, + 0x4c, 0x29, 0x31, 0xf0, 0x61, 0xeb, 0xf6, 0x17, + 0x66, 0x47, 0x1d, 0xc8, 0x20, 0x18, 0xb1, 0xb1, + 0x87, 0x3f, 0x5e, 0xf9, 0xf1, 0x4b, 0xa8, 0x66, + 0x5a, 0xc9, 0x1e, 0xb1, 0xfc, 0xdf, 0x11, 0xa4, + 0x44, 0x25, 0xb3, 0xb4, 0x17, 0x7f, 0x8a, 0xe4, + 0x71, 0x7a, 0x98, 0xe5, 0xb9, 0xd3, 0xf9, 0x57, + 0x08, 0x57, 0xa1, 0xd2, 0x30, 0xc4, 0x0e, 0xef, + 0x15, 0xbd, 0x3e, 0x96, 0xf4, 0x68, 0x30, 0xee, + 0xb9, 0x95, 0xe6, 0xb8, 0x14, 0xda, 0x23, 0x20, + 0x5d, 0xd6, 0xa1, 0x40, 0x8a, 0xd4, 0x89, 0x26, + 0x10, 0xd2, 0x60, 0x81, 0x3a, 0x2b, 0x4b, 0x9e, + 0xa3, 0x8c, 0xe8, 0xf8, 0x25, 0x0c, 0x5d, 0xb3, + 0x7b, 0x20, 0x26, 0x37, 0x5e, 0xda, 0x1a, 0x8c, + 0xba, 0x43, 0x9f, 0x63, 0xd9, 0x60, 0x08, 0xf6, + 0x25, 0xb5, 0x6d, 0x08, 0x27, 0x5e, 0x6e, 0x77, + 0x3e, 0x9d, 0xee, 0x43, 0x5b, 0x9d, 0x0a, 0x2e, + 0x83, 0x1d, 0x02, 0xcd, 0x03, 0xaa, 0x5d, 0x9e, + 0xba, 0xa7, 0xfc, 0x75, 0x2c, 0x75, 0xb3, 0x17, + 0x9f, 0xa4, 0x3d, 0x4e, 0xe8, 0x99, 0x45, 0xdc, + 0x2c, 0x44, 0x01, 0x7c, 0x7c, 0x9a, 0xbc, 0xd4, + 0xa2, 0x10, 0x03, 0xb9, 0x82, 0xc4, 0xbd, 0x39, + 0x8d, 0x2c, 0x22, 0x8e, 0x46, 0x89, 0x70, 0x45, + 0x18, 0x05, 0x66, 0x25, 0x51, 0x7b, 0x50, 0xad + }; + + /* expected ffdh common secret*/ + const uint8_t expected_ffdh_secret[] = { + 0x5d, 0x52, 0xa8, 0x86, 0x7a, 0x2b, 0x18, 0xfc, + 0x49, 0x24, 0x29, 0xe6, 0xb7, 0x8a, 0x36, 0x6e, + 0x4a, 0x9a, 0xcf, 0xc7, 0x6c, 0xd5, 0x00, 0xb9, + 0x2e, 0x99, 0x3f, 0x1e, 0xbe, 0x29, 0x44, 0x5f, + 0x39, 0x4f, 0x34, 0xe4, 0x89, 0x3a, 0x1e, 0x39, + 0x01, 0x86, 0x24, 0xa5, 0xaf, 0x0b, 0x27, 0xb6, + 0x65, 0xc5, 0xa8, 0xf1, 0x95, 0x7e, 0x30, 0x43, + 0xd3, 0x3f, 0x13, 0xdd, 0xda, 0x80, 0x8e, 0x80, + 0x24, 0xe2, 0x0d, 0xfd, 0xcc, 0xfc, 0xe8, 0x0c, + 0x9d, 0xe6, 0x5d, 0x5c, 0xa1, 0x8c, 0x76, 0x28, + 0x28, 0xe3, 0xa9, 0x04, 0x4e, 0x97, 0xbf, 0xa0, + 0x51, 0x00, 0x79, 0x72, 0xab, 0x20, 0x03, 0xc5, + 0xec, 0x00, 0xb7, 0xe6, 0xd2, 0x9d, 0xea, 0x98, + 0xe1, 0x1e, 0x0e, 0x85, 0x40, 0x54, 0x77, 0xcb, + 0xbf, 0x92, 0x19, 0xc0, 0x18, 0xbd, 0xa9, 0x19, + 0x76, 0x57, 0xf1, 0x39, 0xe7, 0x5b, 0xa1, 0x6a, + 0x6c, 0x68, 0xbb, 0xfa, 0x65, 0x4b, 0xc3, 0xd4, + 0x5b, 0x52, 0xea, 0x06, 0xe7, 0xd6, 0x5b, 0xcb, + 0x6d, 0xcb, 0x35, 0xe6, 0xa0, 0x59, 0x41, 0x93, + 0x8d, 0x0d, 0x19, 0x5f, 0x4f, 0xd1, 0xc1, 0x2b, + 0xdc, 0x18, 0x4c, 0x10, 0x4b, 0xf9, 0x78, 0x79, + 0xa2, 0x5b, 0x69, 0x84, 0x7b, 0x97, 0x3a, 0xad, + 0x93, 0x35, 0x88, 0xeb, 0xa9, 0x1e, 0x41, 0x4a, + 0x0e, 0xe5, 0x16, 0x92, 0x59, 0x69, 0x1c, 0xb3, + 0xfe, 0x55, 0x1f, 0xe8, 0xa7, 0x48, 0xd3, 0xf9, + 0x3e, 0xd3, 0x23, 0xd0, 0x18, 0x88, 0xbc, 0xa0, + 0xc8, 0x7a, 0xeb, 0xd0, 0xe3, 0xbb, 0xb4, 0x8f, + 0x68, 0x36, 0xe4, 0x6d, 0x55, 0x58, 0xf2, 0x88, + 0x9e, 0xaa, 0xb8, 0x68, 0x04, 0xc6, 0x8c, 0x15, + 0x09, 0x24, 0x3c, 0x63, 0xa2, 0x4d, 0xde, 0xff, + 0x05, 0x66, 0xff, 0x72, 0x6a, 0xd3, 0x38, 0x5a, + 0xdd, 0x44, 0xc8, 0x11, 0xcb, 0x09, 0xb4, 0x6f + }; dh1 = libspdm_dh_new_by_nid(LIBSPDM_CRYPTO_NID_FFDHE2048); if (dh1 == NULL) { - LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH gen dh1 failed \n")); - result = false; - goto update; - } - - dh2 = libspdm_dh_new_by_nid(LIBSPDM_CRYPTO_NID_FFDHE2048); - if (dh2 == NULL) { - LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH gen dh2 failed \n")); - libspdm_dh_free(dh1); + LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH new failed \n")); result = false; goto update; } - result = libspdm_dh_generate_key(dh1, ff_public_key1, &ff_public_key1_length); - if (!result || ff_public_key1_length != 256) { - LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH generate key1 failed \n")); + result = libspdm_dh_set_priv_key(dh1, self_privkey, sizeof(self_privkey)); + if (!result) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH set private key failed \n")); libspdm_dh_free(dh1); - libspdm_dh_free(dh2); result = false; goto update; } - result = libspdm_dh_generate_key(dh2, ff_public_key2, &ff_public_key2_length); - if (!result || ff_public_key2_length != 256) { - LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH generate key2 failed \n")); - libspdm_dh_free(dh1); - libspdm_dh_free(dh2); - result = false; - goto update; - } - - result = libspdm_dh_compute_key(dh1, ff_public_key2, ff_public_key2_length, + result = libspdm_dh_compute_key(dh1, peer_public, sizeof(peer_public), ff_key1, &ff_key1_length); - if (!result || ff_key1_length != 256) { + if (!result) { LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH compute key failed \n")); libspdm_dh_free(dh1); - libspdm_dh_free(dh2); result = false; goto update; } - result = libspdm_dh_compute_key(dh2, ff_public_key1, ff_public_key1_length, - ff_key2, &ff_key2_length); - if (!result || ff_key2_length != 256) { - LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH compute key failed \n")); + /*KAT test*/ + if (ff_key1_length != sizeof(expected_ffdh_secret)) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH KAT failed \n")); libspdm_dh_free(dh1); - libspdm_dh_free(dh2); result = false; goto update; } - if (!libspdm_consttime_is_mem_equal(ff_key1, ff_key2, ff_key1_length)) { - LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH self_test failed \n")); + if (!libspdm_consttime_is_mem_equal(ff_key1, expected_ffdh_secret, + sizeof(expected_ffdh_secret))) { + LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "FFDH KAT failed \n")); libspdm_dh_free(dh1); - libspdm_dh_free(dh2); result = false; goto update; } libspdm_dh_free(dh1); - libspdm_dh_free(dh2); update: /* mark it as tested*/ diff --git a/os_stub/cryptlib_mbedtls/pk/dh.c b/os_stub/cryptlib_mbedtls/pk/dh.c index 97537d9de30..472de02847b 100644 --- a/os_stub/cryptlib_mbedtls/pk/dh.c +++ b/os_stub/cryptlib_mbedtls/pk/dh.c @@ -1,6 +1,6 @@ /** * Copyright Notice: - * Copyright 2021-2024 DMTF. All rights reserved. + * Copyright 2021-2026 DMTF. All rights reserved. * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md **/ @@ -112,6 +112,62 @@ void libspdm_dh_free(void *dh_context) free_pool(dh_context); } +#if LIBSPDM_FIPS_MODE +/** + * Checks the private key X of the DH context: 1 <= X < q, where q = (P - 1) / 2 because the + * RFC 7919 groups are safe primes. This is the q-known range check of OpenSSL + * ossl_ffc_validate_private_key(), without the 2^length clipping of named groups. + * + * @retval true The private key is in range. + * @retval false The private key is out of range. + **/ +static bool libspdm_dh_check_priv_key(mbedtls_dhm_context *ctx) +{ + mbedtls_mpi q; + bool result; + + mbedtls_mpi_init(&q); + result = mbedtls_mpi_sub_int(&q, &ctx->MBEDTLS_PRIVATE(P), 1) == 0 && + mbedtls_mpi_shift_r(&q, 1) == 0 && + mbedtls_mpi_cmp_int(&ctx->MBEDTLS_PRIVATE(X), 1) >= 0 && + mbedtls_mpi_cmp_mpi(&ctx->MBEDTLS_PRIVATE(X), &q) < 0; + mbedtls_mpi_free(&q); + + return result; +} + +/** + * Sets the private key component into the established DH context. This API can be used for + * FIPS test. + * + * @param[in, out] dh_context Pointer to DH context being set. + * @param[in] priv_key Pointer to the private key buffer. + * @param[in] priv_key_size The size of private key buffer in bytes. + * + * @retval true DH private key component was set successfully. + * @retval false Invalid DH private key component. + **/ +bool libspdm_dh_set_priv_key(void *dh_context, const uint8_t *priv_key, + size_t priv_key_size) +{ + mbedtls_dhm_context *ctx; + + if (dh_context == NULL || priv_key == NULL || priv_key_size == 0) { + return false; + } + + ctx = dh_context; + if (mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(X), priv_key, priv_key_size) != 0 || + !libspdm_dh_check_priv_key(ctx)) { + mbedtls_mpi_free(&ctx->MBEDTLS_PRIVATE(X)); + mbedtls_mpi_init(&ctx->MBEDTLS_PRIVATE(X)); + return false; + } + + return true; +} +#endif /* LIBSPDM_FIPS_MODE */ + /** * Generates DH parameter. * diff --git a/os_stub/cryptlib_null/pk/dh.c b/os_stub/cryptlib_null/pk/dh.c index 544b20185f6..5b81820d466 100644 --- a/os_stub/cryptlib_null/pk/dh.c +++ b/os_stub/cryptlib_null/pk/dh.c @@ -41,6 +41,24 @@ void libspdm_dh_free(void *dh_context) LIBSPDM_ASSERT(false); } +/** + * Sets the private key component into the established DH context. This API can be used for + * FIPS test. + * + * @param[in, out] dh_context Pointer to DH context being set. + * @param[in] priv_key Pointer to the private key buffer. + * @param[in] priv_key_size The size of private key buffer in bytes. + * + * @retval true DH private key component was set successfully. + * @retval false Invalid DH private key component. + **/ +bool libspdm_dh_set_priv_key(void *dh_context, const uint8_t *priv_key, + size_t priv_key_size) +{ + LIBSPDM_ASSERT(false); + return false; +} + /** * Generates DH parameter. * diff --git a/os_stub/cryptlib_openssl/pk/dh.c b/os_stub/cryptlib_openssl/pk/dh.c index dcbde0c712e..3b9b2b8f4b3 100644 --- a/os_stub/cryptlib_openssl/pk/dh.c +++ b/os_stub/cryptlib_openssl/pk/dh.c @@ -122,6 +122,118 @@ void libspdm_dh_free(void *dh_context) free(key_ctx); } +#if LIBSPDM_FIPS_MODE +/** + * Sets the private key component into the established DH context. This API can be used for + * FIPS test. + * + * @param[in, out] dh_context Pointer to DH context being set. + * @param[in] priv_key Pointer to the private key buffer. + * @param[in] priv_key_size The size of private key buffer in bytes. + * + * @retval true DH private key component was set successfully. + * @retval false Invalid DH private key component. + **/ +bool libspdm_dh_set_priv_key(void *dh_context, const uint8_t *priv_key, + size_t priv_key_size) +{ + libspdm_key_context *key_ctx; + EVP_PKEY *new_key = NULL; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY_CTX *check_ctx = NULL; + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *ossl_params = NULL; + BIGNUM *bn_priv = NULL; + BIGNUM *bn_pub = NULL; + BIGNUM *p = NULL, *g = NULL; + BN_CTX *bn_ctx = NULL; + bool result = false; + + if (dh_context == NULL || priv_key == NULL || priv_key_size > INT_MAX) { + return false; + } + + key_ctx = (libspdm_key_context *)dh_context; + if (key_ctx->evp_pkey == NULL) { + return false; + } + + bn_priv = BN_bin2bn(priv_key, (int)priv_key_size, NULL); + if (bn_priv == NULL) { + return false; + } + + if (EVP_PKEY_get_bn_param(key_ctx->evp_pkey, OSSL_PKEY_PARAM_FFC_P, &p) <= 0 || + EVP_PKEY_get_bn_param(key_ctx->evp_pkey, OSSL_PKEY_PARAM_FFC_G, &g) <= 0) { + goto cleanup; + } + + bn_ctx = BN_CTX_new(); + bn_pub = BN_new(); + if (bn_ctx == NULL || bn_pub == NULL) { + goto cleanup; + } + + /* pub = g^priv mod p */ + if (!BN_mod_exp(bn_pub, g, bn_priv, p, bn_ctx)) { + goto cleanup; + } + + param_bld = OSSL_PARAM_BLD_new(); + if (param_bld == NULL) { + goto cleanup; + } + + if (!OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) || + !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) || + !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, bn_priv) || + !OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PUB_KEY, bn_pub)) { + goto cleanup; + } + + ossl_params = OSSL_PARAM_BLD_to_param(param_bld); + if (ossl_params == NULL) { + goto cleanup; + } + + ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL); + if (ctx == NULL) { + goto cleanup; + } + + if (EVP_PKEY_fromdata_init(ctx) <= 0) { + goto cleanup; + } + + if (EVP_PKEY_fromdata(ctx, &new_key, EVP_PKEY_KEYPAIR, ossl_params) <= 0) { + goto cleanup; + } + + check_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, new_key, NULL); + if (check_ctx == NULL || EVP_PKEY_private_check(check_ctx) <= 0) { + goto cleanup; + } + + EVP_PKEY_free(key_ctx->evp_pkey); + key_ctx->evp_pkey = new_key; + new_key = NULL; + result = true; + +cleanup: + EVP_PKEY_CTX_free(check_ctx); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(new_key); + OSSL_PARAM_BLD_free(param_bld); + OSSL_PARAM_free(ossl_params); + BN_clear_free(bn_priv); + BN_free(bn_pub); + BN_free(p); + BN_free(g); + BN_CTX_free(bn_ctx); + return result; +} +#endif /* LIBSPDM_FIPS_MODE */ + /** * Generates DH parameter. * From 0f9a723e9f488580c9f9c6309e8f49a473c7bcd7 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Wed, 28 Oct 2026 21:40:54 +0800 Subject: [PATCH 2/3] Update fips.md: FFDHE self-test is now KAT Signed-off-by: Jiewen Yao Assisted-by: GitHub Copilot:Claude Sonnet 5 --- doc/fips.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/fips.md b/doc/fips.md index 06f07af9510..af1f911f941 100644 --- a/doc/fips.md +++ b/doc/fips.md @@ -20,7 +20,7 @@ libspdm integrator is expected to choose crypto module and support CMVP. | EdDSA | [NIST.FIPS.186-5](https://doi.org/10.6028/NIST.FIPS.186-5), [NIST.SP.800-186](https://doi.org/10.6028/NIST.SP.800-186), [rfc8032](https://www.rfc-editor.org/rfc/rfc8032) | KAT | EdDSA-25519,EdDSA-448 | | HMAC | [NIST.FIPS.198-1](https://doi.org/10.6028/NIST.FIPS.198-1), [rfc2104](https://tools.ietf.org/html/rfc2104) | KAT | HMAC-SHA-256/384/512 | | AES-GCM | [NIST.FIPS.197](https://doi.org/10.6028/NIST.FIPS.197), [NIST.SP.800-38D](https://doi.org/10.6028/NIST.SP.800-38D) | KAT | AES-GCM-256 | -| FFDHE | [NIST.SP.800-56Ar3](https://doi.org/10.6028/NIST.SP.800-56Ar3), [rfc7919](https://www.rfc-editor.org/rfc/rfc7919) | PCT | FFDHE-2048 | +| FFDHE | [NIST.SP.800-56Ar3](https://doi.org/10.6028/NIST.SP.800-56Ar3), [rfc7919](https://www.rfc-editor.org/rfc/rfc7919) | KAT | FFDHE-2048 | | ECDHE | [NIST.SP.800-56Ar3](https://doi.org/10.6028/NIST.SP.800-56Ar3), [rfc8446](https://www.rfc-editor.org/rfc/rfc8446) | KAT | ECDHE-P256 | | HKDF | [NIST.SP.800-56Cr2](https://doi.org/10.6028/NIST.SP.800-56Cr2), [rfc5869](https://tools.ietf.org/html/rfc5869) | KAT | HKDF-HMAC-SHA-256 | | ChaCha-Poly (*) | [rfc8439](https://www.rfc-editor.org/rfc/rfc8439) | KAT | not FIPS approved yet | From f8fecabfb628454b776efe8c53699896c891d9a0 Mon Sep 17 00:00:00 2001 From: Jiewen Yao Date: Wed, 28 Oct 2026 21:43:45 +0800 Subject: [PATCH 3/3] Update changelog.md for FFDHE FIPS self-test change Document the FFDHE known-answer test and the new libspdm_dh_set_priv_key() HAL function. Signed-off-by: Jiewen Yao Assisted-by: GitHub Copilot:Claude Sonnet 5 --- doc/changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/changelog.md b/doc/changelog.md index 3cb0d29711d..742454c6a58 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -8,6 +8,8 @@ establishment, including FIPS known-answer tests. - The ECDSA, RSA-SSA and RSA-PSS FIPS known-answer tests use NIST CAVP vectors, and run with any of SHA-256, SHA-384 or SHA-512 enabled. +- The FFDHE FIPS self-test is a known-answer test, with a fixed private key and a NIST ACVP vector, + in place of a pairwise consistency test. - Redesigned Responder encapsulated request flow. The Integrator registers a single flow handler instead of initializing each encapsulated state individually. See the [encapsulated flow user guide](encapsulated_flow_user_guide.md). @@ -38,6 +40,7 @@ - `cryptlib/cryptlib_ec.h` - `libspdm_ecdsa_verify_fips`, and `cryptlib/cryptlib_rsa.h` - `libspdm_rsa_pkcs1_sign_fips` and `libspdm_rsa_pkcs1_verify_fips`, for the ECDSA and RSA-SSA FIPS known-answer tests. + - `cryptlib/cryptlib_dh.h` - `libspdm_dh_set_priv_key`, for the FFDHE FIPS known-answer test. - HAL functions removed: - `libspdm_write_certificate_to_nvm` - replaced by `libspdm_update_local_cert_chain`. - `libspdm_gen_csr_ex` - merged into `libspdm_gen_csr`, which also takes the post-quantum