/** @file Authenticode Portable Executable Signature Verification which does not provide real capabilities. Copyright (c) 2024, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "InternalCryptLib.h" #include // // OID ASN.1 Value for SPC_INDIRECT_DATA_OBJID // GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 mSpcIndirectOidValue[] = { 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04 }; /** Verifies the validity of a PE/COFF Authenticode Signature as described in "Windows Authenticode Portable Executable Signature Format". Return FALSE to indicate this interface is not supported. @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed PE/COFF image to be verified. @param[in] DataSize Size of the Authenticode Signature in bytes. @param[in] TrustedCert Pointer to a trusted/root certificate encoded in DER, which is used for certificate chain verification. @param[in] CertSize Size of the trusted certificate in bytes. @param[in] ImageHash Pointer to the original image file hash value. The procedure for calculating the image hash value is described in Authenticode specification. @param[in] HashSize Size of Image hash value in bytes. @retval FALSE This interface is not supported. **/ BOOLEAN EFIAPI AuthenticodeVerify ( IN CONST UINT8 *AuthData, IN UINTN DataSize, IN CONST UINT8 *TrustedCert, IN UINTN CertSize, IN CONST UINT8 *ImageHash, IN UINTN HashSize ) { BOOLEAN Status; CONST UINT8 *OrigAuthData; UINT8 *SpcIndirectDataContent; UINT8 Asn1Byte; UINTN ContentSize; CONST UINT8 *SpcIndirectDataOid; UINT8 *Ptr; UINT8 *End; INT32 Len; UINTN ObjLen; OrigAuthData = AuthData; // // Check input parameters. // if ((AuthData == NULL) || (TrustedCert == NULL) || (ImageHash == NULL)) { return FALSE; } if ((DataSize > INT_MAX) || (CertSize > INT_MAX) || (HashSize > INT_MAX)) { return FALSE; } if (DataSize <= HashSize) { return FALSE; } Ptr = (UINT8 *)(UINTN)AuthData; Len = (UINT32)DataSize; End = Ptr + Len; // ContentInfo if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { return FALSE; } // ContentType if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { return FALSE; } Ptr += ObjLen; // content if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { return FALSE; } End = Ptr + ObjLen; // signedData if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { return FALSE; } // version if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_INTEGER) != 0) { return FALSE; } Ptr += ObjLen; // digestAlgo if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET) != 0) { return FALSE; } Ptr += ObjLen; // encapContentInfo if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) { return FALSE; } End = Ptr + ObjLen; // eContentType if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_OID) != 0) { return FALSE; } Status = FALSE; SpcIndirectDataOid = Ptr; if ((ObjLen != sizeof (mSpcIndirectOidValue)) || (CompareMem ( SpcIndirectDataOid, mSpcIndirectOidValue, sizeof (mSpcIndirectOidValue) ) != 0)) { // // Un-matched SPC_INDIRECT_DATA_OBJID. // goto _Exit; } Ptr += ObjLen; // eContent if (mbedtls_asn1_get_tag (&Ptr, End, &ObjLen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC) != 0) { return FALSE; } SpcIndirectDataContent = Ptr; // // Retrieve the SEQUENCE data size from ASN.1-encoded SpcIndirectDataContent. // Asn1Byte = *(SpcIndirectDataContent + 1); if ((Asn1Byte & 0x80) == 0) { // // Short Form of Length Encoding (Length < 128) // ContentSize = (UINTN)(Asn1Byte & 0x7F); // // Skip the SEQUENCE Tag; // SpcIndirectDataContent += 2; } else if ((Asn1Byte & 0x81) == 0x81) { // // Long Form of Length Encoding (128 <= Length < 255, Single Octet) // ContentSize = (UINTN)(*(UINT8 *)(SpcIndirectDataContent + 2)); // // Skip the SEQUENCE Tag; // SpcIndirectDataContent += 3; } else if ((Asn1Byte & 0x82) == 0x82) { // // Long Form of Length Encoding (Length > 255, Two Octet) // ContentSize = (UINTN)(*(UINT8 *)(SpcIndirectDataContent + 2)); ContentSize = (ContentSize << 8) + (UINTN)(*(UINT8 *)(SpcIndirectDataContent + 3)); // // Skip the SEQUENCE Tag; // SpcIndirectDataContent += 4; } else { goto _Exit; } // // Compare the original file hash value to the digest retrieve from SpcIndirectDataContent // defined in Authenticode // NOTE: Need to double-check HashLength here! // if (ContentSize < HashSize) { return FALSE; } if (CompareMem (SpcIndirectDataContent + ContentSize - HashSize, ImageHash, HashSize) != 0) { // // Un-matched PE/COFF Hash Value // goto _Exit; } // // Verifies the PKCS#7 Signed Data in PE/COFF Authenticode Signature // Status = (BOOLEAN)Pkcs7Verify (OrigAuthData, DataSize, TrustedCert, CertSize, SpcIndirectDataContent, ContentSize); _Exit: return Status; }