Skip to content

Commit

Permalink
Add 1.3 erase certificate feature for SET_CERTIFICATE
Browse files Browse the repository at this point in the history
Fix the issue: #2292

Signed-off-by: Wenxing Hou <[email protected]>
  • Loading branch information
Wenxing-hou authored and jyao1 committed Jan 2, 2024
1 parent c50f802 commit 0e44d44
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 73 deletions.
5 changes: 3 additions & 2 deletions include/hal/library/responder/setcertlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
extern bool libspdm_is_in_trusted_environment();

/**
* Stores a certificate chain in non-volatile memory.
*
* Stores or erase a certificate chain in non-volatile memory.
* If the cert_chain is NULL and cert_chain_size is 0,
* the feature is to erase the certificate chain.
*
* @param[in] slot_id The number of slot for the certificate chain.
* @param[in] cert_chain The pointer for the certificate chain to set.
Expand Down
12 changes: 9 additions & 3 deletions include/industry_standard/spdm.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,9 @@ typedef struct {
#define SPDM_ERROR_CODE_LARGE_RESPONSE 0x0F
#define SPDM_ERROR_CODE_MESSAGE_LOST 0x10

/* SPDM error code (1.3) */
#define SPDM_ERROR_CODE_OPERATION_FAILED 0x44

/* SPDM ResponseNotReady extended data */
typedef struct {
uint8_t rd_exponent;
Expand Down Expand Up @@ -1042,9 +1045,12 @@ typedef struct {
/* SPDM SET_CERTIFICATE request */
typedef struct {
spdm_message_header_t header;
/* param1 == BIT[0:3]=slot_id, Request Attribute in 1.3
* param2 == key_pair_id in 1.3
* uint8_t cert_chain[]; */
/* param1 == BIT[0:3]=slot_id, BIT[4:7]=RSVD
* param2 == RSVD
* param1 and param2 are updated in 1.3
* param1 == Request attributes, BIT[0:3]=slot_id, BIT[4:6]=SetCertModel, BIT[7]=Erase
* param2 == KeyPairID
* void * cert_chain*/
} spdm_set_certificate_request_t;

#define SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK 0xF
Expand Down
14 changes: 14 additions & 0 deletions include/internal/libspdm_responder_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,20 @@ libspdm_return_t libspdm_get_response_csr(libspdm_context_t *spdm_context,
/**
* Process the SPDM SET_CERTIFICATE request and return the response.
*
* | Cert State in Slot | Req(KeyPairID,CertMode) | Req(Erase) | Res(KeyPairID,CertMode) | Action |
* |-----------------------|-------------------------|------------|-----------------------------|--------------------------|
* | Not exist | - | - | - | Invalid |
* | exist and empty | Valid | No | Not exist | Provision |
* | exist and empty | Valid | Yes | Not exist | Invalid |
* | exist with key | Valid | No | KeyPairID/CertMode match | Provision |
* | exist with key | Valid | Yes | KeyPairID/CertMode match | Invalid |
* | exist with key | Valid | No | KeyPairID/CertMode not match| Invalid(or OverWrite) |
* | exist with key | Valid | Yes | KeyPairID/CertMode not match| Invalid |
* |exist with key and cert| Valid | No | KeyPairID/CertMode match | Invalid(or OverWrite) |
* |exist with key and cert| Valid | Yes | KeyPairID/CertMode match | Erase Cert |
* |exist with key and cert| Valid | No | KeyPairID/CertMode not match| Invalid |
* |exist with key and cert| Valid | Yes | KeyPairID/CertMode not match| Invalid |
*
* @param spdm_context A pointer to the SPDM context.
* @param request_size size in bytes of the request data.
* @param request A pointer to the request data.
Expand Down
31 changes: 31 additions & 0 deletions include/library/spdm_requester_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,37 @@ libspdm_return_t libspdm_set_certificate(void *spdm_context,
const uint32_t *session_id, uint8_t slot_id,
void *cert_chain, size_t cert_chain_size);

/**
* This function try to send SET_CERTIFICATE
* to set certificate or erase certificate from the device.
*
* @param context A pointer to the SPDM context.
* @param session_id Indicates if it is a secured message protected via SPDM session.
* If session_id is NULL, it is a normal message.
* If session_id is NOT NULL, it is a secured message.
* @param slot_id The number of slot for the certificate chain.
* @param cert_chain The pointer for the certificate chain to set.
* The cert chain is a full SPDM certificate chain, including Length and Root Cert Hash.
* For SPDM 1.2, the cert_chain must be non-NULL.
* For SPDM 1.3 and above:
* If the request_attribute Erase bit is set, the cert_chain must be NULL;
* If the request_attribute Erase bit is not set, the cert_chain must be non-NULL.
* @param cert_chain_size The size of the certificate chain to set.
* For SPDM 1.2, the cert_chain_size must be non-zero.
* For SPDM 1.3 and above:
* If the request_attribute Erase bit is set, the cert_chain_size must be 0;
* If the request_attribute Erase bit is not set, the cert_chain_size must be non-zero.
* If the cert_chain is NULL, the cert_chain_size must be 0.
* @param request_attribute Set certificate request attributes. This field is only used for SPDM 1.3 and above.
* And the bit[0~3] of request_attribute must be 0.
* @param key_pair_id The value of this field shall be the unique key pair number identifying the desired
* asymmetric key pair to associate with SlotID .
**/
libspdm_return_t libspdm_set_certificate_ex(void *spdm_context,
const uint32_t *session_id, uint8_t slot_id,
void *cert_chain, size_t cert_chain_size,
uint8_t request_attribute,
uint8_t key_pair_id);
#endif /* LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP */

#if LIBSPDM_ENABLE_MSG_LOG
Expand Down
76 changes: 68 additions & 8 deletions library/spdm_requester_lib/libspdm_req_set_certificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@
* @param cert_chain The pointer for the certificate chain to set.
* The cert chain is a full SPDM certificate chain, including Length and Root Cert Hash.
* @param cert_chain_size The size of the certificate chain to set.
* @param request_attribute Set certificate request attributes. This field is only used for SPDM 1.3 and above.
* And the bit[0~3] of request_attribute must be 0.
* @param key_pair_id The value of this field shall be the unique key pair number identifying the desired
* asymmetric key pair to associate with SlotID .
*
* @retval RETURN_SUCCESS The measurement is got successfully.
* @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device.
* @retval RETURN_SECURITY_VIOLATION Any verification fails.
**/
static libspdm_return_t libspdm_try_set_certificate(libspdm_context_t *spdm_context,
const uint32_t *session_id, uint8_t slot_id,
void *cert_chain, size_t cert_chain_size)
void *cert_chain, size_t cert_chain_size,
uint8_t request_attribute,
uint8_t key_pair_id)
{
libspdm_return_t status;
spdm_set_certificate_request_t *spdm_request;
Expand All @@ -48,8 +54,10 @@ static libspdm_return_t libspdm_try_set_certificate(libspdm_context_t *spdm_cont

LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);

if ((cert_chain == NULL) || (cert_chain_size == 0)) {
return LIBSPDM_STATUS_INVALID_PARAMETER;
if (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_13) {
if ((cert_chain == NULL) || (cert_chain_size == 0)) {
return LIBSPDM_STATUS_INVALID_PARAMETER;
}
}

if (spdm_context->connection_info.connection_state <
Expand Down Expand Up @@ -84,14 +92,37 @@ static libspdm_return_t libspdm_try_set_certificate(libspdm_context_t *spdm_cont

spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
spdm_request->header.request_response_code = SPDM_SET_CERTIFICATE;
spdm_request->header.param1 = slot_id;
spdm_request->header.param1 = slot_id & SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
spdm_request->header.param2 = 0;

if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
/*And the bit[0~3] of request_attribute must be 0.*/
if ((request_attribute & SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK) != 0) {
return LIBSPDM_STATUS_INVALID_PARAMETER;
}

if ((request_attribute & SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE) != 0) {
/*the CertChain field shall be absent*/
cert_chain_size = 0;
/*the value of SetCertModel shall be zero*/
spdm_request->header.param1 &= ~SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_MASK;
/*set Erase bit */
spdm_request->header.param1 |= SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE;
}
}

LIBSPDM_ASSERT(spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12);

libspdm_copy_mem(spdm_request + 1,
spdm_request_size - sizeof(spdm_set_certificate_request_t),
(uint8_t *)cert_chain, cert_chain_size);
if ((libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_13) ||
(cert_chain_size != 0)) {
if (cert_chain == NULL) {
return LIBSPDM_STATUS_INVALID_PARAMETER;
}

libspdm_copy_mem(spdm_request + 1,
spdm_request_size - sizeof(spdm_set_certificate_request_t),
(uint8_t *)cert_chain, cert_chain_size);
}

spdm_request_size = sizeof(spdm_set_certificate_request_t) + cert_chain_size;

Expand Down Expand Up @@ -171,7 +202,36 @@ libspdm_return_t libspdm_set_certificate(void *spdm_context,
retry_delay_time = context->retry_delay_time;
do {
status = libspdm_try_set_certificate(context, session_id, slot_id,
cert_chain, cert_chain_size);
cert_chain, cert_chain_size, 0, 0);
if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) {
return status;
}

libspdm_sleep(retry_delay_time);
} while (retry-- != 0);

return status;
}

libspdm_return_t libspdm_set_certificate_ex(void *spdm_context,
const uint32_t *session_id, uint8_t slot_id,
void *cert_chain, size_t cert_chain_size,
uint8_t request_attribute,
uint8_t key_pair_id)
{
libspdm_context_t *context;
size_t retry;
uint64_t retry_delay_time;
libspdm_return_t status;

context = spdm_context;
context->crypto_request = true;
retry = context->retry_times;
retry_delay_time = context->retry_delay_time;
do {
status = libspdm_try_set_certificate(context, session_id, slot_id,
cert_chain, cert_chain_size,
request_attribute, key_pair_id);
if ((status != LIBSPDM_STATUS_BUSY_PEER) || (retry == 0)) {
return status;
}
Expand Down
119 changes: 70 additions & 49 deletions library/spdm_responder_lib/libspdm_rsp_set_certificate.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
SPDM_SET_CERTIFICATE, response_size, response);
}

slot_id = spdm_request->header.param1 & SPDM_GET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
slot_id = spdm_request->header.param1 & SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
if (slot_id >= SPDM_MAX_SLOT_COUNT) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
Expand All @@ -147,63 +147,84 @@ libspdm_return_t libspdm_get_response_set_certificate(libspdm_context_t *spdm_co
root_cert_hash_size = libspdm_get_hash_size(
spdm_context->connection_info.algorithm.base_hash_algo);

if (request_size < sizeof(spdm_set_certificate_request_t) +
sizeof(spdm_cert_chain_t) + root_cert_hash_size) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}
if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) &&
((spdm_request->header.param1 & SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE) != 0)) {
/*the CertChain field shall be absent;the value of SetCertModel shall be zero*/
if ((request_size < sizeof(spdm_set_certificate_request_t)) ||
((spdm_request->header.param1 &
SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_MASK) != 0)) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}

/*point to full SPDM certificate chain*/
cert_chain = (const void*)(spdm_request + 1);
cert_chain_header = cert_chain;
/* erase slot_id cert_chain*/
result = libspdm_write_certificate_to_nvm(slot_id, NULL, 0, 0, 0);
if (!result) {
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) +
sizeof(spdm_cert_chain_t) + root_cert_hash_size) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}

if (cert_chain_header->length < sizeof(spdm_cert_chain_t) + root_cert_hash_size) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}
if (cert_chain_header->length > request_size - sizeof(spdm_set_certificate_request_t)) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}
/*point to full SPDM certificate chain*/
cert_chain = (const void*)(spdm_request + 1);
cert_chain_header = cert_chain;

/*get actual cert_chain size*/
cert_chain_size = cert_chain_header->length - sizeof(spdm_cert_chain_t) - root_cert_hash_size;
if (cert_chain_header->length < sizeof(spdm_cert_chain_t) + root_cert_hash_size) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}
if (cert_chain_header->length > request_size - sizeof(spdm_set_certificate_request_t)) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_INVALID_REQUEST, 0,
response_size, response);
}

/*point to actual cert_chain*/
cert_chain = (const void*)((const uint8_t *)cert_chain
+ sizeof(spdm_cert_chain_t) + root_cert_hash_size);
/*get actual cert_chain size*/
cert_chain_size = cert_chain_header->length - sizeof(spdm_cert_chain_t) -
root_cert_hash_size;

is_device_cert_model = false;
if((spdm_context->local_context.capability.flags &
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP) == 0) {
is_device_cert_model = true;
}
/*point to actual cert_chain*/
cert_chain = (const void*)((const uint8_t *)cert_chain
+ sizeof(spdm_cert_chain_t) + root_cert_hash_size);

is_device_cert_model = false;
if((spdm_context->local_context.capability.flags &
SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP) == 0) {
is_device_cert_model = true;
}

#if LIBSPDM_CERT_PARSE_SUPPORT
/*check the cert_chain*/
result = libspdm_set_cert_verify_certchain(cert_chain, cert_chain_size,
spdm_context->connection_info.algorithm.base_asym_algo,
spdm_context->connection_info.algorithm.base_hash_algo,
is_device_cert_model);
if (!result) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_UNSPECIFIED, 0,
response_size, response);
}
/*check the cert_chain*/
result = libspdm_set_cert_verify_certchain(cert_chain, cert_chain_size,
spdm_context->connection_info.algorithm.base_asym_algo,
spdm_context->connection_info.algorithm.base_hash_algo,
is_device_cert_model);
if (!result) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_UNSPECIFIED, 0,
response_size, response);
}
#endif /*LIBSPDM_CERT_PARSE_SUPPORT*/

/* set certificate to NV*/
result = libspdm_write_certificate_to_nvm(slot_id, cert_chain,
cert_chain_size,
spdm_context->connection_info.algorithm.base_hash_algo,
spdm_context->connection_info.algorithm.base_asym_algo);
if (!result) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_UNSPECIFIED, 0,
response_size, response);
/* set certificate to NV*/
result = libspdm_write_certificate_to_nvm(slot_id, cert_chain,
cert_chain_size,
spdm_context->connection_info.algorithm.base_hash_algo,
spdm_context->connection_info.algorithm.base_asym_algo);
if (!result) {
return libspdm_generate_error_response(spdm_context,
SPDM_ERROR_CODE_UNSPECIFIED, 0,
response_size, response);
}
}

LIBSPDM_ASSERT(*response_size >= sizeof(spdm_set_certificate_response_t));
Expand Down
1 change: 1 addition & 0 deletions os_stub/spdm_device_secret_lib_null/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ bool libspdm_write_certificate_to_nvm(uint8_t slot_id, const void * cert_chain,
{
return false;
}

#endif /* LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP */

#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP
Expand Down
Loading

0 comments on commit 0e44d44

Please sign in to comment.