mirror of https://github.com/acidanthera/audk.git
1355 lines
36 KiB
C
1355 lines
36 KiB
C
|
/** @file
|
||
|
PKCS#7 SignedData Sign Wrapper and PKCS#7 SignedData Verification Wrapper
|
||
|
Implementation over mbedtls.
|
||
|
|
||
|
RFC 8422 - Elliptic Curve Cryptography (ECC) Cipher Suites
|
||
|
FIPS 186-4 - Digital Signature Standard (DSS)
|
||
|
|
||
|
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "CryptPkcs7Internal.h"
|
||
|
#include <mbedtls/pkcs7.h>
|
||
|
|
||
|
/* Profile for backward compatibility. Allows RSA 1024, unlike the default
|
||
|
profile. */
|
||
|
STATIC mbedtls_x509_crt_profile gCompatProfile =
|
||
|
{
|
||
|
/* Hashes from SHA-256 and above. Note that this selection
|
||
|
* should be aligned with ssl_preset_default_hashes in ssl_tls.c. */
|
||
|
|
||
|
#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA1) |
|
||
|
#endif
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA256) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA384) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_MD_SHA512),
|
||
|
0xFFFFFFF, /* Any PK alg */
|
||
|
|
||
|
/* Curves at or above 128-bit security level. Note that this selection
|
||
|
* should be aligned with ssl_preset_default_curves in ssl_tls.c. */
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP256R1) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP384R1) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_SECP521R1) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP256R1) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP384R1) |
|
||
|
MBEDTLS_X509_ID_FLAG (MBEDTLS_ECP_DP_BP512R1) |
|
||
|
0,
|
||
|
1024,
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
Init MbedtlsPkcs7.
|
||
|
|
||
|
@param[in] Pkcs7 MbedtlsPkcs7.
|
||
|
**/
|
||
|
STATIC
|
||
|
VOID
|
||
|
MbedTlsPkcs7Init (
|
||
|
MbedtlsPkcs7 *Pkcs7
|
||
|
)
|
||
|
{
|
||
|
ZeroMem (Pkcs7, sizeof (MbedtlsPkcs7));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Get Pkcs7 Next Content Len.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] Len MbedtlsPkcs7 Content Len.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
MbedTlsPkcs7GetNextContentLen (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
UINTN *Len
|
||
|
)
|
||
|
{
|
||
|
INT32 Ret;
|
||
|
|
||
|
Ret = mbedtls_asn1_get_tag (Ptr, End, Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC);
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Get Pkcs7 Version..
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] Ver MbedtlsPkcs7 Version.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
MbedTlsPkcs7GetVersion (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
INT32 *Ver
|
||
|
)
|
||
|
{
|
||
|
INT32 Ret;
|
||
|
|
||
|
Ret = mbedtls_asn1_get_int (Ptr, End, Ver);
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
ContentInfo ::= SEQUENCE {
|
||
|
contentType ContentType,
|
||
|
content
|
||
|
[0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] Pkcs7 MbedtlsPkcs7.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
Pkcs7GetContentInfoType (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
mbedtls_asn1_buf *Pkcs7
|
||
|
)
|
||
|
{
|
||
|
UINTN Len;
|
||
|
int Ret;
|
||
|
|
||
|
Len = 0;
|
||
|
Ret = mbedtls_asn1_get_tag (
|
||
|
Ptr,
|
||
|
End,
|
||
|
&Len,
|
||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
|
||
|
);
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = mbedtls_asn1_get_tag (Ptr, End, &Len, MBEDTLS_ASN1_OID);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Pkcs7->tag = MBEDTLS_ASN1_OID;
|
||
|
Pkcs7->len = Len;
|
||
|
Pkcs7->p = *Ptr;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
DigestAlgorithmIdentifier ::= AlgorithmIdentifier.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] Alg MbedtlsPkcs7 AlgorithmIdentifier.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
MbedTlsPkcs7GetDigestAlgorithm (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
mbedtls_x509_buf *Alg
|
||
|
)
|
||
|
{
|
||
|
INT32 Ret;
|
||
|
|
||
|
Ret = mbedtls_asn1_get_alg_null (Ptr, End, Alg);
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] Alg MbedtlsPkcs7 AlgorithmIdentifier.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
MbedTlsPkcs7GetDigestAlgorithmSet (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
mbedtls_x509_buf *Alg
|
||
|
)
|
||
|
{
|
||
|
UINTN Len;
|
||
|
INT32 Ret;
|
||
|
|
||
|
Len = 0;
|
||
|
Ret = mbedtls_asn1_get_tag (
|
||
|
Ptr,
|
||
|
End,
|
||
|
&Len,
|
||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET
|
||
|
);
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
End = *Ptr + Len;
|
||
|
// assume only one digest algorithm
|
||
|
Ret = mbedtls_asn1_get_alg_null (Ptr, End, Alg);
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
certificates :: SET OF ExtendedCertificateOrCertificate,
|
||
|
ExtendedCertificateOrCertificate ::= CHOICE {
|
||
|
certificate Certificate -- x509,
|
||
|
extendedCertificate[0] IMPLICIT ExtendedCertificate }.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] Plen The buffer len.
|
||
|
@param[out] Certs mbedtls_x509_crt cert.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
MbedTlsPkcs7GetCertificates (
|
||
|
UINT8 **Ptr,
|
||
|
INTN Plen,
|
||
|
mbedtls_x509_crt *Certs
|
||
|
)
|
||
|
{
|
||
|
INT32 Ret;
|
||
|
|
||
|
Ret = mbedtls_x509_crt_parse (Certs, *Ptr, Plen);
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
EncryptedDigest ::= OCTET STRING.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] Signature Signature.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
Pkcs7GetSignature (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
mbedtls_asn1_buf *Signature
|
||
|
)
|
||
|
{
|
||
|
INT32 Ret;
|
||
|
UINTN Len;
|
||
|
|
||
|
Len = 0;
|
||
|
Ret = mbedtls_asn1_get_tag (Ptr, End, &Len, MBEDTLS_ASN1_OCTET_STRING);
|
||
|
if (Ret == 0) {
|
||
|
Signature->tag = MBEDTLS_ASN1_OCTET_STRING;
|
||
|
Signature->len = Len;
|
||
|
Signature->p = *Ptr;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
SignerInfo ::= SEQUENCE {
|
||
|
version Version;
|
||
|
issuerAndSerialNumber IssuerAndSerialNumber,
|
||
|
digestAlgorithm DigestAlgorithmIdentifier,
|
||
|
authenticatedAttributes
|
||
|
[0] IMPLICIT Attributes OPTIONAL,
|
||
|
digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
|
||
|
encryptedDigest EncryptedDigest,
|
||
|
unauthenticatedAttributes
|
||
|
[1] IMPLICIT Attributes OPTIONAL.
|
||
|
|
||
|
@param[in] Ptr The start of the buffer.
|
||
|
@param[in] End The end of the buffer.
|
||
|
@param[out] SignersSet MbedtlsPkcs7SignerInfo.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
MbedTlsPkcs7GetSignersInfoSet (
|
||
|
UINT8 **Ptr,
|
||
|
UINT8 *End,
|
||
|
MbedtlsPkcs7SignerInfo *SignersSet
|
||
|
)
|
||
|
{
|
||
|
UINT8 *EndSet;
|
||
|
INT32 Ret;
|
||
|
UINTN Len;
|
||
|
UINT8 *TempP;
|
||
|
|
||
|
Len = 0;
|
||
|
|
||
|
Ret = mbedtls_asn1_get_tag (
|
||
|
Ptr,
|
||
|
End,
|
||
|
&Len,
|
||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET
|
||
|
);
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
EndSet = *Ptr + Len;
|
||
|
|
||
|
Ret = mbedtls_asn1_get_tag (
|
||
|
Ptr,
|
||
|
EndSet,
|
||
|
&Len,
|
||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = mbedtls_asn1_get_int (Ptr, EndSet, &SignersSet->Version);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = mbedtls_asn1_get_tag (
|
||
|
Ptr,
|
||
|
EndSet,
|
||
|
&Len,
|
||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
SignersSet->IssuerRaw.p = *Ptr;
|
||
|
Ret = mbedtls_asn1_get_tag (
|
||
|
Ptr,
|
||
|
EndSet,
|
||
|
&Len,
|
||
|
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = mbedtls_x509_get_name (Ptr, *Ptr + Len, &SignersSet->Issuer);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
SignersSet->IssuerRaw.len = *Ptr - SignersSet->IssuerRaw.p;
|
||
|
|
||
|
Ret = mbedtls_x509_get_serial (Ptr, EndSet, &SignersSet->Serial);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = MbedTlsPkcs7GetDigestAlgorithm (Ptr, EndSet, &SignersSet->AlgIdentifier);
|
||
|
}
|
||
|
|
||
|
// OPTIONAL AuthenticatedAttributes
|
||
|
if (Ret == 0) {
|
||
|
TempP = *Ptr;
|
||
|
if (mbedtls_asn1_get_tag (&TempP, EndSet, &Len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) == 0) {
|
||
|
SignersSet->AuthAttr.len = Len + (TempP - *Ptr);
|
||
|
SignersSet->AuthAttr.p = *Ptr;
|
||
|
*Ptr = TempP + Len;
|
||
|
} else {
|
||
|
SignersSet->AuthAttr.p = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = MbedTlsPkcs7GetDigestAlgorithm (Ptr, EndSet, &SignersSet->SigAlgIdentifier);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
Ret = Pkcs7GetSignature (Ptr, End, &SignersSet->Sig);
|
||
|
}
|
||
|
|
||
|
if (Ret == 0) {
|
||
|
SignersSet->Next = NULL;
|
||
|
}
|
||
|
|
||
|
return Ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
SignedData ::= SEQUENCE {
|
||
|
version Version,
|
||
|
digestAlgorithms DigestAlgorithmIdentifiers,
|
||
|
contentInfo ContentInfo,
|
||
|
certificates
|
||
|
[0] IMPLICIT ExtendedCertificatesAndCertificates
|
||
|
OPTIONAL,
|
||
|
crls
|
||
|
[0] IMPLICIT CertificateRevocationLists OPTIONAL,
|
||
|
signerInfos SignerInfos }.
|
||
|
|
||
|
@param[in] Buffer The start of the buffer.
|
||
|
@param[in] BufferLen The len the buffer.
|
||
|
@param[out] SignedData MbedtlsPkcs7SignedData.
|
||
|
|
||
|
@retval 0 Success.
|
||
|
@retval negative A negative MBEDTLS_ERR_ASN1_XXX error code on failure.
|
||
|
**/
|
||
|
STATIC
|
||
|
INT32
|
||
|
Pkcs7GetSignedData (
|
||
|
UINT8 *Buffer,
|
||
|
INTN BufferLen,
|
||
|
MbedtlsPkcs7SignedData *SignedData
|
||
|
)
|
||
|
{
|
||
|
UINT8 *Ptr;
|
||
|
UINT8 *End;
|
||
|
UINTN Len;
|
||
|
INT32 Ret;
|
||
|
UINT8 *CertP;
|
||
|
UINTN CertLen;
|
||
|
UINT8 *OldCertP;
|
||
|
UINTN TotalCertLen;
|
||
|
mbedtls_x509_crt *MoreCert;
|
||
|
UINT8 CertNum;
|
||
|
mbedtls_x509_crt *LastCert;
|
||
|
mbedtls_x509_crt *TempCrt;
|
||
|
|
||
|
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;
|
||
|
}
|