public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Li, Yi" <yi1.li@intel.com>
To: "Hou, Wenxing" <wenxing.hou@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Yao, Jiewen" <jiewen.yao@intel.com>
Subject: Re: [edk2-devel] [PATCH 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtls
Date: Mon, 22 Apr 2024 07:52:47 +0000	[thread overview]
Message-ID: <SJ1PR11MB6227661275FC4BC7E915B3AAC5122@SJ1PR11MB6227.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20240416075118.4799-6-wenxing.hou@intel.com>

The pools used to store cert chain are not released properly, which will lead to memory leak problems
Please ensure MbedtlsPkcs7SignedData.Certificates are handled correctly when:
  1. error occurred in Pkcs7GetSigner/SignedData
  2. Pkcs7Verify finished.

Regards,
Yi

-----Original Message-----
From: Hou, Wenxing <wenxing.hou@intel.com> 
Sent: Tuesday, April 16, 2024 3:51 PM
To: devel@edk2.groups.io
Cc: Yao, Jiewen <jiewen.yao@intel.com>; Li, Yi1 <yi1.li@intel.com>
Subject: [PATCH 5/9] CryptoPkg: Add Pkcs7 related functions based on Mbedtls

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                   |   20 +-
 .../BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c   |  615 ++++++++
 .../Pk/CryptPkcs7VerifyBase.c                 |  113 ++
 .../Pk/CryptPkcs7VerifyCommon.c               | 1315 +++++++++++++++++
 .../Pk/CryptPkcs7VerifyEku.c                  |  689 +++++++++
 6 files changed, 2773 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 e2c7e42ecb..1b9742c166 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..d4bdb0abf7 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,18 @@ 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;

 

 #endif

diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c
new file mode 100644
index 0000000000..e4d2d7a2a8
--- /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]  P           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              **P,

+  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 (P, (CONST UINT8 *)Start, (CONST CHAR8 *)OidPtr, OidLen);

+  }

+

+  return 0;

+}

+

+/**

+  DigestAlgorithmIdentifiers ::=

+  SET OF DigestAlgorithmIdentifier.

+

+  @param[in, out]  P           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              **P,

+  UINT8              *Start,

+  mbedtls_md_type_t  *DigestTypes,

+  INTN               Count

+  )

+{

+  INTN   Idx;

+  INT32  Len;

+  INT32  ret;

+

+  Len = 0;

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_null (P, Start));

+

+  for (Idx = 0; Idx < Count; Idx++) {

+    MBEDTLS_ASN1_CHK_ADD (

+      Len,

+      MbedTlsPkcs7WriteDigestAlgorithm (P, Start, DigestTypes[Idx])

+      );

+  }

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, (UINTN)Len));

+

+  MBEDTLS_ASN1_CHK_ADD (

+    Len,

+    mbedtls_asn1_write_tag (

+      P,

+      Start,

+      (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)

+      )

+    );

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, (UINTN)Len));

+

+  MBEDTLS_ASN1_CHK_ADD (

+    Len,

+    mbedtls_asn1_write_tag (

+      P,

+      Start,

+      (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)

+      )

+    );

+

+  return Len;

+}

+

+/**

+   ContentInfo ::= SEQUENCE {

+        contentType ContentType,

+        content

+                [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }.

+

+  @param[in, out]  P           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  **P,

+  UINT8  *Start,

+  UINT8  *Content,

+  INTN   ContentLen

+  )

+{

+  INT32  ret;

+  INT32  Len;

+

+  Len = 0;

+  if (Content != NULL) {

+    MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (P, Start, Content, ContentLen));

+  }

+

+  MBEDTLS_ASN1_CHK_ADD (

+    Len,

+    mbedtls_asn1_write_oid (

+      P,

+      Start,

+      MBEDTLS_OID_PKCS7_DATA,

+      sizeof (MBEDTLS_OID_PKCS7_DATA) - 1

+      )

+    );

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, 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]  P           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             **P,

+  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) {

+    MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (P, Start, TmpCert->raw.p, TmpCert->raw.len));

+    TmpCert = TmpCert->next;

+  }

+

+  /// Write Cert

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (P, Start, Cert->raw.p, Cert->raw.len));

+

+  /// Write NextContext

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));

+  return Len;

+}

+

+/**

+  write Pkcs7 Int.

+

+  @param[in, out]  P            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  **P,

+  UINT8  *Start,

+  UINT8  *SerialRaw,

+  INTN   SerialRawLen

+  )

+{

+  INT32  ret;

+  UINT8  *Ptr;

+  INT32  Len;

+

+  Len = 0;

+  Ptr = SerialRaw + SerialRawLen;

+  while (Ptr > SerialRaw) {

+    *--(*P) = *--Ptr;

+    Len++;

+  }

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN1_INTEGER));

+

+  return Len;

+}

+

+/**

+  write Pkcs7 Issuer And SerialNumber.

+

+  @param[in, out]  P            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  **P,

+  UINT8  *Start,

+  UINT8  *Serial,

+  INTN   SerialLen,

+  UINT8  *IssuerRaw,

+  INTN   IssuerRawLen

+  )

+{

+  INT32  ret;

+  INT32  Len;

+

+  Len = 0;

+  MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteInt (P, Start, Serial, SerialLen));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (P, Start, IssuerRaw, IssuerRawLen));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, 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]  P            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                   **P,

+  UINT8                   *Start,

+  MbedtlsPkcs7SignerInfo  *SignerInfo

+  )

+{

+  INT32  ret;

+  INT32  Len;

+

+  Len = 0;

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (P, Start, SignerInfo->Sig.p, SignerInfo->Sig.len));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (P, Start, (CONST CHAR8 *)SignerInfo->SigAlgIdentifier.p, SignerInfo->SigAlgIdentifier.len, 0));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (P, Start, (CONST CHAR8 *)SignerInfo->AlgIdentifier.p, SignerInfo->AlgIdentifier.len, 0));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteIssuerAndSerialNumber (P, Start, SignerInfo->Serial.p, SignerInfo->Serial.len, SignerInfo->IssuerRaw.p, SignerInfo->IssuerRaw.len));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (P, Start, SignerInfo->Version));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

+

+  return Len;

+}

+

+/**

+  write Pkcs7 Signers Info Set.

+

+  @param[in, out]  P            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                   **P,

+  UINT8                   *Start,

+  MbedtlsPkcs7SignerInfo  *SignersSet

+  )

+{

+  MbedtlsPkcs7SignerInfo  *SignerInfo;

+  INT32                   ret;

+  INT32                   Len;

+

+  SignerInfo = SignersSet;

+  Len        = 0;

+

+  while (SignerInfo != NULL) {

+    MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignerInfo (P, Start, SignerInfo));

+    // move to next

+    SignerInfo = SignerInfo->Next;

+  }

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, 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]  P            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         **P,

+  UINT8         *Start,

+  MbedtlsPkcs7  *Pkcs7

+  )

+{

+  INT32              ret;

+  INT32              Len;

+  mbedtls_md_type_t  DigestAlg[1];

+

+  DigestAlg[0] = MBEDTLS_MD_SHA256;

+  Len          = 0;

+

+  MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignersInfoSet (P, Start, &(Pkcs7->SignedData.SignerInfos)));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteCertificates (P, Start, &(Pkcs7->SignedData.Certificates), Pkcs7->SignedData.Certificates.next));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteContentInfo (P, Start, NULL, 0));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteDigestAlgorithmSet (P, Start, DigestAlg, 1));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (P, Start, Pkcs7->SignedData.Version));

+

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (P, Start, Len));

+  MBEDTLS_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (P, 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                   *P;

+  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;

+  }

+

+  P   = Buffer + BufferSize;

+  Len = MbedTlsPkcs7WriteDer (&P, Buffer, &Pkcs7);

+

+  /// Enlarge buffer if buffer is too small

+  while (Len < 0 && Len == MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) {

+    BufferSize = BufferSize * 2;

+    P          = Buffer + BufferSize;

+    FreePool (Buffer);

+    Buffer = AllocateZeroPool (BufferSize);

+    if (Buffer == NULL) {

+      Status = FALSE;

+      goto Cleanup;

+    }

+

+    P   = Buffer + BufferSize;

+    Len = MbedTlsPkcs7WriteDer (&P, Buffer, &Pkcs7);

+  }

+

+  if (Len <= 0) {

+    Status = FALSE;

+    goto Cleanup;

+  }

+

+  *SignedData     = AllocateZeroPool (Len);

+  *SignedDataSize = Len;

+  CopyMem (*SignedData, P, 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..f5ca4c528a
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c
@@ -0,0 +1,1315 @@
+/** @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]  P            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  **P,

+  UINT8  *End,

+  UINTN  *Len

+  )

+{

+  INT32  Ret;

+

+  Ret = mbedtls_asn1_get_tag (P, End, Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC);

+  return Ret;

+}

+

+/**

+  Get Pkcs7 Version..

+

+  @param[in]  P            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  **P,

+  UINT8  *End,

+  INT32  *Ver

+  )

+{

+  INT32  Ret;

+

+  Ret = mbedtls_asn1_get_int (P, End, Ver);

+  return Ret;

+}

+

+/**

+   ContentInfo ::= SEQUENCE {

+        contentType ContentType,

+        content

+                [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }.

+

+  @param[in]  P            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             **P,

+  UINT8             *End,

+  mbedtls_asn1_buf  *Pkcs7

+  )

+{

+  UINTN  Len;

+  int    Ret;

+

+  Len = 0;

+  Ret = mbedtls_asn1_get_tag (

+          P,

+          End,

+          &Len,

+          MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE

+          );

+

+  if (Ret == 0) {

+    Ret = mbedtls_asn1_get_tag (P, End, &Len, MBEDTLS_ASN1_OID);

+  }

+

+  if (Ret == 0) {

+    Pkcs7->tag = MBEDTLS_ASN1_OID;

+    Pkcs7->len = Len;

+    Pkcs7->p   = *P;

+  }

+

+  return Ret;

+}

+

+/**

+  DigestAlgorithmIdentifier ::= AlgorithmIdentifier.

+

+  @param[in]  P            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             **P,

+  UINT8             *End,

+  mbedtls_x509_buf  *Alg

+  )

+{

+  INT32  Ret;

+

+  Ret = mbedtls_asn1_get_alg_null (P, End, Alg);

+  return Ret;

+}

+

+/**

+  DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier.

+

+  @param[in]  P            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             **P,

+  UINT8             *End,

+  mbedtls_x509_buf  *Alg

+  )

+{

+  UINTN  Len;

+  INT32  Ret;

+

+  Len = 0;

+  Ret = mbedtls_asn1_get_tag (

+          P,

+          End,

+          &Len,

+          MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET

+          );

+

+  if (Ret == 0) {

+    End = *P + Len;

+    // assume only one digest algorithm

+    Ret = mbedtls_asn1_get_alg_null (P, End, Alg);

+  }

+

+  return Ret;

+}

+

+/**

+   certificates :: SET OF ExtendedCertificateOrCertificate,

+   ExtendedCertificateOrCertificate ::= CHOICE {

+        certificate Certificate -- x509,

+        extendedCertificate[0] IMPLICIT ExtendedCertificate }.

+

+  @param[in]  P            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             **P,

+  INTN              Plen,

+  mbedtls_x509_crt  *Certs

+  )

+{

+  INT32  Ret;

+

+  Ret = mbedtls_x509_crt_parse (Certs, *P, Plen);

+  return Ret;

+}

+

+/**

+   EncryptedDigest ::= OCTET STRING.

+

+  @param[in]  P            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             **P,

+  UINT8             *End,

+  mbedtls_asn1_buf  *Signature

+  )

+{

+  INT32  Ret;

+  UINTN  Len;

+

+  Len = 0;

+  Ret = mbedtls_asn1_get_tag (P, End, &Len, MBEDTLS_ASN1_OCTET_STRING);

+  if (Ret == 0) {

+    Signature->tag = MBEDTLS_ASN1_OCTET_STRING;

+    Signature->len = Len;

+    Signature->p   = *P;

+  }

+

+  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]  P            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                   **P,

+  UINT8                   *End,

+  MbedtlsPkcs7SignerInfo  *SignersSet

+  )

+{

+  UINT8  *EndSet;

+  INT32  Ret;

+  UINTN  Len;

+  UINT8  *TempP;

+

+  Len = 0;

+

+  Ret = mbedtls_asn1_get_tag (

+          P,

+          End,

+          &Len,

+          MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET

+          );

+

+  if (Ret == 0) {

+    EndSet = *P + Len;

+

+    Ret = mbedtls_asn1_get_tag (

+            P,

+            EndSet,

+            &Len,

+            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE

+            );

+  }

+

+  if (Ret == 0) {

+    Ret = mbedtls_asn1_get_int (P, EndSet, &SignersSet->Version);

+  }

+

+  if (Ret == 0) {

+    Ret = mbedtls_asn1_get_tag (

+            P,

+            EndSet,

+            &Len,

+            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE

+            );

+  }

+

+  if (Ret == 0) {

+    SignersSet->IssuerRaw.p = *P;

+    Ret                     = mbedtls_asn1_get_tag (

+                                P,

+                                EndSet,

+                                &Len,

+                                MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE

+                                );

+  }

+

+  if (Ret == 0) {

+    Ret = mbedtls_x509_get_name (P, *P + Len, &SignersSet->Issuer);

+  }

+

+  if (Ret == 0) {

+    SignersSet->IssuerRaw.len = *P - SignersSet->IssuerRaw.p;

+

+    Ret = mbedtls_x509_get_serial (P, EndSet, &SignersSet->Serial);

+  }

+

+  if (Ret == 0) {

+    Ret = MbedTlsPkcs7GetDigestAlgorithm (P, EndSet, &SignersSet->AlgIdentifier);

+  }

+

+  // OPTIONAL AuthenticatedAttributes

+  if (Ret == 0) {

+    TempP = *P;

+    if (mbedtls_asn1_get_tag (&TempP, EndSet, &Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) {

+      SignersSet->AuthAttr.len = Len + (TempP - *P);

+      SignersSet->AuthAttr.p   = *P;

+      *P                       = TempP + Len;

+    } else {

+      SignersSet->AuthAttr.p = NULL;

+    }

+  }

+

+  if (Ret == 0) {

+    Ret = MbedTlsPkcs7GetDigestAlgorithm (P, EndSet, &SignersSet->SigAlgIdentifier);

+  }

+

+  if (Ret == 0) {

+    Ret = Pkcs7GetSignature (P, 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             *P;

+  UINT8             *End;

+  UINTN             Len;

+  INT32             Ret;

+  UINT8             *CertP;

+  UINTN             CertLen;

+  UINT8             *OldCertP;

+  UINTN             TotalCertLen;

+  mbedtls_x509_crt  *MoreCert;

+  UINT8             CertNum;

+  mbedtls_x509_crt  *LastCert;

+

+  Len      = 0;

+  P        = Buffer;

+  End      = Buffer + BufferLen;

+  MoreCert = NULL;

+

+  Ret = mbedtls_asn1_get_tag (

+          &P,

+          End,

+          &Len,

+          MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE

+          );

+

+  if (Ret == 0) {

+    // version

+    Ret = MbedTlsPkcs7GetVersion (&P, End, &SignedData->Version);

+  }

+

+  if ((Ret == 0) && (SignedData->Version != 1)) {

+    Ret = -1;

+  }

+

+  if (Ret == 0) {

+    // digest algorithm

+    Ret = MbedTlsPkcs7GetDigestAlgorithmSet (

+            &P,

+            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 (&P, End, &SignedData->ContentInfo.Oid);

+  }

+

+  if (Ret == 0) {

+    // move to next

+    P     = P + SignedData->ContentInfo.Oid.len;

+    Ret   = MbedTlsPkcs7GetNextContentLen (&P, End, &Len);

+    CertP = P + Len;

+

+    // move to actual cert, if there are more [0]

+    if (MbedTlsPkcs7GetNextContentLen (&CertP, End, &CertLen) == 0) {

+      Len = CertLen;

+      P   = CertP;

+    }

+  }

+

+  // certificates: may have many certs

+  CertP = P;

+

+  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 End;

+    }

+

+    // 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 End;

+    }

+

+    CertNum++;

+    MoreCert->next = AllocateZeroPool (sizeof (mbedtls_x509_crt));

+    MoreCert       = MoreCert->next;

+  }

+

+  if (TotalCertLen != Len) {

+    Ret = -1;

+    goto End;

+  }

+

+  LastCert = &(SignedData->Certificates);

+

+  while (CertNum--) {

+    if (CertNum == 0) {

+      LastCert->next = NULL;

+      break;

+    } else {

+      LastCert = LastCert->next;

+    }

+  }

+

+  // signers info

+  if (Ret == 0) {

+    P   = P + Len;

+    Ret = MbedTlsPkcs7GetSignersInfoSet (&P, End, &SignedData->SignerInfos);

+  }

+

+End:

+  if (MoreCert != NULL) {

+    FreePool (MoreCert);

+    MoreCert = NULL;

+  }

+

+  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  *P;

+  UINT8  *End;

+  UINTN  Len;

+  INT32  Ret;

+

+  if (Pkcs7 == NULL) {

+    return -1;

+  }

+

+  Len = 0;

+  P   = (UINT8 *)Buffer;

+  End = P + BufferLen;

+

+  Ret = Pkcs7GetContentInfoType (&P, 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) || (CompareMem (Pkcs7->ContentTypeOid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_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

+  P = P + Pkcs7->ContentTypeOid.len;

+

+  Ret = MbedTlsPkcs7GetNextContentLen (&P, End, &Len);

+  if (Ret != 0) {

+    goto out;

+  }

+

+  Ret = Pkcs7GetSignedData (P, 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] == 0x06) && (P7Data[5] == 0x09)) {

+    if (CompareMem (P7Data + 6, MBEDTLS_OID_PKCS7_SIGNED_DATA, sizeof (MBEDTLS_OID_PKCS7_SIGNED_DATA) - 1) == 0) {

+      if ((P7Data[15] == 0xA0) && (P7Data[16] == 0x82)) {

+        Wrapped = TRUE;

+      }

+    }

+  }

+

+  if (Wrapped) {

+    *WrapData     = (UINT8 *)P7Data;

+    *WrapDataSize = P7Length;

+  } else {

+    //

+    // Wrap PKCS#7 signeddata to a ContentInfo structure - add a header in 19 bytes.

+    //

+    *WrapDataSize = P7Length + 19;

+    *WrapData     = AllocateZeroPool (*WrapDataSize);

+    if (*WrapData == NULL) {

+      *WrapFlag = Wrapped;

+      return FALSE;

+    }

+

+    SignedData = *WrapData;

+

+    //

+    // Part1: 0x30, 0x82.

+    //

+    SignedData[0] = 0x30;

+    SignedData[1] = 0x82;

+

+    //

+    // Part2: Length1 = P7Length + 19 - 4, in big endian.

+    //

+    SignedData[2] = (UINT8)(((UINT16)(*WrapDataSize - 4)) >> 8);

+    SignedData[3] = (UINT8)(((UINT16)(*WrapDataSize - 4)) & 0xff);

+

+    //

+    // Part3: 0x06, 0x09.

+    //

+    SignedData[4] = 0x06;

+    SignedData[5] = 0x09;

+

+    //

+    // Part4: OID value -- 0x2A 0x86 0x48 0x86 0xF7 0x0D 0x01 0x07 0x02.

+    //

+    CopyMem (SignedData + 6, MBEDTLS_OID_PKCS7_SIGNED_DATA, sizeof (MBEDTLS_OID_PKCS7_SIGNED_DATA) - 1);

+

+    //

+    // Part5: 0xA0, 0x82.

+    //

+    SignedData[15] = 0xA0;

+    SignedData[16] = 0x82;

+

+    //

+    // Part6: Length2 = P7Length, in big endian.

+    //

+    SignedData[17] = (UINT8)(((UINT16)P7Length) >> 8);

+    SignedData[18] = (UINT8)(((UINT16)P7Length) & 0xff);

+

+    //

+    // Part7: P7Data.

+    //

+    CopyMem (SignedData + 19, P7Data, P7Length);

+  }

+

+  *WrapFlag = Wrapped;

+  return TRUE;

+}

+

+/**

+  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;

+

+  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);

+  }

+

+  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;

+

+  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 (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..23ea676373
--- /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 (#118072): https://edk2.groups.io/g/devel/message/118072
Mute This Topic: https://groups.io/mt/105552835/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2024-04-22  7:52 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-16  7:51 [edk2-devel] [PATCH 0/9] Add more crypt APIs based on Mbedtls Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 1/9] CryptoPkg: Add AeadAesGcm " Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 2/9] CryptoPkg: Add rand function for BaseCryptLibMbedTls Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 3/9] CryptoPkg: Add Pem APIs based on Mbedtls Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 4/9] CryptoPkg: Add X509 functions " Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 5/9] CryptoPkg: Add Pkcs7 related " Wenxing Hou
2024-04-22  7:52   ` Li, Yi [this message]
2024-04-16  7:51 ` [edk2-devel] [PATCH 6/9] CryptoPkg: Add Pkcs5 " Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 7/9] CryptoPkg: Add more RSA related " Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 8/9] CryptoPkg: Add AuthenticodeVerify " Wenxing Hou
2024-04-16  7:51 ` [edk2-devel] [PATCH 9/9] CryptoPkg: Add ImageTimestampVerify " Wenxing Hou
2024-04-22  7:53 ` [edk2-devel] [PATCH 0/9] Add more crypt APIs " Li, Yi

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=SJ1PR11MB6227661275FC4BC7E915B3AAC5122@SJ1PR11MB6227.namprd11.prod.outlook.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