Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 1.3 erase certificate feature for SET_CERTIFICATE #2433

Merged
merged 2 commits into from
Jan 2, 2024
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
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 @@ -1035,9 +1038,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.
jyao1 marked this conversation as resolved.
Show resolved Hide resolved
* 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.
Wenxing-hou marked this conversation as resolved.
Show resolved Hide resolved
* 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