From acfd991b68f099ff0c8eef69f7d3160b86dff573 Mon Sep 17 00:00:00 2001 From: Wenxing Hou Date: Sun, 7 Apr 2024 15:20:48 +0800 Subject: 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 and only support 0 or 1 certificates in Signed data, the patch implement Pkcs7 by low Mbedtls Api. And the implementation has pass unit_tes and integration test. Cc: Jiewen Yao Cc: Yi Li Signed-off-by: Wenxing Hou Reviewed-by: Yi Li Acked-by: Jiewen Yao --- CryptoPkg/Include/Library/BaseCryptLib.h | 2 + .../Library/BaseCryptLibMbedTls/InternalCryptLib.h | 33 + .../BaseCryptLibMbedTls/Pk/CryptPkcs7Internal.h | 29 +- .../BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c | 635 +++++++++ .../BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c | 113 ++ .../Pk/CryptPkcs7VerifyCommon.c | 1354 ++++++++++++++++++++ .../BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c | 689 ++++++++++ 7 files changed, 2843 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 (limited to 'CryptoPkg') diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h b/CryptoPkg/Include/Library/BaseCryptLib.h index 111df8e..ac5841f 100644 --- a/CryptoPkg/Include/Library/BaseCryptLib.h +++ b/CryptoPkg/Include/Library/BaseCryptLib.h @@ -2351,6 +2351,8 @@ Pkcs7FreeSigners ( unchained to the signer's certificates. The input signed data could be wrapped in a ContentInfo structure. + Pkcs7GetCertificatesList has not been implemented in BaseCryptoLibMbedTls. + @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 diff --git a/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h b/CryptoPkg/Library/BaseCryptLibMbedTls/InternalCryptLib.h index a30666c..c9f19dd 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 207f493..cbdd1dc 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.
+Copyright (c) 2023-2024, Intel Corporation. All rights reserved.
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 0000000..e3283da --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c @@ -0,0 +1,635 @@ +/** @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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CryptPkcs7Internal.h" +#include + +/// +/// 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; + + // + // Check input parameters. + // + if ((PrivateKey == NULL) || (KeyPassword == NULL) || (InData == NULL) || + (SignCert == NULL) || (SignedData == NULL) || (SignedDataSize == NULL) || (InDataSize > INT_MAX)) + { + return FALSE; + } + + 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 { + Ret = mbedtls_oid_get_oid_by_sig_alg (MBEDTLS_PK_ECDSA, MBEDTLS_MD_SHA256, (CONST CHAR8 **)&SignerInfo.SigAlgIdentifier.p, &SignerInfo.SigAlgIdentifier.len); + if (Ret != 0) { + Status = FALSE; + goto Cleanup; + } + } + + 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 == 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); + if (*SignedData == NULL) { + Status = FALSE; + goto Cleanup; + } + + *SignedDataSize = Len; + CopyMem (*SignedData, Ptr, Len); + Status = TRUE; + +Cleanup: + if (&Pkey != NULL) { + mbedtls_pk_free (&Pkey); + } + + if (NewPrivateKey != NULL) { + memset (NewPrivateKey, 0, PrivateKeySize); + FreePool (NewPrivateKey); + } + + if (Buffer != NULL) { + memset (Buffer, 0, BufferSize); + 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 0000000..6b62ee2 --- /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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "InternalCryptLib.h" +#include + +/** + 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 0000000..e9f1b0e --- /dev/null +++ b/CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c @@ -0,0 +1,1354 @@ +/** @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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CryptPkcs7Internal.h" +#include + +/* 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; + + 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 = mbedtls_calloc (1, 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) { + mbedtls_x509_crt_free (MoreCert); + MoreCert = NULL; + } + } else { + if (SignedData->Certificates.next != NULL) { + TempCrt = SignedData->Certificates.next; + mbedtls_x509_crt_free (TempCrt); + } + } + + 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->serial.p == NULL) || (Cert->issuer_raw.p == NULL)) { + return 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; + + // + // Check input parameters. + // + if ((P7Data == NULL) || (TrustedCert == NULL) || (InData == NULL) || + (P7Length > INT_MAX) || (CertLength > INT_MAX) || (DataLength > INT_MAX)) + { + return FALSE; + } + + Status = WrapPkcs7Data (P7Data, P7Length, &Wrapped, &WrapData, &WrapDataSize); + + if (!Status) { + return FALSE; + } + + Status = FALSE; + MbedTlsPkcs7Init (&Pkcs7); + mbedtls_x509_crt_init (&Crt); + + Ret = MbedtlsPkcs7ParseDer (WrapData, (INT32)WrapDataSize, &Pkcs7); + if (Ret != 0) { + goto Cleanup; + } + + Ret = mbedtls_x509_crt_parse_der (&Crt, TrustedCert, CertLength); + if (Ret != 0) { + goto Cleanup; + } + + Status = MbedTlsPkcs7SignedDataVerify (&Pkcs7, &Crt, InData, (INT32)DataLength); + +Cleanup: + if (&Crt != NULL) { + mbedtls_x509_crt_free (&Crt); + } + + if (Pkcs7.SignedData.Certificates.next != NULL) { + TempCrt = Pkcs7.SignedData.Certificates.next; + mbedtls_x509_crt_free (TempCrt); + } + + 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; + + 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); + FreePool (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; + mbedtls_x509_crt_free (TempCrt); + } + } + + 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 0000000..47a8230 --- /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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include "InternalCryptLib.h" +#include +#include + +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; + return Status; + } + + 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; +} -- cgit v1.1