diff --git a/CMakeLists.txt b/CMakeLists.txt index b2253119786..69ade413cb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ SET(CRYPTO ${CRYPTO} CACHE STRING "Choose the crypto of build: mbedtls openssl" SET(GCOV ${GCOV} CACHE STRING "Choose the target of Gcov: ON OFF, and default is OFF" FORCE) SET(STACK_USAGE ${STACK_USAGE} CACHE STRING "Choose the target of STACK_USAGE: ON OFF, and default is OFF" FORCE) SET(BUILD_LINUX_SHARED_LIB ${BUILD_LINUX_SHARED_LIB} CACHE STRING "Choose if libspdm shared library should be built for linux: ON OFF, and default is OFF" FORCE) +SET(X509_IGNORE_CRITICAL ${X509_IGNORE_CRITICAL} CACHE STRING "Choose if libspdm ignore unhandled critical cert extensions : ON OFF, and default is OFF" FORCE) if(NOT GCOV) SET(GCOV "OFF") @@ -32,6 +33,10 @@ if(NOT BUILD_LINUX_SHARED_LIB) SET(BUILD_LINUX_SHARED_LIB "OFF") endif() +if(NOT X509_IGNORE_CRITICAL) + SET(X509_IGNORE_CRITICAL "OFF") +endif() + SET(LIBSPDM_DIR ${PROJECT_SOURCE_DIR}) # @@ -164,6 +169,10 @@ else() MESSAGE(FATAL_ERROR "Unknown CRYPTO") endif() +if ((X509_IGNORE_CRITICAL STREQUAL "ON") AND (CRYPTO STREQUAL "openssl")) + add_definitions(-DOPENSSL_IGNORE_CRITICAL=1) +endif() + if(ENABLE_BINARY_BUILD STREQUAL "1") if(NOT CRYPTO STREQUAL "openssl") MESSAGE(FATAL_ERROR "enabling binary build not supported for non-openssl") @@ -940,6 +949,7 @@ else() ADD_SUBDIRECTORY(unit_test/test_spdm_fips) ADD_SUBDIRECTORY(unit_test/test_spdm_secured_message) ADD_SUBDIRECTORY(unit_test/test_spdm_vendor_cmds) + ADD_SUBDIRECTORY(unit_test/test_spdm_callback) endif() if((NOT TOOLCHAIN STREQUAL "ARM_DS2022") AND (NOT TOOLCHAIN STREQUAL "RISCV_XPACK")) diff --git a/os_stub/cryptlib_openssl/pk/x509.c b/os_stub/cryptlib_openssl/pk/x509.c index b041d863f2f..19c354df9cc 100644 --- a/os_stub/cryptlib_openssl/pk/x509.c +++ b/os_stub/cryptlib_openssl/pk/x509.c @@ -1879,6 +1879,11 @@ bool libspdm_x509_verify_cert(const uint8_t *cert, size_t cert_size, */ X509_STORE_set_flags(cert_store, X509_V_FLAG_PARTIAL_CHAIN); + +#if OPENSSL_IGNORE_CRITICAL + X509_STORE_set_flags(cert_store, X509_V_FLAG_IGNORE_CRITICAL); +#endif + #ifndef OPENSSL_CHECK_TIME X509_STORE_set_flags(cert_store, X509_V_FLAG_NO_CHECK_TIME); #endif diff --git a/unit_test/spdm_unit_test_common/spdm_unit_test.h b/unit_test/spdm_unit_test_common/spdm_unit_test.h index 0c9190d871e..1004f7c0485 100644 --- a/unit_test/spdm_unit_test_common/spdm_unit_test.h +++ b/unit_test/spdm_unit_test_common/spdm_unit_test.h @@ -161,4 +161,10 @@ typedef enum void libspdm_force_error (libspdm_error_target_t target); void libspdm_release_error (libspdm_error_target_t target); +bool libspdm_verify_spdm_cert_chain_with_dice(void *spdm_context, uint8_t slot_id, + size_t cert_chain_size, const void *cert_chain, + const void **trust_anchor, + size_t *trust_anchor_size); + +bool libspdm_verify_cert_dicetcbinfo(const void *cert, size_t cert_size, size_t *spdm_get_dice_tcb_info_size); #endif diff --git a/unit_test/test_spdm_callback/CMakeLists.txt b/unit_test/test_spdm_callback/CMakeLists.txt new file mode 100644 index 00000000000..b6f68939d28 --- /dev/null +++ b/unit_test/test_spdm_callback/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 2.8.12) + +INCLUDE_DIRECTORIES(${LIBSPDM_DIR}/include + ${LIBSPDM_DIR}/unit_test/include + ${LIBSPDM_DIR}/os_stub/spdm_device_secret_lib_sample + ${LIBSPDM_DIR}/unit_test/cmockalib/cmocka/include + ${LIBSPDM_DIR}/unit_test/cmockalib/cmocka/include/cmockery + ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common + ${LIBSPDM_DIR}/os_stub/include + ${LIBSPDM_DIR}/os_stub +) + +if(CMAKE_SYSTEM_NAME MATCHES "Windows") + if((TOOLCHAIN STREQUAL "VS2015") OR (TOOLCHAIN STREQUAL "VS2019") OR (TOOLCHAIN STREQUAL "VS2022")) + ADD_COMPILE_OPTIONS(/wd4819) + endif() +endif() + +SET(src_test_spdm_callback + test_spdm_callback.c + spdm_cert_verify_callback.c + ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/support.c + ${LIBSPDM_DIR}/unit_test/spdm_unit_test_common/algo.c +) + +SET(test_spdm_callback_LIBRARY + memlib + debuglib + spdm_crypt_lib + ${CRYPTO_LIB_PATHS} + cryptlib_${CRYPTO} + rnglib + malloclib + cmockalib + spdm_device_secret_lib_sample + spdm_crypt_ext_lib + spdm_common_lib + spdm_secured_message_lib +) + +if(TOOLCHAIN STREQUAL "ARM_DS2022") + SET(test_spdm_callback_LIBRARY ${test_spdm_callback_LIBRARY} armbuild_lib) +endif() + +if((TOOLCHAIN STREQUAL "KLEE") OR (TOOLCHAIN STREQUAL "CBMC")) + ADD_EXECUTABLE(test_spdm_callback + ${src_test_spdm_callback} + $ + $ + $ + $ + $ + $ + $ + ) +else() + ADD_EXECUTABLE(test_spdm_callback ${src_test_spdm_callback}) + TARGET_LINK_LIBRARIES(test_spdm_callback ${test_spdm_callback_LIBRARY}) +endif() diff --git a/unit_test/test_spdm_callback/spdm_cert_verify_callback.c b/unit_test/test_spdm_callback/spdm_cert_verify_callback.c new file mode 100644 index 00000000000..ee1cebeeca0 --- /dev/null +++ b/unit_test/test_spdm_callback/spdm_cert_verify_callback.c @@ -0,0 +1,264 @@ +/** + * Copyright Notice: + * Copyright 2024 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "spdm_unit_test.h" +#include "library/spdm_common_lib.h" +#include "spdm_crypt_ext_lib/spdm_crypt_ext_lib.h" + +/** + * tcg-dice-TcbInfo OID: 2.23.133.5.4.1 + * https://trustedcomputinggroup.org/wp-content/uploads/DICE-Attestation-Architecture-Version-1.1-Revision-18_pub.pdf + **/ +uint8_t m_libspdm_tcg_dice_tcbinfo_oid[] = {0x67, 0x81, 0x05, 0x05, 0x04, 0x01}; + +/*the cert chain must have a or more cert with DiceTcbInfo extension*/ +bool m_libspdm_must_have_dice_tcb_info = true; + +/*reference DiceTcbinfo*/ + +/*vendor: INTC*/ +uint8_t m_libspdm_dice_tcbinfo_vendor[] = {0x49, 0x4E, 0x54, 0x43}; +/*model: S3M GNR*/ +uint8_t m_libspdm_dice_tcbinfo_model[] = {0x53, 0x33, 0x4D, 0x20, 0x47, 0x4E, 0x52}; +/*version: 000200000000008B*/ +uint8_t m_libspdm_dice_tcbinfo_version[] = {0x30, 0x30, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x38, 0x42}; +/*svn*/ +uint8_t m_libspdm_dice_tcbinfo_svn[] = {0x01}; +/*layer*/ +uint8_t m_libspdm_dice_tcbinfo_layer[] = {0x01}; +/*fwids*/ +uint8_t m_libspdm_dice_tcbinfo_fwids[] = {0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, + 0x02, 0x02, 0x04, 0x30, 0x6B, 0x44, 0x7B, 0x5E, 0x99, + 0x21, 0x0A, 0x58, 0x8A, 0x7B, 0x31, 0x7D, 0xBA, 0x2D, + 0x4A, 0x7F, 0x75, 0xE6, 0x97, 0xF2, 0x07, 0xE0, 0xC2, + 0x99, 0x78, 0xF3, 0xF6, 0x2B, 0x53, 0xF5, 0xBE, 0xEB, + 0x73, 0xF0, 0x37, 0xB8, 0x79, 0xC1, 0xFF, 0x76, 0x2A, + 0x3A, 0x39, 0xCA, 0xE2, 0x8C, 0xF0, 0x56}; +/*type*/ +uint8_t m_libspdm_dice_tcbinfo_type[] = {0x46, 0x69, 0x72, 0x6D, 0x77, 0x61, 0x72, 0x65, 0x20, + 0x44, 0x69, 0x67, 0x65, 0x73, 0x74}; + +/*verify cert DiceTcbInfo extension*/ +bool libspdm_verify_cert_dicetcbinfo(const void *cert, size_t cert_size, size_t *spdm_get_dice_tcb_info_size) { + bool result; + uint8_t spdm_dice_tcb_info[256]; + size_t spdm_dice_tcb_info_size; + uint8_t *ptr; + int32_t length; + size_t obj_len; + uint8_t *end; + + spdm_dice_tcb_info_size = 256; + *spdm_get_dice_tcb_info_size = 0; + result = libspdm_x509_get_extension_data(cert, cert_size, + m_libspdm_tcg_dice_tcbinfo_oid, + sizeof(m_libspdm_tcg_dice_tcbinfo_oid), + spdm_dice_tcb_info, &spdm_dice_tcb_info_size); + if (!result) { + return false; + } else if (spdm_dice_tcb_info_size == 0) { + return true; + } + + *spdm_get_dice_tcb_info_size = spdm_dice_tcb_info_size; + length = (int32_t)spdm_dice_tcb_info_size; + ptr = (uint8_t*)(size_t)spdm_dice_tcb_info; + obj_len = 0; + end = ptr + length; + + /*get DiceTcbInfo*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); + if (!result) { + return false; + } + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); + if (!result) { + return false; + } + + /*vendor*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_vendor)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_vendor, obj_len))) { + return false; + } + ptr += obj_len; + } + /*model*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 1); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_model)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_model, obj_len))) { + return false; + } + ptr += obj_len; + } + /*version*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 2); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_version)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_version, obj_len))) { + return false; + } + ptr += obj_len; + } + /*svn*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 3); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_svn)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_svn, obj_len))) { + return false; + } + ptr += obj_len; + } + /*layer*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 4); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_layer)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_layer, obj_len))) { + return false; + } + ptr += obj_len; + } + /*index*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 5); + if (result) { + ptr += obj_len; + } + /*fwids*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + (LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC | + LIBSPDM_CRYPTO_ASN1_CONSTRUCTED) + 6); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_fwids)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_fwids, obj_len))) { + return false; + } + ptr += obj_len; + } + /*flags*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 7); + if (result) { + ptr += obj_len; + } + /*vendorInfo*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 8); + if (result) { + ptr += obj_len; + } + /*type*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 9); + if (result) { + if ((obj_len != sizeof(m_libspdm_dice_tcbinfo_type)) || + (!libspdm_consttime_is_mem_equal(ptr, m_libspdm_dice_tcbinfo_type, obj_len))) { + return false; + } + ptr += obj_len; + } + /*flagMask*/ + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC + 10); + if (result) { + ptr += obj_len; + } + + if (ptr == end) { + return true; + } else { + return false; + } +} + +/*callback function for verifying cert_chain DiceTcbInfo extension*/ +bool libspdm_verify_spdm_cert_chain_with_dice(void *spdm_context, uint8_t slot_id, + size_t cert_chain_size, const void *cert_chain, + const void **trust_anchor, + size_t *trust_anchor_size) +{ + bool result; + libspdm_context_t *context; + const uint8_t *cert_chain_data; + size_t cert_chain_data_size; + size_t hash_size; + uint8_t *ptr; + uint8_t *tem_ptr; + int32_t length; + size_t obj_len; + uint8_t *end; + size_t cert_dice_tcb_info_size; + bool cert_chain_have_dice; + + /*verify peer cert chain integrity*/ + result = libspdm_verify_peer_cert_chain_buffer_integrity(spdm_context, cert_chain, + cert_chain_size); + if (!result) { + return false; + } + + /*verify peer cert chain authority*/ + result = libspdm_verify_peer_cert_chain_buffer_authority(spdm_context, cert_chain, + cert_chain_size, trust_anchor, + trust_anchor_size); + if (!result) { + return false; + } + + context = spdm_context; + hash_size = libspdm_get_hash_size(context->connection_info.algorithm.base_hash_algo); + + cert_chain_data = (const uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + hash_size; + cert_chain_data_size = cert_chain_size - sizeof(spdm_cert_chain_t) - hash_size; + + length = (int32_t)cert_chain_data_size; + ptr = (uint8_t*)(size_t)cert_chain_data; + obj_len = 0; + end = ptr + length; + cert_dice_tcb_info_size = 0; + cert_chain_have_dice = false; + + while (ptr < end) { + tem_ptr = ptr; + result = libspdm_asn1_get_tag(&ptr, end, &obj_len, + LIBSPDM_CRYPTO_ASN1_SEQUENCE | + LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); + if (result) { + /*verify Dice TCB info*/ + result = libspdm_verify_cert_dicetcbinfo(tem_ptr, obj_len + (ptr - tem_ptr), &cert_dice_tcb_info_size); + if (!result) { + return false; + } else { + if (cert_dice_tcb_info_size != 0) { + cert_chain_have_dice = true; + } + } + /* Move to next cert*/ + ptr += obj_len; + } + } + + if (m_libspdm_must_have_dice_tcb_info && !cert_chain_have_dice) { + return false; + } + + if (ptr == end) { + return true; + } else { + return false; + } +} diff --git a/unit_test/test_spdm_callback/test_spdm_callback.c b/unit_test/test_spdm_callback/test_spdm_callback.c new file mode 100644 index 00000000000..dbf6a484b22 --- /dev/null +++ b/unit_test/test_spdm_callback/test_spdm_callback.c @@ -0,0 +1,139 @@ +/** + * Copyright Notice: + * Copyright 2024 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#define LIBSPDM_MAX_CERT_CHAIN_SIZE 0x2000 + +#include "spdm_unit_test.h" +#include "library/spdm_common_lib.h" +#include "spdm_crypt_ext_lib/spdm_crypt_ext_lib.h" + +/*read cert chain or root cert with dice extension*/ +bool libspdm_read_dice_certificate_chain( + void **data, size_t *size, bool is_cert_chain) +{ + bool res; + void *file_data; + size_t file_size; + char *file; + + *data = NULL; + *size = 0; + + if (is_cert_chain) { + file = "dice_cert/dice_cert_chain.bin"; + } else { + file = "dice_cert/dice_root_cert.der"; + } + + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + *data = file_data; + *size = file_size; + + return true; +} + +void libspdm_test_spdm_verify_cert_chain_callback_function(void **state) +{ + bool status; + libspdm_context_t *spdm_context; + uint8_t slot_id; + void *spdm_cert_chain_with_dicetcbinfo; + size_t spdm_cert_chain_size_with_dicetcbinfo; + void *spdm_root_cert_for_dicetcbinfo; + size_t spdm_root_cert_size_for_dicetcbinfo; + + spdm_context = (void *)malloc(libspdm_get_context_size()); + if (spdm_context == NULL) { + assert_true(false); + } + libspdm_init_context(spdm_context); + spdm_context->local_context.is_requester = true; + spdm_context->connection_info.algorithm.base_hash_algo = + SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384; + spdm_context->connection_info.algorithm.base_asym_algo = + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384; + slot_id = 0; + + status = libspdm_read_dice_certificate_chain(&spdm_root_cert_for_dicetcbinfo, + &spdm_root_cert_size_for_dicetcbinfo, false); + assert_true(status); + spdm_context->local_context.peer_root_cert_provision_size[0] = + spdm_root_cert_size_for_dicetcbinfo; + spdm_context->local_context.peer_root_cert_provision[0] = + (uint8_t *)spdm_root_cert_for_dicetcbinfo; + + status = libspdm_read_dice_certificate_chain(&spdm_cert_chain_with_dicetcbinfo, + &spdm_cert_chain_size_with_dicetcbinfo, true); + assert_true(status); + + /*verify dice cert chain by using call back function*/ + status = libspdm_verify_spdm_cert_chain_with_dice(spdm_context, slot_id, + spdm_cert_chain_size_with_dicetcbinfo, + spdm_cert_chain_with_dicetcbinfo, NULL, NULL); + assert_true(status); + + free(spdm_root_cert_for_dicetcbinfo); + free(spdm_cert_chain_with_dicetcbinfo); + free(spdm_context); +} + +void libspdm_test_spdm_verify_cert_dicetcdinfo(void **state) +{ + bool status; + void *file_data; + size_t file_size; + char *file; + size_t cert_dice_tcb_info_size; + + file = "dice_cert/dice_cert.bin"; + cert_dice_tcb_info_size = 0; + + libspdm_read_input_file(file, &file_data, &file_size); + + /*verify dice cert*/ + status = libspdm_verify_cert_dicetcbinfo(file_data, file_size, &cert_dice_tcb_info_size); + assert_true(status); + free(file_data); +} + +int libspdm_crypt_lib_setup(void **state) +{ + return 0; +} + +int libspdm_crypt_lib_teardown(void **state) +{ + return 0; +} + +int libspdm_crypt_lib_test_main(void) +{ + const struct CMUnitTest spdm_crypt_lib_tests[] = { + cmocka_unit_test( + libspdm_test_spdm_verify_cert_chain_callback_function), + cmocka_unit_test( + libspdm_test_spdm_verify_cert_dicetcdinfo), + }; + + return cmocka_run_group_tests(spdm_crypt_lib_tests, + libspdm_crypt_lib_setup, + libspdm_crypt_lib_teardown); +} + +int main(void) +{ + int return_value = 0; + + if (libspdm_crypt_lib_test_main() != 0) { + return_value = 1; + } + + return return_value; +}