From 45bf2c4789c71c2a65170d07b274acee17b3e374 Mon Sep 17 00:00:00 2001 From: xdu2 Date: Fri, 28 Oct 2011 09:54:08 +0000 Subject: SecurityPkg: Update DxeImageVerificationLib with following changes: 1. Update to check image digest against dbx before execute it. 2. Update to support revoke certificate. 3. Update to support enroll unsigned PE image's Hash to allowed database (db). (Note: Unsigned Image's Hash is calculated in the same way with authenticode, the algorithm is assumed to be SHA256.) Signed-off-by: xdu2 Reviewed-by: tye Reviewed-by: gdong1 git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12598 6f19259b-4bc3-4df7-8a09-765794883524 --- .../DxeImageVerificationLib.c | 379 +++++++++++---------- 1 file changed, 204 insertions(+), 175 deletions(-) (limited to 'SecurityPkg/Library/DxeImageVerificationLib') diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c index 7bc3cc0ec0..91977522a9 100644 --- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -2,12 +2,12 @@ Implement image verification services for secure boot service in UEFI2.3.1. Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
-This program and the accompanying materials -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 +This program and the accompanying materials +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 http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ @@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; UINTN mImageSize; -UINT32 mPeCoffHeaderOffset; +UINT32 mPeCoffHeaderOffset; UINT8 mImageDigest[MAX_DIGEST_SIZE]; UINTN mImageDigestSize; EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL; @@ -59,9 +59,9 @@ HASH_TABLE mHash[] = { Get the image type. @param[in] File This is a pointer to the device path of the file that is - being dispatched. + being dispatched. - @return UINT32 Image Type + @return UINT32 Image Type **/ UINT32 @@ -70,7 +70,7 @@ GetImageType ( ) { EFI_STATUS Status; - EFI_HANDLE DeviceHandle; + EFI_HANDLE DeviceHandle; EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; EFI_BLOCK_IO_PROTOCOL *BlockIo; @@ -78,7 +78,7 @@ GetImageType ( // First check to see if File is from a Firmware Volume // DeviceHandle = NULL; - TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; Status = gBS->LocateDevicePath ( &gEfiFirmwareVolume2ProtocolGuid, &TempDevicePath, @@ -102,7 +102,7 @@ GetImageType ( // Next check to see if File is from a Block I/O device // DeviceHandle = NULL; - TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; Status = gBS->LocateDevicePath ( &gEfiBlockIoProtocolGuid, &TempDevicePath, @@ -136,11 +136,11 @@ GetImageType ( } // - // File is not in a Firmware Volume or on a Block I/O device, so check to see if + // File is not in a Firmware Volume or on a Block I/O device, so check to see if // the device path supports the Simple File System Protocol. // DeviceHandle = NULL; - TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; Status = gBS->LocateDevicePath ( &gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, @@ -155,12 +155,12 @@ GetImageType ( // // File is not from an FV, Block I/O or Simple File System, so the only options - // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. + // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. // - TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) File; while (!IsDevicePathEndType (TempDevicePath)) { switch (DevicePathType (TempDevicePath)) { - + case MEDIA_DEVICE_PATH: if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) { return IMAGE_FROM_OPTION_ROM; @@ -170,7 +170,7 @@ GetImageType ( case MESSAGING_DEVICE_PATH: if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) { return IMAGE_FROM_REMOVABLE_MEDIA; - } + } break; default: @@ -178,7 +178,7 @@ GetImageType ( } TempDevicePath = NextDevicePathNode (TempDevicePath); } - return IMAGE_UNKNOWN; + return IMAGE_UNKNOWN; } /** @@ -186,12 +186,12 @@ GetImageType ( PE/COFF Specification 8.0 Appendix A @param[in] HashAlg Hash algorithm type. - + @retval TRUE Successfully hash image. @retval FALSE Fail in hash image. **/ -BOOLEAN +BOOLEAN HashPeImage ( IN UINT32 HashAlg ) @@ -208,8 +208,8 @@ HashPeImage ( UINTN Index; UINTN Pos; UINTN SumOfSectionBytes; - EFI_IMAGE_SECTION_HEADER *SectionCache; - + EFI_IMAGE_SECTION_HEADER *SectionCache; + HashCtx = NULL; SectionHeader = NULL; Status = FALSE; @@ -217,7 +217,7 @@ HashPeImage ( if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) { return FALSE; } - + // // Initialize context of hash. // @@ -234,7 +234,7 @@ HashPeImage ( } CtxSize = mHash[HashAlg].GetContextSize(); - + HashCtx = AllocatePool (CtxSize); if (HashCtx == NULL) { return FALSE; @@ -244,7 +244,7 @@ HashPeImage ( // 2. Initialize a SHA hash context. Status = mHash[HashAlg].HashInit(HashCtx); - + if (!Status) { goto Done; } @@ -294,7 +294,7 @@ HashPeImage ( } else { // // Use PE32+ offset. - // + // HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); } @@ -353,7 +353,7 @@ HashPeImage ( for (Index = 0, SumOfSectionBytes = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++, SectionCache++) { SumOfSectionBytes += SectionCache->SizeOfRawData; } - + // // Sanity check for file corruption. Sections raw data size should be smaller // than Image Size. @@ -436,7 +436,7 @@ HashPeImage ( HashSize = (UINTN)( mImageSize - mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - - SumOfBytesHashed); + SumOfBytesHashed); } Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); @@ -457,15 +457,15 @@ Done: } /** - Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of - Pe/Coff image based on the authenticode image hashing in PE/COFF Specification + Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of + Pe/Coff image based on the authenticode image hashing in PE/COFF Specification 8.0 Appendix A @retval EFI_UNSUPPORTED Hash algorithm is not supported. @retval EFI_SUCCESS Hash successfully. **/ -EFI_STATUS +EFI_STATUS HashPeImageByType ( VOID ) @@ -475,10 +475,10 @@ HashPeImageByType ( PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); - for (Index = 0; Index < HASHALG_MAX; Index++) { + for (Index = 0; Index < HASHALG_MAX; Index++) { // // Check the Hash algorithm in PE/COFF Authenticode. - // According to PKCS#7 Definition: + // According to PKCS#7 Definition: // SignedData ::= SEQUENCE { // version Version, // digestAlgorithms DigestAlgorithmIdentifiers, @@ -486,7 +486,7 @@ HashPeImageByType ( // .... } // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing // This field has the fixed offset (+32) in final Authenticode ASN.1 data. - // + // if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { break; } @@ -514,7 +514,7 @@ HashPeImageByType ( ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned. @param ImageExeInfoTable A pointer to a image execution info table structure. - + @retval 0 If ImageExeInfoTable is NULL. @retval Others The size of a image execution info table in bytes. @@ -550,12 +550,12 @@ GetImageExeInfoTableSize ( @param[in] DevicePath Input device path pointer. @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure. @param[in] SignatureSize Size of signature. - + **/ VOID AddImageExeInfo ( - IN EFI_IMAGE_EXECUTION_ACTION Action, - IN CHAR16 *Name OPTIONAL, + IN EFI_IMAGE_EXECUTION_ACTION Action, + IN CHAR16 *Name OPTIONAL, IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN EFI_SIGNATURE_LIST *Signature OPTIONAL, IN UINTN SignatureSize @@ -577,13 +577,13 @@ AddImageExeInfo ( if (DevicePath == NULL) { return ; } - + if (Name != NULL) { NameStringLen = StrSize (Name); } ImageExeInfoTable = NULL; - EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable); + EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable); if (ImageExeInfoTable != NULL) { // // The table has been found! @@ -637,7 +637,7 @@ AddImageExeInfo ( // Update/replace the image execution table. // gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable); - + // // Free Old table data! // @@ -649,7 +649,7 @@ AddImageExeInfo ( /** Discover if the UEFI image is authorized by user's policy setting. - @param[in] Policy Specify platform's policy setting. + @param[in] Policy Specify platform's policy setting. @retval EFI_ACCESS_DENIED Image is not allowed to run. @retval EFI_SECURITY_VIOLATION Image is deferred. @@ -667,7 +667,7 @@ ImageAuthorization ( Status = EFI_ACCESS_DENIED; switch (Policy) { - + case QUERY_USER_ON_SECURITY_VIOLATION: do { CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL); @@ -715,7 +715,7 @@ ImageAuthorization ( BOOLEAN IsSignatureFoundInDatabase ( IN CHAR16 *VariableName, - IN UINT8 *Signature, + IN UINT8 *Signature, IN EFI_GUID *CertType, IN UINTN SignatureSize ) @@ -786,16 +786,20 @@ Done: } /** - Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format . + Verify PKCS#7 SignedData using certificate found in Variable which formatted + as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX. - @retval EFI_SUCCESS Image pass verification. - @retval EFI_SECURITY_VIOLATION Image fail verification. - @retval EFI_OUT_OF_RESOURCE Fail to allocate memory. + @param VariableName Name of Variable to search for Certificate. + @param VendorGuid Variable vendor GUID. + + @retval TRUE Image pass verification. + @retval FALSE Image fail verification. **/ -EFI_STATUS -VerifyCertPkcsSignedData ( - VOID +BOOLEAN +IsPkcsSignedDataVerifiedBySignatureList ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid ) { EFI_STATUS Status; @@ -804,55 +808,50 @@ VerifyCertPkcsSignedData ( EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *Cert; UINTN DataSize; - UINT8 *KekData; - UINT8 *DbData; + UINT8 *Data; UINT8 *RootCert; UINTN RootCertSize; UINTN Index; UINTN CertCount; - KekData = NULL; - DbData = NULL; - CertList = NULL; - Cert = NULL; - RootCert = NULL; - RootCertSize = 0; - VerifyStatus = FALSE; - PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); + Data = NULL; + CertList = NULL; + Cert = NULL; + RootCert = NULL; + RootCertSize = 0; + VerifyStatus = FALSE; + PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); - // - // 1: Find certificate from KEK database and try to verify authenticode struct. - // DataSize = 0; - Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL); + Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL); if (Status == EFI_BUFFER_TOO_SMALL) { - KekData = (UINT8 *)AllocateZeroPool (DataSize); - if (KekData == NULL) { - return EFI_OUT_OF_RESOURCES; + Data = (UINT8 *) AllocateZeroPool (DataSize); + if (Data == NULL) { + return VerifyStatus; } - Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)KekData); + Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, (VOID *) Data); if (EFI_ERROR (Status)) { goto Done; } - + + // + // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data. // - // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data. - // - CertList = (EFI_SIGNATURE_LIST *) KekData; + CertList = (EFI_SIGNATURE_LIST *) Data; while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; for (Index = 0; Index < CertCount; Index++) { // - // Iterate each Signature Data Node within this CertList for a verify - // + // Iterate each Signature Data Node within this CertList for verify. + // RootCert = Cert->SignatureData; RootCertSize = CertList->SignatureSize; - + // - // Call AuthenticodeVerify library to Verify Authenticode struct. + // Call AuthenticodeVerify library to Verify Authenticode struct. // VerifyStatus = AuthenticodeVerify ( PkcsCertData->CertData, @@ -862,84 +861,59 @@ VerifyCertPkcsSignedData ( mImageDigest, mImageDigestSize ); - if (VerifyStatus) { goto Done; } Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); - } + } } DataSize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } } - +Done: + if (Data != NULL) { + FreePool (Data); + } - // - // 2: Find certificate from DB database and try to verify authenticode struct. - // - DataSize = 0; - Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); - if (Status == EFI_BUFFER_TOO_SMALL) { - DbData = (UINT8 *)AllocateZeroPool (DataSize); - if (DbData == NULL) { - goto Done; - } + return VerifyStatus; +} - Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)DbData); - if (EFI_ERROR (Status)) { - goto Done; - } +/** + Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format. - // - // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data. - // - CertList = (EFI_SIGNATURE_LIST *) DbData; - while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { - if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { - Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); - CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; - for (Index = 0; Index < CertCount; Index++) { - // - // Iterate each Signature Data Node within this CertList for a verify - // - RootCert = Cert->SignatureData; - RootCertSize = CertList->SignatureSize; - - // - // Call AuthenticodeVerify library to Verify Authenticode struct. - // - VerifyStatus = AuthenticodeVerify ( - PkcsCertData->CertData, - mSecDataDir->Size - sizeof(PkcsCertData->Hdr), - RootCert, - RootCertSize, - mImageDigest, - mImageDigestSize - ); - - if (VerifyStatus) { - goto Done; - } - Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); - } - } - DataSize -= CertList->SignatureListSize; - CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); - } - } + @retval EFI_SUCCESS Image pass verification. + @retval EFI_SECURITY_VIOLATION Image fail verification. -Done: - if (KekData != NULL) { - FreePool (KekData); +**/ +EFI_STATUS +VerifyCertPkcsSignedData ( + VOID + ) +{ + // + // 1: Find certificate from DBX forbidden database for revoked certificate. + // + if (IsPkcsSignedDataVerifiedBySignatureList (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; } - if (DbData != NULL) { - FreePool (DbData); + // + // 2: Find certificate from KEK database and try to verify authenticode struct. + // + if (IsPkcsSignedDataVerifiedBySignatureList (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid)) { + return EFI_SUCCESS; } - if (VerifyStatus) { + // + // 3: Find certificate from DB database and try to verify authenticode struct. + // + if (IsPkcsSignedDataVerifiedBySignatureList (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid)) { return EFI_SUCCESS; } else { return EFI_SECURITY_VIOLATION; @@ -947,14 +921,14 @@ Done: } /** - Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. + Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. @retval EFI_SUCCESS Image pass verification. @retval EFI_SECURITY_VIOLATION Image fail verification. @retval other error value **/ -EFI_STATUS +EFI_STATUS VerifyCertUefiGuid ( VOID ) @@ -1004,7 +978,7 @@ VerifyCertUefiGuid ( if (KekList == NULL) { return EFI_SECURITY_VIOLATION; } - + // // Enumerate all Kek items in this list to verify the variable certificate data. // If anyone is authenticated successfully, it means the variable is correct! @@ -1024,7 +998,7 @@ VerifyCertUefiGuid ( KekDataSize -= KekList->SignatureListSize; KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize); } - + if (!IsFound) { // // Signed key is not a trust one. @@ -1041,8 +1015,8 @@ VerifyCertUefiGuid ( Status = FALSE; goto Done; } - - // + + // // Set RSA Key Components. // NOTE: Only N and E are needed to be set as RSA public key for signature verification. // @@ -1058,13 +1032,13 @@ VerifyCertUefiGuid ( // Verify the signature. // Status = RsaPkcs1Verify ( - Rsa, - mImageDigest, - mImageDigestSize, - CertBlock->Signature, + Rsa, + mImageDigest, + mImageDigestSize, + CertBlock->Signature, EFI_CERT_TYPE_RSA2048_SHA256_SIZE ); - + Done: if (KekList != NULL) { FreePool (KekList); @@ -1081,13 +1055,31 @@ Done: /** 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 MSFT Authenticode type signatures are supported. - - In this implementation, only verify external executables when in USER MODE. - Executables from FV is bypass, so pass in AuthenticationStatus is ignored. - @param[in] AuthenticationStatus + In this implementation, only verify external executables when in USER MODE. + Executables from FV is bypass, so pass in AuthenticationStatus is ignored. + + The image verification process is: + Is the Image signed? + If yes, + Does the image verify against a certificate (root or intermediate) in the allowed db? + Run it + Image verification fail + Is the Image's Hash not in forbidden database and the Image's Hash in allowed db? + Run it + If no, + Is the Image's Hash in the forbidden database (DBX)? + if yes, + Error out + Is the Image's Hash in the allowed database (DB)? + If yes, + Run it + If no, + Error out + + @param[in] AuthenticationStatus This is the authentication status returned from the security measurement services for the input file. @param[in] File This is a pointer to the device path of the file that is @@ -1144,7 +1136,7 @@ DxeImageVerificationHandler ( // Check the image type and get policy setting. // switch (GetImageType (File)) { - + case IMAGE_FROM_FV: Policy = ALWAYS_EXECUTE; break; @@ -1162,7 +1154,7 @@ DxeImageVerificationHandler ( break; default: - Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; + Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; break; } // @@ -1188,8 +1180,8 @@ DxeImageVerificationHandler ( if (*SecureBootEnable == SECURE_BOOT_DISABLE) { FreePool (SecureBootEnable); return EFI_SUCCESS; - } - + } + SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME); // @@ -1216,10 +1208,10 @@ DxeImageVerificationHandler ( } mImageBase = (UINT8 *) FileBuffer; mImageSize = FileSize; - DosHdr = (EFI_IMAGE_DOS_HEADER *) (mImageBase); + DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase; if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { // - // DOS image header is present, + // DOS image header is present, // so read the PE header after the DOS image header. // mPeCoffHeaderOffset = DosHdr->e_lfanew; @@ -1242,12 +1234,12 @@ DxeImageVerificationHandler ( // // Use PE32 offset. // - mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { // // Use PE32+ offset. // - mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; } else { // // Invalid header magic number. @@ -1268,21 +1260,45 @@ DxeImageVerificationHandler ( // // This image is not signed. // + if (!HashPeImage (HASHALG_SHA256)) { + goto Done; + } + + if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) { + // + // Image Hash is in forbidden database (DBX). + // + Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; + Status = EFI_ACCESS_DENIED; + goto Done; + } + + if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) { + // + // Image Hash is in allowed database (DB). + // + return EFI_SUCCESS; + } + + // + // Image Hash is not found in both forbidden and allowed database. + // Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; - Status = EFI_ACCESS_DENIED; - goto Done; + Status = EFI_ACCESS_DENIED; + goto Done; } + // // Verify signature of executables. // WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress); switch (WinCertificate->wCertificateType) { - + case WIN_CERT_TYPE_EFI_GUID: // // Verify UEFI GUID type. - // + // if (!HashPeImage (HASHALG_SHA256)) { goto Done; } @@ -1295,7 +1311,7 @@ DxeImageVerificationHandler ( // Verify Pkcs signed data type. // Status = HashPeImageByType(); - if (EFI_ERROR(Status)) { + if (EFI_ERROR (Status)) { goto Done; } @@ -1306,11 +1322,15 @@ DxeImageVerificationHandler ( // no need to check image's hash in the allowed database. // if (!EFI_ERROR (VerifyStatus)) { - return EFI_SUCCESS; + if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) { + return EFI_SUCCESS; + } } + break; default: - return EFI_ACCESS_DENIED; + Status = EFI_ACCESS_DENIED; + goto Done; } // // Get image hash value as executable's signature. @@ -1334,8 +1354,17 @@ DxeImageVerificationHandler ( // // Verification failure. // - Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; - Status = EFI_ACCESS_DENIED; + 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; + } } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) { // // Executable signature verification passes, but is found in forbidden signature database. @@ -1375,10 +1404,10 @@ Done: /** When VariableWriteArchProtocol install, create "SecureBoot" variable. - + @param[in] Event Event whose notification function is being invoked. @param[in] Context Pointer to the notification function's context. - + **/ VOID EFIAPI @@ -1396,7 +1425,7 @@ VariableWriteCallBack ( if (EFI_ERROR (Status)) { return; } - + // // Check whether "SecureBoot" variable exists. // If this library is built-in, it means firmware has capability to perform @@ -1418,7 +1447,7 @@ VariableWriteCallBack ( } else { FreePool (SecureBootModePtr); } -} +} /** Register security measurement handler. @@ -1439,7 +1468,7 @@ DxeImageVerificationLibConstructor ( // // Register callback function upon VariableWriteArchProtocol. - // + // EfiCreateProtocolNotifyEvent ( &gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, @@ -1451,5 +1480,5 @@ DxeImageVerificationLibConstructor ( return RegisterSecurityHandler ( DxeImageVerificationHandler, EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED - ); + ); } -- cgit v1.2.3