Update the DxeImageVerificationLib to support for Authenticode-signed UEFI images with multiple signatures.

Signed-off-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Ye Ting  <ting.ye@intel.com>
Reviewed-by: Dong Guo <guo.dong@intel.com>

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@14141 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
sfu5 2013-02-21 05:00:21 +00:00
parent 944c84a6dd
commit 6de4c35f99
2 changed files with 115 additions and 145 deletions

View File

@ -12,7 +12,7 @@
DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept
untrusted PE/COFF image and validate its data structure within this image buffer before use. untrusted PE/COFF image and validate its data structure within this image buffer before use.
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -966,43 +966,6 @@ Done:
return VerifyStatus; return VerifyStatus;
} }
/**
Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format.
@param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.
@param[in] AuthDataSize Size of the Authenticode Signature in bytes.
@retval EFI_SUCCESS Image pass verification.
@retval EFI_SECURITY_VIOLATION Image fail verification.
**/
EFI_STATUS
VerifyCertPkcsSignedData (
IN UINT8 *AuthData,
IN UINTN AuthDataSize
)
{
//
// 1: Find certificate from DBX forbidden database for revoked certificate.
//
if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {
//
// DBX is forbidden database, if Authenticode verification pass with
// one of the certificate in DBX, this image should be rejected.
//
return EFI_SECURITY_VIOLATION;
}
//
// 2: Find certificate from DB database and try to verify authenticode struct.
//
if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {
return EFI_SUCCESS;
} else {
return EFI_SECURITY_VIOLATION;
}
}
/** /**
Provide verification service for signed images, which include both signature validation Provide verification service for signed images, which include both signature validation
and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
@ -1011,25 +974,14 @@ VerifyCertPkcsSignedData (
In this implementation, only verify external executables when in USER MODE. In this implementation, only verify external executables when in USER MODE.
Executables from FV is bypass, so pass in AuthenticationStatus is ignored. Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
The image verification process is: The image verification policy is:
If the image is signed, If the image is signed,
If the image's certificate verifies against a certificate (root or intermediate) in the allowed At least one valid signature or at least one hash value of the image must match a record
database (DB) and not in the forbidden database (DBX), the certificate verification is passed. in the security database "db", and no valid signature nor any hash value of the image may
If the image's hash digest is in DBX, be reflected in the security database "dbx".
deny execution.
If not,
run it.
If the Image's certificate verification failed.
If the Image's Hash is in DB and not in DBX,
run it.
Otherwise,
deny execution.
Otherwise, the image is not signed, Otherwise, the image is not signed,
Is the Image's Hash in DBX? The SHA256 hash value of the image must match a record in the security database "db", and
If yes, deny execution. not be reflected in the security data base "dbx".
If not, is the Image's Hash in DB?
If yes, run it.
If not, deny execution.
Caution: This function may receive untrusted input. Caution: This function may receive untrusted input.
PE/COFF image is external input, so this function will validate its data structure PE/COFF image is external input, so this function will validate its data structure
@ -1084,12 +1036,12 @@ DxeImageVerificationHandler (
UINT8 *SecureBoot; UINT8 *SecureBoot;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
UINT32 NumberOfRvaAndSizes; UINT32 NumberOfRvaAndSizes;
UINT32 CertSize;
WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid; WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;
UINT8 *AuthData; UINT8 *AuthData;
UINTN AuthDataSize; UINTN AuthDataSize;
EFI_IMAGE_DATA_DIRECTORY *SecDataDir; EFI_IMAGE_DATA_DIRECTORY *SecDataDir;
UINT32 OffSet;
SignatureList = NULL; SignatureList = NULL;
SignatureListSize = 0; SignatureListSize = 0;
@ -1098,6 +1050,8 @@ DxeImageVerificationHandler (
PkcsCertData = NULL; PkcsCertData = NULL;
Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
VerifyStatus = EFI_ACCESS_DENIED;
// //
// Check the image type and get policy setting. // Check the image type and get policy setting.
// //
@ -1230,9 +1184,13 @@ DxeImageVerificationHandler (
} }
} }
if ((SecDataDir == NULL) || ((SecDataDir != NULL) && (SecDataDir->Size == 0))) {
// //
// This image is not signed. // Start Image Validation.
//
if (SecDataDir == NULL || SecDataDir->Size == 0) {
//
// This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
// and not be reflected in the security data base "dbx".
// //
if (!HashPeImage (HASHALG_SHA256)) { if (!HashPeImage (HASHALG_SHA256)) {
goto Done; goto Done;
@ -1259,14 +1217,17 @@ DxeImageVerificationHandler (
} }
// //
// Verify signature of executables. // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7
// "Attribute Certificate Table".
// The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.
// //
WinCertificate = (WIN_CERTIFICATE *) (mImageBase + SecDataDir->VirtualAddress); for (OffSet = SecDataDir->VirtualAddress;
OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
CertSize = sizeof (WIN_CERTIFICATE); OffSet += WinCertificate->dwLength, OffSet += ALIGN_SIZE (OffSet)) {
WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
if ((SecDataDir->Size <= CertSize) || (SecDataDir->Size < WinCertificate->dwLength)) { if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||
goto Done; (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {
break;
} }
// //
@ -1279,74 +1240,79 @@ DxeImageVerificationHandler (
// //
PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate; PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) { if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
goto Done; break;
} }
AuthData = PkcsCertData->CertData; AuthData = PkcsCertData->CertData;
AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr); AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
Status = HashPeImageByType (AuthData, AuthDataSize);
if (EFI_ERROR (Status)) {
goto Done;
}
VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);
} else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
// //
// The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec. // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
// //
WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate; WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
if (!CompareGuid(&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid) || if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
(WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData))) { break;
goto Done; }
if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
continue;
} }
AuthData = WinCertUefiGuid->CertData; AuthData = WinCertUefiGuid->CertData;
AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData); AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
} else {
if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
break;
}
continue;
}
Status = HashPeImageByType (AuthData, AuthDataSize); Status = HashPeImageByType (AuthData, AuthDataSize);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
goto Done; continue;
} }
VerifyStatus = VerifyCertPkcsSignedData (AuthData, AuthDataSize);
} else { //
goto Done; // Check the digital signature against the revoked certificate in forbidden database (dbx).
//
if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid)) {
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
VerifyStatus = EFI_ACCESS_DENIED;
break;
}
//
// Check the digital signature against the valid certificate in allowed database (db).
//
if (EFI_ERROR (VerifyStatus)) {
if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) {
VerifyStatus = EFI_SUCCESS;
}
}
//
// Check the image's hash value.
//
if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
VerifyStatus = EFI_ACCESS_DENIED;
break;
} else if (EFI_ERROR (VerifyStatus)) {
if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
VerifyStatus = EFI_SUCCESS;
}
}
}
if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
//
// The Size in Certificate Table or the attribute certicate table is corrupted.
//
VerifyStatus = EFI_ACCESS_DENIED;
} }
if (!EFI_ERROR (VerifyStatus)) { if (!EFI_ERROR (VerifyStatus)) {
//
// Verification is passed.
// Continue to check the image digest in signature database.
//
if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
//
// Executable signature verification passes, but is found in forbidden signature database.
//
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
Status = EFI_ACCESS_DENIED;
} else {
//
// For image verification against enrolled X.509 certificate(root or intermediate),
// no need to check image's hash in the allowed database.
//
return EFI_SUCCESS; return EFI_SUCCESS;
}
} else { } else {
//
// Verification failure.
//
if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize) &&
IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
//
// Verification fail, Image Hash is not in forbidden database (DBX),
// and Image Hash is in allowed database (DB).
//
Status = EFI_SUCCESS;
} else {
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
Status = EFI_ACCESS_DENIED; Status = EFI_ACCESS_DENIED;
} if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
}
if (EFI_ERROR (Status)) {
// //
// Get image hash value as executable's signature. // Get image hash value as executable's signature.
// //
@ -1363,6 +1329,7 @@ DxeImageVerificationHandler (
Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST)); Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));
CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize); CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);
} }
}
Done: Done:
if (Status != EFI_SUCCESS) { if (Status != EFI_SUCCESS) {

View File

@ -2,7 +2,7 @@
The internal header file includes the common header files, defines The internal header file includes the common header files, defines
internal structure and functions used by ImageVerificationLib. internal structure and functions used by ImageVerificationLib.
Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR> Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at which accompanies this distribution. The full text of the license may be found at
@ -43,6 +43,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define MAX_NOTIFY_STRING_LEN 64 #define MAX_NOTIFY_STRING_LEN 64
#define TWO_BYTE_ENCODE 0x82 #define TWO_BYTE_ENCODE 0x82
#define ALIGNMENT_SIZE 8
#define ALIGN_SIZE(a) (((a) % ALIGNMENT_SIZE) ? ALIGNMENT_SIZE - ((a) % ALIGNMENT_SIZE) : 0)
// //
// Image type definitions // Image type definitions
// //