Skip to content

Commit

Permalink
Add parameters to libspdm_write_certificate_to_nvm
Browse files Browse the repository at this point in the history
Fix #2873.

Signed-off-by: Steven Bellock <[email protected]>
  • Loading branch information
steven-bellock committed Nov 18, 2024
1 parent c5531f3 commit 757573d
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 57 deletions.
14 changes: 11 additions & 3 deletions include/hal/library/responder/setcertlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ extern bool libspdm_is_in_trusted_environment(
* @param[in] cert_chain_size The size of the certificate chain to set.
* @param[in] base_hash_algo Indicates the negotiated hash algorithm.
* @param[in] base_asym_algo Indicates the negotiated signing algorithms.
*
* @param[in,out] need_reset On input, indicates the value of CERT_INSTALL_RESET_CAP.
* On output, indicates whether the device needs to be reset (true) for
* the SET_CERTIFICATE operation to complete.
* @param[out] is_busy If true, indicates that the certificate chain cannot be written at
* this time, but it may be successful in a later call. The function's
* return value must be false if this parameter is true.
* @retval true The certificate chain was successfully written to non-volatile memory.
* @retval false Unable to write certificate chain to non-volatile memory.
**/
Expand All @@ -48,8 +53,11 @@ extern bool libspdm_write_certificate_to_nvm(
#endif
uint8_t slot_id, const void * cert_chain,
size_t cert_chain_size,
uint32_t base_hash_algo, uint32_t base_asym_algo);

uint32_t base_hash_algo, uint32_t base_asym_algo
#if LIBSPDM_SET_CERT_PARAMS
, bool *need_reset, bool *is_busy
#endif /* LIBSPDM_SET_CERT_PARAMS */
);
#endif /* LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP */

#endif /* RESPONDER_SETCERTLIB_H */
7 changes: 7 additions & 0 deletions include/library/spdm_lib_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,4 +442,11 @@
#define LIBSPDM_ADDITIONAL_CHECK_CERT 0
#endif

/* Enable passing additional parameters to libspdm_write_certificate_to_nvm.
* This macro will be removed when libspdm 4.0 is released.
*/
#ifndef LIBSPDM_SET_CERT_PARAMS
#define LIBSPDM_SET_CERT_PARAMS 1
#endif

#endif /* SPDM_LIB_CONFIG_H */
46 changes: 37 additions & 9 deletions library/spdm_responder_lib/libspdm_rsp_set_certificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
bool result;
uint8_t spdm_version;
uint8_t slot_id;
bool need_reset;
bool is_busy;
bool erase;
uint8_t set_cert_model;

Expand Down Expand Up @@ -212,6 +214,11 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
}
}

need_reset = libspdm_is_capabilities_flag_supported(
spdm_context, false, 0,
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP);
is_busy = false;

if ((spdm_version >= SPDM_MESSAGE_VERSION_13) && erase) {
/*the CertChain field shall be absent;the value of SetCertModel shall be zero*/
if ((request_size < sizeof(spdm_set_certificate_request_t)) ||
Expand All @@ -227,11 +234,21 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
#if LIBSPDM_HAL_PASS_SPDM_CONTEXT
spdm_context,
#endif
slot_id, NULL, 0, 0, 0);
slot_id, NULL, 0, 0, 0
#if LIBSPDM_SET_CERT_PARAMS
, &need_reset, &is_busy
#endif /* LIBSPDM_SET_CERT_PARAMS */
);
if (!result) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_OPERATION_FAILED, 0,
response_size, response);
if (is_busy) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_BUSY, 0,
response_size, response);
} else {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_OPERATION_FAILED, 0,
response_size, response);
}
}
} else {
if (request_size < sizeof(spdm_set_certificate_request_t) +
Expand Down Expand Up @@ -286,11 +303,22 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
slot_id, cert_chain,
cert_chain_size,
spdm_context->connection_info.algorithm.base_hash_algo,
spdm_context->connection_info.algorithm.base_asym_algo);
spdm_context->connection_info.algorithm.base_asym_algo
#if LIBSPDM_SET_CERT_PARAMS
, &need_reset, &is_busy
#endif /* LIBSPDM_SET_CERT_PARAMS */
);

if (!result) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_UNSPECIFIED, 0,
response_size, response);
if (is_busy) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_BUSY, 0,
response_size, response);
} else {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_UNSPECIFIED, 0,
response_size, response);
}
}
}

Expand All @@ -302,7 +330,7 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
/*requires a reset to complete the SET_CERTIFICATE request*/
if (libspdm_is_capabilities_flag_supported(
spdm_context, false, 0,
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP)) {
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP) && need_reset) {
spdm_context->local_context.cert_slot_reset_mask |= (1 << slot_id);

/*the device will reset to set cert*/
Expand Down
6 changes: 5 additions & 1 deletion os_stub/spdm_device_secret_lib_null/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ bool libspdm_write_certificate_to_nvm(
#endif
uint8_t slot_id, const void * cert_chain,
size_t cert_chain_size,
uint32_t base_hash_algo, uint32_t base_asym_algo)
uint32_t base_hash_algo, uint32_t base_asym_algo
#if LIBSPDM_SET_CERT_PARAMS
, bool *need_reset, bool *is_busy
#endif /* LIBSPDM_SET_CERT_PARAMS */
)
{
return false;
}
Expand Down
99 changes: 55 additions & 44 deletions os_stub/spdm_device_secret_lib_sample/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "internal/libspdm_common_lib.h"

bool g_in_trusted_environment = false;
bool g_set_cert_is_busy = false;
uint32_t g_supported_event_groups_list_len = 8;
uint8_t g_event_group_count = 1;
bool g_event_all_subscribe = false;
Expand Down Expand Up @@ -2221,65 +2222,75 @@ bool libspdm_write_certificate_to_nvm(
#endif
uint8_t slot_id, const void * cert_chain,
size_t cert_chain_size,
uint32_t base_hash_algo, uint32_t base_asym_algo)
uint32_t base_hash_algo, uint32_t base_asym_algo
#if LIBSPDM_SET_CERT_PARAMS
, bool *need_reset, bool *is_busy
#endif /* LIBSPDM_SET_CERT_PARAMS */
)
{
#if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
defined(LIBSPDM_CPU_ARM)))
FILE *fp_out;
#else
int64_t fp_out;
#endif
if (g_set_cert_is_busy) {
*is_busy = true;

char file_name[] = "slot_id_0_cert_chain.der";
/*change the file name, for example: slot_id_1_cert_chain.der*/
file_name[8] = (char)(slot_id+'0');

/*check the input parameter*/
if ((cert_chain == NULL) ^ (cert_chain_size == 0) ) {
return false;
}

#if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
defined(LIBSPDM_CPU_ARM)))
if ((fp_out = fopen(file_name, "w+b")) == NULL) {
printf("Unable to open file %s\n", file_name);
return false;
}

if (cert_chain != NULL) {
if ((fwrite(cert_chain, 1, cert_chain_size, fp_out)) != cert_chain_size) {
printf("Write output file error %s\n", file_name);
fclose(fp_out);
} else {
#if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
defined(LIBSPDM_CPU_ARM)))
FILE *fp_out;
#else
int64_t fp_out;
#endif

char file_name[] = "slot_id_0_cert_chain.der";
/*change the file name, for example: slot_id_1_cert_chain.der*/
file_name[8] = (char)(slot_id+'0');

/*check the input parameter*/
if ((cert_chain == NULL) ^ (cert_chain_size == 0) ) {
return false;
}
}

fclose(fp_out);
#else
if (cert_chain != NULL) {
if ((fp_out = open(file_name, O_WRONLY | O_CREAT, S_IRWXU)) == -1) {
#if defined(_WIN32) || (defined(__clang__) && (defined (LIBSPDM_CPU_AARCH64) || \
defined(LIBSPDM_CPU_ARM)))
if ((fp_out = fopen(file_name, "w+b")) == NULL) {
printf("Unable to open file %s\n", file_name);
return false;
}

if ((write(fp_out, cert_chain, cert_chain_size)) != cert_chain_size) {
printf("Write output file error %s\n", file_name);
close(fp_out);
return false;
if (cert_chain != NULL) {
if ((fwrite(cert_chain, 1, cert_chain_size, fp_out)) != cert_chain_size) {
printf("Write output file error %s\n", file_name);
fclose(fp_out);
return false;
}
}
} else {
if ((fp_out = open(file_name, O_WRONLY | O_TRUNC)) == -1) {
printf("Unable to open file %s\n", file_name);
return false;

fclose(fp_out);
#else
if (cert_chain != NULL) {
if ((fp_out = open(file_name, O_WRONLY | O_CREAT, S_IRWXU)) == -1) {
printf("Unable to open file %s\n", file_name);
return false;
}

if ((write(fp_out, cert_chain, cert_chain_size)) != cert_chain_size) {
printf("Write output file error %s\n", file_name);
close(fp_out);
return false;
}
} else {
if ((fp_out = open(file_name, O_WRONLY | O_TRUNC)) == -1) {
printf("Unable to open file %s\n", file_name);
return false;
}

close(fp_out);
}

close(fp_out);
}
#endif

close(fp_out);
#endif

return true;
return true;
}
}
#endif /* LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP */

Expand Down
75 changes: 75 additions & 0 deletions unit_test/test_spdm_responder/set_certificate_rsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP

extern bool g_in_trusted_environment;
extern bool g_set_cert_is_busy;

/**
* Test 1: receives a valid SET_CERTIFICATE request message from Requester to set cert in slot_id:0 with device_cert model
Expand Down Expand Up @@ -1039,6 +1040,79 @@ void libspdm_test_responder_set_certificate_rsp_case12(void **state)
free(m_libspdm_set_certificate_request);
}

/**
* Test 13: The Responder cannot complete request due to busy response when writing to NVM.
* Expected Behavior: The Responder returns a Busy error response.
**/
void libspdm_test_responder_set_certificate_rsp_case13(void **state)
{
libspdm_return_t status;
libspdm_test_context_t *spdm_test_context;
libspdm_context_t *spdm_context;
size_t response_size;
uint8_t response[LIBSPDM_MAX_SPDM_MSG_SIZE];
spdm_set_certificate_response_t *spdm_response;
void *cert_chain;
size_t cert_chain_size;
spdm_set_certificate_request_t *m_libspdm_set_certificate_request;

spdm_test_context = *state;
spdm_context = spdm_test_context->spdm_context;
spdm_test_context->case_id = 0xd;
spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
SPDM_VERSION_NUMBER_SHIFT_BIT;

spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_NEGOTIATED;
spdm_context->local_context.capability.flags |=
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP;
spdm_context->local_context.capability.flags |=
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP;
spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo;
spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo;

spdm_context->local_context.algorithm.base_hash_algo = m_libspdm_use_hash_algo;
spdm_context->local_context.algorithm.base_asym_algo = m_libspdm_use_asym_algo;

libspdm_read_responder_public_certificate_chain(m_libspdm_use_hash_algo,
m_libspdm_use_asym_algo, &cert_chain,
&cert_chain_size, NULL, NULL);

m_libspdm_set_certificate_request = malloc(sizeof(spdm_set_certificate_request_t) +
cert_chain_size);

m_libspdm_set_certificate_request->header.spdm_version = SPDM_MESSAGE_VERSION_12;
m_libspdm_set_certificate_request->header.request_response_code = SPDM_SET_CERTIFICATE;
m_libspdm_set_certificate_request->header.param1 = 0;
m_libspdm_set_certificate_request->header.param2 = 0;

libspdm_copy_mem(m_libspdm_set_certificate_request + 1,
LIBSPDM_MAX_CERT_CHAIN_SIZE,
(uint8_t *)cert_chain, cert_chain_size);

size_t m_libspdm_set_certificate_request_size = sizeof(spdm_set_certificate_request_t) +
cert_chain_size;

/* Unable to write to NVM due to busy condition. */
g_set_cert_is_busy = true;

response_size = sizeof(response);
status = libspdm_get_response_set_certificate(spdm_context,
m_libspdm_set_certificate_request_size,
m_libspdm_set_certificate_request,
&response_size, response);
assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
assert_int_equal(response_size, sizeof(spdm_error_response_t));
spdm_response = (void *)response;
assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_BUSY);
assert_int_equal(spdm_response->header.param2, 0);

g_set_cert_is_busy = false;

free(cert_chain);
free(m_libspdm_set_certificate_request);
}

int libspdm_responder_set_certificate_rsp_test_main(void)
{
const struct CMUnitTest spdm_responder_set_certificate_tests[] = {
Expand All @@ -1065,6 +1139,7 @@ int libspdm_responder_set_certificate_rsp_test_main(void)
/* Success Case for set_certificate to slot_id:1 with key_pair_id*/
cmocka_unit_test(libspdm_test_responder_set_certificate_rsp_case11),
cmocka_unit_test(libspdm_test_responder_set_certificate_rsp_case12),
cmocka_unit_test(libspdm_test_responder_set_certificate_rsp_case13),
};

libspdm_test_context_t test_context = {
Expand Down

0 comments on commit 757573d

Please sign in to comment.