From dca7189058dd0f035c913416597eaf3bf9a3fc80 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Wed, 31 Jul 2024 16:08:19 +0200 Subject: [PATCH] Add libspdm 3.3.0 patch --- libspdm/3.3.0/README | 6 + libspdm/3.3.0/libspdm-3.3.0.patch | 12140 ++++++++++++++++++++++++++++ 2 files changed, 12146 insertions(+) create mode 100644 libspdm/3.3.0/README create mode 100644 libspdm/3.3.0/libspdm-3.3.0.patch diff --git a/libspdm/3.3.0/README b/libspdm/3.3.0/README new file mode 100644 index 000000000..d554e8fe0 --- /dev/null +++ b/libspdm/3.3.0/README @@ -0,0 +1,6 @@ +This folder contains patches for libspdm to work with wolfSSL. Patches make it +easier to add support for newer versions of a target library. The format of +the patch names is: + libspdm-.patch +Instructions for applying each patch are included in the patch commit +message. diff --git a/libspdm/3.3.0/libspdm-3.3.0.patch b/libspdm/3.3.0/libspdm-3.3.0.patch new file mode 100644 index 000000000..6dd6d64ea --- /dev/null +++ b/libspdm/3.3.0/libspdm-3.3.0.patch @@ -0,0 +1,12140 @@ +From 9e155806031d17d38253c3080d6463ecc9219190 Mon Sep 17 00:00:00 2001 +From: Juliusz Sosinowicz +Date: Tue, 30 Jul 2024 17:21:38 +0200 +Subject: [PATCH] wolfSSL patch + +This patch implements wolfSSL support in libspdm. + +Compile wolfSSL with: + ./configure --enable-all --enable-static + make + make install + +Compile libspdm with: + mkdir build + cd build + cmake -DARCH=x64 -DTOOLCHAIN=GCC -DCRYPTO=wolfssl -DENABLE_BINARY_BUILD=1 -DCOMPILED_LIBWOLFSSL_PATH=/usr/local/lib/libwolfssl.a -DWOLFSSL_INCDIR=/usr/local/include .. + make + +Tests passed: +- test_crypt +- test_spdm_secured_message +- test_spdm_crypt +- test_spdm_secured_message + +When building for FIPS or with wolfSSL releases 5.7.2 and older add `CPPFLAGS=-DRSA_LOW_MEM` to the wolfSSL configuration: + ./configure --enable-all CPPFLAGS=-DRSA_LOW_MEM + +To debug the binary, configure wolfSSL with `--enable-debug` and libspdm with `-DTARGET=Debug` + +Co-authored-by: Daniel Pouzzner +--- + CMakeLists.txt | 186 +- + library/spdm_crypt_lib/libspdm_crypt_cert.c | 2 + + os_stub/cryptlib_wolfssl/CMakeLists.txt | 59 + + .../cryptlib_wolfssl/cipher/aead_aes_gcm.c | 267 ++ + .../cipher/aead_chacha20_poly1305.c | 249 ++ + .../cryptlib_wolfssl/cipher/aead_sm4_gcm.c | 81 + + os_stub/cryptlib_wolfssl/der/der.c | 284 ++ + os_stub/cryptlib_wolfssl/hash/sha.c | 582 ++++ + os_stub/cryptlib_wolfssl/hash/sha3.c | 423 +++ + os_stub/cryptlib_wolfssl/hash/sm3.c | 154 + + os_stub/cryptlib_wolfssl/hmac/hmac_sha.c | 683 +++++ + os_stub/cryptlib_wolfssl/hmac/hmac_sha3.c | 457 +++ + os_stub/cryptlib_wolfssl/hmac/hmac_sm3.c | 163 + + os_stub/cryptlib_wolfssl/internal_crypt_lib.h | 103 + + os_stub/cryptlib_wolfssl/kdf/hkdf_sha.c | 404 +++ + os_stub/cryptlib_wolfssl/kdf/hkdf_sha3.c | 238 ++ + os_stub/cryptlib_wolfssl/kdf/hkdf_sm3.c | 98 + + os_stub/cryptlib_wolfssl/pem/pem.c | 379 +++ + os_stub/cryptlib_wolfssl/pk/dh.c | 342 +++ + os_stub/cryptlib_wolfssl/pk/ec.c | 1101 +++++++ + os_stub/cryptlib_wolfssl/pk/ecd.c | 477 +++ + os_stub/cryptlib_wolfssl/pk/rsa_basic.c | 588 ++++ + os_stub/cryptlib_wolfssl/pk/rsa_ext.c | 612 ++++ + os_stub/cryptlib_wolfssl/pk/sm2.c | 915 ++++++ + os_stub/cryptlib_wolfssl/pk/x509.c | 2704 +++++++++++++++++ + os_stub/cryptlib_wolfssl/rand/rand.c | 40 + + .../sys_call/crt_wrapper_host.c | 120 + + 27 files changed, 11651 insertions(+), 60 deletions(-) + create mode 100644 os_stub/cryptlib_wolfssl/CMakeLists.txt + create mode 100644 os_stub/cryptlib_wolfssl/cipher/aead_aes_gcm.c + create mode 100644 os_stub/cryptlib_wolfssl/cipher/aead_chacha20_poly1305.c + create mode 100644 os_stub/cryptlib_wolfssl/cipher/aead_sm4_gcm.c + create mode 100644 os_stub/cryptlib_wolfssl/der/der.c + create mode 100644 os_stub/cryptlib_wolfssl/hash/sha.c + create mode 100644 os_stub/cryptlib_wolfssl/hash/sha3.c + create mode 100644 os_stub/cryptlib_wolfssl/hash/sm3.c + create mode 100644 os_stub/cryptlib_wolfssl/hmac/hmac_sha.c + create mode 100644 os_stub/cryptlib_wolfssl/hmac/hmac_sha3.c + create mode 100644 os_stub/cryptlib_wolfssl/hmac/hmac_sm3.c + create mode 100644 os_stub/cryptlib_wolfssl/internal_crypt_lib.h + create mode 100644 os_stub/cryptlib_wolfssl/kdf/hkdf_sha.c + create mode 100644 os_stub/cryptlib_wolfssl/kdf/hkdf_sha3.c + create mode 100644 os_stub/cryptlib_wolfssl/kdf/hkdf_sm3.c + create mode 100644 os_stub/cryptlib_wolfssl/pem/pem.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/dh.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/ec.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/ecd.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/rsa_basic.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/rsa_ext.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/sm2.c + create mode 100644 os_stub/cryptlib_wolfssl/pk/x509.c + create mode 100644 os_stub/cryptlib_wolfssl/rand/rand.c + create mode 100644 os_stub/cryptlib_wolfssl/sys_call/crt_wrapper_host.c + +diff --git a/CMakeLists.txt b/CMakeLists.txt +index b225311978..9ea09f1aba 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -40,7 +40,10 @@ SET(LIBSPDM_DIR ${PROJECT_SOURCE_DIR}) + SET(COMPILED_LIBCRYPTO_PATH ${COMPILED_LIBCRYPTO_PATH} CACHE STRING "Optionally provide a path to libcrypto" FORCE) + SET(COMPILED_LIBSSL_PATH ${COMPILED_LIBSSL_PATH} CACHE STRING "Optionally provide a path to libssl" FORCE) + +-MESSAGE("CMAKE_GENERATOR = ${CMAKE_GENERATOR}") ++set(COMPILED_LIBWOLFSSL_PATH ${COMPILED_LIBWOLFSSL_PATH} CACHE STRING "Optionally provide a path to libwolfssl.a" FORCE) ++set(WOLFSSL_INCDIR ${WOLFSSL_INCDIR} CACHE STRING "Optionally provide a path to the wolfssl header directory" FORCE) ++ ++message("CMAKE_GENERATOR = ${CMAKE_GENERATOR}") + + if(ARCH STREQUAL "x64") + MESSAGE("ARCH = x64") +@@ -160,37 +163,67 @@ elseif(CRYPTO STREQUAL "openssl") + add_definitions(-DLIBSPDM_SM2_DSA_P256_SUPPORT=0) + add_definitions(-DLIBSPDM_SM2_KEY_EXCHANGE_P256_SUPPORT=0) + add_definitions(-DLIBSPDM_AEAD_SM4_128_GCM_SUPPORT=0) ++elseif(CRYPTO STREQUAL "wolfssl") ++ message("CRYPTO = wolfssl") ++ add_definitions(-DLIBSPDM_EDDSA_ED25519_SUPPORT=0) ++ add_definitions(-DLIBSPDM_EDDSA_ED448_SUPPORT=0) ++ add_definitions(-DLIBSPDM_SM3_256_SUPPORT=0) ++ add_definitions(-DLIBSPDM_SM2_DSA_P256_SUPPORT=0) ++ add_definitions(-DLIBSPDM_SM2_KEY_EXCHANGE_P256_SUPPORT=0) ++ add_definitions(-DLIBSPDM_AEAD_SM4_128_GCM_SUPPORT=0) ++ add_definitions(-DCRYPTO_IS_WOLFSSL) ++ ++ if(NOT WOLFSSL_INCDIR) ++ set(WOLFSSL_INCDIR "/usr/local/include/wolfssl") ++ endif() + else() + MESSAGE(FATAL_ERROR "Unknown CRYPTO") + endif() + + if(ENABLE_BINARY_BUILD STREQUAL "1") +- if(NOT CRYPTO STREQUAL "openssl") +- MESSAGE(FATAL_ERROR "enabling binary build not supported for non-openssl") +- endif() ++ if(CRYPTO STREQUAL "openssl") + +- if(NOT COMPILED_LIBCRYPTO_PATH) +- MESSAGE(FATAL_ERROR "enabling binary build requires path to libcrypto.") +- endif() ++ if(NOT COMPILED_LIBCRYPTO_PATH) ++ message(FATAL_ERROR "enabling binary build for openssl requires path to libcrypto.") ++ endif() ++ ++ if(NOT COMPILED_LIBSSL_PATH) ++ message(FATAL_ERROR "enabling binary build for openssl requires path to libssl.") ++ endif() ++ ++ message("ENABLE_BINARY_BUILD=1 for openssl") ++ message("COMPILED_LIBCRYPTO_PATH=${COMPILED_LIBCRYPTO_PATH}") ++ message("COMPILED_LIBSSL_PATH=${COMPILED_LIBSSL_PATH}") ++ ++ set(CRYPTO_LIB_PATHS ${COMPILED_LIBCRYPTO_PATH} ${COMPILED_LIBSSL_PATH}) ++ ++ elseif(CRYPTO STREQUAL "wolfssl") ++ ++ if(NOT COMPILED_LIBWOLFSSL_PATH) ++ set(COMPILED_LIBWOLFSSL_PATH "/usr/local/lib/libwolfssl.a") ++ endif() ++ ++ message("ENABLE_BINARY_BUILD=1 for wolfssl") ++ message("COMPILED_LIBWOLFSSL_PATH=${COMPILED_LIBWOLFSSL_PATH}") ++ message("LIBWOLFSSL_PATH=${COMPILED_LIBWOLFSSL_PATH}") ++ ++ set(CRYPTO_LIB_PATHS ${COMPILED_LIBWOLFSSL_PATH} -lm) ++ ++ else() ++ ++ message(FATAL_ERROR "enabling binary build supported only for openssl and wolfssl") + +- if(NOT COMPILED_LIBSSL_PATH) +- MESSAGE(FATAL_ERROR "enabling binary build requires path to libssl.") + endif() + + # Disable EDDSA when binary builds are enabled. EDDSA may be enabled in the future. + add_definitions(-DLIBSPDM_EDDSA_ED25519_SUPPORT=0) + add_definitions(-DLIBSPDM_EDDSA_ED448_SUPPORT=0) + +- MESSAGE("ENABLE_BINARY_BUILD=1") +- MESSAGE("COMPILED_LIBCRYPTO_PATH=${COMPILED_LIBCRYPTO_PATH}") +- MESSAGE("COMPILED_LIBSSL_PATH=${COMPILED_LIBSSL_PATH}") +- MESSAGE("Disabling EDDSA support due to ENABLE_BINARY_BUILD=1") +- +- SET(CRYPTO_LIB_PATHS ${COMPILED_LIBCRYPTO_PATH} ${COMPILED_LIBSSL_PATH}) ++ message("Disabling EDDSA support due to ENABLE_BINARY_BUILD=1") + + else() +- SET(CRYPTO_LIB_PATHS ${CRYPTO}lib) +- MESSAGE("ENABLE_BINARY_BUILD=0; Building ${CRYPTO} library from source.") ++ set(CRYPTO_LIB_PATHS ${CRYPTO}lib) ++ message("ENABLE_BINARY_BUILD=0; Building ${CRYPTO} library from source.") + endif() + + if(ENABLE_CODEQL STREQUAL "ON") +@@ -220,9 +253,11 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) + if(STACK_USAGE STREQUAL "ON") +- SET(OPENSSL_FLAGS ${OPENSSL_FLAGS} -fstack-usage) ++ set(OPENSSL_FLAGS ${OPENSSL_FLAGS} -fstack-usage) ++ set(WOLFSSL_FLAGS ${WOLFSSL_FLAGS} -fstack-usage) + endif() + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + if(STACK_USAGE STREQUAL "ON") +@@ -294,8 +329,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") +@@ -335,9 +371,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + ADD_COMPILE_OPTIONS(-g) + endif() + +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wno-error=format -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) +- SET(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -Wno-error -no-pie ${FLTO_LINK_OPTS}") ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wno-error=format -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs -Wno-error -no-pie ${FLTO_LINK_OPTS}") + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + +@@ -350,8 +387,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR arm-linux-gnueabi-gcc-ar) + +@@ -371,8 +409,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR aarch64-linux-gnu-gcc-ar) + +@@ -401,8 +440,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") +@@ -420,8 +460,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR riscv64-linux-gnu-gcc-ar) + +@@ -474,8 +515,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + ADD_COMPILE_OPTIONS(-g) + endif() + +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wno-error=format -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wno-error=format -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR riscv-none-elf-ar) + +@@ -498,8 +540,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR arc-linux-gcc-ar) + +@@ -521,8 +564,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if (ARCH STREQUAL "x64") + ADD_COMPILE_OPTIONS(-mno-red-zone) + endif() +- SET(OPENSSL_FLAGS -std=c11 -include base.h -Wno-error=format -Wno-format -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -std=c11 -include base.h -Wno-error=format -Wno-format -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR llvm-ar) + SET(CMAKE_RANLIB llvm-ranlib) +@@ -538,8 +582,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + ADD_COMPILE_OPTIONS(-g) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_LINKER goto-cc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error") +@@ -555,8 +600,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR gcc-ar) + +@@ -574,8 +620,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + ADD_COMPILE_OPTIONS(-g) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_C_CREATE_STATIC_LIBRARY "") + +@@ -593,8 +640,9 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(-fprofile-instr-generate -fcoverage-mapping) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR llvm-ar) + +@@ -607,10 +655,11 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "NIOS2_GCC") +- SET(CMAKE_C_COMPILER nios2-elf-gcc) +- ADD_COMPILE_OPTIONS(-xc -MP -MMD -pipe -O3 -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -Wno-nonnull-compare -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-builtin-declaration-mismatch -mno-hw-div -mhw-mul -mno-hw-mulx -mgpopt=global -Werror-implicit-function-declaration) +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) +- SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) ++ set(CMAKE_C_COMPILER nios2-elf-gcc) ++ add_compile_options(-xc -MP -MMD -pipe -O3 -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -Wno-nonnull-compare -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-builtin-declaration-mismatch -mno-hw-div -mhw-mul -mno-hw-mulx -mgpopt=global -Werror-implicit-function-declaration) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + + SET(CMAKE_AR nios2-elf-ar) + +@@ -653,9 +702,11 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() +- SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) + if(STACK_USAGE STREQUAL "ON") +- SET(OPENSSL_FLAGS ${OPENSSL_FLAGS} -fstack-usage) ++ set(OPENSSL_FLAGS ${OPENSSL_FLAGS} -fstack-usage) ++ set(WOLFSSL_FLAGS ${WOLFSSL_FLAGS} -fstack-usage) + endif() + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong -Wno-cast-qual) + if(STACK_USAGE STREQUAL "ON") +@@ -675,10 +726,11 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") + endif() + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group /mingw64/lib/libbcrypt.a -Wl,--end-group") + elseif(TOOLCHAIN STREQUAL "CLANG") +- SET(CMAKE_C_COMPILER clang-cl.exe) +- ADD_COMPILE_OPTIONS(-fno-strict-aliasing -Wall -Wno-array-bounds -Wno-address -flto -DUSING_LTO -D_CRT_SECURE_NO_WARNINGS /w) +- SET(OPENSSL_FLAGS /FIbase.h -Wno-cast-qual) +- SET(CMOCKA_FLAGS -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -Wformat -Wno-cast-qual) ++ set(CMAKE_C_COMPILER clang-cl.exe) ++ add_compile_options(-fno-strict-aliasing -Wall -Wno-array-bounds -Wno-address -flto -DUSING_LTO -D_CRT_SECURE_NO_WARNINGS /w) ++ set(OPENSSL_FLAGS /FIbase.h -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -Wformat -Wno-cast-qual) + + SET(CMAKE_STATIC_LINKER_FLAGS "") + +@@ -734,10 +786,11 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Windows") + SET(CMAKE_C_LINK_EXECUTABLE " -o ") + + elseif(TOOLCHAIN STREQUAL "LIBFUZZER") +- SET(CMAKE_C_COMPILER clang-cl.exe) +- ADD_COMPILE_OPTIONS(-fno-strict-aliasing -Wall -Wno-array-bounds -Wno-address -flto -DUSING_LTO -D_CRT_SECURE_NO_WARNINGS /w -DTEST_WITH_LIBFUZZER=TRUE) +- SET(OPENSSL_FLAGS /FIbase.h -Wno-cast-qual) +- SET(CMOCKA_FLAGS -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -Wformat -Wno-cast-qual) ++ set(CMAKE_C_COMPILER clang-cl.exe) ++ add_compile_options(-fno-strict-aliasing -Wall -Wno-array-bounds -Wno-address -flto -DUSING_LTO -D_CRT_SECURE_NO_WARNINGS /w -DTEST_WITH_LIBFUZZER=TRUE) ++ set(OPENSSL_FLAGS /FIbase.h -Wno-cast-qual) ++ set(WOLFSSL_FLAGS -Wno-cast-qual) ++ set(CMOCKA_FLAGS -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -Wformat -Wno-cast-qual) + + SET(CMAKE_STATIC_LINKER_FLAGS "") + +@@ -896,6 +949,8 @@ else() + ADD_SUBDIRECTORY(os_stub/cryptlib_mbedtls) + elseif(CRYPTO STREQUAL "openssl") + ADD_SUBDIRECTORY(os_stub/cryptlib_openssl) ++ elseif(CRYPTO STREQUAL "wolfssl") ++ ADD_SUBDIRECTORY(os_stub/cryptlib_wolfssl) + endif() + + if(NOT ENABLE_BINARY_BUILD STREQUAL "1") +@@ -1079,6 +1134,17 @@ else() + PUBLIC crypto + ) + endif() ++ elseif(CRYPTO STREQUAL "wolfssl") ++ set(CRYPTO_DEPS "-lwolfssl -lm") ++ if(TOOLCHAIN STREQUAL "NONE") ++ target_link_libraries(${LIB_NAME}_crypto ++ PUBLIC cryptlib_wolfssl ++ ) ++ else() ++ target_link_libraries(${LIB_NAME}_crypto ++ PUBLIC wolfssl ++ ) ++ endif() + endif() + + TARGET_LINK_LIBRARIES(${LIB_NAME} +diff --git a/library/spdm_crypt_lib/libspdm_crypt_cert.c b/library/spdm_crypt_lib/libspdm_crypt_cert.c +index f555245b26..4dede524b9 100644 +--- a/library/spdm_crypt_lib/libspdm_crypt_cert.c ++++ b/library/spdm_crypt_lib/libspdm_crypt_cert.c +@@ -886,11 +886,13 @@ static bool libspdm_verify_leaf_cert_spdm_eku(const uint8_t *cert, size_t cert_s + req_auth_oid_find_success = false; + rsp_auth_oid_find_success = false; + ++#ifndef CRYPTO_IS_WOLFSSL /* wolfssl returns data without sequence tag */ + status = libspdm_asn1_get_tag(&ptr, eku + eku_size, &obj_len, + LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); + if (!status) { + return false; + } ++#endif + + while(ptr < eku + eku_size) { + status = libspdm_asn1_get_tag(&ptr, eku + eku_size, &obj_len, LIBSPDM_CRYPTO_ASN1_OID); +diff --git a/os_stub/cryptlib_wolfssl/CMakeLists.txt b/os_stub/cryptlib_wolfssl/CMakeLists.txt +new file mode 100644 +index 0000000000..f2e4427e46 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/CMakeLists.txt +@@ -0,0 +1,59 @@ ++cmake_minimum_required(VERSION 3.5) ++ ++add_library(cryptlib_wolfssl STATIC "") ++ ++target_include_directories(cryptlib_wolfssl ++ PRIVATE ++ ${LIBSPDM_DIR}/include ++ ${LIBSPDM_DIR}/include/hal ++ ${LIBSPDM_DIR}/os_stub/include ++ ${LIBSPDM_DIR}/os_stub/cryptlib_wolfssl ++ ${WOLFSSL_INCDIR}/wolfssl/openssl ++ ${WOLFSSL_INCDIR}/wolfssl ++ ${WOLFSSL_INCDIR} ++) ++ ++target_sources(cryptlib_wolfssl ++ PRIVATE ++ cipher/aead_aes_gcm.c ++ cipher/aead_chacha20_poly1305.c ++# cipher/aead_sm4_gcm.c ++ der/der.c ++ hash/sha.c ++ hash/sha3.c ++# hash/sm3.c ++ hmac/hmac_sha.c ++ hmac/hmac_sha3.c ++# hmac/hmac_sm3.c ++ kdf/hkdf_sha.c ++ kdf/hkdf_sha3.c ++# kdf/hkdf_sm3.c ++ pem/pem.c ++ pk/ec.c ++ pk/ecd.c ++ pk/dh.c ++# pk/sm2.c ++ pk/rsa_basic.c ++ pk/rsa_ext.c ++ rand/rand.c ++ sys_call/crt_wrapper_host.c ++ pk/x509.c ++) ++ ++target_compile_options(cryptlib_wolfssl PRIVATE ${WOLFSSL_FLAGS}) ++ ++if(ARCH STREQUAL "x64") ++ target_compile_options(cryptlib_wolfssl PRIVATE -DLIBSPDM_CPU_X64) ++elseif(ARCH STREQUAL "ia32") ++ target_compile_options(cryptlib_wolfssl PRIVATE -DLIBSPDM_CPU_IA32) ++elseif(ARCH STREQUAL "aarch64") ++ target_compile_options(cryptlib_wolfssl PRIVATE -DLIBSPDM_CPU_AARCH64) ++elseif(ARCH STREQUAL "riscv32") ++ target_compile_options(cryptlib_wolfssl PRIVATE -DLIBSPDM_CPU_RISCV32) ++elseif(ARCH STREQUAL "riscv64") ++ target_compile_options(cryptlib_wolfssl PRIVATE -DLIBSPDM_CPU_RISCV64) ++elseif((ARCH STREQUAL "arm") OR (ARCH STREQUAL "aarch64")) ++ target_compile_options(cryptlib_wolfssl PRIVATE -DLIBSPDM_CPU_ARM) ++else() ++ message(FATAL_ERROR "Unknown ARCH") ++endif() +diff --git a/os_stub/cryptlib_wolfssl/cipher/aead_aes_gcm.c b/os_stub/cryptlib_wolfssl/cipher/aead_aes_gcm.c +new file mode 100644 +index 0000000000..aa3000e2c5 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/cipher/aead_aes_gcm.c +@@ -0,0 +1,267 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * AEAD (AES-GCM) Wrapper Implementation. ++ * ++ * RFC 5116 - An Interface and Algorithms for Authenticated Encryption ++ * NIST SP800-38d - Cipher Modes of Operation: Galois / Counter Mode(GCM) and GMAC ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++/** ++ * Performs AEAD AES-GCM authenticated encryption on a data buffer and additional authenticated data (AAD). ++ * ++ * iv_size must be 12, otherwise false is returned. ++ * key_size must be 16, 24 or 32, otherwise false is returned. ++ * tag_size must be 12, 13, 14, 15, 16, otherwise false is returned. ++ * ++ * @param[in] key Pointer to the encryption key. ++ * @param[in] key_size size of the encryption key in bytes. ++ * @param[in] iv Pointer to the IV value. ++ * @param[in] iv_size size of the IV value in bytes. ++ * @param[in] a_data Pointer to the additional authenticated data (AAD). ++ * @param[in] a_data_size size of the additional authenticated data (AAD) in bytes. ++ * @param[in] data_in Pointer to the input data buffer to be encrypted. ++ * @param[in] data_in_size size of the input data buffer in bytes. ++ * @param[out] tag_out Pointer to a buffer that receives the authentication tag output. ++ * @param[in] tag_size size of the authentication tag in bytes. ++ * @param[out] data_out Pointer to a buffer that receives the encryption output. ++ * @param[out] data_out_size size of the output data buffer in bytes. ++ * ++ * @retval true AEAD AES-GCM authenticated encryption succeeded. ++ * @retval false AEAD AES-GCM authenticated encryption failed. ++ * ++ **/ ++bool libspdm_aead_aes_gcm_encrypt(const uint8_t *key, size_t key_size, ++ const uint8_t *iv, size_t iv_size, ++ const uint8_t *a_data, size_t a_data_size, ++ const uint8_t *data_in, size_t data_in_size, ++ uint8_t *tag_out, size_t tag_size, ++ uint8_t *data_out, size_t *data_out_size) ++{ ++ EVP_CIPHER_CTX *ctx; ++ const EVP_CIPHER *cipher; ++ size_t temp_out_size; ++ bool ret_value; ++ ++ if (data_in_size > INT_MAX) { ++ return false; ++ } ++ if (a_data_size > INT_MAX) { ++ return false; ++ } ++ if (iv_size != 12) { ++ return false; ++ } ++ switch (key_size) { ++ case 16: ++ cipher = EVP_aes_128_gcm(); ++ break; ++ case 24: ++ cipher = EVP_aes_192_gcm(); ++ break; ++ case 32: ++ cipher = EVP_aes_256_gcm(); ++ break; ++ default: ++ return false; ++ } ++ if ((tag_size != 12) && (tag_size != 13) && (tag_size != 14) && ++ (tag_size != 15) && (tag_size != 16)) { ++ return false; ++ } ++ if (data_out_size != NULL) { ++ if ((*data_out_size > INT_MAX) || ++ (*data_out_size < data_in_size)) { ++ return false; ++ } ++ } ++ ++ ctx = EVP_CIPHER_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ ++ ret_value = (bool)EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, ++ (int32_t)iv_size, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptUpdate( ++ ctx, NULL, (int32_t *)&temp_out_size, a_data, (int32_t)a_data_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptUpdate(ctx, data_out, ++ (int32_t *)&temp_out_size, data_in, ++ (int32_t)data_in_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptFinal_ex(ctx, data_out, ++ (int32_t *)&temp_out_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl( ++ ctx, EVP_CTRL_GCM_GET_TAG, (int32_t)tag_size, (void *)tag_out); ++ ++done: ++ EVP_CIPHER_CTX_free(ctx); ++ if (!ret_value) { ++ return ret_value; ++ } ++ ++ if (data_out_size != NULL) { ++ *data_out_size = data_in_size; ++ } ++ ++ return ret_value; ++} ++ ++/** ++ * Performs AEAD AES-GCM authenticated decryption on a data buffer and additional authenticated data (AAD). ++ * ++ * iv_size must be 12, otherwise false is returned. ++ * key_size must be 16, 24 or 32, otherwise false is returned. ++ * tag_size must be 12, 13, 14, 15, 16, otherwise false is returned. ++ * If additional authenticated data verification fails, false is returned. ++ * ++ * @param[in] key Pointer to the encryption key. ++ * @param[in] key_size size of the encryption key in bytes. ++ * @param[in] iv Pointer to the IV value. ++ * @param[in] iv_size size of the IV value in bytes. ++ * @param[in] a_data Pointer to the additional authenticated data (AAD). ++ * @param[in] a_data_size size of the additional authenticated data (AAD) in bytes. ++ * @param[in] data_in Pointer to the input data buffer to be decrypted. ++ * @param[in] data_in_size size of the input data buffer in bytes. ++ * @param[in] tag Pointer to a buffer that contains the authentication tag. ++ * @param[in] tag_size size of the authentication tag in bytes. ++ * @param[out] data_out Pointer to a buffer that receives the decryption output. ++ * @param[out] data_out_size size of the output data buffer in bytes. ++ * ++ * @retval true AEAD AES-GCM authenticated decryption succeeded. ++ * @retval false AEAD AES-GCM authenticated decryption failed. ++ * ++ **/ ++bool libspdm_aead_aes_gcm_decrypt(const uint8_t *key, size_t key_size, ++ const uint8_t *iv, size_t iv_size, ++ const uint8_t *a_data, size_t a_data_size, ++ const uint8_t *data_in, size_t data_in_size, ++ const uint8_t *tag, size_t tag_size, ++ uint8_t *data_out, size_t *data_out_size) ++{ ++ EVP_CIPHER_CTX *ctx; ++ const EVP_CIPHER *cipher; ++ size_t temp_out_size; ++ bool ret_value; ++ ++ if (data_in_size > INT_MAX) { ++ return false; ++ } ++ if (a_data_size > INT_MAX) { ++ return false; ++ } ++ if (iv_size != 12) { ++ return false; ++ } ++ switch (key_size) { ++ case 16: ++ cipher = EVP_aes_128_gcm(); ++ break; ++ case 24: ++ cipher = EVP_aes_192_gcm(); ++ break; ++ case 32: ++ cipher = EVP_aes_256_gcm(); ++ break; ++ default: ++ return false; ++ } ++ if ((tag_size != 12) && (tag_size != 13) && (tag_size != 14) && ++ (tag_size != 15) && (tag_size != 16)) { ++ return false; ++ } ++ if (data_out_size != NULL) { ++ if ((*data_out_size > INT_MAX) || ++ (*data_out_size < data_in_size)) { ++ return false; ++ } ++ } ++ ++ ctx = EVP_CIPHER_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ ++ ret_value = (bool)EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, ++ (int32_t)iv_size, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptUpdate( ++ ctx, NULL, (int32_t *)&temp_out_size, a_data, (int32_t)a_data_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptUpdate(ctx, data_out, ++ (int32_t *)&temp_out_size, data_in, ++ (int32_t)data_in_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, ++ (int32_t)tag_size, (void *)tag); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptFinal_ex(ctx, data_out, ++ (int32_t *)&temp_out_size); ++ ++done: ++ EVP_CIPHER_CTX_free(ctx); ++ if (!ret_value) { ++ return ret_value; ++ } ++ ++ if (data_out_size != NULL) { ++ *data_out_size = data_in_size; ++ } ++ ++ return ret_value; ++} +diff --git a/os_stub/cryptlib_wolfssl/cipher/aead_chacha20_poly1305.c b/os_stub/cryptlib_wolfssl/cipher/aead_chacha20_poly1305.c +new file mode 100644 +index 0000000000..b4451e0536 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/cipher/aead_chacha20_poly1305.c +@@ -0,0 +1,249 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * AEAD (ChaCha20Poly1305) Wrapper Implementation. ++ * ++ * RFC 5116 - An Interface and Algorithms for Authenticated Encryption ++ * RFC 8439 - ChaCha20 and Poly1305 ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++/** ++ * Performs AEAD ChaCha20Poly1305 authenticated encryption on a data buffer and additional authenticated data (AAD). ++ * ++ * iv_size must be 12, otherwise false is returned. ++ * key_size must be 32, otherwise false is returned. ++ * tag_size must be 16, otherwise false is returned. ++ * ++ * @param[in] key Pointer to the encryption key. ++ * @param[in] key_size size of the encryption key in bytes. ++ * @param[in] iv Pointer to the IV value. ++ * @param[in] iv_size size of the IV value in bytes. ++ * @param[in] a_data Pointer to the additional authenticated data (AAD). ++ * @param[in] a_data_size size of the additional authenticated data (AAD) in bytes. ++ * @param[in] data_in Pointer to the input data buffer to be encrypted. ++ * @param[in] data_in_size size of the input data buffer in bytes. ++ * @param[out] tag_out Pointer to a buffer that receives the authentication tag output. ++ * @param[in] tag_size size of the authentication tag in bytes. ++ * @param[out] data_out Pointer to a buffer that receives the encryption output. ++ * @param[out] data_out_size size of the output data buffer in bytes. ++ * ++ * @retval true AEAD ChaCha20Poly1305 authenticated encryption succeeded. ++ * @retval false AEAD ChaCha20Poly1305 authenticated encryption failed. ++ * ++ **/ ++bool libspdm_aead_chacha20_poly1305_encrypt( ++ const uint8_t *key, size_t key_size, const uint8_t *iv, ++ size_t iv_size, const uint8_t *a_data, size_t a_data_size, ++ const uint8_t *data_in, size_t data_in_size, uint8_t *tag_out, ++ size_t tag_size, uint8_t *data_out, size_t *data_out_size) ++{ ++ EVP_CIPHER_CTX *ctx; ++ size_t temp_out_size; ++ bool ret_value; ++ ++ if (data_in_size > INT_MAX) { ++ return false; ++ } ++ if (a_data_size > INT_MAX) { ++ return false; ++ } ++ if (iv_size != 12) { ++ return false; ++ } ++ if (key_size != 32) { ++ return false; ++ } ++ if (tag_size != 16) { ++ return false; ++ } ++ if (data_out_size != NULL) { ++ if ((*data_out_size > INT_MAX) || ++ (*data_out_size < data_in_size)) { ++ return false; ++ } ++ } ++ ++ ctx = EVP_CIPHER_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ ++ ret_value = (bool)EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), ++ NULL, NULL, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, ++ (int32_t)iv_size, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, ++ (int32_t)tag_size, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptUpdate( ++ ctx, NULL, (int32_t *)&temp_out_size, a_data, (int32_t)a_data_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptUpdate(ctx, data_out, ++ (int32_t *)&temp_out_size, data_in, ++ (int32_t)data_in_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_EncryptFinal_ex(ctx, data_out, ++ (int32_t *)&temp_out_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl( ++ ctx, EVP_CTRL_AEAD_GET_TAG, (int32_t)tag_size, (void *)tag_out); ++ ++done: ++ EVP_CIPHER_CTX_free(ctx); ++ if (!ret_value) { ++ return ret_value; ++ } ++ ++ if (data_out_size != NULL) { ++ *data_out_size = data_in_size; ++ } ++ ++ return ret_value; ++} ++ ++/** ++ * Performs AEAD ChaCha20Poly1305 authenticated decryption on a data buffer and additional authenticated data (AAD). ++ * ++ * iv_size must be 12, otherwise false is returned. ++ * key_size must be 32, otherwise false is returned. ++ * tag_size must be 16, otherwise false is returned. ++ * If additional authenticated data verification fails, false is returned. ++ * ++ * @param[in] key Pointer to the encryption key. ++ * @param[in] key_size size of the encryption key in bytes. ++ * @param[in] iv Pointer to the IV value. ++ * @param[in] iv_size size of the IV value in bytes. ++ * @param[in] a_data Pointer to the additional authenticated data (AAD). ++ * @param[in] a_data_size size of the additional authenticated data (AAD) in bytes. ++ * @param[in] data_in Pointer to the input data buffer to be decrypted. ++ * @param[in] data_in_size size of the input data buffer in bytes. ++ * @param[in] tag Pointer to a buffer that contains the authentication tag. ++ * @param[in] tag_size size of the authentication tag in bytes. ++ * @param[out] data_out Pointer to a buffer that receives the decryption output. ++ * @param[out] data_out_size size of the output data buffer in bytes. ++ * ++ * @retval true AEAD ChaCha20Poly1305 authenticated decryption succeeded. ++ * @retval false AEAD ChaCha20Poly1305 authenticated decryption failed. ++ * ++ **/ ++bool libspdm_aead_chacha20_poly1305_decrypt( ++ const uint8_t *key, size_t key_size, const uint8_t *iv, ++ size_t iv_size, const uint8_t *a_data, size_t a_data_size, ++ const uint8_t *data_in, size_t data_in_size, const uint8_t *tag, ++ size_t tag_size, uint8_t *data_out, size_t *data_out_size) ++{ ++ EVP_CIPHER_CTX *ctx; ++ size_t temp_out_size; ++ bool ret_value; ++ ++ if (data_in_size > INT_MAX) { ++ return false; ++ } ++ if (a_data_size > INT_MAX) { ++ return false; ++ } ++ if (iv_size != 12) { ++ return false; ++ } ++ if (key_size != 32) { ++ return false; ++ } ++ if (tag_size != 16) { ++ return false; ++ } ++ if (data_out_size != NULL) { ++ if ((*data_out_size > INT_MAX) || ++ (*data_out_size < data_in_size)) { ++ return false; ++ } ++ } ++ ++ ctx = EVP_CIPHER_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ ++ ret_value = (bool)EVP_DecryptInit_ex(ctx, EVP_chacha20_poly1305(), ++ NULL, NULL, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, ++ (int32_t)iv_size, NULL); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, ++ (int32_t)tag_size, (void *)tag); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptUpdate( ++ ctx, NULL, (int32_t *)&temp_out_size, a_data, (int32_t)a_data_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptUpdate(ctx, data_out, ++ (int32_t *)&temp_out_size, data_in, ++ (int32_t)data_in_size); ++ if (!ret_value) { ++ goto done; ++ } ++ ++ ret_value = (bool)EVP_DecryptFinal_ex(ctx, data_out, ++ (int32_t *)&temp_out_size); ++ ++done: ++ EVP_CIPHER_CTX_free(ctx); ++ if (!ret_value) { ++ return ret_value; ++ } ++ ++ if (data_out_size != NULL) { ++ *data_out_size = data_in_size; ++ } ++ ++ return ret_value; ++} +diff --git a/os_stub/cryptlib_wolfssl/cipher/aead_sm4_gcm.c b/os_stub/cryptlib_wolfssl/cipher/aead_sm4_gcm.c +new file mode 100644 +index 0000000000..81669d68df +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/cipher/aead_sm4_gcm.c +@@ -0,0 +1,81 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * AEAD (SM4-GCM) Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++/** ++ * Performs AEAD SM4-GCM authenticated encryption on a data buffer and additional authenticated data (AAD). ++ * ++ * iv_size must be 12, otherwise false is returned. ++ * key_size must be 16, otherwise false is returned. ++ * tag_size must be 16, otherwise false is returned. ++ * ++ * @param[in] key Pointer to the encryption key. ++ * @param[in] key_size size of the encryption key in bytes. ++ * @param[in] iv Pointer to the IV value. ++ * @param[in] iv_size size of the IV value in bytes. ++ * @param[in] a_data Pointer to the additional authenticated data (AAD). ++ * @param[in] a_data_size size of the additional authenticated data (AAD) in bytes. ++ * @param[in] data_in Pointer to the input data buffer to be encrypted. ++ * @param[in] data_in_size size of the input data buffer in bytes. ++ * @param[out] tag_out Pointer to a buffer that receives the authentication tag output. ++ * @param[in] tag_size size of the authentication tag in bytes. ++ * @param[out] data_out Pointer to a buffer that receives the encryption output. ++ * @param[out] data_out_size size of the output data buffer in bytes. ++ * ++ * @retval true AEAD SM4-GCM authenticated encryption succeeded. ++ * @retval false AEAD SM4-GCM authenticated encryption failed. ++ * ++ **/ ++bool libspdm_aead_sm4_gcm_encrypt(const uint8_t *key, size_t key_size, ++ const uint8_t *iv, size_t iv_size, ++ const uint8_t *a_data, size_t a_data_size, ++ const uint8_t *data_in, size_t data_in_size, ++ uint8_t *tag_out, size_t tag_size, ++ uint8_t *data_out, size_t *data_out_size) ++{ ++ return false; ++} ++ ++/** ++ * Performs AEAD SM4-GCM authenticated decryption on a data buffer and additional authenticated data (AAD). ++ * ++ * iv_size must be 12, otherwise false is returned. ++ * key_size must be 16, otherwise false is returned. ++ * tag_size must be 16, otherwise false is returned. ++ * If additional authenticated data verification fails, false is returned. ++ * ++ * @param[in] key Pointer to the encryption key. ++ * @param[in] key_size size of the encryption key in bytes. ++ * @param[in] iv Pointer to the IV value. ++ * @param[in] iv_size size of the IV value in bytes. ++ * @param[in] a_data Pointer to the additional authenticated data (AAD). ++ * @param[in] a_data_size size of the additional authenticated data (AAD) in bytes. ++ * @param[in] data_in Pointer to the input data buffer to be decrypted. ++ * @param[in] data_in_size size of the input data buffer in bytes. ++ * @param[in] tag Pointer to a buffer that contains the authentication tag. ++ * @param[in] tag_size size of the authentication tag in bytes. ++ * @param[out] data_out Pointer to a buffer that receives the decryption output. ++ * @param[out] data_out_size size of the output data buffer in bytes. ++ * ++ * @retval true AEAD SM4-GCM authenticated decryption succeeded. ++ * @retval false AEAD SM4-GCM authenticated decryption failed. ++ * ++ **/ ++bool libspdm_aead_sm4_gcm_decrypt(const uint8_t *key, size_t key_size, ++ const uint8_t *iv, size_t iv_size, ++ const uint8_t *a_data, size_t a_data_size, ++ const uint8_t *data_in, size_t data_in_size, ++ const uint8_t *tag, size_t tag_size, ++ uint8_t *data_out, size_t *data_out_size) ++{ ++ return false; ++} +diff --git a/os_stub/cryptlib_wolfssl/der/der.c b/os_stub/cryptlib_wolfssl/der/der.c +new file mode 100644 +index 0000000000..4c0efbe520 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/der/der.c +@@ -0,0 +1,284 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * DER (Distinguished Encoding Rules) format Handler Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++#if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) ++/** ++ * Retrieve the RSA Public key from the DER key data. ++ * ++ * The public key is ASN.1 DER-encoded as RFC7250 describes, ++ * namely, the SubjectPublicKeyInfo structure of a X.509 certificate. ++ * ++ * @param[in] der_data Pointer to the DER-encoded key data to be retrieved. ++ * @param[in] der_size size of the DER key data in bytes. ++ * @param[out] rsa_context Pointer to newly generated RSA context which contain the retrieved ++ * RSA public key component. Use libspdm_rsa_free() function to free the ++ * resource. ++ * ++ * If der_data is NULL, then return false. ++ * If rsa_context is NULL, then return false. ++ * ++ * @retval true RSA Public key was retrieved successfully. ++ * @retval false Invalid DER key data. ++ * ++ **/ ++bool libspdm_rsa_get_public_key_from_der(const uint8_t *der_data, ++ size_t der_size, ++ void **rsa_context) ++{ ++ bool status; ++ BIO *der_bio; ++ ++ /* Check input parameters.*/ ++ ++ if (der_data == NULL || rsa_context == NULL || der_size > INT_MAX) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read DER data.*/ ++ ++ der_bio = BIO_new(BIO_s_mem()); ++ if (der_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(der_bio, der_data, (int)der_size) <= 0) { ++ goto done; ++ } ++ ++ /* Retrieve RSA Public key from DER data.*/ ++ ++ *rsa_context = d2i_RSA_PUBKEY_bio(der_bio, NULL); ++ if (*rsa_context != NULL) { ++ status = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(der_bio); ++ ++ return status; ++} ++#endif /* (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) */ ++ ++#if LIBSPDM_ECDSA_SUPPORT ++/** ++ * Retrieve the EC Public key from the DER key data. ++ * ++ * The public key is ASN.1 DER-encoded as RFC7250 describes, ++ * namely, the SubjectPublicKeyInfo structure of a X.509 certificate. ++ * ++ * @param[in] der_data Pointer to the DER-encoded key data to be retrieved. ++ * @param[in] der_size size of the DER key data in bytes. ++ * @param[out] ec_context Pointer to newly generated EC DSA context which contain the retrieved ++ * EC public key component. Use libspdm_ec_free() function to free the ++ * resource. ++ * ++ * If der_data is NULL, then return false. ++ * If ec_context is NULL, then return false. ++ * ++ * @retval true EC Public key was retrieved successfully. ++ * @retval false Invalid DER key data. ++ * ++ **/ ++bool libspdm_ec_get_public_key_from_der(const uint8_t *der_data, ++ size_t der_size, ++ void **ec_context) ++{ ++ bool status; ++ BIO *der_bio; ++ ++ /* Check input parameters.*/ ++ ++ if (der_data == NULL || ec_context == NULL || der_size > INT_MAX) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read DER data.*/ ++ ++ der_bio = BIO_new(BIO_s_mem()); ++ if (der_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(der_bio, der_data, (int)der_size) <= 0) { ++ goto done; ++ } ++ ++ ++ /* Retrieve EC Public key from DER data.*/ ++ ++ *ec_context = d2i_EC_PUBKEY_bio(der_bio, NULL); ++ if (*ec_context != NULL) { ++ status = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(der_bio); ++ ++ return status; ++} ++#endif /* LIBSPDM_ECDSA_SUPPORT */ ++ ++#if (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT) ++/** ++ * Retrieve the Ed Public key from the DER key data. ++ * ++ * The public key is ASN.1 DER-encoded as RFC7250 describes, ++ * namely, the SubjectPublicKeyInfo structure of a X.509 certificate. ++ * ++ * @param[in] der_data Pointer to the DER-encoded key data to be retrieved. ++ * @param[in] der_size size of the DER key data in bytes. ++ * @param[out] ecd_context Pointer to newly generated Ed DSA context which contain the retrieved ++ * Ed public key component. Use libspdm_ecd_free() function to free the ++ * resource. ++ * ++ * If der_data is NULL, then return false. ++ * If ecd_context is NULL, then return false. ++ * ++ * @retval true Ed Public key was retrieved successfully. ++ * @retval false Invalid DER key data. ++ * ++ **/ ++bool libspdm_ecd_get_public_key_from_der(const uint8_t *der_data, ++ size_t der_size, ++ void **ecd_context) ++{ ++ bool status; ++ BIO *der_bio; ++ EVP_PKEY *pkey; ++ int32_t type; ++ ++ /* Check input parameters.*/ ++ ++ if (der_data == NULL || ecd_context == NULL || der_size > INT_MAX) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read DER data.*/ ++ ++ der_bio = BIO_new(BIO_s_mem()); ++ if (der_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(der_bio, der_data, (int)der_size) <= 0) { ++ goto done; ++ } ++ ++ ++ /* Retrieve Ed Public key from DER data.*/ ++ ++ pkey = d2i_PUBKEY_bio(der_bio, NULL); ++ if (pkey == NULL) { ++ goto done; ++ } ++ type = EVP_PKEY_id(pkey); ++ if ((type != EVP_PKEY_ED25519) && (type != EVP_PKEY_ED448)) { ++ goto done; ++ } ++ *ecd_context = pkey; ++ status = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(der_bio); ++ ++ return status; ++} ++#endif /* (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT) */ ++ ++#if LIBSPDM_SM2_DSA_SUPPORT ++/** ++ * Retrieve the sm2 Public key from the DER key data. ++ * ++ * The public key is ASN.1 DER-encoded as RFC7250 describes, ++ * namely, the SubjectPublicKeyInfo structure of a X.509 certificate. ++ * ++ * @param[in] der_data Pointer to the DER-encoded key data to be retrieved. ++ * @param[in] der_size size of the DER key data in bytes. ++ * @param[out] sm2_context Pointer to newly generated sm2 context which contain the retrieved ++ * sm2 public key component. Use sm2_free() function to free the ++ * resource. ++ * ++ * If der_data is NULL, then return false. ++ * If sm2_context is NULL, then return false. ++ * ++ * @retval true sm2 Public key was retrieved successfully. ++ * @retval false Invalid DER key data. ++ * ++ **/ ++bool libspdm_sm2_get_public_key_from_der(const uint8_t *der_data, ++ size_t der_size, ++ void **sm2_context) ++{ ++ bool status; ++ BIO *der_bio; ++ EVP_PKEY *pkey; ++ int result; ++ ++ /* Check input parameters.*/ ++ ++ if (der_data == NULL || sm2_context == NULL || der_size > INT_MAX) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read DER data.*/ ++ ++ der_bio = BIO_new(BIO_s_mem()); ++ if (der_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(der_bio, der_data, (int)der_size) <= 0) { ++ goto done; ++ } ++ ++ /* Retrieve sm2 Public key from DER data.*/ ++ ++ pkey = d2i_PUBKEY_bio(der_bio, NULL); ++ if (pkey == NULL) { ++ goto done; ++ } ++ result = EVP_PKEY_is_a(pkey,"SM2"); ++ if (result == 0) { ++ goto done; ++ } ++ ++ *sm2_context = pkey; ++ status = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(der_bio); ++ ++ return status; ++} ++#endif /* LIBSPDM_SM2_DSA_SUPPORT */ +diff --git a/os_stub/cryptlib_wolfssl/hash/sha.c b/os_stub/cryptlib_wolfssl/hash/sha.c +new file mode 100644 +index 0000000000..0401139613 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/hash/sha.c +@@ -0,0 +1,582 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * SHA-256/384/512 digest Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent MD use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, hash_md_new() returns NULL. ++ * ++ **/ ++void *hash_md_new(void) ++{ ++ return EVP_MD_CTX_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] md_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void hash_md_free(void *md_ctx) ++{ ++ EVP_MD_CTX_free(md_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by md_ctx as hash context for ++ * subsequent use. ++ * ++ * If md_ctx is NULL, then return false. ++ * ++ * @param[in] md message digest. ++ * @param[out] md_ctx Pointer to MD context being initialized. ++ * ++ * @retval true MD context initialization succeeded. ++ * @retval false MD context initialization failed. ++ * ++ **/ ++bool hash_md_init(const EVP_MD *md, void *md_ctx) ++{ ++ if (md_ctx == NULL) { ++ return false; ++ } ++ if (EVP_DigestInit(md_ctx, md) != 1) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Makes a copy of an existing MD context. ++ * ++ * If md_ctx is NULL, then return false. ++ * If new_md_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] md_ctx Pointer to MD context being copied. ++ * @param[out] new_md_ctx Pointer to new MD context. ++ * ++ * @retval true MD context copy succeeded. ++ * @retval false MD context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool hash_md_duplicate(const void *md_ctx, void *new_md_ctx) ++{ ++ if (md_ctx == NULL || new_md_ctx == NULL) { ++ return false; ++ } ++ if (EVP_MD_CTX_copy(new_md_ctx, md_ctx) != 1) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Digests the input data and updates MD context. ++ * ++ * This function performs MD digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * MD context should be already correctly initialized by hash_md_init(), and should not be finalized ++ * by hash_md_final(). Behavior with invalid context is undefined. ++ * ++ * If md_ctx is NULL, then return false. ++ * ++ * @param[in, out] md_ctx Pointer to the MD context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true MD data digest succeeded. ++ * @retval false MD data digest failed. ++ * ++ **/ ++bool hash_md_update(void *md_ctx, const void *data, size_t data_size) ++{ ++ if (md_ctx == NULL) { ++ return false; ++ } ++ if (data == NULL && data_size != 0) { ++ return false; ++ } ++ if (EVP_DigestUpdate(md_ctx, data, data_size) != 1) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Completes computation of the MD digest value. ++ * ++ * This function completes MD hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the MD context cannot ++ * be used again. ++ * MD context should be already correctly initialized by hash_md_init(), and should not be ++ * finalized by hash_md_final(). Behavior with invalid MD context is undefined. ++ * ++ * If md_ctx is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] md_ctx Pointer to the MD context. ++ * @param[out] hash_value Pointer to a buffer that receives the MD digest value. ++ * ++ * @retval true MD digest computation succeeded. ++ * @retval false MD digest computation failed. ++ * ++ **/ ++bool hash_md_final(void *md_ctx, void *hash_value) ++{ ++ if (md_ctx == NULL || hash_value == NULL) { ++ return false; ++ } ++ ++ if (EVP_DigestFinal(md_ctx, hash_value, NULL) != 1) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Computes the MD message digest of a input data buffer. ++ * ++ * This function performs the MD message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] md message digest. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the MD digest value. ++ * ++ * @retval true MD digest computation succeeded. ++ * @retval false MD digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool hash_md_hash_all(const EVP_MD *md, const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ if (hash_value == NULL) { ++ return false; ++ } ++ if (data == NULL && data_size != 0) { ++ return false; ++ } ++ ++ if (EVP_Digest(data, data_size, hash_value, NULL, md, NULL) != 1) { ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SHA256 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sha256_new() returns NULL. ++ * ++ **/ ++void *libspdm_sha256_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sha256_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sha256_free(void *sha256_ctx) ++{ ++ hash_md_free(sha256_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sha256_context as SHA-256 hash context for ++ * subsequent use. ++ * ++ * If sha256_context is NULL, then return false. ++ * ++ * @param[out] sha256_context Pointer to SHA-256 context being initialized. ++ * ++ * @retval true SHA-256 context initialization succeeded. ++ * @retval false SHA-256 context initialization failed. ++ * ++ **/ ++bool libspdm_sha256_init(void *sha256_context) ++{ ++ return hash_md_init (EVP_sha256(), sha256_context); ++} ++ ++/** ++ * Makes a copy of an existing SHA-256 context. ++ * ++ * If sha256_context is NULL, then return false. ++ * If new_sha256_context is NULL, then return false. ++ * ++ * @param[in] sha256_context Pointer to SHA-256 context being copied. ++ * @param[out] new_sha256_context Pointer to new SHA-256 context. ++ * ++ * @retval true SHA-256 context copy succeeded. ++ * @retval false SHA-256 context copy failed. ++ * ++ **/ ++bool libspdm_sha256_duplicate(const void *sha256_context, ++ void *new_sha256_context) ++{ ++ return hash_md_duplicate (sha256_context, new_sha256_context); ++} ++ ++/** ++ * Digests the input data and updates SHA-256 context. ++ * ++ * This function performs SHA-256 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SHA-256 context should be already correctly initialized by libspdm_sha256_init(), and should not be finalized ++ * by libspdm_sha256_final(). Behavior with invalid context is undefined. ++ * ++ * If sha256_context is NULL, then return false. ++ * ++ * @param[in, out] sha256_context Pointer to the SHA-256 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SHA-256 data digest succeeded. ++ * @retval false SHA-256 data digest failed. ++ * ++ **/ ++bool libspdm_sha256_update(void *sha256_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sha256_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SHA-256 digest value. ++ * ++ * This function completes SHA-256 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SHA-256 context cannot ++ * be used again. ++ * SHA-256 context should be already correctly initialized by libspdm_sha256_init(), and should not be ++ * finalized by libspdm_sha256_final(). Behavior with invalid SHA-256 context is undefined. ++ * ++ * If sha256_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sha256_context Pointer to the SHA-256 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA-256 digest ++ * value (32 bytes). ++ * ++ * @retval true SHA-256 digest computation succeeded. ++ * @retval false SHA-256 digest computation failed. ++ * ++ **/ ++bool libspdm_sha256_final(void *sha256_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sha256_context, hash_value); ++} ++ ++/** ++ * Computes the SHA-256 message digest of a input data buffer. ++ * ++ * This function performs the SHA-256 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA-256 digest ++ * value (32 bytes). ++ * ++ * @retval true SHA-256 digest computation succeeded. ++ * @retval false SHA-256 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha256_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sha256(), data, data_size, hash_value); ++} ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SHA384 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sha384_new() returns NULL. ++ * ++ **/ ++void *libspdm_sha384_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sha384_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sha384_free(void *sha384_ctx) ++{ ++ hash_md_free(sha384_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sha384_context as SHA-384 hash context for ++ * subsequent use. ++ * ++ * If sha384_context is NULL, then return false. ++ * ++ * @param[out] sha384_context Pointer to SHA-384 context being initialized. ++ * ++ * @retval true SHA-384 context initialization succeeded. ++ * @retval false SHA-384 context initialization failed. ++ * ++ **/ ++bool libspdm_sha384_init(void *sha384_context) ++{ ++ return hash_md_init (EVP_sha384(), sha384_context); ++} ++ ++/** ++ * Makes a copy of an existing SHA-384 context. ++ * ++ * If sha384_context is NULL, then return false. ++ * If new_sha384_context is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] sha384_context Pointer to SHA-384 context being copied. ++ * @param[out] new_sha384_context Pointer to new SHA-384 context. ++ * ++ * @retval true SHA-384 context copy succeeded. ++ * @retval false SHA-384 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha384_duplicate(const void *sha384_context, ++ void *new_sha384_context) ++{ ++ return hash_md_duplicate (sha384_context, new_sha384_context); ++} ++ ++/** ++ * Digests the input data and updates SHA-384 context. ++ * ++ * This function performs SHA-384 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SHA-384 context should be already correctly initialized by libspdm_sha384_init(), and should not be finalized ++ * by libspdm_sha384_final(). Behavior with invalid context is undefined. ++ * ++ * If sha384_context is NULL, then return false. ++ * ++ * @param[in, out] sha384_context Pointer to the SHA-384 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SHA-384 data digest succeeded. ++ * @retval false SHA-384 data digest failed. ++ * ++ **/ ++bool libspdm_sha384_update(void *sha384_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sha384_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SHA-384 digest value. ++ * ++ * This function completes SHA-384 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SHA-384 context cannot ++ * be used again. ++ * SHA-384 context should be already correctly initialized by libspdm_sha384_init(), and should not be ++ * finalized by libspdm_sha384_final(). Behavior with invalid SHA-384 context is undefined. ++ * ++ * If sha384_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sha384_context Pointer to the SHA-384 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA-384 digest ++ * value (48 bytes). ++ * ++ * @retval true SHA-384 digest computation succeeded. ++ * @retval false SHA-384 digest computation failed. ++ * ++ **/ ++bool libspdm_sha384_final(void *sha384_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sha384_context, hash_value); ++} ++ ++/** ++ * Computes the SHA-384 message digest of a input data buffer. ++ * ++ * This function performs the SHA-384 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA-384 digest ++ * value (48 bytes). ++ * ++ * @retval true SHA-384 digest computation succeeded. ++ * @retval false SHA-384 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha384_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sha384(), data, data_size, hash_value); ++} ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SHA512 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sha512_new() returns NULL. ++ * ++ **/ ++void *libspdm_sha512_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sha512_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sha512_free(void *sha512_ctx) ++{ ++ hash_md_free(sha512_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sha512_context as SHA-512 hash context for ++ * subsequent use. ++ * ++ * If sha512_context is NULL, then return false. ++ * ++ * @param[out] sha512_context Pointer to SHA-512 context being initialized. ++ * ++ * @retval true SHA-512 context initialization succeeded. ++ * @retval false SHA-512 context initialization failed. ++ * ++ **/ ++bool libspdm_sha512_init(void *sha512_context) ++{ ++ return hash_md_init (EVP_sha512(), sha512_context); ++} ++ ++/** ++ * Makes a copy of an existing SHA-512 context. ++ * ++ * If sha512_context is NULL, then return false. ++ * If new_sha512_context is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] sha512_context Pointer to SHA-512 context being copied. ++ * @param[out] new_sha512_context Pointer to new SHA-512 context. ++ * ++ * @retval true SHA-512 context copy succeeded. ++ * @retval false SHA-512 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha512_duplicate(const void *sha512_context, ++ void *new_sha512_context) ++{ ++ return hash_md_duplicate (sha512_context, new_sha512_context); ++} ++ ++/** ++ * Digests the input data and updates SHA-512 context. ++ * ++ * This function performs SHA-512 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SHA-512 context should be already correctly initialized by libspdm_sha512_init(), and should not be finalized ++ * by libspdm_sha512_final(). Behavior with invalid context is undefined. ++ * ++ * If sha512_context is NULL, then return false. ++ * ++ * @param[in, out] sha512_context Pointer to the SHA-512 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SHA-512 data digest succeeded. ++ * @retval false SHA-512 data digest failed. ++ * ++ **/ ++bool libspdm_sha512_update(void *sha512_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sha512_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SHA-512 digest value. ++ * ++ * This function completes SHA-512 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SHA-512 context cannot ++ * be used again. ++ * SHA-512 context should be already correctly initialized by libspdm_sha512_init(), and should not be ++ * finalized by libspdm_sha512_final(). Behavior with invalid SHA-512 context is undefined. ++ * ++ * If sha512_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sha512_context Pointer to the SHA-512 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA-512 digest ++ * value (64 bytes). ++ * ++ * @retval true SHA-512 digest computation succeeded. ++ * @retval false SHA-512 digest computation failed. ++ * ++ **/ ++bool libspdm_sha512_final(void *sha512_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sha512_context, hash_value); ++} ++ ++/** ++ * Computes the SHA-512 message digest of a input data buffer. ++ * ++ * This function performs the SHA-512 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA-512 digest ++ * value (64 bytes). ++ * ++ * @retval true SHA-512 digest computation succeeded. ++ * @retval false SHA-512 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha512_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sha512(), data, data_size, hash_value); ++} +diff --git a/os_stub/cryptlib_wolfssl/hash/sha3.c b/os_stub/cryptlib_wolfssl/hash/sha3.c +new file mode 100644 +index 0000000000..1ae9a013d5 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/hash/sha3.c +@@ -0,0 +1,423 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * SHA3-256/384/512 and Shake-256 digest Wrapper Implementation ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++void *hash_md_new(void); ++void hash_md_free(void *md_ctx); ++bool hash_md_init(const EVP_MD *md, void *md_ctx); ++bool hash_md_duplicate(const void *md_ctx, void *new_md_ctx); ++bool hash_md_update(void *md_ctx, const void *data, size_t data_size); ++bool hash_md_final(void *md_ctx, void *hash_value); ++bool hash_md_hash_all(const EVP_MD *md, const void *data, size_t data_size, ++ uint8_t *hash_value); ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SHA3-256 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sha3_256_new() returns NULL. ++ * ++ **/ ++void *libspdm_sha3_256_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sha3_256_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sha3_256_free(void *sha3_256_ctx) ++{ ++ hash_md_free(sha3_256_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sha3_256_context as SHA3-256 hash context for ++ * subsequent use. ++ * ++ * If sha3_256_context is NULL, then return false. ++ * ++ * @param[out] sha3_256_context Pointer to SHA3-256 context being initialized. ++ * ++ * @retval true SHA3-256 context initialization succeeded. ++ * @retval false SHA3-256 context initialization failed. ++ * ++ **/ ++bool libspdm_sha3_256_init(void *sha3_256_context) ++{ ++ return hash_md_init (EVP_sha3_256(), sha3_256_context); ++} ++ ++/** ++ * Makes a copy of an existing SHA3-256 context. ++ * ++ * If sha3_256_context is NULL, then return false. ++ * If new_sha3_256_context is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] sha3_256_context Pointer to SHA3-256 context being copied. ++ * @param[out] new_sha3_256_context Pointer to new SHA3-256 context. ++ * ++ * @retval true SHA3-256 context copy succeeded. ++ * @retval false SHA3-256 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha3_256_duplicate(const void *sha3_256_context, ++ void *new_sha3_256_context) ++{ ++ return hash_md_duplicate (sha3_256_context, new_sha3_256_context); ++} ++ ++/** ++ * Digests the input data and updates SHA3-256 context. ++ * ++ * This function performs SHA3-256 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SHA3-256 context should be already correctly initialized by libspdm_sha3_256_init(), and should not be finalized ++ * by libspdm_sha3_256_final(). Behavior with invalid context is undefined. ++ * ++ * If sha3_256_context is NULL, then return false. ++ * ++ * @param[in, out] sha3_256_context Pointer to the SHA3-256 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SHA3-256 data digest succeeded. ++ * @retval false SHA3-256 data digest failed. ++ * ++ **/ ++bool libspdm_sha3_256_update(void *sha3_256_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sha3_256_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SHA3-256 digest value. ++ * ++ * This function completes SHA3-256 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SHA3-256 context cannot ++ * be used again. ++ * SHA3-256 context should be already correctly initialized by libspdm_sha3_256_init(), and should not be ++ * finalized by libspdm_sha3_256_final(). Behavior with invalid SHA3-256 context is undefined. ++ * ++ * If sha3_256_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sha3_256_context Pointer to the SHA3-256 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA3-256 digest ++ * value (256 / 8 bytes). ++ * ++ * @retval true SHA3-256 digest computation succeeded. ++ * @retval false SHA3-256 digest computation failed. ++ * ++ **/ ++bool libspdm_sha3_256_final(void *sha3_256_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sha3_256_context, hash_value); ++} ++ ++/** ++ * Computes the SHA3-256 message digest of a input data buffer. ++ * ++ * This function performs the SHA3-256 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA3-256 digest ++ * value (256 / 8 bytes). ++ * ++ * @retval true SHA3-256 digest computation succeeded. ++ * @retval false SHA3-256 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha3_256_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sha3_256(), data, data_size, hash_value); ++} ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SHA3-384 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sha3_384_new() returns NULL. ++ * ++ **/ ++void *libspdm_sha3_384_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sha3_384_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sha3_384_free(void *sha3_384_ctx) ++{ ++ hash_md_free(sha3_384_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sha3_384_context as SHA3-384 hash context for ++ * subsequent use. ++ * ++ * If sha3_384_context is NULL, then return false. ++ * ++ * @param[out] sha3_384_context Pointer to SHA3-384 context being initialized. ++ * ++ * @retval true SHA3-384 context initialization succeeded. ++ * @retval false SHA3-384 context initialization failed. ++ * ++ **/ ++bool libspdm_sha3_384_init(void *sha3_384_context) ++{ ++ return hash_md_init (EVP_sha3_384(), sha3_384_context); ++} ++ ++/** ++ * Makes a copy of an existing SHA3-384 context. ++ * ++ * If sha3_384_context is NULL, then return false. ++ * If new_sha3_384_context is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] sha3_384_context Pointer to SHA3-384 context being copied. ++ * @param[out] new_sha3_384_context Pointer to new SHA3-384 context. ++ * ++ * @retval true SHA3-384 context copy succeeded. ++ * @retval false SHA3-384 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha3_384_duplicate(const void *sha3_384_context, ++ void *new_sha3_384_context) ++{ ++ return hash_md_duplicate (sha3_384_context, new_sha3_384_context); ++} ++ ++/** ++ * Digests the input data and updates SHA3-384 context. ++ * ++ * This function performs SHA3-384 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SHA3-384 context should be already correctly initialized by libspdm_sha3_384_init(), and should not be finalized ++ * by libspdm_sha3_384_final(). Behavior with invalid context is undefined. ++ * ++ * If sha3_384_context is NULL, then return false. ++ * ++ * @param[in, out] sha3_384_context Pointer to the SHA3-384 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SHA3-384 data digest succeeded. ++ * @retval false SHA3-384 data digest failed. ++ * ++ **/ ++bool libspdm_sha3_384_update(void *sha3_384_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sha3_384_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SHA3-384 digest value. ++ * ++ * This function completes SHA3-384 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SHA3-384 context cannot ++ * be used again. ++ * SHA3-384 context should be already correctly initialized by libspdm_sha3_384_init(), and should not be ++ * finalized by libspdm_sha3_384_final(). Behavior with invalid SHA3-384 context is undefined. ++ * ++ * If sha3_384_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sha3_384_context Pointer to the SHA3-384 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA3-384 digest ++ * value (384 / 8 bytes). ++ * ++ * @retval true SHA3-384 digest computation succeeded. ++ * @retval false SHA3-384 digest computation failed. ++ * ++ **/ ++bool libspdm_sha3_384_final(void *sha3_384_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sha3_384_context, hash_value); ++} ++ ++/** ++ * Computes the SHA3-384 message digest of a input data buffer. ++ * ++ * This function performs the SHA3-384 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA3-384 digest ++ * value (384 / 8 bytes). ++ * ++ * @retval true SHA3-384 digest computation succeeded. ++ * @retval false SHA3-384 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha3_384_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sha3_384(), data, data_size, hash_value); ++} ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SHA3-512 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sha3_512_new() returns NULL. ++ * ++ **/ ++void *libspdm_sha3_512_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sha3_512_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sha3_512_free(void *sha3_512_ctx) ++{ ++ hash_md_free(sha3_512_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sha3_512_context as SHA3-512 hash context for ++ * subsequent use. ++ * ++ * If sha3_512_context is NULL, then return false. ++ * ++ * @param[out] sha3_512_context Pointer to SHA3-512 context being initialized. ++ * ++ * @retval true SHA3-512 context initialization succeeded. ++ * @retval false SHA3-512 context initialization failed. ++ * ++ **/ ++bool libspdm_sha3_512_init(void *sha3_512_context) ++{ ++ return hash_md_init (EVP_sha3_512(), sha3_512_context); ++} ++ ++/** ++ * Makes a copy of an existing SHA3-512 context. ++ * ++ * If sha3_512_context is NULL, then return false. ++ * If new_sha3_512_context is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] sha3_512_context Pointer to SHA3-512 context being copied. ++ * @param[out] new_sha3_512_context Pointer to new SHA3-512 context. ++ * ++ * @retval true SHA3-512 context copy succeeded. ++ * @retval false SHA3-512 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha3_512_duplicate(const void *sha3_512_context, ++ void *new_sha3_512_context) ++{ ++ return hash_md_duplicate (sha3_512_context, new_sha3_512_context); ++} ++ ++/** ++ * Digests the input data and updates SHA3-512 context. ++ * ++ * This function performs SHA3-512 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SHA3-512 context should be already correctly initialized by libspdm_sha3_512_init(), and should not be finalized ++ * by libspdm_sha3_512_final(). Behavior with invalid context is undefined. ++ * ++ * If sha3_512_context is NULL, then return false. ++ * ++ * @param[in, out] sha3_512_context Pointer to the SHA3-512 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SHA3-512 data digest succeeded. ++ * @retval false SHA3-512 data digest failed. ++ * ++ **/ ++bool libspdm_sha3_512_update(void *sha3_512_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sha3_512_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SHA3-512 digest value. ++ * ++ * This function completes SHA3-512 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SHA3-512 context cannot ++ * be used again. ++ * SHA3-512 context should be already correctly initialized by libspdm_sha3_512_init(), and should not be ++ * finalized by libspdm_sha3_512_final(). Behavior with invalid SHA3-512 context is undefined. ++ * ++ * If sha3_512_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sha3_512_context Pointer to the SHA3-512 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA3-512 digest ++ * value (512 / 8 bytes). ++ * ++ * @retval true SHA3-512 digest computation succeeded. ++ * @retval false SHA3-512 digest computation failed. ++ * ++ **/ ++bool libspdm_sha3_512_final(void *sha3_512_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sha3_512_context, hash_value); ++} ++ ++/** ++ * Computes the SHA3-512 message digest of a input data buffer. ++ * ++ * This function performs the SHA3-512 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SHA3-512 digest ++ * value (512 / 8 bytes). ++ * ++ * @retval true SHA3-512 digest computation succeeded. ++ * @retval false SHA3-512 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sha3_512_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sha3_512(), data, data_size, hash_value); ++} +diff --git a/os_stub/cryptlib_wolfssl/hash/sm3.c b/os_stub/cryptlib_wolfssl/hash/sm3.c +new file mode 100644 +index 0000000000..f7739bf059 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/hash/sm3.c +@@ -0,0 +1,154 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * SM3 digest Wrapper Implementations. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++void *hash_md_new(void); ++void hash_md_free(const void *md_ctx); ++bool hash_md_init(const EVP_MD *md, void *md_ctx); ++bool hash_md_duplicate(const void *md_ctx, void *new_md_ctx); ++bool hash_md_update(const void *md_ctx, const void *data, size_t data_size); ++bool hash_md_final(const void *md_ctx, void *hash_value); ++bool hash_md_hash_all(const EVP_MD *md, const void *data, size_t data_size, ++ uint8_t *hash_value); ++ ++/** ++ * Allocates and initializes one HASH_CTX context for subsequent SM3-256 use. ++ * ++ * @return Pointer to the HASH_CTX context that has been initialized. ++ * If the allocations fails, libspdm_sm3_256_new() returns NULL. ++ * ++ **/ ++void *libspdm_sm3_256_new(void) ++{ ++ return hash_md_new(); ++} ++ ++/** ++ * Release the specified HASH_CTX context. ++ * ++ * @param[in] sm3_256_ctx Pointer to the HASH_CTX context to be released. ++ * ++ **/ ++void libspdm_sm3_256_free(void *sm3_256_ctx) ++{ ++ hash_md_free(sm3_256_ctx); ++} ++ ++/** ++ * Initializes user-supplied memory pointed by sm3_context as SM3 hash context for ++ * subsequent use. ++ * ++ * If sm3_context is NULL, then return false. ++ * ++ * @param[out] sm3_context Pointer to SM3 context being initialized. ++ * ++ * @retval true SM3 context initialization succeeded. ++ * @retval false SM3 context initialization failed. ++ * ++ **/ ++bool libspdm_sm3_256_init(void *sm3_context) ++{ ++ return hash_md_init (EVP_sm3(), sm3_context); ++} ++ ++/** ++ * Makes a copy of an existing SM3 context. ++ * ++ * If sm3_context is NULL, then return false. ++ * If new_sm3_context is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] sm3_context Pointer to SM3 context being copied. ++ * @param[out] new_sm3_context Pointer to new SM3 context. ++ * ++ * @retval true SM3 context copy succeeded. ++ * @retval false SM3 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sm3_256_duplicate(const void *sm3_context, void *new_sm3_context) ++{ ++ return hash_md_duplicate (sm3_context, new_sm3_context); ++} ++ ++/** ++ * Digests the input data and updates SM3 context. ++ * ++ * This function performs SM3 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * SM3 context should be already correctly initialized by sm3_init(), and should not be finalized ++ * by sm3_final(). Behavior with invalid context is undefined. ++ * ++ * If sm3_context is NULL, then return false. ++ * ++ * @param[in, out] sm3_context Pointer to the SM3 context. ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true SM3 data digest succeeded. ++ * @retval false SM3 data digest failed. ++ * ++ **/ ++bool libspdm_sm3_256_update(void *sm3_context, const void *data, ++ size_t data_size) ++{ ++ return hash_md_update (sm3_context, data, data_size); ++} ++ ++/** ++ * Completes computation of the SM3 digest value. ++ * ++ * This function completes SM3 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the SM3 context cannot ++ * be used again. ++ * SM3 context should be already correctly initialized by sm3_init(), and should not be ++ * finalized by sm3_final(). Behavior with invalid SM3 context is undefined. ++ * ++ * If sm3_context is NULL, then return false. ++ * If hash_value is NULL, then return false. ++ * ++ * @param[in, out] sm3_context Pointer to the SM3 context. ++ * @param[out] hash_value Pointer to a buffer that receives the SM3 digest ++ * value (32 bytes). ++ * ++ * @retval true SM3 digest computation succeeded. ++ * @retval false SM3 digest computation failed. ++ * ++ **/ ++bool libspdm_sm3_256_final(void *sm3_context, uint8_t *hash_value) ++{ ++ return hash_md_final (sm3_context, hash_value); ++} ++ ++/** ++ * Computes the SM3 message digest of a input data buffer. ++ * ++ * This function performs the SM3 message digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be hashed. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the SM3 digest ++ * value (32 bytes). ++ * ++ * @retval true SM3 digest computation succeeded. ++ * @retval false SM3 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_sm3_256_hash_all(const void *data, size_t data_size, ++ uint8_t *hash_value) ++{ ++ return hash_md_hash_all (EVP_sm3(), data, data_size, hash_value); ++} +diff --git a/os_stub/cryptlib_wolfssl/hmac/hmac_sha.c b/os_stub/cryptlib_wolfssl/hmac/hmac_sha.c +new file mode 100644 +index 0000000000..12d5d6c29e +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/hmac/hmac_sha.c +@@ -0,0 +1,683 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * HMAC-SHA256/384/512 Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-MD use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, hmac_md_new() returns NULL. ++ * ++ **/ ++void *hmac_md_new(void) ++{ ++ ++ /* Allocates & Initializes HMAC_CTX context by OpenSSL HMAC_CTX_new()*/ ++ ++ return (void *)HMAC_CTX_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_md_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void hmac_md_free(void *hmac_md_ctx) ++{ ++ ++ /* Free OpenSSL HMAC_CTX context*/ ++ ++ HMAC_CTX_free((HMAC_CTX *)hmac_md_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to hmac_md_update(). ++ * ++ * If hmac_md_ctx is NULL, then return false. ++ * ++ * @param[in] md message digest. ++ * @param[out] hmac_md_ctx Pointer to HMAC-MD context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * ++ **/ ++bool hmac_md_set_key(const EVP_MD *md, void *hmac_md_ctx, ++ const uint8_t *key, size_t key_size) ++{ ++ ++ /* Check input parameters.*/ ++ ++ if (hmac_md_ctx == NULL || key_size > INT_MAX) { ++ return false; ++ } ++ ++ if (HMAC_Init_ex((HMAC_CTX *)hmac_md_ctx, key, (uint32_t)key_size, md, ++ NULL) != 1) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Makes a copy of an existing HMAC-MD context. ++ * ++ * If hmac_md_ctx is NULL, then return false. ++ * If new_hmac_md_ctx is NULL, then return false. ++ * ++ * @param[in] hmac_md_ctx Pointer to HMAC-MD context being copied. ++ * @param[out] new_hmac_md_ctx Pointer to new HMAC-MD context. ++ * ++ * @retval true HMAC-MD context copy succeeded. ++ * @retval false HMAC-MD context copy failed. ++ * ++ **/ ++bool hmac_md_duplicate(const void *hmac_md_ctx, void *new_hmac_md_ctx) ++{ ++ ++ /* Check input parameters.*/ ++ ++ if (hmac_md_ctx == NULL || new_hmac_md_ctx == NULL) { ++ return false; ++ } ++ ++ if (HMAC_CTX_copy((HMAC_CTX *)new_hmac_md_ctx, ++ (HMAC_CTX *)hmac_md_ctx) != 1) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Digests the input data and updates HMAC-MD context. ++ * ++ * This function performs HMAC-MD digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-MD context should be initialized by hmac_md_new(), and should not be finalized ++ * by hmac_md_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_md_ctx is NULL, then return false. ++ * ++ * @param[in, out] hmac_md_ctx Pointer to the HMAC-MD context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-MD data digest succeeded. ++ * @retval false HMAC-MD data digest failed. ++ * ++ **/ ++bool hmac_md_update(void *hmac_md_ctx, const void *data, ++ size_t data_size) ++{ ++ ++ /* Check input parameters.*/ ++ ++ if (hmac_md_ctx == NULL) { ++ return false; ++ } ++ ++ ++ /* Check invalid parameters, in case that only DataLength was checked in OpenSSL*/ ++ ++ if (data == NULL && data_size != 0) { ++ return false; ++ } ++ ++ ++ /* OpenSSL HMAC-MD digest update*/ ++ ++ if (HMAC_Update((HMAC_CTX *)hmac_md_ctx, data, data_size) != 1) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Completes computation of the HMAC-MD digest value. ++ * ++ * This function completes HMAC-MD hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-MD context cannot ++ * be used again. ++ * HMAC-MD context should be initialized by hmac_md_new(), and should not be finalized ++ * by hmac_md_final(). Behavior with invalid HMAC-MD context is undefined. ++ * ++ * If hmac_md_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * ++ * @param[in, out] hmac_md_ctx Pointer to the HMAC-MD context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-MD digest ++ * value. ++ * ++ * @retval true HMAC-MD digest computation succeeded. ++ * @retval false HMAC-MD digest computation failed. ++ * ++ **/ ++bool hmac_md_final(void *hmac_md_ctx, uint8_t *hmac_value) ++{ ++ uint32_t length; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (hmac_md_ctx == NULL || hmac_value == NULL) { ++ return false; ++ } ++ ++ ++ /* OpenSSL HMAC-MD digest finalization*/ ++ ++ if (HMAC_Final((HMAC_CTX *)hmac_md_ctx, hmac_value, &length) != 1) { ++ return false; ++ } ++ if (HMAC_CTX_reset((HMAC_CTX *)hmac_md_ctx) != 1) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Computes the HMAC-MD digest of a input data buffer. ++ * ++ * This function performs the HMAC-MD digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] md message digest. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-MD digest ++ * value. ++ * ++ * @retval true HMAC-MD digest computation succeeded. ++ * @retval false HMAC-MD digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool hmac_md_all(const EVP_MD *md, const void *data, ++ size_t data_size, const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ uint32_t length; ++ HMAC_CTX *ctx; ++ bool ret_val; ++ ++ ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ ++ ret_val = (bool)HMAC_CTX_reset(ctx); ++ if (!ret_val) { ++ goto done; ++ } ++ ret_val = (bool)HMAC_Init_ex(ctx, key, (uint32_t)key_size, md, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ret_val = (bool)HMAC_Update(ctx, data, data_size); ++ if (!ret_val) { ++ goto done; ++ } ++ ret_val = (bool)HMAC_Final(ctx, hmac_value, &length); ++ if (!ret_val) { ++ goto done; ++ } ++ ++done: ++ HMAC_CTX_free(ctx); ++ ++ return ret_val; ++} ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA256 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sha256_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sha256_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sha256_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sha256_free(void *hmac_sha256_ctx) ++{ ++ hmac_md_free(hmac_sha256_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sha256_update(). ++ * ++ * If hmac_sha256_ctx is NULL, then return false. ++ * ++ * @param[out] hmac_sha256_ctx Pointer to HMAC-SHA256 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * ++ **/ ++bool libspdm_hmac_sha256_set_key(void *hmac_sha256_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sha256(), hmac_sha256_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SHA256 context. ++ * ++ * If hmac_sha256_ctx is NULL, then return false. ++ * If new_hmac_sha256_ctx is NULL, then return false. ++ * ++ * @param[in] hmac_sha256_ctx Pointer to HMAC-SHA256 context being copied. ++ * @param[out] new_hmac_sha256_ctx Pointer to new HMAC-SHA256 context. ++ * ++ * @retval true HMAC-SHA256 context copy succeeded. ++ * @retval false HMAC-SHA256 context copy failed. ++ * ++ **/ ++bool libspdm_hmac_sha256_duplicate(const void *hmac_sha256_ctx, ++ void *new_hmac_sha256_ctx) ++{ ++ return hmac_md_duplicate(hmac_sha256_ctx, new_hmac_sha256_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SHA256 context. ++ * ++ * This function performs HMAC-SHA256 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SHA256 context should be initialized by libspdm_hmac_sha256_new(), and should not be finalized ++ * by libspdm_hmac_sha256_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sha256_ctx is NULL, then return false. ++ * ++ * @param[in, out] hmac_sha256_ctx Pointer to the HMAC-SHA256 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SHA256 data digest succeeded. ++ * @retval false HMAC-SHA256 data digest failed. ++ * ++ **/ ++bool libspdm_hmac_sha256_update(void *hmac_sha256_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sha256_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SHA256 digest value. ++ * ++ * This function completes HMAC-SHA256 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SHA256 context cannot ++ * be used again. ++ * HMAC-SHA256 context should be initialized by libspdm_hmac_sha256_new(), and should not be finalized ++ * by libspdm_hmac_sha256_final(). Behavior with invalid HMAC-SHA256 context is undefined. ++ * ++ * If hmac_sha256_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * ++ * @param[in, out] hmac_sha256_ctx Pointer to the HMAC-SHA256 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SHA256 digest ++ * value (32 bytes). ++ * ++ * @retval true HMAC-SHA256 digest computation succeeded. ++ * @retval false HMAC-SHA256 digest computation failed. ++ * ++ **/ ++bool libspdm_hmac_sha256_final(void *hmac_sha256_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sha256_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SHA256 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SHA256 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SHA256 digest ++ * value (32 bytes). ++ * ++ * @retval true HMAC-SHA256 digest computation succeeded. ++ * @retval false HMAC-SHA256 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha256_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sha256(), data, data_size, key, key_size, ++ hmac_value); ++} ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA384 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sha384_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sha384_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sha384_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sha384_free(void *hmac_sha384_ctx) ++{ ++ hmac_md_free(hmac_sha384_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sha384_update(). ++ * ++ * If hmac_sha384_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[out] hmac_sha384_ctx Pointer to HMAC-SHA384 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha384_set_key(void *hmac_sha384_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sha384(), hmac_sha384_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SHA384 context. ++ * ++ * If hmac_sha384_ctx is NULL, then return false. ++ * If new_hmac_sha384_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] hmac_sha384_ctx Pointer to HMAC-SHA384 context being copied. ++ * @param[out] new_hmac_sha384_ctx Pointer to new HMAC-SHA384 context. ++ * ++ * @retval true HMAC-SHA384 context copy succeeded. ++ * @retval false HMAC-SHA384 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha384_duplicate(const void *hmac_sha384_ctx, ++ void *new_hmac_sha384_ctx) ++{ ++ return hmac_md_duplicate(hmac_sha384_ctx, new_hmac_sha384_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SHA384 context. ++ * ++ * This function performs HMAC-SHA384 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SHA384 context should be initialized by libspdm_hmac_sha384_new(), and should not be finalized ++ * by libspdm_hmac_sha384_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sha384_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha384_ctx Pointer to the HMAC-SHA384 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SHA384 data digest succeeded. ++ * @retval false HMAC-SHA384 data digest failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha384_update(void *hmac_sha384_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sha384_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SHA384 digest value. ++ * ++ * This function completes HMAC-SHA384 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SHA384 context cannot ++ * be used again. ++ * HMAC-SHA384 context should be initialized by libspdm_hmac_sha384_new(), and should not be finalized ++ * by libspdm_hmac_sha384_final(). Behavior with invalid HMAC-SHA384 context is undefined. ++ * ++ * If hmac_sha384_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha384_ctx Pointer to the HMAC-SHA384 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SHA384 digest ++ * value (48 bytes). ++ * ++ * @retval true HMAC-SHA384 digest computation succeeded. ++ * @retval false HMAC-SHA384 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha384_final(void *hmac_sha384_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sha384_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SHA384 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SHA384 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SHA384 digest ++ * value (48 bytes). ++ * ++ * @retval true HMAC-SHA384 digest computation succeeded. ++ * @retval false HMAC-SHA384 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha384_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sha384(), data, data_size, key, key_size, ++ hmac_value); ++} ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA512 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sha512_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sha512_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sha512_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sha512_free(void *hmac_sha512_ctx) ++{ ++ hmac_md_free(hmac_sha512_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sha512_update(). ++ * ++ * If hmac_sha512_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[out] hmac_sha512_ctx Pointer to HMAC-SHA512 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha512_set_key(void *hmac_sha512_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sha512(), hmac_sha512_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SHA512 context. ++ * ++ * If hmac_sha512_ctx is NULL, then return false. ++ * If new_hmac_sha512_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] hmac_sha512_ctx Pointer to HMAC-SHA512 context being copied. ++ * @param[out] new_hmac_sha512_ctx Pointer to new HMAC-SHA512 context. ++ * ++ * @retval true HMAC-SHA512 context copy succeeded. ++ * @retval false HMAC-SHA512 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha512_duplicate(const void *hmac_sha512_ctx, ++ void *new_hmac_sha512_ctx) ++{ ++ return hmac_md_duplicate(hmac_sha512_ctx, new_hmac_sha512_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SHA512 context. ++ * ++ * This function performs HMAC-SHA512 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SHA512 context should be initialized by libspdm_hmac_sha512_new(), and should not be finalized ++ * by libspdm_hmac_sha512_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sha512_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha512_ctx Pointer to the HMAC-SHA512 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SHA512 data digest succeeded. ++ * @retval false HMAC-SHA512 data digest failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha512_update(void *hmac_sha512_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sha512_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SHA512 digest value. ++ * ++ * This function completes HMAC-SHA512 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SHA512 context cannot ++ * be used again. ++ * HMAC-SHA512 context should be initialized by libspdm_hmac_sha512_new(), and should not be finalized ++ * by libspdm_hmac_sha512_final(). Behavior with invalid HMAC-SHA512 context is undefined. ++ * ++ * If hmac_sha512_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha512_ctx Pointer to the HMAC-SHA512 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SHA512 digest ++ * value (64 bytes). ++ * ++ * @retval true HMAC-SHA512 digest computation succeeded. ++ * @retval false HMAC-SHA512 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha512_final(void *hmac_sha512_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sha512_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SHA512 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SHA512 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SHA512 digest ++ * value (64 bytes). ++ * ++ * @retval true HMAC-SHA512 digest computation succeeded. ++ * @retval false HMAC-SHA512 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha512_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sha512(), data, data_size, key, key_size, ++ hmac_value); ++} +diff --git a/os_stub/cryptlib_wolfssl/hmac/hmac_sha3.c b/os_stub/cryptlib_wolfssl/hmac/hmac_sha3.c +new file mode 100644 +index 0000000000..ed2fdda35e +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/hmac/hmac_sha3.c +@@ -0,0 +1,457 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * HMAC-SHA3_256/384/512 Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++void *hmac_md_new(void); ++void hmac_md_free(void *hmac_md_ctx); ++bool hmac_md_set_key(const EVP_MD *md, void *hmac_md_ctx, ++ const uint8_t *key, size_t key_size); ++bool hmac_md_duplicate(const void *hmac_md_ctx, void *new_hmac_md_ctx); ++bool hmac_md_update(void *hmac_md_ctx, const void *data, ++ size_t data_size); ++bool hmac_md_final(void *hmac_md_ctx, uint8_t *hmac_value); ++bool hmac_md_all(const EVP_MD *md, const void *data, ++ size_t data_size, const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value); ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA3_256 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sha3_256_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sha3_256_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sha3_256_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sha3_256_free(void *hmac_sha3_256_ctx) ++{ ++ hmac_md_free(hmac_sha3_256_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sha3_256_update(). ++ * ++ * If hmac_sha3_256_ctx is NULL, then return false. ++ * ++ * @param[out] hmac_sha3_256_ctx Pointer to HMAC-SHA3_256 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * ++ **/ ++bool libspdm_hmac_sha3_256_set_key(void *hmac_sha3_256_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sha3_256(), hmac_sha3_256_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SHA3_256 context. ++ * ++ * If hmac_sha3_256_ctx is NULL, then return false. ++ * If new_hmac_sha3_256_ctx is NULL, then return false. ++ * ++ * @param[in] hmac_sha3_256_ctx Pointer to HMAC-SHA3_256 context being copied. ++ * @param[out] new_hmac_sha3_256_ctx Pointer to new HMAC-SHA3_256 context. ++ * ++ * @retval true HMAC-SHA3_256 context copy succeeded. ++ * @retval false HMAC-SHA3_256 context copy failed. ++ * ++ **/ ++bool libspdm_hmac_sha3_256_duplicate(const void *hmac_sha3_256_ctx, ++ void *new_hmac_sha3_256_ctx) ++{ ++ return hmac_md_duplicate(hmac_sha3_256_ctx, new_hmac_sha3_256_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SHA3_256 context. ++ * ++ * This function performs HMAC-SHA3_256 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SHA3_256 context should be initialized by libspdm_hmac_sha3_256_new(), and should not be finalized ++ * by libspdm_hmac_sha3_256_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sha3_256_ctx is NULL, then return false. ++ * ++ * @param[in, out] hmac_sha3_256_ctx Pointer to the HMAC-SHA3_256 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SHA3_256 data digest succeeded. ++ * @retval false HMAC-SHA3_256 data digest failed. ++ * ++ **/ ++bool libspdm_hmac_sha3_256_update(void *hmac_sha3_256_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sha3_256_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SHA3_256 digest value. ++ * ++ * This function completes HMAC-SHA3_256 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SHA3_256 context cannot ++ * be used again. ++ * HMAC-SHA3_256 context should be initialized by libspdm_hmac_sha3_256_new(), and should not be finalized ++ * by libspdm_hmac_sha3_256_final(). Behavior with invalid HMAC-SHA3_256 context is undefined. ++ * ++ * If hmac_sha3_256_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * ++ * @param[in, out] hmac_sha3_256_ctx Pointer to the HMAC-SHA3_256 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SHA3_256 digest ++ * value (32 bytes). ++ * ++ * @retval true HMAC-SHA3_256 digest computation succeeded. ++ * @retval false HMAC-SHA3_256 digest computation failed. ++ * ++ **/ ++bool libspdm_hmac_sha3_256_final(void *hmac_sha3_256_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sha3_256_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SHA3_256 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SHA3_256 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SHA3_256 digest ++ * value (32 bytes). ++ * ++ * @retval true HMAC-SHA3_256 digest computation succeeded. ++ * @retval false HMAC-SHA3_256 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_256_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sha3_256(), data, data_size, key, key_size, ++ hmac_value); ++} ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA3_384 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sha3_384_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sha3_384_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sha3_384_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sha3_384_free(void *hmac_sha3_384_ctx) ++{ ++ hmac_md_free(hmac_sha3_384_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sha3_384_update(). ++ * ++ * If hmac_sha3_384_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[out] hmac_sha3_384_ctx Pointer to HMAC-SHA3_384 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_384_set_key(void *hmac_sha3_384_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sha3_384(), hmac_sha3_384_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SHA3_384 context. ++ * ++ * If hmac_sha3_384_ctx is NULL, then return false. ++ * If new_hmac_sha3_384_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] hmac_sha3_384_ctx Pointer to HMAC-SHA3_384 context being copied. ++ * @param[out] new_hmac_sha3_384_ctx Pointer to new HMAC-SHA3_384 context. ++ * ++ * @retval true HMAC-SHA3_384 context copy succeeded. ++ * @retval false HMAC-SHA3_384 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_384_duplicate(const void *hmac_sha3_384_ctx, ++ void *new_hmac_sha3_384_ctx) ++{ ++ return hmac_md_duplicate(hmac_sha3_384_ctx, new_hmac_sha3_384_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SHA3_384 context. ++ * ++ * This function performs HMAC-SHA3_384 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SHA3_384 context should be initialized by libspdm_hmac_sha3_384_new(), and should not be finalized ++ * by libspdm_hmac_sha3_384_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sha3_384_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha3_384_ctx Pointer to the HMAC-SHA3_384 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SHA3_384 data digest succeeded. ++ * @retval false HMAC-SHA3_384 data digest failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_384_update(void *hmac_sha3_384_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sha3_384_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SHA3_384 digest value. ++ * ++ * This function completes HMAC-SHA3_384 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SHA3_384 context cannot ++ * be used again. ++ * HMAC-SHA3_384 context should be initialized by libspdm_hmac_sha3_384_new(), and should not be finalized ++ * by libspdm_hmac_sha3_384_final(). Behavior with invalid HMAC-SHA3_384 context is undefined. ++ * ++ * If hmac_sha3_384_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha3_384_ctx Pointer to the HMAC-SHA3_384 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SHA3_384 digest ++ * value (48 bytes). ++ * ++ * @retval true HMAC-SHA3_384 digest computation succeeded. ++ * @retval false HMAC-SHA3_384 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_384_final(void *hmac_sha3_384_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sha3_384_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SHA3_384 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SHA3_384 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SHA3_384 digest ++ * value (48 bytes). ++ * ++ * @retval true HMAC-SHA3_384 digest computation succeeded. ++ * @retval false HMAC-SHA3_384 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_384_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sha3_384(), data, data_size, key, key_size, ++ hmac_value); ++} ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA3_512 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sha3_512_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sha3_512_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sha3_512_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sha3_512_free(void *hmac_sha3_512_ctx) ++{ ++ hmac_md_free(hmac_sha3_512_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sha3_512_update(). ++ * ++ * If hmac_sha3_512_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[out] hmac_sha3_512_ctx Pointer to HMAC-SHA3_512 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_512_set_key(void *hmac_sha3_512_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sha3_512(), hmac_sha3_512_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SHA3_512 context. ++ * ++ * If hmac_sha3_512_ctx is NULL, then return false. ++ * If new_hmac_sha3_512_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] hmac_sha3_512_ctx Pointer to HMAC-SHA3_512 context being copied. ++ * @param[out] new_hmac_sha3_512_ctx Pointer to new HMAC-SHA3_512 context. ++ * ++ * @retval true HMAC-SHA3_512 context copy succeeded. ++ * @retval false HMAC-SHA3_512 context copy failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_512_duplicate(const void *hmac_sha3_512_ctx, ++ void *new_hmac_sha3_512_ctx) ++{ ++ return hmac_md_duplicate(hmac_sha3_512_ctx, new_hmac_sha3_512_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SHA3_512 context. ++ * ++ * This function performs HMAC-SHA3_512 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SHA3_512 context should be initialized by libspdm_hmac_sha3_512_new(), and should not be finalized ++ * by libspdm_hmac_sha3_512_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sha3_512_ctx is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha3_512_ctx Pointer to the HMAC-SHA3_512 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SHA3_512 data digest succeeded. ++ * @retval false HMAC-SHA3_512 data digest failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_512_update(void *hmac_sha3_512_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sha3_512_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SHA3_512 digest value. ++ * ++ * This function completes HMAC-SHA3_512 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SHA3_512 context cannot ++ * be used again. ++ * HMAC-SHA3_512 context should be initialized by libspdm_hmac_sha3_512_new(), and should not be finalized ++ * by libspdm_hmac_sha3_512_final(). Behavior with invalid HMAC-SHA3_512 context is undefined. ++ * ++ * If hmac_sha3_512_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] hmac_sha3_512_ctx Pointer to the HMAC-SHA3_512 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SHA3_512 digest ++ * value (64 bytes). ++ * ++ * @retval true HMAC-SHA3_512 digest computation succeeded. ++ * @retval false HMAC-SHA3_512 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_512_final(void *hmac_sha3_512_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sha3_512_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SHA3_512 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SHA3_512 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SHA3_512 digest ++ * value (64 bytes). ++ * ++ * @retval true HMAC-SHA3_512 digest computation succeeded. ++ * @retval false HMAC-SHA3_512 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sha3_512_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sha3_512(), data, data_size, key, key_size, ++ hmac_value); ++} +diff --git a/os_stub/cryptlib_wolfssl/hmac/hmac_sm3.c b/os_stub/cryptlib_wolfssl/hmac/hmac_sm3.c +new file mode 100644 +index 0000000000..5e5896ce88 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/hmac/hmac_sm3.c +@@ -0,0 +1,163 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * HMAC-SM3 Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++ ++void *hmac_md_new(void); ++void hmac_md_free(void *hmac_md_ctx); ++bool hmac_md_set_key(const EVP_MD *md, void *hmac_md_ctx, ++ const uint8_t *key, size_t key_size); ++bool hmac_md_duplicate(const void *hmac_md_ctx, void *new_hmac_md_ctx); ++bool hmac_md_update(void *hmac_md_ctx, const void *data, ++ size_t data_size); ++bool hmac_md_final(void *hmac_md_ctx, uint8_t *hmac_value); ++bool hmac_md_all(const EVP_MD *md, const void *data, ++ size_t data_size, const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value); ++ ++/** ++ * Allocates and initializes one HMAC_CTX context for subsequent HMAC-SM3_256 use. ++ * ++ * @return Pointer to the HMAC_CTX context that has been initialized. ++ * If the allocations fails, libspdm_hmac_sm3_256_new() returns NULL. ++ * ++ **/ ++void *libspdm_hmac_sm3_256_new(void) ++{ ++ return hmac_md_new(); ++} ++ ++/** ++ * Release the specified HMAC_CTX context. ++ * ++ * @param[in] hmac_sm3_256_ctx Pointer to the HMAC_CTX context to be released. ++ * ++ **/ ++void libspdm_hmac_sm3_256_free(void *hmac_sm3_256_ctx) ++{ ++ hmac_md_free(hmac_sm3_256_ctx); ++} ++ ++/** ++ * Set user-supplied key for subsequent use. It must be done before any ++ * calling to libspdm_hmac_sm3_256_update(). ++ * ++ * If hmac_sm3_256_ctx is NULL, then return false. ++ * ++ * @param[out] hmac_sm3_256_ctx Pointer to HMAC-SM3_256 context. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * ++ * @retval true The key is set successfully. ++ * @retval false The key is set unsuccessfully. ++ * ++ **/ ++bool libspdm_hmac_sm3_256_set_key(void *hmac_sm3_256_ctx, const uint8_t *key, ++ size_t key_size) ++{ ++ return hmac_md_set_key(EVP_sm3(), hmac_sm3_256_ctx, key, key_size); ++} ++ ++/** ++ * Makes a copy of an existing HMAC-SM3_256 context. ++ * ++ * If hmac_sm3_256_ctx is NULL, then return false. ++ * If new_hmac_sm3_256_ctx is NULL, then return false. ++ * ++ * @param[in] hmac_sm3_256_ctx Pointer to HMAC-SM3_256 context being copied. ++ * @param[out] new_hmac_sm3_256_ctx Pointer to new HMAC-SM3_256 context. ++ * ++ * @retval true HMAC-SM3_256 context copy succeeded. ++ * @retval false HMAC-SM3_256 context copy failed. ++ * ++ **/ ++bool libspdm_hmac_sm3_256_duplicate(const void *hmac_sm3_256_ctx, ++ void *new_hmac_sm3_256_ctx) ++{ ++ return hmac_md_duplicate(hmac_sm3_256_ctx, new_hmac_sm3_256_ctx); ++} ++ ++/** ++ * Digests the input data and updates HMAC-SM3_256 context. ++ * ++ * This function performs HMAC-SM3_256 digest on a data buffer of the specified size. ++ * It can be called multiple times to compute the digest of long or discontinuous data streams. ++ * HMAC-SM3_256 context should be initialized by libspdm_hmac_sm3_256_new(), and should not be finalized ++ * by libspdm_hmac_sm3_256_final(). Behavior with invalid context is undefined. ++ * ++ * If hmac_sm3_256_ctx is NULL, then return false. ++ * ++ * @param[in, out] hmac_sm3_256_ctx Pointer to the HMAC-SM3_256 context. ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * ++ * @retval true HMAC-SM3_256 data digest succeeded. ++ * @retval false HMAC-SM3_256 data digest failed. ++ * ++ **/ ++bool libspdm_hmac_sm3_256_update(void *hmac_sm3_256_ctx, const void *data, ++ size_t data_size) ++{ ++ return hmac_md_update(hmac_sm3_256_ctx, data, data_size); ++} ++ ++/** ++ * Completes computation of the HMAC-SM3_256 digest value. ++ * ++ * This function completes HMAC-SM3_256 hash computation and retrieves the digest value into ++ * the specified memory. After this function has been called, the HMAC-SM3_256 context cannot ++ * be used again. ++ * HMAC-SM3_256 context should be initialized by libspdm_hmac_sm3_256_new(), and should not be finalized ++ * by libspdm_hmac_sm3_256_final(). Behavior with invalid HMAC-SM3_256 context is undefined. ++ * ++ * If hmac_sm3_256_ctx is NULL, then return false. ++ * If hmac_value is NULL, then return false. ++ * ++ * @param[in, out] hmac_sm3_256_ctx Pointer to the HMAC-SM3_256 context. ++ * @param[out] hmac_value Pointer to a buffer that receives the HMAC-SM3_256 digest ++ * value (32 bytes). ++ * ++ * @retval true HMAC-SM3_256 digest computation succeeded. ++ * @retval false HMAC-SM3_256 digest computation failed. ++ * ++ **/ ++bool libspdm_hmac_sm3_256_final(void *hmac_sm3_256_ctx, uint8_t *hmac_value) ++{ ++ return hmac_md_final(hmac_sm3_256_ctx, hmac_value); ++} ++ ++/** ++ * Computes the HMAC-SM3_256 digest of a input data buffer. ++ * ++ * This function performs the HMAC-SM3_256 digest of a given data buffer, and places ++ * the digest value into the specified memory. ++ * ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] data Pointer to the buffer containing the data to be digested. ++ * @param[in] data_size size of data buffer in bytes. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[out] hash_value Pointer to a buffer that receives the HMAC-SM3_256 digest ++ * value (32 bytes). ++ * ++ * @retval true HMAC-SM3_256 digest computation succeeded. ++ * @retval false HMAC-SM3_256 digest computation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_hmac_sm3_256_all(const void *data, size_t data_size, ++ const uint8_t *key, size_t key_size, ++ uint8_t *hmac_value) ++{ ++ return hmac_md_all(EVP_sm3(), data, data_size, key, key_size, ++ hmac_value); ++} +diff --git a/os_stub/cryptlib_wolfssl/internal_crypt_lib.h b/os_stub/cryptlib_wolfssl/internal_crypt_lib.h +new file mode 100644 +index 0000000000..872b879989 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/internal_crypt_lib.h +@@ -0,0 +1,103 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2024 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * Internal include file for cryptlib. ++ **/ ++ ++#ifndef __INTERNAL_CRYPT_LIB_H__ ++#define __INTERNAL_CRYPT_LIB_H__ ++ ++#include ++#include "library/memlib.h" ++#include "library/malloclib.h" ++#include "library/debuglib.h" ++#include "library/cryptlib.h" ++#include "library/spdm_crypt_lib.h" ++ ++//#include "crt_support.h" ++// from os_stub/openssllib/include/crt_support.h ++#define LIBSPDM_VA_LIST va_list ++#define LIBSPDM_VA_START(marker, parameter) va_start(marker, parameter) ++#define LIBSPDM_VA_ARG(marker, TYPE) va_arg(marker, TYPE) ++#define LIBSPDM_VA_END(marker) va_end(marker) ++ ++#include ++#include ++ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++#define OBJ_get0_data(o) ((o)->data) ++#define OBJ_length(o) ((o)->length) ++#endif ++ ++#include ++#include ++ ++// missing from wolfssl ++ ++RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa); ++// use wolfSSL_d2i_RSAPrivateKey_bio and wolfSSL_d2i_RSAPublicKey as basis ++ ++EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); ++// use wolfSSL_d2i_RSAPrivateKey_bio, wolfSSL_d2i_RSAPublicKey, wolfSSL_ECDSA_do_verify, and wolfSSL_d2i_ECDSA_SIG, as guides ++ ++int EVP_PKEY_is_a(const EVP_PKEY *pkey, const char *name); ++// https://github.com/wolfSSL/wolfssl/pull/7804 ++ ++int DH_compute_key_padded(unsigned char *key, ++ const BIGNUM *pub_key, DH *dh); ++// may be impossible, or require fakery, due to FIPS requirement. ++// see https://github.com/wolfSSL/wolfssl/pull/7802 ++/* "DH_compute_key() computes the shared secret from the private DH value in dh and the other party’s ++ public value in pub_key and stores it in key. key must point to DH_size(dh) bytes of memory. The ++ padding style is RFC 5246 (8.1.2) that strips leading zero bytes. It is not constant time due to ++ the leading zero bytes being stripped. The return value should be considered public." ++ ++ "DH_compute_key_padded() is similar but stores a fixed number of bytes. The padding style is NIST SP ++ 800-56A (C.1) that retains leading zero bytes. It is constant time due to the leading zero bytes ++ being retained. The return value should be considered public." ++ */ ++ ++/* ++// not needed -- altered libspdm_rsa_check_key() to return false for any ++// RSA_check_key() failure, rather than just these. ++#define RSA_R_P_NOT_PRIME (-1) ++#define RSA_R_Q_NOT_PRIME (-1) ++#define RSA_R_N_DOES_NOT_EQUAL_P_Q (-1) ++#define RSA_R_D_E_NOT_CONGRUENT_TO_1 (-1) ++*/ ++ ++int ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str); ++/* "ASN1_TIME_set_string_X509() sets ASN1_TIME structure s to the time represented by string str which ++ must be in appropriate time format that RFC 5280 requires, which means it only allows YYMMDDHHMMSSZ ++ and YYYYMMDDHHMMSSZ (leap second is rejected), all other ASN.1 time format are not allowed. If s is ++ NULL this function performs a format check on str only." ++*/ ++ ++struct X509_req_info_st { ++// ASN1_ENCODING enc; /* cached encoding of signed part */ ++ ASN1_INTEGER *version; /* version, defaults to v1(0) so can be NULL */ ++ X509_NAME *subject; /* certificate request DN */ ++ X509_PUBKEY *pubkey; /* public key of request */ ++ /* ++ * Zero or more attributes. ++ * NB: although attributes is a mandatory field some broken ++ * encodings omit it so this may be NULL in that case. ++ */ ++ STACK_OF(X509_ATTRIBUTE) *attributes; ++}; ++typedef struct X509_req_info_st X509_REQ_INFO; ++ ++X509_REQ_INFO *d2i_X509_REQ_INFO(X509_REQ_INFO **req_info, const unsigned char **ppin, long length); ++// use d2i_X509orX509REQ as a guide ++ ++void X509_REQ_INFO_free(X509_REQ_INFO *req_info); ++// wrapper around wolfSSL_X509_free(); ++ ++void sk_X509_EXTENSION_free(STACK_OF(X509_EXTENSION) *exts); ++// see wolfSSL_X509_EXTENSION_free and wolfSSL_sk_X509_INFO_free ++ ++#endif +diff --git a/os_stub/cryptlib_wolfssl/kdf/hkdf_sha.c b/os_stub/cryptlib_wolfssl/kdf/hkdf_sha.c +new file mode 100644 +index 0000000000..732c807f93 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/kdf/hkdf_sha.c +@@ -0,0 +1,404 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * HMAC-SHA256/384/512 KDF Wrapper Implementation. ++ * ++ * RFC 5869: HMAC-based Extract-and-Expand key Derivation Function (HKDF) ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++/** ++ * Derive HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] md message digest. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool hkdf_md_extract_and_expand(const EVP_MD *md, const uint8_t *key, ++ size_t key_size, const uint8_t *salt, ++ size_t salt_size, const uint8_t *info, ++ size_t info_size, uint8_t *out, ++ size_t out_size) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ bool result; ++ ++ if (key == NULL || salt == NULL || info == NULL || out == NULL || ++ key_size > INT_MAX || salt_size > INT_MAX || info_size > INT_MAX || ++ out_size > INT_MAX) { ++ return false; ++ } ++ ++ pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); ++ if (pkey_ctx == NULL) { ++ return false; ++ } ++ ++ result = EVP_PKEY_derive_init(pkey_ctx) > 0; ++ if (result) { ++ result = EVP_PKEY_CTX_set_hkdf_md(pkey_ctx, md) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_set1_hkdf_salt(pkey_ctx, salt, ++ (uint32_t)salt_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_set1_hkdf_key(pkey_ctx, key, ++ (uint32_t)key_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_add1_hkdf_info(pkey_ctx, info, ++ (uint32_t)info_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_derive(pkey_ctx, out, &out_size) > 0; ++ } ++ ++ EVP_PKEY_CTX_free(pkey_ctx); ++ pkey_ctx = NULL; ++ return result; ++} ++ ++/** ++ * Derive HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] md message digest. ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool hkdf_md_extract(const EVP_MD *md, const uint8_t *key, ++ size_t key_size, const uint8_t *salt, ++ size_t salt_size, uint8_t *prk_out, ++ size_t prk_out_size) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ bool result; ++ ++ if (key == NULL || salt == NULL || prk_out == NULL || ++ key_size > INT_MAX || salt_size > INT_MAX || ++ prk_out_size > INT_MAX) { ++ return false; ++ } ++ ++ pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); ++ if (pkey_ctx == NULL) { ++ return false; ++ } ++ ++ result = EVP_PKEY_derive_init(pkey_ctx) > 0; ++ if (result) { ++ result = EVP_PKEY_CTX_set_hkdf_md(pkey_ctx, md) > 0; ++ } ++ if (result) { ++ result = ++ EVP_PKEY_CTX_hkdf_mode( ++ pkey_ctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_set1_hkdf_salt(pkey_ctx, salt, ++ (uint32_t)salt_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_set1_hkdf_key(pkey_ctx, key, ++ (uint32_t)key_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_derive(pkey_ctx, prk_out, &prk_out_size) > 0; ++ } ++ ++ EVP_PKEY_CTX_free(pkey_ctx); ++ pkey_ctx = NULL; ++ return result; ++} ++ ++/** ++ * Derive HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] md message digest. ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool hkdf_md_expand(const EVP_MD *md, const uint8_t *prk, ++ size_t prk_size, const uint8_t *info, ++ size_t info_size, uint8_t *out, size_t out_size) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ bool result; ++ ++ if (prk == NULL || info == NULL || out == NULL || prk_size > INT_MAX || ++ info_size > INT_MAX || out_size > INT_MAX) { ++ return false; ++ } ++ ++ pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); ++ if (pkey_ctx == NULL) { ++ return false; ++ } ++ ++ result = EVP_PKEY_derive_init(pkey_ctx) > 0; ++ if (result) { ++ result = EVP_PKEY_CTX_set_hkdf_md(pkey_ctx, md) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_hkdf_mode( ++ pkey_ctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_set1_hkdf_key(pkey_ctx, prk, ++ (uint32_t)prk_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_CTX_add1_hkdf_info(pkey_ctx, info, ++ (uint32_t)info_size) > 0; ++ } ++ if (result) { ++ result = EVP_PKEY_derive(pkey_ctx, out, &out_size) > 0; ++ } ++ ++ EVP_PKEY_CTX_free(pkey_ctx); ++ pkey_ctx = NULL; ++ return result; ++} ++ ++/** ++ * Derive SHA256 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha256_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sha256(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA256 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha256_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sha256(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SHA256 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha256_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sha256(), prk, prk_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA384 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha384_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sha384(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA384 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha384_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sha384(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SHA384 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha384_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sha384(), prk, prk_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA512 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha512_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sha512(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA512 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha512_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sha512(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SHA512 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha512_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sha512(), prk, prk_size, info, info_size, out, ++ out_size); ++} +diff --git a/os_stub/cryptlib_wolfssl/kdf/hkdf_sha3.c b/os_stub/cryptlib_wolfssl/kdf/hkdf_sha3.c +new file mode 100644 +index 0000000000..12dbd90f5e +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/kdf/hkdf_sha3.c +@@ -0,0 +1,238 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * HMAC-SHA3_256/384/512 KDF Wrapper Implementation. ++ * ++ * RFC 5869: HMAC-based Extract-and-Expand key Derivation Function (HKDF) ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++bool hkdf_md_extract_and_expand(const EVP_MD *md, const uint8_t *key, ++ size_t key_size, const uint8_t *salt, ++ size_t salt_size, const uint8_t *info, ++ size_t info_size, uint8_t *out, ++ size_t out_size); ++bool hkdf_md_extract(const EVP_MD *md, const uint8_t *key, ++ size_t key_size, const uint8_t *salt, ++ size_t salt_size, uint8_t *prk_out, ++ size_t prk_out_size); ++bool hkdf_md_expand(const EVP_MD *md, const uint8_t *prk, ++ size_t prk_size, const uint8_t *info, ++ size_t info_size, uint8_t *out, size_t out_size); ++ ++/** ++ * Derive SHA3_256 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_256_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sha3_256(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA3_256 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_256_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sha3_256(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SHA3_256 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_256_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sha3_256(), prk, prk_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA3_384 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_384_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sha3_384(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA3_384 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_384_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sha3_384(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SHA3_384 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_384_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sha3_384(), prk, prk_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA3_512 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_512_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sha3_512(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SHA3_512 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_512_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sha3_512(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SHA3_512 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sha3_512_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sha3_512(), prk, prk_size, info, info_size, out, ++ out_size); ++} +diff --git a/os_stub/cryptlib_wolfssl/kdf/hkdf_sm3.c b/os_stub/cryptlib_wolfssl/kdf/hkdf_sm3.c +new file mode 100644 +index 0000000000..7d306af352 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/kdf/hkdf_sm3.c +@@ -0,0 +1,98 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * HMAC-SM3_256 KDF Wrapper Implementation. ++ * ++ * RFC 5869: HMAC-based Extract-and-Expand key Derivation Function (HKDF) ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++bool hkdf_md_extract_and_expand(const EVP_MD *md, const uint8_t *key, ++ size_t key_size, const uint8_t *salt, ++ size_t salt_size, const uint8_t *info, ++ size_t info_size, uint8_t *out, ++ size_t out_size); ++bool hkdf_md_extract(const EVP_MD *md, const uint8_t *key, ++ size_t key_size, const uint8_t *salt, ++ size_t salt_size, uint8_t *prk_out, ++ size_t prk_out_size); ++bool hkdf_md_expand(const EVP_MD *md, const uint8_t *prk, ++ size_t prk_size, const uint8_t *info, ++ size_t info_size, uint8_t *out, size_t out_size); ++ ++/** ++ * Derive SM3_256 HMAC-based Extract-and-Expand key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sm3_256_extract_and_expand(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_extract_and_expand(EVP_sm3(), key, key_size, salt, ++ salt_size, info, info_size, out, ++ out_size); ++} ++ ++/** ++ * Derive SM3_256 HMAC-based Extract key Derivation Function (HKDF). ++ * ++ * @param[in] key Pointer to the user-supplied key. ++ * @param[in] key_size key size in bytes. ++ * @param[in] salt Pointer to the salt(non-secret) value. ++ * @param[in] salt_size salt size in bytes. ++ * @param[out] prk_out Pointer to buffer to receive hkdf value. ++ * @param[in] prk_out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sm3_256_extract(const uint8_t *key, size_t key_size, ++ const uint8_t *salt, size_t salt_size, ++ uint8_t *prk_out, size_t prk_out_size) ++{ ++ return hkdf_md_extract(EVP_sm3(), key, key_size, salt, salt_size, ++ prk_out, prk_out_size); ++} ++ ++/** ++ * Derive SM3_256 HMAC-based Expand key Derivation Function (HKDF). ++ * ++ * @param[in] prk Pointer to the user-supplied key. ++ * @param[in] prk_size key size in bytes. ++ * @param[in] info Pointer to the application specific info. ++ * @param[in] info_size info size in bytes. ++ * @param[out] out Pointer to buffer to receive hkdf value. ++ * @param[in] out_size size of hkdf bytes to generate. ++ * ++ * @retval true Hkdf generated successfully. ++ * @retval false Hkdf generation failed. ++ * ++ **/ ++bool libspdm_hkdf_sm3_256_expand(const uint8_t *prk, size_t prk_size, ++ const uint8_t *info, size_t info_size, ++ uint8_t *out, size_t out_size) ++{ ++ return hkdf_md_expand(EVP_sm3(), prk, prk_size, info, info_size, out, ++ out_size); ++} +diff --git a/os_stub/cryptlib_wolfssl/pem/pem.c b/os_stub/cryptlib_wolfssl/pem/pem.c +new file mode 100644 +index 0000000000..6a4f39ed00 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pem/pem.c +@@ -0,0 +1,379 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * PEM (Privacy Enhanced Mail) format Handler Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++static size_t ascii_str_len(const char *string) ++{ ++ size_t length; ++ ++ LIBSPDM_ASSERT(string != NULL); ++ if (string == NULL) { ++ return 0; ++ } ++ ++ for (length = 0; *string != '\0'; string++, length++) { ++ ; ++ } ++ return length; ++} ++ ++/** ++ * Callback function for password phrase conversion used for retrieving the encrypted PEM. ++ * ++ * @param[out] buf Pointer to the buffer to write the passphrase to. ++ * @param[in] size Maximum length of the passphrase (i.e. the size of buf). ++ * @param[in] flag A flag which is set to 0 when reading and 1 when writing. ++ * @param[in] key key data to be passed to the callback routine. ++ * ++ * @retval The number of characters in the passphrase or 0 if an error occurred. ++ * ++ **/ ++int PasswordCallback(char *buf, const int size, const int flag, const void *key) ++{ ++ int key_length; ++ ++ libspdm_zero_mem((void *)buf, (size_t)size); ++ if (key != NULL) { ++ ++ /* Duplicate key phrase directly.*/ ++ ++ key_length = (int)ascii_str_len((char *)key); ++ key_length = (key_length > size) ? size : key_length; ++ libspdm_copy_mem(buf, size, key, (size_t)key_length); ++ return key_length; ++ } else { ++ return 0; ++ } ++} ++ ++#if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) ++/** ++ * Retrieve the RSA Private key from the password-protected PEM key data. ++ * ++ * @param[in] pem_data Pointer to the PEM-encoded key data to be retrieved. ++ * @param[in] pem_size size of the PEM key data in bytes. ++ * @param[in] password NULL-terminated passphrase used for encrypted PEM key data. ++ * @param[out] rsa_context Pointer to newly generated RSA context which contain the retrieved ++ * RSA private key component. Use libspdm_rsa_free() function to free the ++ * resource. ++ * ++ * If pem_data is NULL, then return false. ++ * If rsa_context is NULL, then return false. ++ * ++ * @retval true RSA Private key was retrieved successfully. ++ * @retval false Invalid PEM key data or incorrect password. ++ * ++ **/ ++bool libspdm_rsa_get_private_key_from_pem(const uint8_t *pem_data, ++ size_t pem_size, ++ const char *password, ++ void **rsa_context) ++{ ++ bool status; ++ BIO *pem_bio; ++ ++ /* Check input parameters.*/ ++ ++ if (pem_data == NULL || rsa_context == NULL || pem_size > INT_MAX) { ++ return false; ++ } ++ ++ /* Add possible block-cipher descriptor for PEM data decryption. ++ * NOTE: Only support most popular ciphers AES for the encrypted PEM.*/ ++ ++ if (EVP_add_cipher(EVP_aes_128_cbc()) == 0) { ++ return false; ++ } ++ if (EVP_add_cipher(EVP_aes_192_cbc()) == 0) { ++ return false; ++ } ++ if (EVP_add_cipher(EVP_aes_256_cbc()) == 0) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read encrypted PEM data.*/ ++ ++ pem_bio = BIO_new(BIO_s_mem()); ++ if (pem_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(pem_bio, pem_data, (int)pem_size) <= 0) { ++ goto done; ++ } ++ ++ /* Retrieve RSA Private key from encrypted PEM data.*/ ++ ++ *rsa_context = ++ PEM_read_bio_RSAPrivateKey(pem_bio, NULL, ++ (pem_password_cb *)&PasswordCallback, ++ (void *)password); ++ if (*rsa_context != NULL) { ++ status = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(pem_bio); ++ ++ return status; ++} ++#endif /* (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) */ ++ ++/** ++ * Retrieve the EC Private key from the password-protected PEM key data. ++ * ++ * @param[in] pem_data Pointer to the PEM-encoded key data to be retrieved. ++ * @param[in] pem_size size of the PEM key data in bytes. ++ * @param[in] password NULL-terminated passphrase used for encrypted PEM key data. ++ * @param[out] ec_context Pointer to newly generated EC DSA context which contain the retrieved ++ * EC private key component. Use libspdm_ec_free() function to free the ++ * resource. ++ * ++ * If pem_data is NULL, then return false. ++ * If ec_context is NULL, then return false. ++ * ++ * @retval true EC Private key was retrieved successfully. ++ * @retval false Invalid PEM key data or incorrect password. ++ * ++ **/ ++bool libspdm_ec_get_private_key_from_pem(const uint8_t *pem_data, size_t pem_size, ++ const char *password, ++ void **ec_context) ++{ ++ bool status; ++ BIO *pem_bio; ++ ++ /* Check input parameters.*/ ++ ++ if (pem_data == NULL || ec_context == NULL || pem_size > INT_MAX) { ++ return false; ++ } ++ ++ /* Add possible block-cipher descriptor for PEM data decryption. ++ * NOTE: Only support most popular ciphers AES for the encrypted PEM.*/ ++ ++ if (EVP_add_cipher(EVP_aes_128_cbc()) == 0) { ++ return false; ++ } ++ if (EVP_add_cipher(EVP_aes_192_cbc()) == 0) { ++ return false; ++ } ++ if (EVP_add_cipher(EVP_aes_256_cbc()) == 0) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read encrypted PEM data.*/ ++ ++ pem_bio = BIO_new(BIO_s_mem()); ++ if (pem_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(pem_bio, pem_data, (int)pem_size) <= 0) { ++ goto done; ++ } ++ ++ ++ /* Retrieve EC Private key from encrypted PEM data.*/ ++ ++ *ec_context = ++ PEM_read_bio_ECPrivateKey(pem_bio, NULL, ++ (pem_password_cb *)&PasswordCallback, ++ (void *)password); ++ if (*ec_context != NULL) { ++ status = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(pem_bio); ++ ++ return status; ++} ++ ++#if (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT) ++/** ++ * Retrieve the Ed Private key from the password-protected PEM key data. ++ * ++ * @param[in] pem_data Pointer to the PEM-encoded key data to be retrieved. ++ * @param[in] pem_size size of the PEM key data in bytes. ++ * @param[in] password NULL-terminated passphrase used for encrypted PEM key data. ++ * @param[out] ecd_context Pointer to newly generated Ed DSA context which contain the retrieved ++ * Ed private key component. Use libspdm_ecd_free() function to free the ++ * resource. ++ * ++ * If pem_data is NULL, then return false. ++ * If ecd_context is NULL, then return false. ++ * ++ * @retval true Ed Private key was retrieved successfully. ++ * @retval false Invalid PEM key data or incorrect password. ++ * ++ **/ ++bool libspdm_ecd_get_private_key_from_pem(const uint8_t *pem_data, ++ size_t pem_size, ++ const char *password, ++ void **ecd_context) ++{ ++ bool status; ++ BIO *pem_bio; ++ EVP_PKEY *pkey; ++ int32_t type; ++ ++ /* Check input parameters.*/ ++ ++ if (pem_data == NULL || ecd_context == NULL || pem_size > INT_MAX) { ++ return false; ++ } ++ ++ /* Add possible block-cipher descriptor for PEM data decryption. ++ * NOTE: Only support most popular ciphers AES for the encrypted PEM.*/ ++ ++ if (EVP_add_cipher(EVP_aes_128_cbc()) == 0) { ++ return false; ++ } ++ if (EVP_add_cipher(EVP_aes_192_cbc()) == 0) { ++ return false; ++ } ++ if (EVP_add_cipher(EVP_aes_256_cbc()) == 0) { ++ return false; ++ } ++ ++ status = false; ++ ++ /* Read encrypted PEM data.*/ ++ ++ pem_bio = BIO_new(BIO_s_mem()); ++ if (pem_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(pem_bio, pem_data, (int)pem_size) <= 0) { ++ goto done; ++ } ++ ++ ++ /* Retrieve Ed Private key from encrypted PEM data.*/ ++ ++ pkey = PEM_read_bio_PrivateKey(pem_bio, NULL, ++ (pem_password_cb *)&PasswordCallback, ++ (void *)password); ++ if (pkey == NULL) { ++ goto done; ++ } ++ type = EVP_PKEY_id(pkey); ++ if ((type != EVP_PKEY_ED25519) && (type != EVP_PKEY_ED448)) { ++ goto done; ++ } ++ *ecd_context = pkey; ++ status = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(pem_bio); ++ ++ return status; ++} ++#endif /* LIBSPDM_EDDSA_ED25519_SUPPORT || LIBSPDM_EDDSA_ED448_SUPPORT */ ++ ++#if LIBSPDM_SM2_DSA_P256_SUPPORT ++/** ++ * Retrieve the sm2 Private key from the password-protected PEM key data. ++ * ++ * @param[in] pem_data Pointer to the PEM-encoded key data to be retrieved. ++ * @param[in] pem_size size of the PEM key data in bytes. ++ * @param[in] password NULL-terminated passphrase used for encrypted PEM key data. ++ * @param[out] sm2_context Pointer to newly generated sm2 context which contain the retrieved ++ * sm2 private key component. Use sm2_free() function to free the ++ * resource. ++ * ++ * If pem_data is NULL, then return false. ++ * If sm2_context is NULL, then return false. ++ * ++ * @retval true sm2 Private key was retrieved successfully. ++ * @retval false Invalid PEM key data or incorrect password. ++ * ++ **/ ++bool libspdm_sm2_get_private_key_from_pem(const uint8_t *pem_data, ++ size_t pem_size, ++ const char *password, ++ void **sm2_context) ++{ ++ bool status; ++ BIO *pem_bio; ++ EVP_PKEY *pkey; ++ EC_KEY *ec_key; ++ int32_t openssl_nid; ++ ++ /* Check input parameters.*/ ++ ++ if (pem_data == NULL || sm2_context == NULL || pem_size > INT_MAX) { ++ return false; ++ } ++ ++ /* Add possible block-cipher descriptor for PEM data decryption. ++ * NOTE: Only support SM4 for the encrypted PEM.*/ ++ ++ /*if (EVP_add_cipher (EVP_sm4_cbc ()) == 0) { ++ * return false; ++ *}*/ ++ ++ status = false; ++ ++ /* Read encrypted PEM data.*/ ++ ++ pem_bio = BIO_new(BIO_s_mem()); ++ if (pem_bio == NULL) { ++ return status; ++ } ++ ++ if (BIO_write(pem_bio, pem_data, (int)pem_size) <= 0) { ++ goto done; ++ } ++ ++ /* Retrieve sm2 Private key from encrypted PEM data.*/ ++ ++ pkey = PEM_read_bio_PrivateKey(pem_bio, NULL, ++ (pem_password_cb *)&PasswordCallback, ++ (void *)password); ++ if (pkey == NULL) { ++ goto done; ++ } ++ ec_key = (void *)EVP_PKEY_get0_EC_KEY(pkey); ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ if (openssl_nid != NID_sm2) { ++ goto done; ++ } ++ ++ *sm2_context = pkey; ++ status = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ BIO_free(pem_bio); ++ ++ return status; ++} ++#endif /* LIBSPDM_SM2_DSA_P256_SUPPORT */ +diff --git a/os_stub/cryptlib_wolfssl/pk/dh.c b/os_stub/cryptlib_wolfssl/pk/dh.c +new file mode 100644 +index 0000000000..aab55679c1 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/dh.c +@@ -0,0 +1,342 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * Diffie-Hellman Wrapper Implementation over. ++ * ++ * RFC 7919 - Negotiated Finite Field Diffie-Hellman Ephemeral (FFDHE) Parameters ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++#include ++ ++#if LIBSPDM_FFDHE_SUPPORT ++ ++/** ++ * Allocates and Initializes one Diffie-Hellman context for subsequent use ++ * with the NID. ++ * ++ * @param nid cipher NID ++ * ++ * @return Pointer to the Diffie-Hellman context that has been initialized. ++ * If the allocations fails, dh_new() returns NULL. ++ * ++ **/ ++void *libspdm_dh_new_by_nid(size_t nid) ++{ ++ switch (nid) { ++ case LIBSPDM_CRYPTO_NID_FFDHE2048: ++ return DH_new_by_nid(NID_ffdhe2048); ++ case LIBSPDM_CRYPTO_NID_FFDHE3072: ++ return DH_new_by_nid(NID_ffdhe3072); ++ case LIBSPDM_CRYPTO_NID_FFDHE4096: ++ return DH_new_by_nid(NID_ffdhe4096); ++ default: ++ return NULL; ++ } ++} ++ ++/** ++ * Release the specified DH context. ++ * ++ * If dh_context is NULL, then return false. ++ * ++ * @param[in] dh_context Pointer to the DH context to be released. ++ * ++ **/ ++void libspdm_dh_free(void *dh_context) ++{ ++ ++ /* Free OpenSSL DH context*/ ++ ++ DH_free((DH *)dh_context); ++} ++ ++/** ++ * Generates DH parameter. ++ * ++ * Given generator g, and length of prime number p in bits, this function generates p, ++ * and sets DH context according to value of g and p. ++ * ++ * If dh_context is NULL, then return false. ++ * If prime is NULL, then return false. ++ * ++ * @param[in, out] dh_context Pointer to the DH context. ++ * @param[in] generator value of generator. ++ * @param[in] prime_length length in bits of prime to be generated. ++ * @param[out] prime Pointer to the buffer to receive the generated prime number. ++ * ++ * @retval true DH parameter generation succeeded. ++ * @retval false value of generator is not supported. ++ * @retval false PRNG fails to generate random prime number with prime_length. ++ * ++ **/ ++bool libspdm_dh_generate_parameter(void *dh_context, size_t generator, ++ size_t prime_length, uint8_t *prime) ++{ ++ bool ret_val; ++ BIGNUM *bn_p; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (dh_context == NULL || prime == NULL || prime_length > INT_MAX) { ++ return false; ++ } ++ ++ if (generator != DH_GENERATOR_2 && generator != DH_GENERATOR_5) { ++ return false; ++ } ++ ++ ret_val = (bool)DH_generate_parameters_ex( ++ dh_context, (uint32_t)prime_length, (uint32_t)generator, NULL); ++ if (!ret_val) { ++ return false; ++ } ++ ++ DH_get0_pqg(dh_context, (const BIGNUM **)&bn_p, NULL, NULL); ++ BN_bn2bin(bn_p, prime); ++ ++ return true; ++} ++ ++/** ++ * Sets generator and prime parameters for DH. ++ * ++ * Given generator g, and prime number p, this function and sets DH ++ * context accordingly. ++ * ++ * If dh_context is NULL, then return false. ++ * If prime is NULL, then return false. ++ * ++ * @param[in, out] dh_context Pointer to the DH context. ++ * @param[in] generator value of generator. ++ * @param[in] prime_length length in bits of prime to be generated. ++ * @param[in] prime Pointer to the prime number. ++ * ++ * @retval true DH parameter setting succeeded. ++ * @retval false value of generator is not supported. ++ * @retval false value of generator is not suitable for the prime. ++ * @retval false value of prime is not a prime number. ++ * @retval false value of prime is not a safe prime number. ++ * ++ **/ ++bool libspdm_dh_set_parameter(void *dh_context, size_t generator, ++ size_t prime_length, const uint8_t *prime) ++{ ++ DH *dh; ++ BIGNUM *bn_p; ++ BIGNUM *bn_g; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (dh_context == NULL || prime == NULL || prime_length > INT_MAX) { ++ return false; ++ } ++ ++ if (generator != DH_GENERATOR_2 && generator != DH_GENERATOR_5) { ++ return false; ++ } ++ ++ ++ /* Set the generator and prime parameters for DH object.*/ ++ ++ dh = (DH *)dh_context; ++ bn_p = BN_bin2bn((const unsigned char *)prime, (int)(prime_length / 8), ++ NULL); ++ bn_g = BN_bin2bn((const unsigned char *)&generator, 1, NULL); ++ if ((bn_p == NULL) || (bn_g == NULL) || ++ !DH_set0_pqg(dh, bn_p, NULL, bn_g)) { ++ goto error; ++ } ++ ++ return true; ++ ++error: ++ BN_free(bn_p); ++ BN_free(bn_g); ++ ++ return false; ++} ++ ++/** ++ * Generates DH public key. ++ * ++ * This function generates random secret exponent, and computes the public key, which is ++ * returned via parameter public_key and public_key_size. DH context is updated accordingly. ++ * If the public_key buffer is too small to hold the public key, false is returned and ++ * public_key_size is set to the required buffer size to obtain the public key. ++ * ++ * If dh_context is NULL, then return false. ++ * If public_key_size is NULL, then return false. ++ * If public_key_size is large enough but public_key is NULL, then return false. ++ * ++ * For FFDHE2048, the public_size is 256. ++ * For FFDHE3072, the public_size is 384. ++ * For FFDHE4096, the public_size is 512. ++ * ++ * @param[in, out] dh_context Pointer to the DH context. ++ * @param[out] public_key Pointer to the buffer to receive generated public key. ++ * @param[in, out] public_key_size On input, the size of public_key buffer in bytes. ++ * On output, the size of data returned in public_key buffer in bytes. ++ * ++ * @retval true DH public key generation succeeded. ++ * @retval false DH public key generation failed. ++ * @retval false public_key_size is not large enough. ++ * ++ **/ ++bool libspdm_dh_generate_key(void *dh_context, uint8_t *public_key, ++ size_t *public_key_size) ++{ ++ bool ret_val; ++ DH *dh; ++ BIGNUM *dh_pub_key; ++ int size; ++ size_t final_pub_key_size; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (dh_context == NULL || public_key_size == NULL) { ++ return false; ++ } ++ ++ if (public_key == NULL && *public_key_size != 0) { ++ return false; ++ } ++ ++ dh = (DH *)dh_context; ++ switch (DH_size(dh)) { ++ case 256: ++ final_pub_key_size = 256; ++ break; ++ case 384: ++ final_pub_key_size = 384; ++ break; ++ case 512: ++ final_pub_key_size = 512; ++ break; ++ default: ++ return false; ++ } ++ ++ if (*public_key_size < final_pub_key_size) { ++ *public_key_size = final_pub_key_size; ++ return false; ++ } ++ *public_key_size = final_pub_key_size; ++ ++ ret_val = (bool)DH_generate_key(dh_context); ++ if (ret_val) { ++ DH_get0_key(dh, (const BIGNUM **)&dh_pub_key, NULL); ++ size = BN_num_bytes(dh_pub_key); ++ if (size <= 0) { ++ return false; ++ } ++ LIBSPDM_ASSERT((size_t)size <= final_pub_key_size); ++ ++ if (public_key != NULL) { ++ libspdm_zero_mem(public_key, *public_key_size); ++ BN_bn2bin(dh_pub_key, ++ &public_key[0 + final_pub_key_size - size]); ++ } ++ } ++ ++ return ret_val; ++} ++ ++/** ++ * Computes exchanged common key. ++ * ++ * Given peer's public key, this function computes the exchanged common key, based on its own ++ * context including value of prime modulus and random secret exponent. ++ * ++ * If dh_context is NULL, then return false. ++ * If peer_public_key is NULL, then return false. ++ * If key_size is NULL, then return false. ++ * If key is NULL, then return false. ++ * If key_size is not large enough, then return false. ++ * ++ * For FFDHE2048, the peer_public_size and key_size is 256. ++ * For FFDHE3072, the peer_public_size and key_size is 384. ++ * For FFDHE4096, the peer_public_size and key_size is 512. ++ * ++ * @param[in, out] dh_context Pointer to the DH context. ++ * @param[in] peer_public_key Pointer to the peer's public key. ++ * @param[in] peer_public_key_size size of peer's public key in bytes. ++ * @param[out] key Pointer to the buffer to receive generated key. ++ * @param[in, out] key_size On input, the size of key buffer in bytes. ++ * On output, the size of data returned in key buffer in bytes. ++ * ++ * @retval true DH exchanged key generation succeeded. ++ * @retval false DH exchanged key generation failed. ++ * @retval false key_size is not large enough. ++ * ++ **/ ++bool libspdm_dh_compute_key(void *dh_context, const uint8_t *peer_public_key, ++ size_t peer_public_key_size, uint8_t *key, ++ size_t *key_size) ++{ ++ BIGNUM *bn; ++ int size; ++ DH *dh; ++ size_t final_key_size; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (dh_context == NULL || peer_public_key == NULL || key_size == NULL || ++ key == NULL) { ++ return false; ++ } ++ ++ if (peer_public_key_size > INT_MAX) { ++ return false; ++ } ++ ++ bn = BN_bin2bn(peer_public_key, (uint32_t)peer_public_key_size, NULL); ++ if (bn == NULL) { ++ return false; ++ } ++ ++ dh = (DH *)dh_context; ++ switch (DH_size(dh)) { ++ case 256: ++ final_key_size = 256; ++ break; ++ case 384: ++ final_key_size = 384; ++ break; ++ case 512: ++ final_key_size = 512; ++ break; ++ default: ++ BN_free(bn); ++ return false; ++ } ++ if (*key_size < final_key_size) { ++ *key_size = final_key_size; ++ BN_free(bn); ++ return false; ++ } ++ ++ size = DH_compute_key_padded(key, bn, dh_context); ++ BN_free(bn); ++ if (size < 0) { ++ return false; ++ } ++ if ((size_t)size != final_key_size) { ++ return false; ++ } ++ ++ *key_size = size; ++ return true; ++} ++ ++#endif /* LIBSPDM_FFDHE_SUPPORT */ +diff --git a/os_stub/cryptlib_wolfssl/pk/ec.c b/os_stub/cryptlib_wolfssl/pk/ec.c +new file mode 100644 +index 0000000000..09df0b9a25 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/ec.c +@@ -0,0 +1,1101 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * Elliptic Curve Wrapper Implementation. ++ * ++ * RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites ++ * FIPS 186-4 - Digital signature Standard (DSS) ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++#include ++ ++/** ++ * Allocates and Initializes one Elliptic Curve context for subsequent use ++ * with the NID. ++ * ++ * @param nid cipher NID ++ * ++ * @return Pointer to the Elliptic Curve context that has been initialized. ++ * If the allocations fails, libspdm_ec_new_by_nid() returns NULL. ++ * ++ **/ ++void *libspdm_ec_new_by_nid(size_t nid) ++{ ++ EC_KEY *ec_key; ++ EC_GROUP *ec_group; ++ bool ret_val; ++ int32_t openssl_nid; ++ ++ ec_key = EC_KEY_new(); ++ if (ec_key == NULL) { ++ return NULL; ++ } ++ switch (nid) { ++ case LIBSPDM_CRYPTO_NID_SECP256R1: ++ case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P256: ++ openssl_nid = NID_X9_62_prime256v1; ++ break; ++ case LIBSPDM_CRYPTO_NID_SECP384R1: ++ case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P384: ++ openssl_nid = NID_secp384r1; ++ break; ++ case LIBSPDM_CRYPTO_NID_SECP521R1: ++ case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P521: ++ openssl_nid = NID_secp521r1; ++ break; ++ default: ++ EC_KEY_free(ec_key); ++ return NULL; ++ } ++ ++ ec_group = EC_GROUP_new_by_curve_name(openssl_nid); ++ if (ec_group == NULL) { ++ EC_KEY_free(ec_key); ++ return NULL; ++ } ++ ret_val = (bool)EC_KEY_set_group(ec_key, ec_group); ++ EC_GROUP_free(ec_group); ++ if (!ret_val) { ++ return NULL; ++ } ++ return (void *)ec_key; ++} ++ ++/** ++ * Release the specified EC context. ++ * ++ * @param[in] ec_context Pointer to the EC context to be released. ++ * ++ **/ ++void libspdm_ec_free(void *ec_context) ++{ ++ EC_KEY_free((EC_KEY *)ec_context); ++} ++ ++/** ++ * Sets the public key component into the established EC context. ++ * ++ * For P-256, the public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * For P-384, the public_size is 96. first 48-byte is X, second 48-byte is Y. ++ * For P-521, the public_size is 132. first 66-byte is X, second 66-byte is Y. ++ * ++ * @param[in, out] ec_context Pointer to EC context being set. ++ * @param[in] public Pointer to the buffer to receive generated public X,Y. ++ * @param[in] public_size The size of public buffer in bytes. ++ * ++ * @retval true EC public key component was set successfully. ++ * @retval false Invalid EC public key component. ++ * ++ **/ ++bool libspdm_ec_set_pub_key(void *ec_context, const uint8_t *public_key, ++ size_t public_key_size) ++{ ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ EC_POINT *ec_point; ++ int32_t openssl_nid; ++ size_t half_size; ++ ++ if (ec_context == NULL || public_key == NULL) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (public_key_size != half_size * 2) { ++ return false; ++ } ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = NULL; ++ ++ bn_x = BN_bin2bn(public_key, (uint32_t)half_size, NULL); ++ bn_y = BN_bin2bn(public_key + half_size, (uint32_t)half_size, NULL); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ec_point = EC_POINT_new(ec_group); ++ if (ec_point == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_set_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ ret_val = (bool)EC_KEY_set_public_key(ec_key, ec_point); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ if (ec_point != NULL) { ++ EC_POINT_free(ec_point); ++ } ++ return ret_val; ++} ++ ++/** ++ * Sets the private key component into the established EC context. ++ * ++ * For P-256, the private_key_size is 32 byte. ++ * For P-384, the private_key_size is 48 byte. ++ * For P-521, the private_key_size is 66 byte. ++ * ++ * @param[in, out] ec_context Pointer to EC context being set. ++ * @param[in] private_key Pointer to the private key buffer. ++ * @param[in] private_key_size The size of private key buffer in bytes. ++ * ++ * @retval true EC private key component was set successfully. ++ * @retval false Invalid EC private key component. ++ * ++ **/ ++bool libspdm_ec_set_priv_key(void *ec_context, const uint8_t *private_key, ++ size_t private_key_size) ++{ ++ EC_KEY *ec_key; ++ bool ret_val; ++ BIGNUM * priv_key; ++ int32_t openssl_nid; ++ size_t half_size; ++ ++ if (ec_context == NULL || private_key == NULL) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (private_key_size != half_size) { ++ return false; ++ } ++ ++ priv_key = BN_bin2bn(private_key, private_key_size, NULL); ++ if (priv_key == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ret_val = (bool)EC_KEY_set_private_key(ec_key, priv_key); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ ret_val = true; ++ ++done: ++ if (priv_key != NULL) { ++ BN_free(priv_key); ++ } ++ return ret_val; ++} ++ ++/** ++ * Gets the public key component from the established EC context. ++ * ++ * For P-256, the public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * For P-384, the public_size is 96. first 48-byte is X, second 48-byte is Y. ++ * For P-521, the public_size is 132. first 66-byte is X, second 66-byte is Y. ++ * ++ * @param[in, out] ec_context Pointer to EC context being set. ++ * @param[out] public Pointer to the buffer to receive generated public X,Y. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true EC key component was retrieved successfully. ++ * @retval false Invalid EC key component. ++ * ++ **/ ++bool libspdm_ec_get_pub_key(void *ec_context, uint8_t *public_key, ++ size_t *public_key_size) ++{ ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ const EC_POINT *ec_point; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ int32_t openssl_nid; ++ size_t half_size; ++ int x_size; ++ int y_size; ++ ++ if (ec_context == NULL || public_key_size == NULL) { ++ return false; ++ } ++ ++ if (public_key == NULL && *public_key_size != 0) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (*public_key_size < half_size * 2) { ++ *public_key_size = half_size * 2; ++ return false; ++ } ++ *public_key_size = half_size * 2; ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = EC_KEY_get0_public_key(ec_key); ++ if (ec_point == NULL) { ++ return false; ++ } ++ ++ bn_x = BN_new(); ++ bn_y = BN_new(); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_get_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ x_size = BN_num_bytes(bn_x); ++ y_size = BN_num_bytes(bn_y); ++ if (x_size <= 0 || y_size <= 0) { ++ ret_val = false; ++ goto done; ++ } ++ LIBSPDM_ASSERT((size_t)x_size <= half_size && (size_t)y_size <= half_size); ++ ++ if (public_key != NULL) { ++ libspdm_zero_mem(public_key, *public_key_size); ++ BN_bn2bin(bn_x, &public_key[0 + half_size - x_size]); ++ BN_bn2bin(bn_y, &public_key[half_size + half_size - y_size]); ++ } ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ return ret_val; ++} ++ ++/** ++ * Validates key components of EC context. ++ * NOTE: This function performs integrity checks on all the EC key material, so ++ * the EC key structure must contain all the private key data. ++ * ++ * If ec_context is NULL, then return false. ++ * ++ * @param[in] ec_context Pointer to EC context to check. ++ * ++ * @retval true EC key components are valid. ++ * @retval false EC key components are not valid. ++ * ++ **/ ++bool libspdm_ec_check_key(const void *ec_context) ++{ ++ EC_KEY *ec_key; ++ bool ret_val; ++ ++ if (ec_context == NULL) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ ++ ret_val = (bool)EC_KEY_check_key(ec_key); ++ if (!ret_val) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Generates EC key and returns EC public key (X, Y). ++ * ++ * This function generates random secret, and computes the public key (X, Y), which is ++ * returned via parameter public, public_size. ++ * X is the first half of public with size being public_size / 2, ++ * Y is the second half of public with size being public_size / 2. ++ * EC context is updated accordingly. ++ * If the public buffer is too small to hold the public X, Y, false is returned and ++ * public_size is set to the required buffer size to obtain the public X, Y. ++ * ++ * For P-256, the public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * For P-384, the public_size is 96. first 48-byte is X, second 48-byte is Y. ++ * For P-521, the public_size is 132. first 66-byte is X, second 66-byte is Y. ++ * ++ * If ec_context is NULL, then return false. ++ * If public_size is NULL, then return false. ++ * If public_size is large enough but public is NULL, then return false. ++ * ++ * @param[in, out] ec_context Pointer to the EC context. ++ * @param[out] public_data Pointer to the buffer to receive generated public X,Y. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true EC public X,Y generation succeeded. ++ * @retval false EC public X,Y generation failed. ++ * @retval false public_size is not large enough. ++ * ++ **/ ++bool libspdm_ec_generate_key(void *ec_context, uint8_t *public_data, ++ size_t *public_size) ++{ ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ const EC_POINT *ec_point; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ int32_t openssl_nid; ++ size_t half_size; ++ int x_size; ++ int y_size; ++ ++ if (ec_context == NULL || public_size == NULL) { ++ return false; ++ } ++ ++ if (public_data == NULL && *public_size != 0) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ ret_val = (bool)EC_KEY_generate_key(ec_key); ++ if (!ret_val) { ++ return false; ++ } ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (*public_size < half_size * 2) { ++ *public_size = half_size * 2; ++ return false; ++ } ++ *public_size = half_size * 2; ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = EC_KEY_get0_public_key(ec_key); ++ if (ec_point == NULL) { ++ return false; ++ } ++ ++ bn_x = BN_new(); ++ bn_y = BN_new(); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_get_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ x_size = BN_num_bytes(bn_x); ++ y_size = BN_num_bytes(bn_y); ++ if (x_size <= 0 || y_size <= 0) { ++ ret_val = false; ++ goto done; ++ } ++ LIBSPDM_ASSERT((size_t)x_size <= half_size && (size_t)y_size <= half_size); ++ ++ if (public_data != NULL) { ++ libspdm_zero_mem(public_data, *public_size); ++ BN_bn2bin(bn_x, &public_data[0 + half_size - x_size]); ++ BN_bn2bin(bn_y, &public_data[half_size + half_size - y_size]); ++ } ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ return ret_val; ++} ++ ++/** ++ * Computes exchanged common key. ++ * ++ * Given peer's public key (X, Y), this function computes the exchanged common key, ++ * based on its own context including value of curve parameter and random secret. ++ * X is the first half of peer_public with size being peer_public_size / 2, ++ * Y is the second half of peer_public with size being peer_public_size / 2. ++ * ++ * If ec_context is NULL, then return false. ++ * If peer_public is NULL, then return false. ++ * If peer_public_size is 0, then return false. ++ * If key is NULL, then return false. ++ * If key_size is not large enough, then return false. ++ * ++ * For P-256, the peer_public_size is 64. first 32-byte is X, second 32-byte is Y. The key_size is 32. ++ * For P-384, the peer_public_size is 96. first 48-byte is X, second 48-byte is Y. The key_size is 48. ++ * For P-521, the peer_public_size is 132. first 66-byte is X, second 66-byte is Y. The key_size is 66. ++ * ++ * @param[in, out] ec_context Pointer to the EC context. ++ * @param[in] peer_public Pointer to the peer's public X,Y. ++ * @param[in] peer_public_size size of peer's public X,Y in bytes. ++ * @param[out] key Pointer to the buffer to receive generated key. ++ * @param[in, out] key_size On input, the size of key buffer in bytes. ++ * On output, the size of data returned in key buffer in bytes. ++ * ++ * @retval true EC exchanged key generation succeeded. ++ * @retval false EC exchanged key generation failed. ++ * @retval false key_size is not large enough. ++ * ++ **/ ++bool libspdm_ec_compute_key(void *ec_context, const uint8_t *peer_public, ++ size_t peer_public_size, uint8_t *key, ++ size_t *key_size) ++{ ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ EC_POINT *ec_point; ++ int32_t openssl_nid; ++ size_t half_size; ++ int size; ++ ++ if (ec_context == NULL || peer_public == NULL || key_size == NULL || ++ key == NULL) { ++ return false; ++ } ++ ++ if (peer_public_size > INT_MAX) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (peer_public_size != half_size * 2) { ++ return false; ++ } ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = NULL; ++ ++ bn_x = BN_bin2bn(peer_public, (uint32_t)half_size, NULL); ++ bn_y = BN_bin2bn(peer_public + half_size, (uint32_t)half_size, NULL); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ec_point = EC_POINT_new(ec_group); ++ if (ec_point == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_set_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ size = ECDH_compute_key(key, *key_size, ec_point, ec_key, NULL); ++ if (size < 0) { ++ ret_val = false; ++ goto done; ++ } ++ ++ if (*key_size < (size_t)size) { ++ *key_size = size; ++ ret_val = false; ++ goto done; ++ } ++ ++ *key_size = size; ++ ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ if (ec_point != NULL) { ++ EC_POINT_free(ec_point); ++ } ++ return ret_val; ++} ++ ++/** ++ * Carries out the EC-DSA signature. ++ * ++ * This function carries out the EC-DSA signature. ++ * If the signature buffer is too small to hold the contents of signature, false ++ * is returned and sig_size is set to the required buffer size to obtain the signature. ++ * ++ * If ec_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If hash_size need match the hash_nid. hash_nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * If sig_size is large enough but signature is NULL, then return false. ++ * ++ * For P-256, the sig_size is 64. first 32-byte is R, second 32-byte is S. ++ * For P-384, the sig_size is 96. first 48-byte is R, second 48-byte is S. ++ * For P-521, the sig_size is 132. first 66-byte is R, second 66-byte is S. ++ * ++ * @param[in] ec_context Pointer to EC context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be signed. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[out] signature Pointer to buffer to receive EC-DSA signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * ++ * @retval true signature successfully generated in EC-DSA. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ * ++ **/ ++bool libspdm_ecdsa_sign(void *ec_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ uint8_t *signature, size_t *sig_size) ++{ ++ EC_KEY *ec_key; ++ ECDSA_SIG *ecdsa_sig; ++ int32_t openssl_nid; ++ uint8_t half_size; ++ BIGNUM *bn_r; ++ BIGNUM *bn_s; ++ int r_size; ++ int s_size; ++ ++ if (ec_context == NULL || message_hash == NULL) { ++ return false; ++ } ++ ++ if (signature == NULL) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (*sig_size < (size_t)(half_size * 2)) { ++ *sig_size = half_size * 2; ++ return false; ++ } ++ *sig_size = half_size * 2; ++ libspdm_zero_mem(signature, *sig_size); ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ ecdsa_sig = ECDSA_do_sign(message_hash, (uint32_t)hash_size, ++ (EC_KEY *)ec_context); ++ if (ecdsa_sig == NULL) { ++ return false; ++ } ++ ++ ECDSA_SIG_get0(ecdsa_sig, (const BIGNUM **)&bn_r, ++ (const BIGNUM **)&bn_s); ++ ++ r_size = BN_num_bytes(bn_r); ++ s_size = BN_num_bytes(bn_s); ++ if (r_size <= 0 || s_size <= 0) { ++ ECDSA_SIG_free(ecdsa_sig); ++ return false; ++ } ++ LIBSPDM_ASSERT((size_t)r_size <= half_size && (size_t)s_size <= half_size); ++ ++ BN_bn2bin(bn_r, &signature[0 + half_size - r_size]); ++ BN_bn2bin(bn_s, &signature[half_size + half_size - s_size]); ++ ++ ECDSA_SIG_free(ecdsa_sig); ++ ++ return true; ++} ++ ++/** ++ * Verifies the EC-DSA signature. ++ * ++ * If ec_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If signature is NULL, then return false. ++ * If hash_size need match the hash_nid. hash_nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * ++ * For P-256, the sig_size is 64. first 32-byte is R, second 32-byte is S. ++ * For P-384, the sig_size is 96. first 48-byte is R, second 48-byte is S. ++ * For P-521, the sig_size is 132. first 66-byte is R, second 66-byte is S. ++ * ++ * @param[in] ec_context Pointer to EC context for signature verification. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be checked. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[in] signature Pointer to EC-DSA signature to be verified. ++ * @param[in] sig_size size of signature in bytes. ++ * ++ * @retval true Valid signature encoded in EC-DSA. ++ * @retval false Invalid signature or invalid EC context. ++ * ++ **/ ++bool libspdm_ecdsa_verify(void *ec_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ const uint8_t *signature, size_t sig_size) ++{ ++ int32_t result; ++ EC_KEY *ec_key; ++ ECDSA_SIG *ecdsa_sig; ++ int32_t openssl_nid; ++ uint8_t half_size; ++ BIGNUM *bn_r; ++ BIGNUM *bn_s; ++ ++ if (ec_context == NULL || message_hash == NULL || signature == NULL) { ++ return false; ++ } ++ ++ if (sig_size > INT_MAX || sig_size == 0) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (sig_size != (size_t)(half_size * 2)) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ ecdsa_sig = ECDSA_SIG_new(); ++ if (ecdsa_sig == NULL) { ++ ECDSA_SIG_free(ecdsa_sig); ++ return false; ++ } ++ ++ bn_r = BN_bin2bn(signature, (uint32_t)half_size, NULL); ++ bn_s = BN_bin2bn(signature + half_size, (uint32_t)half_size, NULL); ++ if (bn_r == NULL || bn_s == NULL) { ++ if (bn_r != NULL) { ++ BN_free(bn_r); ++ } ++ if (bn_s != NULL) { ++ BN_free(bn_s); ++ } ++ ECDSA_SIG_free(ecdsa_sig); ++ return false; ++ } ++ ECDSA_SIG_set0(ecdsa_sig, bn_r, bn_s); ++ ++ result = ECDSA_do_verify(message_hash, (uint32_t)hash_size, ecdsa_sig, ++ (EC_KEY *)ec_context); ++ ++ ECDSA_SIG_free(ecdsa_sig); ++ ++ return (result == 1); ++} ++ ++#if LIBSPDM_FIPS_MODE ++/*setup random number*/ ++static int libspdm_ecdsa_sign_setup_random(EC_KEY *eckey, BIGNUM **kinvp, BIGNUM **rp, ++ uint8_t* random, size_t random_len) ++{ ++ BN_CTX *ctx = NULL; ++ BIGNUM *k = NULL, *r = NULL, *X = NULL, *e = NULL; ++ const BIGNUM *order; ++ EC_POINT *tmp_point = NULL; ++ const EC_GROUP *group; ++ int ret = 0; ++ int order_bits; ++ const BIGNUM *priv_key; ++ ++ ++ if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { ++ return 0; ++ } ++ if ((priv_key = EC_KEY_get0_private_key(eckey)) == NULL) { ++ return 0; ++ } ++ ++ if (!EC_KEY_can_sign(eckey)) { ++ return 0; ++ } ++ ++ ctx = BN_CTX_new(); ++ if (ctx == NULL) { ++ return 0; ++ } ++ ++ /* this value is later returned in *kinvp */ ++ k = BN_new(); ++ /* this value is later returned in *rp */ ++ r = BN_new(); ++ X = BN_new(); ++ ++ if (k == NULL || r == NULL || X == NULL) { ++ return 0; ++ } ++ if ((tmp_point = EC_POINT_new(group)) == NULL) { ++ return 0; ++ } ++ order = EC_GROUP_get0_order(group); ++ ++ /* Preallocate space */ ++ order_bits = BN_num_bits(order); ++ if (!BN_set_bit(k, order_bits) ++ || !BN_set_bit(r, order_bits) ++ || !BN_set_bit(X, order_bits)) { ++ goto err; ++ } ++ ++ e = BN_CTX_get(ctx); ++ if (e == NULL) { ++ return 0; ++ } ++ ++ /*random number*/ ++ k = BN_bin2bn(random, random_len, NULL); ++ ++ /* compute r the x-coordinate of generator * k */ ++ if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { ++ goto err; ++ } ++ if (!EC_POINT_get_affine_coordinates(group, tmp_point, X, NULL, ctx)) { ++ goto err; ++ } ++ if (!BN_nnmod(r, X, order, ctx)) { ++ goto err; ++ } ++ ++ /* ++ * compute the inverse of k ++ * Based on ossl_ec_group_do_inverse_ord() from OpenSSL ++ */ ++ BN_CTX_start(ctx); ++ if (!BN_set_word(e, 2)) { ++ BN_CTX_end(ctx); ++ goto err; ++ } ++ if (!BN_sub(e, order, e)) { ++ BN_CTX_end(ctx); ++ goto err; ++ } ++ if (!BN_mod_exp_mont(k, k, e, order, ctx, EC_GROUP_get_mont_data(group))) { ++ BN_CTX_end(ctx); ++ goto err; ++ } ++ BN_CTX_end(ctx); ++ ++ /* clear old values if necessary */ ++ BN_clear_free(*rp); ++ BN_clear_free(*kinvp); ++ /* save the pre-computed values */ ++ *rp = r; ++ *kinvp = k; ++ ret = 1; ++ ++err: ++ if (!ret) { ++ BN_clear_free(k); ++ BN_clear_free(r); ++ } ++ ++ BN_CTX_free(ctx); ++ EC_POINT_free(tmp_point); ++ BN_clear_free(X); ++ return ret; ++} ++ ++/** ++ * Carries out the EC-DSA signature with caller input random function. This API can be used for FIPS test. ++ * ++ * @param[in] ec_context Pointer to EC context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be signed. ++ * @param[in] hash_size Size of the message hash in bytes. ++ * @param[out] signature Pointer to buffer to receive EC-DSA signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * @param[in] random_func random number function ++ * ++ * @retval true signature successfully generated in EC-DSA. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ **/ ++bool libspdm_ecdsa_sign_ex(void *ec_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ uint8_t *signature, size_t *sig_size, ++ int (*random_func)(void *, unsigned char *, size_t)) ++{ ++ EC_KEY *ec_key; ++ ECDSA_SIG *ecdsa_sig; ++ int32_t openssl_nid; ++ uint8_t half_size; ++ BIGNUM *bn_r; ++ BIGNUM *bn_s; ++ int r_size; ++ int s_size; ++ /*random number*/ ++ uint8_t random[32]; ++ bool result; ++ ++ result = true; ++ ++ BIGNUM *kinv = NULL; ++ BIGNUM *rp = NULL; ++ ++ kinv = NULL; ++ rp = NULL; ++ ++ if (ec_context == NULL || message_hash == NULL) { ++ return false; ++ } ++ ++ if (signature == NULL) { ++ return false; ++ } ++ ++ ec_key = (EC_KEY *)ec_context; ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_X9_62_prime256v1: ++ half_size = 32; ++ break; ++ case NID_secp384r1: ++ half_size = 48; ++ break; ++ case NID_secp521r1: ++ half_size = 66; ++ break; ++ default: ++ return false; ++ } ++ if (*sig_size < (size_t)(half_size * 2)) { ++ *sig_size = half_size * 2; ++ return false; ++ } ++ *sig_size = half_size * 2; ++ libspdm_zero_mem(signature, *sig_size); ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ /*retrieve random number for ecdsa sign*/ ++ if (random_func(NULL, random, sizeof(random)) != 0) { ++ result = false; ++ goto cleanup; ++ } ++ if (!libspdm_ecdsa_sign_setup_random(ec_key, &kinv, &rp, random, sizeof(random))) { ++ result = false; ++ goto cleanup; ++ } ++ ++ ecdsa_sig = ECDSA_do_sign_ex(message_hash, (uint32_t)hash_size, kinv, rp, ++ (EC_KEY *)ec_context); ++ if (ecdsa_sig == NULL) { ++ result = false; ++ goto cleanup; ++ } ++ ++ ECDSA_SIG_get0(ecdsa_sig, (const BIGNUM **)&bn_r, ++ (const BIGNUM **)&bn_s); ++ ++ r_size = BN_num_bytes(bn_r); ++ s_size = BN_num_bytes(bn_s); ++ if (r_size <= 0 || s_size <= 0) { ++ ECDSA_SIG_free(ecdsa_sig); ++ result = false; ++ goto cleanup; ++ } ++ LIBSPDM_ASSERT((size_t)r_size <= half_size && (size_t)s_size <= half_size); ++ ++ BN_bn2bin(bn_r, &signature[0 + half_size - r_size]); ++ BN_bn2bin(bn_s, &signature[half_size + half_size - s_size]); ++ ++ ECDSA_SIG_free(ecdsa_sig); ++ ++cleanup: ++ if (kinv != NULL) { ++ BN_clear_free(kinv); ++ } ++ if (rp != NULL) { ++ BN_clear_free(rp); ++ } ++ ++ libspdm_zero_mem(random, sizeof(random)); ++ return result; ++} ++ ++#endif/*LIBSPDM_FIPS_MODE*/ +diff --git a/os_stub/cryptlib_wolfssl/pk/ecd.c b/os_stub/cryptlib_wolfssl/pk/ecd.c +new file mode 100644 +index 0000000000..23dbd0390b +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/ecd.c +@@ -0,0 +1,477 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * Edwards-Curve Wrapper Implementation. ++ * ++ * RFC 8032 - Edwards-Curve Digital signature algorithm (EdDSA) ++ * FIPS 186-4 - Digital signature Standard (DSS) ++ **/ ++ ++#include "internal_crypt_lib.h" ++ ++#if (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT) ++ ++#include ++#include ++ ++/** ++ * Allocates and Initializes one Edwards-Curve context for subsequent use ++ * with the NID. ++ * ++ * The key is generated before the function returns. ++ * ++ * @param nid cipher NID ++ * ++ * @return Pointer to the Edwards-Curve context that has been initialized. ++ * If the allocations fails, libspdm_ecd_new_by_nid() returns NULL. ++ * ++ **/ ++void *libspdm_ecd_new_by_nid(size_t nid) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ EVP_PKEY *pkey; ++ int32_t result; ++ int32_t openssl_pkey_type; ++ ++ switch (nid) { ++ case LIBSPDM_CRYPTO_NID_EDDSA_ED25519: ++ openssl_pkey_type = EVP_PKEY_ED25519; ++ break; ++ case LIBSPDM_CRYPTO_NID_EDDSA_ED448: ++ openssl_pkey_type = EVP_PKEY_ED448; ++ break; ++ default: ++ return NULL; ++ } ++ ++ pkey_ctx = EVP_PKEY_CTX_new_id(openssl_pkey_type, NULL); ++ if (pkey_ctx == NULL) { ++ return NULL; ++ } ++ result = EVP_PKEY_keygen_init(pkey_ctx); ++ if (result <= 0) { ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return NULL; ++ } ++ pkey = NULL; ++ result = EVP_PKEY_keygen(pkey_ctx, &pkey); ++ if (result <= 0) { ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return NULL; ++ } ++ EVP_PKEY_CTX_free(pkey_ctx); ++ ++ return (void *)pkey; ++} ++ ++/** ++ * Release the specified Ed context. ++ * ++ * @param[in] ecd_context Pointer to the Ed context to be released. ++ * ++ **/ ++void libspdm_ecd_free(void *ecd_context) ++{ ++ EVP_PKEY_free((EVP_PKEY *)ecd_context); ++} ++ ++/** ++ * Sets the public key component into the established Ed context. ++ * ++ * For ed25519, the public_size is 32. ++ * For ed448, the public_size is 57. ++ * ++ * @param[in, out] ecd_context Pointer to Ed context being set. ++ * @param[in] public Pointer to the buffer to receive generated public X,Y. ++ * @param[in] public_size The size of public buffer in bytes. ++ * ++ * @retval true Ed public key component was set successfully. ++ * @retval false Invalid EC public key component. ++ * ++ **/ ++bool libspdm_ecd_set_pub_key(void *ecd_context, const uint8_t *public_key, ++ size_t public_key_size) ++{ ++ uint32_t final_pub_key_size; ++ EVP_PKEY *evp_key; ++ EVP_PKEY *new_evp_key; ++ ++ if ((ecd_context == NULL) || (public_key == NULL)) { ++ return false; ++ } ++ ++ evp_key = (EVP_PKEY *)ecd_context; ++ ++ switch (EVP_PKEY_id(evp_key)) { ++ case EVP_PKEY_ED25519: ++ final_pub_key_size = 32; ++ break; ++ case EVP_PKEY_ED448: ++ final_pub_key_size = 57; ++ break; ++ default: ++ return false; ++ } ++ ++ if (final_pub_key_size != public_key_size) { ++ return false; ++ } ++ ++ new_evp_key = EVP_PKEY_new_raw_public_key(EVP_PKEY_id(evp_key), NULL, ++ public_key, public_key_size); ++ ++ if (new_evp_key == NULL) { ++ return false; ++ } ++ ++ if (evp_pkey_copy_downgraded(&evp_key, new_evp_key) != 1) { ++ EVP_PKEY_free(new_evp_key); ++ return false; ++ } ++ ++ EVP_PKEY_free(new_evp_key); ++ return true; ++} ++ ++/** ++ * Sets the private key component into the established Ed context. ++ * ++ * For ed25519, the private_size is 32. ++ * For ed448, the private_size is 57. ++ * ++ * @param[in, out] ecd_context Pointer to Ed context being set. ++ * @param[in] private Pointer to the buffer to receive generated private X,Y. ++ * @param[in] private_size The size of private buffer in bytes. ++ * ++ * @retval true Ed private key component was set successfully. ++ * @retval false Invalid EC private key component. ++ * ++ **/ ++bool libspdm_ecd_set_pri_key(void *ecd_context, const uint8_t *private_key, ++ size_t private_key_size) ++{ ++ uint32_t final_pri_key_size; ++ EVP_PKEY *evp_key; ++ EVP_PKEY *new_evp_key; ++ ++ if ((ecd_context == NULL) || (private_key == NULL)) { ++ return false; ++ } ++ ++ evp_key = (EVP_PKEY *)ecd_context; ++ ++ switch (EVP_PKEY_id(evp_key)) { ++ case EVP_PKEY_ED25519: ++ final_pri_key_size = 32; ++ break; ++ case EVP_PKEY_ED448: ++ final_pri_key_size = 57; ++ break; ++ default: ++ return false; ++ } ++ ++ if (final_pri_key_size != private_key_size) { ++ return false; ++ } ++ ++ new_evp_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_id(evp_key), NULL, ++ private_key, private_key_size); ++ if (new_evp_key == NULL) { ++ return false; ++ } ++ ++ if (evp_pkey_copy_downgraded(&evp_key, new_evp_key) != 1) { ++ EVP_PKEY_free(new_evp_key); ++ return false; ++ } ++ ++ EVP_PKEY_free(new_evp_key); ++ return true; ++} ++ ++/** ++ * Gets the public key component from the established Ed context. ++ * ++ * For ed25519, the public_size is 32. ++ * For ed448, the public_size is 57. ++ * ++ * @param[in, out] ecd_context Pointer to Ed context being set. ++ * @param[out] public Pointer to the buffer to receive generated public X,Y. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true Ed key component was retrieved successfully. ++ * @retval false Invalid EC public key component. ++ * ++ **/ ++bool libspdm_ecd_get_pub_key(void *ecd_context, uint8_t *public_key, ++ size_t *public_key_size) ++{ ++ EVP_PKEY *pkey; ++ int32_t result; ++ uint32_t final_pub_key_size; ++ ++ if (ecd_context == NULL || public_key == NULL || ++ public_key_size == NULL) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)ecd_context; ++ switch (EVP_PKEY_id(pkey)) { ++ case EVP_PKEY_ED25519: ++ final_pub_key_size = 32; ++ break; ++ case EVP_PKEY_ED448: ++ final_pub_key_size = 57; ++ break; ++ default: ++ return false; ++ } ++ if (*public_key_size < final_pub_key_size) { ++ *public_key_size = final_pub_key_size; ++ return false; ++ } ++ *public_key_size = final_pub_key_size; ++ libspdm_zero_mem(public_key, *public_key_size); ++ result = EVP_PKEY_get_raw_public_key(pkey, public_key, public_key_size); ++ if (result == 0) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Validates key components of Ed context. ++ * NOTE: This function performs integrity checks on all the Ed key material, so ++ * the Ed key structure must contain all the private key data. ++ * ++ * If ecd_context is NULL, then return false. ++ * ++ * @param[in] ecd_context Pointer to Ed context to check. ++ * ++ * @retval true Ed key components are valid. ++ * @retval false Ed key components are not valid. ++ * ++ **/ ++bool libspdm_ecd_check_key(const void *ecd_context) ++{ ++ /* TBD*/ ++ return false; ++} ++ ++/** ++ * Generates Ed key and returns Ed public key. ++ * ++ * For ed25519, the public_size is 32. ++ * For ed448, the public_size is 57. ++ * ++ * If ecd_context is NULL, then return false. ++ * If public_size is NULL, then return false. ++ * If public_size is large enough but public is NULL, then return false. ++ * ++ * @param[in, out] ecd_context Pointer to the Ed context. ++ * @param[out] public Pointer to the buffer to receive generated public key. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true Ed public key generation succeeded. ++ * @retval false Ed public key generation failed. ++ * @retval false public_size is not large enough. ++ * ++ **/ ++bool libspdm_ecd_generate_key(void *ecd_context, uint8_t *public_key, ++ size_t *public_key_size) ++{ ++ /* TBD*/ ++ return true; ++} ++ ++/** ++ * Carries out the Ed-DSA signature. ++ * ++ * This function carries out the Ed-DSA signature. ++ * If the signature buffer is too small to hold the contents of signature, false ++ * is returned and sig_size is set to the required buffer size to obtain the signature. ++ * ++ * If ecd_context is NULL, then return false. ++ * If message is NULL, then return false. ++ * hash_nid must be NULL. ++ * If sig_size is large enough but signature is NULL, then return false. ++ * ++ * For ed25519, context must be NULL and context_size must be 0. ++ * For ed448, context must be maximum of 255 octets. ++ * ++ * For ed25519, the sig_size is 64. first 32-byte is R, second 32-byte is S. ++ * For ed448, the sig_size is 114. first 57-byte is R, second 57-byte is S. ++ * ++ * @param[in] ecd_context Pointer to Ed context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] context the EDDSA signing context. ++ * @param[in] context_size size of EDDSA signing context. ++ * @param[in] message Pointer to octet message to be signed (before hash). ++ * @param[in] size size of the message in bytes. ++ * @param[out] signature Pointer to buffer to receive Ed-DSA signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * ++ * @retval true signature successfully generated in Ed-DSA. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ * ++ **/ ++bool libspdm_eddsa_sign(const void *ecd_context, size_t hash_nid, ++ const uint8_t *context, size_t context_size, ++ const uint8_t *message, size_t size, uint8_t *signature, ++ size_t *sig_size) ++{ ++ EVP_PKEY *pkey; ++ EVP_MD_CTX *ctx; ++ size_t half_size; ++ int32_t result; ++ ++ if (ecd_context == NULL || message == NULL) { ++ return false; ++ } ++ ++ if (signature == NULL || sig_size == NULL) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)ecd_context; ++ switch (EVP_PKEY_id(pkey)) { ++ case EVP_PKEY_ED25519: ++ half_size = 32; ++ break; ++ case EVP_PKEY_ED448: ++ half_size = 57; ++ break; ++ default: ++ return false; ++ } ++ if (*sig_size < (size_t)(half_size * 2)) { ++ *sig_size = half_size * 2; ++ return false; ++ } ++ *sig_size = half_size * 2; ++ libspdm_zero_mem(signature, *sig_size); ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_NULL: ++ break; ++ ++ default: ++ return false; ++ } ++ ++ ctx = EVP_MD_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ result = EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ return false; ++ } ++ result = EVP_DigestSign(ctx, signature, sig_size, message, size); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ return false; ++ } ++ ++ EVP_MD_CTX_free(ctx); ++ return true; ++} ++ ++/** ++ * Verifies the Ed-DSA signature. ++ * ++ * If ecd_context is NULL, then return false. ++ * If message is NULL, then return false. ++ * If signature is NULL, then return false. ++ * hash_nid must be NULL. ++ * ++ * For ed25519, context must be NULL and context_size must be 0. ++ * For ed448, context must be maximum of 255 octets. ++ * ++ * For ed25519, the sig_size is 64. first 32-byte is R, second 32-byte is S. ++ * For ed448, the sig_size is 114. first 57-byte is R, second 57-byte is S. ++ * ++ * @param[in] ecd_context Pointer to Ed context for signature verification. ++ * @param[in] hash_nid hash NID ++ * @param[in] context the EDDSA signing context. ++ * @param[in] context_size size of EDDSA signing context. ++ * @param[in] message Pointer to octet message to be checked (before hash). ++ * @param[in] size size of the message in bytes. ++ * @param[in] signature Pointer to Ed-DSA signature to be verified. ++ * @param[in] sig_size size of signature in bytes. ++ * ++ * @retval true Valid signature encoded in Ed-DSA. ++ * @retval false Invalid signature or invalid Ed context. ++ * ++ **/ ++bool libspdm_eddsa_verify(const void *ecd_context, size_t hash_nid, ++ const uint8_t *context, size_t context_size, ++ const uint8_t *message, size_t size, ++ const uint8_t *signature, size_t sig_size) ++{ ++ EVP_PKEY *pkey; ++ EVP_MD_CTX *ctx; ++ size_t half_size; ++ int32_t result; ++ ++ if (ecd_context == NULL || message == NULL || signature == NULL) { ++ return false; ++ } ++ ++ if (sig_size > INT_MAX || sig_size == 0) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)ecd_context; ++ switch (EVP_PKEY_id(pkey)) { ++ case EVP_PKEY_ED25519: ++ half_size = 32; ++ break; ++ case EVP_PKEY_ED448: ++ half_size = 57; ++ break; ++ default: ++ return false; ++ } ++ if (sig_size != (size_t)(half_size * 2)) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_NULL: ++ break; ++ ++ default: ++ return false; ++ } ++ ++ ctx = EVP_MD_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ result = EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ return false; ++ } ++ result = EVP_DigestVerify(ctx, signature, sig_size, message, size); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ return false; ++ } ++ ++ EVP_MD_CTX_free(ctx); ++ return true; ++} ++#endif /* (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT) */ +diff --git a/os_stub/cryptlib_wolfssl/pk/rsa_basic.c b/os_stub/cryptlib_wolfssl/pk/rsa_basic.c +new file mode 100644 +index 0000000000..7969ba6bdd +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/rsa_basic.c +@@ -0,0 +1,588 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * RSA Asymmetric Cipher Wrapper Implementation. ++ * ++ * This file implements following APIs which provide basic capabilities for RSA: ++ * 1) libspdm_rsa_new ++ * 2) libspdm_rsa_free ++ * 3) libspdm_rsa_set_key ++ * 4) rsa_pkcs1_verify ++ * ++ * RFC 8017 - PKCS #1: RSA Cryptography Specifications version 2.2 ++ **/ ++ ++#include "internal_crypt_lib.h" ++ ++#include ++#include ++#include ++#include ++ ++#if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) ++/** ++ * Allocates and initializes one RSA context for subsequent use. ++ * ++ * @return Pointer to the RSA context that has been initialized. ++ * If the allocations fails, libspdm_rsa_new() returns NULL. ++ * ++ **/ ++void *libspdm_rsa_new(void) ++{ ++ ++ /* Allocates & Initializes RSA context by OpenSSL RSA_new()*/ ++ ++ return (void *)RSA_new(); ++} ++ ++/** ++ * Release the specified RSA context. ++ * ++ * @param[in] rsa_context Pointer to the RSA context to be released. ++ * ++ **/ ++void libspdm_rsa_free(void *rsa_context) ++{ ++ ++ /* Free OpenSSL RSA context*/ ++ ++ RSA_free((RSA *)rsa_context); ++} ++ ++/** ++ * Sets the tag-designated key component into the established RSA context. ++ * ++ * This function sets the tag-designated RSA key component into the established ++ * RSA context from the user-specified non-negative integer (octet string format ++ * represented in RSA PKCS#1). ++ * If big_number is NULL, then the specified key component in RSA context is cleared. ++ * ++ * If rsa_context is NULL, then return false. ++ * ++ * @param[in, out] rsa_context Pointer to RSA context being set. ++ * @param[in] key_tag tag of RSA key component being set. ++ * @param[in] big_number Pointer to octet integer buffer. ++ * If NULL, then the specified key component in RSA ++ * context is cleared. ++ * @param[in] bn_size size of big number buffer in bytes. ++ * If big_number is NULL, then it is ignored. ++ * ++ * @retval true RSA key component was set successfully. ++ * @retval false Invalid RSA key component tag. ++ * ++ **/ ++bool libspdm_rsa_set_key(void *rsa_context, const libspdm_rsa_key_tag_t key_tag, ++ const uint8_t *big_number, size_t bn_size) ++{ ++ RSA *rsa_key; ++ bool status; ++ BIGNUM *bn_n, *bn_n_tmp; ++ BIGNUM *bn_e, *bn_e_tmp; ++ BIGNUM *bn_d, *bn_d_tmp; ++ BIGNUM *bn_p, *bn_p_tmp; ++ BIGNUM *bn_q, *bn_q_tmp; ++ BIGNUM *bn_dp, *bn_dp_tmp; ++ BIGNUM *bn_dq, *bn_dq_tmp; ++ BIGNUM *bn_q_inv, *bn_q_inv_tmp; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (rsa_context == NULL || bn_size > INT_MAX) { ++ return false; ++ } ++ ++ bn_n = NULL; ++ bn_e = NULL; ++ bn_d = NULL; ++ bn_p = NULL; ++ bn_q = NULL; ++ bn_dp = NULL; ++ bn_dq = NULL; ++ bn_q_inv = NULL; ++ ++ bn_n_tmp = NULL; ++ bn_e_tmp = NULL; ++ bn_d_tmp = NULL; ++ bn_p_tmp = NULL; ++ bn_q_tmp = NULL; ++ bn_dp_tmp = NULL; ++ bn_dq_tmp = NULL; ++ bn_q_inv_tmp = NULL; ++ ++ ++ /* Retrieve the components from RSA object.*/ ++ ++ rsa_key = (RSA *)rsa_context; ++ RSA_get0_key(rsa_key, (const BIGNUM **)&bn_n, (const BIGNUM **)&bn_e, ++ (const BIGNUM **)&bn_d); ++ RSA_get0_factors(rsa_key, (const BIGNUM **)&bn_p, ++ (const BIGNUM **)&bn_q); ++ RSA_get0_crt_params(rsa_key, (const BIGNUM **)&bn_dp, ++ (const BIGNUM **)&bn_dq, ++ (const BIGNUM **)&bn_q_inv); ++ ++ ++ /* Set RSA key Components by converting octet string to OpenSSL BN representation. ++ * NOTE: For RSA public key (used in signature verification), only public components ++ * (N, e) are needed.*/ ++ ++ switch (key_tag) { ++ ++ /* RSA public Modulus (N), public Exponent (e) and Private Exponent (d)*/ ++ ++ case LIBSPDM_RSA_KEY_N: ++ case LIBSPDM_RSA_KEY_E: ++ case LIBSPDM_RSA_KEY_D: ++ if (bn_n == NULL) { ++ bn_n = BN_new(); ++ bn_n_tmp = bn_n; ++ } ++ if (bn_e == NULL) { ++ bn_e = BN_new(); ++ bn_e_tmp = bn_e; ++ } ++ if (bn_d == NULL) { ++ bn_d = BN_new(); ++ bn_d_tmp = bn_d; ++ } ++ ++ if ((bn_n == NULL) || (bn_e == NULL) || (bn_d == NULL)) { ++ status = false; ++ goto err; ++ } ++ ++ if (key_tag == LIBSPDM_RSA_KEY_N) { ++ bn_n = BN_bin2bn(big_number, (uint32_t)bn_size, bn_n); ++ } else if (key_tag == LIBSPDM_RSA_KEY_E) { ++ bn_e = BN_bin2bn(big_number, (uint32_t)bn_size, bn_e); ++ } else { ++ bn_d = BN_bin2bn(big_number, (uint32_t)bn_size, bn_d); ++ } ++ if (RSA_set0_key(rsa_key, BN_dup(bn_n), BN_dup(bn_e), ++ BN_dup(bn_d)) == 0) { ++ status = false; ++ goto err; ++ } ++ ++ break; ++ ++ ++ /* RSA Secret prime Factor of Modulus (p and q)*/ ++ ++ case LIBSPDM_RSA_KEY_P: ++ case LIBSPDM_RSA_KEY_Q: ++ if (bn_p == NULL) { ++ bn_p = BN_new(); ++ bn_p_tmp = bn_p; ++ } ++ if (bn_q == NULL) { ++ bn_q = BN_new(); ++ bn_q_tmp = bn_q; ++ } ++ if ((bn_p == NULL) || (bn_q == NULL)) { ++ status = false; ++ goto err; ++ } ++ ++ if (key_tag == LIBSPDM_RSA_KEY_P) { ++ bn_p = BN_bin2bn(big_number, (uint32_t)bn_size, bn_p); ++ } else { ++ bn_q = BN_bin2bn(big_number, (uint32_t)bn_size, bn_q); ++ } ++ if (RSA_set0_factors(rsa_key, BN_dup(bn_p), BN_dup(bn_q)) == ++ 0) { ++ status = false; ++ goto err; ++ } ++ ++ break; ++ ++ ++ /* p's CRT Exponent (== d mod (p - 1)), q's CRT Exponent (== d mod (q - 1)), ++ * and CRT Coefficient (== 1/q mod p)*/ ++ ++ case LIBSPDM_RSA_KEY_DP: ++ case LIBSPDM_RSA_KEY_DQ: ++ case LIBSPDM_RSA_KEY_Q_INV: ++ if (bn_dp == NULL) { ++ bn_dp = BN_new(); ++ bn_dp_tmp = bn_dp; ++ } ++ if (bn_dq == NULL) { ++ bn_dq = BN_new(); ++ bn_dq_tmp = bn_dq; ++ } ++ if (bn_q_inv == NULL) { ++ bn_q_inv = BN_new(); ++ bn_q_inv_tmp = bn_q_inv; ++ } ++ if ((bn_dp == NULL) || (bn_dq == NULL) || (bn_q_inv == NULL)) { ++ status = false; ++ goto err; ++ } ++ ++ if (key_tag == LIBSPDM_RSA_KEY_DP) { ++ bn_dp = BN_bin2bn(big_number, (uint32_t)bn_size, bn_dp); ++ } else if (key_tag == LIBSPDM_RSA_KEY_DQ) { ++ bn_dq = BN_bin2bn(big_number, (uint32_t)bn_size, bn_dq); ++ } else { ++ bn_q_inv = BN_bin2bn(big_number, (uint32_t)bn_size, ++ bn_q_inv); ++ } ++ if (RSA_set0_crt_params(rsa_key, BN_dup(bn_dp), BN_dup(bn_dq), ++ BN_dup(bn_q_inv)) == 0) { ++ status = false; ++ goto err; ++ } ++ ++ break; ++ ++ default: ++ status = false; ++ goto err; ++ } ++ ++ status = true; ++ ++err: ++ BN_free(bn_n_tmp); ++ BN_free(bn_e_tmp); ++ BN_free(bn_d_tmp); ++ BN_free(bn_p_tmp); ++ BN_free(bn_q_tmp); ++ BN_free(bn_dp_tmp); ++ BN_free(bn_dq_tmp); ++ BN_free(bn_q_inv_tmp); ++ ++ return status; ++} ++#endif /* (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) */ ++ ++#if LIBSPDM_RSA_SSA_SUPPORT ++/** ++ * Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in ++ * RSA PKCS#1. ++ * ++ * If rsa_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If signature is NULL, then return false. ++ * If hash_size need match the hash_nid. hash_nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * ++ * @param[in] rsa_context Pointer to RSA context for signature verification. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be checked. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[in] signature Pointer to RSA PKCS1-v1_5 signature to be verified. ++ * @param[in] sig_size size of signature in bytes. ++ * ++ * @retval true Valid signature encoded in PKCS1-v1_5. ++ * @retval false Invalid signature or invalid RSA context. ++ * ++ **/ ++bool libspdm_rsa_pkcs1_verify_with_nid(void *rsa_context, size_t hash_nid, ++ const uint8_t *message_hash, ++ size_t hash_size, const uint8_t *signature, ++ size_t sig_size) ++{ ++ int32_t digest_type; ++ uint8_t *sig_buf; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (rsa_context == NULL || message_hash == NULL || signature == NULL) { ++ return false; ++ } ++ ++ if (sig_size > INT_MAX || sig_size == 0) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ digest_type = NID_sha256; ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ digest_type = NID_sha384; ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ digest_type = NID_sha512; ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ digest_type = NID_sha3_256; ++ if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ digest_type = NID_sha3_384; ++ if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ digest_type = NID_sha3_512; ++ if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ sig_buf = (uint8_t *)signature; ++ return (bool)RSA_verify(digest_type, message_hash, (uint32_t)hash_size, ++ sig_buf, (uint32_t)sig_size, ++ (RSA *)rsa_context); ++} ++#endif /* LIBSPDM_RSA_SSA_SUPPORT */ ++ ++#if LIBSPDM_RSA_PSS_SUPPORT ++/** ++ * Verifies the RSA-SSA signature with EMSA-PSS encoding scheme defined in ++ * RSA PKCS#1 v2.2. ++ * ++ * The salt length is same as digest length. ++ * ++ * If rsa_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If signature is NULL, then return false. ++ * If hash_size need match the hash_nid. nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * ++ * @param[in] rsa_context Pointer to RSA context for signature verification. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be checked. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[in] signature Pointer to RSA-SSA PSS signature to be verified. ++ * @param[in] sig_size size of signature in bytes. ++ * ++ * @retval true Valid signature encoded in RSA-SSA PSS. ++ * @retval false Invalid signature or invalid RSA context. ++ * ++ **/ ++bool libspdm_rsa_pss_verify(void *rsa_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ const uint8_t *signature, size_t sig_size) ++{ ++ RSA *rsa; ++ bool result; ++ int32_t size; ++ const EVP_MD *evp_md; ++ void *buffer; ++ ++ if (rsa_context == NULL || message_hash == NULL || signature == NULL) { ++ return false; ++ } ++ ++ if (sig_size > INT_MAX || sig_size == 0) { ++ return false; ++ } ++ ++ rsa = rsa_context; ++ size = RSA_size(rsa); ++ if (sig_size != (size_t)size) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ evp_md = EVP_sha256(); ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ evp_md = EVP_sha384(); ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ evp_md = EVP_sha512(); ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ evp_md = EVP_sha3_256(); ++ if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ evp_md = EVP_sha3_384(); ++ if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ evp_md = EVP_sha3_512(); ++ if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ buffer = allocate_pool(size); ++ if (buffer == NULL) { ++ return false; ++ } ++ ++ size = RSA_public_decrypt(size, signature, buffer, rsa, RSA_NO_PADDING); ++ if (size <= 0) { ++ free_pool(buffer); ++ return false; ++ } ++ LIBSPDM_ASSERT(sig_size == (size_t)size); ++ ++ result = (bool)RSA_verify_PKCS1_PSS(rsa, message_hash, evp_md, ++ buffer, RSA_PSS_SALTLEN_DIGEST); ++ free_pool(buffer); ++ ++ return result; ++} ++ ++#if LIBSPDM_FIPS_MODE ++/** ++ * Verifies the RSA-SSA signature with EMSA-PSS encoding scheme defined in ++ * RSA PKCS#1 v2.2 for FIPS test. ++ * ++ * The salt length is zero. ++ * ++ * If rsa_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If signature is NULL, then return false. ++ * If hash_size need match the hash_nid. nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * ++ * @param[in] rsa_context Pointer to RSA context for signature verification. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be checked. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[in] signature Pointer to RSA-SSA PSS signature to be verified. ++ * @param[in] sig_size size of signature in bytes. ++ * ++ * @retval true Valid signature encoded in RSA-SSA PSS. ++ * @retval false Invalid signature or invalid RSA context. ++ * ++ **/ ++bool libspdm_rsa_pss_verify_fips(void *rsa_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ const uint8_t *signature, size_t sig_size) ++{ ++ RSA *rsa; ++ bool result; ++ int32_t size; ++ const EVP_MD *evp_md; ++ void *buffer; ++ ++ if (rsa_context == NULL || message_hash == NULL || signature == NULL) { ++ return false; ++ } ++ ++ if (sig_size > INT_MAX || sig_size == 0) { ++ return false; ++ } ++ ++ rsa = rsa_context; ++ size = RSA_size(rsa); ++ if (sig_size != (size_t)size) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ evp_md = EVP_sha256(); ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ evp_md = EVP_sha384(); ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ evp_md = EVP_sha512(); ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ evp_md = EVP_sha3_256(); ++ if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ evp_md = EVP_sha3_384(); ++ if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ evp_md = EVP_sha3_512(); ++ if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ buffer = allocate_pool(size); ++ if (buffer == NULL) { ++ return false; ++ } ++ ++ size = RSA_public_decrypt(size, signature, buffer, rsa, RSA_NO_PADDING); ++ if (size <= 0) { ++ free_pool(buffer); ++ return false; ++ } ++ LIBSPDM_ASSERT(sig_size == (size_t)size); ++ ++ /*salt len is 0*/ ++ result = (bool)RSA_verify_PKCS1_PSS(rsa, message_hash, evp_md, ++ buffer, 0); ++ free_pool(buffer); ++ ++ return result; ++} ++#endif /*LIBSPDM_FIPS_MODE*/ ++ ++#endif /* LIBSPDM_RSA_PSS_SUPPORT */ +diff --git a/os_stub/cryptlib_wolfssl/pk/rsa_ext.c b/os_stub/cryptlib_wolfssl/pk/rsa_ext.c +new file mode 100644 +index 0000000000..699b4089fc +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/rsa_ext.c +@@ -0,0 +1,612 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * RSA Asymmetric Cipher Wrapper Implementation. ++ * ++ * This file implements following APIs which provide more capabilities for RSA: ++ * 1) libspdm_rsa_get_key ++ * 2) libspdm_rsa_generate_key ++ * 3) libspdm_rsa_check_key ++ * 4) rsa_pkcs1_sign ++ * ++ * RFC 8017 - PKCS #1: RSA Cryptography Specifications version 2.2 ++ **/ ++ ++#include "internal_crypt_lib.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) ++/** ++ * Gets the tag-designated RSA key component from the established RSA context. ++ * ++ * This function retrieves the tag-designated RSA key component from the ++ * established RSA context as a non-negative integer (octet string format ++ * represented in RSA PKCS#1). ++ * If specified key component has not been set or has been cleared, then returned ++ * bn_size is set to 0. ++ * If the big_number buffer is too small to hold the contents of the key, false ++ * is returned and bn_size is set to the required buffer size to obtain the key. ++ * ++ * If rsa_context is NULL, then return false. ++ * If bn_size is NULL, then return false. ++ * If bn_size is large enough but big_number is NULL, then return false. ++ * ++ * @param[in, out] rsa_context Pointer to RSA context being set. ++ * @param[in] key_tag tag of RSA key component being set. ++ * @param[out] big_number Pointer to octet integer buffer. ++ * @param[in, out] bn_size On input, the size of big number buffer in bytes. ++ * On output, the size of data returned in big number buffer in bytes. ++ * ++ * @retval true RSA key component was retrieved successfully. ++ * @retval false Invalid RSA key component tag. ++ * @retval false bn_size is too small. ++ * ++ **/ ++bool libspdm_rsa_get_key(void *rsa_context, const libspdm_rsa_key_tag_t key_tag, ++ uint8_t *big_number, size_t *bn_size) ++{ ++ RSA *rsa_key; ++ BIGNUM *bn_key; ++ size_t size; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (rsa_context == NULL || bn_size == NULL) { ++ return false; ++ } ++ ++ rsa_key = (RSA *)rsa_context; ++ size = *bn_size; ++ *bn_size = 0; ++ bn_key = NULL; ++ ++ switch (key_tag) { ++ ++ /* RSA public Modulus (N)*/ ++ ++ case LIBSPDM_RSA_KEY_N: ++ RSA_get0_key(rsa_key, (const BIGNUM **)&bn_key, NULL, NULL); ++ break; ++ ++ ++ /* RSA public Exponent (e)*/ ++ ++ case LIBSPDM_RSA_KEY_E: ++ RSA_get0_key(rsa_key, NULL, (const BIGNUM **)&bn_key, NULL); ++ break; ++ ++ ++ /* RSA Private Exponent (d)*/ ++ ++ case LIBSPDM_RSA_KEY_D: ++ RSA_get0_key(rsa_key, NULL, NULL, (const BIGNUM **)&bn_key); ++ break; ++ ++ ++ /* RSA Secret prime Factor of Modulus (p)*/ ++ ++ case LIBSPDM_RSA_KEY_P: ++ RSA_get0_factors(rsa_key, (const BIGNUM **)&bn_key, NULL); ++ break; ++ ++ ++ /* RSA Secret prime Factor of Modules (q)*/ ++ ++ case LIBSPDM_RSA_KEY_Q: ++ RSA_get0_factors(rsa_key, NULL, (const BIGNUM **)&bn_key); ++ break; ++ ++ ++ /* p's CRT Exponent (== d mod (p - 1))*/ ++ ++ case LIBSPDM_RSA_KEY_DP: ++ RSA_get0_crt_params(rsa_key, (const BIGNUM **)&bn_key, NULL, ++ NULL); ++ break; ++ ++ ++ /* q's CRT Exponent (== d mod (q - 1))*/ ++ ++ case LIBSPDM_RSA_KEY_DQ: ++ RSA_get0_crt_params(rsa_key, NULL, (const BIGNUM **)&bn_key, ++ NULL); ++ break; ++ ++ ++ /* The CRT Coefficient (== 1/q mod p)*/ ++ ++ case LIBSPDM_RSA_KEY_Q_INV: ++ RSA_get0_crt_params(rsa_key, NULL, NULL, ++ (const BIGNUM **)&bn_key); ++ break; ++ ++ default: ++ return false; ++ } ++ ++ if (bn_key == NULL) { ++ return false; ++ } ++ ++ *bn_size = size; ++ size = BN_num_bytes(bn_key); ++ ++ if (*bn_size < size) { ++ *bn_size = size; ++ return false; ++ } ++ ++ if (big_number == NULL) { ++ *bn_size = size; ++ return true; ++ } ++ *bn_size = BN_bn2bin(bn_key, big_number); ++ ++ return true; ++} ++ ++/** ++ * Generates RSA key components. ++ * ++ * This function generates RSA key components. It takes RSA public exponent E and ++ * length in bits of RSA modulus N as input, and generates all key components. ++ * If public_exponent is NULL, the default RSA public exponent (0x10001) will be used. ++ * ++ * If rsa_context is NULL, then return false. ++ * ++ * @param[in, out] rsa_context Pointer to RSA context being set. ++ * @param[in] modulus_length length of RSA modulus N in bits. ++ * @param[in] public_exponent Pointer to RSA public exponent. ++ * @param[in] public_exponent_size size of RSA public exponent buffer in bytes. ++ * ++ * @retval true RSA key component was generated successfully. ++ * @retval false Invalid RSA key component tag. ++ * ++ **/ ++bool libspdm_rsa_generate_key(void *rsa_context, size_t modulus_length, ++ const uint8_t *public_exponent, ++ size_t public_exponent_size) ++{ ++ BIGNUM *bn_e; ++ bool ret_val; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (rsa_context == NULL || modulus_length > INT_MAX || ++ public_exponent_size > INT_MAX) { ++ return false; ++ } ++ ++ bn_e = BN_new(); ++ if (bn_e == NULL) { ++ return false; ++ } ++ ++ ret_val = false; ++ ++ if (public_exponent == NULL) { ++ if (BN_set_word(bn_e, 0x10001) == 0) { ++ goto done; ++ } ++ } else { ++ if (BN_bin2bn(public_exponent, (uint32_t)public_exponent_size, ++ bn_e) == NULL) { ++ goto done; ++ } ++ } ++ ++ if (RSA_generate_key_ex((RSA *)rsa_context, (uint32_t)modulus_length, ++ bn_e, NULL) == 1) { ++ ret_val = true; ++ } ++ ++done: ++ BN_free(bn_e); ++ return ret_val; ++} ++ ++/** ++ * Validates key components of RSA context. ++ * NOTE: This function performs integrity checks on all the RSA key material, so ++ * the RSA key structure must contain all the private key data. ++ * ++ * This function validates key components of RSA context in following aspects: ++ * - Whether p is a prime ++ * - Whether q is a prime ++ * - Whether n = p * q ++ * - Whether d*e = 1 mod lcm(p-1,q-1) ++ * ++ * If rsa_context is NULL, then return false. ++ * ++ * @param[in] rsa_context Pointer to RSA context to check. ++ * ++ * @retval true RSA key components are valid. ++ * @retval false RSA key components are not valid. ++ * ++ **/ ++bool libspdm_rsa_check_key(void *rsa_context) ++{ ++ /* Check input parameters.*/ ++ ++ if (rsa_context == NULL) { ++ return false; ++ } ++ ++ if (RSA_check_key((RSA *)rsa_context) != 1) { ++ return false; ++ } ++ ++ return true; ++} ++#endif /* (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) */ ++ ++#if LIBSPDM_RSA_SSA_SUPPORT ++/** ++ * Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme. ++ * ++ * This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in ++ * RSA PKCS#1. ++ * If the signature buffer is too small to hold the contents of signature, false ++ * is returned and sig_size is set to the required buffer size to obtain the signature. ++ * ++ * If rsa_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If hash_size need match the hash_nid. hash_nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * If sig_size is large enough but signature is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] rsa_context Pointer to RSA context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be signed. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[out] signature Pointer to buffer to receive RSA PKCS1-v1_5 signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * ++ * @retval true signature successfully generated in PKCS1-v1_5. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_rsa_pkcs1_sign_with_nid(void *rsa_context, size_t hash_nid, ++ const uint8_t *message_hash, ++ size_t hash_size, uint8_t *signature, ++ size_t *sig_size) ++{ ++ RSA *rsa; ++ size_t size; ++ int32_t digest_type; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (rsa_context == NULL || message_hash == NULL) { ++ return false; ++ } ++ ++ rsa = (RSA *)rsa_context; ++ size = RSA_size(rsa); ++ ++ if (*sig_size < size) { ++ *sig_size = size; ++ return false; ++ } ++ ++ if (signature == NULL) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ digest_type = NID_sha256; ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ digest_type = NID_sha384; ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ digest_type = NID_sha512; ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ digest_type = NID_sha3_256; ++ if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ digest_type = NID_sha3_384; ++ if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ digest_type = NID_sha3_512; ++ if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ return (bool)RSA_sign(digest_type, message_hash, (uint32_t)hash_size, ++ signature, (uint32_t *)sig_size, ++ (RSA *)rsa_context); ++} ++#endif /* LIBSPDM_RSA_SSA_SUPPORT */ ++ ++#if LIBSPDM_RSA_PSS_SUPPORT ++/** ++ * Carries out the RSA-SSA signature generation with EMSA-PSS encoding scheme. ++ * ++ * This function carries out the RSA-SSA signature generation with EMSA-PSS encoding scheme defined in ++ * RSA PKCS#1 v2.2. ++ * ++ * The salt length is same as digest length. ++ * ++ * If the signature buffer is too small to hold the contents of signature, false ++ * is returned and sig_size is set to the required buffer size to obtain the signature. ++ * ++ * If rsa_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If hash_size need match the hash_nid. nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * If sig_size is large enough but signature is NULL, then return false. ++ * ++ * @param[in] rsa_context Pointer to RSA context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be signed. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[out] signature Pointer to buffer to receive RSA-SSA PSS signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * ++ * @retval true signature successfully generated in RSA-SSA PSS. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ * ++ **/ ++bool libspdm_rsa_pss_sign(void *rsa_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ uint8_t *signature, size_t *sig_size) ++{ ++ RSA *rsa; ++ bool result; ++ int32_t size; ++ const EVP_MD *evp_md; ++ void *buffer; ++ ++ if (rsa_context == NULL || message_hash == NULL) { ++ return false; ++ } ++ ++ rsa = (RSA *)rsa_context; ++ size = RSA_size(rsa); ++ ++ if (*sig_size < (size_t)size) { ++ *sig_size = size; ++ return false; ++ } ++ *sig_size = size; ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ evp_md = EVP_sha256(); ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ evp_md = EVP_sha384(); ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ evp_md = EVP_sha512(); ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ evp_md = EVP_sha3_256(); ++ if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ evp_md = EVP_sha3_384(); ++ if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ evp_md = EVP_sha3_512(); ++ if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ buffer = allocate_pool(size); ++ if (buffer == NULL) { ++ return false; ++ } ++ ++ result = (bool)RSA_padding_add_PKCS1_PSS( ++ rsa, buffer, message_hash, evp_md, RSA_PSS_SALTLEN_DIGEST); ++ if (!result) { ++ free_pool(buffer); ++ return false; ++ } ++ ++ size = RSA_private_encrypt(size, buffer, signature, rsa, ++ RSA_NO_PADDING); ++ free_pool(buffer); ++ if (size <= 0) { ++ return false; ++ } else { ++ LIBSPDM_ASSERT(*sig_size == (size_t)size); ++ return true; ++ } ++} ++ ++#if LIBSPDM_FIPS_MODE ++/** ++ * Carries out the RSA-SSA signature generation with EMSA-PSS encoding scheme for FIPS test. ++ * ++ * This function carries out the RSA-SSA signature generation with EMSA-PSS encoding scheme defined in ++ * RSA PKCS#1 v2.2 for FIPS test. ++ * ++ * The salt length is zero. ++ * ++ * If the signature buffer is too small to hold the contents of signature, false ++ * is returned and sig_size is set to the required buffer size to obtain the signature. ++ * ++ * If rsa_context is NULL, then return false. ++ * If message_hash is NULL, then return false. ++ * If hash_size need match the hash_nid. nid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512. ++ * If sig_size is large enough but signature is NULL, then return false. ++ * ++ * @param[in] rsa_context Pointer to RSA context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] message_hash Pointer to octet message hash to be signed. ++ * @param[in] hash_size size of the message hash in bytes. ++ * @param[out] signature Pointer to buffer to receive RSA-SSA PSS signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * ++ * @retval true signature successfully generated in RSA-SSA PSS. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ * ++ **/ ++bool libspdm_rsa_pss_sign_fips(void *rsa_context, size_t hash_nid, ++ const uint8_t *message_hash, size_t hash_size, ++ uint8_t *signature, size_t *sig_size) ++{ ++ RSA *rsa; ++ bool result; ++ int32_t size; ++ const EVP_MD *evp_md; ++ void *buffer; ++ ++ if (rsa_context == NULL || message_hash == NULL) { ++ return false; ++ } ++ ++ rsa = (RSA *)rsa_context; ++ size = RSA_size(rsa); ++ ++ if (*sig_size < (size_t)size) { ++ *sig_size = size; ++ return false; ++ } ++ *sig_size = size; ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ evp_md = EVP_sha256(); ++ if (hash_size != LIBSPDM_SHA256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ evp_md = EVP_sha384(); ++ if (hash_size != LIBSPDM_SHA384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ evp_md = EVP_sha512(); ++ if (hash_size != LIBSPDM_SHA512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ evp_md = EVP_sha3_256(); ++ if (hash_size != LIBSPDM_SHA3_256_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ evp_md = EVP_sha3_384(); ++ if (hash_size != LIBSPDM_SHA3_384_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ evp_md = EVP_sha3_512(); ++ if (hash_size != LIBSPDM_SHA3_512_DIGEST_SIZE) { ++ return false; ++ } ++ break; ++ ++ default: ++ return false; ++ } ++ ++ buffer = allocate_pool(size); ++ if (buffer == NULL) { ++ return false; ++ } ++ ++ /*salt len is 0*/ ++ result = (bool)RSA_padding_add_PKCS1_PSS( ++ rsa, buffer, message_hash, evp_md, 0); ++ if (!result) { ++ free_pool(buffer); ++ return false; ++ } ++ ++ size = RSA_private_encrypt(size, buffer, signature, rsa, ++ RSA_NO_PADDING); ++ free_pool(buffer); ++ if (size <= 0) { ++ return false; ++ } else { ++ LIBSPDM_ASSERT(*sig_size == (size_t)size); ++ return true; ++ } ++} ++#endif /*LIBSPDM_FIPS_MODE*/ ++ ++#endif /* LIBSPDM_RSA_PSS_SUPPORT */ +diff --git a/os_stub/cryptlib_wolfssl/pk/sm2.c b/os_stub/cryptlib_wolfssl/pk/sm2.c +new file mode 100644 +index 0000000000..a4d8f1c71a +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/sm2.c +@@ -0,0 +1,915 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * Shang-Mi2 Asymmetric Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++#include ++#include ++ ++/** ++ * Allocates and Initializes one Shang-Mi2 context for subsequent use. ++ * ++ * The key is generated before the function returns. ++ * ++ * @param nid cipher NID ++ * ++ * @return Pointer to the Shang-Mi2 context that has been initialized. ++ * If the allocations fails, sm2_new_by_nid() returns NULL. ++ * ++ **/ ++void *libspdm_sm2_dsa_new_by_nid(size_t nid) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ EVP_PKEY_CTX *key_ctx; ++ EVP_PKEY *pkey; ++ int32_t result; ++ EVP_PKEY *params; ++ ++ pkey_ctx = EVP_PKEY_CTX_new_from_name(NULL, "SM2", NULL); ++ if (pkey_ctx == NULL) { ++ return NULL; ++ } ++ result = EVP_PKEY_paramgen_init(pkey_ctx); ++ if (result != 1) { ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return NULL; ++ } ++ result = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, NID_sm2); ++ if (result == 0) { ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return NULL; ++ } ++ ++ params = NULL; ++ result = EVP_PKEY_paramgen(pkey_ctx, ¶ms); ++ if (result == 0) { ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return NULL; ++ } ++ EVP_PKEY_CTX_free(pkey_ctx); ++ ++ key_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, params, NULL); ++ if (key_ctx == NULL) { ++ EVP_PKEY_free(params); ++ return NULL; ++ } ++ EVP_PKEY_free(params); ++ ++ result = EVP_PKEY_keygen_init(key_ctx); ++ if (result == 0) { ++ EVP_PKEY_CTX_free(key_ctx); ++ return NULL; ++ } ++ pkey = NULL; ++ result = EVP_PKEY_keygen(key_ctx, &pkey); ++ if (result == 0 || pkey == NULL) { ++ EVP_PKEY_CTX_free(key_ctx); ++ return NULL; ++ } ++ EVP_PKEY_CTX_free(key_ctx); ++ ++ result = EVP_PKEY_is_a(pkey, "SM2"); ++ if (result != 1) { ++ EVP_PKEY_free(pkey); ++ return NULL; ++ } ++ ++ return (void *)pkey; ++} ++ ++/** ++ * Release the specified sm2 context. ++ * ++ * @param[in] sm2_context Pointer to the sm2 context to be released. ++ * ++ **/ ++void libspdm_sm2_dsa_free(void *sm2_context) ++{ ++ EVP_PKEY_free((EVP_PKEY *)sm2_context); ++} ++ ++/** ++ * Sets the public key component into the established sm2 context. ++ * ++ * The public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * ++ * @param[in, out] ec_context Pointer to sm2 context being set. ++ * @param[in] public Pointer to the buffer to receive generated public X,Y. ++ * @param[in] public_size The size of public buffer in bytes. ++ * ++ * @retval true sm2 public key component was set successfully. ++ * @retval false Invalid sm2 public key component. ++ * ++ **/ ++bool libspdm_sm2_dsa_set_pub_key(void *sm2_context, const uint8_t *public_key, ++ size_t public_key_size) ++{ ++ EVP_PKEY *pkey; ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ EC_POINT *ec_point; ++ int32_t openssl_nid; ++ size_t half_size; ++ ++ if (sm2_context == NULL || public_key == NULL) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)sm2_context; ++ if (EVP_PKEY_id(pkey) != EVP_PKEY_SM2) { ++ return false; ++ } ++ ec_key = (void *)EVP_PKEY_get0_EC_KEY(pkey); ++ ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_sm2: ++ half_size = 32; ++ break; ++ default: ++ return false; ++ } ++ if (public_key_size != half_size * 2) { ++ return false; ++ } ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = NULL; ++ ++ bn_x = BN_bin2bn(public_key, (uint32_t)half_size, NULL); ++ bn_y = BN_bin2bn(public_key + half_size, (uint32_t)half_size, NULL); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ec_point = EC_POINT_new(ec_group); ++ if (ec_point == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_set_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ ret_val = (bool)EC_KEY_set_public_key(ec_key, ec_point); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ if (ec_point != NULL) { ++ EC_POINT_free(ec_point); ++ } ++ return ret_val; ++} ++ ++/** ++ * Gets the public key component from the established sm2 context. ++ * ++ * The public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * ++ * @param[in, out] sm2_context Pointer to sm2 context being set. ++ * @param[out] public Pointer to the buffer to receive generated public X,Y. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true sm2 key component was retrieved successfully. ++ * @retval false Invalid sm2 key component. ++ * ++ **/ ++bool libspdm_sm2_dsa_get_pub_key(void *sm2_context, uint8_t *public_key, ++ size_t *public_key_size) ++{ ++ EVP_PKEY *pkey; ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ const EC_POINT *ec_point; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ int32_t openssl_nid; ++ size_t half_size; ++ int x_size; ++ int y_size; ++ ++ if (sm2_context == NULL || public_key_size == NULL) { ++ return false; ++ } ++ ++ if (public_key == NULL && *public_key_size != 0) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)sm2_context; ++ if (EVP_PKEY_id(pkey) != EVP_PKEY_SM2) { ++ return false; ++ } ++ ec_key = (void *)EVP_PKEY_get0_EC_KEY(pkey); ++ ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_sm2: ++ half_size = 32; ++ break; ++ default: ++ return false; ++ } ++ if (*public_key_size < half_size * 2) { ++ *public_key_size = half_size * 2; ++ return false; ++ } ++ *public_key_size = half_size * 2; ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = EC_KEY_get0_public_key(ec_key); ++ if (ec_point == NULL) { ++ return false; ++ } ++ ++ bn_x = BN_new(); ++ bn_y = BN_new(); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_get_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ x_size = BN_num_bytes(bn_x); ++ y_size = BN_num_bytes(bn_y); ++ if (x_size <= 0 || y_size <= 0) { ++ ret_val = false; ++ goto done; ++ } ++ LIBSPDM_ASSERT((size_t)x_size <= half_size && (size_t)y_size <= half_size); ++ ++ if (public_key != NULL) { ++ libspdm_zero_mem(public_key, *public_key_size); ++ BN_bn2bin(bn_x, &public_key[0 + half_size - x_size]); ++ BN_bn2bin(bn_y, &public_key[half_size + half_size - y_size]); ++ } ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ return ret_val; ++} ++ ++/** ++ * Validates key components of sm2 context. ++ * NOTE: This function performs integrity checks on all the sm2 key material, so ++ * the sm2 key structure must contain all the private key data. ++ * ++ * If sm2_context is NULL, then return false. ++ * ++ * @param[in] sm2_context Pointer to sm2 context to check. ++ * ++ * @retval true sm2 key components are valid. ++ * @retval false sm2 key components are not valid. ++ * ++ **/ ++bool libspdm_sm2_dsa_check_key(const void *sm2_context) ++{ ++ EVP_PKEY *pkey; ++ EC_KEY *ec_key; ++ bool ret_val; ++ ++ if (sm2_context == NULL) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)sm2_context; ++ if (EVP_PKEY_id(pkey) != EVP_PKEY_SM2) { ++ return false; ++ } ++ ec_key = (void *)EVP_PKEY_get0_EC_KEY(pkey); ++ ++ ret_val = (bool)EC_KEY_check_key(ec_key); ++ if (!ret_val) { ++ return false; ++ } ++ ++ return true; ++} ++ ++/** ++ * Generates sm2 key and returns sm2 public key (X, Y), based upon GB/T 32918.3-2016: SM2 - Part3. ++ * ++ * This function generates random secret, and computes the public key (X, Y), which is ++ * returned via parameter public, public_size. ++ * X is the first half of public with size being public_size / 2, ++ * Y is the second half of public with size being public_size / 2. ++ * sm2 context is updated accordingly. ++ * If the public buffer is too small to hold the public X, Y, false is returned and ++ * public_size is set to the required buffer size to obtain the public X, Y. ++ * ++ * The public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * ++ * If sm2_context is NULL, then return false. ++ * If public_size is NULL, then return false. ++ * If public_size is large enough but public is NULL, then return false. ++ * ++ * @param[in, out] sm2_context Pointer to the sm2 context. ++ * @param[out] public_data Pointer to the buffer to receive generated public X,Y. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true sm2 public X,Y generation succeeded. ++ * @retval false sm2 public X,Y generation failed. ++ * @retval false public_size is not large enough. ++ * ++ **/ ++bool libspdm_sm2_dsa_generate_key(void *sm2_context, uint8_t *public_data, ++ size_t *public_size) ++{ ++ EVP_PKEY *pkey; ++ EC_KEY *ec_key; ++ const EC_GROUP *ec_group; ++ bool ret_val; ++ const EC_POINT *ec_point; ++ BIGNUM *bn_x; ++ BIGNUM *bn_y; ++ int32_t openssl_nid; ++ size_t half_size; ++ int x_size; ++ int y_size; ++ ++ if (sm2_context == NULL || public_size == NULL) { ++ return false; ++ } ++ ++ if (public_data == NULL && *public_size != 0) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)sm2_context; ++ if (EVP_PKEY_id(pkey) != EVP_PKEY_SM2) { ++ return false; ++ } ++ ec_key = (void *)EVP_PKEY_get0_EC_KEY(pkey); ++ ++ ret_val = (bool)EC_KEY_generate_key(ec_key); ++ if (!ret_val) { ++ return false; ++ } ++ openssl_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)); ++ switch (openssl_nid) { ++ case NID_sm2: ++ half_size = 32; ++ break; ++ default: ++ return false; ++ } ++ if (*public_size < half_size * 2) { ++ *public_size = half_size * 2; ++ return false; ++ } ++ *public_size = half_size * 2; ++ ++ ec_group = EC_KEY_get0_group(ec_key); ++ ec_point = EC_KEY_get0_public_key(ec_key); ++ if (ec_point == NULL) { ++ return false; ++ } ++ ++ bn_x = BN_new(); ++ bn_y = BN_new(); ++ if (bn_x == NULL || bn_y == NULL) { ++ ret_val = false; ++ goto done; ++ } ++ ++ ret_val = (bool)EC_POINT_get_affine_coordinates(ec_group, ec_point, ++ bn_x, bn_y, NULL); ++ if (!ret_val) { ++ goto done; ++ } ++ ++ x_size = BN_num_bytes(bn_x); ++ y_size = BN_num_bytes(bn_y); ++ if (x_size <= 0 || y_size <= 0) { ++ ret_val = false; ++ goto done; ++ } ++ LIBSPDM_ASSERT((size_t)x_size <= half_size && (size_t)y_size <= half_size); ++ ++ if (public_data != NULL) { ++ libspdm_zero_mem(public_data, *public_size); ++ BN_bn2bin(bn_x, &public_data[0 + half_size - x_size]); ++ BN_bn2bin(bn_y, &public_data[half_size + half_size - y_size]); ++ } ++ ret_val = true; ++ ++done: ++ if (bn_x != NULL) { ++ BN_free(bn_x); ++ } ++ if (bn_y != NULL) { ++ BN_free(bn_y); ++ } ++ return ret_val; ++} ++ ++/** ++ * Allocates and Initializes one Shang-Mi2 context for subsequent use. ++ * ++ * The key is generated before the function returns. ++ * ++ * @param nid cipher NID ++ * ++ * @return Pointer to the Shang-Mi2 context that has been initialized. ++ * If the allocations fails, sm2_new_by_nid() returns NULL. ++ * ++ **/ ++void *libspdm_sm2_key_exchange_new_by_nid(size_t nid) ++{ ++ /* current openssl only supports ECDH with SM2 curve, but does not support SM2-key-exchange.*/ ++ return NULL; ++} ++ ++/** ++ * Release the specified sm2 context. ++ * ++ * @param[in] sm2_context Pointer to the sm2 context to be released. ++ * ++ **/ ++void libspdm_sm2_key_exchange_free(void *sm2_context) ++{ ++ /* current openssl only supports ECDH with SM2 curve, but does not support SM2-key-exchange.*/ ++} ++ ++/** ++ * Initialize the specified sm2 context. ++ * ++ * @param[in] sm2_context Pointer to the sm2 context to be released. ++ * @param[in] hash_nid hash NID, only SM3 is valid. ++ * @param[in] id_a the ID-A of the key exchange context. ++ * @param[in] id_a_size size of ID-A key exchange context. ++ * @param[in] id_b the ID-B of the key exchange context. ++ * @param[in] id_b_size size of ID-B key exchange context. ++ * @param[in] is_initiator if the caller is initiator. ++ * true: initiator ++ * false: not an initiator ++ * ++ * @retval true sm2 context is initialized. ++ * @retval false sm2 context is not initialized. ++ **/ ++bool libspdm_sm2_key_exchange_init(const void *sm2_context, size_t hash_nid, ++ const uint8_t *id_a, size_t id_a_size, ++ const uint8_t *id_b, size_t id_b_size, ++ bool is_initiator) ++{ ++ /* current openssl only supports ECDH with SM2 curve, but does not support SM2-key-exchange.*/ ++ return false; ++} ++ ++/** ++ * Generates sm2 key and returns sm2 public key (X, Y), based upon GB/T 32918.3-2016: SM2 - Part3. ++ * ++ * This function generates random secret, and computes the public key (X, Y), which is ++ * returned via parameter public, public_size. ++ * X is the first half of public with size being public_size / 2, ++ * Y is the second half of public with size being public_size / 2. ++ * sm2 context is updated accordingly. ++ * If the public buffer is too small to hold the public X, Y, false is returned and ++ * public_size is set to the required buffer size to obtain the public X, Y. ++ * ++ * The public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * ++ * If sm2_context is NULL, then return false. ++ * If public_size is NULL, then return false. ++ * If public_size is large enough but public is NULL, then return false. ++ * ++ * @param[in, out] sm2_context Pointer to the sm2 context. ++ * @param[out] public_data Pointer to the buffer to receive generated public X,Y. ++ * @param[in, out] public_size On input, the size of public buffer in bytes. ++ * On output, the size of data returned in public buffer in bytes. ++ * ++ * @retval true sm2 public X,Y generation succeeded. ++ * @retval false sm2 public X,Y generation failed. ++ * @retval false public_size is not large enough. ++ * ++ **/ ++bool libspdm_sm2_key_exchange_generate_key(void *sm2_context, uint8_t *public_data, ++ size_t *public_size) ++{ ++ /* current openssl only supports ECDH with SM2 curve, but does not support SM2-key-exchange.*/ ++ return false; ++} ++ ++/** ++ * Computes exchanged common key, based upon GB/T 32918.3-2016: SM2 - Part3. ++ * ++ * Given peer's public key (X, Y), this function computes the exchanged common key, ++ * based on its own context including value of curve parameter and random secret. ++ * X is the first half of peer_public with size being peer_public_size / 2, ++ * Y is the second half of peer_public with size being peer_public_size / 2. ++ * ++ * If sm2_context is NULL, then return false. ++ * If peer_public is NULL, then return false. ++ * If peer_public_size is 0, then return false. ++ * If key is NULL, then return false. ++ * ++ * The id_a_size and id_b_size must be smaller than 2^16-1. ++ * The peer_public_size is 64. first 32-byte is X, second 32-byte is Y. ++ * The key_size must be smaller than 2^32-1, limited by KDF function. ++ * ++ * @param[in, out] sm2_context Pointer to the sm2 context. ++ * @param[in] peer_public Pointer to the peer's public X,Y. ++ * @param[in] peer_public_size size of peer's public X,Y in bytes. ++ * @param[out] key Pointer to the buffer to receive generated key. ++ * @param[in] key_size On input, the size of key buffer in bytes. ++ * ++ * @retval true sm2 exchanged key generation succeeded. ++ * @retval false sm2 exchanged key generation failed. ++ * ++ **/ ++bool libspdm_sm2_key_exchange_compute_key(void *sm2_context, ++ const uint8_t *peer_public, ++ size_t peer_public_size, uint8_t *key, ++ size_t *key_size) ++{ ++ /* current openssl only supports ECDH with SM2 curve, but does not support SM2-key-exchange.*/ ++ return false; ++} ++ ++static void ecc_signature_der_to_bin(uint8_t *der_signature, ++ size_t der_sig_size, ++ uint8_t *signature, size_t sig_size) ++{ ++ uint8_t der_r_size; ++ uint8_t der_s_size; ++ uint8_t *bn_r; ++ uint8_t *bn_s; ++ uint8_t r_size; ++ uint8_t s_size; ++ uint8_t half_size; ++ ++ half_size = (uint8_t)(sig_size / 2); ++ ++ LIBSPDM_ASSERT(der_signature[0] == 0x30); ++ LIBSPDM_ASSERT((size_t)(der_signature[1] + 2) == der_sig_size); ++ LIBSPDM_ASSERT(der_signature[2] == 0x02); ++ der_r_size = der_signature[3]; ++ LIBSPDM_ASSERT(der_signature[4 + der_r_size] == 0x02); ++ der_s_size = der_signature[5 + der_r_size]; ++ LIBSPDM_ASSERT(der_sig_size == (size_t)(der_r_size + der_s_size + 6)); ++ ++ if (der_signature[4] != 0) { ++ r_size = der_r_size; ++ bn_r = &der_signature[4]; ++ } else { ++ r_size = der_r_size - 1; ++ bn_r = &der_signature[5]; ++ } ++ if (der_signature[6 + der_r_size] != 0) { ++ s_size = der_s_size; ++ bn_s = &der_signature[6 + der_r_size]; ++ } else { ++ s_size = der_s_size - 1; ++ bn_s = &der_signature[7 + der_r_size]; ++ } ++ LIBSPDM_ASSERT(r_size <= half_size && s_size <= half_size); ++ libspdm_zero_mem(signature, sig_size); ++ libspdm_copy_mem(&signature[0 + half_size - r_size], ++ sig_size - (0 + half_size - r_size), ++ bn_r, r_size); ++ libspdm_copy_mem(&signature[half_size + half_size - s_size], ++ sig_size - (half_size + half_size - s_size), ++ bn_s, s_size); ++} ++ ++static void ecc_signature_bin_to_der(uint8_t *signature, size_t sig_size, ++ uint8_t *der_signature, ++ size_t *der_sig_size_in_out) ++{ ++ size_t der_sig_size; ++ uint8_t der_r_size; ++ uint8_t der_s_size; ++ uint8_t *bn_r; ++ uint8_t *bn_s; ++ uint8_t r_size; ++ uint8_t s_size; ++ uint8_t half_size; ++ uint8_t index; ++ ++ half_size = (uint8_t)(sig_size / 2); ++ ++ for (index = 0; index < half_size; index++) { ++ if (signature[index] != 0) { ++ break; ++ } ++ } ++ r_size = (uint8_t)(half_size - index); ++ bn_r = &signature[index]; ++ for (index = 0; index < half_size; index++) { ++ if (signature[half_size + index] != 0) { ++ break; ++ } ++ } ++ s_size = (uint8_t)(half_size - index); ++ bn_s = &signature[half_size + index]; ++ if (r_size == 0 || s_size == 0) { ++ *der_sig_size_in_out = 0; ++ return; ++ } ++ if (bn_r[0] < 0x80) { ++ der_r_size = r_size; ++ } else { ++ der_r_size = r_size + 1; ++ } ++ if (bn_s[0] < 0x80) { ++ der_s_size = s_size; ++ } else { ++ der_s_size = s_size + 1; ++ } ++ der_sig_size = der_r_size + der_s_size + 6; ++ LIBSPDM_ASSERT(der_sig_size <= *der_sig_size_in_out); ++ *der_sig_size_in_out = der_sig_size; ++ libspdm_zero_mem(der_signature, der_sig_size); ++ der_signature[0] = 0x30; ++ der_signature[1] = (uint8_t)(der_sig_size - 2); ++ der_signature[2] = 0x02; ++ der_signature[3] = der_r_size; ++ if (bn_r[0] < 0x80) { ++ libspdm_copy_mem(&der_signature[4], ++ der_sig_size - (&der_signature[4] - der_signature), ++ bn_r, r_size); ++ } else { ++ libspdm_copy_mem(&der_signature[5], ++ der_sig_size - (&der_signature[5] - der_signature), ++ bn_r, r_size); ++ } ++ der_signature[4 + der_r_size] = 0x02; ++ der_signature[5 + der_r_size] = der_s_size; ++ if (bn_s[0] < 0x80) { ++ libspdm_copy_mem(&der_signature[6 + der_r_size], ++ der_sig_size - (&der_signature[6 + der_r_size] - der_signature), ++ bn_s, s_size); ++ } else { ++ libspdm_copy_mem(&der_signature[7 + der_r_size], ++ der_sig_size - (&der_signature[7 + der_r_size] - der_signature), ++ bn_s, s_size); ++ } ++} ++ ++/** ++ * Carries out the SM2 signature, based upon GB/T 32918.2-2016: SM2 - Part2. ++ * ++ * This function carries out the SM2 signature. ++ * If the signature buffer is too small to hold the contents of signature, false ++ * is returned and sig_size is set to the required buffer size to obtain the signature. ++ * ++ * If sm2_context is NULL, then return false. ++ * If message is NULL, then return false. ++ * hash_nid must be SM3_256. ++ * If sig_size is large enough but signature is NULL, then return false. ++ * ++ * The id_a_size must be smaller than 2^16-1. ++ * The sig_size is 64. first 32-byte is R, second 32-byte is S. ++ * ++ * @param[in] sm2_context Pointer to sm2 context for signature generation. ++ * @param[in] hash_nid hash NID ++ * @param[in] id_a the ID-A of the signing context. ++ * @param[in] id_a_size size of ID-A signing context. ++ * @param[in] message Pointer to octet message to be signed (before hash). ++ * @param[in] size size of the message in bytes. ++ * @param[out] signature Pointer to buffer to receive SM2 signature. ++ * @param[in, out] sig_size On input, the size of signature buffer in bytes. ++ * On output, the size of data returned in signature buffer in bytes. ++ * ++ * @retval true signature successfully generated in SM2. ++ * @retval false signature generation failed. ++ * @retval false sig_size is too small. ++ * ++ **/ ++bool libspdm_sm2_dsa_sign(const void *sm2_context, size_t hash_nid, ++ const uint8_t *id_a, size_t id_a_size, ++ const uint8_t *message, size_t size, ++ uint8_t *signature, size_t *sig_size) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ EVP_PKEY *pkey; ++ EVP_MD_CTX *ctx; ++ size_t half_size; ++ int32_t result; ++ uint8_t der_signature[32 * 2 + 8]; ++ size_t der_sig_size; ++ ++ if (sm2_context == NULL || message == NULL) { ++ return false; ++ } ++ ++ if (signature == NULL || sig_size == NULL) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)sm2_context; ++ switch (EVP_PKEY_id(pkey)) { ++ case EVP_PKEY_SM2: ++ half_size = 32; ++ break; ++ default: ++ return false; ++ } ++ ++ if (*sig_size < (size_t)(half_size * 2)) { ++ *sig_size = half_size * 2; ++ return false; ++ } ++ *sig_size = half_size * 2; ++ libspdm_zero_mem(signature, *sig_size); ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SM3_256: ++ break; ++ ++ default: ++ return false; ++ } ++ ++ ctx = EVP_MD_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); ++ if (pkey_ctx == NULL) { ++ EVP_MD_CTX_free(ctx); ++ return false; ++ } ++ ++ if (id_a_size != 0) { ++ result = EVP_PKEY_CTX_set1_id(pkey_ctx, id_a, ++ id_a_size); ++ if (result <= 0) { ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return false; ++ } ++ } ++ ++ EVP_MD_CTX_set_pkey_ctx(ctx, pkey_ctx); ++ ++ result = EVP_DigestSignInit(ctx, NULL, EVP_sm3(), NULL, pkey); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return false; ++ } ++ der_sig_size = sizeof(der_signature); ++ result = EVP_DigestSign(ctx, der_signature, &der_sig_size, message, ++ size); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return false; ++ } ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ ++ ecc_signature_der_to_bin(der_signature, der_sig_size, signature, ++ *sig_size); ++ ++ return true; ++} ++ ++/** ++ * Verifies the SM2 signature, based upon GB/T 32918.2-2016: SM2 - Part2. ++ * ++ * If sm2_context is NULL, then return false. ++ * If message is NULL, then return false. ++ * If signature is NULL, then return false. ++ * hash_nid must be SM3_256. ++ * ++ * The id_a_size must be smaller than 2^16-1. ++ * The sig_size is 64. first 32-byte is R, second 32-byte is S. ++ * ++ * @param[in] sm2_context Pointer to SM2 context for signature verification. ++ * @param[in] hash_nid hash NID ++ * @param[in] id_a the ID-A of the signing context. ++ * @param[in] id_a_size size of ID-A signing context. ++ * @param[in] message Pointer to octet message to be checked (before hash). ++ * @param[in] size size of the message in bytes. ++ * @param[in] signature Pointer to SM2 signature to be verified. ++ * @param[in] sig_size size of signature in bytes. ++ * ++ * @retval true Valid signature encoded in SM2. ++ * @retval false Invalid signature or invalid sm2 context. ++ * ++ **/ ++bool libspdm_sm2_dsa_verify(const void *sm2_context, size_t hash_nid, ++ const uint8_t *id_a, size_t id_a_size, ++ const uint8_t *message, size_t size, ++ const uint8_t *signature, size_t sig_size) ++{ ++ EVP_PKEY_CTX *pkey_ctx; ++ EVP_PKEY *pkey; ++ EVP_MD_CTX *ctx; ++ size_t half_size; ++ int32_t result; ++ uint8_t der_signature[32 * 2 + 8]; ++ size_t der_sig_size; ++ ++ if (sm2_context == NULL || message == NULL || signature == NULL) { ++ return false; ++ } ++ ++ if (sig_size > INT_MAX || sig_size == 0) { ++ return false; ++ } ++ ++ pkey = (EVP_PKEY *)sm2_context; ++ switch (EVP_PKEY_id(pkey)) { ++ case EVP_PKEY_SM2: ++ half_size = 32; ++ break; ++ default: ++ return false; ++ } ++ ++ if (sig_size != (size_t)(half_size * 2)) { ++ return false; ++ } ++ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SM3_256: ++ break; ++ ++ default: ++ return false; ++ } ++ ++ der_sig_size = sizeof(der_signature); ++ ecc_signature_bin_to_der((uint8_t *)signature, sig_size, der_signature, ++ &der_sig_size); ++ ++ ctx = EVP_MD_CTX_new(); ++ if (ctx == NULL) { ++ return false; ++ } ++ pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL); ++ if (pkey_ctx == NULL) { ++ EVP_MD_CTX_free(ctx); ++ return false; ++ } ++ ++ if (id_a_size != 0) { ++ result = EVP_PKEY_CTX_set1_id(pkey_ctx, id_a, ++ id_a_size); ++ if (result <= 0) { ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return false; ++ } ++ } ++ EVP_MD_CTX_set_pkey_ctx(ctx, pkey_ctx); ++ ++ result = EVP_DigestVerifyInit(ctx, NULL, EVP_sm3(), NULL, pkey); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return false; ++ } ++ result = EVP_DigestVerify(ctx, der_signature, (uint32_t)der_sig_size, ++ message, size); ++ if (result != 1) { ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return false; ++ } ++ ++ EVP_MD_CTX_free(ctx); ++ EVP_PKEY_CTX_free(pkey_ctx); ++ return true; ++} +diff --git a/os_stub/cryptlib_wolfssl/pk/x509.c b/os_stub/cryptlib_wolfssl/pk/x509.c +new file mode 100644 +index 0000000000..d719eb7672 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/pk/x509.c +@@ -0,0 +1,2704 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2024 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * X.509 Certificate Handler Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#if LIBSPDM_CERT_PARSE_SUPPORT ++ ++/*buffer size to store subject object*/ ++#define MAX_SBUJECT_NAME_LEN 0x100 ++ ++/*see link:"https://man.openbsd.org/ASN1_get_object.3" */ ++#define OPENSSL_ASN1_ERROR_MASK 0x80 ++ ++/* OID*/ ++#define OID_EXT_KEY_USAGE { 0x55, 0x1D, 0x25 } ++#define OID_BASIC_CONSTRAINTS { 0x55, 0x1D, 0x13 } ++ ++static const uint8_t m_libspdm_oid_ext_key_usage[] = OID_EXT_KEY_USAGE; ++static const uint8_t m_libspdm_oid_basic_constraints[] = OID_BASIC_CONSTRAINTS; ++ ++/** ++ * Construct a X509 object from DER-encoded certificate data. ++ * ++ * If cert is NULL, then return false. ++ * If single_x509_cert is NULL, then return false. ++ * ++ * @param[in] cert Pointer to the DER-encoded certificate data. ++ * @param[in] cert_size The size of certificate data in bytes. ++ * @param[out] single_x509_cert The generated X509 object. ++ * ++ * @retval true The X509 object generation succeeded. ++ * @retval false The operation failed. ++ * ++ **/ ++bool libspdm_x509_construct_certificate(const uint8_t *cert, size_t cert_size, ++ uint8_t **single_x509_cert) ++{ ++ X509 *x509_cert; ++ const uint8_t *temp; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || single_x509_cert == NULL || cert_size > INT_MAX) { ++ return false; ++ } ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ temp = cert; ++ x509_cert = d2i_X509(NULL, &temp, (long)cert_size); ++ if (x509_cert == NULL) { ++ return false; ++ } ++ ++ *single_x509_cert = (uint8_t *)x509_cert; ++ ++ return true; ++} ++ ++/** ++ * Construct a X509 stack object from a list of DER-encoded certificate data. ++ * ++ * If x509_stack is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in, out] x509_stack On input, pointer to an existing or NULL X509 stack object. ++ * On output, pointer to the X509 stack object with new ++ * inserted X509 certificate. ++ * @param[in] args LIBSPDM_VA_LIST marker for the variable argument list. ++ * A list of DER-encoded single certificate data followed ++ * by certificate size. A NULL terminates the list. The ++ * pairs are the arguments to libspdm_x509_construct_certificate(). ++ * ++ * @retval true The X509 stack construction succeeded. ++ * @retval false The construction operation failed. ++ * @retval false This interface is not supported. ++ * ++ **/ ++bool libspdm_x509_construct_certificate_stack_v(uint8_t **x509_stack, ++ LIBSPDM_VA_LIST args) ++{ ++ uint8_t *cert; ++ size_t cert_size; ++ X509 *x509_cert; ++ STACK_OF(X509) * cert_stack; ++ bool res; ++ ++ /* Check input parameters.*/ ++ ++ if (x509_stack == NULL) { ++ return false; ++ } ++ ++ res = false; ++ ++ ++ /* Initialize X509 stack object.*/ ++ ++ cert_stack = (STACK_OF(X509) *)(*x509_stack); ++ if (cert_stack == NULL) { ++ cert_stack = sk_X509_new_null(); ++ if (cert_stack == NULL) { ++ return res; ++ } ++ } ++ ++ for (;;) { ++ ++ /* If cert is NULL, then it is the end of the list.*/ ++ ++ cert = LIBSPDM_VA_ARG(args, uint8_t *); ++ if (cert == NULL) { ++ break; ++ } ++ ++ cert_size = LIBSPDM_VA_ARG(args, size_t); ++ if (cert_size == 0) { ++ break; ++ } ++ ++ ++ /* Construct X509 Object from the given DER-encoded certificate data.*/ ++ ++ x509_cert = NULL; ++ res = libspdm_x509_construct_certificate((const uint8_t *)cert, cert_size, ++ (uint8_t **)&x509_cert); ++ if (!res) { ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ break; ++ } ++ ++ ++ /* Insert the new X509 object into X509 stack object.*/ ++ ++ res = sk_X509_push(cert_stack, x509_cert); ++ if (!res) { ++ X509_free(x509_cert); ++ break; ++ } ++ } ++ ++ if (!res) { ++ sk_X509_pop_free(cert_stack, X509_free); ++ } else { ++ *x509_stack = (uint8_t *)cert_stack; ++ } ++ ++ return res; ++} ++ ++/** ++ * Construct a X509 stack object from a list of DER-encoded certificate data. ++ * ++ * If x509_stack is NULL, then return false. ++ * ++ * @param[in, out] x509_stack On input, pointer to an existing or NULL X509 stack object. ++ * On output, pointer to the X509 stack object with new ++ * inserted X509 certificate. ++ * @param ... A list of DER-encoded single certificate data followed ++ * by certificate size. A NULL terminates the list. The ++ * pairs are the arguments to libspdm_x509_construct_certificate(). ++ * ++ * @retval true The X509 stack construction succeeded. ++ * @retval false The construction operation failed. ++ * ++ **/ ++bool libspdm_x509_construct_certificate_stack(uint8_t **x509_stack, ...) ++{ ++ LIBSPDM_VA_LIST args; ++ bool result; ++ ++ LIBSPDM_VA_START(args, x509_stack); ++ result = libspdm_x509_construct_certificate_stack_v(x509_stack, args); ++ LIBSPDM_VA_END(args); ++ return result; ++} ++ ++/** ++ * Release the specified X509 object. ++ * ++ * If x509_cert is NULL, then return false. ++ * ++ * @param[in] x509_cert Pointer to the X509 object to be released. ++ * ++ **/ ++void libspdm_x509_free(void *x509_cert) ++{ ++ ++ /* Check input parameters.*/ ++ ++ if (x509_cert == NULL) { ++ return; ++ } ++ ++ ++ /* Free OpenSSL X509 object.*/ ++ ++ X509_free((X509 *)x509_cert); ++} ++ ++/** ++ * Release the specified X509 stack object. ++ * ++ * If x509_stack is NULL, then return false. ++ * ++ * @param[in] x509_stack Pointer to the X509 stack object to be released. ++ * ++ **/ ++void libspdm_x509_stack_free(void *x509_stack) ++{ ++ ++ /* Check input parameters.*/ ++ ++ if (x509_stack == NULL) { ++ return; ++ } ++ ++ ++ /* Free OpenSSL X509 stack object.*/ ++ ++ sk_X509_pop_free((STACK_OF(X509) *)x509_stack, X509_free); ++} ++ ++/** ++ * Retrieve the tag and length of the tag. ++ * ++ * @param ptr The position in the ASN.1 data ++ * @param end end of data ++ * @param length The variable that will receive the length ++ * @param tag The expected tag ++ * ++ * @retval true Get tag successful ++ * @retval FALSe Failed to get tag or tag not match ++ **/ ++bool libspdm_asn1_get_tag(uint8_t **ptr, const uint8_t *end, size_t *length, ++ uint32_t tag) ++{ ++ const uint8_t *ptr_old; ++ int32_t obj_tag; ++ int32_t obj_class; ++ long obj_length; ++ int32_t ret; ++ ++ /* Save ptr position*/ ++ ++ ptr_old = *ptr; ++ ++ /*when there is no object, return false*/ ++ if ((*ptr) == end) { ++ return false; ++ } ++ ++ ret = ASN1_get_object((const uint8_t **)ptr, &obj_length, &obj_tag, &obj_class, ++ (int32_t)(end - (*ptr))); ++ /* Either a primitive encoding with a valid tag and definite length, but the content octets won't fit into omax, or parsing failed. */ ++ if (ret & OPENSSL_ASN1_ERROR_MASK) { ++ return false; ++ } ++ ++ if (obj_tag == (int32_t)(tag & LIBSPDM_CRYPTO_ASN1_TAG_VALUE_MASK) && ++ obj_class == (int32_t)(tag & LIBSPDM_CRYPTO_ASN1_TAG_CLASS_MASK)) { ++ *length = (size_t)obj_length; ++ return true; ++ } else { ++ ++ /* if doesn't match tag, restore ptr to origin ptr*/ ++ ++ *ptr = (uint8_t *)ptr_old; ++ return false; ++ } ++} ++ ++/** ++ * Retrieve the subject bytes from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] cert_subject Pointer to the retrieved certificate subject bytes. ++ * @param[in, out] subject_size The size in bytes of the cert_subject buffer on input, ++ * and the size of buffer returned cert_subject on output. ++ * ++ * If cert is NULL, then return false. ++ * If subject_size is NULL, then return false. ++ * ++ * @retval true If the subject_size is not equal 0. The certificate subject retrieved successfully. ++ * @retval true If the subject_size is equal 0. The certificate parse successful. But the cert doesn't have subject. ++ * @retval false If the subject_size is not equal 0. The certificate subject retrieved successfully.But the subject_size is too small for the result. ++ * @retval false If the subject_size is equal 0. Invalid certificate. ++ **/ ++bool libspdm_x509_get_subject_name(const uint8_t *cert, size_t cert_size, ++ uint8_t *cert_subject, ++ size_t *subject_size) ++{ ++ bool res; ++ X509 *x509_cert; ++ X509_NAME *x509_name; ++ size_t x509_name_size; ++ ++ /* Check input parameters.*/ ++ if (cert == NULL || cert == 0 || subject_size == NULL) { ++ if (subject_size != NULL) { ++ *subject_size = 0; ++ } ++ return false; ++ } ++ ++ x509_cert = NULL; ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ *subject_size = 0; ++ res = false; ++ goto done; ++ } ++ ++ res = false; ++ ++ /* Retrieve subject name from certificate object.*/ ++ x509_name = X509_get_subject_name(x509_cert); ++ if (x509_name == NULL) { ++ *subject_size = 0; ++ res = true; ++ goto done; ++ } ++ ++ x509_name_size = i2d_X509_NAME(x509_name, NULL); ++ if (*subject_size < x509_name_size) { ++ *subject_size = x509_name_size; ++ goto done; ++ } ++ *subject_size = x509_name_size; ++ if (cert_subject != NULL) { ++ i2d_X509_NAME(x509_name, &cert_subject); ++ res = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return res; ++} ++ ++/** ++ * Retrieve a string from one X.509 certificate base on the request_nid. ++ * ++ * @param[in] x509_name X509 name ++ * @param[in] request_nid NID of string to obtain ++ * @param[out] common_name buffer to contain the retrieved certificate common ++ * name string (UTF8). At most common_name_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] common_name_size The size in bytes of the common_name buffer on input, ++ * and the size of buffer returned common_name on output. ++ * If common_name is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate common_name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If common_name_size is NULL. ++ * If common_name is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no NID name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool ++libspdm_internal_x509_get_nid_name(X509_NAME *x509_name, const int32_t request_nid, ++ char *common_name, ++ size_t *common_name_size) ++{ ++ bool status; ++ int32_t index; ++ int length; ++ X509_NAME_ENTRY *entry; ++ ASN1_STRING *entry_data; ++ uint8_t *utf8_name; ++ size_t common_name_capacity; ++ ++ status = false; ++ utf8_name = NULL; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (x509_name == NULL || (common_name_size == NULL)) { ++ return false; ++ } ++ if ((common_name != NULL) && (*common_name_size == 0)) { ++ return false; ++ } ++ ++ ++ /* Retrive the string from X.509 Subject base on the request_nid*/ ++ ++ index = X509_NAME_get_index_by_NID(x509_name, request_nid, -1); ++ if (index < 0) { ++ ++ /* No request_nid name entry exists in X509_NAME object*/ ++ ++ *common_name_size = 0; ++ status = false; ++ goto done; ++ } ++ ++ entry = X509_NAME_get_entry(x509_name, index); ++ if (entry == NULL) { ++ ++ /* Fail to retrieve name entry data*/ ++ ++ *common_name_size = 0; ++ status = false; ++ goto done; ++ } ++ ++ entry_data = X509_NAME_ENTRY_get_data(entry); ++ ++ length = ASN1_STRING_to_UTF8(&utf8_name, entry_data); ++ if (length < 0) { ++ ++ /* Fail to convert the name string*/ ++ ++ *common_name_size = 0; ++ status = false; ++ goto done; ++ } ++ ++ if (common_name == NULL) { ++ *common_name_size = length + 1; ++ status = false; ++ } else { ++ common_name_capacity = *common_name_size; ++ *common_name_size = ++ LIBSPDM_MIN((size_t)length, *common_name_size - 1) + 1; ++ libspdm_copy_mem(common_name, common_name_capacity, ++ utf8_name, *common_name_size - 1); ++ common_name[*common_name_size - 1] = '\0'; ++ status = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (utf8_name != NULL) { ++ OPENSSL_free(utf8_name); ++ } ++ ++ return status; ++} ++ ++/** ++ * Retrieve a string from one X.509 certificate base on the request_nid. ++ * ++ * @param[in] x509_name x509_name Struct ++ * @param[in] request_nid NID of string to obtain ++ * @param[out] common_name buffer to contain the retrieved certificate common ++ * name string (UTF8). At most common_name_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] common_name_size The size in bytes of the common_name buffer on input, ++ * and the size of buffer returned common_name on output. ++ * If common_name is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate common_name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If common_name_size is NULL. ++ * If common_name is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no NID name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool ++libspdm_internal_x509_get_subject_nid_name(const uint8_t *cert, size_t cert_size, ++ const int32_t request_nid, char *common_name, ++ size_t *common_name_size) ++{ ++ bool status; ++ X509 *x509_cert; ++ X509_NAME *x509_name; ++ ++ status = false; ++ x509_cert = NULL; ++ ++ if (cert == NULL || cert_size == 0) { ++ goto done; ++ } ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ status = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!status)) { ++ ++ /* Invalid X.509 Certificate*/ ++ ++ status = false; ++ goto done; ++ } ++ ++ status = false; ++ ++ ++ /* Retrieve subject name from certificate object.*/ ++ ++ x509_name = X509_get_subject_name(x509_cert); ++ if (x509_name == NULL) { ++ ++ /* Fail to retrieve subject name content*/ ++ ++ goto done; ++ } ++ ++ status = libspdm_internal_x509_get_nid_name(x509_name, request_nid, common_name, ++ common_name_size); ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ return status; ++} ++ ++/** ++ * Retrieve a string from one X.509 certificate base on the request_nid. ++ * ++ * @param[in] x509_name X509 Struct ++ * @param[in] request_nid NID of string to obtain ++ * @param[out] common_name buffer to contain the retrieved certificate common ++ * name string (UTF8). At most common_name_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] common_name_size The size in bytes of the common_name buffer on input, ++ * and the size of buffer returned common_name on output. ++ * If common_name is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate common_name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If common_name_size is NULL. ++ * If common_name is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no NID name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool ++libspdm_internal_x509_get_issuer_nid_name(const uint8_t *cert, size_t cert_size, ++ const int32_t request_nid, char *common_name, ++ size_t *common_name_size) ++{ ++ bool status; ++ X509 *x509_cert; ++ X509_NAME *x509_name; ++ ++ status = false; ++ x509_cert = NULL; ++ ++ if (cert == NULL || cert_size == 0) { ++ goto done; ++ } ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ status = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!status)) { ++ ++ /* Invalid X.509 Certificate*/ ++ ++ status = false; ++ goto done; ++ } ++ ++ status = false; ++ ++ ++ /* Retrieve subject name from certificate object.*/ ++ ++ x509_name = X509_get_issuer_name(x509_cert); ++ if (x509_name == NULL) { ++ ++ /* Fail to retrieve subject name content*/ ++ ++ goto done; ++ } ++ ++ status = libspdm_internal_x509_get_nid_name(x509_name, request_nid, common_name, ++ common_name_size); ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ return status; ++} ++ ++/** ++ * Retrieve the common name (CN) string from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] common_name buffer to contain the retrieved certificate common ++ * name string. At most common_name_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] common_name_size The size in bytes of the common_name buffer on input, ++ * and the size of buffer returned common_name on output. ++ * If common_name is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate common_name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If common_name_size is NULL. ++ * If common_name is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no common_name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool libspdm_x509_get_common_name(const uint8_t *cert, size_t cert_size, ++ char *common_name, ++ size_t *common_name_size) ++{ ++ return libspdm_internal_x509_get_subject_nid_name( ++ cert, cert_size, NID_commonName, common_name, common_name_size); ++} ++ ++/** ++ * Retrieve the organization name (O) string from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] name_buffer buffer to contain the retrieved certificate organization ++ * name string. At most name_buffer_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] name_buffer_size The size in bytes of the name buffer on input, ++ * and the size of buffer returned name on output. ++ * If name_buffer is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate Organization name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If name_buffer_size is NULL. ++ * If name_buffer is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no Organization name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the name_buffer is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool ++libspdm_x509_get_organization_name(const uint8_t *cert, size_t cert_size, ++ char *name_buffer, ++ size_t *name_buffer_size) ++{ ++ return libspdm_internal_x509_get_subject_nid_name(cert, cert_size, ++ NID_organizationName, ++ name_buffer, ++ name_buffer_size); ++} ++ ++/** ++ * Retrieve the version from one X.509 certificate. ++ * ++ * If cert is NULL, then return false. ++ * If cert_size is 0, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] version Pointer to the retrieved version integer. ++ * ++ * @retval RETURN_SUCCESS The certificate version retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL or cert_size is Zero. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool libspdm_x509_get_version(const uint8_t *cert, size_t cert_size, ++ size_t *version) ++{ ++ bool status; ++ X509 *x509_cert; ++ ++ x509_cert = NULL; ++ status = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!status)) { ++ ++ /* Invalid X.509 Certificate*/ ++ ++ status = false; ++ } ++ ++ if (status) { ++ *version = X509_get_version(x509_cert); ++ } ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ return status; ++} ++ ++/** ++ * Retrieve the serialNumber from one X.509 certificate. ++ * ++ * If cert is NULL, then return false. ++ * If cert_size is 0, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] serial_number Pointer to the retrieved certificate serial_number bytes. ++ * @param[in, out] serial_number_size The size in bytes of the serial_number buffer on input, ++ * and the size of buffer returned serial_number on output. ++ * ++ * @retval RETURN_SUCCESS The certificate serialNumber retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL or cert_size is Zero. ++ * If serial_number_size is NULL. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no serial_number exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the serial_number is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * serial_number_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ **/ ++bool libspdm_x509_get_serial_number(const uint8_t *cert, size_t cert_size, ++ uint8_t *serial_number, ++ size_t *serial_number_size) ++{ ++ X509 *x509_cert; ++ ASN1_INTEGER *asn1_integer; ++ bool status; ++ ++ status = false; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || serial_number_size == NULL) { ++ return status; ++ } ++ ++ x509_cert = NULL; ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ status = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!status)) { ++ *serial_number_size = 0; ++ status = false; ++ goto done; ++ } ++ ++ ++ /* Retrieve subject name from certificate object.*/ ++ ++ asn1_integer = X509_get_serialNumber(x509_cert); ++ if (asn1_integer == NULL) { ++ *serial_number_size = 0; ++ status = false; ++ goto done; ++ } ++ ++ if (*serial_number_size < (size_t)asn1_integer->length) { ++ *serial_number_size = (size_t)asn1_integer->length; ++ status = false; ++ goto done; ++ } ++ ++ if (serial_number != NULL) { ++ libspdm_copy_mem(serial_number, *serial_number_size, ++ asn1_integer->data, (size_t)asn1_integer->length); ++ status = true; ++ } ++ *serial_number_size = (size_t)asn1_integer->length; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return status; ++} ++ ++/** ++ * Retrieve the issuer bytes from one X.509 certificate. ++ * ++ * If cert is NULL, then return false. ++ * If issuer_size is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] cert_issuer Pointer to the retrieved certificate subject bytes. ++ * @param[in, out] issuer_size The size in bytes of the cert_issuer buffer on input, ++ * and the size of buffer returned cert_issuer on output. ++ * ++ * @retval true If the issuer_size is not equal 0. The certificate issuer retrieved successfully. ++ * @retval true If the issuer_size is equal 0. The certificate parse successful. But the cert doesn't have issuer. ++ * @retval false If the issuer_size is not equal 0. The certificate issuer retrieved successfully. But the issuer_size is too small for the result. ++ * @retval false If the issuer_size is equal 0. Invalid certificate. ++ * ++ **/ ++bool libspdm_x509_get_issuer_name(const uint8_t *cert, size_t cert_size, ++ uint8_t *cert_issuer, ++ size_t *issuer_size) ++{ ++ bool res; ++ X509 *x509_cert; ++ X509_NAME *x509_name; ++ size_t x509_name_size; ++ ++ /* Check input parameters.*/ ++ if (cert == NULL || cert_size == 0 || issuer_size == NULL) { ++ if (issuer_size != NULL) { ++ *issuer_size = 0; ++ } ++ return false; ++ } ++ ++ x509_cert = NULL; ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ *issuer_size = 0; ++ goto done; ++ } ++ ++ res = false; ++ ++ /* Retrieve issuer name from certificate object.*/ ++ x509_name = X509_get_issuer_name(x509_cert); ++ if (x509_name == NULL) { ++ *issuer_size = 0; ++ res = true; ++ goto done; ++ } ++ ++ x509_name_size = i2d_X509_NAME(x509_name, NULL); ++ if (*issuer_size < x509_name_size) { ++ *issuer_size = x509_name_size; ++ goto done; ++ } ++ *issuer_size = x509_name_size; ++ if (cert_issuer != NULL) { ++ i2d_X509_NAME(x509_name, &cert_issuer); ++ res = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return res; ++} ++ ++/** ++ * Retrieve the issuer common name (CN) string from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] common_name buffer to contain the retrieved certificate issuer common ++ * name string. At most common_name_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] common_name_size The size in bytes of the common_name buffer on input, ++ * and the size of buffer returned common_name on output. ++ * If common_name is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate Issuer common_name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If common_name_size is NULL. ++ * If common_name is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no common_name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the common_name is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool ++libspdm_x509_get_issuer_common_name(const uint8_t *cert, size_t cert_size, ++ char *common_name, ++ size_t *common_name_size) ++{ ++ return libspdm_internal_x509_get_issuer_nid_name( ++ cert, cert_size, NID_commonName, common_name, common_name_size); ++} ++ ++/** ++ * Retrieve the issuer organization name (O) string from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] name_buffer buffer to contain the retrieved certificate issuer organization ++ * name string. At most name_buffer_size bytes will be ++ * written and the string will be null terminated. May be ++ * NULL in order to determine the size buffer needed. ++ * @param[in,out] name_buffer_size The size in bytes of the name buffer on input, ++ * and the size of buffer returned name on output. ++ * If name_buffer is NULL then the amount of space needed ++ * in buffer (including the final null) is returned. ++ * ++ * @retval RETURN_SUCCESS The certificate issuer Organization name retrieved successfully. ++ * @retval RETURN_INVALID_PARAMETER If cert is NULL. ++ * If name_buffer_size is NULL. ++ * If name_buffer is not NULL and *common_name_size is 0. ++ * If Certificate is invalid. ++ * @retval RETURN_NOT_FOUND If no Organization name entry exists. ++ * @retval RETURN_BUFFER_TOO_SMALL If the name_buffer is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * common_name_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ * ++ **/ ++bool ++libspdm_x509_get_issuer_orgnization_name(const uint8_t *cert, size_t cert_size, ++ char *name_buffer, ++ size_t *name_buffer_size) ++{ ++ return libspdm_internal_x509_get_issuer_nid_name(cert, cert_size, ++ NID_organizationName, ++ name_buffer, name_buffer_size); ++} ++ ++#if LIBSPDM_ADDITIONAL_CHECK_CERT ++/** ++ * Retrieve the signature algorithm from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] oid signature algorithm Object identifier buffer. ++ * @param[in,out] oid_size signature algorithm Object identifier buffer size ++ * ++ * @retval true if the oid_size is equal 0, the cert parse successfully, but cert doesn't have signature algo. ++ * @retval true if the oid_size is not equal 0, the cert parse and get signature algo successfully. ++ * @retval false if the oid_size is equal 0, the cert parse failed. ++ * @retval false if the oid_size is not equal 0, the cert parse and get signature algo successfully, but the input buffer size is small. ++ **/ ++bool libspdm_x509_get_signature_algorithm(const uint8_t *cert, ++ size_t cert_size, uint8_t *oid, ++ size_t *oid_size) ++{ ++ bool status; ++ X509 *x509_cert; ++ int nid; ++ ASN1_OBJECT *asn1_obj; ++ size_t obj_length; ++ ++ /* Check input parameters.*/ ++ if (cert == NULL || cert_size == 0 || oid_size == NULL) { ++ if (oid_size != NULL) { ++ *oid_size = 0; ++ } ++ return false; ++ } ++ ++ x509_cert = NULL; ++ status = false; ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ status = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!status)) { ++ status = false; ++ *oid_size = 0; ++ goto done; ++ } ++ ++ /* Retrieve subject name from certificate object.*/ ++ nid = X509_get_signature_nid(x509_cert); ++ if (nid == NID_undef) { ++ *oid_size = 0; ++ status = true; ++ goto done; ++ } ++ asn1_obj = OBJ_nid2obj(nid); ++ if (asn1_obj == NULL) { ++ *oid_size = 0; ++ status = false; ++ goto done; ++ } ++ ++ obj_length = OBJ_length(asn1_obj); ++ if (*oid_size < obj_length) { ++ *oid_size = obj_length; ++ status = false; ++ goto done; ++ } ++ if (oid != NULL) { ++ libspdm_copy_mem(oid, *oid_size, OBJ_get0_data(asn1_obj), obj_length); ++ } ++ *oid_size = obj_length; ++ status = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return status; ++} ++#endif /* LIBSPDM_ADDITIONAL_CHECK_CERT */ ++ ++/** ++ * Retrieve the Validity from one X.509 certificate ++ * ++ * If cert is NULL, then return false. ++ * If CertIssuerSize is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] from notBefore Pointer to date_time object. ++ * @param[in,out] from_size notBefore date_time object size. ++ * @param[out] to notAfter Pointer to date_time object. ++ * @param[in,out] to_size notAfter date_time object size. ++ * ++ * Note: libspdm_x509_compare_date_time to compare date_time oject ++ * x509SetDateTime to get a date_time object from a date_time_str ++ * ++ * @retval true The certificate Validity retrieved successfully. ++ * @retval false Invalid certificate, or Validity retrieve failed. ++ * @retval false This interface is not supported. ++ **/ ++bool libspdm_x509_get_validity(const uint8_t *cert, size_t cert_size, ++ uint8_t *from, size_t *from_size, uint8_t *to, ++ size_t *to_size) ++{ ++ bool res; ++ X509 *x509_cert; ++ const ASN1_TIME *f_time; ++ const ASN1_TIME *t_time; ++ size_t t_size; ++ size_t f_size; ++ ++ /* Check input parameters.*/ ++ if (cert == NULL || from_size == NULL || to_size == NULL || ++ cert_size == 0) { ++ if (from_size != NULL) { ++ *from_size = 0; ++ } ++ if (to_size != NULL) { ++ *to_size = 0; ++ } ++ return false; ++ } ++ ++ x509_cert = NULL; ++ res = false; ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ *from_size = 0; ++ *to_size = 0; ++ res = false; ++ goto done; ++ } ++ ++ /* Retrieve Validity from/to from certificate object.*/ ++ f_time = X509_get0_notBefore(x509_cert); ++ t_time = X509_get0_notAfter(x509_cert); ++ ++ if (f_time == NULL || t_time == NULL) { ++ *from_size = 0; ++ *to_size = 0; ++ res = true; ++ goto done; ++ } ++ ++ f_size = sizeof(ASN1_TIME) + f_time->length; ++ if (*from_size < f_size) { ++ *from_size = f_size; ++ res = false; ++ goto done; ++ } ++ if (from != NULL) { ++ libspdm_copy_mem(from, *from_size, f_time, sizeof(ASN1_TIME)); ++ } ++ *from_size = f_size; ++ ++ t_size = sizeof(ASN1_TIME) + t_time->length; ++ if (*to_size < t_size) { ++ *to_size = t_size; ++ res = false; ++ goto done; ++ } ++ if (to != NULL) { ++ libspdm_copy_mem(to, *to_size, t_time, sizeof(ASN1_TIME)); ++ } ++ *to_size = t_size; ++ ++ res = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return res; ++} ++ ++/** ++ * format a date_time object into DataTime buffer ++ * ++ * If date_time_str is NULL, then return false. ++ * If date_time_size is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[in] date_time_str date_time string like YYYYMMDDhhmmssZ ++ * Ref: https://www.w3.org/TR/NOTE-datetime ++ * Z stand for UTC time ++ * @param[in,out] date_time Pointer to a date_time object. ++ * @param[in,out] date_time_size date_time object buffer size. ++ * ++ * @retval RETURN_SUCCESS The date_time object create successfully. ++ * @retval RETURN_INVALID_PARAMETER If date_time_str is NULL. ++ * If date_time_size is NULL. ++ * If date_time is not NULL and *date_time_size is 0. ++ * If year month day hour minute second combination is invalid datetime. ++ * @retval RETURN_BUFFER_TOO_SMALL If the date_time is NULL. The required buffer size ++ * (including the final null) is returned in the ++ * date_time_size parameter. ++ * @retval RETURN_UNSUPPORTED The operation is not supported. ++ **/ ++bool libspdm_x509_set_date_time(const char *date_time_str, void *date_time, size_t *date_time_size) ++{ ++ bool status; ++ int32_t ret; ++ ASN1_TIME *dt; ++ size_t d_size; ++ ++ dt = NULL; ++ status = false; ++ ++ dt = ASN1_TIME_new(); ++ if (dt == NULL) { ++ status = false; ++ goto cleanup; ++ } ++ ++ ret = ASN1_TIME_set_string_X509(dt, date_time_str); ++ if (ret != 1) { ++ status = false; ++ goto cleanup; ++ } ++ ++ d_size = sizeof(ASN1_TIME) + dt->length; ++ if (*date_time_size < d_size) { ++ *date_time_size = d_size; ++ status = false; ++ goto cleanup; ++ } ++ if (date_time != NULL) { ++ libspdm_copy_mem(date_time, *date_time_size, dt, sizeof(ASN1_TIME)); ++ } ++ *date_time_size = d_size; ++ status = true; ++ ++cleanup: ++ if (dt != NULL) { ++ ASN1_TIME_free(dt); ++ } ++ return status; ++} ++ ++/** ++ * Compare date_time1 object and date_time2 object. ++ * ++ * If date_time1 is NULL, then return -2. ++ * If date_time2 is NULL, then return -2. ++ * If date_time1 == date_time2, then return 0 ++ * If date_time1 > date_time2, then return 1 ++ * If date_time1 < date_time2, then return -1 ++ * ++ * @param[in] date_time1 Pointer to a date_time Ojbect ++ * @param[in] date_time2 Pointer to a date_time Object ++ * ++ * @retval 0 If date_time1 == date_time2 ++ * @retval 1 If date_time1 > date_time2 ++ * @retval -1 If date_time1 < date_time2 ++ **/ ++int32_t libspdm_x509_compare_date_time(const void *date_time1, const void *date_time2) ++{ ++ return (int32_t)ASN1_TIME_compare(date_time1, date_time2); ++} ++ ++/** ++ * Retrieve the key usage from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] usage key usage (LIBSPDM_CRYPTO_X509_KU_*) ++ * ++ * @retval true if the usage is no equal 0. The certificate key usage retrieved successfully. ++ * @retval true if the usage is equal 0. The certificate parse successfully, but the cert doesn't have key usage. ++ * @retval false Invalid certificate, or usage is NULL. ++ **/ ++bool libspdm_x509_get_key_usage(const uint8_t *cert, size_t cert_size, ++ size_t *usage) ++{ ++ bool res; ++ X509 *x509_cert; ++ ++ /* Check input parameters.*/ ++ if (cert == NULL || cert_size == 0 || usage == NULL) { ++ if (usage != NULL) { ++ *usage = 0; ++ } ++ return false; ++ } ++ ++ x509_cert = NULL; ++ res = false; ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ *usage = 0; ++ goto done; ++ } ++ ++ /* Retrieve key usage from certificate object.*/ ++ *usage = X509_get_key_usage(x509_cert); ++ res = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return res; ++} ++ ++/** ++ * Retrieve Extension data from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[in] oid Object identifier buffer ++ * @param[in] oid_size Object identifier buffer size ++ * @param[out] extension_data Extension bytes. ++ * @param[in, out] extension_data_size Extension bytes size. ++ * ++ * @retval true If the returned extension_data_size == 0, it means that cert and oid are valid, but the oid extension is not found; ++ * If the returned extension_data_size != 0, it means that cert and oid are valid, and the oid extension is found; ++ * @retval false If the returned extension_data_size == 0, it means that cert or oid are invalid; ++ * If the returned extension_data_size != 0, it means that cert and oid are valid, and the oid extension is found, ++ * but the store buffer is too small. ++ **/ ++bool libspdm_x509_get_extension_data(const uint8_t *cert, size_t cert_size, ++ const uint8_t *oid, size_t oid_size, ++ uint8_t *extension_data, ++ size_t *extension_data_size) ++{ ++ bool status; ++ int i; ++ X509 *x509_cert; ++ const STACK_OF(X509_EXTENSION) * extensions; ++ ASN1_OBJECT *asn1_obj; ++ ASN1_OCTET_STRING *asn1_oct; ++ X509_EXTENSION *ext; ++ size_t obj_length; ++ size_t oct_length; ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || cert_size == 0 || oid == NULL || oid_size == 0 || ++ extension_data_size == NULL) { ++ if (extension_data_size != NULL) { ++ *extension_data_size = 0; ++ } ++ return false; ++ } ++ ++ x509_cert = NULL; ++ status = false; ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ status = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if (!status) { ++ *extension_data_size = 0; ++ goto cleanup; ++ } ++ ++ /* Retrieve extensions from certificate object.*/ ++ ++ extensions = X509_get0_extensions(x509_cert); ++ if (sk_X509_EXTENSION_num((WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)*)extensions) <= 0) { ++ *extension_data_size = 0; ++ goto cleanup; ++ } ++ ++ /* Traverse extensions*/ ++ ++ status = false; ++ asn1_oct = NULL; ++ oct_length = 0; ++ for (i = 0; i < sk_X509_EXTENSION_num((WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)*)extensions); i++) { ++ ext = sk_X509_EXTENSION_value((WOLF_STACK_OF(WOLFSSL_X509_EXTENSION)*)extensions, (int)i); ++ if (ext == NULL) { ++ continue; ++ } ++ asn1_obj = X509_EXTENSION_get_object(ext); ++ if (asn1_obj == NULL) { ++ continue; ++ } ++ asn1_oct = X509_EXTENSION_get_data(ext); ++ if (asn1_oct == NULL) { ++ continue; ++ } ++ ++ obj_length = OBJ_length(asn1_obj); ++ oct_length = ASN1_STRING_length(asn1_oct); ++ ++ if ((oid_size == obj_length) && ++ libspdm_consttime_is_mem_equal(OBJ_get0_data(asn1_obj), oid, oid_size)) { ++ ++ /* Extension Found*/ ++ ++ status = true; ++ break; ++ } ++ ++ /* reset to 0 if not found */ ++ oct_length = 0; ++ } ++ ++ if (status) { ++ if (*extension_data_size < oct_length) { ++ *extension_data_size = oct_length; ++ status = false; ++ goto cleanup; ++ } ++ if (asn1_oct != NULL) { ++ libspdm_copy_mem(extension_data, *extension_data_size, ++ ASN1_STRING_get0_data(asn1_oct), oct_length); ++ } ++ *extension_data_size = oct_length; ++ } else { ++ /* the cert extension is found, but the oid extension is not found; */ ++ status = true; ++ *extension_data_size = 0; ++ } ++ ++cleanup: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return status; ++} ++ ++/** ++ * Retrieve the Extended key usage from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] usage key usage bytes. ++ * @param[in, out] usage_size key usage buffer sizs in bytes. ++ * ++ * @retval true If the returned usage_size == 0, it means that cert and oid are valid, but the Extended key usage is not found; ++ * If the returned usage_size != 0, it means that cert and oid are valid, and the Extended key usage is found; ++ * @retval false If the returned usage_size == 0, it means that cert or oid are invalid; ++ * If the returned usage_size != 0, it means that cert and oid are valid, and the Extended key usage is found, ++ * but the store buffer is too small. ++ **/ ++bool libspdm_x509_get_extended_key_usage(const uint8_t *cert, ++ size_t cert_size, uint8_t *usage, ++ size_t *usage_size) ++{ ++ bool status; ++ status = libspdm_x509_get_extension_data(cert, cert_size, ++ m_libspdm_oid_ext_key_usage, ++ sizeof(m_libspdm_oid_ext_key_usage), usage, ++ usage_size); ++ return status; ++} ++ ++/** ++ * Retrieve the basic constraints from one X.509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] basic_constraints basic constraints bytes. ++ * @param[in, out] basic_constraints_size basic constraints buffer sizs in bytes. ++ * ++ * @retval true If the returned basic_constraints_size == 0, it means that cert and oid are valid, but the basic_constraints is not found; ++ * If the returned basic_constraints_size != 0, it means that cert and oid are valid, and the basic_constraints is found; ++ * @retval false If the returned basic_constraints_size == 0, it means that cert or oid are invalid; ++ * If the returned basic_constraints_size != 0, it means that cert and oid are valid, and the basic_constraints is found, ++ * but the store buffer is too small. ++ **/ ++bool libspdm_x509_get_extended_basic_constraints(const uint8_t *cert, ++ size_t cert_size, ++ uint8_t *basic_constraints, ++ size_t *basic_constraints_size) ++{ ++ bool status; ++ ++ if (cert == NULL || cert_size == 0 || basic_constraints_size == NULL) { ++ return false; ++ } ++ status = libspdm_x509_get_extension_data((uint8_t *)cert, cert_size, ++ (uint8_t *)m_libspdm_oid_basic_constraints, ++ sizeof(m_libspdm_oid_basic_constraints), ++ basic_constraints, ++ basic_constraints_size); ++ return status; ++} ++ ++#if (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) ++/** ++ * Retrieve the RSA public key from one DER-encoded X509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] rsa_context Pointer to newly generated RSA context which contain the retrieved ++ * RSA public key component. Use libspdm_rsa_free() function to free the ++ * resource. ++ * ++ * If cert is NULL, then return false. ++ * If rsa_context is NULL, then return false. ++ * ++ * @retval true RSA public key was retrieved successfully. ++ * @retval false Fail to retrieve RSA public key from X509 certificate. ++ * ++ **/ ++bool libspdm_rsa_get_public_key_from_x509(const uint8_t *cert, size_t cert_size, ++ void **rsa_context) ++{ ++ bool res; ++ EVP_PKEY *pkey; ++ X509 *x509_cert; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || rsa_context == NULL) { ++ return false; ++ } ++ ++ pkey = NULL; ++ x509_cert = NULL; ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ goto done; ++ } ++ ++ res = false; ++ ++ ++ /* Retrieve and check EVP_PKEY data from X509 Certificate.*/ ++ ++ pkey = X509_get_pubkey(x509_cert); ++ if ((pkey == NULL) || (EVP_PKEY_id(pkey) != EVP_PKEY_RSA)) { ++ goto done; ++ } ++ ++ ++ /* Duplicate RSA context from the retrieved EVP_PKEY.*/ ++ ++ if ((*rsa_context = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey))) != ++ NULL) { ++ res = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ if (pkey != NULL) { ++ EVP_PKEY_free(pkey); ++ } ++ ++ return res; ++} ++#endif /* (LIBSPDM_RSA_SSA_SUPPORT) || (LIBSPDM_RSA_PSS_SUPPORT) */ ++ ++/** ++ * Retrieve the EC public key from one DER-encoded X509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] ec_context Pointer to newly generated EC DSA context which contain the retrieved ++ * EC public key component. Use libspdm_ec_free() function to free the ++ * resource. ++ * ++ * If cert is NULL, then return false. ++ * If ec_context is NULL, then return false. ++ * ++ * @retval true EC public key was retrieved successfully. ++ * @retval false Fail to retrieve EC public key from X509 certificate. ++ * ++ **/ ++bool libspdm_ec_get_public_key_from_x509(const uint8_t *cert, size_t cert_size, ++ void **ec_context) ++{ ++ bool res; ++ EVP_PKEY *pkey; ++ X509 *x509_cert; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || ec_context == NULL) { ++ return false; ++ } ++ ++ pkey = NULL; ++ x509_cert = NULL; ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ goto done; ++ } ++ ++ res = false; ++ ++ ++ /* Retrieve and check EVP_PKEY data from X509 Certificate.*/ ++ ++ pkey = X509_get_pubkey(x509_cert); ++ if ((pkey == NULL) || (EVP_PKEY_id(pkey) != EVP_PKEY_EC)) { ++ goto done; ++ } ++ ++ ++ /* Duplicate EC context from the retrieved EVP_PKEY.*/ ++ ++ if ((*ec_context = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey))) != NULL) { ++ res = true; ++ } ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ if (pkey != NULL) { ++ EVP_PKEY_free(pkey); ++ } ++ ++ return res; ++} ++ ++#if (LIBSPDM_EDDSA_ED25519_SUPPORT) || (LIBSPDM_EDDSA_ED448_SUPPORT) ++/** ++ * Retrieve the Ed public key from one DER-encoded X509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] ecd_context Pointer to newly generated Ed DSA context which contain the retrieved ++ * Ed public key component. Use libspdm_ecd_free() function to free the ++ * resource. ++ * ++ * If cert is NULL, then return false. ++ * If ecd_context is NULL, then return false. ++ * ++ * @retval true Ed public key was retrieved successfully. ++ * @retval false Fail to retrieve Ed public key from X509 certificate. ++ * ++ **/ ++bool libspdm_ecd_get_public_key_from_x509(const uint8_t *cert, size_t cert_size, ++ void **ecd_context) ++{ ++ bool res; ++ EVP_PKEY *pkey; ++ X509 *x509_cert; ++ int32_t type; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || ecd_context == NULL) { ++ return false; ++ } ++ ++ pkey = NULL; ++ x509_cert = NULL; ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ goto done; ++ } ++ ++ res = false; ++ ++ ++ /* Retrieve and check EVP_PKEY data from X509 Certificate.*/ ++ ++ pkey = X509_get_pubkey(x509_cert); ++ if (pkey == NULL) { ++ goto done; ++ } ++ type = EVP_PKEY_id(pkey); ++ if ((type != EVP_PKEY_ED25519) && (type != EVP_PKEY_ED448)) { ++ goto done; ++ } ++ ++ *ecd_context = pkey; ++ res = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return res; ++} ++#endif /* LIBSPDM_EDDSA_ED25519_SUPPORT || LIBSPDM_EDDSA_ED448_SUPPORT */ ++ ++#if LIBSPDM_SM2_DSA_P256_SUPPORT ++/** ++ * Retrieve the sm2 public key from one DER-encoded X509 certificate. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] sm2_context Pointer to newly generated sm2 context which contain the retrieved ++ * sm2 public key component. Use sm2_free() function to free the ++ * resource. ++ * ++ * If cert is NULL, then return false. ++ * If ecd_context is NULL, then return false. ++ * ++ * @retval true sm2 public key was retrieved successfully. ++ * @retval false Fail to retrieve sm2 public key from X509 certificate. ++ * ++ **/ ++bool libspdm_sm2_get_public_key_from_x509(const uint8_t *cert, size_t cert_size, ++ void **sm2_context) ++{ ++ bool res; ++ EVP_PKEY *pkey; ++ X509 *x509_cert; ++ int result; ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || sm2_context == NULL) { ++ return false; ++ } ++ ++ pkey = NULL; ++ x509_cert = NULL; ++ ++ ++ /* Read DER-encoded X509 Certificate and Construct X509 object.*/ ++ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ goto done; ++ } ++ ++ res = false; ++ ++ ++ /* Retrieve and check EVP_PKEY data from X509 Certificate.*/ ++ ++ pkey = X509_get_pubkey(x509_cert); ++ if (pkey == NULL) { ++ goto done; ++ } ++ ++ result = EVP_PKEY_is_a(pkey,"SM2"); ++ if (result == 0) { ++ goto done; ++ } ++ ++ *sm2_context = pkey; ++ res = true; ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ return res; ++} ++#endif /* LIBSPDM_SM2_DSA_P256_SUPPORT */ ++ ++/** ++ * Verify one X509 certificate was issued by the trusted CA. ++ * ++ * @param[in] cert Pointer to the DER-encoded X509 certificate to be verified. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[in] ca_cert Pointer to the DER-encoded trusted CA certificate. ++ * @param[in] ca_cert_size size of the CA Certificate in bytes. ++ * ++ * If cert is NULL, then return false. ++ * If ca_cert is NULL, then return false. ++ * ++ * @retval true The certificate was issued by the trusted CA. ++ * @retval false Invalid certificate or the certificate was not issued by the given ++ * trusted CA. ++ * ++ **/ ++bool libspdm_x509_verify_cert(const uint8_t *cert, size_t cert_size, ++ const uint8_t *ca_cert, size_t ca_cert_size) ++{ ++ bool res; ++ X509 *x509_cert; ++ X509 *x509_ca_cert; ++ X509_STORE *cert_store; ++ X509_STORE_CTX *cert_ctx; ++ ++ ++ /* Check input parameters.*/ ++ ++ if (cert == NULL || ca_cert == NULL) { ++ return false; ++ } ++ ++ res = false; ++ x509_cert = NULL; ++ x509_ca_cert = NULL; ++ cert_store = NULL; ++ cert_ctx = NULL; ++ ++ ++ /* Register & Initialize necessary digest algorithms for certificate verification.*/ ++ ++ if (EVP_add_digest(EVP_sha256()) == 0) { ++ goto done; ++ } ++ if (EVP_add_digest(EVP_sha384()) == 0) { ++ goto done; ++ } ++ if (EVP_add_digest(EVP_sha512()) == 0) { ++ goto done; ++ } ++ ++ ++ /* Read DER-encoded certificate to be verified and Construct X509 object.*/ ++ ++ res = libspdm_x509_construct_certificate(cert, cert_size, (uint8_t **)&x509_cert); ++ if ((x509_cert == NULL) || (!res)) { ++ res = false; ++ goto done; ++ } ++ ++ ++ /* Read DER-encoded root certificate and Construct X509 object.*/ ++ ++ res = libspdm_x509_construct_certificate(ca_cert, ca_cert_size, ++ (uint8_t **)&x509_ca_cert); ++ if ((x509_ca_cert == NULL) || (!res)) { ++ res = false; ++ goto done; ++ } ++ ++ res = false; ++ ++ ++ /* Set up X509 Store for trusted certificate.*/ ++ ++ cert_store = X509_STORE_new(); ++ if (cert_store == NULL) { ++ goto done; ++ } ++ if (!(X509_STORE_add_cert(cert_store, x509_ca_cert))) { ++ goto done; ++ } ++ ++ /* Allow partial certificate chains, terminated by a non-self-signed but ++ * still trusted intermediate certificate. ++ */ ++ ++ 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 ++ ++ /* Set up X509_STORE_CTX for the subsequent verification operation.*/ ++ ++ cert_ctx = X509_STORE_CTX_new(); ++ if (cert_ctx == NULL) { ++ goto done; ++ } ++ if (!X509_STORE_CTX_init(cert_ctx, cert_store, x509_cert, NULL)) { ++ goto done; ++ } ++ ++ ++ /* X509 Certificate Verification.*/ ++ res = (X509_verify_cert(cert_ctx) <= 0) ? false : true; ++ X509_STORE_CTX_cleanup(cert_ctx); ++ ++done: ++ ++ /* Release Resources.*/ ++ ++ if (x509_cert != NULL) { ++ X509_free(x509_cert); ++ } ++ ++ if (x509_ca_cert != NULL) { ++ X509_free(x509_ca_cert); ++ } ++ ++ if (cert_store != NULL) { ++ X509_STORE_free(cert_store); ++ } ++ ++ X509_STORE_CTX_free(cert_ctx); ++ ++ return res; ++} ++ ++/** ++ * Retrieve the TBSCertificate from one given X.509 certificate. ++ * ++ * @param[in] cert Pointer to the given DER-encoded X509 certificate. ++ * @param[in] cert_size size of the X509 certificate in bytes. ++ * @param[out] tbs_cert DER-Encoded to-Be-Signed certificate. ++ * @param[out] tbs_cert_size size of the TBS certificate in bytes. ++ * ++ * If cert is NULL, then return false. ++ * If tbs_cert is NULL, then return false. ++ * If tbs_cert_size is NULL, then return false. ++ * ++ * @retval true The TBSCertificate was retrieved successfully. ++ * @retval false Invalid X.509 certificate. ++ * ++ **/ ++bool libspdm_x509_get_tbs_cert(const uint8_t *cert, size_t cert_size, ++ uint8_t **tbs_cert, size_t *tbs_cert_size) ++{ ++ const uint8_t *temp; ++ uint32_t asn1_tag; ++ uint32_t obj_class; ++ size_t length; ++ ++ ++ /* Check input parameters.*/ ++ ++ if ((cert == NULL) || (tbs_cert == NULL) || (tbs_cert_size == NULL) || ++ (cert_size > INT_MAX)) { ++ return false; ++ } ++ ++ ++ /* An X.509 Certificate is: (defined in RFC3280) ++ * Certificate ::= SEQUENCE { ++ * tbsCertificate TBSCertificate, ++ * signatureAlgorithm AlgorithmIdentifier, ++ * signature BIT STRING }*/ ++ ++ /* and*/ ++ ++ /* TBSCertificate ::= SEQUENCE { ++ * version [0] version DEFAULT v1, ++ * ... ++ * }*/ ++ ++ /* So we can just ASN1-parse the x.509 DER-encoded data. If we strip ++ * the first SEQUENCE, the second SEQUENCE is the TBSCertificate.*/ ++ ++ temp = cert; ++ length = 0; ++ ASN1_get_object(&temp, (long *)&length, (int *)&asn1_tag, ++ (int *)&obj_class, (long)cert_size); ++ ++ if (asn1_tag != V_ASN1_SEQUENCE) { ++ return false; ++ } ++ ++ *tbs_cert = (uint8_t *)temp; ++ ++ ASN1_get_object(&temp, (long *)&length, (int *)&asn1_tag, ++ (int *)&obj_class, (long)length); ++ ++ /* Verify the parsed TBSCertificate is one correct SEQUENCE data.*/ ++ ++ if (asn1_tag != V_ASN1_SEQUENCE) { ++ return false; ++ } ++ ++ *tbs_cert_size = length + (temp - *tbs_cert); ++ ++ return true; ++} ++ ++/** ++ * Verify one X509 certificate was issued by the trusted CA. ++ * ++ * @param[in] cert_chain One or more ASN.1 DER-encoded X.509 certificates ++ * where the first certificate is signed by the Root ++ * Certificate or is the Root Cerificate itself. and ++ * subsequent cerificate is signed by the preceding ++ * cerificate. ++ * @param[in] cert_chain_length Total length of the certificate chain, in bytes. ++ * ++ * @param[in] root_cert Trusted Root Certificate buffer ++ * ++ * @param[in] root_cert_length Trusted Root Certificate buffer length ++ * ++ * @retval true All cerificates was issued by the first certificate in X509Certchain. ++ * @retval false Invalid certificate or the certificate was not issued by the given ++ * trusted CA. ++ **/ ++bool libspdm_x509_verify_cert_chain(const uint8_t *root_cert, size_t root_cert_length, ++ const uint8_t *cert_chain, size_t cert_chain_length) ++{ ++ const uint8_t *tmp_ptr; ++ size_t length; ++ uint32_t asn1_tag; ++ uint32_t obj_class; ++ const uint8_t *current_cert; ++ size_t current_cert_len; ++ const uint8_t *preceding_cert; ++ size_t preceding_cert_len; ++ bool verify_flag; ++ int32_t ret; ++ uint8_t *root_ptr; ++ uint8_t *chain_ptr; ++ size_t root_obj_len; ++ size_t chain_obj_len; ++ uint8_t *end; ++ ++ preceding_cert = root_cert; ++ preceding_cert_len = root_cert_length; ++ ++ current_cert = cert_chain; ++ length = 0; ++ current_cert_len = 0; ++ ++ root_ptr = (uint8_t*)(size_t)root_cert; ++ end = root_ptr + root_cert_length; ++ verify_flag = libspdm_asn1_get_tag( ++ &root_ptr, end, &root_obj_len, ++ LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ if (!verify_flag) { ++ return false; ++ } ++ ++ chain_ptr = (uint8_t*)(size_t)cert_chain; ++ end = chain_ptr + cert_chain_length; ++ verify_flag = libspdm_asn1_get_tag( ++ &chain_ptr, end, &chain_obj_len, ++ LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ if (!verify_flag) { ++ return false; ++ } ++ ++ /*only self_signed cert is accepted when these two cert are same*/ ++ if ((chain_obj_len == root_obj_len) && ++ (libspdm_consttime_is_mem_equal(root_ptr, chain_ptr, root_obj_len)) && ++ (!libspdm_is_root_certificate(root_cert, root_cert_length))) { ++ return false; ++ } ++ ++ verify_flag = false; ++ while (true) { ++ tmp_ptr = current_cert; ++ ret = ASN1_get_object( ++ (const uint8_t **)&tmp_ptr, (long *)&length, ++ (int *)&asn1_tag, (int *)&obj_class, ++ (long)(cert_chain_length + cert_chain - tmp_ptr)); ++ if (asn1_tag != V_ASN1_SEQUENCE || ret & OPENSSL_ASN1_ERROR_MASK) { ++ break; ++ } ++ ++ ++ /* Calculate current_cert length;*/ ++ ++ current_cert_len = tmp_ptr - current_cert + length; ++ if (current_cert + current_cert_len > cert_chain + cert_chain_length) { ++ verify_flag = false; ++ break; ++ } ++ ++ ++ /* Verify current_cert with preceding cert;*/ ++ ++ verify_flag = ++ libspdm_x509_verify_cert(current_cert, current_cert_len, ++ preceding_cert, preceding_cert_len); ++ if (verify_flag == false) { ++ break; ++ } ++ ++ ++ /* move Current cert to Preceding cert*/ ++ ++ preceding_cert_len = current_cert_len; ++ preceding_cert = current_cert; ++ ++ ++ /* Move to next*/ ++ ++ current_cert = current_cert + current_cert_len; ++ } ++ ++ return verify_flag; ++} ++ ++/** ++ * Get one X509 certificate from cert_chain. ++ * ++ * @param[in] cert_chain One or more ASN.1 DER-encoded X.509 certificates ++ * where the first certificate is signed by the Root ++ * Certificate or is the Root Cerificate itself. and ++ * subsequent cerificate is signed by the preceding ++ * cerificate. ++ * @param[in] cert_chain_length Total length of the certificate chain, in bytes. ++ * ++ * @param[in] cert_index index of certificate. ++ * ++ * @param[out] cert The certificate at the index of cert_chain. ++ * @param[out] cert_length The length certificate at the index of cert_chain. ++ * ++ * @retval true Success. ++ * @retval false Failed to get certificate from certificate chain. ++ **/ ++bool libspdm_x509_get_cert_from_cert_chain(const uint8_t *cert_chain, ++ size_t cert_chain_length, ++ const int32_t cert_index, const uint8_t **cert, ++ size_t *cert_length) ++{ ++ size_t asn1_len; ++ int32_t current_index; ++ size_t current_cert_len; ++ const uint8_t *current_cert; ++ const uint8_t *tmp_ptr; ++ int32_t ret; ++ uint32_t asn1_tag; ++ uint32_t obj_class; ++ ++ ++ /* Check input parameters.*/ ++ ++ if ((cert_chain == NULL) || (cert == NULL) || (cert_index < -1) || ++ (cert_length == NULL)) { ++ return false; ++ } ++ ++ asn1_len = 0; ++ current_cert_len = 0; ++ current_cert = cert_chain; ++ current_index = -1; ++ ++ ++ /* Traverse the certificate chain*/ ++ ++ while (true) { ++ tmp_ptr = current_cert; ++ ++ /* Get asn1 object and taglen*/ ++ ret = ASN1_get_object( ++ (const uint8_t **)&tmp_ptr, (long *)&asn1_len, ++ (int *)&asn1_tag, (int *)&obj_class, ++ (long)(cert_chain_length + cert_chain - tmp_ptr)); ++ if (asn1_tag != V_ASN1_SEQUENCE || ret & OPENSSL_ASN1_ERROR_MASK) { ++ break; ++ } ++ ++ /* Calculate current_cert length;*/ ++ ++ current_cert_len = tmp_ptr - current_cert + asn1_len; ++ current_index++; ++ ++ if (current_index == cert_index) { ++ *cert = current_cert; ++ *cert_length = current_cert_len; ++ return true; ++ } ++ ++ ++ /* Move to next*/ ++ ++ current_cert = current_cert + current_cert_len; ++ } ++ ++ ++ /* If cert_index is -1, Return the last certificate*/ ++ ++ if (cert_index == -1 && current_index >= 0) { ++ *cert = current_cert - current_cert_len; ++ *cert_length = current_cert_len; ++ return true; ++ } ++ ++ return false; ++} ++ ++size_t libspdm_get_str_len(char *dst) ++{ ++ char *p = dst; ++ ++ if (dst == NULL) { ++ return 0; ++ } ++ ++ while (*p != '\0') ++ { ++ p++; ++ } ++ ++ return p - dst; ++} ++ ++char *libspdm_strstr(char *src, char *dst) ++{ ++ size_t index; ++ ++ if ((src == NULL) || (dst == NULL)) { ++ return NULL; ++ } ++ ++ if (libspdm_get_str_len(src) < libspdm_get_str_len(dst)) { ++ return NULL; ++ } ++ ++ for (index = 0; index < libspdm_get_str_len(src) - libspdm_get_str_len(dst); index++) { ++ if ((*(src + index) == *dst) && ++ libspdm_consttime_is_mem_equal(src + index, dst, libspdm_get_str_len(dst))) { ++ return (src + index); ++ } ++ } ++ ++ return NULL; ++} ++ ++bool libspdm_set_subject_name(X509_NAME *x509_name, char *subject_name) ++{ ++ int ret; ++ uint8_t index; ++ char *char_start; ++ char *char_end; ++ char temp[MAX_SBUJECT_NAME_LEN]; ++ char *end_case = ","; ++ ++ ret = 0; ++ char_start = NULL; ++ char_end = NULL; ++ ++ /* X.509 DN attributes from RFC 5280, Appendix A.1. */ ++ char *subject_set[] = { ++ "CN", "commonName", "C", "countryName", "O", "organizationName","L", "OU", ++ "organizationalUnitName", "ST", "stateOrProvinceName", "emailAddress", "serialNumber", ++ "postalAddress", "postalCode", "dnQualifier", "title", "SN","givenName","GN", ++ "initials", "pseudonym", "generationQualifier", "domainComponent", "DC" ++ }; ++ ++ ++ for (index = 0; index < sizeof(subject_set)/sizeof(subject_set[0]); index++) ++ { ++ ++ char_start = libspdm_strstr(subject_name, subject_set[index]); ++ ++ /* find object in subject_set and the next is '=' */ ++ if ((char_start != NULL) && ++ (*(char_start + libspdm_get_str_len(subject_set[index])) == '=')) { ++ ++ char_start += (libspdm_get_str_len(subject_set[index]) + 1); ++ /*end with ','*/ ++ char_end = libspdm_strstr(char_start, end_case); ++ if (char_end != NULL) { ++ libspdm_copy_mem(temp, MAX_SBUJECT_NAME_LEN, char_start, char_end - char_start); ++ temp[char_end - char_start] = '\0'; ++ } else { ++ /*end with '\0'*/ ++ char_end = subject_name + libspdm_get_str_len(subject_name); ++ libspdm_copy_mem(temp, MAX_SBUJECT_NAME_LEN, char_start, char_end - char_start); ++ temp[char_end - char_start] = '\0'; ++ } ++ ++ ret = X509_NAME_add_entry_by_txt(x509_name, subject_set[index], MBSTRING_ASC, ++ (const unsigned char*)temp, -1, -1, 0); ++ if (ret != 1) { ++ LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"set subject error\n")); ++ return false; ++ } ++ } ++ char_start = NULL; ++ } ++ ++ return true; ++} ++ ++/** ++ * Set all attributes object form req_info to CSR ++ * ++ * @param[in] req CSR to set attributes ++ * @param[in] req_info requester info to gen CSR ++ * @param[in] req_info_len The len of requester info ++ * ++ * @retval true Success Set. ++ * @retval false Set failed. ++ **/ ++bool libspdm_set_attribute_for_req(X509_REQ *req, uint8_t *req_info, size_t req_info_len, ++ EVP_PKEY *public_key) ++{ ++ uint8_t *ptr; ++ int32_t length; ++ size_t obj_len; ++ bool ret; ++ uint8_t *end; ++ uint8_t *ptr_old; ++ ++ uint8_t *oid; ++ size_t oid_len; ++ uint8_t *val; ++ size_t val_len; ++ size_t nid; ++ ASN1_OBJECT *oid_asn1_obj; ++ const unsigned char *oid_for_d2i; ++ ++ uint8_t *pubkey_info; ++ size_t pubkey_info_len; ++ uint8_t *der_data; ++ int32_t der_len; ++ X509_REQ_INFO *x509_req_info; ++ ++ x509_req_info = NULL; ++ der_data = NULL; ++ der_len = 0; ++ length = (int32_t)req_info_len; ++ ptr = req_info; ++ obj_len = 0; ++ end = ptr + length; ++ ret = false; ++ ++ if (req_info == NULL) { ++ return false; ++ } ++ ++ /*get subject name from req_info and set it to CSR*/ ++ x509_req_info = d2i_X509_REQ_INFO(NULL, (const unsigned char **)(&req_info), req_info_len); ++ if (x509_req_info) { ++ X509_REQ_set_subject_name(req, X509_REQ_get_subject_name((X509_REQ *)x509_req_info)); ++ X509_REQ_INFO_free(x509_req_info); ++ } else { ++ return false; ++ } ++ ++ /*req_info sequence, all req_info format is ok because the req_info has been verified before*/ ++ ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, ++ LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ ++ /*integer:version*/ ++ ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, LIBSPDM_CRYPTO_ASN1_INTEGER); ++ /*check req_info verson. spec PKCS#10: It shall be 0 for this version of the standard.*/ ++ if ((obj_len != 1) || (*ptr != 0)) { ++ return false; ++ } ++ ptr += obj_len; ++ ++ /*sequence:subject name*/ ++ ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, ++ LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ ptr += obj_len; ++ ++ /*sequence:subject pkinfo*/ ++ pubkey_info = ptr; ++ ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, ++ LIBSPDM_CRYPTO_ASN1_SEQUENCE | LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ ++ pubkey_info_len = obj_len + (ptr - pubkey_info); ++ der_len = i2d_PUBKEY(public_key, &der_data); ++ /*check the public key info*/ ++ if (!((der_len > 0) && (der_len == pubkey_info_len) && ++ (libspdm_consttime_is_mem_equal(pubkey_info, der_data, der_len)))) { ++ if (der_data != NULL) { ++ OPENSSL_free(der_data); ++ } ++ return false; ++ } ++ OPENSSL_free(der_data); ++ ptr += obj_len; ++ ++ /*get attributes from req_info and set them to CSR*/ ++ ++ /*[0]: attributes*/ ++ ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, ++ LIBSPDM_CRYPTO_ASN1_CONTEXT_SPECIFIC | ++ LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ /*there is no attributes*/ ++ if (ptr == end) { ++ return true; ++ } ++ ++ /*there is some attributes object: 1,2 ...*/ ++ while (ret) ++ { ++ ret = libspdm_asn1_get_tag(&ptr, end, &obj_len, ++ LIBSPDM_CRYPTO_ASN1_SEQUENCE | ++ LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ if (ret) { ++ /*save old positon*/ ++ ptr_old = ptr; ++ ++ /*move to the next sequence*/ ++ ptr += obj_len; ++ ++ /*get attributes oid*/ ++ ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, LIBSPDM_CRYPTO_ASN1_OID); ++ if (!ret) { ++ return false; ++ } ++ ++ /*the whole oid include: LIBSPDM_CRYPTO_ASN1_OID and obj_len*/ ++ oid = ptr_old - 2; ++ oid_len = obj_len + 2; ++ ++ ptr_old += obj_len; ++ /*get attributes val*/ ++ ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, ++ LIBSPDM_CRYPTO_ASN1_SET | ++ LIBSPDM_CRYPTO_ASN1_CONSTRUCTED); ++ if (!ret) { ++ return false; ++ } ++ ret = libspdm_asn1_get_tag(&ptr_old, end, &obj_len, LIBSPDM_CRYPTO_ASN1_UTF8_STRING); ++ if (!ret) { ++ return false; ++ } ++ val = ptr_old; ++ val_len = obj_len; ++ ++ /*transfer oid to nid*/ ++ oid_for_d2i = oid; ++ oid_asn1_obj = d2i_ASN1_OBJECT(NULL, &oid_for_d2i, oid_len); ++ nid = OBJ_obj2nid(oid_asn1_obj); ++ ASN1_OBJECT_free(oid_asn1_obj); ++ ++ /*set attributes*/ ++ ret = X509_REQ_add1_attr_by_NID(req, nid, ++ V_ASN1_UTF8STRING, ++ (const unsigned char *)val, ++ val_len); ++ if (ret == 0) { ++ return false; ++ } ++ ++ } else { ++ break; ++ } ++ } ++ ++ if (ptr == end) { ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++/** ++ * Gen CSR ++ * ++ * @param[in] hash_nid hash algo for sign ++ * @param[in] asym_nid asym algo for sign ++ * ++ * @param[in] requester_info requester info to gen CSR ++ * @param[in] requester_info_length The len of requester info ++ * ++ * @param[in] is_ca if true, set basic_constraints: CA:true; Otherwise, set to false. ++ * ++ * @param[in] context Pointer to asymmetric context ++ * @param[in] subject_name Subject name: should be break with ',' in the middle ++ * example: "C=AA,CN=BB" ++ * Subject names should contain a comma-separated list of OID types and values: ++ * The valid OID type name is in: ++ * {"CN", "commonName", "C", "countryName", "O", "organizationName","L", ++ * "OU", "organizationalUnitName", "ST", "stateOrProvinceName", "emailAddress", ++ * "serialNumber", "postalAddress", "postalCode", "dnQualifier", "title", ++ * "SN","givenName","GN", "initials", "pseudonym", "generationQualifier", "domainComponent", "DC"}. ++ * Note: The object of C and countryName should be CSR Supported Country Codes ++ * ++ * @param[in, out] csr_len For input, csr_len is the size of store CSR buffer. ++ * For output, csr_len is CSR len for DER format ++ * @param[in, out] csr_pointer For input, csr_pointer is buffer address to store CSR. ++ * For output, csr_pointer is address for stored CSR. ++ * The csr_pointer address will be changed. ++ * @param[in] base_cert An optional leaf certificate whose ++ * extensions should be copied to the CSR ++ * ++ * @retval true Success. ++ * @retval false Failed to gen CSR. ++ **/ ++bool libspdm_gen_x509_csr(size_t hash_nid, size_t asym_nid, ++ uint8_t *requester_info, size_t requester_info_length, ++ bool is_ca, ++ void *context, char *subject_name, ++ size_t *csr_len, uint8_t *csr_pointer, ++ void *base_cert) ++{ ++ int ret; ++ int version; ++ ++ X509_REQ *x509_req; ++ X509_NAME *x509_name; ++ EVP_PKEY *private_key; ++ EVP_PKEY *public_key; ++ RSA *rsa_public_key; ++ EC_KEY *ec_public_key; ++ const EVP_MD *md; ++ uint8_t *csr_p; ++ STACK_OF(X509_EXTENSION) *exts; ++ X509_EXTENSION *basic_constraints_ext; ++ int num_exts; ++ ++ exts = NULL; ++ basic_constraints_ext = NULL; ++ ret = 0; ++ version = 0; ++ ++ x509_req = NULL; ++ x509_name = NULL; ++ private_key = NULL; ++ public_key = NULL; ++ rsa_public_key = NULL; ++ ec_public_key = NULL; ++ md = NULL; ++ csr_p = csr_pointer; ++ num_exts = 0; ++ ++ x509_req = X509_REQ_new(); ++ if (x509_req == NULL) { ++ return false; ++ } ++ ++ private_key = EVP_PKEY_new(); ++ if (private_key == NULL) { ++ X509_REQ_free(x509_req); ++ return false; ++ } ++ ++ public_key = EVP_PKEY_new(); ++ if (public_key == NULL) { ++ X509_REQ_free(x509_req); ++ EVP_PKEY_free(private_key); ++ return false; ++ } ++ ++ switch (asym_nid) ++ { ++ case LIBSPDM_CRYPTO_NID_RSASSA2048: ++ case LIBSPDM_CRYPTO_NID_RSAPSS2048: ++ case LIBSPDM_CRYPTO_NID_RSASSA3072: ++ case LIBSPDM_CRYPTO_NID_RSAPSS3072: ++ case LIBSPDM_CRYPTO_NID_RSASSA4096: ++ case LIBSPDM_CRYPTO_NID_RSAPSS4096: ++ ret = EVP_PKEY_set1_RSA(private_key, (RSA *)context); ++ if (ret != 1) { ++ goto free_all; ++ } ++ ++ rsa_public_key = RSAPublicKey_dup((RSA *)context); ++ EVP_PKEY_assign_RSA(public_key, rsa_public_key); ++ break; ++ case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P256: ++ case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P384: ++ case LIBSPDM_CRYPTO_NID_ECDSA_NIST_P521: ++ ret = EVP_PKEY_set1_EC_KEY(private_key, (EC_KEY *)context); ++ if (ret != 1) { ++ goto free_all; ++ } ++ ++ ec_public_key = EC_KEY_dup((EC_KEY *)context); ++ EVP_PKEY_assign_EC_KEY(public_key, ec_public_key); ++ break; ++ default: ++ goto free_all; ++ } ++ ++ /*set version of x509 req*/ ++ ret = X509_REQ_set_version(x509_req, version); ++ if (ret != 1) { ++ LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"set version error\n")); ++ goto free_all; ++ } ++ ++ /*set subject of x509 req*/ ++ x509_name = X509_REQ_get_subject_name(x509_req); ++ ++ if (subject_name != NULL) { ++ ret = libspdm_set_subject_name(x509_name, subject_name); ++ if (ret != 1) { ++ goto free_all; ++ } ++ } ++ ++ /* requester info parse ++ * check the req_info version and subjectPKInfo; ++ * get attribute and subject from req_info and set them to CSR; ++ **/ ++ if (requester_info_length != 0) { ++ ret = libspdm_set_attribute_for_req(x509_req, requester_info, requester_info_length, ++ public_key); ++ if (ret == 0) { ++ goto free_all; ++ } ++ } ++ ++ /*set public key for x509 req: the public key is from private key*/ ++ ret = X509_REQ_set_pubkey(x509_req, private_key); ++ if (ret != 1) { ++ LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"set public key error\n")); ++ goto free_all; ++ } ++ ++ /*get hash algo*/ ++ switch (hash_nid) { ++ case LIBSPDM_CRYPTO_NID_SHA256: ++ md = EVP_sha256(); ++ break; ++ case LIBSPDM_CRYPTO_NID_SHA384: ++ md = EVP_sha384(); ++ break; ++ case LIBSPDM_CRYPTO_NID_SHA512: ++ md = EVP_sha512(); ++ break; ++ case LIBSPDM_CRYPTO_NID_SHA3_256: ++ md = EVP_sha3_256(); ++ break; ++ case LIBSPDM_CRYPTO_NID_SHA3_384: ++ md = EVP_sha3_384(); ++ break; ++ case LIBSPDM_CRYPTO_NID_SHA3_512: ++ md = EVP_sha3_512(); ++ break; ++#ifdef WOLFSSL_SM3 ++ case LIBSPDM_CRYPTO_NID_SM3_256: ++ md = EVP_sm3(); ++ break; ++#endif ++ default: ++ ret = 0; ++ goto free_all; ++ } ++ ++ /*gen basicConstraints*/ ++ exts = sk_X509_EXTENSION_new_null(); ++ if (!exts) { ++ ret = 0; ++ goto free_all; ++ } ++ ++ /*set basicConstraints*/ ++ basic_constraints_ext = X509V3_EXT_conf_nid( ++ NULL, NULL, NID_basic_constraints, ++ is_ca ? "CA:TRUE" : "CA:FALSE"); ++ if (!basic_constraints_ext) { ++ sk_X509_EXTENSION_free(exts); ++ ret = 0; ++ goto free_all; ++ } ++ sk_X509_EXTENSION_push(exts, basic_constraints_ext); ++ ++ if (base_cert != NULL) { ++ const ASN1_OBJECT *basic_constraints_obj = OBJ_nid2obj(NID_basic_constraints); ++ const ASN1_OBJECT *authority_key_identifier_obj = OBJ_nid2obj(NID_authority_key_identifier); ++ ++ num_exts = X509_get_ext_count(base_cert); ++ ++ for (int i = 0; i < num_exts; i++) { ++ X509_EXTENSION *extension = X509_get_ext(base_cert, i); ++ ASN1_OBJECT *obj = X509_EXTENSION_get_object(extension); ++ ++ if (OBJ_cmp(basic_constraints_obj, obj) == 0) { ++ continue; ++ } ++ ++ if (OBJ_cmp(authority_key_identifier_obj, obj) == 0) { ++ continue; ++ } ++ ++ sk_X509_EXTENSION_push(exts, extension); ++ } ++ } ++ ++ X509_REQ_add_extensions(x509_req, exts); ++ sk_X509_EXTENSION_free(exts); ++ ++ /*sign for x509 req*/ ++ ret = X509_REQ_sign(x509_req, private_key, md); ++ if (ret <= 0) { ++ ret = 0; ++ LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"sign csr error\n")); ++ goto free_all; ++ } ++ ++ ret = i2d_X509_REQ(x509_req, &csr_p); ++ if (ret <= 0) { ++ ret = 0; ++ LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"i2d_X509_REQ error\n")); ++ goto free_all; ++ } else { ++ *csr_len = ret; ++ } ++ ++ /*free*/ ++free_all: ++ X509_REQ_free(x509_req); ++ EVP_PKEY_free(private_key); ++ EVP_PKEY_free(public_key); ++ ++ return (ret != 0); ++} ++ ++#endif +diff --git a/os_stub/cryptlib_wolfssl/rand/rand.c b/os_stub/cryptlib_wolfssl/rand/rand.c +new file mode 100644 +index 0000000000..fea47fc7ea +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/rand/rand.c +@@ -0,0 +1,40 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * Pseudorandom Number generator Wrapper Implementation. ++ **/ ++ ++#include "internal_crypt_lib.h" ++#include ++#include ++ ++/** ++ * Generates a random byte stream of the specified size. ++ * ++ * If output is NULL, then return false. ++ * If this interface is not supported, then return false. ++ * ++ * @param[out] output Pointer to buffer to receive random value. ++ * @param[in] size Size of random bytes to generate. ++ * ++ * @retval true Random byte stream generated successfully. ++ * @retval false Generation of random byte stream failed. ++ **/ ++bool libspdm_random_bytes(uint8_t *output, size_t size) ++{ ++ /* Check input parameters. */ ++ if (output == NULL || size > INT_MAX) { ++ return false; ++ } ++ ++ /* Generate random data. */ ++ if (RAND_bytes(output, size) != 1) { ++ return false; ++ } ++ ++ return true; ++} +diff --git a/os_stub/cryptlib_wolfssl/sys_call/crt_wrapper_host.c b/os_stub/cryptlib_wolfssl/sys_call/crt_wrapper_host.c +new file mode 100644 +index 0000000000..265d6153a7 +--- /dev/null ++++ b/os_stub/cryptlib_wolfssl/sys_call/crt_wrapper_host.c +@@ -0,0 +1,120 @@ ++/** ++ * Copyright Notice: ++ * Copyright 2021-2022 DMTF. All rights reserved. ++ * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md ++ **/ ++ ++/** @file ++ * C Run-Time Libraries (CRT) Wrapper Implementation. ++ **/ ++ ++#include ++ ++#include ++#include "library/debuglib.h" ++#include "internal_crypt_lib.h" ++#include ++ ++/* Convert character to lowercase */ ++int tolower(int c) ++{ ++ if (('A' <= (c)) && ((c) <= 'Z')) { ++ return (c - ('A' - 'a')); ++ } ++ return (c); ++} ++ ++/* Compare first n bytes of string s1 with string s2, ignoring case */ ++int strncasecmp(const char *s1, const char *s2, size_t n) ++{ ++ int val; ++ ++ LIBSPDM_ASSERT(s1 != NULL); ++ LIBSPDM_ASSERT(s2 != NULL); ++ if (s1 == NULL || s2 == NULL) { ++ return -1; ++ } ++ ++ if (n != 0) { ++ do { ++ val = tolower(*s1) - tolower(*s2); ++ if (val != 0) { ++ return val; ++ } ++ ++s1; ++ ++s2; ++ if (*s1 == '\0') { ++ break; ++ } ++ } while (--n != 0); ++ } ++ return 0; ++} ++ ++int strcasecmp(const char *s1, const char *s2) ++{ ++ int val; ++ ++ LIBSPDM_ASSERT(s1 != NULL); ++ LIBSPDM_ASSERT(s2 != NULL); ++ if (s1 == NULL || s2 == NULL) { ++ return -1; ++ } ++ ++ while ((*s1 != '\0') && (*s2 != '\0')) { ++ val = tolower(*s1) - tolower(*s2); ++ if (val != 0) { ++ return val; ++ } ++ ++s1; ++ ++s2; ++ } ++ ++ val = tolower(*s1) - tolower(*s2); ++ return val; ++} ++ ++/* Read formatted data from a string */ ++int sscanf(const char *buffer, const char *format, ...) ++{ ++ ++ /* Null sscanf() function implementation to satisfy the linker, since ++ * no direct functionality logic dependency in present cases.*/ ++ ++ return 0; ++} ++ ++ ++/* -- Dummy OpenSSL Support Routines --*/ ++ ++ ++uid_t getuid(void) ++{ ++ return 0; ++} ++ ++uid_t geteuid(void) ++{ ++ return 0; ++} ++ ++gid_t getgid(void) ++{ ++ return 0; ++} ++ ++gid_t getegid(void) ++{ ++ return 0; ++} ++ ++#if !defined(__GNUC__) && !defined(_WIN32) ++int GetLastError () ++{ ++ return 0; ++} ++#endif ++ ++void SetLastError(int e) ++{ ++} +-- +2.34.1 +