diff --git a/include/hal/library/responder/setcertlib.h b/include/hal/library/responder/setcertlib.h index 860281ab248..42efc48b1c5 100644 --- a/include/hal/library/responder/setcertlib.h +++ b/include/hal/library/responder/setcertlib.h @@ -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. diff --git a/include/industry_standard/spdm.h b/include/industry_standard/spdm.h index 852a1127ff0..f1c9c726416 100644 --- a/include/industry_standard/spdm.h +++ b/include/industry_standard/spdm.h @@ -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; @@ -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 diff --git a/include/internal/libspdm_responder_lib.h b/include/internal/libspdm_responder_lib.h index c36566d00a3..64e4f37e436 100644 --- a/include/internal/libspdm_responder_lib.h +++ b/include/internal/libspdm_responder_lib.h @@ -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. diff --git a/include/library/spdm_requester_lib.h b/include/library/spdm_requester_lib.h index d8813582b4d..4d45bbac9d0 100644 --- a/include/library/spdm_requester_lib.h +++ b/include/library/spdm_requester_lib.h @@ -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 diff --git a/library/spdm_requester_lib/libspdm_req_set_certificate.c b/library/spdm_requester_lib/libspdm_req_set_certificate.c index 1d2bf360187..fd137d301d8 100644 --- a/library/spdm_requester_lib/libspdm_req_set_certificate.c +++ b/library/spdm_requester_lib/libspdm_req_set_certificate.c @@ -19,6 +19,10 @@ * @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. @@ -26,7 +30,9 @@ **/ 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; @@ -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 < @@ -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; @@ -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; } diff --git a/library/spdm_responder_lib/libspdm_rsp_set_certificate.c b/library/spdm_responder_lib/libspdm_rsp_set_certificate.c index b23e7e241c2..4f0a0c9f2a0 100644 --- a/library/spdm_responder_lib/libspdm_rsp_set_certificate.c +++ b/library/spdm_responder_lib/libspdm_rsp_set_certificate.c @@ -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, @@ -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)); diff --git a/os_stub/spdm_device_secret_lib_null/lib.c b/os_stub/spdm_device_secret_lib_null/lib.c index 2a6fc105ecc..e3f029dc690 100644 --- a/os_stub/spdm_device_secret_lib_null/lib.c +++ b/os_stub/spdm_device_secret_lib_null/lib.c @@ -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 diff --git a/os_stub/spdm_device_secret_lib_sample/lib.c b/os_stub/spdm_device_secret_lib_sample/lib.c index f39db6452d8..81ac142ad55 100644 --- a/os_stub/spdm_device_secret_lib_sample/lib.c +++ b/os_stub/spdm_device_secret_lib_sample/lib.c @@ -1694,6 +1694,11 @@ bool libspdm_write_certificate_to_nvm(uint8_t slot_id, const void * cert_chain, /*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) { @@ -1701,23 +1706,34 @@ bool libspdm_write_certificate_to_nvm(uint8_t slot_id, const void * cert_chain, return false; } - 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; + 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; + } } fclose(fp_out); #else - 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 (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; + } - 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; } close(fp_out);