public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Wenxing Hou" <wenxing.hou@intel.com>
To: devel@edk2.groups.io
Cc: Jiewen Yao <jiewen.yao@intel.com>, Yi Li <yi1.li@intel.com>
Subject: [edk2-devel] [PATCH v2 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtls
Date: Tue, 23 Apr 2024 10:34:28 +0800	[thread overview]
Message-ID: <20240423023432.2147-6-wenxing.hou@intel.com> (raw)
In-Reply-To: <20240423023432.2147-1-wenxing.hou@intel.com>

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]
-=-=-=-=-=-=-=-=-=-=-=-



  parent reply	other threads:[~2024-04-23  2:34 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 ` Wenxing Hou [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240423023432.2147-6-wenxing.hou@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox