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 <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
Reviewed-by: Yi Li <yi1.li@intel.com>
Acked-by: Jiewen Yao <Jiewen.yao@intel.com>
This commit is contained in:
Wenxing Hou 2024-04-07 15:20:48 +08:00 committed by Liming Gao
parent 40fa5cf299
commit acfd991b68
7 changed files with 2843 additions and 12 deletions

View File

@ -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

View File

@ -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

View File

@ -4,7 +4,7 @@
RFC 2315 - PKCS #7: Cryptographic Message Syntax Version 1.5
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2023-2024, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@ -31,10 +31,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x05"
#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x06"
typedef mbedtls_asn1_buf MBEDTLSPKCS7BUF;
typedef mbedtls_asn1_named_data MBEDTLSPKCS7NAME;
typedef mbedtls_asn1_sequence MBEDTLSPKCS7SEQUENCE;
///
/// PKCS7 SignerInfo type
/// https://tools.ietf.org/html/rfc2315#section-9.2
@ -48,8 +44,8 @@ typedef struct MbedtlsPkcs7SignerInfo {
mbedtls_x509_buf SigAlgIdentifier;
mbedtls_x509_buf AuthAttr;
mbedtls_x509_buf Sig;
struct MBEDTLSPKCS7SIGNERINFO *Next;
} MBEDTLSPKCS7SIGNERINFO;
struct MbedtlsPkcs7SignerInfo *Next;
} MbedtlsPkcs7SignerInfo;
///
/// PKCS7 signed data attached data format
@ -57,7 +53,7 @@ typedef struct MbedtlsPkcs7SignerInfo {
typedef struct MbedtlsPkcs7Data {
mbedtls_asn1_buf Oid;
mbedtls_asn1_buf Data;
} MBEDTLSPKCS7DATA;
} MbedtlsPkcs7Data;
///
/// Signed Data
@ -66,18 +62,27 @@ typedef struct MbedtlsPkcs7Data {
typedef struct MbedtlsPkcs7SignedData {
INT32 Version;
mbedtls_asn1_buf DigestAlgorithms;
struct MBEDTLSPKCS7DATA ContentInfo;
struct MbedtlsPkcs7Data ContentInfo;
mbedtls_x509_crt Certificates;
mbedtls_x509_crl Crls;
struct MbedtlsPkcs7SignerInfo SignerInfos;
} MBEDTLSPKCS7SIGNEDDATA;
} MbedtlsPkcs7SignedData;
///
/// PKCS7 struct, only support SignedData
///
typedef struct MbedtlsPkcs7 {
mbedtls_asn1_buf ContentTypeOid;
struct MBEDTLSPKCS7SIGNEDDATA SignedData;
} MBEDTLSPKCS7;
struct MbedtlsPkcs7SignedData SignedData;
} MbedtlsPkcs7;
#define EDKII_ASN1_CHK_ADD(g, f) \
do \
{ \
if( ( Ret = (f) ) < 0 ) \
return( Ret ); \
else \
(g) += Ret; \
} while( 0 )
#endif

View File

@ -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.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "CryptPkcs7Internal.h"
#include <mbedtls/ecdh.h>
///
/// Enough to store any signature generated by PKCS7
///
#define MAX_SIGNATURE_SIZE 1024
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 MbedtlsOidDigestAlgSha256[] = MBEDTLS_OID_DIGEST_ALG_SHA256;
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 MbedtlsOidPkcs1Rsa[] = MBEDTLS_OID_PKCS1_RSA;
/**
Write DigestAlgorithmIdentifier.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] DigestType Digest Type
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteDigestAlgorithm (
UINT8 **Ptr,
UINT8 *Start,
mbedtls_md_type_t DigestType
)
{
UINT8 *OidPtr;
UINTN OidLen;
INT32 Ret;
Ret = mbedtls_oid_get_oid_by_md (DigestType, (CONST CHAR8 **)&OidPtr, &OidLen);
if (Ret == 0) {
return mbedtls_asn1_write_oid (Ptr, (CONST UINT8 *)Start, (CONST CHAR8 *)OidPtr, OidLen);
}
return 0;
}
/**
DigestAlgorithmIdentifiers ::=
SET OF DigestAlgorithmIdentifier.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] DigestTypes Digest Type array.
@param[in] Count The index for Digest Type.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteDigestAlgorithmSet (
UINT8 **Ptr,
UINT8 *Start,
mbedtls_md_type_t *DigestTypes,
INTN Count
)
{
INTN Idx;
INT32 Len;
INT32 Ret;
Len = 0;
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_null (Ptr, Start));
for (Idx = 0; Idx < Count; Idx++) {
EDKII_ASN1_CHK_ADD (
Len,
MbedTlsPkcs7WriteDigestAlgorithm (Ptr, Start, DigestTypes[Idx])
);
}
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, (UINTN)Len));
EDKII_ASN1_CHK_ADD (
Len,
mbedtls_asn1_write_tag (
Ptr,
Start,
(MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
)
);
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, (UINTN)Len));
EDKII_ASN1_CHK_ADD (
Len,
mbedtls_asn1_write_tag (
Ptr,
Start,
(MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET)
)
);
return Len;
}
/**
ContentInfo ::= SEQUENCE {
contentType ContentType,
content
[0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] Content ContentInfo.
@param[in] ContentLen Size of ContentInfo.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteContentInfo (
UINT8 **Ptr,
UINT8 *Start,
UINT8 *Content,
INTN ContentLen
)
{
INT32 Ret;
INT32 Len;
Len = 0;
if (Content != NULL) {
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (Ptr, Start, Content, ContentLen));
}
EDKII_ASN1_CHK_ADD (
Len,
mbedtls_asn1_write_oid (
Ptr,
Start,
MBEDTLS_OID_PKCS7_DATA,
sizeof (MBEDTLS_OID_PKCS7_DATA) - 1
)
);
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
return Len;
}
/**
certificates :: SET OF ExtendedCertificateOrCertificate,
ExtendedCertificateOrCertificate ::= CHOICE {
certificate Certificate -- x509,
extendedCertificate[0] IMPLICIT ExtendedCertificate }.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] Cert Certificate.
@param[in] OtherCerts Ohter Certificate.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteCertificates (
UINT8 **Ptr,
UINT8 *Start,
mbedtls_x509_crt *Cert,
mbedtls_x509_crt *OtherCerts
)
{
INT32 Ret;
INT32 Len;
mbedtls_x509_crt *TmpCert;
Len = 0;
/// Write OtherCerts
TmpCert = OtherCerts;
while (TmpCert != NULL) {
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (Ptr, Start, TmpCert->raw.p, TmpCert->raw.len));
TmpCert = TmpCert->next;
}
/// Write Cert
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (Ptr, Start, Cert->raw.p, Cert->raw.len));
/// Write NextContext
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC));
return Len;
}
/**
write Pkcs7 Int.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] SerialRaw SerialRaw.
@param[in] SerialRawLen Size of SerialRaw.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteInt (
UINT8 **Ptr,
UINT8 *Start,
UINT8 *SerialRaw,
INTN SerialRawLen
)
{
INT32 Ret;
UINT8 *Pt;
INT32 Len;
Len = 0;
Pt = SerialRaw + SerialRawLen;
while (Pt > SerialRaw) {
*--(*Ptr) = *--Pt;
Len++;
}
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_INTEGER));
return Len;
}
/**
write Pkcs7 Issuer And SerialNumber.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] Serial Serial.
@param[in] SerialLen Size of Serial.
@param[in] IssuerRaw IssuerRawLen.
@param[in] IssuerRawLen Size of IssuerRawLen.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteIssuerAndSerialNumber (
UINT8 **Ptr,
UINT8 *Start,
UINT8 *Serial,
INTN SerialLen,
UINT8 *IssuerRaw,
INTN IssuerRawLen
)
{
INT32 Ret;
INT32 Len;
Len = 0;
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteInt (Ptr, Start, Serial, SerialLen));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_raw_buffer (Ptr, Start, IssuerRaw, IssuerRawLen));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
return Len;
}
/**
SignerInfo ::= SEQUENCE {
version Version;
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier,
authenticatedAttributes
[0] IMPLICIT Attributes OPTIONAL,
digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
encryptedDigest EncryptedDigest,
unauthenticatedAttributes
[1] IMPLICIT Attributes OPTIONAL.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] SignerInfo SignerInfo.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteSignerInfo (
UINT8 **Ptr,
UINT8 *Start,
MbedtlsPkcs7SignerInfo *SignerInfo
)
{
INT32 Ret;
INT32 Len;
Len = 0;
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_octet_string (Ptr, Start, SignerInfo->Sig.p, SignerInfo->Sig.len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (Ptr, Start, (CONST CHAR8 *)SignerInfo->SigAlgIdentifier.p, SignerInfo->SigAlgIdentifier.len, 0));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_algorithm_identifier (Ptr, Start, (CONST CHAR8 *)SignerInfo->AlgIdentifier.p, SignerInfo->AlgIdentifier.len, 0));
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteIssuerAndSerialNumber (Ptr, Start, SignerInfo->Serial.p, SignerInfo->Serial.len, SignerInfo->IssuerRaw.p, SignerInfo->IssuerRaw.len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (Ptr, Start, SignerInfo->Version));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
return Len;
}
/**
write Pkcs7 Signers Info Set.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] SignersSet SignerInfo Set.
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteSignersInfoSet (
UINT8 **Ptr,
UINT8 *Start,
MbedtlsPkcs7SignerInfo *SignersSet
)
{
MbedtlsPkcs7SignerInfo *SignerInfo;
INT32 Ret;
INT32 Len;
SignerInfo = SignersSet;
Len = 0;
while (SignerInfo != NULL) {
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignerInfo (Ptr, Start, SignerInfo));
// move to next
SignerInfo = SignerInfo->Next;
}
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET));
return Len;
}
/**
Signed Data Type
SignedData ::= SEQUENCE {
version Version,
digestAlgorithms DigestAlgorithmIdentifiers,
contentInfo ContentInfo,
certificates
[0] IMPLICIT ExtendedCertificatesAndCertificates
OPTIONAL,
crls
[1] IMPLICIT CertificateRevocationLists OPTIONAL,
signerInfos SignerInfos }
DigestAlgorithmIdentifiers ::=
SET OF DigestAlgorithmIdentifier
SignerInfos ::= SET OF SignerInfo.
@param[in, out] Ptr The reference to the current position pointer.
@param[in] Start The start of the buffer, for bounds-checking.
@param[in] Pkcs7 MbedtlsPkcs7
@retval number The number of bytes written to p on success.
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
**/
STATIC
INT32
MbedTlsPkcs7WriteDer (
UINT8 **Ptr,
UINT8 *Start,
MbedtlsPkcs7 *Pkcs7
)
{
INT32 Ret;
INT32 Len;
mbedtls_md_type_t DigestAlg[1];
DigestAlg[0] = MBEDTLS_MD_SHA256;
Len = 0;
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteSignersInfoSet (Ptr, Start, &(Pkcs7->SignedData.SignerInfos)));
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteCertificates (Ptr, Start, &(Pkcs7->SignedData.Certificates), Pkcs7->SignedData.Certificates.next));
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteContentInfo (Ptr, Start, NULL, 0));
EDKII_ASN1_CHK_ADD (Len, MbedTlsPkcs7WriteDigestAlgorithmSet (Ptr, Start, DigestAlg, 1));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_int (Ptr, Start, Pkcs7->SignedData.Version));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_len (Ptr, Start, Len));
EDKII_ASN1_CHK_ADD (Len, mbedtls_asn1_write_tag (Ptr, Start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
return Len;
}
/**
Creates a PKCS#7 signedData as described in "PKCS #7: Cryptographic Message
Syntax Standard, version 1.5". This interface is only intended to be used for
application to perform PKCS#7 functionality validation.
If this interface is not supported, then return FALSE.
@param[in] PrivateKey Pointer to the PEM-formatted private key data for
data signing.
@param[in] PrivateKeySize Size of the PEM private key data in bytes.
@param[in] KeyPassword NULL-terminated passphrase used for encrypted PEM
key data.
@param[in] InData Pointer to the content to be signed.
@param[in] InDataSize Size of InData in bytes.
@param[in] SignCert Pointer to signer's DER-encoded certificate to sign with.
@param[in] OtherCerts Pointer to an optional additional set of certificates to
include in the PKCS#7 signedData (e.g. any intermediate
CAs in the chain).
@param[out] SignedData Pointer to output PKCS#7 signedData. It's caller's
responsibility to free the buffer with FreePool().
@param[out] SignedDataSize Size of SignedData in bytes.
@retval TRUE PKCS#7 data signing succeeded.
@retval FALSE PKCS#7 data signing failed.
@retval FALSE This interface is not supported.
**/
BOOLEAN
EFIAPI
Pkcs7Sign (
IN CONST UINT8 *PrivateKey,
IN UINTN PrivateKeySize,
IN CONST UINT8 *KeyPassword,
IN UINT8 *InData,
IN UINTN InDataSize,
IN UINT8 *SignCert,
IN UINT8 *OtherCerts OPTIONAL,
OUT UINT8 **SignedData,
OUT UINTN *SignedDataSize
)
{
BOOLEAN Status;
INT32 Ret;
mbedtls_pk_context Pkey;
UINT8 HashValue[SHA256_DIGEST_SIZE];
UINT8 Signature[MAX_SIGNATURE_SIZE];
UINTN SignatureLen;
UINT8 *NewPrivateKey;
mbedtls_x509_crt *Crt;
MbedtlsPkcs7 Pkcs7;
MbedtlsPkcs7SignerInfo SignerInfo;
UINT8 *Buffer;
INTN BufferSize;
UINT8 *Ptr;
INT32 Len;
//
// 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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
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;
}