Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion doc/fips.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
16 changes: 16 additions & 0 deletions include/hal/library/cryptlib/cryptlib_dh.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
170 changes: 126 additions & 44 deletions library/spdm_crypt_lib/fips/libspdm_selftest_ffdh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note:
RELEASE/v1.1.0.41
commit hash b121fee031dc65d32c96f4109a42a10dacbe2076

/* 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*/
Expand Down
58 changes: 57 additions & 1 deletion os_stub/cryptlib_mbedtls/pk/dh.c
Original file line number Diff line number Diff line change
@@ -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
**/

Expand Down Expand Up @@ -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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the function comment and reference links mentioned above.
Actually I have no actual idea how to use Mbed-TLS to do key validation in proper way like OpenSSL in detail.

Sample code generated from my agent.
assisted-by: GitHub Copilot:Claude OPUS 5.5

    mbedtls_mpi q;
    bool ok;

    ctx = dh_context;
    mbedtls_mpi_init(&q);

    ok = mbedtls_mpi_read_binary(&ctx->MBEDTLS_PRIVATE(X), priv_key, priv_key_size) == 0 &&
         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);
    if (!ok) {
        mbedtls_mpi_free(&ctx->MBEDTLS_PRIVATE(X));
        mbedtls_mpi_init(&ctx->MBEDTLS_PRIVATE(X));
    }
    return ok;

FYI.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand your comment.

What is the problem of the original code? Could you please be specific?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed this function libspdm_dh_set_priv_key several times.
Currently libspdm_dh_set_priv_key implemented in MbedTLS does not check private key as it claimed.
I can imagine the libspdm users probably utilize this API in their Known Answer Test (KAT) with given invalid private key even worst reuse this API in production codes instead of unit tests.

I found it is not easy to implement key validation by MbedTLS like EVP_PKEY_private_check() in OpenSSL.

Quoted from https://docs.openssl.org/3.0/man3/EVP_PKEY_check/#description
Refer to SP800-56A and SP800-56B for rules relating to when these functions should be called during key establishment. It is not necessary to call these functions after locally calling an approved key generation method, but may be required for assurance purposes when receiving keys from a third party.

But incomplete implementation by MbedTLS is worst than no implementation to me.

In this PR, there are still many benefits from the FIPS self-test in different perspectives.

  • Evaluate any change from relying third-party cryptographic library does not break the expected behavior.
  • Ensure any change to libspdm API doest not break the expected behavior.

In summary it is good to me.

@jyao1 jyao1 Nov 2, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently libspdm_dh_set_priv_key implemented in MbedTLS does not check private key as it claimed.

Yes, that is because mbedtls does not provide.
I do not expect this API will be used in production code except FIPS test.
Anyway, I think there is no harm to mirror what OpenSSL does for the check.

**/
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.
*
Expand Down
18 changes: 18 additions & 0 deletions os_stub/cryptlib_null/pk/dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
Loading
Loading