* [edk2-devel] [PATCH v2 1/9] CryptoPkg: Add AeadAesGcm based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 2/9] CryptoPkg: Add rand function for BaseCryptLibMbedTls Wenxing Hou
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
AeadAesGcm implementation based on Mbedtls.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../Cipher/CryptAeadAesGcm.c | 227 ++++++++++++++++++
1 file changed, 227 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Cipher/CryptAeadAesGcm.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Cipher/CryptAeadAesGcm.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Cipher/CryptAeadAesGcm.c
new file mode 100644
index 0000000000..b49d6f9f87
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Cipher/CryptAeadAesGcm.c
@@ -0,0 +1,227 @@
+/** @file
+ AEAD (AES-GCM) Wrapper Implementation over MbedTLS.
+
+ RFC 5116 - An Interface and Algorithms for Authenticated Encryption
+ NIST SP800-38d - Cipher Modes of Operation: Galois / Counter Mode(GCM) and GMAC
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/gcm.h>
+
+/**
+ Performs AEAD AES-GCM authenticated encryption on a data buffer and additional authenticated data (AAD).
+
+ IvSize must be 12, otherwise FALSE is returned.
+ KeySize must be 16, 24 or 32, otherwise FALSE is returned.
+ TagSize must be 12, 13, 14, 15, 16, otherwise FALSE is returned.
+
+ @param[in] Key Pointer to the encryption key.
+ @param[in] KeySize Size of the encryption key in bytes.
+ @param[in] Iv Pointer to the IV value.
+ @param[in] IvSize Size of the IV value in bytes.
+ @param[in] AData Pointer to the additional authenticated data (AAD).
+ @param[in] ADataSize Size of the additional authenticated data (AAD) in bytes.
+ @param[in] DataIn Pointer to the input data buffer to be encrypted.
+ @param[in] DataInSize Size of the input data buffer in bytes.
+ @param[out] TagOut Pointer to a buffer that receives the authentication tag output.
+ @param[in] TagSize Size of the authentication tag in bytes.
+ @param[out] DataOut Pointer to a buffer that receives the encryption output.
+ @param[out] DataOutSize Size of the output data buffer in bytes.
+
+ @retval TRUE AEAD AES-GCM authenticated encryption succeeded.
+ @retval FALSE AEAD AES-GCM authenticated encryption failed.
+
+**/
+BOOLEAN
+EFIAPI
+AeadAesGcmEncrypt (
+ IN CONST UINT8 *Key,
+ IN UINTN KeySize,
+ IN CONST UINT8 *Iv,
+ IN UINTN IvSize,
+ IN CONST UINT8 *AData,
+ IN UINTN ADataSize,
+ IN CONST UINT8 *DataIn,
+ IN UINTN DataInSize,
+ OUT UINT8 *TagOut,
+ IN UINTN TagSize,
+ OUT UINT8 *DataOut,
+ OUT UINTN *DataOutSize
+ )
+{
+ mbedtls_gcm_context Ctx;
+ INT32 Ret;
+
+ if (DataInSize > INT_MAX) {
+ return FALSE;
+ }
+
+ if (ADataSize > INT_MAX) {
+ return FALSE;
+ }
+
+ if (IvSize != 12) {
+ return FALSE;
+ }
+
+ switch (KeySize) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return FALSE;
+ }
+
+ if ((TagSize != 12) && (TagSize != 13) && (TagSize != 14) && (TagSize != 15) && (TagSize != 16)) {
+ return FALSE;
+ }
+
+ if (DataOutSize != NULL) {
+ if ((*DataOutSize > INT_MAX) || (*DataOutSize < DataInSize)) {
+ return FALSE;
+ }
+ }
+
+ mbedtls_gcm_init (&Ctx);
+
+ Ret = mbedtls_gcm_setkey (&Ctx, MBEDTLS_CIPHER_ID_AES, Key, (UINT32)(KeySize * 8));
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ Ret = mbedtls_gcm_crypt_and_tag (
+ &Ctx,
+ MBEDTLS_GCM_ENCRYPT,
+ (UINT32)DataInSize,
+ Iv,
+ (UINT32)IvSize,
+ AData,
+ (UINT32)ADataSize,
+ DataIn,
+ DataOut,
+ TagSize,
+ TagOut
+ );
+ mbedtls_gcm_free (&Ctx);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ if (DataOutSize != NULL) {
+ *DataOutSize = DataInSize;
+ }
+
+ return TRUE;
+}
+
+/**
+ Performs AEAD AES-GCM authenticated decryption on a data buffer and additional authenticated data (AAD).
+
+ IvSize must be 12, otherwise FALSE is returned.
+ KeySize must be 16, 24 or 32, otherwise FALSE is returned.
+ TagSize must be 12, 13, 14, 15, 16, otherwise FALSE is returned.
+ If additional authenticated data verification fails, FALSE is returned.
+
+ @param[in] Key Pointer to the encryption key.
+ @param[in] KeySize Size of the encryption key in bytes.
+ @param[in] Iv Pointer to the IV value.
+ @param[in] IvSize Size of the IV value in bytes.
+ @param[in] AData Pointer to the additional authenticated data (AAD).
+ @param[in] ADataSize Size of the additional authenticated data (AAD) in bytes.
+ @param[in] DataIn Pointer to the input data buffer to be decrypted.
+ @param[in] DataInSize Size of the input data buffer in bytes.
+ @param[in] Tag Pointer to a buffer that contains the authentication tag.
+ @param[in] TagSize Size of the authentication tag in bytes.
+ @param[out] DataOut Pointer to a buffer that receives the decryption output.
+ @param[out] DataOutSize Size of the output data buffer in bytes.
+
+ @retval TRUE AEAD AES-GCM authenticated decryption succeeded.
+ @retval FALSE AEAD AES-GCM authenticated decryption failed.
+
+**/
+BOOLEAN
+EFIAPI
+AeadAesGcmDecrypt (
+ IN CONST UINT8 *Key,
+ IN UINTN KeySize,
+ IN CONST UINT8 *Iv,
+ IN UINTN IvSize,
+ IN CONST UINT8 *AData,
+ IN UINTN ADataSize,
+ IN CONST UINT8 *DataIn,
+ IN UINTN DataInSize,
+ IN CONST UINT8 *Tag,
+ IN UINTN TagSize,
+ OUT UINT8 *DataOut,
+ OUT UINTN *DataOutSize
+ )
+{
+ mbedtls_gcm_context Ctx;
+ INT32 Ret;
+
+ if (DataInSize > INT_MAX) {
+ return FALSE;
+ }
+
+ if (ADataSize > INT_MAX) {
+ return FALSE;
+ }
+
+ if (IvSize != 12) {
+ return FALSE;
+ }
+
+ switch (KeySize) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ return FALSE;
+ }
+
+ if ((TagSize != 12) && (TagSize != 13) && (TagSize != 14) && (TagSize != 15) && (TagSize != 16)) {
+ return FALSE;
+ }
+
+ if (DataOutSize != NULL) {
+ if ((*DataOutSize > INT_MAX) || (*DataOutSize < DataInSize)) {
+ return FALSE;
+ }
+ }
+
+ mbedtls_gcm_init (&Ctx);
+
+ Ret = mbedtls_gcm_setkey (&Ctx, MBEDTLS_CIPHER_ID_AES, Key, (UINT32)(KeySize * 8));
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ Ret = mbedtls_gcm_auth_decrypt (
+ &Ctx,
+ (UINT32)DataInSize,
+ Iv,
+ (UINT32)IvSize,
+ AData,
+ (UINT32)ADataSize,
+ Tag,
+ (UINT32)TagSize,
+ DataIn,
+ DataOut
+ );
+ mbedtls_gcm_free (&Ctx);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ if (DataOutSize != NULL) {
+ *DataOutSize = DataInSize;
+ }
+
+ return TRUE;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118111): https://edk2.groups.io/g/devel/message/118111
Mute This Topic: https://groups.io/mt/105683585/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 2/9] CryptoPkg: Add rand function for BaseCryptLibMbedTls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 1/9] CryptoPkg: Add AeadAesGcm " Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 3/9] CryptoPkg: Add Pem APIs based on Mbedtls Wenxing Hou
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
Add rand function for BaseCryptLibMbedTls.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../BaseCryptLibMbedTls/InternalCryptLib.h | 16 +++
.../BaseCryptLibMbedTls/Rand/CryptRand.c | 105 ++++++++++++++++++
.../BaseCryptLibMbedTls/Rand/CryptRandTsc.c | 105 ++++++++++++++++++
3 files changed, 226 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRand.c
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRandTsc.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h b/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h
index 039aa32028..8c463457d5 100644
--- a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h
@@ -22,4 +22,20 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
#include <mbedtls/mbedtls_config.h>
+/**
+ The MbedTLS function f_rng, which MbedtlsRand implements.
+
+ @param[in] RngState Not used, just for compatibility with mbedlts.
+ @param[out] Output Pointer to buffer to receive random value.
+ @param[in] Len Size of random bytes to generate.
+
+ @retval 0 Pseudorandom byte stream generated successfully.
+ @retval Non-0 Pseudorandom number generator fails to generate due to lack of entropy.
+**/
+INTN
+MbedtlsRand (
+ VOID *RngState,
+ UINT8 *Output,
+ UINTN Len
+ );
#endif
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRand.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRand.c
new file mode 100644
index 0000000000..b1531ee5b8
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRand.c
@@ -0,0 +1,105 @@
+/** @file
+ Pseudorandom Number Generator Wrapper Implementation over MbedTLS.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <Library/RngLib.h>
+
+/**
+ 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
+ )
+{
+ return TRUE;
+}
+
+/**
+ 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
+ )
+{
+ BOOLEAN Ret;
+ UINT64 TempRand;
+
+ Ret = FALSE;
+
+ while (Size > 0) {
+ // Use RngLib to get random number
+ Ret = GetRandomNumber64 (&TempRand);
+
+ if (!Ret) {
+ return Ret;
+ }
+
+ if (Size >= sizeof (TempRand)) {
+ *((UINT64 *)Output) = TempRand;
+ Output += sizeof (UINT64);
+ Size -= sizeof (TempRand);
+ } else {
+ CopyMem (Output, &TempRand, Size);
+ Size = 0;
+ }
+ }
+
+ return Ret;
+}
+
+/**
+ The MbedTLS function f_rng, which MbedtlsRand implements.
+
+ @param[in] RngState Not used, just for compatibility with mbedlts.
+ @param[out] Output Pointer to buffer to receive random value.
+ @param[in] Len Size of random bytes to generate.
+
+ @retval 0 Pseudorandom byte stream generated successfully.
+ @retval Non-0 Pseudorandom number generator fails to generate due to lack of entropy.
+**/
+INTN
+MbedtlsRand (
+ VOID *RngState,
+ UINT8 *Output,
+ UINTN Len
+ )
+{
+ BOOLEAN Result;
+
+ Result = RandomBytes (Output, Len);
+
+ return Result ? 0 : -1;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRandTsc.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRandTsc.c
new file mode 100644
index 0000000000..b1531ee5b8
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRandTsc.c
@@ -0,0 +1,105 @@
+/** @file
+ Pseudorandom Number Generator Wrapper Implementation over MbedTLS.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <Library/RngLib.h>
+
+/**
+ 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
+ )
+{
+ return TRUE;
+}
+
+/**
+ 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
+ )
+{
+ BOOLEAN Ret;
+ UINT64 TempRand;
+
+ Ret = FALSE;
+
+ while (Size > 0) {
+ // Use RngLib to get random number
+ Ret = GetRandomNumber64 (&TempRand);
+
+ if (!Ret) {
+ return Ret;
+ }
+
+ if (Size >= sizeof (TempRand)) {
+ *((UINT64 *)Output) = TempRand;
+ Output += sizeof (UINT64);
+ Size -= sizeof (TempRand);
+ } else {
+ CopyMem (Output, &TempRand, Size);
+ Size = 0;
+ }
+ }
+
+ return Ret;
+}
+
+/**
+ The MbedTLS function f_rng, which MbedtlsRand implements.
+
+ @param[in] RngState Not used, just for compatibility with mbedlts.
+ @param[out] Output Pointer to buffer to receive random value.
+ @param[in] Len Size of random bytes to generate.
+
+ @retval 0 Pseudorandom byte stream generated successfully.
+ @retval Non-0 Pseudorandom number generator fails to generate due to lack of entropy.
+**/
+INTN
+MbedtlsRand (
+ VOID *RngState,
+ UINT8 *Output,
+ UINTN Len
+ )
+{
+ BOOLEAN Result;
+
+ Result = RandomBytes (Output, Len);
+
+ return Result ? 0 : -1;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118112): https://edk2.groups.io/g/devel/message/118112
Mute This Topic: https://groups.io/mt/105683586/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 3/9] CryptoPkg: Add Pem APIs based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 1/9] CryptoPkg: Add AeadAesGcm " Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 2/9] CryptoPkg: Add rand function for BaseCryptLibMbedTls Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 4/9] CryptoPkg: Add X509 functions " Wenxing Hou
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
Implement Pem API based on Mbedtls.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../BaseCryptLibMbedTls/Pem/CryptPem.c | 138 ++++++++++++++++++
1 file changed, 138 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pem/CryptPem.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pem/CryptPem.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pem/CryptPem.c
new file mode 100644
index 0000000000..56411174dd
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pem/CryptPem.c
@@ -0,0 +1,138 @@
+/** @file
+ PEM (Privacy Enhanced Mail) Format Handler Wrapper Implementation over MbedTLS.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/pem.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/rsa.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/ecdh.h>
+#include <mbedtls/ecdsa.h>
+
+/**
+ 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
+ )
+{
+ INT32 Ret;
+ mbedtls_pk_context Pk;
+ mbedtls_rsa_context *Rsa;
+ UINT8 *NewPemData;
+ UINTN PasswordLen;
+
+ if ((PemData == NULL) || (RsaContext == NULL) || (PemSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ NewPemData = NULL;
+ if (PemData[PemSize - 1] != 0) {
+ NewPemData = AllocateZeroPool (PemSize + 1);
+ if (NewPemData == NULL) {
+ return FALSE;
+ }
+
+ CopyMem (NewPemData, PemData, PemSize + 1);
+ NewPemData[PemSize] = 0;
+ PemData = NewPemData;
+ PemSize += 1;
+ }
+
+ mbedtls_pk_init (&Pk);
+
+ if (Password != NULL) {
+ PasswordLen = AsciiStrLen (Password);
+ } else {
+ PasswordLen = 0;
+ }
+
+ Ret = mbedtls_pk_parse_key (&Pk, PemData, PemSize, (CONST UINT8 *)Password, PasswordLen, NULL, NULL);
+
+ if (NewPemData != NULL) {
+ FreePool (NewPemData);
+ NewPemData = NULL;
+ }
+
+ if (Ret != 0) {
+ mbedtls_pk_free (&Pk);
+ return FALSE;
+ }
+
+ if (mbedtls_pk_get_type (&Pk) != MBEDTLS_PK_RSA) {
+ mbedtls_pk_free (&Pk);
+ return FALSE;
+ }
+
+ Rsa = RsaNew ();
+ if (Rsa == NULL) {
+ mbedtls_pk_free (&Pk);
+ return FALSE;
+ }
+
+ Ret = mbedtls_rsa_copy (Rsa, mbedtls_pk_rsa (Pk));
+ if (Ret != 0) {
+ RsaFree (Rsa);
+ mbedtls_pk_free (&Pk);
+ return FALSE;
+ }
+
+ mbedtls_pk_free (&Pk);
+
+ *RsaContext = Rsa;
+ return TRUE;
+}
+
+/**
+ Retrieve the EC 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] EcContext Pointer to new-generated EC DSA context which contain the retrieved
+ EC private key component. Use EcFree() function to free the
+ resource.
+
+ If PemData is NULL, then return FALSE.
+ If EcContext is NULL, then return FALSE.
+
+ @retval TRUE EC Private Key was retrieved successfully.
+ @retval FALSE Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPrivateKeyFromPem (
+ IN CONST UINT8 *PemData,
+ IN UINTN PemSize,
+ IN CONST CHAR8 *Password,
+ OUT VOID **EcContext
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118113): https://edk2.groups.io/g/devel/message/118113
Mute This Topic: https://groups.io/mt/105683587/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 4/9] CryptoPkg: Add X509 functions based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
` (2 preceding siblings ...)
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 3/9] CryptoPkg: Add Pem APIs based on Mbedtls Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 5/9] CryptoPkg: Add Pkcs7 related " Wenxing Hou
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
X.509 Certificate Handler Wrapper Implementation over MbedTLS.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../BaseCryptLibMbedTls/Pk/CryptX509.c | 1925 +++++++++++++++++
1 file changed, 1925 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c
new file mode 100644
index 0000000000..5a2ad9b49e
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c
@@ -0,0 +1,1925 @@
+/** @file
+ X.509 Certificate Handler Wrapper Implementation over MbedTLS.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/x509.h>
+#include <mbedtls/x509_crt.h>
+#include <mbedtls/rsa.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/ecdh.h>
+#include <mbedtls/ecdsa.h>
+
+///
+/// OID
+///
+STATIC CONST UINT8 OID_commonName[] = {
+ 0x55, 0x04, 0x03
+};
+STATIC CONST UINT8 OID_organizationName[] = {
+ 0x55, 0x04, 0x0A
+};
+STATIC CONST UINT8 OID_extKeyUsage[] = {
+ 0x55, 0x1D, 0x25
+};
+STATIC CONST UINT8 OID_BasicConstraints[] = {
+ 0x55, 0x1D, 0x13
+};
+
+/* Profile for backward compatibility. Allows RSA 1024, unlike the default
+ profile. */
+STATIC mbedtls_x509_crt_profile gCompatProfile =
+{
+ /* Hashes from SHA-256 and above. Note that this selection
+ * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA256) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA384) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA512),
+ 0xFFFFFFF, /* Any PK alg */
+
+ /* Curves at or above 128-bit security level. Note that this selection
+ * should be aligned with ssl_preset_default_curves in ssl_tls.c. */
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP256R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP384R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP521R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP256R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP384R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP512R1) |
+ 0,
+ 1024,
+};
+
+/**
+ 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
+ )
+{
+ mbedtls_x509_crt *MbedTlsCert;
+ INT32 Ret;
+
+ if ((Cert == NULL) || (SingleX509Cert == NULL) || (CertSize == 0)) {
+ return FALSE;
+ }
+
+ MbedTlsCert = AllocateZeroPool (sizeof (mbedtls_x509_crt));
+ if (MbedTlsCert == NULL) {
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_init (MbedTlsCert);
+
+ *SingleX509Cert = (UINT8 *)(VOID *)MbedTlsCert;
+ Ret = mbedtls_x509_crt_parse_der (MbedTlsCert, Cert, CertSize);
+
+ return Ret == 0;
+}
+
+/**
+ 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;
+ INT32 Index;
+ INT32 Ret;
+ mbedtls_x509_crt *Crt;
+
+ if (X509Stack == NULL) {
+ return FALSE;
+ }
+
+ Ret = 0;
+ Crt = (mbedtls_x509_crt *)*X509Stack;
+ if (Crt == NULL) {
+ Crt = AllocateZeroPool (sizeof (mbedtls_x509_crt));
+ if (Crt == NULL) {
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_init (Crt);
+ *X509Stack = (UINT8 *)Crt;
+ }
+
+ 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;
+ }
+
+ Ret = mbedtls_x509_crt_parse_der (Crt, Cert, CertSize);
+
+ if (Ret != 0) {
+ break;
+ }
+ }
+
+ return Ret == 0;
+}
+
+/**
+ 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
+ )
+{
+ if (X509Cert != NULL) {
+ mbedtls_x509_crt_free (X509Cert);
+ FreePool (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
+ )
+{
+ if (X509Stack == NULL) {
+ return;
+ }
+
+ mbedtls_x509_crt_free (X509Stack);
+}
+
+/**
+ Retrieve the tag and length of the tag.
+
+ @param Ptr The position in the ASN.1 data
+ @param End End of data
+ @param Length The variable that will receive the length
+ @param Tag The expected tag
+
+ @retval TRUE Get tag successful
+ @retval FALSe Failed to get tag or tag not match
+**/
+BOOLEAN
+EFIAPI
+Asn1GetTag (
+ IN OUT UINT8 **Ptr,
+ IN CONST UINT8 *End,
+ OUT UINTN *Length,
+ IN UINT32 Tag
+ )
+{
+ if (mbedtls_asn1_get_tag (Ptr, End, Length, (INT32)Tag) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ 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
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (CertSubject != NULL) {
+ CopyMem (CertSubject, Crt.subject_raw.p, Crt.subject_raw.len);
+ }
+
+ *SubjectSize = Crt.subject_raw.len;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return Ret == 0;
+}
+
+/**
+ Retrieve a string from one X.509 certificate base on the Request_NID.
+
+ @param[in] Name mbedtls_x509_name
+ @param[in] Oid Oid
+ @param[in] OidSize Size of Oid
+ @param[in,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.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalX509GetNIDName (
+ IN mbedtls_x509_name *Name,
+ IN CHAR8 *Oid,
+ IN UINTN OidSize,
+ IN OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ CONST mbedtls_asn1_named_data *data;
+
+ data = mbedtls_asn1_find_named_data (Name, Oid, OidSize);
+ if (data != NULL) {
+ if (*CommonNameSize <= data->val.len) {
+ *CommonNameSize = data->val.len + 1;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+
+ if (CommonName != NULL) {
+ CopyMem (CommonName, data->val.p, data->val.len);
+ CommonName[data->val.len] = '\0';
+ }
+
+ *CommonNameSize = data->val.len + 1;
+ return RETURN_SUCCESS;
+ } else {
+ return RETURN_NOT_FOUND;
+ }
+}
+
+/**
+ Get X509 SubjectNIDName by OID.
+
+ @param[in] Cert certificate
+ @param[in] CertSize certificate size.
+ @param[in] Oid Oid
+ @param[in] OidSize Size of Oid
+ @param[in,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.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalX509GetSubjectNIDName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CHAR8 *Oid,
+ IN UINTN OidSize,
+ IN OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ mbedtls_x509_name *Name;
+ RETURN_STATUS ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ Name = &(Crt.subject);
+ ReturnStatus = InternalX509GetNIDName (Name, Oid, OidSize, CommonName, CommonNameSize);
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Get X509 IssuerNIDName by OID.
+
+ @param[in] Cert certificate
+ @param[in] CertSize certificate size.
+ @param[in] Oid Oid
+ @param[in] OidSize Size of Oid
+ @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.
+
+**/
+RETURN_STATUS
+EFIAPI
+InternalX509GetIssuerNIDName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CHAR8 *Oid,
+ IN UINTN OidSize,
+ OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ mbedtls_x509_name *Name;
+ RETURN_STATUS ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ Name = &(Crt.issuer);
+ ReturnStatus = InternalX509GetNIDName (Name, Oid, OidSize, CommonName, CommonNameSize);
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ 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 InternalX509GetSubjectNIDName (Cert, CertSize, (CHAR8 *)OID_commonName, sizeof (OID_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 InternalX509GetSubjectNIDName (Cert, CertSize, (CHAR8 *)OID_organizationName, sizeof (OID_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
+ )
+{
+ mbedtls_x509_crt Crt;
+ mbedtls_rsa_context *Rsa;
+ INT32 Ret;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ if (mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize) != 0) {
+ return FALSE;
+ }
+
+ if (mbedtls_pk_get_type (&Crt.pk) != MBEDTLS_PK_RSA) {
+ mbedtls_x509_crt_free (&Crt);
+ return FALSE;
+ }
+
+ Rsa = RsaNew ();
+ if (Rsa == NULL) {
+ mbedtls_x509_crt_free (&Crt);
+ return FALSE;
+ }
+
+ Ret = mbedtls_rsa_copy (Rsa, mbedtls_pk_rsa (Crt.pk));
+ if (Ret != 0) {
+ RsaFree (Rsa);
+ mbedtls_x509_crt_free (&Crt);
+ return FALSE;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ *RsaContext = Rsa;
+ return TRUE;
+}
+
+/**
+ Retrieve the EC 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] EcContext Pointer to new-generated EC DSA context which contain the retrieved
+ EC public key component. Use EcFree() function to free the
+ resource.
+
+ If Cert is NULL, then return FALSE.
+ If EcContext is NULL, then return FALSE.
+
+ @retval TRUE EC Public Key was retrieved successfully.
+ @retval FALSE Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT VOID **EcContext
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ 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
+ )
+{
+ INT32 Ret;
+ mbedtls_x509_crt Ca;
+ mbedtls_x509_crt End;
+ UINT32 VFlag;
+ mbedtls_x509_crt_profile Profile;
+
+ if ((Cert == NULL) || (CACert == NULL)) {
+ return FALSE;
+ }
+
+ VFlag = 0;
+ CopyMem (&Profile, &gCompatProfile, sizeof (mbedtls_x509_crt_profile));
+
+ mbedtls_x509_crt_init (&Ca);
+ mbedtls_x509_crt_init (&End);
+
+ Ret = mbedtls_x509_crt_parse_der (&Ca, CACert, CACertSize);
+
+ if (Ret == 0) {
+ Ret = mbedtls_x509_crt_parse_der (&End, Cert, CertSize);
+ }
+
+ if (Ret == 0) {
+ Ret = mbedtls_x509_crt_verify_with_profile (&End, &Ca, NULL, &Profile, NULL, &VFlag, NULL, NULL);
+ }
+
+ mbedtls_x509_crt_free (&Ca);
+ mbedtls_x509_crt_free (&End);
+
+ return Ret == 0;
+}
+
+/**
+ Verify one X509 certificate was issued by the trusted CA.
+
+ @param[in] RootCert Trusted Root Certificate buffer
+ @param[in] RootCertLength Trusted Root Certificate buffer length
+ @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates
+ where the first certificate is signed by the Root
+ Certificate or is the Root Cerificate itself. and
+ subsequent cerificate is signed by the preceding
+ cerificate.
+ @param[in] CertChainLength Total length of the certificate chain, in bytes.
+
+ @retval TRUE All cerificates was issued by the first certificate in X509Certchain.
+ @retval FALSE Invalid certificate or the certificate was not issued by the given
+ trusted CA.
+**/
+BOOLEAN
+EFIAPI
+X509VerifyCertChain (
+ IN CONST UINT8 *RootCert,
+ IN UINTN RootCertLength,
+ IN CONST UINT8 *CertChain,
+ IN UINTN CertChainLength
+ )
+{
+ UINTN Asn1Len;
+ UINTN PrecedingCertLen;
+ CONST UINT8 *PrecedingCert;
+ UINTN CurrentCertLen;
+ CONST UINT8 *CurrentCert;
+ CONST UINT8 *TmpPtr;
+ UINT32 Ret;
+ BOOLEAN VerifyFlag;
+
+ VerifyFlag = FALSE;
+ PrecedingCert = RootCert;
+ PrecedingCertLen = RootCertLength;
+
+ CurrentCert = CertChain;
+
+ //
+ // Get Current certificate from Certificates buffer and Verify with preciding cert
+ //
+ do {
+ TmpPtr = CurrentCert;
+ Ret = mbedtls_asn1_get_tag ((UINT8 **)&TmpPtr, CertChain + CertChainLength, &Asn1Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ break;
+ }
+
+ CurrentCertLen = Asn1Len + (TmpPtr - CurrentCert);
+
+ if (!X509VerifyCert (CurrentCert, CurrentCertLen, PrecedingCert, PrecedingCertLen)) {
+ VerifyFlag = FALSE;
+ break;
+ } else {
+ VerifyFlag = TRUE;
+ }
+
+ //
+ // Save preceding certificate
+ //
+ PrecedingCert = CurrentCert;
+ PrecedingCertLen = CurrentCertLen;
+
+ //
+ // Move current certificate to next;
+ //
+ CurrentCert = CurrentCert + CurrentCertLen;
+ } while (1);
+
+ return VerifyFlag;
+}
+
+/**
+ Get one X509 certificate from CertChain.
+
+ @param[in] CertChain One or more ASN.1 DER-encoded X.509 certificates
+ where the first certificate is signed by the Root
+ Certificate or is the Root Cerificate itself. and
+ subsequent cerificate is signed by the preceding
+ cerificate.
+ @param[in] CertChainLength Total length of the certificate chain, in bytes.
+
+ @param[in] CertIndex Index of certificate.
+
+ @param[out] Cert The certificate at the index of CertChain.
+ @param[out] CertLength The length certificate at the index of CertChain.
+
+ @retval TRUE Success.
+ @retval FALSE Failed to get certificate from certificate chain.
+**/
+BOOLEAN
+EFIAPI
+X509GetCertFromCertChain (
+ IN CONST UINT8 *CertChain,
+ IN UINTN CertChainLength,
+ IN CONST INT32 CertIndex,
+ OUT CONST UINT8 **Cert,
+ OUT UINTN *CertLength
+ )
+{
+ UINTN Asn1Len;
+ INT32 CurrentIndex;
+ UINTN CurrentCertLen;
+ CONST UINT8 *CurrentCert;
+ CONST UINT8 *TmpPtr;
+ INT32 Ret;
+
+ //
+ // Check input parameters.
+ //
+ if ((CertChain == NULL) || (Cert == NULL) ||
+ (CertIndex < -1) || (CertLength == NULL))
+ {
+ return FALSE;
+ }
+
+ CurrentCert = CertChain;
+ CurrentIndex = -1;
+
+ //
+ // Traverse the certificate chain
+ //
+ while (TRUE) {
+ //
+ // Get asn1 tag len
+ //
+ TmpPtr = CurrentCert;
+ Ret = mbedtls_asn1_get_tag ((UINT8 **)&TmpPtr, CertChain + CertChainLength, &Asn1Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ break;
+ }
+
+ CurrentCertLen = Asn1Len + (TmpPtr - CurrentCert);
+ CurrentIndex++;
+
+ if (CurrentIndex == CertIndex) {
+ *Cert = CurrentCert;
+ *CertLength = CurrentCertLen;
+ return TRUE;
+ }
+
+ //
+ // Move to next
+ //
+ CurrentCert = CurrentCert + CurrentCertLen;
+ }
+
+ //
+ // If CertIndex is -1, Return the last certificate
+ //
+ if ((CertIndex == -1) && (CurrentIndex >= 0)) {
+ *Cert = CurrentCert - CurrentCertLen;
+ *CertLength = CurrentCertLen;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ 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
+ )
+{
+ UINTN Length;
+ UINTN Ret;
+ UINT8 *Ptr;
+ CONST UINT8 *Temp;
+ CONST UINT8 *End;
+
+ //
+ // 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.
+ //
+
+ Length = 0;
+
+ Ptr = (UINT8 *)Cert;
+ End = Cert + CertSize;
+
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &Length, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ Temp = Ptr;
+ End = Ptr + Length;
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &Length, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ *TBSCert = (UINT8 *)Temp;
+ *TBSCertSize = Length + (Ptr - Temp);
+
+ return TRUE;
+}
+
+/**
+ Retrieve the version from one X.509 certificate.
+
+ If Cert is NULL, then return FALSE.
+ If CertSize is 0, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] Version Pointer to the retrieved version integer.
+
+ @retval TRUE The certificate version retrieved successfully.
+ @retval FALSE If Cert is NULL or CertSize is Zero.
+ @retval FALSE The operation is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetVersion (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINTN *Version
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ *Version = Crt.version - 1;
+ ReturnStatus = TRUE;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve the serialNumber from one X.509 certificate.
+
+ If Cert is NULL, then return FALSE.
+ If CertSize is 0, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] SerialNumber Pointer to the retrieved certificate SerialNumber bytes.
+ @param[in, out] SerialNumberSize The size in bytes of the SerialNumber buffer on input,
+ and the size of buffer returned SerialNumber on output.
+
+ @retval TRUE The certificate serialNumber retrieved successfully.
+ @retval FALSE If Cert is NULL or CertSize is Zero.
+ If SerialNumberSize is NULL.
+ If Certificate is invalid.
+ @retval FALSE If no SerialNumber exists.
+ @retval FALSE If the SerialNumber is NULL. The required buffer size
+ (including the final null) is returned in the
+ SerialNumberSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetSerialNumber (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *SerialNumber OPTIONAL,
+ IN OUT UINTN *SerialNumberSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN ReturnStatus;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ ReturnStatus = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (*SerialNumberSize <= Crt.serial.len) {
+ *SerialNumberSize = Crt.serial.len + 1;
+ ReturnStatus = FALSE;
+ goto Cleanup;
+ }
+
+ if (SerialNumber != NULL) {
+ CopyMem (SerialNumber, Crt.serial.p, Crt.serial.len);
+ SerialNumber[Crt.serial.len] = '\0';
+ }
+
+ *SerialNumberSize = Crt.serial.len + 1;
+ ReturnStatus = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve the issuer bytes from one X.509 certificate.
+
+ If Cert is NULL, then return FALSE.
+ If CertIssuerSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[out] CertIssuer Pointer to the retrieved certificate subject bytes.
+ @param[in, out] CertIssuerSize The size in bytes of the CertIssuer buffer on input,
+ and the size of buffer returned CertSubject on output.
+
+ @retval TRUE The certificate issuer retrieved successfully.
+ @retval FALSE Invalid certificate, or the CertIssuerSize is too small for the result.
+ The CertIssuerSize will be updated with the required size.
+ @retval FALSE This interface is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+X509GetIssuerName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *CertIssuer,
+ IN OUT UINTN *CertIssuerSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (*CertIssuerSize < Crt.serial.len) {
+ *CertIssuerSize = Crt.serial.len;
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ if (CertIssuer != NULL) {
+ CopyMem (CertIssuer, Crt.serial.p, Crt.serial.len);
+ }
+
+ *CertIssuerSize = Crt.serial.len;
+ Status = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the issuer 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 issuer 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 Issuer 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
+X509GetIssuerCommonName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *CommonName OPTIONAL,
+ IN OUT UINTN *CommonNameSize
+ )
+{
+ return InternalX509GetIssuerNIDName (Cert, CertSize, (CHAR8 *)OID_commonName, sizeof (OID_commonName), CommonName, CommonNameSize);
+}
+
+/**
+ Retrieve the issuer 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 issuer 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 issuer 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
+X509GetIssuerOrganizationName (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT CHAR8 *NameBuffer OPTIONAL,
+ IN OUT UINTN *NameBufferSize
+ )
+{
+ return InternalX509GetIssuerNIDName (Cert, CertSize, (CHAR8 *)OID_organizationName, sizeof (OID_organizationName), NameBuffer, NameBufferSize);
+}
+
+/**
+ Retrieve the Signature Algorithm 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] Oid Signature Algorithm Object identifier buffer.
+ @param[in,out] OidSize Signature Algorithm Object identifier buffer size
+
+ @retval TRUE The certificate Extension data retrieved successfully.
+ @retval FALSE If Cert is NULL.
+ If OidSize is NULL.
+ If Oid is not NULL and *OidSize is 0.
+ If Certificate is invalid.
+ @retval FALSE If no SignatureType.
+ @retval FALSE If the Oid is NULL. The required buffer size
+ is returned in the OidSize.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetSignatureAlgorithm (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *Oid OPTIONAL,
+ IN OUT UINTN *OidSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN ReturnStatus;
+
+ if ((Cert == NULL) || (CertSize == 0) || (OidSize == NULL)) {
+ return FALSE;
+ }
+
+ ReturnStatus = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ if (*OidSize < Crt.sig_oid.len) {
+ *OidSize = Crt.serial.len;
+ ReturnStatus = FALSE;
+ goto Cleanup;
+ }
+
+ if (Oid != NULL) {
+ CopyMem (Oid, Crt.sig_oid.p, Crt.sig_oid.len);
+ }
+
+ *OidSize = Crt.sig_oid.len;
+ ReturnStatus = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return ReturnStatus;
+}
+
+/**
+ Find first Extension data match with given OID
+
+ @param[in] Start Pointer to the DER-encoded Extensions Data
+ @param[in] End Extensions Data size in bytes
+ @param[in ] Oid OID for match
+ @param[in ] OidSize OID size in bytes
+ @param[out] FindExtensionData output matched extension data.
+ @param[out] FindExtensionDataLen matched extension data size.
+
+ **/
+STATIC
+RETURN_STATUS
+InternalX509FindExtensionData (
+ UINT8 *Start,
+ UINT8 *End,
+ CONST UINT8 *Oid,
+ UINTN OidSize,
+ UINT8 **FindExtensionData,
+ UINTN *FindExtensionDataLen
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ExtensionPtr;
+ size_t ObjLen;
+ INT32 Ret;
+ RETURN_STATUS ReturnStatus;
+ size_t FindExtensionLen;
+ size_t HeaderLen;
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+ Ptr = Start;
+
+ Ret = 0;
+
+ while (TRUE) {
+ /*
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ */
+ ExtensionPtr = Ptr;
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret == 0) {
+ HeaderLen = (size_t)(Ptr - ExtensionPtr);
+ FindExtensionLen = ObjLen;
+ // Get Object Identifier
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID);
+ } else {
+ break;
+ }
+
+ if ((Ret == 0) && (CompareMem (Ptr, Oid, OidSize) == 0)) {
+ Ptr += ObjLen;
+
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_BOOLEAN);
+ if (Ret == 0) {
+ Ptr += ObjLen;
+ }
+
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OCTET_STRING);
+ } else {
+ Ret = 1;
+ }
+
+ if (Ret == 0) {
+ *FindExtensionData = Ptr;
+ *FindExtensionDataLen = ObjLen;
+ ReturnStatus = RETURN_SUCCESS;
+ break;
+ }
+
+ // move to next
+ Ptr = ExtensionPtr + HeaderLen + FindExtensionLen;
+ Ret = 0;
+ }
+
+ return ReturnStatus;
+}
+
+/**
+ Retrieve Extension data 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[in] Oid Object identifier buffer
+ @param[in] OidSize Object identifier buffer size
+ @param[out] ExtensionData Extension bytes.
+ @param[in, out] ExtensionDataSize Extension bytes size.
+
+ @retval TRUE The certificate Extension data retrieved successfully.
+ @retval FALSE If Cert is NULL.
+ If ExtensionDataSize is NULL.
+ If ExtensionData is not NULL and *ExtensionDataSize is 0.
+ If Certificate is invalid.
+ @retval FALSE If no Extension entry match Oid.
+ @retval FALSE If the ExtensionData is NULL. The required buffer size
+ is returned in the ExtensionDataSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetExtensionData (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CONST UINT8 *Oid,
+ IN UINTN OidSize,
+ OUT UINT8 *ExtensionData,
+ IN OUT UINTN *ExtensionDataSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ RETURN_STATUS ReturnStatus;
+ BOOLEAN Status;
+ UINT8 *Ptr;
+ UINT8 *End;
+ size_t ObjLen;
+
+ if ((Cert == NULL) ||
+ (CertSize == 0) ||
+ (Oid == NULL) ||
+ (OidSize == 0) ||
+ (ExtensionDataSize == NULL))
+ {
+ return FALSE;
+ }
+
+ ReturnStatus = RETURN_INVALID_PARAMETER;
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ Ptr = Crt.v3_ext.p;
+ End = Crt.v3_ext.p + Crt.v3_ext.len;
+ Ret = mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ }
+
+ if (Ret == 0) {
+ ReturnStatus = InternalX509FindExtensionData (Ptr, End, Oid, OidSize, &Ptr, &ObjLen);
+ }
+
+ if (ReturnStatus == RETURN_SUCCESS) {
+ if (*ExtensionDataSize < ObjLen) {
+ *ExtensionDataSize = ObjLen;
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ if (Oid != NULL) {
+ CopyMem (ExtensionData, Ptr, ObjLen);
+ }
+
+ *ExtensionDataSize = ObjLen;
+ Status = TRUE;
+ }
+
+Cleanup:
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the Validity from one X.509 certificate
+
+ If Cert is NULL, then return FALSE.
+ If CertIssuerSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] Cert Pointer to the DER-encoded X509 certificate.
+ @param[in] CertSize Size of the X509 certificate in bytes.
+ @param[in] From notBefore Pointer to DateTime object.
+ @param[in,out] FromSize notBefore DateTime object size.
+ @param[in] To notAfter Pointer to DateTime object.
+ @param[in,out] ToSize notAfter DateTime object size.
+
+ Note: X509CompareDateTime to compare DateTime oject
+ x509SetDateTime to get a DateTime object from a DateTimeStr
+
+ @retval TRUE The certificate Validity retrieved successfully.
+ @retval FALSE Invalid certificate, or Validity retrieve failed.
+ @retval FALSE This interface is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetValidity (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN UINT8 *From,
+ IN OUT UINTN *FromSize,
+ IN UINT8 *To,
+ IN OUT UINTN *ToSize
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+ UINTN TSize;
+ UINTN FSize;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ FSize = sizeof (mbedtls_x509_time);
+ if (*FromSize < FSize) {
+ *FromSize = FSize;
+ goto _Exit;
+ }
+
+ *FromSize = FSize;
+ if (From != NULL) {
+ CopyMem (From, &(Crt.valid_from), FSize);
+ }
+
+ TSize = sizeof (mbedtls_x509_time);
+ if (*ToSize < TSize) {
+ *ToSize = TSize;
+ goto _Exit;
+ }
+
+ *ToSize = TSize;
+ if (To != NULL) {
+ CopyMem (To, &(Crt.valid_to), sizeof (mbedtls_x509_time));
+ }
+
+ Status = TRUE;
+ }
+
+_Exit:
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the Key Usage 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] Usage Key Usage (CRYPTO_X509_KU_*)
+
+ @retval TRUE The certificate Key Usage retrieved successfully.
+ @retval FALSE Invalid certificate, or Usage is NULL
+ @retval FALSE This interface is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetKeyUsage (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINTN *Usage
+ )
+{
+ mbedtls_x509_crt Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+
+ if (Cert == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ mbedtls_x509_crt_init (&Crt);
+
+ Ret = mbedtls_x509_crt_parse_der (&Crt, Cert, CertSize);
+
+ if (Ret == 0) {
+ *Usage = Crt.key_usage;
+ Status = TRUE;
+ }
+
+ mbedtls_x509_crt_free (&Crt);
+
+ return Status;
+}
+
+/**
+ Retrieve the Extended Key Usage 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] Usage Key Usage bytes.
+ @param[in, out] UsageSize Key Usage buffer sizs in bytes.
+
+ @retval TRUE The Usage bytes retrieve successfully.
+ @retval FALSE If Cert is NULL.
+ If CertSize is NULL.
+ If Usage is not NULL and *UsageSize is 0.
+ If Cert is invalid.
+ @retval FALSE If the Usage is NULL. The required buffer size
+ is returned in the UsageSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509GetExtendedKeyUsage (
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ OUT UINT8 *Usage,
+ IN OUT UINTN *UsageSize
+ )
+{
+ BOOLEAN ReturnStatus;
+
+ if ((Cert == NULL) || (CertSize == 0) || (UsageSize == NULL)) {
+ return FALSE;
+ }
+
+ ReturnStatus = X509GetExtensionData ((UINT8 *)Cert, CertSize, (UINT8 *)OID_extKeyUsage, sizeof (OID_extKeyUsage), Usage, UsageSize);
+
+ return ReturnStatus;
+}
+
+/**
+ Compare DateTime1 object and DateTime2 object time.
+
+ @param[in] Before Pointer to a DateTime Ojbect
+ @param[in] After Pointer to a DateTime Object
+
+ @retval 0 If DateTime1 <= DateTime2
+ @retval 1 If DateTime1 > DateTime2
+**/
+STATIC
+INTN
+InternalX509CheckTime (
+ CONST mbedtls_x509_time *Before,
+ CONST mbedtls_x509_time *After
+ )
+{
+ if (Before->year > After->year) {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon > After->mon))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day > After->day))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day == After->day) &&
+ (Before->hour > After->hour))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day == After->day) &&
+ (Before->hour == After->hour) &&
+ (Before->min > After->min))
+ {
+ return (1);
+ }
+
+ if ((Before->year == After->year) &&
+ (Before->mon == After->mon) &&
+ (Before->day == After->day) &&
+ (Before->hour == After->hour) &&
+ (Before->min == After->min) &&
+ (Before->sec > After->sec))
+ {
+ return (1);
+ }
+
+ return (0);
+}
+
+/**
+ change string to int.
+
+ @param[in] PStart Pointer to a string Start
+ @param[in] PEnd Pointer to a string End
+
+ @return number
+**/
+STATIC
+INT32
+InternalAtoI (
+ CHAR8 *PStart,
+ CHAR8 *PEnd
+ )
+{
+ CHAR8 *Ptr;
+ INT32 Knum;
+
+ Knum = 0;
+ Ptr = PStart;
+
+ while (Ptr < PEnd) {
+ ///
+ /// k = k * 2^3 + k * 2^1 = k * 8 + k * 2 = k * 10
+ ///
+ Knum = (Knum << 3) + (Knum << 1) + (*Ptr) - '0';
+ Ptr++;
+ }
+
+ return Knum;
+}
+
+/**
+ Format a DateTime object into DataTime Buffer
+
+ If DateTimeStr is NULL, then return FALSE.
+ If DateTimeSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ
+ Ref: https://www.w3.org/TR/NOTE-datetime
+ Z stand for UTC time
+ @param[in,out] DateTime Pointer to a DateTime object.
+ @param[in,out] DateTimeSize DateTime object buffer size.
+
+ @retval RETURN_SUCCESS The DateTime object create successfully.
+ @retval RETURN_INVALID_PARAMETER If DateTimeStr is NULL.
+ If DateTimeSize is NULL.
+ If DateTime is not NULL and *DateTimeSize is 0.
+ If Year Month Day Hour Minute Second combination is invalid datetime.
+ @retval RETURN_BUFFER_TOO_SMALL If the DateTime is NULL. The required buffer size
+ (including the final null) is returned in the
+ DateTimeSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+**/
+RETURN_STATUS
+EFIAPI
+X509SetDateTime (
+ CHAR8 *DateTimeStr,
+ IN OUT VOID *DateTime,
+ IN OUT UINTN *DateTimeSize
+ )
+{
+ mbedtls_x509_time Dt;
+
+ INT32 Year;
+ INT32 Month;
+ INT32 Day;
+ INT32 Hour;
+ INT32 Minute;
+ INT32 Second;
+ RETURN_STATUS ReturnStatus;
+ CHAR8 *Ptr;
+
+ Ptr = DateTimeStr;
+
+ Year = InternalAtoI (Ptr, Ptr + 4);
+ Ptr += 4;
+ Month = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Day = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Hour = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Minute = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Second = InternalAtoI (Ptr, Ptr + 2);
+ Ptr += 2;
+ Dt.year = (int)Year;
+ Dt.mon = (int)Month;
+ Dt.day = (int)Day;
+ Dt.hour = (int)Hour;
+ Dt.min = (int)Minute;
+ Dt.sec = (int)Second;
+
+ if (*DateTimeSize < sizeof (mbedtls_x509_time)) {
+ *DateTimeSize = sizeof (mbedtls_x509_time);
+ ReturnStatus = RETURN_BUFFER_TOO_SMALL;
+ goto Cleanup;
+ }
+
+ if (DateTime != NULL) {
+ CopyMem (DateTime, &Dt, sizeof (mbedtls_x509_time));
+ }
+
+ *DateTimeSize = sizeof (mbedtls_x509_time);
+ ReturnStatus = RETURN_SUCCESS;
+Cleanup:
+ return ReturnStatus;
+}
+
+/**
+ Compare DateTime1 object and DateTime2 object.
+
+ If DateTime1 is NULL, then return -2.
+ If DateTime2 is NULL, then return -2.
+ If DateTime1 == DateTime2, then return 0
+ If DateTime1 > DateTime2, then return 1
+ If DateTime1 < DateTime2, then return -1
+
+ @param[in] DateTime1 Pointer to a DateTime Ojbect
+ @param[in] DateTime2 Pointer to a DateTime Object
+
+ @retval 0 If DateTime1 == DateTime2
+ @retval 1 If DateTime1 > DateTime2
+ @retval -1 If DateTime1 < DateTime2
+**/
+INT32
+EFIAPI
+X509CompareDateTime (
+ IN CONST VOID *DateTime1,
+ IN CONST VOID *DateTime2
+ )
+{
+ if ((DateTime1 == NULL) || (DateTime2 == NULL)) {
+ return -2;
+ }
+
+ if (CompareMem (DateTime2, DateTime1, sizeof (mbedtls_x509_time)) == 0) {
+ return 0;
+ }
+
+ if (InternalX509CheckTime ((mbedtls_x509_time *)DateTime1, (mbedtls_x509_time *)DateTime2) == 0) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+/**
+ Retrieve the basic constraints 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] BasicConstraints basic constraints bytes.
+ @param[in, out] BasicConstraintsSize basic constraints buffer sizs in bytes.
+
+ @retval TRUE The basic constraints retrieve successfully.
+ @retval FALSE If cert is NULL.
+ If cert_size is NULL.
+ If basic_constraints is not NULL and *basic_constraints_size is 0.
+ If cert is invalid.
+ @retval FALSE The required buffer size is small.
+ The return buffer size is basic_constraints_size parameter.
+ @retval FALSE If no Extension entry match oid.
+ @retval FALSE The operation is not supported.
+ **/
+BOOLEAN
+EFIAPI
+X509GetExtendedBasicConstraints (
+ CONST UINT8 *Cert,
+ UINTN CertSize,
+ UINT8 *BasicConstraints,
+ UINTN *BasicConstraintsSize
+ )
+{
+ BOOLEAN Status;
+
+ if ((Cert == NULL) || (CertSize == 0) || (BasicConstraintsSize == NULL)) {
+ return FALSE;
+ }
+
+ Status = X509GetExtensionData (
+ (UINT8 *)Cert,
+ CertSize,
+ OID_BasicConstraints,
+ sizeof (OID_BasicConstraints),
+ BasicConstraints,
+ BasicConstraintsSize
+ );
+
+ return Status;
+}
+
+/**
+ Format a DateTimeStr to DataTime object in DataTime Buffer
+
+ If DateTimeStr is NULL, then return FALSE.
+ If DateTimeSize is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in] DateTimeStr DateTime string like YYYYMMDDhhmmssZ
+ Ref: https://www.w3.org/TR/NOTE-datetime
+ Z stand for UTC time
+ @param[out] DateTime Pointer to a DateTime object.
+ @param[in,out] DateTimeSize DateTime object buffer size.
+
+ @retval TRUE The DateTime object create successfully.
+ @retval FALSE If DateTimeStr is NULL.
+ If DateTimeSize is NULL.
+ If DateTime is not NULL and *DateTimeSize is 0.
+ If Year Month Day Hour Minute Second combination is invalid datetime.
+ @retval FALSE If the DateTime is NULL. The required buffer size
+ (including the final null) is returned in the
+ DateTimeSize parameter.
+ @retval FALSE The operation is not supported.
+**/
+BOOLEAN
+EFIAPI
+X509FormatDateTime (
+ IN CONST CHAR8 *DateTimeStr,
+ OUT VOID *DateTime,
+ IN OUT UINTN *DateTimeSize
+ )
+{
+ mbedtls_x509_time *Tm;
+
+ if (*DateTimeSize < sizeof (mbedtls_x509_time)) {
+ return FALSE;
+ }
+
+ if (DateTime == NULL) {
+ return FALSE;
+ }
+
+ Tm = (mbedtls_x509_time *)DateTime;
+
+ Tm->year = (DateTimeStr[0] + '0') * 1000 + (DateTimeStr[1] + '0') * 100 +
+ (DateTimeStr[2] + '0') * 10 + (DateTimeStr[3] + '0') * 1;
+
+ Tm->mon = (DateTimeStr[4] + '0') * 10 + (DateTimeStr[5] + '0') * 1;
+
+ Tm->day = (DateTimeStr[6] + '0') * 10 + (DateTimeStr[7] + '0') * 1;
+
+ Tm->hour = (DateTimeStr[8] + '0') * 10 + (DateTimeStr[9] + '0') * 1;
+
+ Tm->min = (DateTimeStr[10] + '0') * 10 + (DateTimeStr[11] + '0') * 1;
+
+ Tm->sec = (DateTimeStr[12] + '0') * 10 + (DateTimeStr[13] + '0') * 1;
+
+ return TRUE;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118114): https://edk2.groups.io/g/devel/message/118114
Mute This Topic: https://groups.io/mt/105683588/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
` (3 preceding siblings ...)
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 4/9] CryptoPkg: Add X509 functions " Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 6/9] CryptoPkg: Add Pkcs5 " Wenxing Hou
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
Because the current Mbedlts pkcs7 library doesn't support
authenticatedAttributes:
Mbed-TLS/mbedtls@bb82ab7
and only support 0 or 1 certificates in Signed data:
tianocore/edk2-staging@9c5b26b
The patch implement Pkcs7 by low Mbedtls Api.
And the implementation has pass unit_tes and integration test.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../BaseCryptLibMbedTls/InternalCryptLib.h | 33 +
.../Pk/CryptPkcs7Internal.h | 29 +-
.../BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c | 615 ++++++++
.../Pk/CryptPkcs7VerifyBase.c | 113 ++
.../Pk/CryptPkcs7VerifyCommon.c | 1363 +++++++++++++++++
.../Pk/CryptPkcs7VerifyEku.c | 689 +++++++++
6 files changed, 2830 insertions(+), 12 deletions(-)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h b/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h
index 8c463457d5..edeba84e59 100644
--- a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h
@@ -38,4 +38,37 @@ MbedtlsRand (
UINT8 *Output,
UINTN Len
);
+
+/**
+ 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/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h
index 207f493cbb..cbdd1dc530 100644
--- a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h
@@ -4,7 +4,7 @@
RFC 2315 - PKCS #7: Cryptographic Message Syntax Version 1.5
-Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2023-2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -31,10 +31,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x05"
#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x06"
-typedef mbedtls_asn1_buf MBEDTLSPKCS7BUF;
-typedef mbedtls_asn1_named_data MBEDTLSPKCS7NAME;
-typedef mbedtls_asn1_sequence MBEDTLSPKCS7SEQUENCE;
-
///
/// PKCS7 SignerInfo type
/// https://tools.ietf.org/html/rfc2315#section-9.2
@@ -48,8 +44,8 @@ typedef struct MbedtlsPkcs7SignerInfo {
mbedtls_x509_buf SigAlgIdentifier;
mbedtls_x509_buf AuthAttr;
mbedtls_x509_buf Sig;
- struct MBEDTLSPKCS7SIGNERINFO *Next;
-} MBEDTLSPKCS7SIGNERINFO;
+ struct MbedtlsPkcs7SignerInfo *Next;
+} MbedtlsPkcs7SignerInfo;
///
/// PKCS7 signed data attached data format
@@ -57,7 +53,7 @@ typedef struct MbedtlsPkcs7SignerInfo {
typedef struct MbedtlsPkcs7Data {
mbedtls_asn1_buf Oid;
mbedtls_asn1_buf Data;
-} MBEDTLSPKCS7DATA;
+} MbedtlsPkcs7Data;
///
/// Signed Data
@@ -66,18 +62,27 @@ typedef struct MbedtlsPkcs7Data {
typedef struct MbedtlsPkcs7SignedData {
INT32 Version;
mbedtls_asn1_buf DigestAlgorithms;
- struct MBEDTLSPKCS7DATA ContentInfo;
+ struct MbedtlsPkcs7Data ContentInfo;
mbedtls_x509_crt Certificates;
mbedtls_x509_crl Crls;
struct MbedtlsPkcs7SignerInfo SignerInfos;
-} MBEDTLSPKCS7SIGNEDDATA;
+} MbedtlsPkcs7SignedData;
///
/// PKCS7 struct, only support SignedData
///
typedef struct MbedtlsPkcs7 {
mbedtls_asn1_buf ContentTypeOid;
- struct MBEDTLSPKCS7SIGNEDDATA SignedData;
-} MBEDTLSPKCS7;
+ struct MbedtlsPkcs7SignedData SignedData;
+} MbedtlsPkcs7;
+
+#define EDKII_ASN1_CHK_ADD(g, f) \
+ do \
+ { \
+ if( ( Ret = (f) ) < 0 ) \
+ return( Ret ); \
+ else \
+ (g) += Ret; \
+ } while( 0 )
#endif
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c
new file mode 100644
index 0000000000..a46f63a551
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c
@@ -0,0 +1,615 @@
+/** @file
+ PKCS#7 SignedData Sign Wrapper and PKCS#7 SignedData Verification Wrapper
+ Implementation over mbedtls.
+
+ RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites
+ FIPS 186-4 - Digital Signature Standard (DSS)
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CryptPkcs7Internal.h"
+#include <mbedtls/ecdh.h>
+
+///
+/// Enough to store any signature generated by PKCS7
+///
+#define MAX_SIGNATURE_SIZE 1024
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 MbedtlsOidDigestAlgSha256[] = MBEDTLS_OID_DIGEST_ALG_SHA256;
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 MbedtlsOidPkcs1Rsa[] = MBEDTLS_OID_PKCS1_RSA;
+
+/**
+ Write DigestAlgorithmIdentifier.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] DigestType Digest Type
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteDigestAlgorithm (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ mbedtls_md_type_t DigestType
+ )
+{
+ UINT8 *OidPtr;
+ UINTN OidLen;
+ INT32 Ret;
+
+ Ret = mbedtls_oid_get_oid_by_md (DigestType, (CONST CHAR8 **)&OidPtr, &OidLen);
+ if (Ret == 0) {
+ return mbedtls_asn1_write_oid (Ptr, (CONST UINT8 *)Start, (CONST CHAR8 *)OidPtr, OidLen);
+ }
+
+ return 0;
+}
+
+/**
+ DigestAlgorithmIdentifiers ::=
+ SET OF DigestAlgorithmIdentifier.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] DigestTypes Digest Type array.
+ @param[in] Count The index for Digest Type.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteDigestAlgorithmSet (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ mbedtls_md_type_t *DigestTypes,
+ INTN Count
+ )
+{
+ INTN Idx;
+ INT32 Len;
+ INT32 Ret;
+
+ Len = 0;
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_null (Ptr, Start));
+
+ for (Idx = 0; Idx < Count; Idx++) {
+ EDKII_ASN1_CHK_ADD (
+ Len,
+ MbedTlsPkcs7WriteDigestAlgorithm (Ptr, Start, DigestTypes[Idx])
+ );
+ }
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, (UINTN)Len));
+
+ EDKII_ASN1_CHK_ADD (
+ Len,
+ mbedtls_asn1_write_tag (
+ Ptr,
+ Start,
+ (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
+ )
+ );
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, (UINTN)Len));
+
+ EDKII_ASN1_CHK_ADD (
+ Len,
+ mbedtls_asn1_write_tag (
+ Ptr,
+ Start,
+ (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)
+ )
+ );
+
+ return Len;
+}
+
+/**
+ ContentInfo ::= SEQUENCE {
+ contentType ContentType,
+ content
+ [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] Content ContentInfo.
+ @param[in] ContentLen Size of ContentInfo.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteContentInfo (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ UINT8 *Content,
+ INTN ContentLen
+ )
+{
+ INT32 Ret;
+ INT32 Len;
+
+ Len = 0;
+ if (Content != NULL) {
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (Ptr, Start, Content, ContentLen));
+ }
+
+ EDKII_ASN1_CHK_ADD (
+ Len,
+ mbedtls_asn1_write_oid (
+ Ptr,
+ Start,
+ MBEDTLS_OID_PKCS7_DATA,
+ sizeof (MBEDTLS_OID_PKCS7_DATA) - 1
+ )
+ );
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
+
+ return Len;
+}
+
+/**
+ certificates :: SET OF ExtendedCertificateOrCertificate,
+ ExtendedCertificateOrCertificate ::= CHOICE {
+ certificate Certificate -- x509,
+ extendedCertificate[0] IMPLICIT ExtendedCertificate }.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] Cert Certificate.
+ @param[in] OtherCerts Ohter Certificate.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteCertificates (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ mbedtls_x509_crt *Cert,
+ mbedtls_x509_crt *OtherCerts
+ )
+{
+ INT32 Ret;
+ INT32 Len;
+ mbedtls_x509_crt *TmpCert;
+
+ Len = 0;
+
+ /// Write OtherCerts
+ TmpCert = OtherCerts;
+ while (TmpCert != NULL) {
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (Ptr, Start, TmpCert->raw.p, TmpCert->raw.len));
+ TmpCert = TmpCert->next;
+ }
+
+ /// Write Cert
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (Ptr, Start, Cert->raw.p, Cert->raw.len));
+
+ /// Write NextContext
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));
+ return Len;
+}
+
+/**
+ write Pkcs7 Int.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] SerialRaw SerialRaw.
+ @param[in] SerialRawLen Size of SerialRaw.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteInt (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ UINT8 *SerialRaw,
+ INTN SerialRawLen
+ )
+{
+ INT32 Ret;
+ UINT8 *Pt;
+ INT32 Len;
+
+ Len = 0;
+ Pt = SerialRaw + SerialRawLen;
+ while (Pt > SerialRaw) {
+ *--(*Ptr) = *--Pt;
+ Len++;
+ }
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_INTEGER));
+
+ return Len;
+}
+
+/**
+ write Pkcs7 Issuer And SerialNumber.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] Serial Serial.
+ @param[in] SerialLen Size of Serial.
+ @param[in] IssuerRaw IssuerRawLen.
+ @param[in] IssuerRawLen Size of IssuerRawLen.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteIssuerAndSerialNumber (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ UINT8 *Serial,
+ INTN SerialLen,
+ UINT8 *IssuerRaw,
+ INTN IssuerRawLen
+ )
+{
+ INT32 Ret;
+ INT32 Len;
+
+ Len = 0;
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteInt (Ptr, Start, Serial, SerialLen));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (Ptr, Start, IssuerRaw, IssuerRawLen));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
+
+ return Len;
+}
+
+/**
+ SignerInfo ::= SEQUENCE {
+ version Version;
+ issuerAndSerialNumber IssuerAndSerialNumber,
+ digestAlgorithm DigestAlgorithmIdentifier,
+ authenticatedAttributes
+ [0] IMPLICIT Attributes OPTIONAL,
+ digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ encryptedDigest EncryptedDigest,
+ unauthenticatedAttributes
+ [1] IMPLICIT Attributes OPTIONAL.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] SignerInfo SignerInfo.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteSignerInfo (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ MbedtlsPkcs7SignerInfo *SignerInfo
+ )
+{
+ INT32 Ret;
+ INT32 Len;
+
+ Len = 0;
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (Ptr, Start, SignerInfo->Sig.p, SignerInfo->Sig.len));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (Ptr, Start, (CONST CHAR8 *)SignerInfo->SigAlgIdentifier.p, SignerInfo->SigAlgIdentifier.len, 0));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (Ptr, Start, (CONST CHAR8 *)SignerInfo->AlgIdentifier.p, SignerInfo->AlgIdentifier.len, 0));
+
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteIssuerAndSerialNumber (Ptr, Start, SignerInfo->Serial.p, SignerInfo->Serial.len, SignerInfo->IssuerRaw.p, SignerInfo->IssuerRaw.len));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (Ptr, Start, SignerInfo->Version));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
+
+ return Len;
+}
+
+/**
+ write Pkcs7 Signers Info Set.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] SignersSet SignerInfo Set.
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteSignersInfoSet (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ MbedtlsPkcs7SignerInfo *SignersSet
+ )
+{
+ MbedtlsPkcs7SignerInfo *SignerInfo;
+ INT32 Ret;
+ INT32 Len;
+
+ SignerInfo = SignersSet;
+ Len = 0;
+
+ while (SignerInfo != NULL) {
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignerInfo (Ptr, Start, SignerInfo));
+ // move to next
+ SignerInfo = SignerInfo->Next;
+ }
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET));
+
+ return Len;
+}
+
+/**
+ Signed Data Type
+ SignedData ::= SEQUENCE {
+ version Version,
+ digestAlgorithms DigestAlgorithmIdentifiers,
+ contentInfo ContentInfo,
+ certificates
+ [0] IMPLICIT ExtendedCertificatesAndCertificates
+ OPTIONAL,
+ crls
+ [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ signerInfos SignerInfos }
+
+ DigestAlgorithmIdentifiers ::=
+ SET OF DigestAlgorithmIdentifier
+
+ SignerInfos ::= SET OF SignerInfo.
+
+ @param[in, out] Ptr The reference to the current position pointer.
+ @param[in] Start The start of the buffer, for bounds-checking.
+ @param[in] Pkcs7 MbedtlsPkcs7
+
+ @retval number The number of bytes written to p on success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7WriteDer (
+ UINT8 **Ptr,
+ UINT8 *Start,
+ MbedtlsPkcs7 *Pkcs7
+ )
+{
+ INT32 Ret;
+ INT32 Len;
+ mbedtls_md_type_t DigestAlg[1];
+
+ DigestAlg[0] = MBEDTLS_MD_SHA256;
+ Len = 0;
+
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignersInfoSet (Ptr, Start, &(Pkcs7->SignedData.SignerInfos)));
+
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteCertificates (Ptr, Start, &(Pkcs7->SignedData.Certificates), Pkcs7->SignedData.Certificates.next));
+
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteContentInfo (Ptr, Start, NULL, 0));
+
+ EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteDigestAlgorithmSet (Ptr, Start, DigestAlg, 1));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (Ptr, Start, Pkcs7->SignedData.Version));
+
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
+ EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
+
+ return Len;
+}
+
+/**
+ 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.
+
+ If this interface is not supported, then return FALSE.
+
+ @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.
+ @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
+ )
+{
+ BOOLEAN Status;
+ INT32 Ret;
+ mbedtls_pk_context Pkey;
+ UINT8 HashValue[SHA256_DIGEST_SIZE];
+ UINT8 Signature[MAX_SIGNATURE_SIZE];
+ UINTN SignatureLen;
+ UINT8 *NewPrivateKey;
+ mbedtls_x509_crt *Crt;
+
+ MbedtlsPkcs7 Pkcs7;
+ MbedtlsPkcs7SignerInfo SignerInfo;
+ UINT8 *Buffer;
+ INTN BufferSize;
+ UINT8 *Ptr;
+ INT32 Len;
+
+ BufferSize = 4096;
+
+ SignatureLen = MAX_SIGNATURE_SIZE;
+ Crt = (mbedtls_x509_crt *)SignCert;
+
+ NewPrivateKey = NULL;
+ if (PrivateKey[PrivateKeySize - 1] != 0) {
+ NewPrivateKey = AllocateZeroPool (PrivateKeySize + 1);
+ if (NewPrivateKey == NULL) {
+ return FALSE;
+ }
+
+ CopyMem (NewPrivateKey, PrivateKey, PrivateKeySize);
+ NewPrivateKey[PrivateKeySize] = 0;
+ PrivateKeySize++;
+ } else {
+ NewPrivateKey = AllocateZeroPool (PrivateKeySize);
+ if (NewPrivateKey == NULL) {
+ return FALSE;
+ }
+
+ CopyMem (NewPrivateKey, PrivateKey, PrivateKeySize);
+ }
+
+ mbedtls_pk_init (&Pkey);
+ Ret = mbedtls_pk_parse_key (
+ &Pkey,
+ NewPrivateKey,
+ PrivateKeySize,
+ KeyPassword,
+ KeyPassword == NULL ? 0 : AsciiStrLen ((CONST CHAR8 *)KeyPassword),
+ NULL,
+ NULL
+ );
+ if (Ret != 0) {
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ /// Calculate InData Digest
+ ZeroMem (HashValue, SHA256_DIGEST_SIZE);
+ Status = Sha256HashAll (InData, InDataSize, HashValue);
+ if (!Status) {
+ goto Cleanup;
+ }
+
+ /// Pk Sign
+ ZeroMem (Signature, MAX_SIGNATURE_SIZE);
+ Ret = mbedtls_pk_sign (
+ &Pkey,
+ MBEDTLS_MD_SHA256,
+ HashValue,
+ SHA256_DIGEST_SIZE,
+ Signature,
+ MAX_SIGNATURE_SIZE,
+ &SignatureLen,
+ MbedtlsRand,
+ NULL
+ );
+ if (Ret != 0) {
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ ZeroMem (&Pkcs7, sizeof (MbedtlsPkcs7));
+ Pkcs7.SignedData.Version = 1;
+
+ Crt->next = (mbedtls_x509_crt *)OtherCerts;
+ Pkcs7.SignedData.Certificates = *Crt;
+
+ SignerInfo.Next = NULL;
+ SignerInfo.Sig.p = Signature;
+ SignerInfo.Sig.len = SignatureLen;
+ SignerInfo.Version = 1;
+ SignerInfo.AlgIdentifier.p = MbedtlsOidDigestAlgSha256;
+ SignerInfo.AlgIdentifier.len = sizeof (MBEDTLS_OID_DIGEST_ALG_SHA256) - 1;
+ if (mbedtls_pk_get_type (&Pkey) == MBEDTLS_PK_RSA) {
+ SignerInfo.SigAlgIdentifier.p = MbedtlsOidPkcs1Rsa;
+ SignerInfo.SigAlgIdentifier.len = sizeof (MBEDTLS_OID_PKCS1_RSA) - 1;
+ } else {
+ mbedtls_oid_get_oid_by_sig_alg (MBEDTLS_PK_ECDSA, MBEDTLS_MD_SHA256, (CONST CHAR8 **)&SignerInfo.SigAlgIdentifier.p, &SignerInfo.SigAlgIdentifier.len);
+ }
+
+ SignerInfo.Serial = ((mbedtls_x509_crt *)SignCert)->serial;
+ SignerInfo.IssuerRaw = ((mbedtls_x509_crt *)SignCert)->issuer_raw;
+ Pkcs7.SignedData.SignerInfos = SignerInfo;
+
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ Ptr = Buffer + BufferSize;
+ Len = MbedTlsPkcs7WriteDer (&Ptr, Buffer, &Pkcs7);
+
+ /// Enlarge buffer if buffer is too small
+ while (Len < 0 && Len == MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) {
+ BufferSize = BufferSize * 2;
+ Ptr = Buffer + BufferSize;
+ FreePool (Buffer);
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ Ptr = Buffer + BufferSize;
+ Len = MbedTlsPkcs7WriteDer (&Ptr, Buffer, &Pkcs7);
+ }
+
+ if (Len <= 0) {
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ *SignedData = AllocateZeroPool (Len);
+ *SignedDataSize = Len;
+ CopyMem (*SignedData, Ptr, Len);
+ Status = TRUE;
+
+Cleanup:
+ if (&Pkey != NULL) {
+ mbedtls_pk_free (&Pkey);
+ }
+
+ if (NewPrivateKey != NULL) {
+ FreePool (NewPrivateKey);
+ }
+
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ return Status;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c
new file mode 100644
index 0000000000..6b62ee2618
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c
@@ -0,0 +1,113 @@
+/** @file
+ Non-runtime specific implementation of PKCS#7 SignedData Verification Wrapper.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/pkcs7.h>
+
+/**
+ 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;
+ UINT8 *SignedData;
+ UINTN SignedDataSize;
+ BOOLEAN Wrapped;
+ INTN Ret;
+ mbedtls_pkcs7 Pkcs7;
+ mbedtls_pkcs7_data *MbedtlsContent;
+
+ mbedtls_pkcs7_init (&Pkcs7);
+
+ //
+ // Check input parameter.
+ //
+ if ((P7Data == NULL) || (P7Length > INT_MAX) || (Content == NULL) || (ContentSize == NULL)) {
+ return FALSE;
+ }
+
+ *Content = NULL;
+ SignedData = NULL;
+
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &SignedData, &SignedDataSize);
+ if (!Status || (SignedDataSize > INT_MAX)) {
+ goto _Exit;
+ }
+
+ Status = FALSE;
+
+ Ret = mbedtls_pkcs7_parse_der (&Pkcs7, SignedData, (INT32)SignedDataSize);
+
+ //
+ // The type of Pkcs7 must be signedData
+ //
+ if (Ret != MBEDTLS_PKCS7_SIGNED_DATA) {
+ goto _Exit;
+ }
+
+ //
+ // Check for detached or attached content
+ //
+ MbedtlsContent = &(Pkcs7.signed_data.content);
+
+ if (MbedtlsContent == NULL) {
+ //
+ // No Content supplied for PKCS7 detached signedData
+ //
+ *Content = NULL;
+ *ContentSize = 0;
+ } else {
+ //
+ // Retrieve the attached content in PKCS7 signedData
+ //
+ if ((MbedtlsContent->data.len > 0) && (MbedtlsContent->data.p != NULL)) {
+ *ContentSize = MbedtlsContent->data.len;
+ *Content = AllocateZeroPool (*ContentSize);
+ if (*Content == NULL) {
+ *ContentSize = 0;
+ goto _Exit;
+ }
+
+ CopyMem (*Content, MbedtlsContent->data.p, *ContentSize);
+ }
+ }
+
+ Status = TRUE;
+
+_Exit:
+ //
+ // Release Resources
+ //
+ mbedtls_pkcs7_free (&Pkcs7);
+
+ return Status;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c
new file mode 100644
index 0000000000..83dfe01b60
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c
@@ -0,0 +1,1363 @@
+/** @file
+ PKCS#7 SignedData Sign Wrapper and PKCS#7 SignedData Verification Wrapper
+ Implementation over mbedtls.
+
+ RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites
+ FIPS 186-4 - Digital Signature Standard (DSS)
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CryptPkcs7Internal.h"
+#include <mbedtls/pkcs7.h>
+
+/* Profile for backward compatibility. Allows RSA 1024, unlike the default
+ profile. */
+STATIC mbedtls_x509_crt_profile gCompatProfile =
+{
+ /* Hashes from SHA-256 and above. Note that this selection
+ * should be aligned with ssl_preset_default_hashes in ssl_tls.c. */
+
+ #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA1) |
+ #endif
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA256) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA384) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA512),
+ 0xFFFFFFF, /* Any PK alg */
+
+ /* Curves at or above 128-bit security level. Note that this selection
+ * should be aligned with ssl_preset_default_curves in ssl_tls.c. */
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP256R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP384R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP521R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP256R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP384R1) |
+ MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP512R1) |
+ 0,
+ 1024,
+};
+
+/**
+ Init MbedtlsPkcs7.
+
+ @param[in] Pkcs7 MbedtlsPkcs7.
+**/
+STATIC
+VOID
+MbedTlsPkcs7Init (
+ MbedtlsPkcs7 *Pkcs7
+ )
+{
+ ZeroMem (Pkcs7, sizeof (MbedtlsPkcs7));
+}
+
+/**
+ Get Pkcs7 Next Content Len.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] Len MbedtlsPkcs7 Content Len.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7GetNextContentLen (
+ UINT8 **Ptr,
+ UINT8 *End,
+ UINTN *Len
+ )
+{
+ INT32 Ret;
+
+ Ret = mbedtls_asn1_get_tag (Ptr, End, Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
+ return Ret;
+}
+
+/**
+ Get Pkcs7 Version..
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] Ver MbedtlsPkcs7 Version.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7GetVersion (
+ UINT8 **Ptr,
+ UINT8 *End,
+ INT32 *Ver
+ )
+{
+ INT32 Ret;
+
+ Ret = mbedtls_asn1_get_int (Ptr, End, Ver);
+ return Ret;
+}
+
+/**
+ ContentInfo ::= SEQUENCE {
+ contentType ContentType,
+ content
+ [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] Pkcs7 MbedtlsPkcs7.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+Pkcs7GetContentInfoType (
+ UINT8 **Ptr,
+ UINT8 *End,
+ mbedtls_asn1_buf *Pkcs7
+ )
+{
+ UINTN Len;
+ int Ret;
+
+ Len = 0;
+ Ret = mbedtls_asn1_get_tag (
+ Ptr,
+ End,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
+ );
+
+ if (Ret == 0) {
+ Ret = mbedtls_asn1_get_tag (Ptr, End, &Len, MBEDTLS_ASN1_OID);
+ }
+
+ if (Ret == 0) {
+ Pkcs7->tag = MBEDTLS_ASN1_OID;
+ Pkcs7->len = Len;
+ Pkcs7->p = *Ptr;
+ }
+
+ return Ret;
+}
+
+/**
+ DigestAlgorithmIdentifier ::= AlgorithmIdentifier.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] Alg MbedtlsPkcs7 AlgorithmIdentifier.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7GetDigestAlgorithm (
+ UINT8 **Ptr,
+ UINT8 *End,
+ mbedtls_x509_buf *Alg
+ )
+{
+ INT32 Ret;
+
+ Ret = mbedtls_asn1_get_alg_null (Ptr, End, Alg);
+ return Ret;
+}
+
+/**
+ DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] Alg MbedtlsPkcs7 AlgorithmIdentifier.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7GetDigestAlgorithmSet (
+ UINT8 **Ptr,
+ UINT8 *End,
+ mbedtls_x509_buf *Alg
+ )
+{
+ UINTN Len;
+ INT32 Ret;
+
+ Len = 0;
+ Ret = mbedtls_asn1_get_tag (
+ Ptr,
+ End,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET
+ );
+
+ if (Ret == 0) {
+ End = *Ptr + Len;
+ // assume only one digest algorithm
+ Ret = mbedtls_asn1_get_alg_null (Ptr, End, Alg);
+ }
+
+ return Ret;
+}
+
+/**
+ certificates :: SET OF ExtendedCertificateOrCertificate,
+ ExtendedCertificateOrCertificate ::= CHOICE {
+ certificate Certificate -- x509,
+ extendedCertificate[0] IMPLICIT ExtendedCertificate }.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] Plen The buffer len.
+ @param[out] Certs mbedtls_x509_crt cert.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7GetCertificates (
+ UINT8 **Ptr,
+ INTN Plen,
+ mbedtls_x509_crt *Certs
+ )
+{
+ INT32 Ret;
+
+ Ret = mbedtls_x509_crt_parse (Certs, *Ptr, Plen);
+ return Ret;
+}
+
+/**
+ EncryptedDigest ::= OCTET STRING.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] Signature Signature.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+Pkcs7GetSignature (
+ UINT8 **Ptr,
+ UINT8 *End,
+ mbedtls_asn1_buf *Signature
+ )
+{
+ INT32 Ret;
+ UINTN Len;
+
+ Len = 0;
+ Ret = mbedtls_asn1_get_tag (Ptr, End, &Len, MBEDTLS_ASN1_OCTET_STRING);
+ if (Ret == 0) {
+ Signature->tag = MBEDTLS_ASN1_OCTET_STRING;
+ Signature->len = Len;
+ Signature->p = *Ptr;
+ }
+
+ return Ret;
+}
+
+/**
+ SignerInfo ::= SEQUENCE {
+ version Version;
+ issuerAndSerialNumber IssuerAndSerialNumber,
+ digestAlgorithm DigestAlgorithmIdentifier,
+ authenticatedAttributes
+ [0] IMPLICIT Attributes OPTIONAL,
+ digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ encryptedDigest EncryptedDigest,
+ unauthenticatedAttributes
+ [1] IMPLICIT Attributes OPTIONAL.
+
+ @param[in] Ptr The start of the buffer.
+ @param[in] End The end of the buffer.
+ @param[out] SignersSet MbedtlsPkcs7SignerInfo.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedTlsPkcs7GetSignersInfoSet (
+ UINT8 **Ptr,
+ UINT8 *End,
+ MbedtlsPkcs7SignerInfo *SignersSet
+ )
+{
+ UINT8 *EndSet;
+ INT32 Ret;
+ UINTN Len;
+ UINT8 *TempP;
+
+ Len = 0;
+
+ Ret = mbedtls_asn1_get_tag (
+ Ptr,
+ End,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET
+ );
+
+ if (Ret == 0) {
+ EndSet = *Ptr + Len;
+
+ Ret = mbedtls_asn1_get_tag (
+ Ptr,
+ EndSet,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
+ );
+ }
+
+ if (Ret == 0) {
+ Ret = mbedtls_asn1_get_int (Ptr, EndSet, &SignersSet->Version);
+ }
+
+ if (Ret == 0) {
+ Ret = mbedtls_asn1_get_tag (
+ Ptr,
+ EndSet,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
+ );
+ }
+
+ if (Ret == 0) {
+ SignersSet->IssuerRaw.p = *Ptr;
+ Ret = mbedtls_asn1_get_tag (
+ Ptr,
+ EndSet,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
+ );
+ }
+
+ if (Ret == 0) {
+ Ret = mbedtls_x509_get_name (Ptr, *Ptr + Len, &SignersSet->Issuer);
+ }
+
+ if (Ret == 0) {
+ SignersSet->IssuerRaw.len = *Ptr - SignersSet->IssuerRaw.p;
+
+ Ret = mbedtls_x509_get_serial (Ptr, EndSet, &SignersSet->Serial);
+ }
+
+ if (Ret == 0) {
+ Ret = MbedTlsPkcs7GetDigestAlgorithm (Ptr, EndSet, &SignersSet->AlgIdentifier);
+ }
+
+ // OPTIONAL AuthenticatedAttributes
+ if (Ret == 0) {
+ TempP = *Ptr;
+ if (mbedtls_asn1_get_tag (&TempP, EndSet, &Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) {
+ SignersSet->AuthAttr.len = Len + (TempP - *Ptr);
+ SignersSet->AuthAttr.p = *Ptr;
+ *Ptr = TempP + Len;
+ } else {
+ SignersSet->AuthAttr.p = NULL;
+ }
+ }
+
+ if (Ret == 0) {
+ Ret = MbedTlsPkcs7GetDigestAlgorithm (Ptr, EndSet, &SignersSet->SigAlgIdentifier);
+ }
+
+ if (Ret == 0) {
+ Ret = Pkcs7GetSignature (Ptr, End, &SignersSet->Sig);
+ }
+
+ if (Ret == 0) {
+ SignersSet->Next = NULL;
+ }
+
+ return Ret;
+}
+
+/**
+ SignedData ::= SEQUENCE {
+ version Version,
+ digestAlgorithms DigestAlgorithmIdentifiers,
+ contentInfo ContentInfo,
+ certificates
+ [0] IMPLICIT ExtendedCertificatesAndCertificates
+ OPTIONAL,
+ crls
+ [0] IMPLICIT CertificateRevocationLists OPTIONAL,
+ signerInfos SignerInfos }.
+
+ @param[in] Buffer The start of the buffer.
+ @param[in] BufferLen The len the buffer.
+ @param[out] SignedData MbedtlsPkcs7SignedData.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+Pkcs7GetSignedData (
+ UINT8 *Buffer,
+ INTN BufferLen,
+ MbedtlsPkcs7SignedData *SignedData
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *End;
+ UINTN Len;
+ INT32 Ret;
+ UINT8 *CertP;
+ UINTN CertLen;
+ UINT8 *OldCertP;
+ UINTN TotalCertLen;
+ mbedtls_x509_crt *MoreCert;
+ UINT8 CertNum;
+ mbedtls_x509_crt *LastCert;
+ mbedtls_x509_crt *TempCrt;
+ mbedtls_x509_crt *NextCrt;
+
+ Len = 0;
+ Ptr = Buffer;
+ End = Buffer + BufferLen;
+ MoreCert = NULL;
+
+ Ret = mbedtls_asn1_get_tag (
+ &Ptr,
+ End,
+ &Len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
+ );
+
+ if (Ret == 0) {
+ // version
+ Ret = MbedTlsPkcs7GetVersion (&Ptr, End, &SignedData->Version);
+ }
+
+ if ((Ret == 0) && (SignedData->Version != 1)) {
+ Ret = -1;
+ }
+
+ if (Ret == 0) {
+ // digest algorithm
+ Ret = MbedTlsPkcs7GetDigestAlgorithmSet (
+ &Ptr,
+ End,
+ &SignedData->DigestAlgorithms
+ );
+ }
+
+ if (Ret == 0) {
+ if (
+ #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES
+ ((SignedData->DigestAlgorithms.len == sizeof (MBEDTLS_OID_DIGEST_ALG_SHA1) - 1) &&
+ (CompareMem (
+ SignedData->DigestAlgorithms.p,
+ MBEDTLS_OID_DIGEST_ALG_SHA1,
+ SignedData->DigestAlgorithms.len
+ ) == 0)) ||
+ #endif
+ ((SignedData->DigestAlgorithms.len == sizeof (MBEDTLS_OID_DIGEST_ALG_SHA256) - 1) &&
+ (CompareMem (
+ SignedData->DigestAlgorithms.p,
+ MBEDTLS_OID_DIGEST_ALG_SHA256,
+ SignedData->DigestAlgorithms.len
+ ) == 0)) ||
+ ((SignedData->DigestAlgorithms.len == sizeof (MBEDTLS_OID_DIGEST_ALG_SHA384) - 1) &&
+ (CompareMem (
+ SignedData->DigestAlgorithms.p,
+ MBEDTLS_OID_DIGEST_ALG_SHA384,
+ SignedData->DigestAlgorithms.len
+ ) == 0)) ||
+ ((SignedData->DigestAlgorithms.len == sizeof (MBEDTLS_OID_DIGEST_ALG_SHA512) - 1) &&
+ (CompareMem (
+ SignedData->DigestAlgorithms.p,
+ MBEDTLS_OID_DIGEST_ALG_SHA512,
+ SignedData->DigestAlgorithms.len
+ ) == 0)))
+ {
+ Ret = 0;
+ } else {
+ Ret = -1;
+ }
+ }
+
+ if (Ret == 0) {
+ Ret = Pkcs7GetContentInfoType (&Ptr, End, &SignedData->ContentInfo.Oid);
+ }
+
+ if (Ret == 0) {
+ // move to next
+ Ptr = Ptr + SignedData->ContentInfo.Oid.len;
+ Ret = MbedTlsPkcs7GetNextContentLen (&Ptr, End, &Len);
+ CertP = Ptr + Len;
+
+ // move to actual cert, if there are more [0]
+ if (MbedTlsPkcs7GetNextContentLen (&CertP, End, &CertLen) == 0) {
+ Len = CertLen;
+ Ptr = CertP;
+ }
+ }
+
+ // certificates: may have many certs
+ CertP = Ptr;
+
+ TotalCertLen = 0;
+
+ MoreCert = &SignedData->Certificates;
+ CertNum = 0;
+
+ while (TotalCertLen < Len) {
+ OldCertP = CertP;
+
+ Ret = mbedtls_asn1_get_tag (&CertP, End, &CertLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
+ if (Ret != 0) {
+ goto Out;
+ }
+
+ // cert total len
+ CertLen = CertLen + (CertP - OldCertP);
+
+ // move to next cert
+ CertP = OldCertP + CertLen;
+
+ // change TotalCertLen
+ TotalCertLen += CertLen;
+
+ mbedtls_x509_crt_init (MoreCert);
+ Ret = MbedTlsPkcs7GetCertificates (&OldCertP, CertLen, MoreCert);
+ if (Ret != 0) {
+ goto Out;
+ }
+
+ CertNum++;
+ MoreCert->next = AllocateZeroPool (sizeof (mbedtls_x509_crt));
+ MoreCert = MoreCert->next;
+ }
+
+ if (TotalCertLen != Len) {
+ Ret = -1;
+ goto Out;
+ }
+
+ LastCert = &(SignedData->Certificates);
+
+ while (CertNum--) {
+ if (CertNum == 0) {
+ LastCert->next = NULL;
+ break;
+ } else {
+ LastCert = LastCert->next;
+ }
+ }
+
+ // signers info
+ if (Ret == 0) {
+ Ptr = Ptr + Len;
+ Ret = MbedTlsPkcs7GetSignersInfoSet (&Ptr, End, &SignedData->SignerInfos);
+ }
+
+Out:
+ if (Ret == 0) {
+ if (MoreCert != NULL) {
+ FreePool (MoreCert);
+ MoreCert = NULL;
+ }
+ } else {
+ if (SignedData->Certificates.next != NULL) {
+ TempCrt = SignedData->Certificates.next;
+
+ while (TempCrt != NULL) {
+ NextCrt = TempCrt->next;
+ mbedtls_x509_crt_free (TempCrt);
+ FreePool (TempCrt);
+ TempCrt = NextCrt;
+ }
+ }
+ }
+
+ return Ret;
+}
+
+/**
+ Parse MbedtlsPkcs7 to Der format.
+ @param[in] Buffer The start of the buffer.
+ @param[in] BufferLen The len the buffer.
+ @param[out] Pkcs7 MbedtlsPkcs7.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedtlsPkcs7ParseDer (
+ CONST UINT8 *Buffer,
+ INTN BufferLen,
+ MbedtlsPkcs7 *Pkcs7
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *End;
+ UINTN Len;
+ INT32 Ret;
+
+ if (Pkcs7 == NULL) {
+ return -1;
+ }
+
+ Len = 0;
+ Ptr = (UINT8 *)Buffer;
+ End = Ptr + BufferLen;
+
+ Ret = Pkcs7GetContentInfoType (&Ptr, End, &Pkcs7->ContentTypeOid);
+ if (Ret != 0) {
+ goto Out;
+ }
+
+ if ((CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_DATA, Pkcs7->ContentTypeOid.len) == 0) ||
+ (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, Pkcs7->ContentTypeOid.len) == 0) ||
+ (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_ENVELOPED_DATA, Pkcs7->ContentTypeOid.len) == 0) ||
+ (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, Pkcs7->ContentTypeOid.len) == 0) ||
+ (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_DIGESTED_DATA, Pkcs7->ContentTypeOid.len) == 0))
+ {
+ // Invalid PKCS7 data type;
+ Ret = -1;
+ goto Out;
+ }
+
+ if (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_SIGNED_DATA, Pkcs7->ContentTypeOid.len) != 0) {
+ // Invalid PKCS7 data type;
+ Ret = -1;
+ goto Out;
+ }
+
+ // Content type is SignedData
+ Ptr = Ptr + Pkcs7->ContentTypeOid.len;
+
+ Ret = MbedTlsPkcs7GetNextContentLen (&Ptr, End, &Len);
+ if (Ret != 0) {
+ goto Out;
+ }
+
+ Ret = Pkcs7GetSignedData (Ptr, Len, &Pkcs7->SignedData);
+ if (Ret != 0) {
+ goto Out;
+ }
+
+Out:
+ return Ret;
+}
+
+/**
+ MbedtlsPkcs7 verify MbedtlsPkcs7SignerInfo.
+ @param[in] SignerInfo MbedtlsPkcs7 SignerInfo.
+ @param[in] Cert cert.
+ @param[in] Data Pointer for data.
+ @param[in] DataLen The len the buffer.
+
+ @retval 0 Success.
+ @retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
+**/
+STATIC
+INT32
+MbedtlsPkcs7SignedDataVerifySigners (
+ MbedtlsPkcs7SignerInfo *SignerInfo,
+ mbedtls_x509_crt *Cert,
+ CONST UINT8 *Data,
+ INTN DataLen
+ )
+{
+ INT32 Ret;
+ UINT8 Hash[MBEDTLS_MD_MAX_SIZE];
+ mbedtls_pk_context Pk;
+ CONST mbedtls_md_info_t *MdInfo;
+ INTN HashLen;
+ UINT8 TempAuthAttr;
+
+ Pk = Cert->pk;
+ ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE);
+
+ // all the hash algo
+ #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES
+ MdInfo = mbedtls_md_info_from_type (MBEDTLS_MD_SHA1);
+ HashLen = mbedtls_md_get_size (MdInfo);
+ mbedtls_md (MdInfo, Data, DataLen, Hash);
+ if (SignerInfo->AuthAttr.p != NULL) {
+ TempAuthAttr = *(SignerInfo->AuthAttr.p);
+ *(SignerInfo->AuthAttr.p) = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET;
+ mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, Hash);
+ // Restore content
+ *(SignerInfo->AuthAttr.p) = TempAuthAttr;
+ }
+
+ Ret = mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA1, Hash, HashLen, SignerInfo->Sig.p, SignerInfo->Sig.len);
+
+ if (Ret == 0) {
+ return Ret;
+ }
+
+ #endif
+
+ MdInfo = mbedtls_md_info_from_type (MBEDTLS_MD_SHA256);
+ HashLen = mbedtls_md_get_size (MdInfo);
+ ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE);
+ mbedtls_md (MdInfo, Data, DataLen, Hash);
+ if (SignerInfo->AuthAttr.p != NULL) {
+ TempAuthAttr = *(SignerInfo->AuthAttr.p);
+ *(SignerInfo->AuthAttr.p) = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET;
+ mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, Hash);
+ // Restore content
+ *(SignerInfo->AuthAttr.p) = TempAuthAttr;
+ }
+
+ Ret = mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA256, Hash, HashLen, SignerInfo->Sig.p, SignerInfo->Sig.len);
+ if (Ret == 0) {
+ return Ret;
+ }
+
+ MdInfo = mbedtls_md_info_from_type (MBEDTLS_MD_SHA384);
+ HashLen = mbedtls_md_get_size (MdInfo);
+ ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE);
+ mbedtls_md (MdInfo, Data, DataLen, Hash);
+ if (SignerInfo->AuthAttr.p != NULL) {
+ TempAuthAttr = *(SignerInfo->AuthAttr.p);
+ *(SignerInfo->AuthAttr.p) = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET;
+ mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, Hash);
+ // Restore content
+ *(SignerInfo->AuthAttr.p) = TempAuthAttr;
+ }
+
+ Ret = mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA384, Hash, HashLen, SignerInfo->Sig.p, SignerInfo->Sig.len);
+ if (Ret == 0) {
+ return Ret;
+ }
+
+ MdInfo = mbedtls_md_info_from_type (MBEDTLS_MD_SHA512);
+ HashLen = mbedtls_md_get_size (MdInfo);
+ ZeroMem (Hash, MBEDTLS_MD_MAX_SIZE);
+ mbedtls_md (MdInfo, Data, DataLen, Hash);
+ if (SignerInfo->AuthAttr.p != NULL) {
+ TempAuthAttr = *(SignerInfo->AuthAttr.p);
+ *(SignerInfo->AuthAttr.p) = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET;
+ mbedtls_md (MdInfo, SignerInfo->AuthAttr.p, SignerInfo->AuthAttr.len, Hash);
+ // Restore content
+ *(SignerInfo->AuthAttr.p) = TempAuthAttr;
+ }
+
+ Ret = mbedtls_pk_verify (&Pk, MBEDTLS_MD_SHA512, Hash, HashLen, SignerInfo->Sig.p, SignerInfo->Sig.len);
+ if (Ret == 0) {
+ return Ret;
+ }
+
+ return Ret;
+}
+
+/**
+ Find signer cert in MbedtlsPkcs7SignerInfo.
+
+ @param[in] SignerInfo MbedtlsPkcs7 SignerInfo.
+ @param[in] Certs MbedtlsPkcs7 SignerInfo certs.
+
+ @retval cert Signer Cert.
+**/
+STATIC
+mbedtls_x509_crt *
+MbedTlsPkcs7FindSignerCert (
+ MbedtlsPkcs7SignerInfo *SignerInfo,
+ mbedtls_x509_crt *Certs
+ )
+{
+ mbedtls_x509_crt *Cert;
+
+ Cert = Certs;
+ while (Cert != NULL) {
+ if ((Cert->issuer_raw.len == SignerInfo->IssuerRaw.len) &&
+ (CompareMem (Cert->issuer_raw.p, SignerInfo->IssuerRaw.p, Cert->issuer_raw.len) == 0) &&
+ (Cert->serial.len == SignerInfo->Serial.len) &&
+ (CompareMem (Cert->serial.p, SignerInfo->Serial.p, Cert->serial.len) == 0))
+ {
+ break;
+ }
+
+ Cert = Cert->next;
+ }
+
+ return Cert;
+}
+
+/**
+ verify cert.
+
+ @param[in] Ca CA cert.
+ @param[in] CaCrl CRL.
+ @param[in] End Cert which need be verified.
+
+ @retval TRUE Verify successfully.
+ @retval FALSE Verify failed.
+**/
+STATIC
+BOOLEAN
+MbedTlsPkcs7VerifyCert (
+ mbedtls_x509_crt *Ca,
+ mbedtls_x509_crl *CaCrl,
+ mbedtls_x509_crt *End
+ )
+{
+ INT32 Ret;
+ UINT32 VFlag;
+ mbedtls_x509_crt_profile Profile;
+
+ VFlag = 0;
+ CopyMem (&Profile, &gCompatProfile, sizeof (mbedtls_x509_crt_profile));
+
+ Ret = mbedtls_x509_crt_verify_with_profile (End, Ca, CaCrl, &Profile, NULL, &VFlag, NULL, NULL);
+
+ return Ret == 0;
+}
+
+/**
+ verify cert chain.
+
+ @param[in] Pkcs7 MbedtlsPkcs7.
+ @param[in] Ca CA cert.
+ @param[in] End Cert which need be verified.
+
+ @retval TRUE Verify successfully.
+ @retval FALSE Verify failed.
+**/
+STATIC
+BOOLEAN
+MbedTlsPkcs7VerifyCertChain (
+ MbedtlsPkcs7 *Pkcs7,
+ mbedtls_x509_crt *Ca,
+ mbedtls_x509_crt *End
+ )
+{
+ mbedtls_x509_crt *AllCert;
+ mbedtls_x509_crt *InterCert;
+
+ AllCert = &(Pkcs7->SignedData.Certificates);
+ InterCert = NULL;
+
+ while (AllCert != NULL) {
+ if ((AllCert->next == End) && (MbedTlsPkcs7VerifyCert (AllCert, NULL, End))) {
+ InterCert = AllCert;
+ break;
+ }
+
+ AllCert = AllCert->next;
+ }
+
+ if (InterCert == NULL) {
+ return FALSE;
+ }
+
+ if (MbedTlsPkcs7VerifyCert (Ca, &(Pkcs7->SignedData.Crls), InterCert)) {
+ return TRUE;
+ } else {
+ return MbedTlsPkcs7VerifyCertChain (Pkcs7, Ca, InterCert);
+ }
+}
+
+/**
+ MbedTlsPkcs7 Verify SignedData.
+
+ @param[in] Pkcs7 MbedtlsPkcs7.
+ @param[in] TrustCert CA cert.
+ @param[in] Data Pointer for data.
+ @param[in] DataLen The len the buffer.
+
+ @retval TRUE Verify successfully.
+ @retval FALSE Verify failed.
+**/
+STATIC
+BOOLEAN
+MbedTlsPkcs7SignedDataVerify (
+ MbedtlsPkcs7 *Pkcs7,
+ mbedtls_x509_crt *TrustCert,
+ CONST UINT8 *Data,
+ INTN DataLen
+ )
+{
+ MbedtlsPkcs7SignerInfo *SignerInfo;
+ mbedtls_x509_crt *Cert;
+ mbedtls_x509_crt *AllCert;
+ BOOLEAN Result;
+
+ SignerInfo = &(Pkcs7->SignedData.SignerInfos);
+ Result = TRUE;
+
+ //
+ // Traverse signers and verify each signers
+ //
+ while (SignerInfo != NULL) {
+ Result = FALSE;
+ // 1. Find signers cert
+ Cert = MbedTlsPkcs7FindSignerCert (SignerInfo, &(Pkcs7->SignedData.Certificates));
+ if (Cert != NULL) {
+ // 2. Check signer cert is trusted by trustCert
+ if (MbedTlsPkcs7VerifyCert (TrustCert, &(Pkcs7->SignedData.Crls), Cert)) {
+ // root cert verify pass
+ Result = TRUE;
+ } else {
+ if (MbedTlsPkcs7VerifyCertChain (Pkcs7, TrustCert, Cert)) {
+ Result = TRUE;
+ } else {
+ Result = FALSE;
+ }
+ }
+
+ if (Result == TRUE) {
+ // 3. Check signed data
+ AllCert = &(Pkcs7->SignedData.Certificates);
+ while (AllCert != NULL) {
+ if (MbedtlsPkcs7SignedDataVerifySigners (SignerInfo, AllCert, Data, DataLen) == 0) {
+ return TRUE;
+ }
+
+ AllCert = AllCert->next;
+ }
+
+ Result = FALSE;
+ }
+ }
+
+ // move to next
+ SignerInfo = SignerInfo->Next;
+ }
+
+ return Result;
+}
+
+/**
+ 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] == MBEDTLS_ASN1_OID) && (P7Data[5] == sizeof (MBEDTLS_OID_PKCS7_SIGNED_DATA) - 1)) {
+ if (CompareMem (P7Data + 6, MBEDTLS_OID_PKCS7_SIGNED_DATA, sizeof (MBEDTLS_OID_PKCS7_SIGNED_DATA) - 1) == 0) {
+ if ((P7Data[15] == MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) && (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 = AllocateZeroPool (*WrapDataSize);
+ if (*WrapData == NULL) {
+ *WrapFlag = Wrapped;
+ return FALSE;
+ }
+
+ SignedData = *WrapData;
+
+ //
+ // Part1: 0x30, 0x82.
+ //
+ SignedData[0] = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE;
+ 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] = MBEDTLS_ASN1_OID;
+ SignedData[5] = sizeof (MBEDTLS_OID_PKCS7_SIGNED_DATA) - 1;
+
+ //
+ // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.
+ //
+ CopyMem (SignedData + 6, MBEDTLS_OID_PKCS7_SIGNED_DATA, sizeof (MBEDTLS_OID_PKCS7_SIGNED_DATA) - 1);
+
+ //
+ // Part5: 0xA0, 0x82.
+ //
+ SignedData[15] = MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC;
+ 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;
+}
+
+/**
+ 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.
+ If this interface is not supported, then return FALSE.
+
+ @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.
+ @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
+ )
+{
+ BOOLEAN Status;
+ UINT8 *WrapData;
+ UINTN WrapDataSize;
+ BOOLEAN Wrapped;
+ MbedtlsPkcs7 Pkcs7;
+ INT32 Ret;
+ mbedtls_x509_crt Crt;
+ mbedtls_x509_crt *TempCrt;
+ mbedtls_x509_crt *NextCrt;
+
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &WrapData, &WrapDataSize);
+
+ if (Status) {
+ Ret = 0;
+ Status = FALSE;
+ } else {
+ Ret = -1;
+ }
+
+ MbedTlsPkcs7Init (&Pkcs7);
+ mbedtls_x509_crt_init (&Crt);
+
+ if (Ret == 0) {
+ Ret = MbedtlsPkcs7ParseDer (WrapData, (INT32)WrapDataSize, &Pkcs7);
+ }
+
+ if (Ret == 0) {
+ Ret = mbedtls_x509_crt_parse_der (&Crt, TrustedCert, CertLength);
+ }
+
+ if (Ret == 0) {
+ Status = MbedTlsPkcs7SignedDataVerify (&Pkcs7, &Crt, InData, (INT32)DataLength);
+ }
+
+ if (&Crt != NULL) {
+ mbedtls_x509_crt_free (&Crt);
+ }
+
+ if (Pkcs7.SignedData.Certificates.next != NULL) {
+ TempCrt = Pkcs7.SignedData.Certificates.next;
+
+ while (TempCrt != NULL) {
+ NextCrt = TempCrt->next;
+ mbedtls_x509_crt_free (TempCrt);
+ FreePool (TempCrt);
+ TempCrt = NextCrt;
+ }
+ }
+
+ 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;
+ }
+
+ FreePool (Certs);
+}
+
+/**
+ 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
+ )
+{
+ MbedtlsPkcs7SignerInfo *SignerInfo;
+ mbedtls_x509_crt *Cert;
+ MbedtlsPkcs7 Pkcs7;
+ BOOLEAN Status;
+ UINT8 *WrapData;
+ UINTN WrapDataSize;
+ BOOLEAN Wrapped;
+ mbedtls_x509_crt *TempCrt;
+ mbedtls_x509_crt *NextCrt;
+
+ UINTN CertSize;
+ UINT8 Index;
+ UINT8 *CertBuf;
+ UINT8 *OldBuf;
+ UINTN BufferSize;
+ UINTN OldSize;
+
+ if ((P7Data == NULL) || (CertStack == NULL) || (StackLength == NULL) ||
+ (TrustedCert == NULL) || (CertLength == NULL) || (P7Length > INT_MAX))
+ {
+ return FALSE;
+ }
+
+ Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &WrapData, &WrapDataSize);
+
+ if (!Status) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ CertBuf = NULL;
+ OldBuf = NULL;
+ Cert = NULL;
+
+ MbedTlsPkcs7Init (&Pkcs7);
+ if (MbedtlsPkcs7ParseDer (WrapData, (INT32)WrapDataSize, &Pkcs7) != 0) {
+ goto _Exit;
+ }
+
+ SignerInfo = &(Pkcs7.SignedData.SignerInfos);
+
+ //
+ // Traverse each signers
+ //
+ // 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;
+ Index = 0;
+
+ while (SignerInfo != NULL) {
+ // Find signers cert
+ Cert = MbedTlsPkcs7FindSignerCert (SignerInfo, &(Pkcs7.SignedData.Certificates));
+ if (Cert == NULL) {
+ goto _Exit;
+ }
+
+ CertSize = Cert->raw.len;
+ OldSize = BufferSize;
+ OldBuf = CertBuf;
+ BufferSize = OldSize + CertSize + sizeof (UINT32);
+
+ CertBuf = AllocateZeroPool (BufferSize);
+ if (CertBuf == NULL) {
+ goto _Exit;
+ }
+
+ if (OldBuf != NULL) {
+ CopyMem (CertBuf, OldBuf, OldSize);
+ free (OldBuf);
+ OldBuf = NULL;
+ }
+
+ WriteUnaligned32 ((UINT32 *)(CertBuf + OldSize), (UINT32)CertSize);
+ CopyMem (CertBuf + OldSize + sizeof (UINT32), Cert->raw.p, CertSize);
+
+ Index++;
+
+ // move to next
+ SignerInfo = SignerInfo->Next;
+ }
+
+ if (CertBuf != NULL) {
+ //
+ // Update CertNumber.
+ //
+ CertBuf[0] = Index;
+
+ *CertLength = BufferSize - OldSize - sizeof (UINT32);
+ *TrustedCert = AllocateZeroPool (*CertLength);
+ if (*TrustedCert == NULL) {
+ goto _Exit;
+ }
+
+ CopyMem (*TrustedCert, CertBuf + OldSize + sizeof (UINT32), *CertLength);
+ *CertStack = CertBuf;
+ *StackLength = BufferSize;
+ Status = TRUE;
+ }
+
+_Exit:
+ //
+ // Release Resources
+ //
+ if (!Status && (CertBuf != NULL)) {
+ FreePool (CertBuf);
+ *CertStack = NULL;
+ }
+
+ if (Status) {
+ if (Pkcs7.SignedData.Certificates.next != NULL) {
+ TempCrt = Pkcs7.SignedData.Certificates.next;
+
+ while (TempCrt != NULL) {
+ NextCrt = TempCrt->next;
+ mbedtls_x509_crt_free (TempCrt);
+ FreePool (TempCrt);
+ TempCrt = NextCrt;
+ }
+ }
+ }
+
+ if (OldBuf != NULL) {
+ FreePool (OldBuf);
+ }
+
+ return Status;
+}
+
+/**
+ 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;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c
new file mode 100644
index 0000000000..c81e4468bb
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c
@@ -0,0 +1,689 @@
+/** @file
+ This module verifies that Enhanced Key Usages (EKU's) are present within
+ a PKCS7 signature blob using MbedTLS.
+
+ Copyright (C) Microsoft Corporation. All Rights Reserved.
+ Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include "InternalCryptLib.h"
+#include <mbedtls/pkcs7.h>
+#include <mbedtls/asn1write.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 EkuOID[] = { 0x55, 0x1D, 0x25 };
+
+/*leaf Cert basic_constraints case1: CA: false and CA object is excluded */
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gBasicConstraintsCase1[] = { 0x30, 0x00 };
+
+/*leaf Cert basic_constraints case2: CA: false */
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gBasicConstraintsCase2[] = { 0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00 };
+
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8 gOidBasicConstraints[] = { 0x55, 0x1D, 0x13 };
+
+/**
+ Find first Extension data match with given OID
+
+ @param[in] Start Pointer to the DER-encoded extensions data
+ @param[in] End extensions data size in bytes
+ @param[in ] Oid OID for match
+ @param[in ] OidSize OID size in bytes
+ @param[out] FindExtensionData output matched extension data.
+ @param[out] FindExtensionDataLen matched extension data size.
+
+**/
+STATIC
+BOOLEAN
+InternalX509FindExtensionData (
+ UINT8 *Start,
+ UINT8 *End,
+ CONST UINT8 *Oid,
+ UINTN OidSize,
+ UINT8 **FindExtensionData,
+ UINTN *FindExtensionDataLen
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ExtensionPtr;
+ UINTN ObjLen;
+ INT32 Ret;
+ BOOLEAN Status;
+ UINTN FindExtensionLen;
+ UINTN HeaderLen;
+
+ /*If no Extension entry match Oid*/
+ Status = FALSE;
+ Ptr = Start;
+
+ Ret = 0;
+
+ while (TRUE) {
+ //
+ // Extension ::= SEQUENCE {
+ // extnID OBJECT IDENTIFIER,
+ // critical BOOLEAN DEFAULT FALSE,
+ // extnValue OCTET STRING }
+ //
+ ExtensionPtr = Ptr;
+ Ret = mbedtls_asn1_get_tag (
+ &Ptr,
+ End,
+ &ObjLen,
+ MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE
+ );
+ if (Ret == 0) {
+ HeaderLen = (UINTN)(Ptr - ExtensionPtr);
+ FindExtensionLen = ObjLen;
+ /* Get Object Identifier*/
+ Ret = mbedtls_asn1_get_tag (
+ &Ptr,
+ End,
+ &ObjLen,
+ MBEDTLS_ASN1_OID
+ );
+ } else {
+ break;
+ }
+
+ if ((Ret == 0) && !CompareMem (Ptr, Oid, OidSize)) {
+ Ptr += ObjLen;
+
+ Ret = mbedtls_asn1_get_tag (
+ &Ptr,
+ End,
+ &ObjLen,
+ MBEDTLS_ASN1_BOOLEAN
+ );
+ if (Ret == 0) {
+ Ptr += ObjLen;
+ }
+
+ Ret = mbedtls_asn1_get_tag (
+ &Ptr,
+ End,
+ &ObjLen,
+ MBEDTLS_ASN1_OCTET_STRING
+ );
+ } else {
+ Ret = 1;
+ }
+
+ if (Ret == 0) {
+ *FindExtensionData = Ptr;
+ *FindExtensionDataLen = ObjLen;
+ Status = TRUE;
+ break;
+ }
+
+ /* move to next*/
+ Ptr = ExtensionPtr + HeaderLen + FindExtensionLen;
+ Ret = 0;
+ }
+
+ return Status;
+}
+
+/**
+ Retrieve Extension data from one X.509 certificate.
+
+ @param[in] Cert Pointer to the X509 certificate.
+ @param[in] Oid Object identifier buffer
+ @param[in] OidSize Object identifier buffer size
+ @param[out] ExtensionData Extension bytes.
+ @param[in, out] ExtensionDataSize Extension bytes size.
+
+ @retval RETURN_SUCCESS The certificate Extension data retrieved successfully.
+ @retval RETURN_INVALID_PARAMETER If Cert is NULL.
+ If ExtensionDataSize is NULL.
+ If ExtensionData is not NULL and *ExtensionDataSize is 0.
+ If Certificate is invalid.
+ @retval RETURN_NOT_FOUND If no Extension entry match Oid.
+ @retval RETURN_BUFFER_TOO_SMALL If the ExtensionData is NULL. The required buffer size
+ is returned in the ExtensionDataSize parameter.
+ @retval RETURN_UNSUPPORTED The operation is not supported.
+**/
+STATIC
+BOOLEAN
+GetExtensionData (
+ CONST mbedtls_x509_crt *Cert,
+ CONST UINT8 *Oid,
+ UINTN OidSize,
+ UINT8 *ExtensionData,
+ UINTN *ExtensionDataSize
+ )
+{
+ CONST mbedtls_x509_crt *Crt;
+ INT32 Ret;
+ BOOLEAN Status;
+ UINT8 *Ptr;
+ UINT8 *End;
+ UINTN ObjLen;
+
+ Ptr = NULL;
+ End = NULL;
+ ObjLen = 0;
+
+ if ((Cert == NULL) || (Oid == NULL) || (OidSize == 0) ||
+ (ExtensionDataSize == NULL))
+ {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ Crt = Cert;
+
+ Ptr = Crt->v3_ext.p;
+ End = Crt->v3_ext.p + Crt->v3_ext.len;
+ Ret = mbedtls_asn1_get_tag (
+ &Ptr,
+ End,
+ &ObjLen,
+ MBEDTLS_ASN1_CONSTRUCTED |
+ MBEDTLS_ASN1_SEQUENCE
+ );
+
+ if (Ret == 0) {
+ Status = InternalX509FindExtensionData (
+ Ptr,
+ End,
+ Oid,
+ OidSize,
+ &Ptr,
+ &ObjLen
+ );
+ }
+
+ if (Status) {
+ if (*ExtensionDataSize < ObjLen) {
+ *ExtensionDataSize = ObjLen;
+ Status = FALSE;
+ goto Cleanup;
+ }
+
+ if (Oid != NULL) {
+ if (ExtensionData == NULL) {
+ return FALSE;
+ }
+
+ CopyMem (ExtensionData, Ptr, ObjLen);
+ }
+
+ *ExtensionDataSize = ObjLen;
+ } else {
+ *ExtensionDataSize = 0;
+ }
+
+Cleanup:
+ 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] EKU The EKU to look for.
+ @param[in] EkuLen The size of EKU.
+
+ @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.
+
+**/
+STATIC
+EFI_STATUS
+IsEkuInCertificate (
+ IN CONST mbedtls_x509_crt *Cert,
+ IN UINT8 *EKU,
+ IN UINTN EkuLen
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Ret;
+ UINT8 *Buffer;
+ UINTN Index;
+ UINTN Len;
+
+ if ((Cert == NULL) || (EKU == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Len = 0;
+ Buffer = NULL;
+ Ret = GetExtensionData (
+ Cert,
+ (CONST UINT8 *)EkuOID,
+ sizeof (EkuOID),
+ NULL,
+ &Len
+ );
+ if (Len == 0) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ Buffer = AllocateZeroPool (Len);
+ if (Buffer == NULL) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ Ret = GetExtensionData (
+ Cert,
+ (CONST UINT8 *)EkuOID,
+ sizeof (EkuOID),
+ Buffer,
+ &Len
+ );
+
+ if ((Len == 0) || (!Ret)) {
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ Status = EFI_NOT_FOUND;
+ /*find the spdm hardware identity OID*/
+ for (Index = 0; Index <= Len - EkuLen; Index++) {
+ if (!CompareMem (Buffer + Index, EKU, EkuLen)) {
+ // check sub EKU
+ if (Index == Len - EkuLen) {
+ Status = EFI_SUCCESS;
+ break;
+ // Ensure that the OID is complete
+ } else if (Buffer[Index + EkuLen] == 0x06) {
+ Status = EFI_SUCCESS;
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+
+Exit:
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ return Status;
+}
+
+/**
+ Get OID from txt.
+
+ @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,out] CheckOid OID.
+ @param[out] OidLen The size of OID.
+
+**/
+void
+GetOidFromTxt (
+ IN CONST CHAR8 *RequiredEKUs,
+ IN UINTN RequiredEKUsSize,
+ IN OUT UINT8 *CheckOid,
+ OUT UINT8 *OidLen
+ )
+{
+ UINT8 *Ptr;
+ UINT16 Index;
+ UINT32 Data;
+ UINT8 OidIndex;
+ UINTN EKUsSize;
+
+ EKUsSize = RequiredEKUsSize;
+ // https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier?redirectedfrom=MSDN
+ CheckOid[0] = (UINT8)((RequiredEKUs[0] - '0') * 40 + (RequiredEKUs[2] - '0'));
+
+ EKUsSize = EKUsSize - 4;
+ Ptr = (UINT8 *)(RequiredEKUs + 4);
+
+ OidIndex = 1;
+
+ while (EKUsSize) {
+ Index = 0;
+ Data = 0;
+
+ while ((*Ptr != '.') && (*Ptr != '\0')) {
+ Index++;
+ Ptr++;
+ EKUsSize--;
+ }
+
+ while (Index) {
+ Data = 10 * Data + (*(Ptr - Index) - '0');
+ Index--;
+ }
+
+ if (EKUsSize != 0) {
+ Ptr++;
+ EKUsSize--;
+ }
+
+ if (Data < 128) {
+ CheckOid[OidIndex] = (UINT8)Data;
+ OidIndex++;
+ } else {
+ CheckOid[OidIndex + 1] = (UINT8)(Data & 0xFF);
+ CheckOid[OidIndex] = (UINT8)(((((Data & 0xFF00) << 1) | 0x8000) >> 8) & 0xFF);
+ OidIndex = OidIndex + 2;
+ }
+ }
+
+ *OidLen = OidIndex;
+}
+
+/**
+ Verify the Cert is signer cert
+
+ @param[in] Start Pointer to the DER-encoded certificate data Start.
+ @param[in] End Pointer to the DER-encoded certificate data End.
+
+ @retval true verify pass
+ @retval false verify fail
+**/
+STATIC
+BOOLEAN
+IsCertSignerCert (
+ UINT8 *Start,
+ UINT8 *End
+ )
+{
+ BOOLEAN Status;
+ UINT8 *Buffer;
+ UINTN Len;
+ mbedtls_x509_crt Cert;
+ UINTN ObjLen;
+
+ mbedtls_x509_crt_init (&Cert);
+
+ ObjLen = End - Start;
+
+ if (mbedtls_x509_crt_parse_der (&Cert, Start, ObjLen) != 0) {
+ return FALSE;
+ }
+
+ Len = 0;
+ Buffer = NULL;
+ Status = GetExtensionData (
+ &Cert,
+ (CONST UINT8 *)gOidBasicConstraints,
+ sizeof (gOidBasicConstraints),
+ NULL,
+ &Len
+ );
+ if (Len == 0) {
+ /* basic constraints is not present in Cert */
+ return TRUE;
+ }
+
+ Buffer = AllocateZeroPool (Len);
+ if (Buffer == NULL) {
+ return FALSE;
+ }
+
+ Status = GetExtensionData (
+ &Cert,
+ (CONST UINT8 *)gOidBasicConstraints,
+ sizeof (gOidBasicConstraints),
+ Buffer,
+ &Len
+ );
+
+ if (Len == 0) {
+ /* basic constraints is not present in Cert */
+ Status = TRUE;
+ goto Exit;
+ } else if (!Status) {
+ Status = FALSE;
+ goto Exit;
+ }
+
+ if ((Len == sizeof (gBasicConstraintsCase1)) &&
+ (!CompareMem (Buffer, gBasicConstraintsCase1, sizeof (gBasicConstraintsCase1))))
+ {
+ Status = TRUE;
+ goto Exit;
+ }
+
+ if ((Len == sizeof (gBasicConstraintsCase2)) &&
+ (!CompareMem (Buffer, gBasicConstraintsCase2, sizeof (gBasicConstraintsCase2))))
+ {
+ Status = TRUE;
+ goto Exit;
+ }
+
+ Status = FALSE;
+
+Exit:
+ mbedtls_x509_crt_free (&Cert);
+
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ 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.
+**/
+STATIC
+EFI_STATUS
+CheckEKUs (
+ IN CONST mbedtls_x509_crt *SignerCert,
+ IN CONST CHAR8 *RequiredEKUs[],
+ IN CONST UINT32 RequiredEKUsSize,
+ IN BOOLEAN RequireAllPresent
+ )
+{
+ EFI_STATUS Status;
+ UINT32 NumEkusFound;
+ UINT32 Index;
+ UINT8 *EKU;
+ UINTN EkuLen;
+ UINT8 CheckOid[20];
+ UINT8 OidLen;
+
+ Status = EFI_SUCCESS;
+ 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.
+ //
+ GetOidFromTxt (RequiredEKUs[Index], strlen (RequiredEKUs[Index]), CheckOid, &OidLen);
+
+ EKU = CheckOid;
+ EkuLen = OidLen;
+
+ Status = IsEkuInCertificate (SignerCert, EKU, EkuLen);
+ 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 (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;
+ mbedtls_x509_crt Cert;
+ UINT8 *Ptr;
+ UINT8 *End;
+ INT32 Len;
+ UINTN ObjLen;
+ UINT8 *OldEnd;
+
+ //
+ // Check input parameter.
+ //
+ if ((RequiredEKUs == NULL) || (Pkcs7Signature == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+
+ mbedtls_x509_crt_init (&Cert);
+
+ Ptr = (UINT8 *)(UINTN)Pkcs7Signature;
+ Len = (UINT32)SignatureSize;
+ End = Ptr + Len;
+
+ // Cert
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // tbscert
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // signature algo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // signature
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ OldEnd = Ptr;
+ // Cert
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ End = Ptr + ObjLen;
+
+ // leaf Cert
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ while ((Ptr != End) && (Ptr < End)) {
+ if (IsCertSignerCert (OldEnd, Ptr)) {
+ break;
+ }
+
+ OldEnd = Ptr;
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ }
+
+ if (Ptr != End) {
+ return FALSE;
+ } else {
+ Ptr = End - ObjLen;
+ }
+
+ // leaf Cert
+ ObjLen += Ptr - OldEnd;
+ Ptr = OldEnd;
+
+ if (mbedtls_x509_crt_parse_der (&Cert, Ptr, ObjLen) != 0) {
+ return FALSE;
+ }
+
+ Status = CheckEKUs (&Cert, RequiredEKUs, RequiredEKUsSize, RequireAllPresent);
+ if (Status != EFI_SUCCESS) {
+ goto Exit;
+ }
+
+Exit:
+ //
+ // Release Resources
+ //
+ mbedtls_x509_crt_free (&Cert);
+
+ return Status;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118115): https://edk2.groups.io/g/devel/message/118115
Mute This Topic: https://groups.io/mt/105683589/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 6/9] CryptoPkg: Add Pkcs5 functions based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
` (4 preceding siblings ...)
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 5/9] CryptoPkg: Add Pkcs7 related " Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 7/9] CryptoPkg: Add more RSA related " Wenxing Hou
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
PBKDF2 Key Derivation Function Wrapper Implementation over MbedTLS.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c
new file mode 100644
index 0000000000..94f1fcfa3b
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c
@@ -0,0 +1,100 @@
+/** @file
+ PBKDF2 Key Derivation Function Wrapper Implementation over MbedTLS.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/pkcs5.h>
+
+/**
+ 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
+ )
+{
+ mbedtls_md_type_t HashAlg;
+
+ //
+ // 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 = MBEDTLS_MD_SHA1;
+ break;
+ case SHA256_DIGEST_SIZE:
+ HashAlg = MBEDTLS_MD_SHA256;
+ break;
+ default:
+ return FALSE;
+ break;
+ }
+
+ //
+ // Perform password-based key derivation routines.
+ //
+ if (mbedtls_pkcs5_pbkdf2_hmac_ext (
+ HashAlg,
+ (CONST UINT8 *)Password,
+ (int)PasswordLength,
+ (CONST UINT8 *)Salt,
+ (int)SaltLength,
+ (int)IterationCount,
+ (int)KeyLength,
+ (UINT8 *)OutKey
+ ) != 0)
+ {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118116): https://edk2.groups.io/g/devel/message/118116
Mute This Topic: https://groups.io/mt/105683590/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 7/9] CryptoPkg: Add more RSA related functions based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
` (5 preceding siblings ...)
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 6/9] CryptoPkg: Add Pkcs5 " Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 8/9] CryptoPkg: Add AuthenticodeVerify " Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 9/9] CryptoPkg: Add ImageTimestampVerify " Wenxing Hou
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
Implement more RSA functions such as RsaPkcs1Sign based Mbedlts.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c | 278 ++++++++++++++
.../BaseCryptLibMbedTls/Pk/CryptRsaExt.c | 346 ++++++++++++++++++
.../BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c | 137 +++++++
3 files changed, 761 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaExt.c
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c
new file mode 100644
index 0000000000..61ccdd78e6
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c
@@ -0,0 +1,278 @@
+/** @file
+ This file contains UEFI wrapper functions for RSA PKCS1v2 OAEP encryption routines.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/rsa.h>
+#include <mbedtls/x509_crt.h>
+#include <Library/MemoryAllocationLib.h>
+
+/**
+ 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;
+ UINT32 Ret;
+ UINT8 *OutData;
+ mbedtls_x509_crt CertContext;
+ mbedtls_rsa_context RsaContext;
+
+ //
+ // Check input parameters.
+ //
+ if ((PublicKey == NULL) || (InData == NULL) ||
+ (EncryptedData == NULL) || (EncryptedDataSize == NULL))
+ {
+ return FALSE;
+ }
+
+ //
+ // Check public key size.
+ //
+ if (PublicKeySize > UINT_MAX) {
+ //
+ // Public key size is too large for implementation.
+ //
+ return FALSE;
+ }
+
+ *EncryptedData = NULL;
+ *EncryptedDataSize = 0;
+ Result = FALSE;
+ OutData = NULL;
+
+ mbedtls_x509_crt_init (&CertContext);
+
+ if (mbedtls_x509_crt_parse_der (&CertContext, PublicKey, (UINT32)PublicKeySize) != 0) {
+ goto _Exit;
+ }
+
+ if (mbedtls_pk_get_type (&CertContext.pk) != MBEDTLS_PK_RSA) {
+ goto _Exit;
+ }
+
+ mbedtls_rsa_init (&RsaContext);
+ if (mbedtls_rsa_set_padding (&RsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_NONE) != 0) {
+ goto _Exit;
+ }
+
+ Ret = mbedtls_rsa_copy (&RsaContext, mbedtls_pk_rsa (CertContext.pk));
+ if (Ret != 0) {
+ goto _Exit;
+ }
+
+ *EncryptedDataSize = RsaContext.len;
+
+ //
+ // Allocate a buffer for the output data.
+ //
+ OutData = AllocateZeroPool (*EncryptedDataSize);
+ if (OutData == NULL) {
+ //
+ // Fail to allocate the output buffer.
+ //
+ goto _Exit;
+ }
+
+ Ret = mbedtls_rsa_pkcs1_encrypt (
+ &RsaContext,
+ MbedtlsRand,
+ NULL,
+ InDataSize,
+ InData,
+ OutData
+ );
+ if (Ret != 0) {
+ FreePool (OutData);
+ OutData = NULL;
+ goto _Exit;
+ }
+
+ *EncryptedData = OutData;
+ Result = TRUE;
+
+_Exit:
+ //
+ // Release Resources
+ //
+ if (&CertContext != NULL) {
+ mbedtls_x509_crt_free (&CertContext);
+ }
+
+ if (&RsaContext != NULL) {
+ mbedtls_rsa_free (&RsaContext);
+ }
+
+ return Result;
+}
+
+/**
+ 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 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] RsaContext A pointer to an RSA context created by RsaNew() and
+ provisioned with a public key using RsaSetKey().
+ @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[in] DigestLen [Optional] If provided, size of the hash used:
+ SHA1_DIGEST_SIZE
+ SHA256_DIGEST_SIZE
+ SHA384_DIGEST_SIZE
+ SHA512_DIGEST_SIZE
+ 0 to use default (SHA1)
+ @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
+RsaOaepEncrypt (
+ IN VOID *RsaContext,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN CONST UINT8 *PrngSeed OPTIONAL,
+ IN UINTN PrngSeedSize OPTIONAL,
+ IN UINT16 DigestLen OPTIONAL,
+ OUT UINT8 **EncryptedData,
+ OUT UINTN *EncryptedDataSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Decrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the
+ decrypted message in a newly allocated buffer.
+
+ Things that can cause a failure include:
+ - Fail to parse private key.
+ - Fail to allocate an intermediate buffer.
+ - Null pointer provided for a non-optional parameter.
+
+ @param[in] PrivateKey A pointer to the DER-encoded private key.
+ @param[in] PrivateKeySize Size of the private key buffer.
+ @param[in] EncryptedData Data to be decrypted.
+ @param[in] EncryptedDataSize Size of the encrypted buffer.
+ @param[out] OutData Pointer to an allocated buffer containing the encrypted
+ message.
+ @param[out] OutDataSize Size of the encrypted message buffer.
+
+ @retval TRUE Encryption was successful.
+ @retval FALSE Encryption failed.
+
+**/
+BOOLEAN
+EFIAPI
+Pkcs1v2Decrypt (
+ IN CONST UINT8 *PrivateKey,
+ IN UINTN PrivateKeySize,
+ IN UINT8 *EncryptedData,
+ IN UINTN EncryptedDataSize,
+ OUT UINT8 **OutData,
+ OUT UINTN *OutDataSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Decrypts a blob using PKCS1v2 (RSAES-OAEP) schema. On success, will return the
+ decrypted message in a newly allocated buffer.
+
+ Things that can cause a failure include:
+ - Fail to parse private key.
+ - Fail to allocate an intermediate buffer.
+ - Null pointer provided for a non-optional parameter.
+
+ @param[in] RsaContext A pointer to an RSA context created by RsaNew() and
+ provisioned with a private key using RsaSetKey().
+ @param[in] EncryptedData Data to be decrypted.
+ @param[in] EncryptedDataSize Size of the encrypted buffer.
+ @param[in] DigestLen [Optional] If provided, size of the hash used:
+ SHA1_DIGEST_SIZE
+ SHA256_DIGEST_SIZE
+ SHA384_DIGEST_SIZE
+ SHA512_DIGEST_SIZE
+ 0 to use default (SHA1)
+ @param[out] OutData Pointer to an allocated buffer containing the encrypted
+ message.
+ @param[out] OutDataSize Size of the encrypted message buffer.
+
+ @retval TRUE Encryption was successful.
+ @retval FALSE Encryption failed.
+
+**/
+BOOLEAN
+EFIAPI
+RsaOaepDecrypt (
+ IN VOID *RsaContext,
+ IN UINT8 *EncryptedData,
+ IN UINTN EncryptedDataSize,
+ IN UINT16 DigestLen OPTIONAL,
+ OUT UINT8 **OutData,
+ OUT UINTN *OutDataSize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaExt.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaExt.c
new file mode 100644
index 0000000000..e832912495
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaExt.c
@@ -0,0 +1,346 @@
+/** @file
+ RSA Asymmetric Cipher Wrapper Implementation over MbedTLS.
+
+ This file implements following APIs which provide more capabilities for RSA:
+ 1) RsaGetKey
+ 2) RsaGenerateKey
+ 3) RsaCheckKey
+ 4) RsaPkcs1Sign
+
+ RFC 8017 - PKCS #1: RSA Cryptography Specifications Version 2.2
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/rsa.h>
+
+/**
+ 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
+ )
+{
+ mbedtls_rsa_context *RsaKey;
+ INT32 Ret;
+ mbedtls_mpi Value;
+ UINTN Size;
+
+ //
+ // Check input parameters.
+ //
+ if ((RsaContext == NULL) || (*BnSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ //
+ // Init mbedtls_mpi
+ //
+ mbedtls_mpi_init (&Value);
+ Size = *BnSize;
+ *BnSize = 0;
+
+ RsaKey = (mbedtls_rsa_context *)RsaContext;
+
+ switch (KeyTag) {
+ case RsaKeyN:
+ Ret = mbedtls_rsa_export (RsaKey, &Value, NULL, NULL, NULL, NULL);
+ break;
+ case RsaKeyE:
+ Ret = mbedtls_rsa_export (RsaKey, NULL, NULL, NULL, NULL, &Value);
+ break;
+ case RsaKeyD:
+ Ret = mbedtls_rsa_export (RsaKey, NULL, NULL, NULL, &Value, NULL);
+ break;
+ case RsaKeyQ:
+ Ret = mbedtls_rsa_export (RsaKey, NULL, NULL, &Value, NULL, NULL);
+ break;
+ case RsaKeyP:
+ Ret = mbedtls_rsa_export (RsaKey, NULL, &Value, NULL, NULL, NULL);
+ break;
+ case RsaKeyDp:
+ case RsaKeyDq:
+ case RsaKeyQInv:
+ default:
+ Ret = -1;
+ break;
+ }
+
+ if (Ret != 0) {
+ goto End;
+ }
+
+ if (mbedtls_mpi_size (&Value) == 0) {
+ Ret = 0;
+ goto End;
+ }
+
+ *BnSize = Size;
+
+ Size = mbedtls_mpi_size (&Value);
+ if (*BnSize < Size) {
+ Ret = 1;
+ *BnSize = Size;
+ goto End;
+ }
+
+ if (BigNumber == NULL) {
+ Ret = 0;
+ *BnSize = Size;
+ goto End;
+ }
+
+ if ((BigNumber != NULL) && (Ret == 0)) {
+ Ret = mbedtls_mpi_write_binary (&Value, BigNumber, Size);
+ *BnSize = Size;
+ }
+
+End:
+ mbedtls_mpi_free (&Value);
+ return Ret == 0;
+}
+
+/**
+ Generates RSA key components.
+
+ This function generates RSA key components. It takes RSA public exponent Pe 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
+ )
+{
+ INT32 Ret;
+ mbedtls_rsa_context *Rsa;
+ INT32 Pe;
+
+ //
+ // Check input parameters.
+ //
+ if ((RsaContext == NULL) || (ModulusLength > INT_MAX) || (PublicExponentSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ Rsa = (mbedtls_rsa_context *)RsaContext;
+
+ if (PublicExponent == NULL) {
+ Pe = 0x10001;
+ } else {
+ if (PublicExponentSize == 0) {
+ return FALSE;
+ }
+
+ switch (PublicExponentSize) {
+ case 1:
+ Pe = PublicExponent[0];
+ break;
+ case 2:
+ Pe = PublicExponent[0] << 8 | PublicExponent[1];
+ break;
+ case 3:
+ Pe = PublicExponent[0] << 16 | PublicExponent[1] << 8 |
+ PublicExponent[2];
+ break;
+ case 4:
+ Pe = PublicExponent[0] << 24 | PublicExponent[1] << 16 |
+ PublicExponent[2] << 8 | PublicExponent[3];
+ break;
+ default:
+ return FALSE;
+ }
+ }
+
+ Ret = mbedtls_rsa_gen_key (
+ Rsa,
+ MbedtlsRand,
+ NULL,
+ (UINT32)ModulusLength,
+ Pe
+ );
+
+ return Ret == 0;
+}
+
+/**
+ 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
+ )
+{
+ if (RsaContext == NULL) {
+ return FALSE;
+ }
+
+ UINT32 Ret;
+
+ Ret = mbedtls_rsa_complete (RsaContext);
+ if (Ret == 0) {
+ Ret = mbedtls_rsa_check_privkey (RsaContext);
+ }
+
+ return Ret == 0;
+}
+
+/**
+ 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
+ )
+{
+ INT32 Ret;
+ mbedtls_md_type_t MdAlg;
+
+ if ((RsaContext == NULL) || (MessageHash == NULL)) {
+ return FALSE;
+ }
+
+ if (mbedtls_rsa_complete ((mbedtls_rsa_context *)RsaContext) != 0) {
+ return FALSE;
+ }
+
+ switch (HashSize) {
+ case MD5_DIGEST_SIZE:
+ break;
+
+ case SHA1_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA1;
+ break;
+
+ case SHA256_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA256;
+ break;
+
+ case SHA384_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA384;
+ break;
+
+ case SHA512_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA512;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ if (mbedtls_rsa_get_len (RsaContext) > *SigSize) {
+ *SigSize = mbedtls_rsa_get_len (RsaContext);
+ return FALSE;
+ }
+
+ mbedtls_rsa_set_padding (RsaContext, MBEDTLS_RSA_PKCS_V15, MdAlg);
+
+ Ret = mbedtls_rsa_pkcs1_sign (
+ RsaContext,
+ MbedtlsRand,
+ NULL,
+ MdAlg,
+ (UINT32)HashSize,
+ MessageHash,
+ Signature
+ );
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ *SigSize = mbedtls_rsa_get_len (RsaContext);
+ return TRUE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c
new file mode 100644
index 0000000000..0e2203cdb9
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c
@@ -0,0 +1,137 @@
+/** @file
+ RSA PSS Asymmetric Cipher Wrapper Implementation over MbedTLS.
+
+ This file implements following APIs which provide basic capabilities for RSA:
+ 1) RsaPssSign
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/rsa.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/sha512.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 not equal to 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
+ )
+{
+ INT32 Ret;
+ mbedtls_md_type_t MdAlg;
+ UINT8 HashValue[SHA512_DIGEST_SIZE];
+
+ if (RsaContext == NULL) {
+ return FALSE;
+ }
+
+ if (mbedtls_rsa_complete ((mbedtls_rsa_context *)RsaContext) != 0) {
+ return FALSE;
+ }
+
+ if ((Message == NULL) || (MsgSize == 0) || (MsgSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ if (SaltLen != DigestLen) {
+ return FALSE;
+ }
+
+ ZeroMem (HashValue, DigestLen);
+
+ switch (DigestLen) {
+ case SHA256_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA256;
+ if (mbedtls_sha256 (Message, MsgSize, HashValue, FALSE) != 0) {
+ return FALSE;
+ }
+
+ break;
+
+ case SHA384_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA384;
+ if (mbedtls_sha512 (Message, MsgSize, HashValue, TRUE) != 0) {
+ return FALSE;
+ }
+
+ break;
+
+ case SHA512_DIGEST_SIZE:
+ MdAlg = MBEDTLS_MD_SHA512;
+ if (mbedtls_sha512 (Message, MsgSize, HashValue, FALSE) != 0) {
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ if (Signature == NULL) {
+ //
+ // If Signature is NULL, return safe SignatureSize
+ //
+ *SigSize = MBEDTLS_MPI_MAX_SIZE;
+ return FALSE;
+ }
+
+ mbedtls_rsa_set_padding (RsaContext, MBEDTLS_RSA_PKCS_V21, MdAlg);
+
+ Ret = mbedtls_rsa_rsassa_pss_sign (
+ RsaContext,
+ MbedtlsRand,
+ NULL,
+ MdAlg,
+ (UINT32)DigestLen,
+ HashValue,
+ Signature
+ );
+ if (Ret != 0) {
+ return FALSE;
+ }
+
+ *SigSize = ((mbedtls_rsa_context *)RsaContext)->len;
+ return TRUE;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118117): https://edk2.groups.io/g/devel/message/118117
Mute This Topic: https://groups.io/mt/105683591/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 8/9] CryptoPkg: Add AuthenticodeVerify based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
` (6 preceding siblings ...)
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 7/9] CryptoPkg: Add more RSA related " Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 9/9] CryptoPkg: Add ImageTimestampVerify " Wenxing Hou
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
Implement AuthenticodeVerify based on Mbedtls.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../Pk/CryptAuthenticode.c | 214 ++++++++++++++++++
1 file changed, 214 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptAuthenticode.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptAuthenticode.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptAuthenticode.c
new file mode 100644
index 0000000000..9d8301b2c0
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptAuthenticode.c
@@ -0,0 +1,214 @@
+/** @file
+ Authenticode Portable Executable Signature Verification which does not provide
+ real capabilities.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/pkcs7.h>
+
+//
+// OID ASN.1 Value for SPC_INDIRECT_DATA_OBJID
+//
+GLOBAL_REMOVE_IF_UNREFERENCED const 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".
+
+ 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
+ )
+{
+ BOOLEAN Status;
+ CONST UINT8 *OrigAuthData;
+ UINT8 *SpcIndirectDataContent;
+ UINT8 Asn1Byte;
+ UINTN ContentSize;
+ CONST UINT8 *SpcIndirectDataOid;
+ UINT8 *Ptr;
+ UINT8 *End;
+ INT32 Len;
+ UINTN ObjLen;
+
+ OrigAuthData = AuthData;
+
+ //
+ // Check input parameters.
+ //
+ if ((AuthData == NULL) || (TrustedCert == NULL) || (ImageHash == NULL)) {
+ return FALSE;
+ }
+
+ if ((DataSize > INT_MAX) || (CertSize > INT_MAX) || (HashSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ if (DataSize <= HashSize) {
+ return FALSE;
+ }
+
+ Ptr = (UINT8 *)(UINTN)AuthData;
+ Len = (UINT32)DataSize;
+ End = Ptr + Len;
+
+ // ContentInfo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // ContentType
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // content
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ End = Ptr + ObjLen;
+ // signedData
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // version
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // digestAlgo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // encapContentInfo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ End = Ptr + ObjLen;
+ // eContentType
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+
+ SpcIndirectDataOid = Ptr;
+ if ((ObjLen != sizeof (mSpcIndirectOidValue)) ||
+ (CompareMem (
+ SpcIndirectDataOid,
+ mSpcIndirectOidValue,
+ sizeof (mSpcIndirectOidValue)
+ ) != 0))
+ {
+ //
+ // Un-matched SPC_INDIRECT_DATA_OBJID.
+ //
+ goto _Exit;
+ }
+
+ Ptr += ObjLen;
+ // eContent
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ SpcIndirectDataContent = Ptr;
+
+ //
+ // 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 (ContentSize < HashSize) {
+ return FALSE;
+ }
+
+ 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:
+
+ return Status;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118118): https://edk2.groups.io/g/devel/message/118118
Mute This Topic: https://groups.io/mt/105683592/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [edk2-devel] [PATCH v2 9/9] CryptoPkg: Add ImageTimestampVerify based on Mbedtls
2024-04-23 2:34 [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
` (7 preceding siblings ...)
2024-04-23 2:34 ` [edk2-devel] [PATCH v2 8/9] CryptoPkg: Add AuthenticodeVerify " Wenxing Hou
@ 2024-04-23 2:34 ` Wenxing Hou
8 siblings, 0 replies; 10+ messages in thread
From: Wenxing Hou @ 2024-04-23 2:34 UTC (permalink / raw)
To: devel; +Cc: Jiewen Yao, Yi Li
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177
Timestamp Countersignature Verification implementaion based on Mbedtls.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
---
.../Library/BaseCryptLibMbedTls/Pk/CryptTs.c | 381 ++++++++++++++++++
1 file changed, 381 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptTs.c
diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptTs.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptTs.c
new file mode 100644
index 0000000000..d3fa205f9c
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptTs.c
@@ -0,0 +1,381 @@
+/** @file
+ RFC3161 Timestamp Countersignature Verification Wrapper Implementation which does
+ not provide real capabilities.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <mbedtls/asn1.h>
+
+//
+// OID ASN.1 Value for SPC_RFC3161_OBJID ("1.3.6.1.4.1.311.3.3.1")
+//
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 mSpcRFC3161OidValue[] = {
+ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x03, 0x03, 0x01
+};
+
+/**
+ Convert ASN.1 GeneralizedTime to EFI Time.
+
+ @param[in] Ptr Pointer to the ASN.1 GeneralizedTime to be converted.
+ @param[out] EfiTime Return the corresponding EFI Time.
+
+ @retval TRUE The time conversion succeeds.
+ @retval FALSE Invalid parameters.
+
+**/
+STATIC
+BOOLEAN
+ConvertAsn1TimeToEfiTime (
+ IN UINT8 *Ptr,
+ OUT EFI_TIME *EfiTime
+ )
+{
+ CONST CHAR8 *Str;
+ UINTN Index;
+
+ if ((Ptr == NULL) || (EfiTime == NULL)) {
+ return FALSE;
+ }
+
+ Str = (CONST CHAR8 *)Ptr;
+ SetMem (EfiTime, sizeof (EFI_TIME), 0);
+
+ Index = 0;
+
+ /* 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;
+}
+
+/**
+ 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
+ )
+{
+ BOOLEAN Status;
+ UINT8 *Ptr;
+ UINT8 *End;
+ INT32 Len;
+ UINTN ObjLen;
+ UINT8 *TempPtr;
+
+ //
+ // Initializations
+ //
+ if (SigningTime != NULL) {
+ SetMem (SigningTime, sizeof (EFI_TIME), 0);
+ }
+
+ //
+ // Input Parameters Checking.
+ //
+ if ((AuthData == NULL) || (TsaCert == NULL)) {
+ return FALSE;
+ }
+
+ if ((DataSize > INT_MAX) || (CertSize > INT_MAX)) {
+ return FALSE;
+ }
+
+ Ptr = (UINT8 *)(UINTN)AuthData;
+ Len = (UINT32)DataSize;
+ End = Ptr + Len;
+
+ // ContentInfo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // ContentType
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // content
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ End = Ptr + ObjLen;
+ // signedData
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // version
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // digestAlgo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // encapContentInfo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // cert
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ TempPtr = Ptr;
+ // OPTIONAL CRLs
+ if (mbedtls_asn1_get_tag (&TempPtr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) {
+ Ptr = TempPtr + ObjLen;
+ }
+
+ // signerInfo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) {
+ return FALSE;
+ }
+
+ // sub parse
+ // signerInfo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ End = Ptr + ObjLen;
+
+ // version
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // sid
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // digestalgo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // OPTIONAL AuthenticatedAttributes
+ TempPtr = Ptr;
+ if (mbedtls_asn1_get_tag (&TempPtr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) {
+ Ptr = TempPtr + ObjLen;
+ }
+
+ // signaturealgo
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // signature
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OCTET_STRING) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // OPTIONAL UnauthenticatedAttributes
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, 0xA1) != 0) {
+ return FALSE;
+ }
+
+ // Attribute
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // type
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ if (CompareMem (Ptr, mSpcRFC3161OidValue, sizeof (mSpcRFC3161OidValue)) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // values
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) {
+ return FALSE;
+ }
+
+ // values
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // signedData OID
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // [0]
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // integer
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // SET
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // tST OID
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) {
+ return FALSE;
+ }
+
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OCTET_STRING) != 0) {
+ return FALSE;
+ }
+
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ // Integer
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // policy OID
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // sequence
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+ // Integer
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) {
+ return FALSE;
+ }
+
+ Ptr += ObjLen;
+
+ // GeneralizedTime
+ if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_GENERALIZED_TIME) != 0) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the signing time from TS_TST_INFO structure.
+ //
+ if (SigningTime != NULL) {
+ SetMem (SigningTime, sizeof (EFI_TIME), 0);
+ Status = ConvertAsn1TimeToEfiTime (Ptr, SigningTime);
+ }
+
+ return Status;
+}
--
2.26.2.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118119): https://edk2.groups.io/g/devel/message/118119
Mute This Topic: https://groups.io/mt/105683593/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 10+ messages in thread