public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH v2 0/9] Add more crypt APIs based on Mbedtls
@ 2024-04-23  2:34 Wenxing Hou
  2024-04-23  2:34 ` [edk2-devel] [PATCH v2 1/9] CryptoPkg: Add AeadAesGcm " Wenxing Hou
                   ` (8 more replies)
  0 siblings, 9 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 AeadAesGcm/Pem(only RSA)/X509(only RSA)/More RSA/PKCS5/pKCS7/Authenticode/Timestamp
implementation based on Mbedtls.

The patch has passed the EDKII CI check:
https://github.com/tianocore/edk2/pull/5552

And the patch has passed unit_test in EDKII and integration test for platform.
And the patch hass passed the fuzz test:
https://github.com/tianocore/edk2-staging/commit/4f19398053c92e4f7791d468a184530b6ab89128

v2 changes:
 - Fix format variable name/hardcode number issue;
 - Fix Pkcs7 memory leak;

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>

Wenxing Hou (9):
  CryptoPkg: Add AeadAesGcm based on Mbedtls
  CryptoPkg: Add rand function for BaseCryptLibMbedTls
  CryptoPkg: Add Pem APIs based on Mbedtls
  CryptoPkg: Add X509 functions based on Mbedtls
  CryptoPkg: Add Pkcs7 related functions based on Mbedtls
  CryptoPkg: Add Pkcs5 functions based on Mbedtls
  CryptoPkg: Add more RSA related functions based on Mbedtls
  CryptoPkg: Add AuthenticodeVerify based on Mbedtls
  CryptoPkg: Add ImageTimestampVerify based on Mbedtls

 .../Cipher/CryptAeadAesGcm.c                  |  227 ++
 .../BaseCryptLibMbedTls/InternalCryptLib.h    |   49 +
 .../BaseCryptLibMbedTls/Pem/CryptPem.c        |  138 ++
 .../Pk/CryptAuthenticode.c                    |  214 ++
 .../BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c   |  278 +++
 .../BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c |  100 +
 .../Pk/CryptPkcs7Internal.h                   |   29 +-
 .../BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c   |  615 ++++++
 .../Pk/CryptPkcs7VerifyBase.c                 |  113 +
 .../Pk/CryptPkcs7VerifyCommon.c               | 1363 ++++++++++++
 .../Pk/CryptPkcs7VerifyEku.c                  |  689 ++++++
 .../BaseCryptLibMbedTls/Pk/CryptRsaExt.c      |  346 +++
 .../BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c  |  137 ++
 .../Library/BaseCryptLibMbedTls/Pk/CryptTs.c  |  381 ++++
 .../BaseCryptLibMbedTls/Pk/CryptX509.c        | 1925 +++++++++++++++++
 .../BaseCryptLibMbedTls/Rand/CryptRand.c      |  105 +
 .../BaseCryptLibMbedTls/Rand/CryptRandTsc.c   |  105 +
 17 files changed, 6802 insertions(+), 12 deletions(-)
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Cipher/CryptAeadAesGcm.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pem/CryptPem.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptAuthenticode.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs1Oaep.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs5Pbkdf2.c
 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
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaExt.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptRsaPssSign.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptTs.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptX509.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRand.c
 create mode 100644 CryptoPkg/Library/BaseCryptLibMbedTls/Rand/CryptRandTsc.c

-- 
2.26.2.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118110): https://edk2.groups.io/g/devel/message/118110
Mute This Topic: https://groups.io/mt/105683584/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [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

end of thread, other threads:[~2024-04-23  2:34 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [edk2-devel] [PATCH v2 3/9] CryptoPkg: Add Pem APIs based on Mbedtls Wenxing Hou
2024-04-23  2:34 ` [edk2-devel] [PATCH v2 4/9] CryptoPkg: Add X509 functions " Wenxing Hou
2024-04-23  2:34 ` [edk2-devel] [PATCH v2 5/9] CryptoPkg: Add Pkcs7 related " Wenxing Hou
2024-04-23  2:34 ` [edk2-devel] [PATCH v2 6/9] CryptoPkg: Add Pkcs5 " Wenxing Hou
2024-04-23  2:34 ` [edk2-devel] [PATCH v2 7/9] CryptoPkg: Add more RSA related " 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox