From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Library/BaseCryptLib/BaseCryptLib.inf | 108 +++ .../Library/BaseCryptLib/BaseCryptLib.uni | 19 + .../Library/BaseCryptLib/Cipher/CryptAes.c | 203 +++++ .../Library/BaseCryptLib/Cipher/CryptAesNull.c | 107 +++ .../CryptoPkg/Library/BaseCryptLib/Hash/CryptMd5.c | 226 +++++ .../Library/BaseCryptLib/Hash/CryptSha1.c | 225 +++++ .../Library/BaseCryptLib/Hash/CryptSha256.c | 223 +++++ .../Library/BaseCryptLib/Hash/CryptSha512.c | 440 ++++++++++ .../Library/BaseCryptLib/Hash/CryptSha512Null.c | 275 +++++++ .../CryptoPkg/Library/BaseCryptLib/Hash/CryptSm3.c | 234 ++++++ .../Library/BaseCryptLib/Hmac/CryptHmacSha256.c | 216 +++++ .../BaseCryptLib/Hmac/CryptHmacSha256Null.c | 139 ++++ .../Library/BaseCryptLib/InternalCryptLib.h | 62 ++ .../CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c | 75 ++ .../Library/BaseCryptLib/Kdf/CryptHkdfNull.c | 43 + .../CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf | 98 +++ .../CryptoPkg/Library/BaseCryptLib/PeiCryptLib.uni | 25 + .../CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c | 126 +++ .../Library/BaseCryptLib/Pem/CryptPemNull.c | 38 + .../Library/BaseCryptLib/Pk/CryptAuthenticode.c | 192 +++++ .../BaseCryptLib/Pk/CryptAuthenticodeNull.c | 45 + .../CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c | 306 +++++++ .../Library/BaseCryptLib/Pk/CryptDhNull.c | 150 ++++ .../Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c | 208 +++++ .../Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c | 51 ++ .../Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c | 95 +++ .../Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c | 50 ++ .../Library/BaseCryptLib/Pk/CryptPkcs7Sign.c | 194 +++++ .../Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c | 54 ++ .../Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c | 190 +++++ .../BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c | 910 +++++++++++++++++++++ .../Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c | 517 ++++++++++++ .../BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c | 57 ++ .../Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c | 163 ++++ .../BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c | 39 + .../Library/BaseCryptLib/Pk/CryptRsaBasic.c | 327 ++++++++ .../Library/BaseCryptLib/Pk/CryptRsaExt.c | 364 +++++++++ .../Library/BaseCryptLib/Pk/CryptRsaExtNull.c | 119 +++ .../Library/BaseCryptLib/Pk/CryptRsaPss.c | 152 ++++ .../Library/BaseCryptLib/Pk/CryptRsaPssNull.c | 46 ++ .../Library/BaseCryptLib/Pk/CryptRsaPssSign.c | 175 ++++ .../Library/BaseCryptLib/Pk/CryptRsaPssSignNull.c | 60 ++ .../CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c | 659 +++++++++++++++ .../Library/BaseCryptLib/Pk/CryptTsNull.c | 42 + .../CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c | 832 +++++++++++++++++++ .../Library/BaseCryptLib/Pk/CryptX509Null.c | 294 +++++++ .../Library/BaseCryptLib/Rand/CryptRand.c | 104 +++ .../Library/BaseCryptLib/Rand/CryptRandNull.c | 57 ++ .../Library/BaseCryptLib/Rand/CryptRandTsc.c | 112 +++ .../Library/BaseCryptLib/RuntimeCryptLib.inf | 113 +++ .../Library/BaseCryptLib/RuntimeCryptLib.uni | 24 + .../CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf | 103 +++ .../CryptoPkg/Library/BaseCryptLib/SmmCryptLib.uni | 24 + .../BaseCryptLib/SysCall/BaseMemAllocation.c | 112 +++ .../BaseCryptLib/SysCall/ConstantTimeClock.c | 37 + .../Library/BaseCryptLib/SysCall/CrtWrapper.c | 473 +++++++++++ .../BaseCryptLib/SysCall/RuntimeMemAllocation.c | 455 +++++++++++ .../Library/BaseCryptLib/SysCall/TimerWrapper.c | 168 ++++ .../BaseCryptLib/SysCall/UnitTestHostCrtWrapper.c | 93 +++ .../Library/BaseCryptLib/SysCall/inet_pton.c | 257 ++++++ .../BaseCryptLib/UnitTestHostBaseCryptLib.inf | 92 +++ 61 files changed, 11397 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAes.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAesNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptMd5.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha1.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha256.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512Null.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSm3.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256Null.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/InternalCryptLib.h create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdfNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPss.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSignNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRand.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandNull.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandTsc.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.uni create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/ConstantTimeClock.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/UnitTestHostCrtWrapper.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c create mode 100644 src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/UnitTestHostBaseCryptLib.inf (limited to 'src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib') diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf new file mode 100644 index 00000000..e560479f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf @@ -0,0 +1,108 @@ +## @file +# Cryptographic Library Instance for DXE_DRIVER. +# +# Caution: This module requires additional review when modified. +# This library will have external input - signature. +# This external input must be validated carefully to avoid security issues such as +# buffer overflow or integer overflow. +# +# Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseCryptLib + MODULE_UNI_FILE = BaseCryptLib.uni + FILE_GUID = be3bb803-91b6-4da0-bd91-a8b21c18ca5d + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = BaseCryptLib|DXE_DRIVER DXE_CORE UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 RISCV64 +# + +[Sources] + InternalCryptLib.h + Hash/CryptMd5.c + Hash/CryptSha1.c + Hash/CryptSha256.c + Hash/CryptSha512.c + Hash/CryptSm3.c + Hmac/CryptHmacSha256.c + Kdf/CryptHkdf.c + Cipher/CryptAes.c + Pk/CryptRsaBasic.c + Pk/CryptRsaExt.c + Pk/CryptPkcs1Oaep.c + Pk/CryptPkcs5Pbkdf2.c + Pk/CryptPkcs7Sign.c + Pk/CryptPkcs7VerifyCommon.c + Pk/CryptPkcs7VerifyBase.c + Pk/CryptPkcs7VerifyEku.c + Pk/CryptDh.c + Pk/CryptX509.c + Pk/CryptAuthenticode.c + Pk/CryptTs.c + Pk/CryptRsaPss.c + Pk/CryptRsaPssSign.c + Pem/CryptPem.c + + SysCall/CrtWrapper.c + SysCall/TimerWrapper.c + SysCall/BaseMemAllocation.c + SysCall/inet_pton.c + +[Sources.Ia32] + Rand/CryptRandTsc.c + +[Sources.X64] + Rand/CryptRandTsc.c + +[Sources.ARM] + Rand/CryptRand.c + +[Sources.AARCH64] + Rand/CryptRand.c + +[Sources.RISCV64] + Rand/CryptRand.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiRuntimeServicesTableLib + DebugLib + OpensslLib + IntrinsicLib + PrintLib + +# +# Remove these [BuildOptions] after this library is cleaned up +# +[BuildOptions] + # + # suppress the following warnings so we do not break the build with warnings-as-errors: + # C4090: 'function' : different 'const' qualifiers + # + MSFT:*_*_*_CC_FLAGS = /wd4090 + + # -JCryptoPkg/Include : To disable the use of the system includes provided by RVCT + # --diag_remark=1 : Reduce severity of "#1-D: last line of file ends without a newline" + RVCT:*_*_ARM_CC_FLAGS = -JCryptoPkg/Include --diag_remark=1 + + GCC:*_CLANG35_*_CC_FLAGS = -std=c99 + GCC:*_CLANG38_*_CC_FLAGS = -std=c99 + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + + XCODE:*_*_*_CC_FLAGS = -std=c99 diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.uni b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.uni new file mode 100644 index 00000000..ed1852ef --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.uni @@ -0,0 +1,19 @@ +// /** @file +// Cryptographic Library Instance for DXE_DRIVER. +// +// Caution: This module requires additional review when modified. +// This library will have external input - signature. +// This external input must be validated carefully to avoid security issues such as +// buffer overflow or integer overflow. +// +// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Cryptographic Library Instance for DXE_DRIVER" + +#string STR_MODULE_DESCRIPTION #language en-US "Caution: This module requires additional review when modified. This library will have external input - signature. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow." + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAes.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAes.c new file mode 100644 index 00000000..ac561272 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAes.c @@ -0,0 +1,203 @@ +/** @file + AES Wrapper Implementation over OpenSSL. + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + Retrieves the size, in bytes, of the context buffer required for AES operations. + + @return The size, in bytes, of the context buffer required for AES operations. + +**/ +UINTN +EFIAPI +AesGetContextSize ( + VOID + ) +{ + // + // AES uses different key contexts for encryption and decryption, so here memory + // for 2 copies of AES_KEY is allocated. + // + return (UINTN) (2 * sizeof (AES_KEY)); +} + +/** + Initializes user-supplied memory as AES context for subsequent use. + + This function initializes user-supplied memory pointed by AesContext as AES context. + In addition, it sets up all AES key materials for subsequent encryption and decryption + operations. + There are 3 options for key length, 128 bits, 192 bits, and 256 bits. + + If AesContext is NULL, then return FALSE. + If Key is NULL, then return FALSE. + If KeyLength is not valid, then return FALSE. + + @param[out] AesContext Pointer to AES context being initialized. + @param[in] Key Pointer to the user-supplied AES key. + @param[in] KeyLength Length of AES key in bits. + + @retval TRUE AES context initialization succeeded. + @retval FALSE AES context initialization failed. + +**/ +BOOLEAN +EFIAPI +AesInit ( + OUT VOID *AesContext, + IN CONST UINT8 *Key, + IN UINTN KeyLength + ) +{ + AES_KEY *AesKey; + + // + // Check input parameters. + // + if (AesContext == NULL || Key == NULL || (KeyLength != 128 && KeyLength != 192 && KeyLength != 256)) { + return FALSE; + } + + // + // Initialize AES encryption & decryption key schedule. + // + AesKey = (AES_KEY *) AesContext; + if (AES_set_encrypt_key (Key, (UINT32) KeyLength, AesKey) != 0) { + return FALSE; + } + if (AES_set_decrypt_key (Key, (UINT32) KeyLength, AesKey + 1) != 0) { + return FALSE; + } + return TRUE; +} + +/** + Performs AES encryption on a data buffer of the specified size in CBC mode. + + This function performs AES encryption on data buffer pointed by Input, of specified + size of InputSize, in CBC mode. + InputSize must be multiple of block size (16 bytes). This function does not perform + padding. Caller must perform padding, if necessary, to ensure valid input data size. + Initialization vector should be one block size (16 bytes). + AesContext should be already correctly initialized by AesInit(). Behavior with + invalid AES context is undefined. + + If AesContext is NULL, then return FALSE. + If Input is NULL, then return FALSE. + If InputSize is not multiple of block size (16 bytes), then return FALSE. + If Ivec is NULL, then return FALSE. + If Output is NULL, then return FALSE. + + @param[in] AesContext Pointer to the AES context. + @param[in] Input Pointer to the buffer containing the data to be encrypted. + @param[in] InputSize Size of the Input buffer in bytes. + @param[in] Ivec Pointer to initialization vector. + @param[out] Output Pointer to a buffer that receives the AES encryption output. + + @retval TRUE AES encryption succeeded. + @retval FALSE AES encryption failed. + +**/ +BOOLEAN +EFIAPI +AesCbcEncrypt ( + IN VOID *AesContext, + IN CONST UINT8 *Input, + IN UINTN InputSize, + IN CONST UINT8 *Ivec, + OUT UINT8 *Output + ) +{ + AES_KEY *AesKey; + UINT8 IvecBuffer[AES_BLOCK_SIZE]; + + // + // Check input parameters. + // + if (AesContext == NULL || Input == NULL || (InputSize % AES_BLOCK_SIZE) != 0) { + return FALSE; + } + + if (Ivec == NULL || Output == NULL || InputSize > INT_MAX) { + return FALSE; + } + + AesKey = (AES_KEY *) AesContext; + CopyMem (IvecBuffer, Ivec, AES_BLOCK_SIZE); + + // + // Perform AES data encryption with CBC mode + // + AES_cbc_encrypt (Input, Output, (UINT32) InputSize, AesKey, IvecBuffer, AES_ENCRYPT); + + return TRUE; +} + +/** + Performs AES decryption on a data buffer of the specified size in CBC mode. + + This function performs AES decryption on data buffer pointed by Input, of specified + size of InputSize, in CBC mode. + InputSize must be multiple of block size (16 bytes). This function does not perform + padding. Caller must perform padding, if necessary, to ensure valid input data size. + Initialization vector should be one block size (16 bytes). + AesContext should be already correctly initialized by AesInit(). Behavior with + invalid AES context is undefined. + + If AesContext is NULL, then return FALSE. + If Input is NULL, then return FALSE. + If InputSize is not multiple of block size (16 bytes), then return FALSE. + If Ivec is NULL, then return FALSE. + If Output is NULL, then return FALSE. + + @param[in] AesContext Pointer to the AES context. + @param[in] Input Pointer to the buffer containing the data to be encrypted. + @param[in] InputSize Size of the Input buffer in bytes. + @param[in] Ivec Pointer to initialization vector. + @param[out] Output Pointer to a buffer that receives the AES encryption output. + + @retval TRUE AES decryption succeeded. + @retval FALSE AES decryption failed. + +**/ +BOOLEAN +EFIAPI +AesCbcDecrypt ( + IN VOID *AesContext, + IN CONST UINT8 *Input, + IN UINTN InputSize, + IN CONST UINT8 *Ivec, + OUT UINT8 *Output + ) +{ + AES_KEY *AesKey; + UINT8 IvecBuffer[AES_BLOCK_SIZE]; + + // + // Check input parameters. + // + if (AesContext == NULL || Input == NULL || (InputSize % AES_BLOCK_SIZE) != 0) { + return FALSE; + } + + if (Ivec == NULL || Output == NULL || InputSize > INT_MAX) { + return FALSE; + } + + AesKey = (AES_KEY *) AesContext; + CopyMem (IvecBuffer, Ivec, AES_BLOCK_SIZE); + + // + // Perform AES data decryption with CBC mode + // + AES_cbc_encrypt (Input, Output, (UINT32) InputSize, AesKey + 1, IvecBuffer, AES_DECRYPT); + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAesNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAesNull.c new file mode 100644 index 00000000..40d94c66 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Cipher/CryptAesNull.c @@ -0,0 +1,107 @@ +/** @file + AES Wrapper Implementation which does not provide real capabilities. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Retrieves the size, in bytes, of the context buffer required for AES operations. + + Return zero to indicate this interface is not supported. + + @retval 0 This interface is not supported. + +**/ +UINTN +EFIAPI +AesGetContextSize ( + VOID + ) +{ + ASSERT (FALSE); + return 0; +} + +/** + Initializes user-supplied memory as AES context for subsequent use. + + Return FALSE to indicate this interface is not supported. + + @param[out] AesContext Pointer to AES context being initialized. + @param[in] Key Pointer to the user-supplied AES key. + @param[in] KeyLength Length of AES key in bits. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +AesInit ( + OUT VOID *AesContext, + IN CONST UINT8 *Key, + IN UINTN KeyLength + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Performs AES encryption on a data buffer of the specified size in CBC mode. + + Return FALSE to indicate this interface is not supported. + + @param[in] AesContext Pointer to the AES context. + @param[in] Input Pointer to the buffer containing the data to be encrypted. + @param[in] InputSize Size of the Input buffer in bytes. + @param[in] Ivec Pointer to initialization vector. + @param[out] Output Pointer to a buffer that receives the AES encryption output. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +AesCbcEncrypt ( + IN VOID *AesContext, + IN CONST UINT8 *Input, + IN UINTN InputSize, + IN CONST UINT8 *Ivec, + OUT UINT8 *Output + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Performs AES decryption on a data buffer of the specified size in CBC mode. + + Return FALSE to indicate this interface is not supported. + + @param[in] AesContext Pointer to the AES context. + @param[in] Input Pointer to the buffer containing the data to be encrypted. + @param[in] InputSize Size of the Input buffer in bytes. + @param[in] Ivec Pointer to initialization vector. + @param[out] Output Pointer to a buffer that receives the AES encryption output. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +AesCbcDecrypt ( + IN VOID *AesContext, + IN CONST UINT8 *Input, + IN UINTN InputSize, + IN CONST UINT8 *Ivec, + OUT UINT8 *Output + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptMd5.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptMd5.c new file mode 100644 index 00000000..2625f049 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptMd5.c @@ -0,0 +1,226 @@ +/** @file + MD5 Digest Wrapper Implementation over OpenSSL. + +Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +#ifdef ENABLE_MD5_DEPRECATED_INTERFACES +/** + Retrieves the size, in bytes, of the context buffer required for MD5 hash operations. + + @return The size, in bytes, of the context buffer required for MD5 hash operations. + +**/ +UINTN +EFIAPI +Md5GetContextSize ( + VOID + ) +{ + // + // Retrieves the OpenSSL MD5 Context Size + // + return (UINTN) (sizeof (MD5_CTX)); +} + + +/** + Initializes user-supplied memory pointed by Md5Context as MD5 hash context for + subsequent use. + + If Md5Context is NULL, then return FALSE. + + @param[out] Md5Context Pointer to MD5 context being initialized. + + @retval TRUE MD5 context initialization succeeded. + @retval FALSE MD5 context initialization failed. + +**/ +BOOLEAN +EFIAPI +Md5Init ( + OUT VOID *Md5Context + ) +{ + // + // Check input parameters. + // + if (Md5Context == NULL) { + return FALSE; + } + + // + // OpenSSL MD5 Context Initialization + // + return (BOOLEAN) (MD5_Init ((MD5_CTX *) Md5Context)); +} + +/** + Makes a copy of an existing MD5 context. + + If Md5Context is NULL, then return FALSE. + If NewMd5Context is NULL, then return FALSE. + + @param[in] Md5Context Pointer to MD5 context being copied. + @param[out] NewMd5Context Pointer to new MD5 context. + + @retval TRUE MD5 context copy succeeded. + @retval FALSE MD5 context copy failed. + +**/ +BOOLEAN +EFIAPI +Md5Duplicate ( + IN CONST VOID *Md5Context, + OUT VOID *NewMd5Context + ) +{ + // + // Check input parameters. + // + if (Md5Context == NULL || NewMd5Context == NULL) { + return FALSE; + } + + CopyMem (NewMd5Context, Md5Context, sizeof (MD5_CTX)); + + return TRUE; +} + +/** + Digests the input data and updates MD5 context. + + This function performs MD5 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. + MD5 context should be already correctly initialized by Md5Init(), and should not be finalized + by Md5Final(). Behavior with invalid context is undefined. + + If Md5Context is NULL, then return FALSE. + + @param[in, out] Md5Context Pointer to the MD5 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE MD5 data digest succeeded. + @retval FALSE MD5 data digest failed. + +**/ +BOOLEAN +EFIAPI +Md5Update ( + IN OUT VOID *Md5Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (Md5Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in OpenSSL + // + if (Data == NULL && (DataSize != 0)) { + return FALSE; + } + + // + // OpenSSL MD5 Hash Update + // + return (BOOLEAN) (MD5_Update ((MD5_CTX *) Md5Context, Data, DataSize)); +} + +/** + Completes computation of the MD5 digest value. + + This function completes MD5 hash computation and retrieves the digest value into + the specified memory. After this function has been called, the MD5 context cannot + be used again. + MD5 context should be already correctly initialized by Md5Init(), and should not be + finalized by Md5Final(). Behavior with invalid MD5 context is undefined. + + If Md5Context is NULL, then return FALSE. + If HashValue is NULL, then return FALSE. + + @param[in, out] Md5Context Pointer to the MD5 context. + @param[out] HashValue Pointer to a buffer that receives the MD5 digest + value (16 bytes). + + @retval TRUE MD5 digest computation succeeded. + @retval FALSE MD5 digest computation failed. + +**/ +BOOLEAN +EFIAPI +Md5Final ( + IN OUT VOID *Md5Context, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (Md5Context == NULL || HashValue == NULL) { + return FALSE; + } + + // + // OpenSSL MD5 Hash Finalization + // + return (BOOLEAN) (MD5_Final (HashValue, (MD5_CTX *) Md5Context)); +} + +/** + Computes the MD5 message digest of a input data buffer. + + This function performs the MD5 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] DataSize Size of Data buffer in bytes. + @param[out] HashValue Pointer to a buffer that receives the MD5 digest + value (16 bytes). + + @retval TRUE MD5 digest computation succeeded. + @retval FALSE MD5 digest computation failed. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Md5HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (HashValue == NULL) { + return FALSE; + } + if (Data == NULL && (DataSize != 0)) { + return FALSE; + } + + // + // OpenSSL MD5 Hash Computation. + // + if (MD5 (Data, DataSize, HashValue) == NULL) { + return FALSE; + } else { + return TRUE; + } +} +#endif diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha1.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha1.c new file mode 100644 index 00000000..5e951621 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha1.c @@ -0,0 +1,225 @@ +/** @file + SHA-1 Digest Wrapper Implementation over OpenSSL. + +Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES +/** + Retrieves the size, in bytes, of the context buffer required for SHA-1 hash operations. + + @return The size, in bytes, of the context buffer required for SHA-1 hash operations. + +**/ +UINTN +EFIAPI +Sha1GetContextSize ( + VOID + ) +{ + // + // Retrieves OpenSSL SHA Context Size + // + return (UINTN) (sizeof (SHA_CTX)); +} + +/** + Initializes user-supplied memory pointed by Sha1Context as SHA-1 hash context for + subsequent use. + + If Sha1Context is NULL, then return FALSE. + + @param[out] Sha1Context Pointer to SHA-1 context being initialized. + + @retval TRUE SHA-1 context initialization succeeded. + @retval FALSE SHA-1 context initialization failed. + +**/ +BOOLEAN +EFIAPI +Sha1Init ( + OUT VOID *Sha1Context + ) +{ + // + // Check input parameters. + // + if (Sha1Context == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-1 Context Initialization + // + return (BOOLEAN) (SHA1_Init ((SHA_CTX *) Sha1Context)); +} + +/** + Makes a copy of an existing SHA-1 context. + + If Sha1Context is NULL, then return FALSE. + If NewSha1Context is NULL, then return FALSE. + + @param[in] Sha1Context Pointer to SHA-1 context being copied. + @param[out] NewSha1Context Pointer to new SHA-1 context. + + @retval TRUE SHA-1 context copy succeeded. + @retval FALSE SHA-1 context copy failed. + +**/ +BOOLEAN +EFIAPI +Sha1Duplicate ( + IN CONST VOID *Sha1Context, + OUT VOID *NewSha1Context + ) +{ + // + // Check input parameters. + // + if (Sha1Context == NULL || NewSha1Context == NULL) { + return FALSE; + } + + CopyMem (NewSha1Context, Sha1Context, sizeof (SHA_CTX)); + + return TRUE; +} + +/** + Digests the input data and updates SHA-1 context. + + This function performs SHA-1 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-1 context should be already correctly initialized by Sha1Init(), and should not be finalized + by Sha1Final(). Behavior with invalid context is undefined. + + If Sha1Context is NULL, then return FALSE. + + @param[in, out] Sha1Context Pointer to the SHA-1 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE SHA-1 data digest succeeded. + @retval FALSE SHA-1 data digest failed. + +**/ +BOOLEAN +EFIAPI +Sha1Update ( + IN OUT VOID *Sha1Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (Sha1Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in OpenSSL + // + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-1 Hash Update + // + return (BOOLEAN) (SHA1_Update ((SHA_CTX *) Sha1Context, Data, DataSize)); +} + +/** + Completes computation of the SHA-1 digest value. + + This function completes SHA-1 hash computation and retrieves the digest value into + the specified memory. After this function has been called, the SHA-1 context cannot + be used again. + SHA-1 context should be already correctly initialized by Sha1Init(), and should not be + finalized by Sha1Final(). Behavior with invalid SHA-1 context is undefined. + + If Sha1Context is NULL, then return FALSE. + If HashValue is NULL, then return FALSE. + + @param[in, out] Sha1Context Pointer to the SHA-1 context. + @param[out] HashValue Pointer to a buffer that receives the SHA-1 digest + value (20 bytes). + + @retval TRUE SHA-1 digest computation succeeded. + @retval FALSE SHA-1 digest computation failed. + +**/ +BOOLEAN +EFIAPI +Sha1Final ( + IN OUT VOID *Sha1Context, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (Sha1Context == NULL || HashValue == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-1 Hash Finalization + // + return (BOOLEAN) (SHA1_Final (HashValue, (SHA_CTX *) Sha1Context)); +} + +/** + Computes the SHA-1 message digest of a input data buffer. + + This function performs the SHA-1 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] DataSize Size of Data buffer in bytes. + @param[out] HashValue Pointer to a buffer that receives the SHA-1 digest + value (20 bytes). + + @retval TRUE SHA-1 digest computation succeeded. + @retval FALSE SHA-1 digest computation failed. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha1HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (HashValue == NULL) { + return FALSE; + } + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-1 Hash Computation. + // + if (SHA1 (Data, DataSize, HashValue) == NULL) { + return FALSE; + } else { + return TRUE; + } +} +#endif diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha256.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha256.c new file mode 100644 index 00000000..d65b0619 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha256.c @@ -0,0 +1,223 @@ +/** @file + SHA-256 Digest Wrapper Implementation over OpenSSL. + +Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + Retrieves the size, in bytes, of the context buffer required for SHA-256 hash operations. + + @return The size, in bytes, of the context buffer required for SHA-256 hash operations. + +**/ +UINTN +EFIAPI +Sha256GetContextSize ( + VOID + ) +{ + // + // Retrieves OpenSSL SHA-256 Context Size + // + return (UINTN) (sizeof (SHA256_CTX)); +} + +/** + Initializes user-supplied memory pointed by Sha256Context as SHA-256 hash context for + subsequent use. + + If Sha256Context is NULL, then return FALSE. + + @param[out] Sha256Context Pointer to SHA-256 context being initialized. + + @retval TRUE SHA-256 context initialization succeeded. + @retval FALSE SHA-256 context initialization failed. + +**/ +BOOLEAN +EFIAPI +Sha256Init ( + OUT VOID *Sha256Context + ) +{ + // + // Check input parameters. + // + if (Sha256Context == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-256 Context Initialization + // + return (BOOLEAN) (SHA256_Init ((SHA256_CTX *) Sha256Context)); +} + +/** + Makes a copy of an existing SHA-256 context. + + If Sha256Context is NULL, then return FALSE. + If NewSha256Context is NULL, then return FALSE. + + @param[in] Sha256Context Pointer to SHA-256 context being copied. + @param[out] NewSha256Context Pointer to new SHA-256 context. + + @retval TRUE SHA-256 context copy succeeded. + @retval FALSE SHA-256 context copy failed. + +**/ +BOOLEAN +EFIAPI +Sha256Duplicate ( + IN CONST VOID *Sha256Context, + OUT VOID *NewSha256Context + ) +{ + // + // Check input parameters. + // + if (Sha256Context == NULL || NewSha256Context == NULL) { + return FALSE; + } + + CopyMem (NewSha256Context, Sha256Context, sizeof (SHA256_CTX)); + + return TRUE; +} + +/** + 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 Sha256Init(), and should not be finalized + by Sha256Final(). Behavior with invalid context is undefined. + + If Sha256Context is NULL, then return FALSE. + + @param[in, out] Sha256Context Pointer to the SHA-256 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE SHA-256 data digest succeeded. + @retval FALSE SHA-256 data digest failed. + +**/ +BOOLEAN +EFIAPI +Sha256Update ( + IN OUT VOID *Sha256Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (Sha256Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in OpenSSL + // + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-256 Hash Update + // + return (BOOLEAN) (SHA256_Update ((SHA256_CTX *) Sha256Context, Data, DataSize)); +} + +/** + 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 Sha256Init(), and should not be + finalized by Sha256Final(). Behavior with invalid SHA-256 context is undefined. + + If Sha256Context is NULL, then return FALSE. + If HashValue is NULL, then return FALSE. + + @param[in, out] Sha256Context Pointer to the SHA-256 context. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sha256Final ( + IN OUT VOID *Sha256Context, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (Sha256Context == NULL || HashValue == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-256 Hash Finalization + // + return (BOOLEAN) (SHA256_Final (HashValue, (SHA256_CTX *) Sha256Context)); +} + +/** + 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] DataSize Size of Data buffer in bytes. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sha256HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (HashValue == NULL) { + return FALSE; + } + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-256 Hash Computation. + // + if (SHA256 (Data, DataSize, HashValue) == NULL) { + return FALSE; + } else { + return TRUE; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512.c new file mode 100644 index 00000000..bee25a0a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512.c @@ -0,0 +1,440 @@ +/** @file + SHA-384 and SHA-512 Digest Wrapper Implementations over OpenSSL. + +Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + Retrieves the size, in bytes, of the context buffer required for SHA-384 hash operations. + + @return The size, in bytes, of the context buffer required for SHA-384 hash operations. + +**/ +UINTN +EFIAPI +Sha384GetContextSize ( + VOID + ) +{ + // + // Retrieves OpenSSL SHA-384 Context Size + // + return (UINTN) (sizeof (SHA512_CTX)); +} + +/** + Initializes user-supplied memory pointed by Sha384Context as SHA-384 hash context for + subsequent use. + + If Sha384Context is NULL, then return FALSE. + + @param[out] Sha384Context Pointer to SHA-384 context being initialized. + + @retval TRUE SHA-384 context initialization succeeded. + @retval FALSE SHA-384 context initialization failed. + +**/ +BOOLEAN +EFIAPI +Sha384Init ( + OUT VOID *Sha384Context + ) +{ + // + // Check input parameters. + // + if (Sha384Context == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-384 Context Initialization + // + return (BOOLEAN) (SHA384_Init ((SHA512_CTX *) Sha384Context)); +} + +/** + Makes a copy of an existing SHA-384 context. + + If Sha384Context is NULL, then return FALSE. + If NewSha384Context is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] Sha384Context Pointer to SHA-384 context being copied. + @param[out] NewSha384Context 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. + +**/ +BOOLEAN +EFIAPI +Sha384Duplicate ( + IN CONST VOID *Sha384Context, + OUT VOID *NewSha384Context + ) +{ + // + // Check input parameters. + // + if (Sha384Context == NULL || NewSha384Context == NULL) { + return FALSE; + } + + CopyMem (NewSha384Context, Sha384Context, sizeof (SHA512_CTX)); + + return TRUE; +} + +/** + 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 Sha384Init(), and should not be finalized + by Sha384Final(). Behavior with invalid context is undefined. + + If Sha384Context is NULL, then return FALSE. + + @param[in, out] Sha384Context Pointer to the SHA-384 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE SHA-384 data digest succeeded. + @retval FALSE SHA-384 data digest failed. + +**/ +BOOLEAN +EFIAPI +Sha384Update ( + IN OUT VOID *Sha384Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (Sha384Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in OpenSSL + // + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-384 Hash Update + // + return (BOOLEAN) (SHA384_Update ((SHA512_CTX *) Sha384Context, Data, DataSize)); +} + +/** + 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 Sha384Init(), and should not be + finalized by Sha384Final(). Behavior with invalid SHA-384 context is undefined. + + If Sha384Context is NULL, then return FALSE. + If HashValue is NULL, then return FALSE. + + @param[in, out] Sha384Context Pointer to the SHA-384 context. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sha384Final ( + IN OUT VOID *Sha384Context, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (Sha384Context == NULL || HashValue == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-384 Hash Finalization + // + return (BOOLEAN) (SHA384_Final (HashValue, (SHA512_CTX *) Sha384Context)); +} + +/** + 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] DataSize Size of Data buffer in bytes. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sha384HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (HashValue == NULL) { + return FALSE; + } + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-384 Hash Computation. + // + if (SHA384 (Data, DataSize, HashValue) == NULL) { + return FALSE; + } else { + return TRUE; + } +} + +/** + Retrieves the size, in bytes, of the context buffer required for SHA-512 hash operations. + + @return The size, in bytes, of the context buffer required for SHA-512 hash operations. + +**/ +UINTN +EFIAPI +Sha512GetContextSize ( + VOID + ) +{ + // + // Retrieves OpenSSL SHA-512 Context Size + // + return (UINTN) (sizeof (SHA512_CTX)); +} + +/** + Initializes user-supplied memory pointed by Sha512Context as SHA-512 hash context for + subsequent use. + + If Sha512Context is NULL, then return FALSE. + + @param[out] Sha512Context Pointer to SHA-512 context being initialized. + + @retval TRUE SHA-512 context initialization succeeded. + @retval FALSE SHA-512 context initialization failed. + +**/ +BOOLEAN +EFIAPI +Sha512Init ( + OUT VOID *Sha512Context + ) +{ + // + // Check input parameters. + // + if (Sha512Context == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-512 Context Initialization + // + return (BOOLEAN) (SHA512_Init ((SHA512_CTX *) Sha512Context)); +} + +/** + Makes a copy of an existing SHA-512 context. + + If Sha512Context is NULL, then return FALSE. + If NewSha512Context is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] Sha512Context Pointer to SHA-512 context being copied. + @param[out] NewSha512Context 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. + +**/ +BOOLEAN +EFIAPI +Sha512Duplicate ( + IN CONST VOID *Sha512Context, + OUT VOID *NewSha512Context + ) +{ + // + // Check input parameters. + // + if (Sha512Context == NULL || NewSha512Context == NULL) { + return FALSE; + } + + CopyMem (NewSha512Context, Sha512Context, sizeof (SHA512_CTX)); + + return TRUE; +} + +/** + 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 Sha512Init(), and should not be finalized + by Sha512Final(). Behavior with invalid context is undefined. + + If Sha512Context is NULL, then return FALSE. + + @param[in, out] Sha512Context Pointer to the SHA-512 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE SHA-512 data digest succeeded. + @retval FALSE SHA-512 data digest failed. + +**/ +BOOLEAN +EFIAPI +Sha512Update ( + IN OUT VOID *Sha512Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (Sha512Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in OpenSSL + // + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-512 Hash Update + // + return (BOOLEAN) (SHA512_Update ((SHA512_CTX *) Sha512Context, Data, DataSize)); +} + +/** + 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 Sha512Init(), and should not be + finalized by Sha512Final(). Behavior with invalid SHA-512 context is undefined. + + If Sha512Context is NULL, then return FALSE. + If HashValue is NULL, then return FALSE. + + @param[in, out] Sha512Context Pointer to the SHA-512 context. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sha512Final ( + IN OUT VOID *Sha512Context, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (Sha512Context == NULL || HashValue == NULL) { + return FALSE; + } + + // + // OpenSSL SHA-512 Hash Finalization + // + return (BOOLEAN) (SHA384_Final (HashValue, (SHA512_CTX *) Sha512Context)); +} + +/** + 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] DataSize Size of Data buffer in bytes. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sha512HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (HashValue == NULL) { + return FALSE; + } + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL SHA-512 Hash Computation. + // + if (SHA512 (Data, DataSize, HashValue) == NULL) { + return FALSE; + } else { + return TRUE; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512Null.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512Null.c new file mode 100644 index 00000000..321cbf1b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSha512Null.c @@ -0,0 +1,275 @@ +/** @file + SHA-384 and SHA-512 Digest Wrapper Implementations which does not provide real capabilities. + +Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Retrieves the size, in bytes, of the context buffer required for SHA-384 hash operations. + + Return zero to indicate this interface is not supported. + + @retval 0 This interface is not supported. + +**/ +UINTN +EFIAPI +Sha384GetContextSize ( + VOID + ) +{ + ASSERT (FALSE); + return 0; +} + +/** + Initializes user-supplied memory pointed by Sha384Context as SHA-384 hash context for + subsequent use. + + Return FALSE to indicate this interface is not supported. + + @param[out] Sha384Context Pointer to SHA-384 context being initialized. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha384Init ( + OUT VOID *Sha384Context + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Makes a copy of an existing SHA-384 context. + + Return FALSE to indicate this interface is not supported. + + @param[in] Sha384Context Pointer to SHA-384 context being copied. + @param[out] NewSha384Context Pointer to new SHA-384 context. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha384Duplicate ( + IN CONST VOID *Sha384Context, + OUT VOID *NewSha384Context + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Digests the input data and updates SHA-384 context. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] Sha384Context Pointer to the SHA-384 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha384Update ( + IN OUT VOID *Sha384Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Completes computation of the SHA-384 digest value. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] Sha384Context Pointer to the SHA-384 context. + @param[out] HashValue Pointer to a buffer that receives the SHA-384 digest + value (48 bytes). + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha384Final ( + IN OUT VOID *Sha384Context, + OUT UINT8 *HashValue + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Computes the SHA-384 message digest of a input data buffer. + + Return FALSE to indicate this interface is not supported. + + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + @param[out] HashValue Pointer to a buffer that receives the SHA-384 digest + value (48 bytes). + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha384HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Retrieves the size, in bytes, of the context buffer required for SHA-512 hash operations. + + Return zero to indicate this interface is not supported. + + @retval 0 This interface is not supported. + +**/ +UINTN +EFIAPI +Sha512GetContextSize ( + VOID + ) +{ + ASSERT (FALSE); + return 0; +} + +/** + Initializes user-supplied memory pointed by Sha512Context as SHA-512 hash context for + subsequent use. + + Return FALSE to indicate this interface is not supported. + + @param[out] Sha512Context Pointer to SHA-512 context being initialized. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha512Init ( + OUT VOID *Sha512Context + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Makes a copy of an existing SHA-512 context. + + Return FALSE to indicate this interface is not supported. + + @param[in] Sha512Context Pointer to SHA-512 context being copied. + @param[out] NewSha512Context Pointer to new SHA-512 context. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha512Duplicate ( + IN CONST VOID *Sha512Context, + OUT VOID *NewSha512Context + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Digests the input data and updates SHA-512 context. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] Sha512Context Pointer to the SHA-512 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha512Update ( + IN OUT VOID *Sha512Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Completes computation of the SHA-512 digest value. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] Sha512Context Pointer to the SHA-512 context. + @param[out] HashValue Pointer to a buffer that receives the SHA-512 digest + value (64 bytes). + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha512Final ( + IN OUT VOID *Sha512Context, + OUT UINT8 *HashValue + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Computes the SHA-512 message digest of a input data buffer. + + Return FALSE to indicate this interface is not supported. + + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + @param[out] HashValue Pointer to a buffer that receives the SHA-512 digest + value (64 bytes). + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sha512HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSm3.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSm3.c new file mode 100644 index 00000000..470d37ea --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hash/CryptSm3.c @@ -0,0 +1,234 @@ +/** @file + SM3 Digest Wrapper Implementations over openssl. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include "crypto/sm3.h" + +/** + Retrieves the size, in bytes, of the context buffer required for SM3 hash operations. + + @return The size, in bytes, of the context buffer required for SM3 hash operations. + +**/ +UINTN +EFIAPI +Sm3GetContextSize ( + VOID + ) +{ + // + // Retrieves Openssl SM3 Context Size + // + return (UINTN) (sizeof (SM3_CTX)); +} + +/** + Initializes user-supplied memory pointed by Sm3Context as SM3 hash context for + subsequent use. + + If Sm3Context is NULL, then return FALSE. + + @param[out] Sm3Context Pointer to SM3 context being initialized. + + @retval TRUE SM3 context initialization succeeded. + @retval FALSE SM3 context initialization failed. + +**/ +BOOLEAN +EFIAPI +Sm3Init ( + OUT VOID *Sm3Context + ) +{ + // + // Check input parameters. + // + if (Sm3Context == NULL) { + return FALSE; + } + + // + // Openssl SM3 Context Initialization + // + sm3_init ((SM3_CTX *) Sm3Context); + return TRUE; +} + +/** + Makes a copy of an existing SM3 context. + + If Sm3Context is NULL, then return FALSE. + If NewSm3Context is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] Sm3Context Pointer to SM3 context being copied. + @param[out] NewSm3Context Pointer to new SM3 context. + + @retval TRUE SM3 context copy succeeded. + @retval FALSE SM3 context copy failed. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Sm3Duplicate ( + IN CONST VOID *Sm3Context, + OUT VOID *NewSm3Context + ) +{ + // + // Check input parameters. + // + if (Sm3Context == NULL || NewSm3Context == NULL) { + return FALSE; + } + + CopyMem (NewSm3Context, Sm3Context, sizeof (SM3_CTX)); + + return TRUE; +} + +/** + 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 Sm3Init(), and should not be finalized + by Sm3Final(). Behavior with invalid context is undefined. + + If Sm3Context is NULL, then return FALSE. + + @param[in, out] Sm3Context Pointer to the SM3 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE SM3 data digest succeeded. + @retval FALSE SM3 data digest failed. + +**/ +BOOLEAN +EFIAPI +Sm3Update ( + IN OUT VOID *Sm3Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (Sm3Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in Openssl + // + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // Openssl SM3 Hash Update + // + sm3_update ((SM3_CTX *) Sm3Context, Data, DataSize); + + return TRUE; +} + +/** + 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 Sm3Init(), and should not be + finalized by Sm3Final(). Behavior with invalid SM3 context is undefined. + + If Sm3Context is NULL, then return FALSE. + If HashValue is NULL, then return FALSE. + + @param[in, out] Sm3Context Pointer to the SM3 context. + @param[out] HashValue Pointer to a buffer that receives the SM3 digest + value (32 bytes). + + @retval TRUE SM3 digest computation succeeded. + @retval FALSE SM3 digest computation failed. + +**/ +BOOLEAN +EFIAPI +Sm3Final ( + IN OUT VOID *Sm3Context, + OUT UINT8 *HashValue + ) +{ + // + // Check input parameters. + // + if (Sm3Context == NULL || HashValue == NULL) { + return FALSE; + } + + // + // Openssl SM3 Hash Finalization + // + sm3_final (HashValue, (SM3_CTX *) Sm3Context); + + return TRUE; +} + +/** + 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] DataSize Size of Data buffer in bytes. + @param[out] HashValue 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. + +**/ +BOOLEAN +EFIAPI +Sm3HashAll ( + IN CONST VOID *Data, + IN UINTN DataSize, + OUT UINT8 *HashValue + ) +{ + SM3_CTX Ctx; + + // + // Check input parameters. + // + if (HashValue == NULL) { + return FALSE; + } + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // SM3 Hash Computation. + // + sm3_init(&Ctx); + + sm3_update(&Ctx, Data, DataSize); + + sm3_final(HashValue, &Ctx); + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256.c new file mode 100644 index 00000000..c4b1f968 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256.c @@ -0,0 +1,216 @@ +/** @file + HMAC-SHA256 Wrapper Implementation over OpenSSL. + +Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + 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, HmacSha256New() returns NULL. + +**/ +VOID * +EFIAPI +HmacSha256New ( + VOID + ) +{ + // + // Allocates & Initializes HMAC_CTX Context by OpenSSL HMAC_CTX_new() + // + return (VOID *) HMAC_CTX_new (); +} + +/** + Release the specified HMAC_CTX context. + + @param[in] HmacSha256Ctx Pointer to the HMAC_CTX context to be released. + +**/ +VOID +EFIAPI +HmacSha256Free ( + IN VOID *HmacSha256Ctx + ) +{ + // + // Free OpenSSL HMAC_CTX Context + // + HMAC_CTX_free ((HMAC_CTX *)HmacSha256Ctx); +} + +/** + Set user-supplied key for subsequent use. It must be done before any + calling to HmacSha256Update(). + + If HmacSha256Context is NULL, then return FALSE. + + @param[out] HmacSha256Context Pointer to HMAC-SHA256 context. + @param[in] Key Pointer to the user-supplied key. + @param[in] KeySize Key size in bytes. + + @retval TRUE The Key is set successfully. + @retval FALSE The Key is set unsuccessfully. + +**/ +BOOLEAN +EFIAPI +HmacSha256SetKey ( + OUT VOID *HmacSha256Context, + IN CONST UINT8 *Key, + IN UINTN KeySize + ) +{ + // + // Check input parameters. + // + if (HmacSha256Context == NULL || KeySize > INT_MAX) { + return FALSE; + } + + if (HMAC_Init_ex ((HMAC_CTX *)HmacSha256Context, Key, (UINT32) KeySize, EVP_sha256(), NULL) != 1) { + return FALSE; + } + + return TRUE; +} + +/** + Makes a copy of an existing HMAC-SHA256 context. + + If HmacSha256Context is NULL, then return FALSE. + If NewHmacSha256Context is NULL, then return FALSE. + + @param[in] HmacSha256Context Pointer to HMAC-SHA256 context being copied. + @param[out] NewHmacSha256Context Pointer to new HMAC-SHA256 context. + + @retval TRUE HMAC-SHA256 context copy succeeded. + @retval FALSE HMAC-SHA256 context copy failed. + +**/ +BOOLEAN +EFIAPI +HmacSha256Duplicate ( + IN CONST VOID *HmacSha256Context, + OUT VOID *NewHmacSha256Context + ) +{ + // + // Check input parameters. + // + if (HmacSha256Context == NULL || NewHmacSha256Context == NULL) { + return FALSE; + } + + if (HMAC_CTX_copy ((HMAC_CTX *)NewHmacSha256Context, (HMAC_CTX *)HmacSha256Context) != 1) { + return FALSE; + } + + return TRUE; +} + +/** + 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 HmacSha256New(), and should not be finalized + by HmacSha256Final(). Behavior with invalid context is undefined. + + If HmacSha256Context is NULL, then return FALSE. + + @param[in, out] HmacSha256Context Pointer to the HMAC-SHA256 context. + @param[in] Data Pointer to the buffer containing the data to be digested. + @param[in] DataSize Size of Data buffer in bytes. + + @retval TRUE HMAC-SHA256 data digest succeeded. + @retval FALSE HMAC-SHA256 data digest failed. + +**/ +BOOLEAN +EFIAPI +HmacSha256Update ( + IN OUT VOID *HmacSha256Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + // + // Check input parameters. + // + if (HmacSha256Context == NULL) { + return FALSE; + } + + // + // Check invalid parameters, in case that only DataLength was checked in OpenSSL + // + if (Data == NULL && DataSize != 0) { + return FALSE; + } + + // + // OpenSSL HMAC-SHA256 digest update + // + if (HMAC_Update ((HMAC_CTX *)HmacSha256Context, Data, DataSize) != 1) { + return FALSE; + } + + return TRUE; +} + +/** + 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 HmacSha256New(), and should not be finalized + by HmacSha256Final(). Behavior with invalid HMAC-SHA256 context is undefined. + + If HmacSha256Context is NULL, then return FALSE. + If HmacValue is NULL, then return FALSE. + + @param[in, out] HmacSha256Context Pointer to the HMAC-SHA256 context. + @param[out] HmacValue 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. + +**/ +BOOLEAN +EFIAPI +HmacSha256Final ( + IN OUT VOID *HmacSha256Context, + OUT UINT8 *HmacValue + ) +{ + UINT32 Length; + + // + // Check input parameters. + // + if (HmacSha256Context == NULL || HmacValue == NULL) { + return FALSE; + } + + // + // OpenSSL HMAC-SHA256 digest finalization + // + if (HMAC_Final ((HMAC_CTX *)HmacSha256Context, HmacValue, &Length) != 1) { + return FALSE; + } + if (HMAC_CTX_reset ((HMAC_CTX *)HmacSha256Context) != 1) { + return FALSE; + } + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256Null.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256Null.c new file mode 100644 index 00000000..aef2f8c2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Hmac/CryptHmacSha256Null.c @@ -0,0 +1,139 @@ +/** @file + HMAC-SHA256 Wrapper Implementation which does not provide real capabilities. + +Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Allocates and initializes one HMAC_CTX context for subsequent HMAC-SHA256 use. + + Return NULL to indicate this interface is not supported. + + @return NULL This interface is not supported.. + +**/ +VOID * +EFIAPI +HmacSha256New ( + VOID + ) +{ + ASSERT (FALSE); + return NULL; +} + +/** + Release the specified HMAC_CTX context. + + This function will do nothing. + + @param[in] HmacSha256Ctx Pointer to the HMAC_CTX context to be released. + +**/ +VOID +EFIAPI +HmacSha256Free ( + IN VOID *HmacSha256Ctx + ) +{ + ASSERT (FALSE); + return; +} + +/** + Set user-supplied key for subsequent use. It must be done before any + calling to HmacSha256Update(). + + Return FALSE to indicate this interface is not supported. + + @param[out] HmacSha256Context Pointer to HMAC-SHA256 context. + @param[in] Key Pointer to the user-supplied key. + @param[in] KeySize Key size in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +HmacSha256SetKey ( + OUT VOID *HmacSha256Context, + IN CONST UINT8 *Key, + IN UINTN KeySize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Makes a copy of an existing HMAC-SHA256 context. + + Return FALSE to indicate this interface is not supported. + + @param[in] HmacSha256Context Pointer to HMAC-SHA256 context being copied. + @param[out] NewHmacSha256Context Pointer to new HMAC-SHA256 context. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +HmacSha256Duplicate ( + IN CONST VOID *HmacSha256Context, + OUT VOID *NewHmacSha256Context + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Digests the input data and updates HMAC-SHA256 context. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] HmacSha256Context Pointer to the HMAC-SHA256 context. + @param[in] Data Pointer to the buffer containing the data to be digested. + @param[in] DataSize Size of Data buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +HmacSha256Update ( + IN OUT VOID *HmacSha256Context, + IN CONST VOID *Data, + IN UINTN DataSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Completes computation of the HMAC-SHA256 digest value. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] HmacSha256Context Pointer to the HMAC-SHA256 context. + @param[out] HmacValue Pointer to a buffer that receives the HMAC-SHA256 digest + value (32 bytes). + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +HmacSha256Final ( + IN OUT VOID *HmacSha256Context, + OUT UINT8 *HmacValue + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/InternalCryptLib.h b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/InternalCryptLib.h new file mode 100644 index 00000000..f5900cfb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/InternalCryptLib.h @@ -0,0 +1,62 @@ +/** @file + Internal include file for BaseCryptLib. + +Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __INTERNAL_CRYPT_LIB_H__ +#define __INTERNAL_CRYPT_LIB_H__ + +#undef _WIN32 +#undef _WIN64 + +#include +#include +#include +#include +#include + +#include "CrtLibSupport.h" + +#include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define OBJ_get0_data(o) ((o)->data) +#define OBJ_length(o) ((o)->length) +#endif + +/** + Check input P7Data is a wrapped ContentInfo structure or not. If not construct + a new structure to wrap P7Data. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise + return FALSE. + @param[out] WrapData If return status of this function is TRUE: + 1) when WrapFlag is TRUE, pointer to P7Data. + 2) when WrapFlag is FALSE, pointer to a new ContentInfo + structure. It's caller's responsibility to free this + buffer. + @param[out] WrapDataSize Length of ContentInfo structure in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE The operation is failed due to lack of resources. + +**/ +BOOLEAN +WrapPkcs7Data ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT BOOLEAN *WrapFlag, + OUT UINT8 **WrapData, + OUT UINTN *WrapDataSize + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c new file mode 100644 index 00000000..9c170656 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdf.c @@ -0,0 +1,75 @@ +/** @file + HMAC-SHA256 KDF Wrapper Implementation over OpenSSL. + +Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +/** + Derive HMAC-based Extract-and-Expand Key Derivation Function (HKDF). + + @param[in] Key Pointer to the user-supplied key. + @param[in] KeySize Key size in bytes. + @param[in] Salt Pointer to the salt(non-secret) value. + @param[in] SaltSize Salt size in bytes. + @param[in] Info Pointer to the application specific info. + @param[in] InfoSize Info size in bytes. + @param[out] Out Pointer to buffer to receive hkdf value. + @param[in] OutSize Size of hkdf bytes to generate. + + @retval TRUE Hkdf generated successfully. + @retval FALSE Hkdf generation failed. + +**/ +BOOLEAN +EFIAPI +HkdfSha256ExtractAndExpand ( + IN CONST UINT8 *Key, + IN UINTN KeySize, + IN CONST UINT8 *Salt, + IN UINTN SaltSize, + IN CONST UINT8 *Info, + IN UINTN InfoSize, + OUT UINT8 *Out, + IN UINTN OutSize + ) +{ + EVP_PKEY_CTX *pHkdfCtx; + BOOLEAN Result; + + if (Key == NULL || Salt == NULL || Info == NULL || Out == NULL || + KeySize > INT_MAX || SaltSize > INT_MAX || InfoSize > INT_MAX || OutSize > INT_MAX ) { + return FALSE; + } + + pHkdfCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + if (pHkdfCtx == NULL) { + return FALSE; + } + + Result = EVP_PKEY_derive_init(pHkdfCtx) > 0; + if (Result) { + Result = EVP_PKEY_CTX_set_hkdf_md(pHkdfCtx, EVP_sha256()) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_set1_hkdf_salt(pHkdfCtx, Salt, (UINT32)SaltSize) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_set1_hkdf_key(pHkdfCtx, Key, (UINT32)KeySize) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_add1_hkdf_info(pHkdfCtx, Info, (UINT32)InfoSize) > 0; + } + if (Result) { + Result = EVP_PKEY_derive(pHkdfCtx, Out, &OutSize) > 0; + } + + EVP_PKEY_CTX_free(pHkdfCtx); + pHkdfCtx = NULL; + return Result; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdfNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdfNull.c new file mode 100644 index 00000000..64792476 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Kdf/CryptHkdfNull.c @@ -0,0 +1,43 @@ +/** @file + HMAC-SHA256 KDF Wrapper Implementation which does not provide real capabilities. + +Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +/** + Derive key data using HMAC-SHA256 based KDF. + + @param[in] Key Pointer to the user-supplied key. + @param[in] KeySize Key size in bytes. + @param[in] Salt Pointer to the salt(non-secret) value. + @param[in] SaltSize Salt size in bytes. + @param[in] Info Pointer to the application specific info. + @param[in] InfoSize Info size in bytes. + @param[out] Out Pointer to buffer to receive hkdf value. + @param[in] OutSize Size of hkdf bytes to generate. + + @retval TRUE Hkdf generated successfully. + @retval FALSE Hkdf generation failed. + +**/ +BOOLEAN +EFIAPI +HkdfSha256ExtractAndExpand ( + IN CONST UINT8 *Key, + IN UINTN KeySize, + IN CONST UINT8 *Salt, + IN UINTN SaltSize, + IN CONST UINT8 *Info, + IN UINTN InfoSize, + OUT UINT8 *Out, + IN UINTN OutSize + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf new file mode 100644 index 00000000..d8d965c7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf @@ -0,0 +1,98 @@ +## @file +# Cryptographic Library Instance for PEIM. +# +# Caution: This module requires additional review when modified. +# This library will have external input - signature. +# This external input must be validated carefully to avoid security issues such as +# buffer overflow or integer overflow. +# +# Note: +# HMAC-SHA256 functions, AES functions, RSA external +# functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, X.509 +# certificate handler functions, authenticode signature verification functions, +# PEM handler functions, and pseudorandom number generator functions are not +# supported in this instance. +# +# Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiCryptLib + MODULE_UNI_FILE = PeiCryptLib.uni + FILE_GUID = 9a2a4375-194c-4e97-9f67-547ec98d96ca + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = BaseCryptLib|PEIM PEI_CORE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + InternalCryptLib.h + Hash/CryptMd5.c + Hash/CryptSha1.c + Hash/CryptSha256.c + Hash/CryptSm3.c + Hash/CryptSha512.c + Hmac/CryptHmacSha256.c + Kdf/CryptHkdf.c + Cipher/CryptAesNull.c + Pk/CryptRsaBasic.c + Pk/CryptRsaExtNull.c + Pk/CryptPkcs1OaepNull.c + Pk/CryptPkcs5Pbkdf2Null.c + Pk/CryptPkcs7SignNull.c + Pk/CryptPkcs7VerifyCommon.c + Pk/CryptPkcs7VerifyBase.c + Pk/CryptPkcs7VerifyEku.c + Pk/CryptDhNull.c + Pk/CryptX509Null.c + Pk/CryptAuthenticodeNull.c + Pk/CryptTsNull.c + Pk/CryptRsaPss.c + Pk/CryptRsaPssSignNull.c + Pem/CryptPemNull.c + Rand/CryptRandNull.c + + SysCall/CrtWrapper.c + SysCall/ConstantTimeClock.c + SysCall/BaseMemAllocation.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + OpensslLib + IntrinsicLib + +# +# Remove these [BuildOptions] after this library is cleaned up +# +[BuildOptions] + # + # suppress the following warnings so we do not break the build with warnings-as-errors: + # C4090: 'function' : different 'const' qualifiers + # C4718: 'function call' : recursive call has no side effects, deleting + # + MSFT:*_*_*_CC_FLAGS = /wd4090 /wd4718 + + # -JCryptoPkg/Include : To disable the use of the system includes provided by RVCT + # --diag_remark=1 : Reduce severity of "#1-D: last line of file ends without a newline" + RVCT:*_*_ARM_CC_FLAGS = -JCryptoPkg/Include --diag_remark=1 + + GCC:*_CLANG35_*_CC_FLAGS = -std=c99 + GCC:*_CLANG38_*_CC_FLAGS = -std=c99 + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + + XCODE:*_*_*_CC_FLAGS = -std=c99 diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.uni b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.uni new file mode 100644 index 00000000..20ae64e8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.uni @@ -0,0 +1,25 @@ +// /** @file +// Cryptographic Library Instance for PEIM. +// +// Caution: This module requires additional review when modified. +// This library will have external input - signature. +// This external input must be validated carefully to avoid security issues such as +// buffer overflow or integer overflow. +// +// Note: AES +// functions, RSA external functions, PKCS#7 SignedData sign functions, +// Diffie-Hellman functions, X.509 certificate handler functions, authenticode +// signature verification functions, PEM handler functions, and pseudorandom number +// generator functions are not supported in this instance. +// +// Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Cryptographic Library Instance for PEIM" + +#string STR_MODULE_DESCRIPTION #language en-US "Caution: This module requires additional review when modified. This library will have external input - signature. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow. Note: AES functions, RSA external functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, X.509 certificate handler functions, authenticode signature verification functions, PEM handler functions, and pseudorandom number generator functions are not supported in this instance." + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c new file mode 100644 index 00000000..287e308d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c @@ -0,0 +1,126 @@ +/** @file + PEM (Privacy Enhanced Mail) Format Handler Wrapper Implementation over OpenSSL. + +Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + 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. + +**/ +INTN +PasswordCallback ( + OUT CHAR8 *Buf, + IN INTN Size, + IN INTN Flag, + IN VOID *Key + ) +{ + INTN KeyLength; + + ZeroMem ((VOID *) Buf, (UINTN) Size); + if (Key != NULL) { + // + // Duplicate key phrase directly. + // + KeyLength = (INTN) AsciiStrLen ((CHAR8 *)Key); + KeyLength = (KeyLength > Size ) ? Size : KeyLength; + CopyMem (Buf, Key, (UINTN) KeyLength); + return KeyLength; + } else { + return 0; + } +} + +/** + Retrieve the RSA Private Key from the password-protected PEM key data. + + @param[in] PemData Pointer to the PEM-encoded key data to be retrieved. + @param[in] PemSize Size of the PEM key data in bytes. + @param[in] Password NULL-terminated passphrase used for encrypted PEM key data. + @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved + RSA private key component. Use RsaFree() function to free the + resource. + + If PemData is NULL, then return FALSE. + If RsaContext is NULL, then return FALSE. + + @retval TRUE RSA Private Key was retrieved successfully. + @retval FALSE Invalid PEM key data or incorrect password. + +**/ +BOOLEAN +EFIAPI +RsaGetPrivateKeyFromPem ( + IN CONST UINT8 *PemData, + IN UINTN PemSize, + IN CONST CHAR8 *Password, + OUT VOID **RsaContext + ) +{ + BOOLEAN Status; + BIO *PemBio; + + // + // Check input parameters. + // + if (PemData == NULL || RsaContext == NULL || PemSize > 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. + // + PemBio = BIO_new (BIO_s_mem ()); + if (PemBio == NULL) { + goto _Exit; + } + + if (BIO_write (PemBio, PemData, (int) PemSize) <= 0) { + goto _Exit; + } + + // + // Retrieve RSA Private Key from encrypted PEM data. + // + *RsaContext = PEM_read_bio_RSAPrivateKey (PemBio, NULL, (pem_password_cb *) &PasswordCallback, (void *) Password); + if (*RsaContext != NULL) { + Status = TRUE; + } + +_Exit: + // + // Release Resources. + // + BIO_free (PemBio); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c new file mode 100644 index 00000000..7a9f6d61 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c @@ -0,0 +1,38 @@ +/** @file + PEM (Privacy Enhanced Mail) Format Handler Wrapper Implementation which does + not provide real capabilities. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Retrieve the RSA Private Key from the password-protected PEM key data. + + Return FALSE to indicate this interface is not supported. + + @param[in] PemData Pointer to the PEM-encoded key data to be retrieved. + @param[in] PemSize Size of the PEM key data in bytes. + @param[in] Password NULL-terminated passphrase used for encrypted PEM key data. + @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved + RSA private key component. Use RsaFree() function to free the + resource. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaGetPrivateKeyFromPem ( + IN CONST UINT8 *PemData, + IN UINTN PemSize, + IN CONST CHAR8 *Password, + OUT VOID **RsaContext + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c new file mode 100644 index 00000000..6421efeb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticode.c @@ -0,0 +1,192 @@ +/** @file + Authenticode Portable Executable Signature Verification over OpenSSL. + + Caution: This module requires additional review when modified. + This library will have external input - signature (e.g. PE/COFF Authenticode). + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + AuthenticodeVerify() will get PE/COFF Authenticode and will do basic check for + data structure. + +Copyright (c) 2011 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include + +// +// OID ASN.1 Value for SPC_INDIRECT_DATA_OBJID +// +UINT8 mSpcIndirectOidValue[] = { + 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04 + }; + +/** + Verifies the validity of a PE/COFF Authenticode Signature as described in "Windows + Authenticode Portable Executable Signature Format". + + If AuthData is NULL, then return FALSE. + If ImageHash is NULL, then return FALSE. + + Caution: This function may receive untrusted input. + PE/COFF Authenticode is external input, so this function will do basic check for + Authenticode data structure. + + @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed + PE/COFF image to be verified. + @param[in] DataSize Size of the Authenticode Signature in bytes. + @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which + is used for certificate chain verification. + @param[in] CertSize Size of the trusted certificate in bytes. + @param[in] ImageHash Pointer to the original image file hash value. The procedure + for calculating the image hash value is described in Authenticode + specification. + @param[in] HashSize Size of Image hash value in bytes. + + @retval TRUE The specified Authenticode Signature is valid. + @retval FALSE Invalid Authenticode Signature. + +**/ +BOOLEAN +EFIAPI +AuthenticodeVerify ( + IN CONST UINT8 *AuthData, + IN UINTN DataSize, + IN CONST UINT8 *TrustedCert, + IN UINTN CertSize, + IN CONST UINT8 *ImageHash, + IN UINTN HashSize + ) +{ + BOOLEAN Status; + PKCS7 *Pkcs7; + CONST UINT8 *Temp; + CONST UINT8 *OrigAuthData; + UINT8 *SpcIndirectDataContent; + UINT8 Asn1Byte; + UINTN ContentSize; + CONST UINT8 *SpcIndirectDataOid; + + // + // Check input parameters. + // + if ((AuthData == NULL) || (TrustedCert == NULL) || (ImageHash == NULL)) { + return FALSE; + } + + if ((DataSize > INT_MAX) || (CertSize > INT_MAX) || (HashSize > INT_MAX)) { + return FALSE; + } + + Status = FALSE; + Pkcs7 = NULL; + OrigAuthData = AuthData; + + // + // Retrieve & Parse PKCS#7 Data (DER encoding) from Authenticode Signature + // + Temp = AuthData; + Pkcs7 = d2i_PKCS7 (NULL, &Temp, (int)DataSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) + // + if (!PKCS7_type_is_signed (Pkcs7) || PKCS7_get_detached (Pkcs7)) { + goto _Exit; + } + + // + // NOTE: OpenSSL PKCS7 Decoder didn't work for Authenticode-format signed data due to + // some authenticode-specific structure. Use opaque ASN.1 string to retrieve + // PKCS#7 ContentInfo here. + // + SpcIndirectDataOid = OBJ_get0_data(Pkcs7->d.sign->contents->type); + if (OBJ_length(Pkcs7->d.sign->contents->type) != sizeof(mSpcIndirectOidValue) || + CompareMem ( + SpcIndirectDataOid, + mSpcIndirectOidValue, + sizeof (mSpcIndirectOidValue) + ) != 0) { + // + // Un-matched SPC_INDIRECT_DATA_OBJID. + // + goto _Exit; + } + + + SpcIndirectDataContent = (UINT8 *)(Pkcs7->d.sign->contents->d.other->value.asn1_string->data); + + // + // Retrieve the SEQUENCE data size from ASN.1-encoded SpcIndirectDataContent. + // + Asn1Byte = *(SpcIndirectDataContent + 1); + + if ((Asn1Byte & 0x80) == 0) { + // + // Short Form of Length Encoding (Length < 128) + // + ContentSize = (UINTN) (Asn1Byte & 0x7F); + // + // Skip the SEQUENCE Tag; + // + SpcIndirectDataContent += 2; + + } else if ((Asn1Byte & 0x81) == 0x81) { + // + // Long Form of Length Encoding (128 <= Length < 255, Single Octet) + // + ContentSize = (UINTN) (*(UINT8 *)(SpcIndirectDataContent + 2)); + // + // Skip the SEQUENCE Tag; + // + SpcIndirectDataContent += 3; + + } else if ((Asn1Byte & 0x82) == 0x82) { + // + // Long Form of Length Encoding (Length > 255, Two Octet) + // + ContentSize = (UINTN) (*(UINT8 *)(SpcIndirectDataContent + 2)); + ContentSize = (ContentSize << 8) + (UINTN)(*(UINT8 *)(SpcIndirectDataContent + 3)); + // + // Skip the SEQUENCE Tag; + // + SpcIndirectDataContent += 4; + + } else { + goto _Exit; + } + + // + // Compare the original file hash value to the digest retrieve from SpcIndirectDataContent + // defined in Authenticode + // NOTE: Need to double-check HashLength here! + // + if (CompareMem (SpcIndirectDataContent + ContentSize - HashSize, ImageHash, HashSize) != 0) { + // + // Un-matched PE/COFF Hash Value + // + goto _Exit; + } + + // + // Verifies the PKCS#7 Signed Data in PE/COFF Authenticode Signature + // + Status = (BOOLEAN) Pkcs7Verify (OrigAuthData, DataSize, TrustedCert, CertSize, SpcIndirectDataContent, ContentSize); + +_Exit: + // + // Release Resources + // + PKCS7_free (Pkcs7); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c new file mode 100644 index 00000000..60b750d9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptAuthenticodeNull.c @@ -0,0 +1,45 @@ +/** @file + Authenticode Portable Executable Signature Verification which does not provide + real capabilities. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Verifies the validity of a PE/COFF Authenticode Signature as described in "Windows + Authenticode Portable Executable Signature Format". + + Return FALSE to indicate this interface is not supported. + + @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed + PE/COFF image to be verified. + @param[in] DataSize Size of the Authenticode Signature in bytes. + @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which + is used for certificate chain verification. + @param[in] CertSize Size of the trusted certificate in bytes. + @param[in] ImageHash Pointer to the original image file hash value. The procedure + for calculating the image hash value is described in Authenticode + specification. + @param[in] HashSize Size of Image hash value in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +AuthenticodeVerify ( + IN CONST UINT8 *AuthData, + IN UINTN DataSize, + IN CONST UINT8 *TrustedCert, + IN UINTN CertSize, + IN CONST UINT8 *ImageHash, + IN UINTN HashSize + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c new file mode 100644 index 00000000..109d6f00 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDh.c @@ -0,0 +1,306 @@ +/** @file + Diffie-Hellman Wrapper Implementation over OpenSSL. + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include +#include + +/** + Allocates and Initializes one Diffie-Hellman Context for subsequent use. + + @return Pointer to the Diffie-Hellman Context that has been initialized. + If the allocations fails, DhNew() returns NULL. + +**/ +VOID * +EFIAPI +DhNew ( + VOID + ) +{ + // + // Allocates & Initializes DH Context by OpenSSL DH_new() + // + return (VOID *) DH_new (); +} + +/** + Release the specified DH context. + + If DhContext is NULL, then return FALSE. + + @param[in] DhContext Pointer to the DH context to be released. + +**/ +VOID +EFIAPI +DhFree ( + IN VOID *DhContext + ) +{ + // + // Free OpenSSL DH Context + // + DH_free ((DH *) DhContext); +} + +/** + 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. + + Before this function can be invoked, pseudorandom number generator must be correctly + initialized by RandomSeed(). + + If DhContext is NULL, then return FALSE. + If Prime is NULL, then return FALSE. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] Generator Value of generator. + @param[in] PrimeLength 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 PrimeLength. + +**/ +BOOLEAN +EFIAPI +DhGenerateParameter ( + IN OUT VOID *DhContext, + IN UINTN Generator, + IN UINTN PrimeLength, + OUT UINT8 *Prime + ) +{ + BOOLEAN RetVal; + BIGNUM *BnP; + + // + // Check input parameters. + // + if (DhContext == NULL || Prime == NULL || PrimeLength > INT_MAX) { + return FALSE; + } + + if (Generator != DH_GENERATOR_2 && Generator != DH_GENERATOR_5) { + return FALSE; + } + + RetVal = (BOOLEAN) DH_generate_parameters_ex (DhContext, (UINT32) PrimeLength, (UINT32) Generator, NULL); + if (!RetVal) { + return FALSE; + } + + DH_get0_pqg (DhContext, (const BIGNUM **)&BnP, NULL, NULL); + BN_bn2bin (BnP, 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 DhContext is NULL, then return FALSE. + If Prime is NULL, then return FALSE. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] Generator Value of generator. + @param[in] PrimeLength 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. + +**/ +BOOLEAN +EFIAPI +DhSetParameter ( + IN OUT VOID *DhContext, + IN UINTN Generator, + IN UINTN PrimeLength, + IN CONST UINT8 *Prime + ) +{ + DH *Dh; + BIGNUM *BnP; + BIGNUM *BnG; + + // + // Check input parameters. + // + if (DhContext == NULL || Prime == NULL || PrimeLength > 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 *)DhContext; + BnP = BN_bin2bn ((const unsigned char *)Prime, (int)(PrimeLength / 8), NULL); + BnG = BN_bin2bn ((const unsigned char *)&Generator, 1, NULL); + if ((BnP == NULL) || (BnG == NULL) || !DH_set0_pqg (Dh, BnP, NULL, BnG)) { + goto Error; + } + + return TRUE; + +Error: + BN_free (BnP); + BN_free (BnG); + + return FALSE; +} + +/** + Generates DH public key. + + This function generates random secret exponent, and computes the public key, which is + returned via parameter PublicKey and PublicKeySize. DH context is updated accordingly. + If the PublicKey buffer is too small to hold the public key, FALSE is returned and + PublicKeySize is set to the required buffer size to obtain the public key. + + If DhContext is NULL, then return FALSE. + If PublicKeySize is NULL, then return FALSE. + If PublicKeySize is large enough but PublicKey is NULL, then return FALSE. + + @param[in, out] DhContext Pointer to the DH context. + @param[out] PublicKey Pointer to the buffer to receive generated public key. + @param[in, out] PublicKeySize On input, the size of PublicKey buffer in bytes. + On output, the size of data returned in PublicKey buffer in bytes. + + @retval TRUE DH public key generation succeeded. + @retval FALSE DH public key generation failed. + @retval FALSE PublicKeySize is not large enough. + +**/ +BOOLEAN +EFIAPI +DhGenerateKey ( + IN OUT VOID *DhContext, + OUT UINT8 *PublicKey, + IN OUT UINTN *PublicKeySize + ) +{ + BOOLEAN RetVal; + DH *Dh; + BIGNUM *DhPubKey; + INTN Size; + + // + // Check input parameters. + // + if (DhContext == NULL || PublicKeySize == NULL) { + return FALSE; + } + + if (PublicKey == NULL && *PublicKeySize != 0) { + return FALSE; + } + + Dh = (DH *) DhContext; + + RetVal = (BOOLEAN) DH_generate_key (DhContext); + if (RetVal) { + DH_get0_key (Dh, (const BIGNUM **)&DhPubKey, NULL); + Size = BN_num_bytes (DhPubKey); + if ((Size > 0) && (*PublicKeySize < (UINTN) Size)) { + *PublicKeySize = Size; + return FALSE; + } + + if (PublicKey != NULL) { + BN_bn2bin (DhPubKey, PublicKey); + } + *PublicKeySize = Size; + } + + return RetVal; +} + +/** + 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 DhContext is NULL, then return FALSE. + If PeerPublicKey is NULL, then return FALSE. + If KeySize is NULL, then return FALSE. + If Key is NULL, then return FALSE. + If KeySize is not large enough, then return FALSE. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] PeerPublicKey Pointer to the peer's public key. + @param[in] PeerPublicKeySize Size of peer's public key in bytes. + @param[out] Key Pointer to the buffer to receive generated key. + @param[in, out] KeySize 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 KeySize is not large enough. + +**/ +BOOLEAN +EFIAPI +DhComputeKey ( + IN OUT VOID *DhContext, + IN CONST UINT8 *PeerPublicKey, + IN UINTN PeerPublicKeySize, + OUT UINT8 *Key, + IN OUT UINTN *KeySize + ) +{ + BIGNUM *Bn; + INTN Size; + + // + // Check input parameters. + // + if (DhContext == NULL || PeerPublicKey == NULL || KeySize == NULL || Key == NULL) { + return FALSE; + } + + if (PeerPublicKeySize > INT_MAX) { + return FALSE; + } + + Bn = BN_bin2bn (PeerPublicKey, (UINT32) PeerPublicKeySize, NULL); + if (Bn == NULL) { + return FALSE; + } + + Size = DH_compute_key (Key, Bn, DhContext); + if (Size < 0) { + BN_free (Bn); + return FALSE; + } + + if (*KeySize < (UINTN) Size) { + *KeySize = Size; + BN_free (Bn); + return FALSE; + } + + *KeySize = Size; + BN_free (Bn); + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c new file mode 100644 index 00000000..b7ab9c08 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptDhNull.c @@ -0,0 +1,150 @@ +/** @file + Diffie-Hellman Wrapper Implementation which does not provide + real capabilities. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Allocates and Initializes one Diffie-Hellman Context for subsequent use. + + @return Pointer to the Diffie-Hellman Context that has been initialized. + If the interface is not supported, DhNew() returns NULL. + +**/ +VOID * +EFIAPI +DhNew ( + VOID + ) +{ + ASSERT (FALSE); + return NULL; +} + +/** + Release the specified DH context. + + If the interface is not supported, then ASSERT(). + + @param[in] DhContext Pointer to the DH context to be released. + +**/ +VOID +EFIAPI +DhFree ( + IN VOID *DhContext + ) +{ + ASSERT (FALSE); +} + +/** + Generates DH parameter. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] Generator Value of generator. + @param[in] PrimeLength Length in bits of prime to be generated. + @param[out] Prime Pointer to the buffer to receive the generated prime number. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +DhGenerateParameter ( + IN OUT VOID *DhContext, + IN UINTN Generator, + IN UINTN PrimeLength, + OUT UINT8 *Prime + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Sets generator and prime parameters for DH. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] Generator Value of generator. + @param[in] PrimeLength Length in bits of prime to be generated. + @param[in] Prime Pointer to the prime number. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +DhSetParameter ( + IN OUT VOID *DhContext, + IN UINTN Generator, + IN UINTN PrimeLength, + IN CONST UINT8 *Prime + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Generates DH public key. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] DhContext Pointer to the DH context. + @param[out] PublicKey Pointer to the buffer to receive generated public key. + @param[in, out] PublicKeySize On input, the size of PublicKey buffer in bytes. + On output, the size of data returned in PublicKey buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +DhGenerateKey ( + IN OUT VOID *DhContext, + OUT UINT8 *PublicKey, + IN OUT UINTN *PublicKeySize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Computes exchanged common key. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] DhContext Pointer to the DH context. + @param[in] PeerPublicKey Pointer to the peer's public key. + @param[in] PeerPublicKeySize Size of peer's public key in bytes. + @param[out] Key Pointer to the buffer to receive generated key. + @param[in, out] KeySize On input, the size of Key buffer in bytes. + On output, the size of data returned in Key buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +DhComputeKey ( + IN OUT VOID *DhContext, + IN CONST UINT8 *PeerPublicKey, + IN UINTN PeerPublicKeySize, + OUT UINT8 *Key, + IN OUT UINTN *KeySize + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c new file mode 100644 index 00000000..d61069bb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1Oaep.c @@ -0,0 +1,208 @@ +/** @file + This file contains UEFI wrapper functions for RSA PKCS1v2 OAEP encryption routines. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ +**/ + +#include "InternalCryptLib.h" +#include +#include +#include +#include + +/** + Encrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the + encrypted message in a newly allocated buffer. + + Things that can cause a failure include: + - X509 key size does not match any known key size. + - Fail to parse X509 certificate. + - Fail to allocate an intermediate buffer. + - Null pointer provided for a non-optional parameter. + - Data size is too large for the provided key size (max size is a function of key size + and hash digest size). + + @param[in] PublicKey A pointer to the DER-encoded X509 certificate that + will be used to encrypt the data. + @param[in] PublicKeySize Size of the X509 cert buffer. + @param[in] InData Data to be encrypted. + @param[in] InDataSize Size of the data buffer. + @param[in] PrngSeed [Optional] If provided, a pointer to a random seed buffer + to be used when initializing the PRNG. NULL otherwise. + @param[in] PrngSeedSize [Optional] If provided, size of the random seed buffer. + 0 otherwise. + @param[out] EncryptedData Pointer to an allocated buffer containing the encrypted + message. + @param[out] EncryptedDataSize Size of the encrypted message buffer. + + @retval TRUE Encryption was successful. + @retval FALSE Encryption failed. + +**/ +BOOLEAN +EFIAPI +Pkcs1v2Encrypt ( + IN CONST UINT8 *PublicKey, + IN UINTN PublicKeySize, + IN UINT8 *InData, + IN UINTN InDataSize, + IN CONST UINT8 *PrngSeed, OPTIONAL + IN UINTN PrngSeedSize, OPTIONAL + OUT UINT8 **EncryptedData, + OUT UINTN *EncryptedDataSize + ) +{ + BOOLEAN Result; + CONST UINT8 *TempPointer; + X509 *CertData; + EVP_PKEY *InternalPublicKey; + EVP_PKEY_CTX *PkeyCtx; + UINT8 *OutData; + UINTN OutDataSize; + + // + // Check input parameters. + // + if (PublicKey == NULL || InData == NULL || + EncryptedData == NULL || EncryptedDataSize == NULL) { + return FALSE; + } + + // + // Check public key size. + // + if (PublicKeySize > 0xFFFFFFFF) { + // + // Public key size is too large for implementation. + // + return FALSE; + } + + *EncryptedData = NULL; + *EncryptedDataSize = 0; + Result = FALSE; + TempPointer = NULL; + CertData = NULL; + InternalPublicKey = NULL; + PkeyCtx = NULL; + OutData = NULL; + OutDataSize = 0; + + // + // If it provides a seed then use it. + // Ohterwise, we'll seed with fixed values and hope that the PRNG has already been + // used enough to generate sufficient entropy. + // + if (PrngSeed != NULL) { + RandomSeed (PrngSeed, PrngSeedSize); + } else { + RandomSeed (NULL, 0); + } + + // + // Parse the X509 cert and extract the public key. + // + TempPointer = PublicKey; + CertData = d2i_X509 (&CertData, &TempPointer, (UINT32)PublicKeySize); + if (CertData == NULL) { + // + // Fail to parse X509 cert. + // + goto _Exit; + } + + // + // Extract the public key from the x509 cert in a format that + // OpenSSL can use. + // + InternalPublicKey = X509_get_pubkey (CertData); + if (InternalPublicKey == NULL) { + // + // Fail to extract public key. + // + goto _Exit; + } + + // + // Create a context for the public key operation. + // + PkeyCtx = EVP_PKEY_CTX_new (InternalPublicKey, NULL); + if (PkeyCtx == NULL) { + // + // Fail to create contex. + // + goto _Exit; + } + // + // Initialize the context and set the desired padding. + // + if (EVP_PKEY_encrypt_init (PkeyCtx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding (PkeyCtx, RSA_PKCS1_OAEP_PADDING) <= 0) { + // + // Fail to initialize the context. + // + goto _Exit; + } + + // + // Determine the required buffer length for malloc'ing. + // + if (EVP_PKEY_encrypt (PkeyCtx, NULL, &OutDataSize, InData, InDataSize) <= 0) { + // + // Fail to determine output buffer size. + // + goto _Exit; + } + + // + // Allocate a buffer for the output data. + // + OutData = AllocatePool (OutDataSize); + if (OutData == NULL) { + // + // Fail to allocate the output buffer. + // + goto _Exit; + } + + // + // Encrypt Data. + // + if (EVP_PKEY_encrypt (PkeyCtx, OutData, &OutDataSize, InData, InDataSize) <= 0) { + // + // Fail to encrypt data, need to free the output buffer. + // + FreePool (OutData); + OutData = NULL; + OutDataSize = 0; + goto _Exit; + } + + // + // Encrypt done. + // + *EncryptedData = OutData; + *EncryptedDataSize = OutDataSize; + Result = TRUE; + +_Exit: + // + // Release Resources + // + if (CertData != NULL) { + X509_free (CertData ); + } + if (InternalPublicKey != NULL) { + EVP_PKEY_free (InternalPublicKey); + } + if (PkeyCtx != NULL) { + EVP_PKEY_CTX_free (PkeyCtx); + } + + return Result; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c new file mode 100644 index 00000000..eca1d88f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs1OaepNull.c @@ -0,0 +1,51 @@ +/** @file + This file contains UEFI wrapper functions for RSA PKCS1v2 OAEP encryption routines. + + SPDX-License-Identifier: BSD-2-Clause-Patent + + Copyright (C) 2016 Microsoft Corporation. All Rights Reserved. + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ +**/ + +#include "InternalCryptLib.h" + +/** + Encrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the + encrypted message in a newly allocated buffer. + + Return FALSE to indicate this interface is not supported. + + @param[in] PublicKey A pointer to the DER-encoded X509 certificate that + will be used to encrypt the data. + @param[in] PublicKeySize Size of the X509 cert buffer. + @param[in] InData Data to be encrypted. + @param[in] InDataSize Size of the data buffer. + @param[in] PrngSeed [Optional] If provided, a pointer to a random seed buffer + to be used when initializing the PRNG. NULL otherwise. + @param[in] PrngSeedSize [Optional] If provided, size of the random seed buffer. + 0 otherwise. + @param[out] EncryptedData Pointer to an allocated buffer containing the encrypted + message. + @param[out] EncryptedDataSize Size of the encrypted message buffer. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs1v2Encrypt ( + IN CONST UINT8 *PublicKey, + IN UINTN PublicKeySize, + IN UINT8 *InData, + IN UINTN InDataSize, + IN CONST UINT8 *PrngSeed, OPTIONAL + IN UINTN PrngSeedSize, OPTIONAL + OUT UINT8 **EncryptedData, + OUT UINTN *EncryptedDataSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c new file mode 100644 index 00000000..373e8061 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2.c @@ -0,0 +1,95 @@ +/** @file + PBKDF2 Key Derivation Function Wrapper Implementation over OpenSSL. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include +#include + +/** + Derives a key from a password using a salt and iteration count, based on PKCS#5 v2.0 + password based encryption key derivation function PBKDF2, as specified in RFC 2898. + + If Password or Salt or OutKey is NULL, then return FALSE. + If the hash algorithm could not be determined, then return FALSE. + + @param[in] PasswordLength Length of input password in bytes. + @param[in] Password Pointer to the array for the password. + @param[in] SaltLength Size of the Salt in bytes. + @param[in] Salt Pointer to the Salt. + @param[in] IterationCount Number of iterations to perform. Its value should be + greater than or equal to 1. + @param[in] DigestSize Size of the message digest to be used (eg. SHA256_DIGEST_SIZE). + NOTE: DigestSize will be used to determine the hash algorithm. + Only SHA1_DIGEST_SIZE or SHA256_DIGEST_SIZE is supported. + @param[in] KeyLength Size of the derived key buffer in bytes. + @param[out] OutKey Pointer to the output derived key buffer. + + @retval TRUE A key was derived successfully. + @retval FALSE One of the pointers was NULL or one of the sizes was too large. + @retval FALSE The hash algorithm could not be determined from the digest size. + @retval FALSE The key derivation operation failed. + +**/ +BOOLEAN +EFIAPI +Pkcs5HashPassword ( + IN UINTN PasswordLength, + IN CONST CHAR8 *Password, + IN UINTN SaltLength, + IN CONST UINT8 *Salt, + IN UINTN IterationCount, + IN UINTN DigestSize, + IN UINTN KeyLength, + OUT UINT8 *OutKey + ) +{ + CONST EVP_MD *HashAlg; + + HashAlg = NULL; + + // + // Parameter Checking. + // + if ((Password == NULL) || (Salt == NULL) || (OutKey == NULL)) { + return FALSE; + } + if ((PasswordLength == 0) || (PasswordLength > INT_MAX) || + (SaltLength == 0) || (SaltLength > INT_MAX) || + (KeyLength == 0) || (KeyLength > INT_MAX) || + (IterationCount < 1) || (IterationCount > INT_MAX)) { + return FALSE; + } + // + // Make sure the digest algorithm is supported. + // + switch (DigestSize) { + case SHA1_DIGEST_SIZE: + HashAlg = EVP_sha1(); + break; + case SHA256_DIGEST_SIZE: + HashAlg = EVP_sha256(); + break; + default: + return FALSE; + break; + } + + // + // Perform password-based key derivation routines. + // + return (BOOLEAN)PKCS5_PBKDF2_HMAC ( + (const char *)Password, + (int)PasswordLength, + (const unsigned char *)Salt, + (int)SaltLength, + (int)IterationCount, + HashAlg, + (int)KeyLength, + (unsigned char *)OutKey + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c new file mode 100644 index 00000000..93455cb7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs5Pbkdf2Null.c @@ -0,0 +1,50 @@ +/** @file + PBKDF2 Key Derivation Function Wrapper Implementation which does not provide real + capabilities. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include +#include + +/** + Derives a key from a password using a salt and iteration count, based on PKCS#5 v2.0 + password based encryption key derivation function PBKDF2, as specified in RFC 2898. + + Return FALSE to indicate this interface is not supported. + + @param[in] PasswordLength Length of input password in bytes. + @param[in] Password Pointer to the array for the password. + @param[in] SaltLength Size of the Salt in bytes. + @param[in] Salt Pointer to the Salt. + @param[in] IterationCount Number of iterations to perform. Its value should be + greater than or equal to 1. + @param[in] DigestSize Size of the message digest to be used (eg. SHA256_DIGEST_SIZE). + NOTE: DigestSize will be used to determine the hash algorithm. + Only SHA1_DIGEST_SIZE or SHA256_DIGEST_SIZE is supported. + @param[in] KeyLength Size of the derived key buffer in bytes. + @param[out] OutKey Pointer to the output derived key buffer. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs5HashPassword ( + IN UINTN PasswordLength, + IN CONST CHAR8 *Password, + IN UINTN SaltLength, + IN CONST UINT8 *Salt, + IN UINTN IterationCount, + IN UINTN DigestSize, + IN UINTN KeyLength, + OUT UINT8 *OutKey + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c new file mode 100644 index 00000000..e32fc91c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7Sign.c @@ -0,0 +1,194 @@ +/** @file + PKCS#7 SignedData Sign Wrapper Implementation over OpenSSL. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include + +/** + Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message + Syntax Standard, version 1.5". This interface is only intended to be used for + application to perform PKCS#7 functionality validation. + + @param[in] PrivateKey Pointer to the PEM-formatted private key data for + data signing. + @param[in] PrivateKeySize Size of the PEM private key data in bytes. + @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM + key data. + @param[in] InData Pointer to the content to be signed. + @param[in] InDataSize Size of InData in bytes. + @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with. + @param[in] OtherCerts Pointer to an optional additional set of certificates to + include in the PKCS#7 signedData (e.g. any intermediate + CAs in the chain). + @param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's + responsibility to free the buffer with FreePool(). + @param[out] SignedDataSize Size of SignedData in bytes. + + @retval TRUE PKCS#7 data signing succeeded. + @retval FALSE PKCS#7 data signing failed. + +**/ +BOOLEAN +EFIAPI +Pkcs7Sign ( + IN CONST UINT8 *PrivateKey, + IN UINTN PrivateKeySize, + IN CONST UINT8 *KeyPassword, + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *SignCert, + IN UINT8 *OtherCerts OPTIONAL, + OUT UINT8 **SignedData, + OUT UINTN *SignedDataSize + ) +{ + BOOLEAN Status; + EVP_PKEY *Key; + BIO *DataBio; + PKCS7 *Pkcs7; + UINT8 *RsaContext; + UINT8 *P7Data; + UINTN P7DataSize; + UINT8 *Tmp; + + // + // Check input parameters. + // + if (PrivateKey == NULL || KeyPassword == NULL || InData == NULL || + SignCert == NULL || SignedData == NULL || SignedDataSize == NULL || InDataSize > INT_MAX) { + return FALSE; + } + + RsaContext = NULL; + Key = NULL; + Pkcs7 = NULL; + DataBio = NULL; + Status = FALSE; + + // + // Retrieve RSA private key from PEM data. + // + Status = RsaGetPrivateKeyFromPem ( + PrivateKey, + PrivateKeySize, + (CONST CHAR8 *) KeyPassword, + (VOID **) &RsaContext + ); + if (!Status) { + return Status; + } + + Status = FALSE; + + // + // Register & Initialize necessary digest algorithms and PRNG for PKCS#7 Handling + // + if (EVP_add_digest (EVP_md5 ()) == 0) { + goto _Exit; + } + if (EVP_add_digest (EVP_sha1 ()) == 0) { + goto _Exit; + } + if (EVP_add_digest (EVP_sha256 ()) == 0) { + goto _Exit; + } + + RandomSeed (NULL, 0); + + // + // Construct OpenSSL EVP_PKEY for private key. + // + Key = EVP_PKEY_new (); + if (Key == NULL) { + goto _Exit; + } + if (EVP_PKEY_assign_RSA (Key, (RSA *) RsaContext) == 0) { + goto _Exit; + } + + // + // Convert the data to be signed to BIO format. + // + DataBio = BIO_new (BIO_s_mem ()); + if (DataBio == NULL) { + goto _Exit; + } + + if (BIO_write (DataBio, InData, (int) InDataSize) <= 0) { + goto _Exit; + } + + // + // Create the PKCS#7 signedData structure. + // + Pkcs7 = PKCS7_sign ( + (X509 *) SignCert, + Key, + (STACK_OF(X509) *) OtherCerts, + DataBio, + PKCS7_BINARY | PKCS7_NOATTR | PKCS7_DETACHED + ); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Convert PKCS#7 signedData structure into DER-encoded buffer. + // + P7DataSize = i2d_PKCS7 (Pkcs7, NULL); + if (P7DataSize <= 19) { + goto _Exit; + } + + P7Data = malloc (P7DataSize); + if (P7Data == NULL) { + goto _Exit; + } + + Tmp = P7Data; + P7DataSize = i2d_PKCS7 (Pkcs7, (unsigned char **) &Tmp); + ASSERT (P7DataSize > 19); + + // + // Strip ContentInfo to content only for signeddata. The data be trimmed off + // is totally 19 bytes. + // + *SignedDataSize = P7DataSize - 19; + *SignedData = AllocatePool (*SignedDataSize); + if (*SignedData == NULL) { + OPENSSL_free (P7Data); + goto _Exit; + } + + CopyMem (*SignedData, P7Data + 19, *SignedDataSize); + + OPENSSL_free (P7Data); + + Status = TRUE; + +_Exit: + // + // Release Resources + // + if (Key != NULL) { + EVP_PKEY_free (Key); + } + + if (DataBio != NULL) { + BIO_free (DataBio); + } + + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c new file mode 100644 index 00000000..f016d04a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7SignNull.c @@ -0,0 +1,54 @@ +/** @file + PKCS#7 SignedData Sign Wrapper Implementation which does not provide real + capabilities. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message + Syntax Standard, version 1.5". This interface is only intended to be used for + application to perform PKCS#7 functionality validation. + + Return FALSE to indicate this interface is not supported. + + @param[in] PrivateKey Pointer to the PEM-formatted private key data for + data signing. + @param[in] PrivateKeySize Size of the PEM private key data in bytes. + @param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM + key data. + @param[in] InData Pointer to the content to be signed. + @param[in] InDataSize Size of InData in bytes. + @param[in] SignCert Pointer to signer's DER-encoded certificate to sign with. + @param[in] OtherCerts Pointer to an optional additional set of certificates to + include in the PKCS#7 signedData (e.g. any intermediate + CAs in the chain). + @param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's + responsibility to free the buffer with FreePool(). + @param[out] SignedDataSize Size of SignedData in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7Sign ( + IN CONST UINT8 *PrivateKey, + IN UINTN PrivateKeySize, + IN CONST UINT8 *KeyPassword, + IN UINT8 *InData, + IN UINTN InDataSize, + IN UINT8 *SignCert, + IN UINT8 *OtherCerts OPTIONAL, + OUT UINT8 **SignedData, + OUT UINTN *SignedDataSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c new file mode 100644 index 00000000..0deb7a20 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyBase.c @@ -0,0 +1,190 @@ +/** @file + Non-runtime specific implementation of PKCS#7 SignedData Verification Wrapper. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include +#include + +/** + Check the contents of PKCS7 is not data. + + It is copied from PKCS7_type_is_other() in pk7_doit.c. + + @param[in] P7 Pointer to the location at which the PKCS7 is located. + + @retval TRUE If the type is others. + @retval FALSE If the type is expected. +**/ +STATIC +BOOLEAN +Pkcs7TypeIsOther ( + IN PKCS7 *P7 + ) +{ + BOOLEAN Others; + INTN Nid = OBJ_obj2nid (P7->type); + + switch (Nid) { + case NID_pkcs7_data: + case NID_pkcs7_signed: + case NID_pkcs7_enveloped: + case NID_pkcs7_signedAndEnveloped: + case NID_pkcs7_encrypted: + Others = FALSE; + break; + default: + Others = TRUE; + } + + return Others; +} + +/** + Get the ASN.1 string for the PKCS7. + + It is copied from PKCS7_get_octet_string() in pk7_doit.c. + + @param[in] P7 Pointer to the location at which the PKCS7 is located. + + @return ASN1_OCTET_STRING ASN.1 string. +**/ +STATIC +ASN1_OCTET_STRING* +Pkcs7GetOctetString ( + IN PKCS7 *P7 + ) +{ + if (PKCS7_type_is_data (P7)) { + return P7->d.data; + } + + if (Pkcs7TypeIsOther(P7) && (P7->d.other != NULL) && + (P7->d.other->type == V_ASN1_OCTET_STRING)) { + return P7->d.other->value.octet_string; + } + + return NULL; +} + +/** + Extracts the attached content from a PKCS#7 signed data if existed. The input signed + data could be wrapped in a ContentInfo structure. + + If P7Data, Content, or ContentSize is NULL, then return FALSE. If P7Length overflow, + then return FALSE. If the P7Data is not correctly formatted, then return FALSE. + + Caution: This function may receive untrusted input. So this function will do + basic check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 signed data to process. + @param[in] P7Length Length of the PKCS#7 signed data in bytes. + @param[out] Content Pointer to the extracted content from the PKCS#7 signedData. + It's caller's responsibility to free the buffer with FreePool(). + @param[out] ContentSize The size of the extracted content in bytes. + + @retval TRUE The P7Data was correctly formatted for processing. + @retval FALSE The P7Data was not correctly formatted for processing. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetAttachedContent ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT VOID **Content, + OUT UINTN *ContentSize + ) +{ + BOOLEAN Status; + PKCS7 *Pkcs7; + UINT8 *SignedData; + UINTN SignedDataSize; + BOOLEAN Wrapped; + CONST UINT8 *Temp; + ASN1_OCTET_STRING *OctStr; + + // + // Check input parameter. + // + if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) { + return FALSE; + } + + *Content = NULL; + Pkcs7 = NULL; + SignedData = NULL; + OctStr = NULL; + + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize); + if (!Status || (SignedDataSize > INT_MAX)) { + goto _Exit; + } + + Status = FALSE; + + // + // Decoding PKCS#7 SignedData + // + Temp = SignedData; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (int)SignedDataSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // The type of Pkcs7 must be signedData + // + if (!PKCS7_type_is_signed (Pkcs7)) { + goto _Exit; + } + + // + // Check for detached or attached content + // + if (PKCS7_get_detached (Pkcs7)) { + // + // No Content supplied for PKCS7 detached signedData + // + *Content = NULL; + *ContentSize = 0; + } else { + // + // Retrieve the attached content in PKCS7 signedData + // + OctStr = Pkcs7GetOctetString (Pkcs7->d.sign->contents); + if (OctStr == NULL) { + goto _Exit; + } + + if ((OctStr->length > 0) && (OctStr->data != NULL)) { + *ContentSize = OctStr->length; + *Content = AllocatePool (*ContentSize); + if (*Content == NULL) { + *ContentSize = 0; + goto _Exit; + } + CopyMem (*Content, OctStr->data, *ContentSize); + } + } + Status = TRUE; + +_Exit: + // + // Release Resources + // + PKCS7_free (Pkcs7); + + if (!Wrapped) { + OPENSSL_free (SignedData); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c new file mode 100644 index 00000000..e4cca018 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c @@ -0,0 +1,910 @@ +/** @file + PKCS#7 SignedData Verification Wrapper Implementation over OpenSSL. + + Caution: This module requires additional review when modified. + This library will have external input - signature (e.g. UEFI Authenticated + Variable). It may by input in SMM mode. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + WrapPkcs7Data(), Pkcs7GetSigners(), Pkcs7Verify() will get UEFI Authenticated + Variable and will do basic check for data structure. + +Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include +#include + +UINT8 mOidValue[9] = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x02 }; + +/** + Check input P7Data is a wrapped ContentInfo structure or not. If not construct + a new structure to wrap P7Data. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] WrapFlag If TRUE P7Data is a ContentInfo structure, otherwise + return FALSE. + @param[out] WrapData If return status of this function is TRUE: + 1) when WrapFlag is TRUE, pointer to P7Data. + 2) when WrapFlag is FALSE, pointer to a new ContentInfo + structure. It's caller's responsibility to free this + buffer. + @param[out] WrapDataSize Length of ContentInfo structure in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE The operation is failed due to lack of resources. + +**/ +BOOLEAN +WrapPkcs7Data ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT BOOLEAN *WrapFlag, + OUT UINT8 **WrapData, + OUT UINTN *WrapDataSize + ) +{ + BOOLEAN Wrapped; + UINT8 *SignedData; + + // + // Check whether input P7Data is a wrapped ContentInfo structure or not. + // + Wrapped = FALSE; + if ((P7Data[4] == 0x06) && (P7Data[5] == 0x09)) { + if (CompareMem (P7Data + 6, mOidValue, sizeof (mOidValue)) == 0) { + if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) { + Wrapped = TRUE; + } + } + } + + if (Wrapped) { + *WrapData = (UINT8 *) P7Data; + *WrapDataSize = P7Length; + } else { + // + // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes. + // + *WrapDataSize = P7Length + 19; + *WrapData = malloc (*WrapDataSize); + if (*WrapData == NULL) { + *WrapFlag = Wrapped; + return FALSE; + } + + SignedData = *WrapData; + + // + // Part1: 0x30, 0x82. + // + SignedData[0] = 0x30; + SignedData[1] = 0x82; + + // + // Part2: Length1 = P7Length + 19 - 4, in big endian. + // + SignedData[2] = (UINT8) (((UINT16) (*WrapDataSize - 4)) >> 8); + SignedData[3] = (UINT8) (((UINT16) (*WrapDataSize - 4)) & 0xff); + + // + // Part3: 0x06, 0x09. + // + SignedData[4] = 0x06; + SignedData[5] = 0x09; + + // + // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02. + // + CopyMem (SignedData + 6, mOidValue, sizeof (mOidValue)); + + // + // Part5: 0xA0, 0x82. + // + SignedData[15] = 0xA0; + SignedData[16] = 0x82; + + // + // Part6: Length2 = P7Length, in big endian. + // + SignedData[17] = (UINT8) (((UINT16) P7Length) >> 8); + SignedData[18] = (UINT8) (((UINT16) P7Length) & 0xff); + + // + // Part7: P7Data. + // + CopyMem (SignedData + 19, P7Data, P7Length); + } + + *WrapFlag = Wrapped; + return TRUE; +} + +/** + Pop single certificate from STACK_OF(X509). + + If X509Stack, Cert, or CertSize is NULL, then return FALSE. + + @param[in] X509Stack Pointer to a X509 stack object. + @param[out] Cert Pointer to a X509 certificate. + @param[out] CertSize Length of output X509 certificate in bytes. + + @retval TRUE The X509 stack pop succeeded. + @retval FALSE The pop operation failed. + +**/ +BOOLEAN +X509PopCertificate ( + IN VOID *X509Stack, + OUT UINT8 **Cert, + OUT UINTN *CertSize + ) +{ + BIO *CertBio; + X509 *X509Cert; + STACK_OF(X509) *CertStack; + BOOLEAN Status; + INT32 Result; + BUF_MEM *Ptr; + INT32 Length; + VOID *Buffer; + + Status = FALSE; + + if ((X509Stack == NULL) || (Cert == NULL) || (CertSize == NULL)) { + return Status; + } + + CertStack = (STACK_OF(X509) *) X509Stack; + + X509Cert = sk_X509_pop (CertStack); + + if (X509Cert == NULL) { + return Status; + } + + Buffer = NULL; + + CertBio = BIO_new (BIO_s_mem ()); + if (CertBio == NULL) { + return Status; + } + + Result = i2d_X509_bio (CertBio, X509Cert); + if (Result == 0) { + goto _Exit; + } + + BIO_get_mem_ptr (CertBio, &Ptr); + Length = (INT32)(Ptr->length); + if (Length <= 0) { + goto _Exit; + } + + Buffer = malloc (Length); + if (Buffer == NULL) { + goto _Exit; + } + + Result = BIO_read (CertBio, Buffer, Length); + if (Result != Length) { + goto _Exit; + } + + *Cert = Buffer; + *CertSize = Length; + + Status = TRUE; + +_Exit: + + BIO_free (CertBio); + + if (!Status && (Buffer != NULL)) { + free (Buffer); + } + + return Status; +} + +/** + Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, CertStack, StackLength, TrustedCert or CertLength is NULL, then + return FALSE. If P7Length overflow, then return FALSE. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data. + It's caller's responsibility to free the buffer with + Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] StackLength Length of signer's certificates in bytes. + @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates. + It's caller's responsibility to free the buffer with + Pkcs7FreeSigners(). + @param[out] CertLength Length of the trusted certificate in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSigners ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **CertStack, + OUT UINTN *StackLength, + OUT UINT8 **TrustedCert, + OUT UINTN *CertLength + ) +{ + PKCS7 *Pkcs7; + BOOLEAN Status; + UINT8 *SignedData; + CONST UINT8 *Temp; + UINTN SignedDataSize; + BOOLEAN Wrapped; + STACK_OF(X509) *Stack; + UINT8 Index; + UINT8 *CertBuf; + UINT8 *OldBuf; + UINTN BufferSize; + UINTN OldSize; + UINT8 *SingleCert; + UINTN SingleCertSize; + + if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) || + (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX)) { + return FALSE; + } + + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize); + if (!Status) { + return Status; + } + + Status = FALSE; + Pkcs7 = NULL; + Stack = NULL; + CertBuf = NULL; + OldBuf = NULL; + SingleCert = NULL; + + // + // Retrieve PKCS#7 Data (DER encoding) + // + if (SignedDataSize > INT_MAX) { + goto _Exit; + } + + Temp = SignedData; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) + // + if (!PKCS7_type_is_signed (Pkcs7)) { + goto _Exit; + } + + Stack = PKCS7_get0_signers(Pkcs7, NULL, PKCS7_BINARY); + if (Stack == NULL) { + goto _Exit; + } + + // + // Convert CertStack to buffer in following format: + // UINT8 CertNumber; + // UINT32 Cert1Length; + // UINT8 Cert1[]; + // UINT32 Cert2Length; + // UINT8 Cert2[]; + // ... + // UINT32 CertnLength; + // UINT8 Certn[]; + // + BufferSize = sizeof (UINT8); + OldSize = BufferSize; + + for (Index = 0; ; Index++) { + Status = X509PopCertificate (Stack, &SingleCert, &SingleCertSize); + if (!Status) { + break; + } + + OldSize = BufferSize; + OldBuf = CertBuf; + BufferSize = OldSize + SingleCertSize + sizeof (UINT32); + CertBuf = malloc (BufferSize); + + if (CertBuf == NULL) { + goto _Exit; + } + + if (OldBuf != NULL) { + CopyMem (CertBuf, OldBuf, OldSize); + free (OldBuf); + OldBuf = NULL; + } + + WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) SingleCertSize); + CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, SingleCertSize); + + free (SingleCert); + SingleCert = NULL; + } + + if (CertBuf != NULL) { + // + // Update CertNumber. + // + CertBuf[0] = Index; + + *CertLength = BufferSize - OldSize - sizeof (UINT32); + *TrustedCert = malloc (*CertLength); + if (*TrustedCert == NULL) { + goto _Exit; + } + + CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength); + *CertStack = CertBuf; + *StackLength = BufferSize; + Status = TRUE; + } + +_Exit: + // + // Release Resources + // + if (!Wrapped) { + free (SignedData); + } + + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + + if (Stack != NULL) { + sk_X509_pop_free(Stack, X509_free); + } + + if (SingleCert != NULL) { + free (SingleCert); + } + + if (!Status && (CertBuf != NULL)) { + free (CertBuf); + *CertStack = NULL; + } + + if (OldBuf != NULL) { + free (OldBuf); + } + + return Status; +} + +/** + Wrap function to use free() to free allocated memory for certificates. + + @param[in] Certs Pointer to the certificates to be freed. + +**/ +VOID +EFIAPI +Pkcs7FreeSigners ( + IN UINT8 *Certs + ) +{ + if (Certs == NULL) { + return; + } + + free (Certs); +} + +/** + Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate lists chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SignerChainCerts Pointer to the certificates list chained to signer's + certificate. It's caller's responsibility to free the buffer + with Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] ChainLength Length of the chained certificates list buffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's + responsibility to free the buffer with Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] UnchainLength Length of the unchained certificates list buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ) +{ + BOOLEAN Status; + UINT8 *NewP7Data; + UINTN NewP7Length; + BOOLEAN Wrapped; + UINT8 Index; + PKCS7 *Pkcs7; + X509_STORE_CTX *CertCtx; + STACK_OF(X509) *CtxChain; + STACK_OF(X509) *CtxUntrusted; + X509 *CtxCert; + STACK_OF(X509) *Signers; + X509 *Signer; + X509 *Cert; + X509 *Issuer; + X509_NAME *IssuerName; + UINT8 *CertBuf; + UINT8 *OldBuf; + UINTN BufferSize; + UINTN OldSize; + UINT8 *SingleCert; + UINTN CertSize; + + // + // Initializations + // + Status = FALSE; + NewP7Data = NULL; + Pkcs7 = NULL; + CertCtx = NULL; + CtxChain = NULL; + CtxCert = NULL; + CtxUntrusted = NULL; + Cert = NULL; + SingleCert = NULL; + CertBuf = NULL; + OldBuf = NULL; + Signers = NULL; + + ZeroMem (&CertCtx, sizeof (CertCtx)); + + // + // Parameter Checking + // + if ((P7Data == NULL) || (SignerChainCerts == NULL) || (ChainLength == NULL) || + (UnchainCerts == NULL) || (UnchainLength == NULL) || (P7Length > INT_MAX)) { + return Status; + } + + *SignerChainCerts = NULL; + *ChainLength = 0; + *UnchainCerts = NULL; + *UnchainLength = 0; + + // + // Construct a new PKCS#7 data wrapping with ContentInfo structure if needed. + // + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &NewP7Data, &NewP7Length); + if (!Status || (NewP7Length > INT_MAX)) { + goto _Error; + } + + // + // Decodes PKCS#7 SignedData + // + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &NewP7Data, (int) NewP7Length); + if ((Pkcs7 == NULL) || (!PKCS7_type_is_signed (Pkcs7))) { + goto _Error; + } + + // + // Obtains Signer's Certificate from PKCS#7 data + // NOTE: Only one signer case will be handled in this function, which means SignerInfos + // should include only one signer's certificate. + // + Signers = PKCS7_get0_signers (Pkcs7, NULL, PKCS7_BINARY); + if ((Signers == NULL) || (sk_X509_num (Signers) != 1)) { + goto _Error; + } + Signer = sk_X509_value (Signers, 0); + + CertCtx = X509_STORE_CTX_new (); + if (CertCtx == NULL) { + goto _Error; + } + if (!X509_STORE_CTX_init (CertCtx, NULL, Signer, Pkcs7->d.sign->cert)) { + goto _Error; + } + // + // Initialize Chained & Untrusted stack + // + CtxChain = X509_STORE_CTX_get0_chain (CertCtx); + CtxCert = X509_STORE_CTX_get0_cert (CertCtx); + if (CtxChain == NULL) { + if (((CtxChain = sk_X509_new_null ()) == NULL) || + (!sk_X509_push (CtxChain, CtxCert))) { + goto _Error; + } + } + CtxUntrusted = X509_STORE_CTX_get0_untrusted (CertCtx); + if (CtxUntrusted != NULL) { + (VOID)sk_X509_delete_ptr (CtxUntrusted, Signer); + } + + // + // Build certificates stack chained from Signer's certificate. + // + Cert = Signer; + for (; ;) { + // + // Self-Issue checking + // + Issuer = NULL; + if (X509_STORE_CTX_get1_issuer (&Issuer, CertCtx, Cert) == 1) { + if (X509_cmp (Issuer, Cert) == 0) { + break; + } + } + + // + // Found the issuer of the current certificate + // + if (CtxUntrusted != NULL) { + Issuer = NULL; + IssuerName = X509_get_issuer_name (Cert); + Issuer = X509_find_by_subject (CtxUntrusted, IssuerName); + if (Issuer != NULL) { + if (!sk_X509_push (CtxChain, Issuer)) { + goto _Error; + } + (VOID)sk_X509_delete_ptr (CtxUntrusted, Issuer); + + Cert = Issuer; + continue; + } + } + + break; + } + + // + // Converts Chained and Untrusted Certificate to Certificate Buffer in following format: + // UINT8 CertNumber; + // UINT32 Cert1Length; + // UINT8 Cert1[]; + // UINT32 Cert2Length; + // UINT8 Cert2[]; + // ... + // UINT32 CertnLength; + // UINT8 Certn[]; + // + + if (CtxChain != NULL) { + BufferSize = sizeof (UINT8); + CertBuf = NULL; + + for (Index = 0; ; Index++) { + Status = X509PopCertificate (CtxChain, &SingleCert, &CertSize); + if (!Status) { + break; + } + + OldSize = BufferSize; + OldBuf = CertBuf; + BufferSize = OldSize + CertSize + sizeof (UINT32); + CertBuf = malloc (BufferSize); + + if (CertBuf == NULL) { + Status = FALSE; + goto _Error; + } + if (OldBuf != NULL) { + CopyMem (CertBuf, OldBuf, OldSize); + free (OldBuf); + OldBuf = NULL; + } + + WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize); + CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize); + + free (SingleCert); + SingleCert = NULL; + } + + if (CertBuf != NULL) { + // + // Update CertNumber. + // + CertBuf[0] = Index; + + *SignerChainCerts = CertBuf; + *ChainLength = BufferSize; + } + } + + if (CtxUntrusted != NULL) { + BufferSize = sizeof (UINT8); + CertBuf = NULL; + + for (Index = 0; ; Index++) { + Status = X509PopCertificate (CtxUntrusted, &SingleCert, &CertSize); + if (!Status) { + break; + } + + OldSize = BufferSize; + OldBuf = CertBuf; + BufferSize = OldSize + CertSize + sizeof (UINT32); + CertBuf = malloc (BufferSize); + + if (CertBuf == NULL) { + Status = FALSE; + goto _Error; + } + if (OldBuf != NULL) { + CopyMem (CertBuf, OldBuf, OldSize); + free (OldBuf); + OldBuf = NULL; + } + + WriteUnaligned32 ((UINT32 *) (CertBuf + OldSize), (UINT32) CertSize); + CopyMem (CertBuf + OldSize + sizeof (UINT32), SingleCert, CertSize); + + free (SingleCert); + SingleCert = NULL; + } + + if (CertBuf != NULL) { + // + // Update CertNumber. + // + CertBuf[0] = Index; + + *UnchainCerts = CertBuf; + *UnchainLength = BufferSize; + } + } + + Status = TRUE; + +_Error: + // + // Release Resources. + // + if (!Wrapped && (NewP7Data != NULL)) { + free (NewP7Data); + } + + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + sk_X509_free (Signers); + + if (CertCtx != NULL) { + X509_STORE_CTX_cleanup (CertCtx); + X509_STORE_CTX_free (CertCtx); + } + + if (SingleCert != NULL) { + free (SingleCert); + } + + if (OldBuf != NULL) { + free (OldBuf); + } + + if (!Status && (CertBuf != NULL)) { + free (CertBuf); + *SignerChainCerts = NULL; + *UnchainCerts = NULL; + } + + return Status; +} + +/** + Verifies the validity of a PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + If P7Data, TrustedCert or InData is NULL, then return FALSE. + If P7Length, CertLength or DataLength overflow, then return FALSE. + + Caution: This function may receive untrusted input. + UEFI Authenticated Variable is external input, so this function will do basic + check for PKCS#7 data structure. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which + is used for certificate chain verification. + @param[in] CertLength Length of the trusted certificate in bytes. + @param[in] InData Pointer to the content to be verified. + @param[in] DataLength Length of InData in bytes. + + @retval TRUE The specified PKCS#7 signed data is valid. + @retval FALSE Invalid PKCS#7 signed data. + +**/ +BOOLEAN +EFIAPI +Pkcs7Verify ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + IN CONST UINT8 *TrustedCert, + IN UINTN CertLength, + IN CONST UINT8 *InData, + IN UINTN DataLength + ) +{ + PKCS7 *Pkcs7; + BIO *DataBio; + BOOLEAN Status; + X509 *Cert; + X509_STORE *CertStore; + UINT8 *SignedData; + CONST UINT8 *Temp; + UINTN SignedDataSize; + BOOLEAN Wrapped; + + // + // Check input parameters. + // + if (P7Data == NULL || TrustedCert == NULL || InData == NULL || + P7Length > INT_MAX || CertLength > INT_MAX || DataLength > INT_MAX) { + return FALSE; + } + + Pkcs7 = NULL; + DataBio = NULL; + Cert = NULL; + CertStore = NULL; + + // + // Register & Initialize necessary digest algorithms for PKCS#7 Handling + // + if (EVP_add_digest (EVP_md5 ()) == 0) { + return FALSE; + } + if (EVP_add_digest (EVP_sha1 ()) == 0) { + return FALSE; + } + if (EVP_add_digest (EVP_sha256 ()) == 0) { + return FALSE; + } + if (EVP_add_digest (EVP_sha384 ()) == 0) { + return FALSE; + } + if (EVP_add_digest (EVP_sha512 ()) == 0) { + return FALSE; + } + if (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA) == 0) { + return FALSE; + } + + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize); + if (!Status) { + return Status; + } + + Status = FALSE; + + // + // Retrieve PKCS#7 Data (DER encoding) + // + if (SignedDataSize > INT_MAX) { + goto _Exit; + } + + Temp = SignedData; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) SignedDataSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Check if it's PKCS#7 Signed Data (for Authenticode Scenario) + // + if (!PKCS7_type_is_signed (Pkcs7)) { + goto _Exit; + } + + // + // Read DER-encoded root certificate and Construct X509 Certificate + // + Temp = TrustedCert; + Cert = d2i_X509 (NULL, &Temp, (long) CertLength); + if (Cert == NULL) { + goto _Exit; + } + + // + // Setup X509 Store for trusted certificate + // + CertStore = X509_STORE_new (); + if (CertStore == NULL) { + goto _Exit; + } + if (!(X509_STORE_add_cert (CertStore, Cert))) { + goto _Exit; + } + + // + // For generic PKCS#7 handling, InData may be NULL if the content is present + // in PKCS#7 structure. So ignore NULL checking here. + // + DataBio = BIO_new (BIO_s_mem ()); + if (DataBio == NULL) { + goto _Exit; + } + + if (BIO_write (DataBio, InData, (int) DataLength) <= 0) { + goto _Exit; + } + + // + // Allow partial certificate chains, terminated by a non-self-signed but + // still trusted intermediate certificate. Also disable time checks. + // + X509_STORE_set_flags (CertStore, + X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME); + + // + // OpenSSL PKCS7 Verification by default checks for SMIME (email signing) and + // doesn't support the extended key usage for Authenticode Code Signing. + // Bypass the certificate purpose checking by enabling any purposes setting. + // + X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY); + + // + // Verifies the PKCS#7 signedData structure + // + Status = (BOOLEAN) PKCS7_verify (Pkcs7, NULL, CertStore, DataBio, NULL, PKCS7_BINARY); + +_Exit: + // + // Release Resources + // + BIO_free (DataBio); + X509_free (Cert); + X509_STORE_free (CertStore); + PKCS7_free (Pkcs7); + + if (!Wrapped) { + OPENSSL_free (SignedData); + } + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c new file mode 100644 index 00000000..b5f350b3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEku.c @@ -0,0 +1,517 @@ +/** @file + This module verifies that Enhanced Key Usages (EKU's) are present within + a PKCS7 signature blob using OpenSSL. + + Copyright (C) Microsoft Corporation. All Rights Reserved. + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include "InternalCryptLib.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + This function will return the leaf signer certificate in a chain. This is + required because certificate chains are not guaranteed to have the + certificates in the order that they were issued. + + A typical certificate chain looks like this: + + + ---------------------------- + | Root | + ---------------------------- + ^ + | + ---------------------------- + | Policy CA | <-- Typical Trust Anchor. + ---------------------------- + ^ + | + ---------------------------- + | Issuing CA | + ---------------------------- + ^ + | + ----------------------------- + / End-Entity (leaf) signer / <-- Bottom certificate. + ----------------------------- EKU: "1.3.6.1.4.1.311.76.9.21.1" + (Firmware Signing) + + + @param[in] CertChain Certificate chain. + + @param[out] SignerCert Last certificate in the chain. For PKCS7 signatures, + this will be the end-entity (leaf) signer cert. + + @retval EFI_SUCCESS The required EKUs were found in the signature. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND The number of signers found was not 1. + +**/ +EFI_STATUS +GetSignerCertificate ( + IN CONST PKCS7 *CertChain, + OUT X509 **SignerCert + ) +{ + EFI_STATUS Status; + STACK_OF(X509) *Signers; + INT32 NumberSigners; + + Status = EFI_SUCCESS; + Signers = NULL; + NumberSigners = 0; + + if (CertChain == NULL || SignerCert == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the signers from the chain. + // + Signers = PKCS7_get0_signers ((PKCS7*) CertChain, NULL, PKCS7_BINARY); + if (Signers == NULL) { + // + // Fail to get signers form PKCS7 + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // There should only be one signer in the PKCS7 stack. + // + NumberSigners = sk_X509_num (Signers); + if (NumberSigners != 1) { + // + // The number of singers should have been 1 + // + Status = EFI_NOT_FOUND; + goto Exit; + } + + *SignerCert = sk_X509_value (Signers, 0); + +Exit: + // + // Release Resources + // + if (Signers != NULL) { + sk_X509_free (Signers); + } + + return Status; +} + + +/** + Determines if the specified EKU represented in ASN1 form is present + in a given certificate. + + @param[in] Cert The certificate to check. + + @param[in] Asn1ToFind The EKU to look for. + + @retval EFI_SUCCESS We successfully identified the signing type. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. + +**/ +EFI_STATUS +IsEkuInCertificate ( + IN CONST X509 *Cert, + IN ASN1_OBJECT *Asn1ToFind + ) +{ + EFI_STATUS Status; + X509 *ClonedCert; + X509_EXTENSION *Extension; + EXTENDED_KEY_USAGE *Eku; + INT32 ExtensionIndex; + INTN NumExtensions; + ASN1_OBJECT *Asn1InCert; + INTN Index; + + Status = EFI_NOT_FOUND; + ClonedCert = NULL; + Extension = NULL; + Eku = NULL; + ExtensionIndex = -1; + NumExtensions = 0; + Asn1InCert = NULL; + + if (Cert == NULL || Asn1ToFind == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Clone the certificate. This is required because the Extension API's + // only work once per instance of an X509 object. + // + ClonedCert = X509_dup ((X509*)Cert); + if (ClonedCert == NULL) { + // + // Fail to duplicate cert. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Look for the extended key usage. + // + ExtensionIndex = X509_get_ext_by_NID (ClonedCert, NID_ext_key_usage, -1); + + if (ExtensionIndex < 0) { + // + // Fail to find 'NID_ext_key_usage' in Cert. + // + goto Exit; + } + + Extension = X509_get_ext (ClonedCert, ExtensionIndex); + if (Extension == NULL) { + // + // Fail to get Extension form cert. + // + goto Exit; + } + + Eku = (EXTENDED_KEY_USAGE*)X509V3_EXT_d2i (Extension); + if (Eku == NULL) { + // + // Fail to get Eku from extension. + // + goto Exit; + } + + NumExtensions = sk_ASN1_OBJECT_num (Eku); + + // + // Now loop through the extensions, looking for the specified Eku. + // + for (Index = 0; Index < NumExtensions; Index++) { + Asn1InCert = sk_ASN1_OBJECT_value (Eku, (INT32)Index); + if (Asn1InCert == NULL) { + // + // Fail to get ASN object from Eku. + // + goto Exit; + } + + if (Asn1InCert->length == Asn1ToFind->length && + CompareMem (Asn1InCert->data, Asn1ToFind->data, Asn1InCert->length) == 0) { + // + // Found Eku in certificate. + // + Status = EFI_SUCCESS; + goto Exit; + } + } + +Exit: + + // + // Release Resources + // + if (ClonedCert != NULL) { + X509_free (ClonedCert); + } + + if (Eku != NULL) { + sk_ASN1_OBJECT_pop_free (Eku, ASN1_OBJECT_free); + } + + return Status; +} + + +/** + Determines if the specified EKUs are present in a signing certificate. + + @param[in] SignerCert The certificate to check. + @param[in] RequiredEKUs The EKUs to look for. + @param[in] RequiredEKUsSize The number of EKUs + @param[in] RequireAllPresent If TRUE, then all the specified EKUs + must be present in the certificate. + + @retval EFI_SUCCESS We successfully identified the signing type. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. +**/ +EFI_STATUS +CheckEKUs( + IN CONST X509 *SignerCert, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + EFI_STATUS Status; + ASN1_OBJECT *Asn1ToFind; + UINT32 NumEkusFound; + UINT32 Index; + + Status = EFI_SUCCESS; + Asn1ToFind = NULL; + NumEkusFound = 0; + + if (SignerCert == NULL || RequiredEKUs == NULL || RequiredEKUsSize == 0) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + for (Index = 0; Index < RequiredEKUsSize; Index++) { + // + // Finding required EKU in cert. + // + if (Asn1ToFind != NULL) { + ASN1_OBJECT_free(Asn1ToFind); + Asn1ToFind = NULL; + } + + Asn1ToFind = OBJ_txt2obj (RequiredEKUs[Index], 0); + if (Asn1ToFind == NULL) { + // + // Fail to convert required EKU to ASN1. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = IsEkuInCertificate (SignerCert, Asn1ToFind); + if (Status == EFI_SUCCESS) { + NumEkusFound++; + if (!RequireAllPresent) { + // + // Found at least one, so we are done. + // + goto Exit; + } + } else { + // + // Fail to find Eku in cert + break; + } + } + +Exit: + + if (Asn1ToFind != NULL) { + ASN1_OBJECT_free(Asn1ToFind); + } + + if (RequireAllPresent && + NumEkusFound == RequiredEKUsSize) { + // + // Found all required EKUs in certificate. + // + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + This function receives a PKCS#7 formatted signature blob, + looks for the EKU SEQUENCE blob, and if found then looks + for all the required EKUs. This function was created so that + the Surface team can cut down on the number of Certificate + Authorities (CA's) by checking EKU's on leaf signers for + a specific product. This prevents one product's certificate + from signing another product's firmware or unlock blobs. + + Note that this function does not validate the certificate chain. + That needs to be done before using this function. + + @param[in] Pkcs7Signature The PKCS#7 signed information content block. An array + containing the content block with both the signature, + the signer's certificate, and any necessary intermediate + certificates. + @param[in] Pkcs7SignatureSize Number of bytes in Pkcs7Signature. + @param[in] RequiredEKUs Array of null-terminated strings listing OIDs of + required EKUs that must be present in the signature. + @param[in] RequiredEKUsSize Number of elements in the RequiredEKUs string array. + @param[in] RequireAllPresent If this is TRUE, then all of the specified EKU's + must be present in the leaf signer. If it is + FALSE, then we will succeed if we find any + of the specified EKU's. + + @retval EFI_SUCCESS The required EKUs were found in the signature. + @retval EFI_INVALID_PARAMETER A parameter was invalid. + @retval EFI_NOT_FOUND One or more EKU's were not found in the signature. + +**/ +EFI_STATUS +EFIAPI +VerifyEKUsInPkcs7Signature ( + IN CONST UINT8 *Pkcs7Signature, + IN CONST UINT32 SignatureSize, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + EFI_STATUS Status; + PKCS7 *Pkcs7; + STACK_OF(X509) *CertChain; + INT32 SignatureType; + INT32 NumberCertsInSignature; + X509 *SignerCert; + UINT8 *SignedData; + UINT8 *Temp; + UINTN SignedDataSize; + BOOLEAN IsWrapped; + BOOLEAN Ok; + + Status = EFI_SUCCESS; + Pkcs7 = NULL; + CertChain = NULL; + SignatureType = 0; + NumberCertsInSignature = 0; + SignerCert = NULL; + SignedData = NULL; + SignedDataSize = 0; + IsWrapped = FALSE; + Ok = FALSE; + + // + //Validate the input parameters. + // + if (Pkcs7Signature == NULL || + SignatureSize == 0 || + RequiredEKUs == NULL || + RequiredEKUsSize == 0) { + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + if (RequiredEKUsSize == 1) { + RequireAllPresent = TRUE; + } + + // + // Wrap the PKCS7 data if needed. + // + Ok = WrapPkcs7Data (Pkcs7Signature, + SignatureSize, + &IsWrapped, + &SignedData, + &SignedDataSize); + if (!Ok) { + // + // Fail to Wrap the PKCS7 data. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Temp = SignedData; + + // + // Create the PKCS7 object. + // + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **)&Temp, (INT32)SignedDataSize); + if (Pkcs7 == NULL) { + // + // Fail to read PKCS7 data. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the certificate chain. + // + SignatureType = OBJ_obj2nid (Pkcs7->type); + switch (SignatureType) { + case NID_pkcs7_signed: + if (Pkcs7->d.sign != NULL) { + CertChain = Pkcs7->d.sign->cert; + } + break; + case NID_pkcs7_signedAndEnveloped: + if (Pkcs7->d.signed_and_enveloped != NULL) { + CertChain = Pkcs7->d.signed_and_enveloped->cert; + } + break; + default: + break; + } + + // + // Ensure we have a certificate stack + // + if (CertChain == NULL) { + // + // Fail to get the certificate stack from signature. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Find out how many certificates were in the PKCS7 signature. + // + NumberCertsInSignature = sk_X509_num (CertChain); + + if (NumberCertsInSignature == 0) { + // + // Fail to find any certificates in signature. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + // + // Get the leaf signer. + // + Status = GetSignerCertificate (Pkcs7, &SignerCert); + if (Status != EFI_SUCCESS || SignerCert == NULL) { + // + // Fail to get the end-entity leaf signer certificate. + // + Status = EFI_INVALID_PARAMETER; + goto Exit; + } + + Status = CheckEKUs (SignerCert, RequiredEKUs, RequiredEKUsSize, RequireAllPresent); + if (Status != EFI_SUCCESS) { + goto Exit; + } + +Exit: + + // + // Release Resources + // + // If the signature was not wrapped, then the call to WrapData() will allocate + // the data and add a header to it + // + if (!IsWrapped && SignedData) { + free (SignedData); + } + + if (Pkcs7 != NULL) { + PKCS7_free (Pkcs7); + } + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c new file mode 100644 index 00000000..14d6f01b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyEkuRuntime.c @@ -0,0 +1,57 @@ +/** @file + This module verifies that Enhanced Key Usages (EKU's) are present within + a PKCS7 signature blob using OpenSSL. + + Copyright (C) Microsoft Corporation. All Rights Reserved. + Copyright (c) 2019, Intel Corporation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + This function receives a PKCS#7 formatted signature blob, + looks for the EKU SEQUENCE blob, and if found then looks + for all the required EKUs. This function was created so that + the Surface team can cut down on the number of Certificate + Authorities (CA's) by checking EKU's on leaf signers for + a specific product. This prevents one product's certificate + from signing another product's firmware or unlock blobs. + + Return RETURN_UNSUPPORTED to indicate this interface is not supported. + + @param[in] Pkcs7Signature The PKCS#7 signed information content block. An array + containing the content block with both the signature, + the signer's certificate, and any necessary intermediate + certificates. + @param[in] Pkcs7SignatureSize Number of bytes in pPkcs7Signature. + @param[in] RequiredEKUs Array of null-terminated strings listing OIDs of + required EKUs that must be present in the signature. + All specified EKU's must be present in order to + succeed. + @param[in] RequiredEKUsSize Number of elements in the rgRequiredEKUs string. + This parameter has a maximum of MAX_EKU_SEARCH. + @param[in] RequireAllPresent If this is TRUE, then all of the specified EKU's + must be present in the leaf signer. If it is + FALSE, then we will succeed if we find any + of the specified EKU's. + + @retval RETURN_UNSUPPORTED The operation is not supported. + +**/ +EFI_STATUS +EFIAPI +VerifyEKUsInPkcs7Signature ( + IN CONST UINT8 *Pkcs7Signature, + IN CONST UINT32 SignatureSize, + IN CONST CHAR8 *RequiredEKUs[], + IN CONST UINT32 RequiredEKUsSize, + IN BOOLEAN RequireAllPresent + ) +{ + ASSERT (FALSE); + return RETURN_UNSUPPORTED; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c new file mode 100644 index 00000000..2665fc18 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyNull.c @@ -0,0 +1,163 @@ +/** @file + PKCS#7 SignedData Verification Wrapper Implementation which does not provide + real capabilities. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Get the signer's certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + Return FALSE to indicate this interface is not supported. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] CertStack Pointer to Signer's certificates retrieved from P7Data. + It's caller's responsibility to free the buffer with + Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] StackLength Length of signer's certificates in bytes. + @param[out] TrustedCert Pointer to a trusted certificate from Signer's certificates. + It's caller's responsibility to free the buffer with + Pkcs7FreeSigners(). + @param[out] CertLength Length of the trusted certificate in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetSigners ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **CertStack, + OUT UINTN *StackLength, + OUT UINT8 **TrustedCert, + OUT UINTN *CertLength + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Wrap function to use free() to free allocated memory for certificates. + + If the interface is not supported, then ASSERT(). + + @param[in] Certs Pointer to the certificates to be freed. + +**/ +VOID +EFIAPI +Pkcs7FreeSigners ( + IN UINT8 *Certs + ) +{ + ASSERT (FALSE); +} + +/** + Retrieves all embedded certificates from PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard", and outputs two certificate lists chained and + unchained to the signer's certificates. + The input signed data could be wrapped in a ContentInfo structure. + + @param[in] P7Data Pointer to the PKCS#7 message. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[out] SignerChainCerts Pointer to the certificates list chained to signer's + certificate. It's caller's responsibility to free the buffer + with Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] ChainLength Length of the chained certificates list buffer in bytes. + @param[out] UnchainCerts Pointer to the unchained certificates lists. It's caller's + responsibility to free the buffer with Pkcs7FreeSigners(). + This data structure is EFI_CERT_STACK type. + @param[out] UnchainLength Length of the unchained certificates list buffer in bytes. + + @retval TRUE The operation is finished successfully. + @retval FALSE Error occurs during the operation. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetCertificatesList ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT UINT8 **SignerChainCerts, + OUT UINTN *ChainLength, + OUT UINT8 **UnchainCerts, + OUT UINTN *UnchainLength + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Verifies the validity of a PKCS#7 signed data as described in "PKCS #7: + Cryptographic Message Syntax Standard". The input signed data could be wrapped + in a ContentInfo structure. + + Return FALSE to indicate this interface is not supported. + + @param[in] P7Data Pointer to the PKCS#7 message to verify. + @param[in] P7Length Length of the PKCS#7 message in bytes. + @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which + is used for certificate chain verification. + @param[in] CertLength Length of the trusted certificate in bytes. + @param[in] InData Pointer to the content to be verified. + @param[in] DataLength Length of InData in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +Pkcs7Verify ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + IN CONST UINT8 *TrustedCert, + IN UINTN CertLength, + IN CONST UINT8 *InData, + IN UINTN DataLength + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Extracts the attached content from a PKCS#7 signed data if existed. The input signed + data could be wrapped in a ContentInfo structure. + + Return FALSE to indicate this interface is not supported. + + @param[in] P7Data Pointer to the PKCS#7 signed data to process. + @param[in] P7Length Length of the PKCS#7 signed data in bytes. + @param[out] Content Pointer to the extracted content from the PKCS#7 signedData. + It's caller's responsibility to free the buffer with FreePool(). + @param[out] ContentSize The size of the extracted content in bytes. + + @retval TRUE The P7Data was correctly formatted for processing. + @retval FALSE The P7Data was not correctly formatted for processing. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetAttachedContent ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT VOID **Content, + OUT UINTN *ContentSize + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c new file mode 100644 index 00000000..8249bb24 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyRuntime.c @@ -0,0 +1,39 @@ +/** @file + Runtime specific implementation of PKCS#7 SignedData Verification Wrapper. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Extracts the attached content from a PKCS#7 signed data if existed. The input signed + data could be wrapped in a ContentInfo structure. + + Return FALSE to indicate this interface is not supported. + + @param[in] P7Data Pointer to the PKCS#7 signed data to process. + @param[in] P7Length Length of the PKCS#7 signed data in bytes. + @param[out] Content Pointer to the extracted content from the PKCS#7 signedData. + It's caller's responsibility to free the buffer with FreePool(). + @param[out] ContentSize The size of the extracted content in bytes. + + @retval TRUE The P7Data was correctly formatted for processing. + @retval FALSE The P7Data was not correctly formatted for processing. + +**/ +BOOLEAN +EFIAPI +Pkcs7GetAttachedContent ( + IN CONST UINT8 *P7Data, + IN UINTN P7Length, + OUT VOID **Content, + OUT UINTN *ContentSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c new file mode 100644 index 00000000..4038af3e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c @@ -0,0 +1,327 @@ +/** @file + RSA Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file implements following APIs which provide basic capabilities for RSA: + 1) RsaNew + 2) RsaFree + 3) RsaSetKey + 4) RsaPkcs1Verify + +Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include + +/** + Allocates and initializes one RSA context for subsequent use. + + @return Pointer to the RSA context that has been initialized. + If the allocations fails, RsaNew() returns NULL. + +**/ +VOID * +EFIAPI +RsaNew ( + VOID + ) +{ + // + // Allocates & Initializes RSA Context by OpenSSL RSA_new() + // + return (VOID *) RSA_new (); +} + +/** + Release the specified RSA context. + + @param[in] RsaContext Pointer to the RSA context to be released. + +**/ +VOID +EFIAPI +RsaFree ( + IN VOID *RsaContext + ) +{ + // + // Free OpenSSL RSA Context + // + RSA_free ((RSA *) RsaContext); +} + +/** + 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 BigNumber is NULL, then the specified key component in RSA context is cleared. + + If RsaContext is NULL, then return FALSE. + + @param[in, out] RsaContext Pointer to RSA context being set. + @param[in] KeyTag Tag of RSA key component being set. + @param[in] BigNumber Pointer to octet integer buffer. + If NULL, then the specified key component in RSA + context is cleared. + @param[in] BnSize Size of big number buffer in bytes. + If BigNumber is NULL, then it is ignored. + + @retval TRUE RSA key component was set successfully. + @retval FALSE Invalid RSA key component tag. + +**/ +BOOLEAN +EFIAPI +RsaSetKey ( + IN OUT VOID *RsaContext, + IN RSA_KEY_TAG KeyTag, + IN CONST UINT8 *BigNumber, + IN UINTN BnSize + ) +{ + RSA *RsaKey; + BIGNUM *BnN; + BIGNUM *BnE; + BIGNUM *BnD; + BIGNUM *BnP; + BIGNUM *BnQ; + BIGNUM *BnDp; + BIGNUM *BnDq; + BIGNUM *BnQInv; + + // + // Check input parameters. + // + if (RsaContext == NULL || BnSize > INT_MAX) { + return FALSE; + } + + BnN = NULL; + BnE = NULL; + BnD = NULL; + BnP = NULL; + BnQ = NULL; + BnDp = NULL; + BnDq = NULL; + BnQInv = NULL; + + // + // Retrieve the components from RSA object. + // + RsaKey = (RSA *) RsaContext; + RSA_get0_key (RsaKey, (const BIGNUM **)&BnN, (const BIGNUM **)&BnE, (const BIGNUM **)&BnD); + RSA_get0_factors (RsaKey, (const BIGNUM **)&BnP, (const BIGNUM **)&BnQ); + RSA_get0_crt_params (RsaKey, (const BIGNUM **)&BnDp, (const BIGNUM **)&BnDq, (const BIGNUM **)&BnQInv); + + // + // 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 (KeyTag) { + + // + // RSA Public Modulus (N), Public Exponent (e) and Private Exponent (d) + // + case RsaKeyN: + case RsaKeyE: + case RsaKeyD: + if (BnN == NULL) { + BnN = BN_new (); + } + if (BnE == NULL) { + BnE = BN_new (); + } + if (BnD == NULL) { + BnD = BN_new (); + } + + if ((BnN == NULL) || (BnE == NULL) || (BnD == NULL)) { + return FALSE; + } + + switch (KeyTag) { + case RsaKeyN: + BnN = BN_bin2bn (BigNumber, (UINT32)BnSize, BnN); + break; + case RsaKeyE: + BnE = BN_bin2bn (BigNumber, (UINT32)BnSize, BnE); + break; + case RsaKeyD: + BnD = BN_bin2bn (BigNumber, (UINT32)BnSize, BnD); + break; + default: + return FALSE; + } + if (RSA_set0_key (RsaKey, BN_dup(BnN), BN_dup(BnE), BN_dup(BnD)) == 0) { + return FALSE; + } + + break; + + // + // RSA Secret Prime Factor of Modulus (p and q) + // + case RsaKeyP: + case RsaKeyQ: + if (BnP == NULL) { + BnP = BN_new (); + } + if (BnQ == NULL) { + BnQ = BN_new (); + } + if ((BnP == NULL) || (BnQ == NULL)) { + return FALSE; + } + + switch (KeyTag) { + case RsaKeyP: + BnP = BN_bin2bn (BigNumber, (UINT32)BnSize, BnP); + break; + case RsaKeyQ: + BnQ = BN_bin2bn (BigNumber, (UINT32)BnSize, BnQ); + break; + default: + return FALSE; + } + if (RSA_set0_factors (RsaKey, BN_dup(BnP), BN_dup(BnQ)) == 0) { + return FALSE; + } + + 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 RsaKeyDp: + case RsaKeyDq: + case RsaKeyQInv: + if (BnDp == NULL) { + BnDp = BN_new (); + } + if (BnDq == NULL) { + BnDq = BN_new (); + } + if (BnQInv == NULL) { + BnQInv = BN_new (); + } + if ((BnDp == NULL) || (BnDq == NULL) || (BnQInv == NULL)) { + return FALSE; + } + + switch (KeyTag) { + case RsaKeyDp: + BnDp = BN_bin2bn (BigNumber, (UINT32)BnSize, BnDp); + break; + case RsaKeyDq: + BnDq = BN_bin2bn (BigNumber, (UINT32)BnSize, BnDq); + break; + case RsaKeyQInv: + BnQInv = BN_bin2bn (BigNumber, (UINT32)BnSize, BnQInv); + break; + default: + return FALSE; + } + if (RSA_set0_crt_params (RsaKey, BN_dup(BnDp), BN_dup(BnDq), BN_dup(BnQInv)) == 0) { + return FALSE; + } + + break; + + default: + return FALSE; + } + + return TRUE; +} + +/** + Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in + RSA PKCS#1. + + If RsaContext is NULL, then return FALSE. + If MessageHash is NULL, then return FALSE. + If Signature is NULL, then return FALSE. + If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE. + + @param[in] RsaContext Pointer to RSA context for signature verification. + @param[in] MessageHash Pointer to octet message hash to be checked. + @param[in] HashSize Size of the message hash in bytes. + @param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified. + @param[in] SigSize Size of signature in bytes. + + @retval TRUE Valid signature encoded in PKCS1-v1_5. + @retval FALSE Invalid signature or invalid RSA context. + +**/ +BOOLEAN +EFIAPI +RsaPkcs1Verify ( + IN VOID *RsaContext, + IN CONST UINT8 *MessageHash, + IN UINTN HashSize, + IN CONST UINT8 *Signature, + IN UINTN SigSize + ) +{ + INT32 DigestType; + UINT8 *SigBuf; + + // + // Check input parameters. + // + if (RsaContext == NULL || MessageHash == NULL || Signature == NULL) { + return FALSE; + } + + if (SigSize > INT_MAX || SigSize == 0) { + return FALSE; + } + + // + // Determine the message digest algorithm according to digest size. + // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported. + // + switch (HashSize) { + case MD5_DIGEST_SIZE: + DigestType = NID_md5; + break; + + case SHA1_DIGEST_SIZE: + DigestType = NID_sha1; + break; + + case SHA256_DIGEST_SIZE: + DigestType = NID_sha256; + break; + + case SHA384_DIGEST_SIZE: + DigestType = NID_sha384; + break; + + case SHA512_DIGEST_SIZE: + DigestType = NID_sha512; + break; + + default: + return FALSE; + } + + SigBuf = (UINT8 *) Signature; + return (BOOLEAN) RSA_verify ( + DigestType, + MessageHash, + (UINT32) HashSize, + SigBuf, + (UINT32) SigSize, + (RSA *) RsaContext + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c new file mode 100644 index 00000000..10d96814 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExt.c @@ -0,0 +1,364 @@ +/** @file + RSA Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file implements following APIs which provide more capabilities for RSA: + 1) RsaGetKey + 2) RsaGenerateKey + 3) RsaCheckKey + 4) RsaPkcs1Sign + +Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include +#include + +/** + 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 + BnSize is set to 0. + If the BigNumber buffer is too small to hold the contents of the key, FALSE + is returned and BnSize is set to the required buffer size to obtain the key. + + If RsaContext is NULL, then return FALSE. + If BnSize is NULL, then return FALSE. + If BnSize is large enough but BigNumber is NULL, then return FALSE. + + @param[in, out] RsaContext Pointer to RSA context being set. + @param[in] KeyTag Tag of RSA key component being set. + @param[out] BigNumber Pointer to octet integer buffer. + @param[in, out] BnSize 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 BnSize is too small. + +**/ +BOOLEAN +EFIAPI +RsaGetKey ( + IN OUT VOID *RsaContext, + IN RSA_KEY_TAG KeyTag, + OUT UINT8 *BigNumber, + IN OUT UINTN *BnSize + ) +{ + RSA *RsaKey; + BIGNUM *BnKey; + UINTN Size; + + // + // Check input parameters. + // + if (RsaContext == NULL || BnSize == NULL) { + return FALSE; + } + + RsaKey = (RSA *) RsaContext; + Size = *BnSize; + *BnSize = 0; + BnKey = NULL; + + switch (KeyTag) { + + // + // RSA Public Modulus (N) + // + case RsaKeyN: + RSA_get0_key (RsaKey, (const BIGNUM **)&BnKey, NULL, NULL); + break; + + // + // RSA Public Exponent (e) + // + case RsaKeyE: + RSA_get0_key (RsaKey, NULL, (const BIGNUM **)&BnKey, NULL); + break; + + // + // RSA Private Exponent (d) + // + case RsaKeyD: + RSA_get0_key (RsaKey, NULL, NULL, (const BIGNUM **)&BnKey); + break; + + // + // RSA Secret Prime Factor of Modulus (p) + // + case RsaKeyP: + RSA_get0_factors (RsaKey, (const BIGNUM **)&BnKey, NULL); + break; + + // + // RSA Secret Prime Factor of Modules (q) + // + case RsaKeyQ: + RSA_get0_factors (RsaKey, NULL, (const BIGNUM **)&BnKey); + break; + + // + // p's CRT Exponent (== d mod (p - 1)) + // + case RsaKeyDp: + RSA_get0_crt_params (RsaKey, (const BIGNUM **)&BnKey, NULL, NULL); + break; + + // + // q's CRT Exponent (== d mod (q - 1)) + // + case RsaKeyDq: + RSA_get0_crt_params (RsaKey, NULL, (const BIGNUM **)&BnKey, NULL); + break; + + // + // The CRT Coefficient (== 1/q mod p) + // + case RsaKeyQInv: + RSA_get0_crt_params (RsaKey, NULL, NULL, (const BIGNUM **)&BnKey); + break; + + default: + return FALSE; + } + + if (BnKey == NULL) { + return FALSE; + } + + *BnSize = Size; + Size = BN_num_bytes (BnKey); + + if (*BnSize < Size) { + *BnSize = Size; + return FALSE; + } + + if (BigNumber == NULL) { + *BnSize = Size; + return TRUE; + } + *BnSize = BN_bn2bin (BnKey, BigNumber) ; + + 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 PublicExponent is NULL, the default RSA public exponent (0x10001) will be used. + + Before this function can be invoked, pseudorandom number generator must be correctly + initialized by RandomSeed(). + + If RsaContext is NULL, then return FALSE. + + @param[in, out] RsaContext Pointer to RSA context being set. + @param[in] ModulusLength Length of RSA modulus N in bits. + @param[in] PublicExponent Pointer to RSA public exponent. + @param[in] PublicExponentSize Size of RSA public exponent buffer in bytes. + + @retval TRUE RSA key component was generated successfully. + @retval FALSE Invalid RSA key component tag. + +**/ +BOOLEAN +EFIAPI +RsaGenerateKey ( + IN OUT VOID *RsaContext, + IN UINTN ModulusLength, + IN CONST UINT8 *PublicExponent, + IN UINTN PublicExponentSize + ) +{ + BIGNUM *KeyE; + BOOLEAN RetVal; + + // + // Check input parameters. + // + if (RsaContext == NULL || ModulusLength > INT_MAX || PublicExponentSize > INT_MAX) { + return FALSE; + } + + KeyE = BN_new (); + if (KeyE == NULL) { + return FALSE; + } + + RetVal = FALSE; + + if (PublicExponent == NULL) { + if (BN_set_word (KeyE, 0x10001) == 0) { + goto _Exit; + } + } else { + if (BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE) == NULL) { + goto _Exit; + } + } + + if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) { + RetVal = TRUE; + } + +_Exit: + BN_free (KeyE); + return RetVal; +} + +/** + 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 RsaContext is NULL, then return FALSE. + + @param[in] RsaContext Pointer to RSA context to check. + + @retval TRUE RSA key components are valid. + @retval FALSE RSA key components are not valid. + +**/ +BOOLEAN +EFIAPI +RsaCheckKey ( + IN VOID *RsaContext + ) +{ + UINTN Reason; + + // + // Check input parameters. + // + if (RsaContext == NULL) { + return FALSE; + } + + if (RSA_check_key ((RSA *) RsaContext) != 1) { + Reason = ERR_GET_REASON (ERR_peek_last_error ()); + if (Reason == RSA_R_P_NOT_PRIME || + Reason == RSA_R_Q_NOT_PRIME || + Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q || + Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) { + return FALSE; + } + } + + return TRUE; +} + +/** + 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 SigSize is set to the required buffer size to obtain the signature. + + If RsaContext is NULL, then return FALSE. + If MessageHash is NULL, then return FALSE. + If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE. + If SigSize is large enough but Signature is NULL, then return FALSE. + + @param[in] RsaContext Pointer to RSA context for signature generation. + @param[in] MessageHash Pointer to octet message hash to be signed. + @param[in] HashSize Size of the message hash in bytes. + @param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature. + @param[in, out] SigSize 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 SigSize is too small. + +**/ +BOOLEAN +EFIAPI +RsaPkcs1Sign ( + IN VOID *RsaContext, + IN CONST UINT8 *MessageHash, + IN UINTN HashSize, + OUT UINT8 *Signature, + IN OUT UINTN *SigSize + ) +{ + RSA *Rsa; + UINTN Size; + INT32 DigestType; + + // + // Check input parameters. + // + if (RsaContext == NULL || MessageHash == NULL) { + return FALSE; + } + + Rsa = (RSA *) RsaContext; + Size = RSA_size (Rsa); + + if (*SigSize < Size) { + *SigSize = Size; + return FALSE; + } + + if (Signature == NULL) { + return FALSE; + } + + // + // Determine the message digest algorithm according to digest size. + // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported. + // + switch (HashSize) { + case MD5_DIGEST_SIZE: + DigestType = NID_md5; + break; + + case SHA1_DIGEST_SIZE: + DigestType = NID_sha1; + break; + + case SHA256_DIGEST_SIZE: + DigestType = NID_sha256; + break; + + case SHA384_DIGEST_SIZE: + DigestType = NID_sha384; + break; + + case SHA512_DIGEST_SIZE: + DigestType = NID_sha512; + break; + + default: + return FALSE; + } + + return (BOOLEAN) RSA_sign ( + DigestType, + MessageHash, + (UINT32) HashSize, + Signature, + (UINT32 *) SigSize, + (RSA *) RsaContext + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c new file mode 100644 index 00000000..82982a1f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaExtNull.c @@ -0,0 +1,119 @@ +/** @file + RSA Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file does not provide real capabilities for following APIs in RSA handling: + 1) RsaGetKey + 2) RsaGenerateKey + 3) RsaCheckKey + 4) RsaPkcs1Sign + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Gets the tag-designated RSA key component from the established RSA context. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] RsaContext Pointer to RSA context being set. + @param[in] KeyTag Tag of RSA key component being set. + @param[out] BigNumber Pointer to octet integer buffer. + @param[in, out] BnSize On input, the size of big number buffer in bytes. + On output, the size of data returned in big number buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaGetKey ( + IN OUT VOID *RsaContext, + IN RSA_KEY_TAG KeyTag, + OUT UINT8 *BigNumber, + IN OUT UINTN *BnSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Generates RSA key components. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] RsaContext Pointer to RSA context being set. + @param[in] ModulusLength Length of RSA modulus N in bits. + @param[in] PublicExponent Pointer to RSA public exponent. + @param[in] PublicExponentSize Size of RSA public exponent buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaGenerateKey ( + IN OUT VOID *RsaContext, + IN UINTN ModulusLength, + IN CONST UINT8 *PublicExponent, + IN UINTN PublicExponentSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Validates key components of RSA context. + + Return FALSE to indicate this interface is not supported. + + @param[in] RsaContext Pointer to RSA context to check. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaCheckKey ( + IN VOID *RsaContext + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme. + + Return FALSE to indicate this interface is not supported. + + @param[in] RsaContext Pointer to RSA context for signature generation. + @param[in] MessageHash Pointer to octet message hash to be signed. + @param[in] HashSize Size of the message hash in bytes. + @param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature. + @param[in, out] SigSize On input, the size of Signature buffer in bytes. + On output, the size of data returned in Signature buffer in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaPkcs1Sign ( + IN VOID *RsaContext, + IN CONST UINT8 *MessageHash, + IN UINTN HashSize, + OUT UINT8 *Signature, + IN OUT UINTN *SigSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPss.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPss.c new file mode 100644 index 00000000..4c25404c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPss.c @@ -0,0 +1,152 @@ +/** @file + RSA Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file implements following APIs which provide basic capabilities for RSA: + 1) RsaPssVerify + +Copyright (c) 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include +#include + + +/** + Retrieve a pointer to EVP message digest object. + + @param[in] DigestLen Length of the message digest. + +**/ +STATIC +const +EVP_MD* +GetEvpMD ( + IN UINT16 DigestLen + ) +{ + switch (DigestLen){ + case SHA256_DIGEST_SIZE: + return EVP_sha256(); + break; + case SHA384_DIGEST_SIZE: + return EVP_sha384(); + break; + case SHA512_DIGEST_SIZE: + return EVP_sha512(); + break; + default: + return NULL; + } +} + + +/** + Verifies the RSA signature with RSASSA-PSS signature scheme defined in RFC 8017. + Implementation determines salt length automatically from the signature encoding. + Mask generation function is the same as the message digest algorithm. + Salt length should atleast be equal to digest length. + + @param[in] RsaContext Pointer to RSA context for signature verification. + @param[in] Message Pointer to octet message to be verified. + @param[in] MsgSize Size of the message in bytes. + @param[in] Signature Pointer to RSASSA-PSS signature to be verified. + @param[in] SigSize Size of signature in bytes. + @param[in] DigestLen Length of digest for RSA operation. + @param[in] SaltLen Salt length for PSS encoding. + + @retval TRUE Valid signature encoded in RSASSA-PSS. + @retval FALSE Invalid signature or invalid RSA context. + +**/ +BOOLEAN +EFIAPI +RsaPssVerify ( + IN VOID *RsaContext, + IN CONST UINT8 *Message, + IN UINTN MsgSize, + IN CONST UINT8 *Signature, + IN UINTN SigSize, + IN UINT16 DigestLen, + IN UINT16 SaltLen + ) +{ + BOOLEAN Result; + EVP_PKEY *EvpRsaKey; + EVP_MD_CTX *EvpVerifyCtx; + EVP_PKEY_CTX *KeyCtx; + CONST EVP_MD *HashAlg; + + Result = FALSE; + EvpRsaKey = NULL; + EvpVerifyCtx = NULL; + KeyCtx = NULL; + HashAlg = NULL; + + if (RsaContext == NULL) { + return FALSE; + } + if (Message == NULL || MsgSize == 0 || MsgSize > INT_MAX) { + return FALSE; + } + if (Signature == NULL || SigSize == 0 || SigSize > INT_MAX) { + return FALSE; + } + if (SaltLen < DigestLen) { + return FALSE; + } + + HashAlg = GetEvpMD(DigestLen); + + if (HashAlg == NULL) { + return FALSE; + } + + EvpRsaKey = EVP_PKEY_new(); + if (EvpRsaKey == NULL) { + goto _Exit; + } + + EVP_PKEY_set1_RSA(EvpRsaKey, RsaContext); + + EvpVerifyCtx = EVP_MD_CTX_create(); + if (EvpVerifyCtx == NULL) { + goto _Exit; + } + + Result = EVP_DigestVerifyInit(EvpVerifyCtx, &KeyCtx, HashAlg, NULL, EvpRsaKey) > 0; + if (KeyCtx == NULL) { + goto _Exit; + } + + if (Result) { + Result = EVP_PKEY_CTX_set_rsa_padding(KeyCtx, RSA_PKCS1_PSS_PADDING) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_set_rsa_pss_saltlen(KeyCtx, SaltLen) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_set_rsa_mgf1_md(KeyCtx, HashAlg) > 0; + } + if (Result) { + Result = EVP_DigestVerifyUpdate(EvpVerifyCtx, Message, (UINT32)MsgSize) > 0; + } + if (Result) { + Result = EVP_DigestVerifyFinal(EvpVerifyCtx, Signature, (UINT32)SigSize) > 0; + } + +_Exit : + if (EvpRsaKey != NULL) { + EVP_PKEY_free(EvpRsaKey); + } + if (EvpVerifyCtx != NULL) { + EVP_MD_CTX_destroy(EvpVerifyCtx); + } + + return Result; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssNull.c new file mode 100644 index 00000000..ff6d11c8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssNull.c @@ -0,0 +1,46 @@ +/** @file + RSA-PSS Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file does not provide real capabilities for following APIs in RSA handling: + 1) RsaPssVerify + +Copyright (c) 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Verifies the RSA signature with RSASSA-PSS signature scheme defined in RFC 8017. + Implementation determines salt length automatically from the signature encoding. + Mask generation function is the same as the message digest algorithm. + Salt length should atleast be equal to digest length. + + @param[in] RsaContext Pointer to RSA context for signature verification. + @param[in] Message Pointer to octet message to be verified. + @param[in] MsgSize Size of the message in bytes. + @param[in] Signature Pointer to RSASSA-PSS signature to be verified. + @param[in] SigSize Size of signature in bytes. + @param[in] DigestLen Length of digest for RSA operation. + @param[in] SaltLen Salt length for PSS encoding. + + @retval TRUE Valid signature encoded in RSASSA-PSS. + @retval FALSE Invalid signature or invalid RSA context. + +**/ +BOOLEAN +EFIAPI +RsaPssVerify ( + IN VOID *RsaContext, + IN CONST UINT8 *Message, + IN UINTN MsgSize, + IN CONST UINT8 *Signature, + IN UINTN SigSize, + IN UINT16 DigestLen, + IN UINT16 SaltLen + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c new file mode 100644 index 00000000..369648e0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSign.c @@ -0,0 +1,175 @@ +/** @file + RSA PSS Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file implements following APIs which provide basic capabilities for RSA: + 1) RsaPssSign + +Copyright (c) 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include +#include + + +/** + Retrieve a pointer to EVP message digest object. + + @param[in] DigestLen Length of the message digest. + +**/ +STATIC +const +EVP_MD* +GetEvpMD ( + IN UINT16 DigestLen + ) +{ + switch (DigestLen){ + case SHA256_DIGEST_SIZE: + return EVP_sha256(); + break; + case SHA384_DIGEST_SIZE: + return EVP_sha384(); + break; + case SHA512_DIGEST_SIZE: + return EVP_sha512(); + break; + default: + return NULL; + } +} + + +/** + 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 + RFC 8017. + Mask generation function is the same as the message digest algorithm. + If the Signature buffer is too small to hold the contents of signature, FALSE + is returned and SigSize is set to the required buffer size to obtain the signature. + + If RsaContext is NULL, then return FALSE. + If Message is NULL, then return FALSE. + If MsgSize is zero or > INT_MAX, then return FALSE. + If DigestLen is NOT 32, 48 or 64, return FALSE. + If SaltLen is < DigestLen, then return FALSE. + If SigSize is large enough but Signature is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] RsaContext Pointer to RSA context for signature generation. + @param[in] Message Pointer to octet message to be signed. + @param[in] MsgSize Size of the message in bytes. + @param[in] DigestLen Length of the digest in bytes to be used for RSA signature operation. + @param[in] SaltLen Length of the salt in bytes to be used for PSS encoding. + @param[out] Signature Pointer to buffer to receive RSA PSS signature. + @param[in, out] SigSize 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 RSASSA-PSS. + @retval FALSE Signature generation failed. + @retval FALSE SigSize is too small. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaPssSign ( + IN VOID *RsaContext, + IN CONST UINT8 *Message, + IN UINTN MsgSize, + IN UINT16 DigestLen, + IN UINT16 SaltLen, + OUT UINT8 *Signature, + IN OUT UINTN *SigSize + ) +{ + BOOLEAN Result; + UINTN RsaSigSize; + EVP_PKEY *EvpRsaKey; + EVP_MD_CTX *EvpVerifyCtx; + EVP_PKEY_CTX *KeyCtx; + CONST EVP_MD *HashAlg; + + Result = FALSE; + EvpRsaKey = NULL; + EvpVerifyCtx = NULL; + KeyCtx = NULL; + HashAlg = NULL; + + if (RsaContext == NULL) { + return FALSE; + } + if (Message == NULL || MsgSize == 0 || MsgSize > INT_MAX) { + return FALSE; + } + + RsaSigSize = RSA_size (RsaContext); + if (*SigSize < RsaSigSize) { + *SigSize = RsaSigSize; + return FALSE; + } + + if (Signature == NULL) { + return FALSE; + } + + if (SaltLen < DigestLen) { + return FALSE; + } + + HashAlg = GetEvpMD(DigestLen); + + if (HashAlg == NULL) { + return FALSE; + } + + EvpRsaKey = EVP_PKEY_new(); + if (EvpRsaKey == NULL) { + goto _Exit; + } + + EVP_PKEY_set1_RSA(EvpRsaKey, RsaContext); + + EvpVerifyCtx = EVP_MD_CTX_create(); + if (EvpVerifyCtx == NULL) { + goto _Exit; + } + + Result = EVP_DigestSignInit(EvpVerifyCtx, &KeyCtx, HashAlg, NULL, EvpRsaKey) > 0; + if (KeyCtx == NULL) { + goto _Exit; + } + + if (Result) { + Result = EVP_PKEY_CTX_set_rsa_padding(KeyCtx, RSA_PKCS1_PSS_PADDING) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_set_rsa_pss_saltlen(KeyCtx, SaltLen) > 0; + } + if (Result) { + Result = EVP_PKEY_CTX_set_rsa_mgf1_md(KeyCtx, HashAlg) > 0; + } + if (Result) { + Result = EVP_DigestSignUpdate(EvpVerifyCtx, Message, (UINT32)MsgSize) > 0; + } + if (Result) { + Result = EVP_DigestSignFinal(EvpVerifyCtx, Signature, SigSize) > 0; + } + +_Exit : + if (EvpRsaKey != NULL) { + EVP_PKEY_free(EvpRsaKey); + } + if (EvpVerifyCtx != NULL) { + EVP_MD_CTX_destroy(EvpVerifyCtx); + } + + return Result; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSignNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSignNull.c new file mode 100644 index 00000000..52cef5eb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaPssSignNull.c @@ -0,0 +1,60 @@ +/** @file + RSA-PSS Asymmetric Cipher Wrapper Implementation over OpenSSL. + + This file does not provide real capabilities for following APIs in RSA handling: + 1) RsaPssSign + +Copyright (c) 2021, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + 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 + RFC 8017. + Mask generation function is the same as the message digest algorithm. + If the Signature buffer is too small to hold the contents of signature, FALSE + is returned and SigSize is set to the required buffer size to obtain the signature. + + If RsaContext is NULL, then return FALSE. + If Message is NULL, then return FALSE. + If MsgSize is zero or > INT_MAX, then return FALSE. + If DigestLen is NOT 32, 48 or 64, return FALSE. + If SaltLen is < DigestLen, then return FALSE. + If SigSize is large enough but Signature is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in] RsaContext Pointer to RSA context for signature generation. + @param[in] Message Pointer to octet message to be signed. + @param[in] MsgSize Size of the message in bytes. + @param[in] DigestLen Length of the digest in bytes to be used for RSA signature operation. + @param[in] SaltLen Length of the salt in bytes to be used for PSS encoding. + @param[out] Signature Pointer to buffer to receive RSA PSS signature. + @param[in, out] SigSize 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 RSASSA-PSS. + @retval FALSE Signature generation failed. + @retval FALSE SigSize is too small. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaPssSign ( + IN VOID *RsaContext, + IN CONST UINT8 *Message, + IN UINTN MsgSize, + IN UINT16 DigestLen, + IN UINT16 SaltLen, + OUT UINT8 *Signature, + IN OUT UINTN *SigSize + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c new file mode 100644 index 00000000..ab6ca633 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTs.c @@ -0,0 +1,659 @@ +/** @file + RFC3161 Timestamp Countersignature Verification over OpenSSL. + The timestamp is generated by a TimeStamping Authority (TSA) and asserts that a + publisher's signature existed before the specified time. The timestamp extends + the lifetime of the signature when a signing certificate expires or is later + revoked. + +Copyright (c) 2014 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +#include +#include +#include +#include +#include + +// +// OID ASN.1 Value for SPC_RFC3161_OBJID ("1.3.6.1.4.1.311.3.3.1") +// +UINT8 mSpcRFC3161OidValue[] = { + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01 + }; + +/// +/// The messageImprint field SHOULD contain the hash of the datum to be +/// time-stamped. The hash is represented as an OCTET STRING. Its +/// length MUST match the length of the hash value for that algorithm +/// (e.g., 20 bytes for SHA-1 or 16 bytes for MD5). +/// +/// MessageImprint ::= SEQUENCE { +/// hashAlgorithm AlgorithmIdentifier, +/// hashedMessage OCTET STRING } +/// +typedef struct { + X509_ALGOR *HashAlgorithm; + ASN1_OCTET_STRING *HashedMessage; +} TS_MESSAGE_IMPRINT; + +// +// ASN.1 Functions for TS_MESSAGE_IMPRINT +// +DECLARE_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT) +ASN1_SEQUENCE (TS_MESSAGE_IMPRINT) = { + ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashAlgorithm, X509_ALGOR), + ASN1_SIMPLE (TS_MESSAGE_IMPRINT, HashedMessage, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END (TS_MESSAGE_IMPRINT) +IMPLEMENT_ASN1_FUNCTIONS (TS_MESSAGE_IMPRINT) + +/// +/// Accuracy represents the time deviation around the UTC time contained +/// in GeneralizedTime of time-stamp token. +/// +/// Accuracy ::= SEQUENCE { +/// seconds INTEGER OPTIONAL, +/// millis [0] INTEGER (1..999) OPTIONAL, +/// micros [1] INTEGER (1..999) OPTIONAL } +/// +typedef struct { + ASN1_INTEGER *Seconds; + ASN1_INTEGER *Millis; + ASN1_INTEGER *Micros; +} TS_ACCURACY; + +// +// ASN.1 Functions for TS_ACCURACY +// +DECLARE_ASN1_FUNCTIONS (TS_ACCURACY) +ASN1_SEQUENCE (TS_ACCURACY) = { + ASN1_OPT (TS_ACCURACY, Seconds, ASN1_INTEGER), + ASN1_IMP_OPT (TS_ACCURACY, Millis, ASN1_INTEGER, 0), + ASN1_IMP_OPT (TS_ACCURACY, Micros, ASN1_INTEGER, 1) +} ASN1_SEQUENCE_END (TS_ACCURACY) +IMPLEMENT_ASN1_FUNCTIONS (TS_ACCURACY) + +/// +/// The timestamp token info resulting from a successful timestamp request, +/// as defined in RFC 3161. +/// +/// TSTInfo ::= SEQUENCE { +/// version INTEGER { v1(1) }, +/// policy TSAPolicyId, +/// messageImprint MessageImprint, +/// -- MUST have the same value as the similar field in +/// -- TimeStampReq +/// serialNumber INTEGER, +/// -- Time-Stamping users MUST be ready to accommodate integers +/// -- up to 160 bits. +/// genTime GeneralizedTime, +/// accuracy Accuracy OPTIONAL, +/// ordering BOOLEAN DEFAULT FALSE, +/// nonce INTEGER OPTIONAL, +/// -- MUST be present if the similar field was present +/// -- in TimeStampReq. In that case it MUST have the same value. +/// tsa [0] GeneralName OPTIONAL, +/// extensions [1] IMPLICIT Extensions OPTIONAL } +/// +typedef struct { + ASN1_INTEGER *Version; + ASN1_OBJECT *Policy; + TS_MESSAGE_IMPRINT *MessageImprint; + ASN1_INTEGER *SerialNumber; + ASN1_GENERALIZEDTIME *GenTime; + TS_ACCURACY *Accuracy; + ASN1_BOOLEAN Ordering; + ASN1_INTEGER *Nonce; + GENERAL_NAME *Tsa; + STACK_OF(X509_EXTENSION) *Extensions; +} TS_TST_INFO; + +// +// ASN.1 Functions for TS_TST_INFO +// +DECLARE_ASN1_FUNCTIONS (TS_TST_INFO) +ASN1_SEQUENCE (TS_TST_INFO) = { + ASN1_SIMPLE (TS_TST_INFO, Version, ASN1_INTEGER), + ASN1_SIMPLE (TS_TST_INFO, Policy, ASN1_OBJECT), + ASN1_SIMPLE (TS_TST_INFO, MessageImprint, TS_MESSAGE_IMPRINT), + ASN1_SIMPLE (TS_TST_INFO, SerialNumber, ASN1_INTEGER), + ASN1_SIMPLE (TS_TST_INFO, GenTime, ASN1_GENERALIZEDTIME), + ASN1_OPT (TS_TST_INFO, Accuracy, TS_ACCURACY), + ASN1_OPT (TS_TST_INFO, Ordering, ASN1_FBOOLEAN), + ASN1_OPT (TS_TST_INFO, Nonce, ASN1_INTEGER), + ASN1_EXP_OPT(TS_TST_INFO, Tsa, GENERAL_NAME, 0), + ASN1_IMP_SEQUENCE_OF_OPT (TS_TST_INFO, Extensions, X509_EXTENSION, 1) +} ASN1_SEQUENCE_END (TS_TST_INFO) +IMPLEMENT_ASN1_FUNCTIONS (TS_TST_INFO) + + +/** + Convert ASN.1 GeneralizedTime to EFI Time. + + @param[in] Asn1Time Pointer to the ASN.1 GeneralizedTime to be converted. + @param[out] SigningTime Return the corresponding EFI Time. + + @retval TRUE The time conversion succeeds. + @retval FALSE Invalid parameters. + +**/ +BOOLEAN +EFIAPI +ConvertAsn1TimeToEfiTime ( + IN ASN1_TIME *Asn1Time, + OUT EFI_TIME *EfiTime + ) +{ + CONST CHAR8 *Str; + UINTN Index; + + if ((Asn1Time == NULL) || (EfiTime == NULL)) { + return FALSE; + } + + Str = (CONST CHAR8*)Asn1Time->data; + SetMem (EfiTime, 0, sizeof (EFI_TIME)); + + Index = 0; + if (Asn1Time->type == V_ASN1_UTCTIME) { /* two digit year */ + EfiTime->Year = (Str[Index++] - '0') * 10; + EfiTime->Year += (Str[Index++] - '0'); + if (EfiTime->Year < 70) { + EfiTime->Year += 100; + } + } else if (Asn1Time->type == V_ASN1_GENERALIZEDTIME) { /* four digit year */ + EfiTime->Year = (Str[Index++] - '0') * 1000; + EfiTime->Year += (Str[Index++] - '0') * 100; + EfiTime->Year += (Str[Index++] - '0') * 10; + EfiTime->Year += (Str[Index++] - '0'); + if ((EfiTime->Year < 1900) || (EfiTime->Year > 9999)) { + return FALSE; + } + } + + EfiTime->Month = (Str[Index++] - '0') * 10; + EfiTime->Month += (Str[Index++] - '0'); + if ((EfiTime->Month < 1) || (EfiTime->Month > 12)) { + return FALSE; + } + + EfiTime->Day = (Str[Index++] - '0') * 10; + EfiTime->Day += (Str[Index++] - '0'); + if ((EfiTime->Day < 1) || (EfiTime->Day > 31)) { + return FALSE; + } + + EfiTime->Hour = (Str[Index++] - '0') * 10; + EfiTime->Hour += (Str[Index++] - '0'); + if (EfiTime->Hour > 23) { + return FALSE; + } + + EfiTime->Minute = (Str[Index++] - '0') * 10; + EfiTime->Minute += (Str[Index++] - '0'); + if (EfiTime->Minute > 59) { + return FALSE; + } + + EfiTime->Second = (Str[Index++] - '0') * 10; + EfiTime->Second += (Str[Index++] - '0'); + if (EfiTime->Second > 59) { + return FALSE; + } + + /* Note: we did not adjust the time based on time zone information */ + + return TRUE; +} + +/** + + Check the validity of TimeStamp Token Information. + + @param[in] TstInfo Pointer to the TS_TST_INFO structure. + @param[in] TimestampedData Pointer to the data to be time-stamped. + @param[in] DataSize Size of timestamped data in bytes. + + @retval TRUE The TimeStamp Token Information is valid. + @retval FALSE Invalid TimeStamp Token Information. + +**/ +BOOLEAN +EFIAPI +CheckTSTInfo ( + IN CONST TS_TST_INFO *TstInfo, + IN CONST UINT8 *TimestampedData, + IN UINTN DataSize + ) +{ + BOOLEAN Status; + TS_MESSAGE_IMPRINT *Imprint; + X509_ALGOR *HashAlgo; + CONST EVP_MD *Md; + EVP_MD_CTX *MdCtx; + UINTN MdSize; + UINT8 *HashedMsg; + + // + // Initialization + // + Status = FALSE; + HashAlgo = NULL; + HashedMsg = NULL; + MdCtx = NULL; + + // + // -- Check version number of Timestamp: + // The version field (currently v1) describes the version of the time-stamp token. + // Conforming time-stamping servers MUST be able to provide version 1 time-stamp tokens. + // + if ((ASN1_INTEGER_get (TstInfo->Version)) != 1) { + return FALSE; + } + + // + // -- Check Policies + // The policy field MUST indicate the TSA's policy under which the response was produced. + // + if (TstInfo->Policy == NULL) { + /// NOTE: Need to check if the requested and returned policies. + /// We have no information about the Requested TSA Policy. + return FALSE; + } + + // + // -- Compute & Check Message Imprint + // + Imprint = TstInfo->MessageImprint; + HashAlgo = X509_ALGOR_dup (Imprint->HashAlgorithm); + + Md = EVP_get_digestbyobj (HashAlgo->algorithm); + if (Md == NULL) { + goto _Exit; + } + + MdSize = EVP_MD_size (Md); + HashedMsg = AllocateZeroPool (MdSize); + if (HashedMsg == NULL) { + goto _Exit; + } + MdCtx = EVP_MD_CTX_new (); + if (MdCtx == NULL) { + goto _Exit; + } + if ((EVP_DigestInit_ex (MdCtx, Md, NULL) != 1) || + (EVP_DigestUpdate (MdCtx, TimestampedData, DataSize) != 1) || + (EVP_DigestFinal (MdCtx, HashedMsg, NULL) != 1)) { + goto _Exit; + } + if ((MdSize == (UINTN)ASN1_STRING_length (Imprint->HashedMessage)) && + (CompareMem (HashedMsg, ASN1_STRING_get0_data (Imprint->HashedMessage), MdSize) != 0)) { + goto _Exit; + } + + // + // -- Check Nonces + // + if (TstInfo->Nonce != NULL) { + // + // Nonces is optional, No error if no nonce is returned; + // + } + + // + // -- Check if the TSA name and signer certificate is matched. + // + if (TstInfo->Tsa != NULL) { + // + // Ignored the optional Tsa field checking. + // + } + + Status = TRUE; + +_Exit: + X509_ALGOR_free (HashAlgo); + EVP_MD_CTX_free (MdCtx); + if (HashedMsg != NULL) { + FreePool (HashedMsg); + } + + return Status; +} + +/** + Verifies the validity of a TimeStamp Token as described in RFC 3161 ("Internet + X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)"). + + If TSToken is NULL, then return FALSE. + If TimestampedData is NULL, then return FALSE. + + @param[in] TSToken Pointer to the RFC3161 TimeStamp Token, which is generated + by a TSA and located in the software publisher's SignerInfo + structure. + @param[in] TokenSize Size of the TimeStamp Token in bytes. + @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER. + @param[in] CertSize Size of the trusted TSA certificate in bytes. + @param[in] TimestampedData Pointer to the data to be time-stamped. + @param[in] DataSize Size of timestamped data in bytes. + @param[out] SigningTime Return the time of timestamp generation time if the timestamp + signature is valid. + + @retval TRUE The specified timestamp token is valid. + @retval FALSE Invalid timestamp token. + +**/ +BOOLEAN +EFIAPI +TimestampTokenVerify ( + IN CONST UINT8 *TSToken, + IN UINTN TokenSize, + IN CONST UINT8 *TsaCert, + IN UINTN CertSize, + IN CONST UINT8 *TimestampedData, + IN UINTN DataSize, + OUT EFI_TIME *SigningTime + ) +{ + BOOLEAN Status; + CONST UINT8 *TokenTemp; + PKCS7 *Pkcs7; + X509 *Cert; + CONST UINT8 *CertTemp; + X509_STORE *CertStore; + BIO *OutBio; + UINT8 *TstData; + UINTN TstSize; + CONST UINT8 *TstTemp; + TS_TST_INFO *TstInfo; + + Status = FALSE; + + // + // Check input parameters + // + if ((TSToken == NULL) || (TsaCert == NULL) || (TimestampedData == NULL) || + (TokenSize > INT_MAX) || (CertSize > INT_MAX) || (DataSize > INT_MAX)) { + return FALSE; + } + + // + // Initializations + // + if (SigningTime != NULL) { + SetMem (SigningTime, sizeof (EFI_TIME), 0); + } + Pkcs7 = NULL; + Cert = NULL; + CertStore = NULL; + OutBio = NULL; + TstData = NULL; + TstInfo = NULL; + + // + // TimeStamp Token should contain one valid DER-encoded ASN.1 PKCS#7 structure. + // + TokenTemp = TSToken; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &TokenTemp, (int) TokenSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // The timestamp signature (TSA's response) will be one PKCS#7 signed data. + // + if (!PKCS7_type_is_signed (Pkcs7)) { + goto _Exit; + } + + // + // Read the trusted TSA certificate (DER-encoded), and Construct X509 Certificate. + // + CertTemp = TsaCert; + Cert = d2i_X509 (NULL, &CertTemp, (long) CertSize); + if (Cert == NULL) { + goto _Exit; + } + + // + // Setup X509 Store for trusted certificate. + // + CertStore = X509_STORE_new (); + if ((CertStore == NULL) || !(X509_STORE_add_cert (CertStore, Cert))) { + goto _Exit; + } + + // + // Allow partial certificate chains, terminated by a non-self-signed but + // still trusted intermediate certificate. Also disable time checks. + // + X509_STORE_set_flags (CertStore, + X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME); + + X509_STORE_set_purpose (CertStore, X509_PURPOSE_ANY); + + // + // Verifies the PKCS#7 signedData structure, and output the signed contents. + // + OutBio = BIO_new (BIO_s_mem ()); + if (OutBio == NULL) { + goto _Exit; + } + if (!PKCS7_verify (Pkcs7, NULL, CertStore, NULL, OutBio, PKCS7_BINARY)) { + goto _Exit; + } + + // + // Read the signed contents detached in timestamp signature. + // + TstData = AllocateZeroPool (2048); + if (TstData == NULL) { + goto _Exit; + } + TstSize = BIO_read (OutBio, (void *) TstData, 2048); + + // + // Construct TS_TST_INFO structure from the signed contents. + // + TstTemp = TstData; + TstInfo = d2i_TS_TST_INFO (NULL, (const unsigned char **) &TstTemp, + (int)TstSize); + if (TstInfo == NULL) { + goto _Exit; + } + + // + // Check TS_TST_INFO structure. + // + Status = CheckTSTInfo (TstInfo, TimestampedData, DataSize); + if (!Status) { + goto _Exit; + } + + // + // Retrieve the signing time from TS_TST_INFO structure. + // + if (SigningTime != NULL) { + SetMem (SigningTime, sizeof (EFI_TIME), 0); + Status = ConvertAsn1TimeToEfiTime (TstInfo->GenTime, SigningTime); + } + +_Exit: + // + // Release Resources + // + PKCS7_free (Pkcs7); + X509_free (Cert); + X509_STORE_free (CertStore); + BIO_free (OutBio); + TS_TST_INFO_free (TstInfo); + + if (TstData != NULL) { + FreePool (TstData); + } + + return Status; +} + +/** + Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode + signature. + + If AuthData is NULL, then return FALSE. + + @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed + PE/COFF image to be verified. + @param[in] DataSize Size of the Authenticode Signature in bytes. + @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which + is used for TSA certificate chain verification. + @param[in] CertSize Size of the trusted certificate in bytes. + @param[out] SigningTime Return the time of timestamp generation time if the timestamp + signature is valid. + + @retval TRUE The specified Authenticode includes a valid RFC3161 Timestamp CounterSignature. + @retval FALSE No valid RFC3161 Timestamp CounterSignature in the specified Authenticode data. + +**/ +BOOLEAN +EFIAPI +ImageTimestampVerify ( + IN CONST UINT8 *AuthData, + IN UINTN DataSize, + IN CONST UINT8 *TsaCert, + IN UINTN CertSize, + OUT EFI_TIME *SigningTime + ) +{ + BOOLEAN Status; + PKCS7 *Pkcs7; + CONST UINT8 *Temp; + STACK_OF(PKCS7_SIGNER_INFO) *SignerInfos; + PKCS7_SIGNER_INFO *SignInfo; + UINTN Index; + STACK_OF(X509_ATTRIBUTE) *Sk; + X509_ATTRIBUTE *Xa; + ASN1_OBJECT *XaObj; + ASN1_TYPE *Asn1Type; + ASN1_OCTET_STRING *EncDigest; + UINT8 *TSToken; + UINTN TokenSize; + + // + // Input Parameters Checking. + // + if ((AuthData == NULL) || (TsaCert == NULL)) { + return FALSE; + } + + if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) { + return FALSE; + } + + // + // Register & Initialize necessary digest algorithms for PKCS#7 Handling. + // + if ((EVP_add_digest (EVP_md5 ()) == 0) || (EVP_add_digest (EVP_sha1 ()) == 0) || + (EVP_add_digest (EVP_sha256 ()) == 0) || (EVP_add_digest_alias (SN_sha1WithRSAEncryption, SN_sha1WithRSA)) == 0) { + return FALSE; + } + + // + // Initialization. + // + Status = FALSE; + Pkcs7 = NULL; + SignInfo = NULL; + + // + // Decode ASN.1-encoded Authenticode data into PKCS7 structure. + // + Temp = AuthData; + Pkcs7 = d2i_PKCS7 (NULL, (const unsigned char **) &Temp, (int) DataSize); + if (Pkcs7 == NULL) { + goto _Exit; + } + + // + // Check if there is one and only one signer. + // + SignerInfos = PKCS7_get_signer_info (Pkcs7); + if (!SignerInfos || (sk_PKCS7_SIGNER_INFO_num (SignerInfos) != 1)) { + goto _Exit; + } + + // + // Locate the TimeStamp CounterSignature. + // + SignInfo = sk_PKCS7_SIGNER_INFO_value (SignerInfos, 0); + if (SignInfo == NULL) { + goto _Exit; + } + + // + // Locate Message Digest which will be the data to be time-stamped. + // + EncDigest = SignInfo->enc_digest; + if (EncDigest == NULL) { + goto _Exit; + } + + // + // The RFC3161 timestamp counterSignature is contained in unauthenticatedAttributes field + // of SignerInfo. + // + Sk = SignInfo->unauth_attr; + if (Sk == NULL) { // No timestamp counterSignature. + goto _Exit; + } + + Asn1Type = NULL; + for (Index = 0; Index < (UINTN) sk_X509_ATTRIBUTE_num (Sk); Index++) { + // + // Search valid RFC3161 timestamp counterSignature based on OBJID. + // + Xa = sk_X509_ATTRIBUTE_value (Sk, (int)Index); + if (Xa == NULL) { + continue; + } + XaObj = X509_ATTRIBUTE_get0_object(Xa); + if (XaObj == NULL) { + continue; + } + if ((OBJ_length(XaObj) != sizeof (mSpcRFC3161OidValue)) || + (CompareMem (OBJ_get0_data(XaObj), mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0)) { + continue; + } + Asn1Type = X509_ATTRIBUTE_get0_type(Xa, 0); + } + + if (Asn1Type == NULL) { + Status = FALSE; + goto _Exit; + } + TSToken = Asn1Type->value.octet_string->data; + TokenSize = Asn1Type->value.octet_string->length; + + // + // TimeStamp counterSignature (Token) verification. + // + Status = TimestampTokenVerify ( + TSToken, + TokenSize, + TsaCert, + CertSize, + EncDigest->data, + EncDigest->length, + SigningTime + ); + +_Exit: + // + // Release Resources + // + PKCS7_free (Pkcs7); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c new file mode 100644 index 00000000..3535774b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptTsNull.c @@ -0,0 +1,42 @@ +/** @file + RFC3161 Timestamp Countersignature Verification Wrapper Implementation which does + not provide real capabilities. + +Copyright (c) 2014, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Verifies the validity of a RFC3161 Timestamp CounterSignature embedded in PE/COFF Authenticode + signature. + + Return FALSE to indicate this interface is not supported. + + @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed + PE/COFF image to be verified. + @param[in] DataSize Size of the Authenticode Signature in bytes. + @param[in] TsaCert Pointer to a trusted/root TSA certificate encoded in DER, which + is used for TSA certificate chain verification. + @param[in] CertSize Size of the trusted certificate in bytes. + @param[out] SigningTime Return the time of timestamp generation time if the timestamp + signature is valid. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +ImageTimestampVerify ( + IN CONST UINT8 *AuthData, + IN UINTN DataSize, + IN CONST UINT8 *TsaCert, + IN UINTN CertSize, + OUT EFI_TIME *SigningTime + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c new file mode 100644 index 00000000..5f66a148 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c @@ -0,0 +1,832 @@ +/** @file + X.509 Certificate Handler Wrapper Implementation over OpenSSL. + +Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include +#include + +/** + Construct a X509 object from DER-encoded certificate data. + + If Cert is NULL, then return FALSE. + If SingleX509Cert is NULL, then return FALSE. + + @param[in] Cert Pointer to the DER-encoded certificate data. + @param[in] CertSize The size of certificate data in bytes. + @param[out] SingleX509Cert The generated X509 object. + + @retval TRUE The X509 object generation succeeded. + @retval FALSE The operation failed. + +**/ +BOOLEAN +EFIAPI +X509ConstructCertificate ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT UINT8 **SingleX509Cert + ) +{ + X509 *X509Cert; + CONST UINT8 *Temp; + + // + // Check input parameters. + // + if (Cert == NULL || SingleX509Cert == NULL || CertSize > INT_MAX) { + return FALSE; + } + + // + // Read DER-encoded X509 Certificate and Construct X509 object. + // + Temp = Cert; + X509Cert = d2i_X509 (NULL, &Temp, (long) CertSize); + if (X509Cert == NULL) { + return FALSE; + } + + *SingleX509Cert = (UINT8 *) X509Cert; + + return TRUE; +} + +/** + Construct a X509 stack object from a list of DER-encoded certificate data. + + If X509Stack is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in, out] X509Stack 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 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 X509ConstructCertificate(). + + @retval TRUE The X509 stack construction succeeded. + @retval FALSE The construction operation failed. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509ConstructCertificateStackV ( + IN OUT UINT8 **X509Stack, + IN VA_LIST Args + ) +{ + UINT8 *Cert; + UINTN CertSize; + X509 *X509Cert; + STACK_OF(X509) *CertStack; + BOOLEAN Status; + UINTN Index; + + // + // Check input parameters. + // + if (X509Stack == NULL) { + return FALSE; + } + + Status = FALSE; + + // + // Initialize X509 stack object. + // + CertStack = (STACK_OF(X509) *) (*X509Stack); + if (CertStack == NULL) { + CertStack = sk_X509_new_null (); + if (CertStack == NULL) { + return Status; + } + } + + for (Index = 0; ; Index++) { + // + // If Cert is NULL, then it is the end of the list. + // + Cert = VA_ARG (Args, UINT8 *); + if (Cert == NULL) { + break; + } + + CertSize = VA_ARG (Args, UINTN); + if (CertSize == 0) { + break; + } + + // + // Construct X509 Object from the given DER-encoded certificate data. + // + X509Cert = NULL; + Status = X509ConstructCertificate ( + (CONST UINT8 *) Cert, + CertSize, + (UINT8 **) &X509Cert + ); + if (!Status) { + if (X509Cert != NULL) { + X509_free (X509Cert); + } + break; + } + + // + // Insert the new X509 object into X509 stack object. + // + sk_X509_push (CertStack, X509Cert); + } + + if (!Status) { + sk_X509_pop_free (CertStack, X509_free); + } else { + *X509Stack = (UINT8 *) CertStack; + } + + return Status; +} + +/** + Construct a X509 stack object from a list of DER-encoded certificate data. + + If X509Stack is NULL, then return FALSE. + + @param[in, out] X509Stack 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 X509ConstructCertificate(). + + @retval TRUE The X509 stack construction succeeded. + @retval FALSE The construction operation failed. + +**/ +BOOLEAN +EFIAPI +X509ConstructCertificateStack ( + IN OUT UINT8 **X509Stack, + ... + ) +{ + VA_LIST Args; + BOOLEAN Result; + + VA_START (Args, X509Stack); + Result = X509ConstructCertificateStackV (X509Stack, Args); + VA_END (Args); + return Result; +} + +/** + Release the specified X509 object. + + If X509Cert is NULL, then return FALSE. + + @param[in] X509Cert Pointer to the X509 object to be released. + +**/ +VOID +EFIAPI +X509Free ( + IN VOID *X509Cert + ) +{ + // + // Check input parameters. + // + if (X509Cert == NULL) { + return; + } + + // + // Free OpenSSL X509 object. + // + X509_free ((X509 *) X509Cert); +} + +/** + Release the specified X509 stack object. + + If X509Stack is NULL, then return FALSE. + + @param[in] X509Stack Pointer to the X509 stack object to be released. + +**/ +VOID +EFIAPI +X509StackFree ( + IN VOID *X509Stack + ) +{ + // + // Check input parameters. + // + if (X509Stack == NULL) { + return; + } + + // + // Free OpenSSL X509 stack object. + // + sk_X509_pop_free ((STACK_OF(X509) *) X509Stack, X509_free); +} + +/** + Retrieve the subject bytes from one X.509 certificate. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] CertSubject Pointer to the retrieved certificate subject bytes. + @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input, + and the size of buffer returned CertSubject on output. + + If Cert is NULL, then return FALSE. + If SubjectSize is NULL, then return FALSE. + + @retval TRUE The certificate subject retrieved successfully. + @retval FALSE Invalid certificate, or the SubjectSize is too small for the result. + The SubjectSize will be updated with the required size. + +**/ +BOOLEAN +EFIAPI +X509GetSubjectName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT UINT8 *CertSubject, + IN OUT UINTN *SubjectSize + ) +{ + BOOLEAN Status; + X509 *X509Cert; + X509_NAME *X509Name; + UINTN X509NameSize; + + // + // Check input parameters. + // + if (Cert == NULL || SubjectSize == NULL) { + return FALSE; + } + + X509Cert = NULL; + + // + // Read DER-encoded X509 Certificate and Construct X509 object. + // + Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert); + if ((X509Cert == NULL) || (!Status)) { + Status = FALSE; + goto _Exit; + } + + Status = FALSE; + + // + // Retrieve subject name from certificate object. + // + X509Name = X509_get_subject_name (X509Cert); + if (X509Name == NULL) { + goto _Exit; + } + + X509NameSize = i2d_X509_NAME(X509Name, NULL); + if (*SubjectSize < X509NameSize) { + *SubjectSize = X509NameSize; + goto _Exit; + } + *SubjectSize = X509NameSize; + if (CertSubject != NULL) { + i2d_X509_NAME(X509Name, &CertSubject); + Status = TRUE; + } + +_Exit: + // + // Release Resources. + // + if (X509Cert != NULL) { + X509_free (X509Cert); + } + + return Status; +} + +/** + Retrieve a string from one X.509 certificate base on the Request_NID. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[in] Request_NID NID of string to obtain + @param[out] CommonName Buffer to contain the retrieved certificate common + name string (UTF8). At most CommonNameSize 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] CommonNameSize The size in bytes of the CommonName buffer on input, + and the size of buffer returned CommonName on output. + If CommonName is NULL then the amount of space needed + in buffer (including the final null) is returned. + + @retval RETURN_SUCCESS The certificate CommonName retrieved successfully. + @retval RETURN_INVALID_PARAMETER If Cert is NULL. + If CommonNameSize is NULL. + If CommonName is not NULL and *CommonNameSize is 0. + If Certificate is invalid. + @retval RETURN_NOT_FOUND If no NID Name entry exists. + @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size + (including the final null) is returned in the + CommonNameSize parameter. + @retval RETURN_UNSUPPORTED The operation is not supported. + +**/ +STATIC +RETURN_STATUS +InternalX509GetNIDName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + IN INT32 Request_NID, + OUT CHAR8 *CommonName, OPTIONAL + IN OUT UINTN *CommonNameSize + ) +{ + RETURN_STATUS ReturnStatus; + BOOLEAN Status; + X509 *X509Cert; + X509_NAME *X509Name; + INT32 Index; + INTN Length; + X509_NAME_ENTRY *Entry; + ASN1_STRING *EntryData; + UINT8 *UTF8Name; + + ReturnStatus = RETURN_INVALID_PARAMETER; + UTF8Name = NULL; + + // + // Check input parameters. + // + if ((Cert == NULL) || (CertSize > INT_MAX) || (CommonNameSize == NULL)) { + return ReturnStatus; + } + if ((CommonName != NULL) && (*CommonNameSize == 0)) { + return ReturnStatus; + } + + X509Cert = NULL; + // + // Read DER-encoded X509 Certificate and Construct X509 object. + // + Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert); + if ((X509Cert == NULL) || (!Status)) { + // + // Invalid X.509 Certificate + // + goto _Exit; + } + + Status = FALSE; + + // + // Retrieve subject name from certificate object. + // + X509Name = X509_get_subject_name (X509Cert); + if (X509Name == NULL) { + // + // Fail to retrieve subject name content + // + goto _Exit; + } + + // + // Retrive the string from X.509 Subject base on the Request_NID + // + Index = X509_NAME_get_index_by_NID (X509Name, Request_NID, -1); + if (Index < 0) { + // + // No Request_NID name entry exists in X509_NAME object + // + *CommonNameSize = 0; + ReturnStatus = RETURN_NOT_FOUND; + goto _Exit; + } + + Entry = X509_NAME_get_entry (X509Name, Index); + if (Entry == NULL) { + // + // Fail to retrieve name entry data + // + *CommonNameSize = 0; + ReturnStatus = RETURN_NOT_FOUND; + goto _Exit; + } + + EntryData = X509_NAME_ENTRY_get_data (Entry); + + Length = ASN1_STRING_to_UTF8 (&UTF8Name, EntryData); + if (Length < 0) { + // + // Fail to convert the Name string + // + *CommonNameSize = 0; + ReturnStatus = RETURN_INVALID_PARAMETER; + goto _Exit; + } + + if (CommonName == NULL) { + *CommonNameSize = Length + 1; + ReturnStatus = RETURN_BUFFER_TOO_SMALL; + } else { + *CommonNameSize = MIN ((UINTN)Length, *CommonNameSize - 1) + 1; + CopyMem (CommonName, UTF8Name, *CommonNameSize - 1); + CommonName[*CommonNameSize - 1] = '\0'; + ReturnStatus = RETURN_SUCCESS; + } + +_Exit: + // + // Release Resources. + // + if (X509Cert != NULL) { + X509_free (X509Cert); + } + if (UTF8Name != NULL) { + OPENSSL_free (UTF8Name); + } + + return ReturnStatus; +} + +/** + Retrieve the common name (CN) string from one X.509 certificate. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] CommonName Buffer to contain the retrieved certificate common + name string. At most CommonNameSize 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] CommonNameSize The size in bytes of the CommonName buffer on input, + and the size of buffer returned CommonName on output. + If CommonName is NULL then the amount of space needed + in buffer (including the final null) is returned. + + @retval RETURN_SUCCESS The certificate CommonName retrieved successfully. + @retval RETURN_INVALID_PARAMETER If Cert is NULL. + If CommonNameSize is NULL. + If CommonName is not NULL and *CommonNameSize is 0. + If Certificate is invalid. + @retval RETURN_NOT_FOUND If no CommonName entry exists. + @retval RETURN_BUFFER_TOO_SMALL If the CommonName is NULL. The required buffer size + (including the final null) is returned in the + CommonNameSize parameter. + @retval RETURN_UNSUPPORTED The operation is not supported. + +**/ +RETURN_STATUS +EFIAPI +X509GetCommonName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT CHAR8 *CommonName, OPTIONAL + IN OUT UINTN *CommonNameSize + ) +{ + return InternalX509GetNIDName (Cert, CertSize, NID_commonName, CommonName, CommonNameSize); +} + +/** + Retrieve the organization name (O) string from one X.509 certificate. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] NameBuffer Buffer to contain the retrieved certificate organization + name string. At most NameBufferSize 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] NameBufferSize The size in bytes of the Name buffer on input, + and the size of buffer returned Name on output. + If NameBuffer 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 NameBufferSize is NULL. + If NameBuffer is not NULL and *CommonNameSize is 0. + If Certificate is invalid. + @retval RETURN_NOT_FOUND If no Organization Name entry exists. + @retval RETURN_BUFFER_TOO_SMALL If the NameBuffer is NULL. The required buffer size + (including the final null) is returned in the + CommonNameSize parameter. + @retval RETURN_UNSUPPORTED The operation is not supported. + +**/ +RETURN_STATUS +EFIAPI +X509GetOrganizationName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT CHAR8 *NameBuffer, OPTIONAL + IN OUT UINTN *NameBufferSize + ) +{ + return InternalX509GetNIDName (Cert, CertSize, NID_organizationName, NameBuffer, NameBufferSize); +} + +/** + Retrieve the RSA Public Key from one DER-encoded X509 certificate. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved + RSA public key component. Use RsaFree() function to free the + resource. + + If Cert is NULL, then return FALSE. + If RsaContext is NULL, then return FALSE. + + @retval TRUE RSA Public Key was retrieved successfully. + @retval FALSE Fail to retrieve RSA public key from X509 certificate. + +**/ +BOOLEAN +EFIAPI +RsaGetPublicKeyFromX509 ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT VOID **RsaContext + ) +{ + BOOLEAN Status; + EVP_PKEY *Pkey; + X509 *X509Cert; + + // + // Check input parameters. + // + if (Cert == NULL || RsaContext == NULL) { + return FALSE; + } + + Pkey = NULL; + X509Cert = NULL; + + // + // Read DER-encoded X509 Certificate and Construct X509 object. + // + Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert); + if ((X509Cert == NULL) || (!Status)) { + Status = FALSE; + goto _Exit; + } + + Status = FALSE; + + // + // Retrieve and check EVP_PKEY data from X509 Certificate. + // + Pkey = X509_get_pubkey (X509Cert); + if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_RSA)) { + goto _Exit; + } + + // + // Duplicate RSA Context from the retrieved EVP_PKEY. + // + if ((*RsaContext = RSAPublicKey_dup (EVP_PKEY_get0_RSA (Pkey))) != NULL) { + Status = TRUE; + } + +_Exit: + // + // Release Resources. + // + if (X509Cert != NULL) { + X509_free (X509Cert); + } + + if (Pkey != NULL) { + EVP_PKEY_free (Pkey); + } + + return Status; +} + +/** + 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] CertSize Size of the X509 certificate in bytes. + @param[in] CACert Pointer to the DER-encoded trusted CA certificate. + @param[in] CACertSize Size of the CA Certificate in bytes. + + If Cert is NULL, then return FALSE. + If CACert 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. + +**/ +BOOLEAN +EFIAPI +X509VerifyCert ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + IN CONST UINT8 *CACert, + IN UINTN CACertSize + ) +{ + BOOLEAN Status; + X509 *X509Cert; + X509 *X509CACert; + X509_STORE *CertStore; + X509_STORE_CTX *CertCtx; + + // + // Check input parameters. + // + if (Cert == NULL || CACert == NULL) { + return FALSE; + } + + Status = FALSE; + X509Cert = NULL; + X509CACert = NULL; + CertStore = NULL; + CertCtx = NULL; + + // + // Register & Initialize necessary digest algorithms for certificate verification. + // + if (EVP_add_digest (EVP_md5 ()) == 0) { + goto _Exit; + } + if (EVP_add_digest (EVP_sha1 ()) == 0) { + goto _Exit; + } + if (EVP_add_digest (EVP_sha256 ()) == 0) { + goto _Exit; + } + + // + // Read DER-encoded certificate to be verified and Construct X509 object. + // + Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **) &X509Cert); + if ((X509Cert == NULL) || (!Status)) { + Status = FALSE; + goto _Exit; + } + + // + // Read DER-encoded root certificate and Construct X509 object. + // + Status = X509ConstructCertificate (CACert, CACertSize, (UINT8 **) &X509CACert); + if ((X509CACert == NULL) || (!Status)) { + Status = FALSE; + goto _Exit; + } + + Status = FALSE; + + // + // Set up X509 Store for trusted certificate. + // + CertStore = X509_STORE_new (); + if (CertStore == NULL) { + goto _Exit; + } + if (!(X509_STORE_add_cert (CertStore, X509CACert))) { + goto _Exit; + } + + // + // Allow partial certificate chains, terminated by a non-self-signed but + // still trusted intermediate certificate. Also disable time checks. + // + X509_STORE_set_flags (CertStore, + X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_NO_CHECK_TIME); + + // + // Set up X509_STORE_CTX for the subsequent verification operation. + // + CertCtx = X509_STORE_CTX_new (); + if (CertCtx == NULL) { + goto _Exit; + } + if (!X509_STORE_CTX_init (CertCtx, CertStore, X509Cert, NULL)) { + goto _Exit; + } + + // + // X509 Certificate Verification. + // + Status = (BOOLEAN) X509_verify_cert (CertCtx); + X509_STORE_CTX_cleanup (CertCtx); + +_Exit: + // + // Release Resources. + // + if (X509Cert != NULL) { + X509_free (X509Cert); + } + + if (X509CACert != NULL) { + X509_free (X509CACert); + } + + if (CertStore != NULL) { + X509_STORE_free (CertStore); + } + + X509_STORE_CTX_free (CertCtx); + + return Status; +} + +/** + Retrieve the TBSCertificate from one given X.509 certificate. + + @param[in] Cert Pointer to the given DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] TBSCert DER-Encoded To-Be-Signed certificate. + @param[out] TBSCertSize Size of the TBS certificate in bytes. + + If Cert is NULL, then return FALSE. + If TBSCert is NULL, then return FALSE. + If TBSCertSize is NULL, then return FALSE. + + @retval TRUE The TBSCertificate was retrieved successfully. + @retval FALSE Invalid X.509 certificate. + +**/ +BOOLEAN +EFIAPI +X509GetTBSCert ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT UINT8 **TBSCert, + OUT UINTN *TBSCertSize + ) +{ + CONST UINT8 *Temp; + UINT32 Asn1Tag; + UINT32 ObjClass; + UINTN Length; + + // + // Check input parameters. + // + if ((Cert == NULL) || (TBSCert == NULL) || + (TBSCertSize == NULL) || (CertSize > 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 *)&Asn1Tag, (int *)&ObjClass, (long)CertSize); + + if (Asn1Tag != V_ASN1_SEQUENCE) { + return FALSE; + } + + *TBSCert = (UINT8 *)Temp; + + ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length); + // + // Verify the parsed TBSCertificate is one correct SEQUENCE data. + // + if (Asn1Tag != V_ASN1_SEQUENCE) { + return FALSE; + } + + *TBSCertSize = Length + (Temp - *TBSCert); + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c new file mode 100644 index 00000000..fb4c7a36 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c @@ -0,0 +1,294 @@ +/** @file + X.509 Certificate Handler Wrapper Implementation which does not provide + real capabilities. + +Copyright (c) 2012 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + +/** + Construct a X509 object from DER-encoded certificate data. + + Return FALSE to indicate this interface is not supported. + + @param[in] Cert Pointer to the DER-encoded certificate data. + @param[in] CertSize The size of certificate data in bytes. + @param[out] SingleX509Cert The generated X509 object. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509ConstructCertificate ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT UINT8 **SingleX509Cert + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Construct a X509 stack object from a list of DER-encoded certificate data. + + If X509Stack is NULL, then return FALSE. + If this interface is not supported, then return FALSE. + + @param[in, out] X509Stack 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 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 X509ConstructCertificate(). + + @retval TRUE The X509 stack construction succeeded. + @retval FALSE The construction operation failed. + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509ConstructCertificateStackV ( + IN OUT UINT8 **X509Stack, + IN VA_LIST Args + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Construct a X509 stack object from a list of DER-encoded certificate data. + + Return FALSE to indicate this interface is not supported. + + @param[in, out] X509Stack 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 X509ConstructCertificate(). + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509ConstructCertificateStack ( + IN OUT UINT8 **X509Stack, + ... + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Release the specified X509 object. + + If the interface is not supported, then ASSERT(). + + @param[in] X509Cert Pointer to the X509 object to be released. + +**/ +VOID +EFIAPI +X509Free ( + IN VOID *X509Cert + ) +{ + ASSERT (FALSE); +} + +/** + Release the specified X509 stack object. + + If the interface is not supported, then ASSERT(). + + @param[in] X509Stack Pointer to the X509 stack object to be released. + +**/ +VOID +EFIAPI +X509StackFree ( + IN VOID *X509Stack + ) +{ + ASSERT (FALSE); +} + +/** + Retrieve the subject bytes from one X.509 certificate. + + Return FALSE to indicate this interface is not supported. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] CertSubject Pointer to the retrieved certificate subject bytes. + @param[in, out] SubjectSize The size in bytes of the CertSubject buffer on input, + and the size of buffer returned CertSubject on output. + + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509GetSubjectName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT UINT8 *CertSubject, + IN OUT UINTN *SubjectSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Retrieve the common name (CN) string from one X.509 certificate. + + Return RETURN_UNSUPPORTED to indicate this interface is not supported. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] CommonName Buffer to contain the retrieved certificate common + name string (UTF8). At most CommonNameSize 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] CommonNameSize The size in bytes of the CommonName buffer on input, + and the size of buffer returned CommonName on output. + If CommonName is NULL then the amount of space needed + in buffer (including the final null) is returned. + + @retval RETURN_UNSUPPORTED The operation is not supported. + +**/ +RETURN_STATUS +EFIAPI +X509GetCommonName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT CHAR8 *CommonName, OPTIONAL + IN OUT UINTN *CommonNameSize + ) +{ + ASSERT (FALSE); + return RETURN_UNSUPPORTED; +} + +/** + Retrieve the organization name (ON) string from one X.509 certificate. + + Return RETURN_UNSUPPORTED to indicate this interface is not supported. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] NameBuffer Buffer to contain the retrieved certificate organization + name string. At most NameBufferSize 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] NameBufferSize The size in bytes of the Name buffer on input, + and the size of buffer returned Name on output. + If NameBuffer is NULL then the amount of space needed + in buffer (including the final null) is returned. + + @retval RETURN_UNSUPPORTED The operation is not supported. + +**/ +RETURN_STATUS +EFIAPI +X509GetOrganizationName ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT CHAR8 *NameBuffer, OPTIONAL + IN OUT UINTN *NameBufferSize + ) +{ + ASSERT (FALSE); + return RETURN_UNSUPPORTED; +} + +/** + Retrieve the RSA Public Key from one DER-encoded X509 certificate. + + Return FALSE to indicate this interface is not supported. + + @param[in] Cert Pointer to the DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] RsaContext Pointer to new-generated RSA context which contain the retrieved + RSA public key component. Use RsaFree() function to free the + resource. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RsaGetPublicKeyFromX509 ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT VOID **RsaContext + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Verify one X509 certificate was issued by the trusted CA. + + Return FALSE to indicate this interface is not supported. + + @param[in] Cert Pointer to the DER-encoded X509 certificate to be verified. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[in] CACert Pointer to the DER-encoded trusted CA certificate. + @param[in] CACertSize Size of the CA Certificate in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509VerifyCert ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + IN CONST UINT8 *CACert, + IN UINTN CACertSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Retrieve the TBSCertificate from one given X.509 certificate. + + Return FALSE to indicate this interface is not supported. + + @param[in] Cert Pointer to the given DER-encoded X509 certificate. + @param[in] CertSize Size of the X509 certificate in bytes. + @param[out] TBSCert DER-Encoded To-Be-Signed certificate. + @param[out] TBSCertSize Size of the TBS certificate in bytes. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +X509GetTBSCert ( + IN CONST UINT8 *Cert, + IN UINTN CertSize, + OUT UINT8 **TBSCert, + OUT UINTN *TBSCertSize + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRand.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRand.c new file mode 100644 index 00000000..31b08b7a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRand.c @@ -0,0 +1,104 @@ +/** @file + Pseudorandom Number Generator Wrapper Implementation over OpenSSL. + +Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include +#include + +// +// Default seed for UEFI Crypto Library +// +CONST UINT8 DefaultSeed[] = "UEFI Crypto Library default seed"; + +/** + Sets up the seed value for the pseudorandom number generator. + + This function sets up the seed value for the pseudorandom number generator. + If Seed is not NULL, then the seed passed in is used. + If Seed is NULL, then default seed is used. + + @param[in] Seed Pointer to seed value. + If NULL, default seed is used. + @param[in] SeedSize Size of seed value. + If Seed is NULL, this parameter is ignored. + + @retval TRUE Pseudorandom number generator has enough entropy for random generation. + @retval FALSE Pseudorandom number generator does not have enough entropy for random generation. + +**/ +BOOLEAN +EFIAPI +RandomSeed ( + IN CONST UINT8 *Seed OPTIONAL, + IN UINTN SeedSize + ) +{ + if (SeedSize > INT_MAX) { + return FALSE; + } + + // + // The software PRNG implementation built in OpenSSL depends on message digest algorithm. + // Make sure SHA-1 digest algorithm is available here. + // + if (EVP_add_digest (EVP_sha1 ()) == 0) { + return FALSE; + } + + // + // Seed the pseudorandom number generator with user-supplied value. + // NOTE: A cryptographic PRNG must be seeded with unpredictable data. + // + if (Seed != NULL) { + RAND_seed (Seed, (UINT32) SeedSize); + } else { + RAND_seed (DefaultSeed, sizeof (DefaultSeed)); + } + + if (RAND_status () == 1) { + return TRUE; + } + + return FALSE; +} + +/** + Generates a pseudorandom byte stream of the specified size. + + If Output is NULL, then return FALSE. + + @param[out] Output Pointer to buffer to receive random value. + @param[in] Size Size of random bytes to generate. + + @retval TRUE Pseudorandom byte stream generated successfully. + @retval FALSE Pseudorandom number generator fails to generate due to lack of entropy. + +**/ +BOOLEAN +EFIAPI +RandomBytes ( + OUT UINT8 *Output, + IN UINTN Size + ) +{ + // + // Check input parameters. + // + if (Output == NULL || Size > INT_MAX) { + return FALSE; + } + + // + // Generate random data. + // + if (RAND_bytes (Output, (UINT32) Size) != 1) { + return FALSE; + } + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandNull.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandNull.c new file mode 100644 index 00000000..7eb080bb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandNull.c @@ -0,0 +1,57 @@ +/** @file + Pseudorandom Number Generator Wrapper Implementation which does not provide + real capabilities. + +Copyright (c) 2012, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" + + +/** + Sets up the seed value for the pseudorandom number generator. + + Return FALSE to indicate this interface is not supported. + + @param[in] Seed Pointer to seed value. + If NULL, default seed is used. + @param[in] SeedSize Size of seed value. + If Seed is NULL, this parameter is ignored. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RandomSeed ( + IN CONST UINT8 *Seed OPTIONAL, + IN UINTN SeedSize + ) +{ + ASSERT (FALSE); + return FALSE; +} + +/** + Generates a pseudorandom byte stream of the specified size. + + Return FALSE to indicate this interface is not supported. + + @param[out] Output Pointer to buffer to receive random value. + @param[in] Size Size of random bytes to generate. + + @retval FALSE This interface is not supported. + +**/ +BOOLEAN +EFIAPI +RandomBytes ( + OUT UINT8 *Output, + IN UINTN Size + ) +{ + ASSERT (FALSE); + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandTsc.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandTsc.c new file mode 100644 index 00000000..696cf935 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/Rand/CryptRandTsc.c @@ -0,0 +1,112 @@ +/** @file + Pseudorandom Number Generator Wrapper Implementation over OpenSSL. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include +#include +#include + +/** + Sets up the seed value for the pseudorandom number generator. + + This function sets up the seed value for the pseudorandom number generator. + If Seed is not NULL, then the seed passed in is used. + If Seed is NULL, then default seed is used. + + @param[in] Seed Pointer to seed value. + If NULL, default seed is used. + @param[in] SeedSize Size of seed value. + If Seed is NULL, this parameter is ignored. + + @retval TRUE Pseudorandom number generator has enough entropy for random generation. + @retval FALSE Pseudorandom number generator does not have enough entropy for random generation. + +**/ +BOOLEAN +EFIAPI +RandomSeed ( + IN CONST UINT8 *Seed OPTIONAL, + IN UINTN SeedSize + ) +{ + CHAR8 DefaultSeed[128]; + + if (SeedSize > INT_MAX) { + return FALSE; + } + + // + // The software PRNG implementation built in OpenSSL depends on message digest algorithm. + // Make sure SHA-1 digest algorithm is available here. + // + if (EVP_add_digest (EVP_sha1 ()) == 0) { + return FALSE; + } + + // + // Seed the pseudorandom number generator with user-supplied value. + // NOTE: A cryptographic PRNG must be seeded with unpredictable data. + // + if (Seed != NULL) { + RAND_seed (Seed, (UINT32) SeedSize); + } else { + // + // Retrieve current time. + // + AsciiSPrint ( + DefaultSeed, + sizeof (DefaultSeed), + "UEFI Crypto Library default seed (%ld)", + AsmReadTsc () + ); + + RAND_seed (DefaultSeed, sizeof (DefaultSeed)); + } + + if (RAND_status () == 1) { + return TRUE; + } + + return FALSE; +} + +/** + Generates a pseudorandom byte stream of the specified size. + + If Output is NULL, then return FALSE. + + @param[out] Output Pointer to buffer to receive random value. + @param[in] Size Size of random bytes to generate. + + @retval TRUE Pseudorandom byte stream generated successfully. + @retval FALSE Pseudorandom number generator fails to generate due to lack of entropy. + +**/ +BOOLEAN +EFIAPI +RandomBytes ( + OUT UINT8 *Output, + IN UINTN Size + ) +{ + // + // Check input parameters. + // + if (Output == NULL || Size > INT_MAX) { + return FALSE; + } + + // + // Generate random data. + // + if (RAND_bytes (Output, (UINT32) Size) != 1) { + return FALSE; + } + + return TRUE; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf new file mode 100644 index 00000000..62d8f60b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf @@ -0,0 +1,113 @@ +## @file +# Cryptographic Library Instance for DXE_RUNTIME_DRIVER. +# +# Caution: This module requires additional review when modified. +# This library will have external input - signature. +# This external input must be validated carefully to avoid security issues such as +# buffer overflow or integer overflow. +# +# Note: SHA-384 Digest functions, SHA-512 Digest functions, +# HMAC-SHA256 functions, AES functions, RSA external +# functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, and +# authenticode signature verification functions are not supported in this instance. +# +# Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = RuntimeCryptLib + MODULE_UNI_FILE = RuntimeCryptLib.uni + FILE_GUID = 78189cc0-727d-46a4-84ea-f7dd860de64a + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = BaseCryptLib|DXE_RUNTIME_DRIVER + CONSTRUCTOR = RuntimeCryptLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + InternalCryptLib.h + Hash/CryptMd5.c + Hash/CryptSha1.c + Hash/CryptSha256.c + Hash/CryptSm3.c + Hash/CryptSha512Null.c + Hmac/CryptHmacSha256.c + Kdf/CryptHkdf.c + Cipher/CryptAes.c + Pk/CryptRsaBasic.c + Pk/CryptRsaExtNull.c + Pk/CryptPkcs1OaepNull.c + Pk/CryptPkcs5Pbkdf2Null.c + Pk/CryptPkcs7SignNull.c + Pk/CryptPkcs7VerifyCommon.c + Pk/CryptPkcs7VerifyRuntime.c + Pk/CryptPkcs7VerifyEkuRuntime.c + Pk/CryptDhNull.c + Pk/CryptX509.c + Pk/CryptAuthenticodeNull.c + Pk/CryptTsNull.c + Pk/CryptRsaPssNull.c + Pk/CryptRsaPssSignNull.c + Pem/CryptPem.c + + SysCall/CrtWrapper.c + SysCall/TimerWrapper.c + SysCall/RuntimeMemAllocation.c + +[Sources.Ia32] + Rand/CryptRandTsc.c + +[Sources.X64] + Rand/CryptRandTsc.c + +[Sources.ARM] + Rand/CryptRand.c + +[Sources.AARCH64] + Rand/CryptRand.c + +[Sources.RISCV64] + Rand/CryptRand.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + DebugLib + OpensslLib + IntrinsicLib + PrintLib + +# +# Remove these [BuildOptions] after this library is cleaned up +# +[BuildOptions] + # + # suppress the following warnings so we do not break the build with warnings-as-errors: + # C4090: 'function' : different 'const' qualifiers + # + MSFT:*_*_*_CC_FLAGS = /wd4090 + + # -JCryptoPkg/Include : To disable the use of the system includes provided by RVCT + # --diag_remark=1 : Reduce severity of "#1-D: last line of file ends without a newline" + RVCT:*_*_ARM_CC_FLAGS = -JCryptoPkg/Include --diag_remark=1 + + GCC:*_CLANG35_*_CC_FLAGS = -std=c99 + GCC:*_CLANG38_*_CC_FLAGS = -std=c99 + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types + + XCODE:*_*_*_CC_FLAGS = -std=c99 diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.uni b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.uni new file mode 100644 index 00000000..0cf378c5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.uni @@ -0,0 +1,24 @@ +// /** @file +// Cryptographic Library Instance for DXE_RUNTIME_DRIVER. +// +// Caution: This module requires additional review when modified. +// This library will have external input - signature. +// This external input must be validated carefully to avoid security issues such as +// buffer overflow or integer overflow. +// +// Note: AES +// functions, RSA external functions, PKCS#7 SignedData sign functions, +// Diffie-Hellman functions, and authenticode signature verification functions are +// not supported in this instance. +// +// Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Cryptographic Library Instance for DXE_RUNTIME_DRIVER" + +#string STR_MODULE_DESCRIPTION #language en-US "Caution: This module requires additional review when modified. This library will have external input - signature. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow. Note: AES functions, RSA external functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, and authenticode signature verification functions are not supported in this instance." + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf new file mode 100644 index 00000000..caa66399 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf @@ -0,0 +1,103 @@ +## @file +# Cryptographic Library Instance for SMM driver. +# +# Caution: This module requires additional review when modified. +# This library will have external input - signature. +# This external input must be validated carefully to avoid security issues such as +# buffer overflow or integer overflow. +# +# Note: SHA-384 Digest functions, SHA-512 Digest functions, +# RSA external functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, and +# authenticode signature verification functions are not supported in this instance. +# +# Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmCryptLib + MODULE_UNI_FILE = SmmCryptLib.uni + FILE_GUID = 028080a3-8958-4a62-a1a8-0fa1da162007 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + LIBRARY_CLASS = BaseCryptLib|DXE_SMM_DRIVER SMM_CORE MM_STANDALONE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + InternalCryptLib.h + Hash/CryptMd5.c + Hash/CryptSha1.c + Hash/CryptSha256.c + Hash/CryptSm3.c + Hash/CryptSha512Null.c + Hmac/CryptHmacSha256.c + Kdf/CryptHkdfNull.c + Cipher/CryptAes.c + Pk/CryptRsaBasic.c + Pk/CryptRsaExtNull.c + Pk/CryptPkcs1Oaep.c + Pk/CryptPkcs5Pbkdf2.c + Pk/CryptPkcs7SignNull.c + Pk/CryptPkcs7VerifyCommon.c + Pk/CryptPkcs7VerifyBase.c + Pk/CryptPkcs7VerifyEku.c + Pk/CryptDhNull.c + Pk/CryptX509.c + Pk/CryptAuthenticodeNull.c + Pk/CryptTsNull.c + Pk/CryptRsaPss.c + Pk/CryptRsaPssSignNull.c + Pem/CryptPem.c + + SysCall/CrtWrapper.c + SysCall/ConstantTimeClock.c + SysCall/BaseMemAllocation.c + +[Sources.Ia32] + Rand/CryptRandTsc.c + +[Sources.X64] + Rand/CryptRandTsc.c + +[Sources.ARM] + Rand/CryptRand.c + +[Sources.AARCH64] + Rand/CryptRand.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + IoLib + BaseMemoryLib + MemoryAllocationLib + OpensslLib + IntrinsicLib + PrintLib + +# +# Remove these [BuildOptions] after this library is cleaned up +# +[BuildOptions] + # + # suppress the following warnings so we do not break the build with warnings-as-errors: + # C4090: 'function' : different 'const' qualifiers + # + MSFT:*_*_*_CC_FLAGS = /wd4090 + + XCODE:*_*_*_CC_FLAGS = -mmmx -msse -std=c99 + + GCC:*_CLANG35_*_CC_FLAGS = -std=c99 + GCC:*_CLANG38_*_CC_FLAGS = -std=c99 + GCC:*_CLANGPDB_*_CC_FLAGS = -std=c99 -Wno-error=incompatible-pointer-types diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.uni b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.uni new file mode 100644 index 00000000..f0c33abb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.uni @@ -0,0 +1,24 @@ +// /** @file +// Cryptographic Library Instance for SMM driver. +// +// Caution: This module requires additional review when modified. +// This library will have external input - signature. +// This external input must be validated carefully to avoid security issues such as +// buffer overflow or integer overflow. +// +// Note: AES +// functions, RSA external functions, PKCS#7 SignedData sign functions, +// Diffie-Hellman functions, and authenticode signature verification functions are +// not supported in this instance. +// +// Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Cryptographic Library Instance for SMM driver" + +#string STR_MODULE_DESCRIPTION #language en-US "Caution: This module requires additional review when modified. This library will have external input - signature. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow. Note: AES functions, RSA external functions, PKCS#7 SignedData sign functions, Diffie-Hellman functions, and authenticode signature verification functions are not supported in this instance." + diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c new file mode 100644 index 00000000..1b1611f3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/BaseMemAllocation.c @@ -0,0 +1,112 @@ +/** @file + Base Memory Allocation Routines Wrapper for Crypto library over OpenSSL + during PEI & DXE phases. + +Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +// +// Extra header to record the memory buffer size from malloc routine. +// +#define CRYPTMEM_HEAD_SIGNATURE SIGNATURE_32('c','m','h','d') +typedef struct { + UINT32 Signature; + UINT32 Reserved; + UINTN Size; +} CRYPTMEM_HEAD; + +#define CRYPTMEM_OVERHEAD sizeof(CRYPTMEM_HEAD) + +// +// -- Memory-Allocation Routines -- +// + +/* Allocates memory blocks */ +void *malloc (size_t size) +{ + CRYPTMEM_HEAD *PoolHdr; + UINTN NewSize; + VOID *Data; + + // + // Adjust the size by the buffer header overhead + // + NewSize = (UINTN)(size) + CRYPTMEM_OVERHEAD; + + Data = AllocatePool (NewSize); + if (Data != NULL) { + PoolHdr = (CRYPTMEM_HEAD *)Data; + // + // Record the memory brief information + // + PoolHdr->Signature = CRYPTMEM_HEAD_SIGNATURE; + PoolHdr->Size = size; + + return (VOID *)(PoolHdr + 1); + } else { + // + // The buffer allocation failed. + // + return NULL; + } +} + +/* Reallocate memory blocks */ +void *realloc (void *ptr, size_t size) +{ + CRYPTMEM_HEAD *OldPoolHdr; + CRYPTMEM_HEAD *NewPoolHdr; + UINTN OldSize; + UINTN NewSize; + VOID *Data; + + NewSize = (UINTN)size + CRYPTMEM_OVERHEAD; + Data = AllocatePool (NewSize); + if (Data != NULL) { + NewPoolHdr = (CRYPTMEM_HEAD *)Data; + NewPoolHdr->Signature = CRYPTMEM_HEAD_SIGNATURE; + NewPoolHdr->Size = size; + if (ptr != NULL) { + // + // Retrieve the original size from the buffer header. + // + OldPoolHdr = (CRYPTMEM_HEAD *)ptr - 1; + ASSERT (OldPoolHdr->Signature == CRYPTMEM_HEAD_SIGNATURE); + OldSize = OldPoolHdr->Size; + + // + // Duplicate the buffer content. + // + CopyMem ((VOID *)(NewPoolHdr + 1), ptr, MIN (OldSize, size)); + FreePool ((VOID *)OldPoolHdr); + } + + return (VOID *)(NewPoolHdr + 1); + } else { + // + // The buffer allocation failed. + // + return NULL; + } +} + +/* De-allocates or frees a memory block */ +void free (void *ptr) +{ + CRYPTMEM_HEAD *PoolHdr; + + // + // In Standard C, free() handles a null pointer argument transparently. This + // is not true of FreePool() below, so protect it. + // + if (ptr != NULL) { + PoolHdr = (CRYPTMEM_HEAD *)ptr - 1; + ASSERT (PoolHdr->Signature == CRYPTMEM_HEAD_SIGNATURE); + FreePool (PoolHdr); + } +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/ConstantTimeClock.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/ConstantTimeClock.c new file mode 100644 index 00000000..bf6b4136 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/ConstantTimeClock.c @@ -0,0 +1,37 @@ +/** @file + C Run-Time Libraries (CRT) Time Management Routines Wrapper Implementation + for OpenSSL-based Cryptographic Library. + + This C file implements constant time value for time() and NULL for gmtime() + thus should not be used in library instances which require functionality + of following APIs which need system time support: + 1) RsaGenerateKey + 2) RsaCheckKey + 3) RsaPkcs1Sign + 4) Pkcs7Sign + 5) DhGenerateParameter + 6) DhGenerateKey + +Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +// +// -- Time Management Routines -- +// + +time_t time (time_t *timer) +{ + if (timer != NULL) { + *timer = 0; + } + return 0; +} + +struct tm * gmtime (const time_t *timer) +{ + return NULL; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c new file mode 100644 index 00000000..0c9ac39e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/CrtWrapper.c @@ -0,0 +1,473 @@ +/** @file + C Run-Time Libraries (CRT) Wrapper Implementation for OpenSSL-based + Cryptographic Library. + +Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +int errno = 0; + +FILE *stderr = NULL; +FILE *stdin = NULL; +FILE *stdout = NULL; + +typedef +int +(*SORT_COMPARE)( + IN VOID *Buffer1, + IN VOID *Buffer2 + ); + +// +// Duplicated from EDKII BaseSortLib for qsort() wrapper +// +STATIC +VOID +QuickSortWorker ( + IN OUT VOID *BufferToSort, + IN CONST UINTN Count, + IN CONST UINTN ElementSize, + IN SORT_COMPARE CompareFunction, + IN VOID *Buffer + ) +{ + VOID *Pivot; + UINTN LoopCount; + UINTN NextSwapLocation; + + ASSERT(BufferToSort != NULL); + ASSERT(CompareFunction != NULL); + ASSERT(Buffer != NULL); + + if (Count < 2 || ElementSize < 1) { + return; + } + + NextSwapLocation = 0; + + // + // Pick a pivot (we choose last element) + // + Pivot = ((UINT8 *)BufferToSort + ((Count - 1) * ElementSize)); + + // + // Now get the pivot such that all on "left" are below it + // and everything "right" are above it + // + for (LoopCount = 0; LoopCount < Count - 1; LoopCount++) + { + // + // If the element is less than the pivot + // + if (CompareFunction ((VOID *)((UINT8 *)BufferToSort + ((LoopCount) * ElementSize)), Pivot) <= 0) { + // + // Swap + // + CopyMem (Buffer, (UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), ElementSize); + CopyMem ((UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), (UINT8 *)BufferToSort + ((LoopCount) * ElementSize), ElementSize); + CopyMem ((UINT8 *)BufferToSort + ((LoopCount) * ElementSize), Buffer, ElementSize); + + // + // Increment NextSwapLocation + // + NextSwapLocation++; + } + } + // + // Swap pivot to its final position (NextSwapLocation) + // + CopyMem (Buffer, Pivot, ElementSize); + CopyMem (Pivot, (UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), ElementSize); + CopyMem ((UINT8 *)BufferToSort + (NextSwapLocation * ElementSize), Buffer, ElementSize); + + // + // Now recurse on 2 partial lists. Neither of these will have the 'pivot' element. + // IE list is sorted left half, pivot element, sorted right half... + // + QuickSortWorker ( + BufferToSort, + NextSwapLocation, + ElementSize, + CompareFunction, + Buffer + ); + + QuickSortWorker ( + (UINT8 *)BufferToSort + (NextSwapLocation + 1) * ElementSize, + Count - NextSwapLocation - 1, + ElementSize, + CompareFunction, + Buffer + ); + + return; +} + +//--------------------------------------------------------- +// Standard C Run-time Library Interface Wrapper +//--------------------------------------------------------- + +// +// -- String Manipulation Routines -- +// + +char *strchr(const char *str, int ch) +{ + return ScanMem8 (str, AsciiStrSize (str), (UINT8)ch); +} + +/* Scan a string for the last occurrence of a character */ +char *strrchr (const char *str, int c) +{ + char * save; + + for (save = NULL; ; ++str) { + if (*str == c) { + save = (char *)str; + } + if (*str == 0) { + return (save); + } + } +} + +/* 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; + + ASSERT(s1 != NULL); + ASSERT(s2 != NULL); + + 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; +} + +/* 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 UEFI cases. + // + return 0; +} + +/* Maps errnum to an error-message string */ +char * strerror (int errnum) +{ + return NULL; +} + +/* Computes the length of the maximum initial segment of the string pointed to by s1 + which consists entirely of characters from the string pointed to by s2. */ +size_t strspn (const char *s1 , const char *s2) +{ + UINT8 Map[32]; + UINT32 Index; + size_t Count; + + for (Index = 0; Index < 32; Index++) { + Map[Index] = 0; + } + + while (*s2) { + Map[*s2 >> 3] |= (1 << (*s2 & 7)); + s2++; + } + + if (*s1) { + Count = 0; + while (Map[*s1 >> 3] & (1 << (*s1 & 7))) { + Count++; + s1++; + } + + return Count; + } + + return 0; +} + +/* Computes the length of the maximum initial segment of the string pointed to by s1 + which consists entirely of characters not from the string pointed to by s2. */ +size_t strcspn (const char *s1, const char *s2) +{ + UINT8 Map[32]; + UINT32 Index; + size_t Count; + + for (Index = 0; Index < 32; Index++) { + Map[Index] = 0; + } + + while (*s2) { + Map[*s2 >> 3] |= (1 << (*s2 & 7)); + s2++; + } + + Map[0] |= 1; + + Count = 0; + while (!(Map[*s1 >> 3] & (1 << (*s1 & 7)))) { + Count ++; + s1++; + } + + return Count; +} + +// +// -- Character Classification Routines -- +// + +/* Determines if a particular character is a decimal-digit character */ +int isdigit (int c) +{ + // + // ::= [0-9] + // + return (('0' <= (c)) && ((c) <= '9')); +} + +/* Determine if an integer represents character that is a hex digit */ +int isxdigit (int c) +{ + // + // ::= [0-9] | [a-f] | [A-F] + // + return ((('0' <= (c)) && ((c) <= '9')) || + (('a' <= (c)) && ((c) <= 'f')) || + (('A' <= (c)) && ((c) <= 'F'))); +} + +/* Determines if a particular character represents a space character */ +int isspace (int c) +{ + // + // ::= [ ] + // + return ((c) == ' '); +} + +/* Determine if a particular character is an alphanumeric character */ +int isalnum (int c) +{ + // + // ::= [0-9] | [a-z] | [A-Z] + // + return ((('0' <= (c)) && ((c) <= '9')) || + (('a' <= (c)) && ((c) <= 'z')) || + (('A' <= (c)) && ((c) <= 'Z'))); +} + +/* Determines if a particular character is in upper case */ +int isupper (int c) +{ + // + // := [A-Z] + // + return (('A' <= (c)) && ((c) <= 'Z')); +} + +// +// -- Data Conversion Routines -- +// + +/* Convert strings to a long-integer value */ +long strtol (const char *nptr, char **endptr, int base) +{ + // + // Null strtol() function implementation to satisfy the linker, since there is + // no direct functionality logic dependency in present UEFI cases. + // + return 0; +} + +/* Convert strings to an unsigned long-integer value */ +unsigned long strtoul (const char *nptr, char **endptr, int base) +{ + // + // Null strtoul() function implementation to satisfy the linker, since there is + // no direct functionality logic dependency in present UEFI cases. + // + return 0; +} + +/* Convert character to lowercase */ +int tolower (int c) +{ + if (('A' <= (c)) && ((c) <= 'Z')) { + return (c - ('A' - 'a')); + } + return (c); +} + +// +// -- Searching and Sorting Routines -- +// + +/* Performs a quick sort */ +void qsort (void *base, size_t num, size_t width, int (*compare)(const void *, const void *)) +{ + VOID *Buffer; + + ASSERT (base != NULL); + ASSERT (compare != NULL); + + // + // Use CRT-style malloc to cover BS and RT memory allocation. + // + Buffer = malloc (width); + ASSERT (Buffer != NULL); + + // + // Re-use PerformQuickSort() function Implementation in EDKII BaseSortLib. + // + QuickSortWorker (base, (UINTN)num, (UINTN)width, (SORT_COMPARE)compare, Buffer); + + free (Buffer); + return; +} + +// +// -- Process and Environment Control Routines -- +// + +/* Get a value from the current environment */ +char *getenv (const char *varname) +{ + // + // Null getenv() function implementation to satisfy the linker, since there is + // no direct functionality logic dependency in present UEFI cases. + // + return NULL; +} + +/* Get a value from the current environment */ +char *secure_getenv (const char *varname) +{ + // + // Null secure_getenv() function implementation to satisfy the linker, since + // there is no direct functionality logic dependency in present UEFI cases. + // + // From the secure_getenv() manual: 'just like getenv() except that it + // returns NULL in cases where "secure execution" is required'. + // + return NULL; +} + +// +// -- Stream I/O Routines -- +// + +/* Write data to a stream */ +size_t fwrite (const void *buffer, size_t size, size_t count, FILE *stream) +{ + return 0; +} + +// +// -- Dummy OpenSSL Support Routines -- +// + +int BIO_printf (void *bio, const char *format, ...) +{ + return 0; +} + +int BIO_snprintf(char *buf, size_t n, const char *format, ...) +{ + return 0; +} + +#ifdef __GNUC__ + +typedef +VOID +(EFIAPI *NoReturnFuncPtr)( + VOID + ) __attribute__((__noreturn__)); + +STATIC +VOID +EFIAPI +NopFunction ( + VOID + ) +{ +} + +void abort (void) +{ + NoReturnFuncPtr NoReturnFunc; + + NoReturnFunc = (NoReturnFuncPtr) NopFunction; + + NoReturnFunc (); +} + +#else + +void abort (void) +{ + // Do nothing +} + +#endif + +int fclose (FILE *f) +{ + return 0; +} + +FILE *fopen (const char *c, const char *m) +{ + return NULL; +} + +size_t fread (void *b, size_t c, size_t i, FILE *f) +{ + return 0; +} + +uid_t getuid (void) +{ + return 0; +} + +uid_t geteuid (void) +{ + return 0; +} + +gid_t getgid (void) +{ + return 0; +} + +gid_t getegid (void) +{ + return 0; +} + +int printf (char const *fmt, ...) +{ + return 0; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c new file mode 100644 index 00000000..d90cdd4d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/RuntimeMemAllocation.c @@ -0,0 +1,455 @@ +/** @file + Light-weight Memory Management Routines for OpenSSL-based Crypto + Library at Runtime Phase. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +//---------------------------------------------------------------- +// Initial version. Needs further optimizations. +//---------------------------------------------------------------- + +// +// Definitions for Runtime Memory Operations +// +#define RT_PAGE_SIZE 0x200 +#define RT_PAGE_MASK 0x1FF +#define RT_PAGE_SHIFT 9 + +#define RT_SIZE_TO_PAGES(a) (((a) >> RT_PAGE_SHIFT) + (((a) & RT_PAGE_MASK) ? 1 : 0)) +#define RT_PAGES_TO_SIZE(a) ((a) << RT_PAGE_SHIFT) + +// +// Page Flag Definitions +// +#define RT_PAGE_FREE 0x00000000 +#define RT_PAGE_USED 0x00000001 + +#define MIN_REQUIRED_BLOCKS 600 + +// +// Memory Page Table +// +typedef struct { + UINTN StartPageOffset; // Offset of the starting page allocated. + // Only available for USED pages. + UINT32 PageFlag; // Page Attributes. +} RT_MEMORY_PAGE_ENTRY; + +typedef struct { + UINTN PageCount; + UINTN LastEmptyPageOffset; + UINT8 *DataAreaBase; // Pointer to data Area. + RT_MEMORY_PAGE_ENTRY Pages[1]; // Page Table Entries. +} RT_MEMORY_PAGE_TABLE; + +// +// Global Page Table for Runtime Cryptographic Provider. +// +RT_MEMORY_PAGE_TABLE *mRTPageTable = NULL; + +// +// Event for Runtime Address Conversion. +// +STATIC EFI_EVENT mVirtualAddressChangeEvent; + + +/** + Initializes pre-allocated memory pointed by ScratchBuffer for subsequent + runtime use. + + @param[in, out] ScratchBuffer Pointer to user-supplied memory buffer. + @param[in] ScratchBufferSize Size of supplied buffer in bytes. + + @retval EFI_SUCCESS Successful initialization. + +**/ +EFI_STATUS +InitializeScratchMemory ( + IN OUT UINT8 *ScratchBuffer, + IN UINTN ScratchBufferSize + ) +{ + UINTN Index; + UINTN MemorySize; + + // + // Parameters Checking + // + if (ScratchBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (ScratchBufferSize < MIN_REQUIRED_BLOCKS * 1024) { + return EFI_BUFFER_TOO_SMALL; + } + + mRTPageTable = (RT_MEMORY_PAGE_TABLE *)ScratchBuffer; + + // + // Initialize Internal Page Table for Memory Management + // + SetMem (mRTPageTable, ScratchBufferSize, 0xFF); + MemorySize = ScratchBufferSize - sizeof (RT_MEMORY_PAGE_TABLE) + sizeof (RT_MEMORY_PAGE_ENTRY); + + mRTPageTable->PageCount = MemorySize / (RT_PAGE_SIZE + sizeof (RT_MEMORY_PAGE_ENTRY)); + mRTPageTable->LastEmptyPageOffset = 0x0; + + for (Index = 0; Index < mRTPageTable->PageCount; Index++) { + mRTPageTable->Pages[Index].PageFlag = RT_PAGE_FREE; + mRTPageTable->Pages[Index].StartPageOffset = 0; + } + + mRTPageTable->DataAreaBase = ScratchBuffer + sizeof (RT_MEMORY_PAGE_TABLE) + + (mRTPageTable->PageCount - 1) * sizeof (RT_MEMORY_PAGE_ENTRY); + + return EFI_SUCCESS; +} + + +/** + Look-up Free memory Region for object allocation. + + @param[in] AllocationSize Bytes to be allocated. + + @return Return available page offset for object allocation. + +**/ +UINTN +LookupFreeMemRegion ( + IN UINTN AllocationSize + ) +{ + UINTN StartPageIndex; + UINTN Index; + UINTN SubIndex; + UINTN ReqPages; + + StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->LastEmptyPageOffset); + ReqPages = RT_SIZE_TO_PAGES (AllocationSize); + if (ReqPages > mRTPageTable->PageCount) { + // + // No enough region for object allocation. + // + return (UINTN)(-1); + } + + // + // Look up the free memory region with in current memory map table. + // + for (Index = StartPageIndex; Index <= (mRTPageTable->PageCount - ReqPages); ) { + // + // Check consecutive ReqPages pages. + // + for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) { + if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) { + break; + } + } + + if (SubIndex == ReqPages) { + // + // Succeed! Return the Starting Offset. + // + return RT_PAGES_TO_SIZE (Index); + } + + // + // Failed! Skip current free memory pages and adjacent Used pages + // + while ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) { + SubIndex++; + } + + Index += SubIndex; + } + + // + // Look up the free memory region from the beginning of the memory table + // until the StartCursorOffset + // + if (ReqPages > StartPageIndex) { + // + // No enough region for object allocation. + // + return (UINTN)(-1); + } + for (Index = 0; Index < (StartPageIndex - ReqPages); ) { + // + // Check Consecutive ReqPages Pages. + // + for (SubIndex = 0; SubIndex < ReqPages; SubIndex++) { + if ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0) { + break; + } + } + + if (SubIndex == ReqPages) { + // + // Succeed! Return the Starting Offset. + // + return RT_PAGES_TO_SIZE (Index); + } + + // + // Failed! Skip current adjacent Used pages + // + while ((SubIndex < (StartPageIndex - ReqPages)) && + ((mRTPageTable->Pages[SubIndex + Index].PageFlag & RT_PAGE_USED) != 0)) { + SubIndex++; + } + + Index += SubIndex; + } + + // + // No available region for object allocation! + // + return (UINTN)(-1); +} + + +/** + Allocates a buffer at runtime phase. + + @param[in] AllocationSize Bytes to be allocated. + + @return A pointer to the allocated buffer or NULL if allocation fails. + +**/ +VOID * +RuntimeAllocateMem ( + IN UINTN AllocationSize + ) +{ + UINT8 *AllocPtr; + UINTN ReqPages; + UINTN Index; + UINTN StartPage; + UINTN AllocOffset; + + AllocPtr = NULL; + ReqPages = 0; + + // + // Look for available consecutive memory region starting from LastEmptyPageOffset. + // If no proper memory region found, look up from the beginning. + // If still not found, return NULL to indicate failed allocation. + // + AllocOffset = LookupFreeMemRegion (AllocationSize); + if (AllocOffset == (UINTN)(-1)) { + return NULL; + } + + // + // Allocates consecutive memory pages with length of Size. Update the page + // table status. Returns the starting address. + // + ReqPages = RT_SIZE_TO_PAGES (AllocationSize); + AllocPtr = mRTPageTable->DataAreaBase + AllocOffset; + StartPage = RT_SIZE_TO_PAGES (AllocOffset); + Index = 0; + while (Index < ReqPages) { + mRTPageTable->Pages[StartPage + Index].PageFlag |= RT_PAGE_USED; + mRTPageTable->Pages[StartPage + Index].StartPageOffset = AllocOffset; + + Index++; + } + + mRTPageTable->LastEmptyPageOffset = AllocOffset + RT_PAGES_TO_SIZE (ReqPages); + + ZeroMem (AllocPtr, AllocationSize); + + // + // Returns a void pointer to the allocated space + // + return AllocPtr; +} + + +/** + Frees a buffer that was previously allocated at runtime phase. + + @param[in] Buffer Pointer to the buffer to free. + +**/ +VOID +RuntimeFreeMem ( + IN VOID *Buffer + ) +{ + UINTN StartOffset; + UINTN StartPageIndex; + + StartOffset = (UINTN)Buffer - (UINTN)mRTPageTable->DataAreaBase; + StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES(StartOffset)].StartPageOffset); + + while (StartPageIndex < mRTPageTable->PageCount) { + if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) && + (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) { + // + // Free this page + // + mRTPageTable->Pages[StartPageIndex].PageFlag &= ~RT_PAGE_USED; + mRTPageTable->Pages[StartPageIndex].PageFlag |= RT_PAGE_FREE; + mRTPageTable->Pages[StartPageIndex].StartPageOffset = 0; + + StartPageIndex++; + } else { + break; + } + } + + return; +} + + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE + event. It converts a pointer to a new virtual address. + + @param[in] Event The event whose notification function is being invoked. + @param[in] Context The pointer to the notification function's context. + +**/ +VOID +EFIAPI +RuntimeCryptLibAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Converts a pointer for runtime memory management to a new virtual address. + // + EfiConvertPointer (0x0, (VOID **) &mRTPageTable->DataAreaBase); + EfiConvertPointer (0x0, (VOID **) &mRTPageTable); +} + + +/** + Constructor routine for runtime crypt library instance. + + The constructor function pre-allocates space for runtime cryptographic operation. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The construction succeeded. + @retval EFI_OUT_OF_RESOURCE Failed to allocate memory. + +**/ +EFI_STATUS +EFIAPI +RuntimeCryptLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VOID *Buffer; + + // + // Pre-allocates runtime space for possible cryptographic operations + // + Buffer = AllocateRuntimePool (MIN_REQUIRED_BLOCKS * 1024); + Status = InitializeScratchMemory (Buffer, MIN_REQUIRED_BLOCKS * 1024); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create address change event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + RuntimeCryptLibAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + + +// +// -- Memory-Allocation Routines Wrapper for UEFI-OpenSSL Library -- +// + +/* Allocates memory blocks */ +void *malloc (size_t size) +{ + return RuntimeAllocateMem ((UINTN) size); +} + +/* Reallocate memory blocks */ +void *realloc (void *ptr, size_t size) +{ + VOID *NewPtr; + UINTN StartOffset; + UINTN StartPageIndex; + UINTN PageCount; + + if (ptr == NULL) { + return malloc (size); + } + + // + // Get Original Size of ptr + // + StartOffset = (UINTN)ptr - (UINTN)mRTPageTable->DataAreaBase; + StartPageIndex = RT_SIZE_TO_PAGES (mRTPageTable->Pages[RT_SIZE_TO_PAGES (StartOffset)].StartPageOffset); + PageCount = 0; + while (StartPageIndex < mRTPageTable->PageCount) { + if (((mRTPageTable->Pages[StartPageIndex].PageFlag & RT_PAGE_USED) != 0) && + (mRTPageTable->Pages[StartPageIndex].StartPageOffset == StartOffset)) { + StartPageIndex++; + PageCount++; + } else { + break; + } + } + + if (size <= RT_PAGES_TO_SIZE (PageCount)) { + // + // Return the original pointer, if Caller try to reduce region size; + // + return ptr; + } + + NewPtr = RuntimeAllocateMem ((UINTN) size); + if (NewPtr == NULL) { + return NULL; + } + + CopyMem (NewPtr, ptr, RT_PAGES_TO_SIZE (PageCount)); + + RuntimeFreeMem (ptr); + + return NewPtr; +} + +/* Deallocates or frees a memory block */ +void free (void *ptr) +{ + // + // In Standard C, free() handles a null pointer argument transparently. This + // is not true of RuntimeFreeMem() below, so protect it. + // + if (ptr != NULL) { + RuntimeFreeMem (ptr); + } +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c new file mode 100644 index 00000000..eea6379a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/TimerWrapper.c @@ -0,0 +1,168 @@ +/** @file + C Run-Time Libraries (CRT) Time Management Routines Wrapper Implementation + for OpenSSL-based Cryptographic Library (used in DXE & RUNTIME). + +Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +// +// -- Time Management Routines -- +// + +#define IsLeap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) +#define SECSPERMIN (60) +#define SECSPERHOUR (60 * 60) +#define SECSPERDAY (24 * SECSPERHOUR) + +// +// The arrays give the cumulative number of days up to the first of the +// month number used as the index (1 -> 12) for regular and leap years. +// The value at index 13 is for the whole year. +// +UINTN CumulativeDays[2][14] = { + { + 0, + 0, + 31, + 31 + 28, + 31 + 28 + 31, + 31 + 28 + 31 + 30, + 31 + 28 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 + }, + { + 0, + 0, + 31, + 31 + 29, + 31 + 29 + 31, + 31 + 29 + 31 + 30, + 31 + 29 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 + } +}; + +/* Get the system time as seconds elapsed since midnight, January 1, 1970. */ +//INTN time( +// INTN *timer +// ) +time_t time (time_t *timer) +{ + EFI_STATUS Status; + EFI_TIME Time; + time_t CalTime; + UINTN Year; + + // + // Get the current time and date information + // + Status = gRT->GetTime (&Time, NULL); + if (EFI_ERROR (Status) || (Time.Year < 1970)) { + return 0; + } + + // + // Years Handling + // UTime should now be set to 00:00:00 on Jan 1 of the current year. + // + for (Year = 1970, CalTime = 0; Year != Time.Year; Year++) { + CalTime = CalTime + (time_t)(CumulativeDays[IsLeap(Year)][13] * SECSPERDAY); + } + + // + // Add in number of seconds for current Month, Day, Hour, Minute, Seconds, and TimeZone adjustment + // + CalTime = CalTime + + (time_t)((Time.TimeZone != EFI_UNSPECIFIED_TIMEZONE) ? (Time.TimeZone * 60) : 0) + + (time_t)(CumulativeDays[IsLeap(Time.Year)][Time.Month] * SECSPERDAY) + + (time_t)(((Time.Day > 0) ? Time.Day - 1 : 0) * SECSPERDAY) + + (time_t)(Time.Hour * SECSPERHOUR) + + (time_t)(Time.Minute * 60) + + (time_t)Time.Second; + + if (timer != NULL) { + *timer = CalTime; + } + + return CalTime; +} + +// +// Convert a time value from type time_t to struct tm. +// +struct tm * gmtime (const time_t *timer) +{ + struct tm *GmTime; + UINT16 DayNo; + UINT16 DayRemainder; + time_t Year; + time_t YearNo; + UINT16 TotalDays; + UINT16 MonthNo; + + if (timer == NULL) { + return NULL; + } + + GmTime = malloc (sizeof (struct tm)); + if (GmTime == NULL) { + return NULL; + } + + ZeroMem ((VOID *) GmTime, (UINTN) sizeof (struct tm)); + + DayNo = (UINT16) (*timer / SECSPERDAY); + DayRemainder = (UINT16) (*timer % SECSPERDAY); + + GmTime->tm_sec = (int) (DayRemainder % SECSPERMIN); + GmTime->tm_min = (int) ((DayRemainder % SECSPERHOUR) / SECSPERMIN); + GmTime->tm_hour = (int) (DayRemainder / SECSPERHOUR); + GmTime->tm_wday = (int) ((DayNo + 4) % 7); + + for (Year = 1970, YearNo = 0; DayNo > 0; Year++) { + TotalDays = (UINT16) (IsLeap (Year) ? 366 : 365); + if (DayNo >= TotalDays) { + DayNo = (UINT16) (DayNo - TotalDays); + YearNo++; + } else { + break; + } + } + + GmTime->tm_year = (int) (YearNo + (1970 - 1900)); + GmTime->tm_yday = (int) DayNo; + + for (MonthNo = 12; MonthNo > 1; MonthNo--) { + if (DayNo >= CumulativeDays[IsLeap(Year)][MonthNo]) { + DayNo = (UINT16) (DayNo - (UINT16) (CumulativeDays[IsLeap(Year)][MonthNo])); + break; + } + } + + GmTime->tm_mon = (int) MonthNo - 1; + GmTime->tm_mday = (int) DayNo + 1; + + GmTime->tm_isdst = 0; + GmTime->tm_gmtoff = 0; + GmTime->tm_zone = NULL; + + return GmTime; +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/UnitTestHostCrtWrapper.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/UnitTestHostCrtWrapper.c new file mode 100644 index 00000000..dee33e83 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/UnitTestHostCrtWrapper.c @@ -0,0 +1,93 @@ +/** @file + C Run-Time Libraries (CRT) Wrapper Implementation for OpenSSL-based + Cryptographic Library. + +Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#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; + + ASSERT(s1 != NULL); + ASSERT(s2 != NULL); + + 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; +} + +/* 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 UEFI cases. + // + return 0; +} + +// +// -- Dummy OpenSSL Support Routines -- +// + +int BIO_printf (void *bio, const char *format, ...) +{ + return 0; +} + +int BIO_snprintf(char *buf, size_t n, const char *format, ...) +{ + return 0; +} + +uid_t getuid (void) +{ + return 0; +} + +uid_t geteuid (void) +{ + return 0; +} + +gid_t getgid (void) +{ + return 0; +} + +gid_t getegid (void) +{ + return 0; +} + +int errno = 0; diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c new file mode 100644 index 00000000..81640af8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/SysCall/inet_pton.c @@ -0,0 +1,257 @@ +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* + * Portions copyright (c) 1999, 2000 + * Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Intel Corporation and + * its contributors. + * + * 4. Neither the name of Intel Corporation or its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char rcsid[] = "$Id: inet_pton.c $"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4 (const char *src, u_char *dst); +static int inet_pton6 (const char *src, u_char *dst); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +inet_pton( + int af, + const char *src, + void *dst + ) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4( + const char *src, + u_char *dst + ) +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (u_int)(pch - digits); + + if (new > 255) + return (0); + *tp = (u_char)new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6( + const char *src, + u_char *dst + ) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = (int)(tp - colonp); + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} diff --git a/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/UnitTestHostBaseCryptLib.inf b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/UnitTestHostBaseCryptLib.inf new file mode 100644 index 00000000..b02e6fef --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/CryptoPkg/Library/BaseCryptLib/UnitTestHostBaseCryptLib.inf @@ -0,0 +1,92 @@ +## @file +# Cryptographic Library Instance for host based unit tests +# +# Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseCryptLib + FILE_GUID = c97d34aa-caf8-42cd-8261-8705f46304b3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = BaseCryptLib|HOST_APPLICATION + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + InternalCryptLib.h + Hash/CryptMd5.c + Hash/CryptSha1.c + Hash/CryptSha256.c + Hash/CryptSha512.c + Hash/CryptSm3.c + Hmac/CryptHmacSha256.c + Kdf/CryptHkdf.c + Cipher/CryptAes.c + Pk/CryptRsaBasic.c + Pk/CryptRsaExt.c + Pk/CryptPkcs1Oaep.c + Pk/CryptPkcs5Pbkdf2.c + Pk/CryptPkcs7Sign.c + Pk/CryptPkcs7VerifyCommon.c + Pk/CryptPkcs7VerifyBase.c + Pk/CryptPkcs7VerifyEku.c + Pk/CryptDh.c + Pk/CryptX509.c + Pk/CryptAuthenticode.c + Pk/CryptTs.c + Pem/CryptPem.c + Pk/CryptRsaPss.c + Pk/CryptRsaPssSign.c + + SysCall/UnitTestHostCrtWrapper.c + +[Sources.Ia32] + Rand/CryptRandTsc.c + +[Sources.X64] + Rand/CryptRandTsc.c + +[Sources.ARM] + Rand/CryptRand.c + +[Sources.AARCH64] + Rand/CryptRand.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + DebugLib + OpensslLib + +# +# Remove these [BuildOptions] after this library is cleaned up +# +[BuildOptions] + # + # suppress the following warnings so we do not break the build with warnings-as-errors: + # C4090: 'function' : different 'const' qualifiers + # C4018: '>': signed/unsigned mismatch + MSFT:*_*_*_CC_FLAGS = /wd4090 /wd4018 + + # -JCryptoPkg/Include : To disable the use of the system includes provided by RVCT + # --diag_remark=1 : Reduce severity of "#1-D: last line of file ends without a newline" + RVCT:*_*_ARM_CC_FLAGS = -JCryptoPkg/Include --diag_remark=1 + + GCC:*_CLANG35_*_CC_FLAGS = -std=c99 + GCC:*_CLANG38_*_CC_FLAGS = -std=c99 + + XCODE:*_*_*_CC_FLAGS = -std=c99 -- cgit v1.2.3