mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
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:
parent
40fa5cf299
commit
acfd991b68
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
635
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c
Normal file
635
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7Sign.c
Normal 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;
|
||||
}
|
113
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c
Normal file
113
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyBase.c
Normal 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;
|
||||
}
|
1354
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c
Normal file
1354
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyCommon.c
Normal file
File diff suppressed because it is too large
Load Diff
689
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c
Normal file
689
CryptoPkg/Library/BaseCryptLibMbedTls/Pk/CryptPkcs7VerifyEku.c
Normal 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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user