From 3bbcb24dbae81a25cb04dd185b0fe948e6ac6b25 Mon Sep 17 00:00:00 2001 From: Wenxing Hou Date: Tue, 5 Dec 2023 20:22:31 +0800 Subject: [PATCH] Add get_certificate unit_test for alias_cert model cert Signed-off-by: Wenxing Hou --- os_stub/spdm_device_secret_lib_sample/cert.c | 147 ++++++++++ .../spdm_device_secret_lib_internal.h | 5 + .../test_spdm_requester/get_certificate.c | 267 ++++++++++++++++++ 3 files changed, 419 insertions(+) diff --git a/os_stub/spdm_device_secret_lib_sample/cert.c b/os_stub/spdm_device_secret_lib_sample/cert.c index 4ad132a07d9..5d0deeac05c 100644 --- a/os_stub/spdm_device_secret_lib_sample/cert.c +++ b/os_stub/spdm_device_secret_lib_sample/cert.c @@ -643,6 +643,153 @@ bool libspdm_read_responder_public_certificate_chain_alias_cert_till_dev_cert_ca return true; } +/*This alias cert chain is entire, from root CA to leaf certificate.*/ +bool libspdm_read_responder_public_certificate_chain_alias_cert_entire( + uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, + size_t *size, void **hash, size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + const uint8_t *leaf_cert; + size_t leaf_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + /*default is false*/ + is_device_cert_model = false; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_responder.certchain_alias_entire.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + /* Get leaf Certificate*/ + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, -1, &leaf_cert, + &leaf_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + res = libspdm_x509_certificate_check(leaf_cert, leaf_cert_len, + base_asym_algo, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + /* Get Root Certificate*/ + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + /*verify cert_chain*/ + res = libspdm_x509_verify_cert_chain(root_cert, root_cert_len, file_data, file_size); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + /*calculate hash value*/ + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + bool libspdm_read_responder_public_certificate_chain_per_slot( uint8_t slot_id, uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, size_t *size, void **hash, size_t *hash_size) diff --git a/os_stub/spdm_device_secret_lib_sample/spdm_device_secret_lib_internal.h b/os_stub/spdm_device_secret_lib_sample/spdm_device_secret_lib_internal.h index 9a3d143fba5..3549a82c66b 100644 --- a/os_stub/spdm_device_secret_lib_sample/spdm_device_secret_lib_internal.h +++ b/os_stub/spdm_device_secret_lib_sample/spdm_device_secret_lib_internal.h @@ -56,6 +56,11 @@ bool libspdm_read_responder_public_certificate_chain_alias_cert_till_dev_cert_ca uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, size_t *size, void **hash, size_t *hash_size); +/*This alias cert chain is entire, from root CA to leaf certificate.*/ +bool libspdm_read_responder_public_certificate_chain_alias_cert_entire( + uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, + size_t *size, void **hash, size_t *hash_size); + bool libspdm_read_responder_public_certificate_chain_per_slot( uint8_t slot_id, uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, size_t *size, void **hash, size_t *hash_size); diff --git a/unit_test/test_spdm_requester/get_certificate.c b/unit_test/test_spdm_requester/get_certificate.c index addaa0c3839..18b5e475622 100644 --- a/unit_test/test_spdm_requester/get_certificate.c +++ b/unit_test/test_spdm_requester/get_certificate.c @@ -172,6 +172,10 @@ libspdm_return_t libspdm_requester_get_certificate_test_send_message( return LIBSPDM_STATUS_SUCCESS; case 0x1B: return LIBSPDM_STATUS_SUCCESS; + case 0x1C: + return LIBSPDM_STATUS_SUCCESS; + case 0x1D: + return LIBSPDM_STATUS_SUCCESS; default: return LIBSPDM_STATUS_SEND_FAIL; } @@ -2030,6 +2034,137 @@ libspdm_return_t libspdm_requester_get_certificate_test_receive_message( } return LIBSPDM_STATUS_SUCCESS; + case 0x1C: { + spdm_certificate_response_t *spdm_response; + size_t spdm_response_size; + size_t transport_header_size; + uint16_t portion_length; + uint16_t remainder_length; + size_t count; + static size_t calling_index = 0; + + if (m_libspdm_local_certificate_chain == NULL) { + libspdm_read_responder_public_certificate_chain_alias_cert_entire( + m_libspdm_use_hash_algo, m_libspdm_use_asym_algo, + &m_libspdm_local_certificate_chain, + &m_libspdm_local_certificate_chain_size, NULL, NULL); + } + if (m_libspdm_local_certificate_chain == NULL) { + return LIBSPDM_STATUS_RECEIVE_FAIL; + } + count = (m_libspdm_local_certificate_chain_size + + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN - 1) / + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN; + if (calling_index != count - 1) { + portion_length = LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN; + remainder_length = + (uint16_t)(m_libspdm_local_certificate_chain_size - + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN * + (calling_index + 1)); + } else { + portion_length = (uint16_t)( + m_libspdm_local_certificate_chain_size - + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN * (count - 1)); + remainder_length = 0; + } + + spdm_response_size = + sizeof(spdm_certificate_response_t) + portion_length; + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_12; + spdm_response->header.request_response_code = SPDM_CERTIFICATE; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + spdm_response->portion_length = portion_length; + spdm_response->remainder_length = remainder_length; + libspdm_copy_mem(spdm_response + 1, + (size_t)(*response) + *response_size - (size_t)(spdm_response + 1), + (uint8_t *)m_libspdm_local_certificate_chain + + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN * calling_index, + portion_length); + + libspdm_transport_test_encode_message(spdm_context, NULL, false, + false, spdm_response_size, + spdm_response, response_size, + response); + + calling_index++; + if (calling_index == count) { + calling_index = 0; + free(m_libspdm_local_certificate_chain); + m_libspdm_local_certificate_chain = NULL; + m_libspdm_local_certificate_chain_size = 0; + } + } + return LIBSPDM_STATUS_SUCCESS; + + case 0x1D: { + spdm_certificate_response_t *spdm_response; + size_t spdm_response_size; + size_t transport_header_size; + uint16_t portion_length; + uint16_t remainder_length; + size_t count; + static size_t calling_index = 0; + + if (m_libspdm_local_certificate_chain == NULL) { + libspdm_read_responder_public_certificate_chain_alias_cert_till_dev_cert_ca( + m_libspdm_use_hash_algo, m_libspdm_use_asym_algo, + &m_libspdm_local_certificate_chain, + &m_libspdm_local_certificate_chain_size, NULL, NULL); + } + if (m_libspdm_local_certificate_chain == NULL) { + return LIBSPDM_STATUS_RECEIVE_FAIL; + } + count = (m_libspdm_local_certificate_chain_size + + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN - 1) / + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN; + if (calling_index != count - 1) { + portion_length = LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN; + remainder_length = + (uint16_t)(m_libspdm_local_certificate_chain_size - + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN * + (calling_index + 1)); + } else { + portion_length = (uint16_t)( + m_libspdm_local_certificate_chain_size - + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN * (count - 1)); + remainder_length = 0; + } + + spdm_response_size = + sizeof(spdm_certificate_response_t) + portion_length; + transport_header_size = LIBSPDM_TEST_TRANSPORT_HEADER_SIZE; + spdm_response = (void *)((uint8_t *)*response + transport_header_size); + + spdm_response->header.spdm_version = SPDM_MESSAGE_VERSION_12; + spdm_response->header.request_response_code = SPDM_CERTIFICATE; + spdm_response->header.param1 = 0; + spdm_response->header.param2 = 0; + spdm_response->portion_length = portion_length; + spdm_response->remainder_length = remainder_length; + libspdm_copy_mem(spdm_response + 1, + (size_t)(*response) + *response_size - (size_t)(spdm_response + 1), + (uint8_t *)m_libspdm_local_certificate_chain + + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN * calling_index, + portion_length); + + libspdm_transport_test_encode_message(spdm_context, NULL, false, + false, spdm_response_size, + spdm_response, response_size, + response); + + calling_index++; + if (calling_index == count) { + calling_index = 0; + free(m_libspdm_local_certificate_chain); + m_libspdm_local_certificate_chain = NULL; + m_libspdm_local_certificate_chain_size = 0; + } + } + return LIBSPDM_STATUS_SUCCESS; default: return LIBSPDM_STATUS_RECEIVE_FAIL; } @@ -3811,6 +3946,134 @@ void libspdm_test_requester_get_certificate_case27(void **state) cert_chain); assert_int_equal(status, LIBSPDM_STATUS_INVALID_MSG_FIELD); free(data); + + if (m_libspdm_local_certificate_chain != NULL) { + free(m_libspdm_local_certificate_chain); + m_libspdm_local_certificate_chain = NULL; + } +} + +/** + * Test 28: Normal case, request a certificate chain. Validates certificate by using a preloaded chain instead of root hash + * Expected Behavior: receives the correct number of Certificate messages + **/ +void libspdm_test_requester_get_certificate_case28(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + size_t cert_chain_size; + uint8_t cert_chain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; + void *data; + size_t data_size; + void *hash; + size_t hash_size; + const uint8_t *root_cert; + size_t root_cert_size; +#if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT + size_t count; +#endif + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x1C; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = + LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP; + libspdm_read_responder_public_certificate_chain_alias_cert_entire( + m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data, + &data_size, &hash, &hash_size); + libspdm_x509_get_cert_from_cert_chain((uint8_t *)data + sizeof(spdm_cert_chain_t) + hash_size, + data_size - sizeof(spdm_cert_chain_t) - hash_size, 0, + &root_cert, &root_cert_size); + + spdm_context->local_context.peer_root_cert_provision_size[0] = 0; + spdm_context->local_context.peer_root_cert_provision[0] = NULL; + libspdm_reset_message_b(spdm_context); + 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->connection_info.algorithm.req_base_asym_alg = + m_libspdm_use_req_asym_algo; + spdm_context->local_context.is_requester = true; + + cert_chain_size = sizeof(cert_chain); + libspdm_zero_mem(cert_chain, sizeof(cert_chain)); + status = libspdm_get_certificate(spdm_context, NULL, 0, &cert_chain_size, + cert_chain); + assert_int_equal(status, LIBSPDM_STATUS_SUCCESS); +#if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT + count = (data_size + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN - 1) / + LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN; + assert_int_equal(spdm_context->transcript.message_b.buffer_size, + sizeof(spdm_get_certificate_request_t) * count + + sizeof(spdm_certificate_response_t) * count + + data_size); +#endif + free(data); +} + +/** + * Test 29: Normal case, request a certificate chain. Validates certificate by using a preloaded chain instead of root hash + * Expected Behavior: receives the correct number of Certificate messages + **/ +void libspdm_test_requester_get_certificate_case29(void **state) +{ + libspdm_return_t status; + libspdm_test_context_t *spdm_test_context; + libspdm_context_t *spdm_context; + size_t cert_chain_size; + uint8_t cert_chain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; + void *data; + size_t data_size; + void *hash; + size_t hash_size; + const uint8_t *root_cert; + size_t root_cert_size; + + spdm_test_context = *state; + spdm_context = spdm_test_context->spdm_context; + spdm_test_context->case_id = 0x1D; + spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 << + SPDM_VERSION_NUMBER_SHIFT_BIT; + spdm_context->connection_info.connection_state = + LIBSPDM_CONNECTION_STATE_AFTER_DIGESTS; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP; + spdm_context->connection_info.capability.flags |= + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP; + libspdm_read_responder_public_certificate_chain_alias_cert_entire( + m_libspdm_use_hash_algo, + m_libspdm_use_asym_algo, &data, + &data_size, &hash, &hash_size); + libspdm_x509_get_cert_from_cert_chain((uint8_t *)data + sizeof(spdm_cert_chain_t) + hash_size, + data_size - sizeof(spdm_cert_chain_t) - hash_size, 0, + &root_cert, &root_cert_size); + + spdm_context->local_context.peer_root_cert_provision_size[0] = 0; + spdm_context->local_context.peer_root_cert_provision[0] = NULL; + libspdm_reset_message_b(spdm_context); + 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->connection_info.algorithm.req_base_asym_alg = + m_libspdm_use_req_asym_algo; + spdm_context->local_context.is_requester = true; + + cert_chain_size = sizeof(cert_chain); + libspdm_zero_mem(cert_chain, sizeof(cert_chain)); + status = libspdm_get_certificate(spdm_context, NULL, 0, &cert_chain_size, + cert_chain); + assert_int_equal(status, LIBSPDM_STATUS_VERIF_FAIL); + free(data); } libspdm_test_context_t m_libspdm_requester_get_certificate_test_context = { @@ -3880,6 +4143,10 @@ int libspdm_requester_get_certificate_test_main(void) cmocka_unit_test(libspdm_test_requester_get_certificate_case26), /* Fail response: responder return wrong SlotID 3, not equal with SlotID 0 in request message. */ cmocka_unit_test(libspdm_test_requester_get_certificate_case27), + /*Successful response: get the entire alias_cert model cert_chain*/ + cmocka_unit_test(libspdm_test_requester_get_certificate_case28), + /*Fail response: get the partial alias_cert model cert_chain*/ + cmocka_unit_test(libspdm_test_requester_get_certificate_case29), }; libspdm_setup_test_context(&m_libspdm_requester_get_certificate_test_context);