summaryrefslogtreecommitdiff
path: root/Core/EM/SecurityPkg/ImageVerificationLib/DxeImageVerificationLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'Core/EM/SecurityPkg/ImageVerificationLib/DxeImageVerificationLib.c')
-rw-r--r--Core/EM/SecurityPkg/ImageVerificationLib/DxeImageVerificationLib.c2431
1 files changed, 2431 insertions, 0 deletions
diff --git a/Core/EM/SecurityPkg/ImageVerificationLib/DxeImageVerificationLib.c b/Core/EM/SecurityPkg/ImageVerificationLib/DxeImageVerificationLib.c
new file mode 100644
index 0000000..7593b20
--- /dev/null
+++ b/Core/EM/SecurityPkg/ImageVerificationLib/DxeImageVerificationLib.c
@@ -0,0 +1,2431 @@
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2013, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//**********************************************************************
+// $Header: /Alaska/SOURCE/Modules/SecureBoot_WIN8/ImageVerification_efi/DxeImageVerificationLib.c 79 6/22/15 6:26p Alexp $
+//
+// $Revision: 79 $
+//
+// $Date: 6/22/15 6:26p $
+//**********************************************************************
+// Revision History
+// ----------------
+// $Log: /Alaska/SOURCE/Modules/SecureBoot_WIN8/ImageVerification_efi/DxeImageVerificationLib.c $
+//
+// 79 6/22/15 6:26p Alexp
+// EIP219415
+// [Category] Bug Fix
+// [Severity] Minor
+// [Symptom] UEFI PXE can launch unsigned images when
+// SecureBoot is enabled.
+// [RootCause] Image from PXE server gets cloned device path
+// from its parent network controller with PciIo protocol
+// and embedded PCI ROM attributes
+// [Solution] Add checking for unique path for embedded
+// Pci OpROMs to prevent non-OpROM images
+//
+// 77 5/14/15 9:49a Alexp
+// DxeImageVerificationHandler()
+// Modify certificate offset calculation to match EDKII version
+//
+// 76 3/09/15 4:24p Alexp
+// EIP192504: Prevent Built In EFI Shell boot option from being created in
+// BDS when Secure Boot is enabled
+// [Resolution]: Leave old logic to allow launching embedded shell
+// based on the token:LOAD_UNSIGNED_EMBEDDED_SHELL
+// enabled by default only in Debug mode
+// EIP197749: Need to authenticate images loaded from external FV
+// [Resolution] Add logic inside GetImageType() to detect images loaded
+// from external FV
+//
+// 75 5/29/14 8:52a Alexp
+// minor debug trace message change;
+//
+// 74 8/15/13 11:29a Alexp
+// EIP#118850: Implement support for Certificate Revocation Storage
+// reduction and Timestamp Support.
+// Link AmyCryptoLib to make use of os_mktime()
+//
+// 73 7/26/13 3:40p Alexp
+// 1. EIP118850: Integrate ECR1009 chnages for TimeStamp dbt processing
+// 2. Image policy settings are checked against the build time defaults.
+// Prevents un-authorized change to NVRAM policy settings
+// to lower security policy.
+//
+// 72 6/26/13 10:48a Alexp
+// EIP[125931]: Security review. Fix after follow up review.
+// UINT32 integer wrapping still occurs due to incorrect placement
+// of delimiting parentheses
+//
+// 70 6/25/13 7:21p Alexp
+// EIP:127292 Item#2. Add dependency on ENABLE_IMAGE_EXEC_POLICY_OVERRIDE
+// EIP:127292 Item#3 Only For deprecated Security protocol:
+// DxeImageVerificationHandler Returns Error if FileRead() is
+// unsuccessful
+//
+// 67 6/21/13 10:41a Alexp
+// EIP[125931]: Security review: HashPeImage does not validate certificate
+// table offset and size
+//
+// 66 5/21/13 4:05p Alexp
+// EIP:124444 Secure boot improvement for LoadImage call with NULL
+// DevicePath
+// EIP:122339 GetImageType() detect if PciOpROM image is loaded from
+// internal FV by
+// checking the corresponding PCI I/O instance for the embedded
+// attribute.
+//
+// 63 3/25/13 3:41p Alexp
+// 1. EIP:118243 add support for multi-signed PE Images
+// 2. Removed append image certificates to db from User Query dialog.
+//
+// 56 3/11/13 5:07p Alexp
+// IsSignatureFoundInDatabase(): fix method to calculate CertCount.
+// AddImageExeInfo(): code cleanup for cases when *Name is NULL
+// DxeImageVerificationHandler(): Optimized code to determine if PE image
+// is signed
+//
+// 55 3/09/13 4:31p Alexp
+// EIP114998: wrong cert size passed in PCR[7] calculation
+//
+// 54 12/19/12 10:28a Alexp
+// EIP[104046]: Hardened code per #2,3,4,5,6,7 of security review findings
+//
+//
+// 53 12/17/12 3:10p Alexp
+// code fixes according to "cppcheck" style & performance suggestions
+//
+// 52 12/06/12 7:31p Alexp
+// Update ImageAuthorization()
+//
+// 51 11/26/12 10:46a Alexp
+// replaced hardwired Var name L"SecureBootSetup" to generic Var define
+//
+// 50 11/19/12 4:42p Alexp
+// Fix for Win8 SecureBoot logo requirement: restore Secure Boot state
+// across flash updates.
+// Move all secure boot Setup settings to a separate varsore variable.
+// Preserve var across re-flash
+//
+// 49 11/09/12 4:32p Alexp
+// IsPkcsSignedDataVerifiedBySignatureList()
+// Fix CertData size - excude EFI_GUID size
+//
+// 48 10/17/12 3:03p Alexp
+// EIP[104046]: Findings from Security review on Aptio4 Image verification
+// Includes the fix for item #4:
+// HashPeImage returns TRUE even in error case
+//
+// 47 10/16/12 3:53p Alexp
+// EIP[104046]: Findings from Security review on Aptio4 Image verification
+// Includes the fix for item #7 from the list attached to the EIP
+//
+// 46 9/25/12 11:22a Alexp
+// removed ImageVerify simulation when system in SetupMode.
+//
+// 45 9/24/12 12:26p Alexp
+// fix code branch for WIN_CERT_TYPE_EFI_GUID certificates
+//
+// 44 9/19/12 4:07p Alexp
+// fix code branch to set action EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED
+//
+// 43 9/14/12 3:42p Alexp
+// Hardwire LoadFromFv to AlwaysEnable irrespective of SetupData
+//
+// 42 9/13/12 11:38a Alexp
+// Fix Bug in HashPeiImage.
+// Last step 16 in hashing of optional data structures after the
+// Certificate entry was missing
+//
+// 41 9/07/12 9:37a Alexp
+// 1. Set all global variables Static
+// 2. IsPkcsSignedDataVerifiedBySignatureList(). Compiler optimization for
+// "IsVerified = VerifyWinCertificateForPkcsSignedData(
+// &(PkcsCertData->Hdr));"
+// may not link the main code.
+// 3. Run Verify code when platform is in SetupMode and SecureBoot set to
+// Custom
+//
+// 39 9/05/12 5:42p Alexp
+// GetImageType() :
+// Change Device Path search criteria to match EDKII example:
+// check FV path first and then Block I/O
+//
+// 38 8/29/12 11:16a Alexp
+// Add definition for EFI_MAX_ADDRESS if it's not defined elsewhere in
+// included header files
+//
+// 37 8/28/12 4:21p Alexp
+// Restore dependencies on SecureBootMode->Custom Setup option
+//
+// 35 8/15/12 4:16p Alexp
+// IsPkcsSignedDataVerifiedBySignatureList()
+// Fix bug prev version in processing multiple Certs from PE Hdr.
+//
+// 34 7/26/12 3:54p Alexp
+// Query User -> Append Certificate only available in Setup Mode.
+//
+// 33 7/25/12 6:45p Alexp
+// 1. Update ImageVerification logic to the latest EDK2 patch (13469)
+// Add support for multiple Signatures within PE/COFF table
+// Additional Header validation checks
+// 2. Add code flow when SecureBoot set to Custom mode.
+// Image Verification is performed but failing images are allowed to
+// run
+// Use this mode to append image certificates to DB in User Query mode.
+//
+// 32 6/11/12 3:15p Alexp
+// use modified WIN_CERTIFICATE_UEFI_GUID_1 struc in
+// AppendEfiImageSecurityDatabaseVariableEx()
+// moded struc is shorter by 4 bytes
+//
+// 30 5/18/12 9:21a Alexp
+// Fine tune User Query messages. Only display the messages if Admin user
+// has signed in
+//
+// 29 5/01/12 4:43p Alexp
+// PCR[7] - mTrustSigDbOffs contains offset to SigData struct within SigDb
+//
+// 28 4/27/12 3:57p Alexp
+// Fix Certificate type in AppendEfiImageSecurityDatabaseVariableEx()
+//
+// 27 4/23/12 5:19p Alexp
+// EIP:80874 Made changes to support PCR[7] measurments for Secure Boot
+// state in TCG
+// Install "Efi Boot Image Certificate" info strusture on Efi System
+// Table.
+//
+// 26 4/20/12 5:14p Alexp
+// Add new function to install the handle on Efi System Table with the
+// location
+// within DB variable of the Trusted Certificate that was used to verify
+// signature of Efi OS BootLoader image.
+//
+// 25 4/10/12 6:52p Alexp
+// Update VerifyCertPkcsSignedData() to support extended search in
+// Forbidded db for any leaf certificate, not only Root CA
+//
+// 23 4/03/12 7:35p Alexp
+// Move ReadImage() under legacy SecureFileAuthentication()
+//
+// 22 4/02/12 4:24p Alexp
+// Installs EFI_SECURITY2_ARCH_PROTOCOL.
+// Input arguments include File Path and pointer to a File buffer in
+// memory.
+//
+// 20 3/20/12 10:51a Alexp
+// 1. fix in AppendEfiImageSecurityDatabaseVariableEx()
+// 2. removed unused global vars
+//
+// 18 3/16/12 10:29a Alexp
+// [EIP85500] Build problem with (INT)4.6.5.1_SECUREBOOT_WIN8_11
+// move "extern EFI_GUID BdsConnectDriversProtocolGuid " outside of #ifdef
+// scope
+//
+// 17 3/13/12 2:41p Alexp
+// Add check for Admin signed credentials while allowing User Querry
+// policy
+//
+// 16 3/12/12 3:01p Alexp
+// 1. Deffer image verification till BdsConnectDriversProtocol event.
+// Speeds up the boot time.
+// 2. Enforce default (hardwired by SDL token) image veriication policy
+// for image device path if SecureBootMode is set to Standard.
+//
+// 15 3/09/12 3:39p Alexp
+// 1. Fixed Image authentication by Hash certificate in "db"
+// 2. Add User interructive controls to append image certificate to Sig
+// "db" (test implementation, will change in later releases)
+//
+// 14 2/27/12 6:47p Alexp
+// Reduce time spent in the DxeImageVerificationHandler function during
+// non-Secure Boot mode. Original code caused additional 0.5 sec to boot
+// time.
+// Note: internal SecureBoot mode flag once registered during
+// initializaton - will not change until restart.
+//
+// 13 1/04/12 3:27p Alexp
+// Fixed possible security risk:
+// GetImageType(). Block I/O Device Path check made higher priority then
+// of FV device path.
+//
+// 12 12/29/11 6:49p Alexp
+// GetImageType() - Fix for Image Device Path resolution
+// Added SubType = MEDIA_FV_FILEPATH_DP to search options for
+// MEDIA_DEVICE_PATH.
+// It appears SmmDriverDispatcher sets this device path for files loaded
+// by SmmDispatcher.
+//
+// 11 12/23/11 8:59a Alexp
+// Bug fix:
+// EIP:78978:Secure boot will hang at CP 0x72
+// ConOut & ConIn are not available until later in BDS phase, earlier
+// calls to display User Prompt may hang the system
+//
+// 10 12/07/11 7:23p Alexp
+// Bug fix:
+// EIP:77088 SecureBoot: Image can be loaded if click "No" when query
+// user after image verification failed
+// ImageAuthorization() -> Return EFI_ACCESS_DENIED of User Override
+// option
+//
+// 9 8/22/11 11:14a Alexp
+// optimizations to GetImageType()
+//
+// 6 7/18/11 4:12p Alexp
+// EIP:65085. LoadImage Error status is different When Secure Boot is ON
+// EIP:65194: No way to control the Secure Boot module to not interact
+// with the USER without changing the code
+//
+// 4 6/23/11 9:27a Alexp
+// moved mDigitalSig Protocol check up before API may be called
+//
+// 3 6/22/11 5:45p Alexp
+// draft change: add Sha256 as valid cert for "db" databases
+//
+// 2 6/13/11 7:21p Alexp
+// fix Hash calculation for Sha256 Certs in Forbidden database dbx
+//
+// 10 5/17/11 5:36p Alexp
+// update conOut messages
+//
+// 9 5/17/11 12:50p Alexp
+// replace AmiPostManager with pST->ConOut
+// use pBS instead of gBS
+//
+// 6 5/13/11 4:02p Alexp
+// 1. add dependency on Core rev. 4.6.5+ to buld for older Aptio cores
+// 2. Ignore Querry User policy for internal FV files
+//
+//**********************************************************************
+/*++
+ This file contains an 'Intel Peripheral Driver' and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+--*/
+/** @file
+
+ Implement image verification services for secure boot
+ service in UEFI2.2.
+
+ Caution: This file requires additional review when modified.
+ This library will have external input - PE/COFF image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content
+ read is within the image buffer.
+
+ DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept
+ 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>
+
+This software and associated documentation (if any) is furnished
+under a license and may only be used or copied in accordance
+with the terms of the license. Except as permitted by such
+license, no part of this software or documentation may be
+reproduced, stored in a retrieval system, or transmitted in any
+form or by any means without the express written consent of
+Intel Corporation.
+
+**/
+
+#pragma warning (disable : 4090)
+
+#include <Token.h>
+#include <Protocol/Security.h>
+#include "DxeImageVerificationLib.h"
+#include "EfiImage.h"
+#include <AmiDxeLib.h>
+#include<Guid/PeiPeCoffLoader.h>
+#include <Protocol/AmiDigitalSignature.h>
+#include <AmiCertificate.h>
+#include <Setup.h>
+#include <SecureBootMod.h>
+#include <Protocol/PciIo.h> //EIP 122339
+#include <cryptlib.h>
+
+extern EFI_GUID BdsConnectDriversProtocolGuid;
+
+// 4.6.5.4
+#if defined(CORE_COMBINED_VERSION) && CORE_COMBINED_VERSION >=0x4028e
+#include <Protocol/Security2.h>
+#endif
+
+// 4.6.5.1
+#if defined(CORE_COMBINED_VERSION) && CORE_COMBINED_VERSION >=0x4028b
+#include <EdkIICommon.h>
+#else
+#include <Tiano.h>
+
+//********tmp declaration from EdkIICommon.h
+#define MEDIA_RELATIVE_OFFSET_RANGE_DP 0x08
+
+extern VOID ZeroMem (
+ OUT VOID *Buffer,
+ IN UINTN Size
+);
+VOID* CopyMem (
+ OUT VOID *DestinationBuffer,
+ IN VOID *SourceBuffer,
+ IN UINTN Length
+);
+#endif
+EFI_STATUS
+EFIAPI
+PeCoffLoaderGetImageInfo (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextOut.h>
+
+#define AMI_MEDIA_DEVICE_PATH_GUID \
+ { 0x5023b95c, 0xdb26, 0x429b, 0xa6, 0x48, 0xbd, 0x47, 0x66, 0x4c, 0x80, 0x12 }
+
+#define STANDARD_SECURE_BOOT 0
+#define CUSTOM_SECURE_BOOT 1
+
+static EFI_GUID AmiMediaDevicePathGuid = AMI_MEDIA_DEVICE_PATH_GUID;
+static EFI_GUID gSecureSetupGuid = SECURITY_FORM_SET_GUID;
+static EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE;
+
+static AMI_DIGITAL_SIGNATURE_PROTOCOL *mDigitalSigProtocol = NULL;
+//
+// Caution: This is used by a function which may receive untrusted input.
+// These global variables hold PE/COFF image data, and they should be validated before use.
+//
+EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
+static UINT8 *mImageBase = NULL;
+static UINTN mImageSize;
+static EFI_GUID *mCertType;
+static UINT32 mPeCoffHeaderOffset;
+static UINT8 mImageDigest[MAX_DIGEST_SIZE];
+static UINTN mImageDigestSize;
+static SECURE_BOOT_SETUP_VAR mSecureBootSetup;
+static UINT8 mSecureBootEnable = 0;
+static UINTN mFvHandlesCount = 0;
+static EFI_HANDLE *mFvHandles = NULL;
+static BOOLEAN gImageLoadingAfterBDS = FALSE;
+
+//
+// Notify string for authorization UI.
+//
+CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"\r\nImage verification failed!\r\n";
+CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"\r\nLaunch this image anyway? (Y/N)";
+CHAR16 mNotifyString3[MAX_NOTIFY_STRING_LEN] = L"Image Certificate not found in Authorized database(db)!";
+CHAR16 mNotifyString4[MAX_NOTIFY_STRING_LEN] = L"Image Certificate is found in Forbidden database(dbx)!";
+CHAR16 mNotifyString5[MAX_NOTIFY_STRING_LEN] = L"Image is unsigned or Certificate is invalid!";
+
+//6683D10C-CF6E-4914-B5B4-AB8ED7370ED7
+EFI_GUID gBootImageCertTblGuid = AMI_VALID_BOOT_IMAGE_CERT_TBL_GUID;
+static UINT32 mTrustSigDbOffs = 0;
+static UINT32 mTrustSigDbSize = 0;
+
+//---------------------------------------
+// NEW TIME STAMP definitions ECR#1009
+//---------------------------------------
+extern EFI_GUID gEfiCertX509Sha256Guid;
+extern EFI_GUID gEfiCertX509Sha384Guid;
+extern EFI_GUID gEfiCertX509Sha512Guid;
+static INT32 mTimeOfSigningLong;
+typedef enum {
+ CertUndefined,
+ CertSha256,
+ CertX509,
+ CertX509Sha256,
+ CertX509Sha384,
+ CertX509Sha512,
+} nCertType;
+//---------------------------------------
+// NEW TIME STAMP definitions ECR#1009
+//---------------------------------------
+
+//************TEMP UTILITY FUNCTIONS. Use EDKII common wrapper lib instead****************
+#if defined(CORE_COMBINED_VERSION) && CORE_COMBINED_VERSION >=0x4028b
+#else
+UINTN StrSize (
+ IN CHAR16 *String)
+{
+ UINTN Size;
+
+ for (Size = 2; *String != L'\0'; String++, Size += 2);
+
+ return Size;
+}
+#endif
+
+VOID* GetEfiGlobalVariableEx (
+ IN CHAR16 *Name,
+ IN OUT UINTN *VarSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Var=NULL;
+
+ Status = GetEfiVariable(Name, &gEfiGlobalVariableGuid, NULL, VarSize, &Var);
+ return (EFI_ERROR(Status)) ? NULL : Var;
+}
+
+VOID* GetEfiImageSecurityDatabaseVariableEx (
+ IN CHAR16 *Name,
+ IN OUT UINTN *VarSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *Var = NULL;
+
+ Status = GetEfiVariable(Name, &gEfiImageSecurityDatabaseGuid, NULL, VarSize, &Var);
+ return (EFI_ERROR(Status)) ? NULL : Var;
+}
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image buffer.
+
+ @param FileHandle Pointer to the file handle to read the PE/COFF image.
+ @param FileOffset Offset into the PE/COFF image to begin the read operation.
+ @param ReadSize On input, the size in bytes of the requested read operation.
+ On output, the number of bytes actually read.
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.
+
+ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
+**/
+EFI_STATUS
+EFIAPI
+DxeImageVerificationLibImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((EFI_MAX_ADDRESS - FileOffset) < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((UINT64)FileOffset + *ReadSize) > mImageSize) {
+// *ReadSize = (UINT32)(mImageSize - FileOffset);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (FileOffset >= mImageSize) {
+// *ReadSize = 0;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get the image type.
+
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched.
+
+ @return UINT32 Image Type
+
+**/
+UINT32
+GetImageType (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ UINT8 nDevicePathSubType;
+ //EIP 122339 Start
+ EFI_PCI_IO_PROTOCOL *PciIoInterface = NULL;
+ UINT64 AttributesResult;
+ //EIP 122339 Stop
+ UINTN Index;
+ BOOLEAN IsFv = FALSE;
+
+ // Unknown device path: image security policy is applied to the image with the least trusted origin.
+ if (File == NULL) {
+ return IMAGE_UNKNOWN;
+ }
+
+ //
+ // Check if File is just a Firmware Volume.
+ //
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ while (!IsDevicePathEndType(TempDevicePath)){
+ nDevicePathSubType = DevicePathSubType (TempDevicePath);
+ TRACE((TRACE_ALWAYS,"Device PathType %x, SubType %x\n", DevicePathType(TempDevicePath), nDevicePathSubType ));
+ //
+ // EFI Specification extension on Media Device Path. MEDIA_FW_VOL_FILEPATH_DEVICE_PATH is adopted by UEFI later and added in UEFI2.10.
+ // In EdkCompatibility Package, we only support MEDIA_FW_VOL_FILEPATH_DEVICE_PATH that complies with EFI 1.10 and UEFI 2.10.
+ //
+ if( (DevicePathType(TempDevicePath) == MEDIA_DEVICE_PATH && nDevicePathSubType == MEDIA_FV_FILEPATH_DP) ||
+ (DevicePathType(TempDevicePath) == HARDWARE_DEVICE_PATH && nDevicePathSubType == HW_MEMMAP_DP)
+ ){
+ IsFv = TRUE;
+ } else {
+ IsFv = FALSE;
+ break;
+ }
+ TempDevicePath = NextDevicePathNode(TempDevicePath);
+ }
+
+ //
+ // Check to see if a File or a FV is from internal Firmware Volume.
+ //
+ if(IsFv) {
+
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = pBS->LocateDevicePath (
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
+ &gEfiFirmwareVolumeProtocolGuid,
+#else
+ &gEfiFirmwareVolume2ProtocolGuid,
+#endif
+ &TempDevicePath,
+ &DeviceHandle
+ );
+
+ if (!EFI_ERROR (Status)) {
+ if(!gImageLoadingAfterBDS)
+ return IMAGE_FROM_FV;
+
+ Status = pBS->OpenProtocol (
+ DeviceHandle,
+#if (PI_SPECIFICATION_VERSION < 0x00010000)
+ &gEfiFirmwareVolumeProtocolGuid,
+#else
+ &gEfiFirmwareVolume2ProtocolGuid,
+#endif
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ for(Index=0;Index < mFvHandlesCount;Index++){
+ TRACE((TRACE_ALWAYS,"FV%02d. DeviceHandle %X=%X\n", Index, DeviceHandle, mFvHandles[Index] ));
+ if(DeviceHandle == mFvHandles[Index] )
+ return IMAGE_FROM_FV;
+ }
+ }
+ }
+ return IMAGE_UNKNOWN;
+ }
+ //
+ // Next check to see if File is from a Block I/O device
+ // Must be a Block I/O device since we reached here after Int FV path check
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = pBS->LocateDevicePath (
+ &gEfiBlockIoProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ BlockIo = NULL;
+ Status = pBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status) && BlockIo != NULL) {
+ if (BlockIo->Media != NULL) {
+ if (BlockIo->Media->RemovableMedia) {
+ //
+ // Block I/O is present and specifies the media is removable
+ //
+ return IMAGE_FROM_REMOVABLE_MEDIA;
+ } else {
+ //
+ // Block I/O is present and specifies the media is not removable
+ //
+ return IMAGE_FROM_FIXED_MEDIA;
+ }
+ }
+ }
+ }
+ //
+ // 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;
+ Status = pBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Simple File System is present without Block I/O, so assume media is fixed.
+ //
+ return IMAGE_FROM_FIXED_MEDIA;
+ }
+
+ //
+ // 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.
+ //
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ nDevicePathSubType = DevicePathSubType (TempDevicePath);
+ switch (DevicePathType (TempDevicePath)) {
+ //EIP 219415 Start
+ //Embedded OpROM
+ case HARDWARE_DEVICE_PATH:
+
+ if(nDevicePathSubType == HW_MEMMAP_DP) {
+ //EIP 122339 Start: Return IMAGE_FROM_FV if the EFI_PCI_IO_PROTOCOL installed
+ //on the same handle as the Device Path has the attribute EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM
+ DeviceHandle = NULL;
+ //
+ // Check if an instance of the EFI_PCI_IO_PROTOCOL is installed on the same handle
+ // as the Device Path. If an instance is found WorkAroundDevHandle contains the
+ // handle for the Device Path and EFI_PCI_IO_PROTOCOL instance.
+ //
+ Status = pBS->LocateDevicePath(
+ &gEfiPciIoProtocolGuid,
+ &File,
+ &DeviceHandle
+ );
+ if(EFI_ERROR(Status)) break;
+
+ Status = pBS->HandleProtocol(
+ DeviceHandle,
+ &gEfiPciIoProtocolGuid,
+ &PciIoInterface
+ );
+
+ if(EFI_ERROR(Status)) break;
+
+ //
+ // Using the EFI_PCI_IO_PROTOCOL get the value of the PCI controller's
+ // Embedded Rom attribute (EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)
+ //
+ Status = PciIoInterface->Attributes(
+ PciIoInterface,
+ EfiPciIoAttributeOperationGet,
+ 0, //this parameter is ignored during Get operation
+ &AttributesResult
+ );
+ if(EFI_ERROR(Status)) break;
+ //
+ // Check if the PCI controller's EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM is set
+ //
+ if(AttributesResult & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)
+ return IMAGE_FROM_FV;
+ //EIP 122339 Stop
+ }
+ break;
+ //EIP 219415 end
+ case MEDIA_DEVICE_PATH:
+
+ if (nDevicePathSubType == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
+ return IMAGE_FROM_OPTION_ROM;
+ }
+#if LOAD_UNSIGNED_EMBEDDED_SHELL == 1
+ // Case for embedded FV application such as Shell(check GUID. BootOptions.h)
+ if (nDevicePathSubType == MEDIA_VENDOR_DP &&
+ !guidcmp(&((VENDOR_DEVICE_PATH*)TempDevicePath)->Guid, &AmiMediaDevicePathGuid)) {
+ return IMAGE_FROM_FV;
+ }
+#endif
+ break;
+
+ case MESSAGING_DEVICE_PATH:
+
+ if (nDevicePathSubType == MSG_MAC_ADDR_DP) {
+ return IMAGE_FROM_REMOVABLE_MEDIA;
+ }
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ return IMAGE_UNKNOWN;
+}
+
+/**
+ Caculate hash of Pe/Coff image based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ @param[in] HashAlg Hash algorithm type.
+
+ @retval TRUE Successfully hash image.
+ @retval FALSE Fail in hash image.
+
+**/
+BOOLEAN
+HashPeImage (
+ IN UINT32 HashAlg
+ )
+{
+ EFI_STATUS EfiStatus;
+ BOOLEAN Status;
+ UINT16 Magic;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ UINT8 *HashBase;
+ UINTN HashSize;
+ UINTN SumOfBytesHashed;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ UINTN Index;
+ UINTN Pos;
+
+ const UINT8 *addr[MAX_ELEM_NUM]; // tbd. test if 20 elements is enough
+ UINTN num_elem, len[MAX_ELEM_NUM];
+ EFI_GUID *EfiHashAlgorithmGuid;
+
+ UINT32 CertSize;
+ UINT32 NumberOfRvaAndSizes;
+
+ SectionHeader = NULL;
+ Status = FALSE;
+ EfiStatus = EFI_SECURITY_VIOLATION;
+ num_elem = 0;
+ //
+ // Initialize context of hash.
+ //
+ ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
+ if (HashAlg == HASHALG_SHA1) {
+ mImageDigestSize = SHA1_DIGEST_SIZE;
+ EfiHashAlgorithmGuid = &gEfiHashAlgorithmSha1Guid;
+ mCertType = &gEfiCertSha1Guid;
+ } else if (HashAlg == HASHALG_SHA256) {
+ mImageDigestSize = SHA256_DIGEST_SIZE;
+ EfiHashAlgorithmGuid = &gEfiHashAlgorithmSha256Guid;
+ mCertType = &gEfiCertSha256Guid;
+ } else {
+ return FALSE;
+ }
+
+ // 1. Load the image header into memory.
+
+ //
+ // Measuring PE/COFF Image Header;
+ // But CheckSum field and SECURITY data directory (certificate) are excluded
+ //
+ if (mNtHeader.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;
+ }
+
+ //
+ // 3. Calculate the distance from the base of the image header to the image checksum address.
+ // 4. Hash the image header from its base to beginning of the image checksum.
+ //
+ HashBase = mImageBase;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
+ NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ } else {
+ //
+ // Invalid header magic number.
+ //
+ TRACE((TRACE_ALWAYS,"Invalid header magic number.\n"));
+ goto Done;
+ }
+
+ if (HashSize != 0)
+ {
+ addr[num_elem] = HashBase;
+ len[num_elem++] = HashSize;
+ } else {
+//TRACE((TRACE_ALWAYS,"Hash1.%x\n", HashSize));
+ goto Done;}
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ //
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ //
+ // 6. Since there is no Cert Directory in optional header, hash everything
+ // from the end of the checksum to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);
+ }
+
+ if (HashSize != 0)
+ {
+ addr[num_elem] = HashBase;
+ len[num_elem++] = HashSize;
+ } else {
+//TRACE((TRACE_ALWAYS,"Hash2.%x\n", HashSize));
+ goto Done;}
+ } else {
+ //
+ // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } 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);
+ }
+ if (HashSize != 0)
+ {
+ addr[num_elem] = HashBase;
+ len[num_elem++] = HashSize;
+ } else {
+//TRACE((TRACE_ALWAYS,"Hash3.%x\n", HashSize));
+ goto Done;}
+
+ //
+ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
+ // 9. Hash everything from the end of the Cert Directory to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - mImageBase);
+ }
+ if (HashSize != 0)
+ {
+ addr[num_elem] = HashBase;
+ len[num_elem++] = HashSize;
+ } else {
+//TRACE((TRACE_ALWAYS,"Hash4.%x\n", HashSize));
+ goto Done;}
+ }
+
+ //
+ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
+ }
+
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ mImageBase +
+ mPeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ //
+ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
+ // structures in the image. The 'NumberOfSections' field of the image
+ // header indicates how big the table should be. Do not include any
+ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
+ //
+// TRACE((TRACE_ALWAYS,"Num Sections = %x\n", mNtHeader.Pe32->FileHeader.NumberOfSections));
+
+// Security review [305408]: HashPeImage does not validate NumberOfSections field
+ Pos = sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections;
+ if(Pos > mImageSize)
+ goto Done;
+
+ EfiStatus = pBS->AllocatePool(EfiBootServicesData, Pos, &SectionHeader);
+ if (SectionHeader == NULL || EFI_ERROR(EfiStatus)) {
+//TRACE((TRACE_ALWAYS,"Hash4.\n"));
+ goto Done;
+
+ }
+ MemSet(SectionHeader, Pos, 0);
+ //
+ // 12. Using the 'PointerToRawData' in the referenced section headers as
+ // a key, arrange the elements in the table in ascending order. In other
+ // words, sort the section headers according to the disk-file offset of
+ // the section.
+ //
+ for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
+ Pos = Index;
+
+ // Security review EIP[104046]:6. HashPeImage does not validate NumberOfSections field
+ if(((UINT64)Section + sizeof (EFI_IMAGE_SECTION_HEADER))> ((UINT64)mImageBase+mImageSize) )
+ goto Done;
+
+ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
+ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
+ Pos--;
+ }
+ CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
+ Section += 1;
+ }
+
+ //
+ // 13. Walk through the sorted table, bring the corresponding section
+ // into memory, and hash the entire section (using the 'SizeOfRawData'
+ // field in the section header to determine the amount of data to hash).
+ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
+ // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
+ //
+ for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
+ Section = &SectionHeader[Index];
+ if (Section->SizeOfRawData == 0) {
+ continue;
+ }
+
+//TRACE((TRACE_ALWAYS,"Section->PointerToRawData = %x\nSection->SizeOfRawData = %x\nSumOfBytesHashed = %x\n",Section->PointerToRawData, Section->SizeOfRawData, SumOfBytesHashed+Section->SizeOfRawData));
+ // Security review EIP[104046]: 5.HashPeImage does not validate PointerToRawData and SizeOfRawData fields
+ if( ((UINT64)Section->PointerToRawData + Section->SizeOfRawData) > mImageSize )
+ goto Done;
+
+ HashBase = mImageBase + Section->PointerToRawData;
+ HashSize = (UINTN) Section->SizeOfRawData;
+
+ addr[num_elem] = HashBase;
+ len[num_elem++] = HashSize;
+ if(num_elem >= MAX_ELEM_NUM)
+// goto Done;
+ {
+TRACE((TRACE_ALWAYS,"MAX_ELEM_NUM.1 = %d\n", num_elem));
+ goto Done;}
+ // Security review EIP[125931]: HashPeImage does not validate certificate table offset and size
+ if (((UINT64)SumOfBytesHashed+HashSize) > mImageSize)
+ goto Done;
+
+ SumOfBytesHashed += HashSize;
+ }
+
+ //
+ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
+ // data in the file that needs to be added to the hash. This data begins
+ // at file offset SUM_OF_BYTES_HASHED and its length is:
+ // FileSize - (CertDirectory->Size)
+ //
+//dbg
+//TRACE((TRACE_ALWAYS,"mImageSize > SumOfBytesHashed.\n%x > %x\n", mImageSize, SumOfBytesHashed));
+//dbg
+ if (mImageSize > SumOfBytesHashed) {
+
+ HashBase = mImageBase + SumOfBytesHashed;
+
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ CertSize = 0;
+ } else {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ }
+ }
+
+ if (mImageSize > ((UINT64)CertSize + SumOfBytesHashed)) {
+ HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);
+
+//TRACE((TRACE_ALWAYS,"\nData beyond nSumOfBytesHashed\nBase = %x, Size = %x\n",SumOfBytesHashed, HashSize));
+
+ addr[num_elem] = HashBase;
+ len[num_elem++] = HashSize;
+ if(num_elem >= MAX_ELEM_NUM)
+// goto Done;
+ {
+TRACE((TRACE_ALWAYS,"MAX_ELEM_NUM.2=%d\n", num_elem));
+ goto Done;}
+
+ } else if (mImageSize < ((UINT64)CertSize + SumOfBytesHashed)) {
+TRACE((TRACE_ALWAYS,"mImageSize < CertSize + SumOfBytesHashed.\n%d < %d\n", mImageSize, CertSize + SumOfBytesHashed));
+ goto Done;
+ }
+ else
+ HashSize = 0;
+ // ??? HashBase += CertSize;
+//TRACE((TRACE_ALWAYS,"\nData beyond CertDir\nBase = %x, Size = %x\n",SumOfBytesHashed+HashSize+CertSize, mImageSize-(SumOfBytesHashed+HashSize+CertSize)));
+ }
+ EfiStatus = mDigitalSigProtocol->Hash(
+ mDigitalSigProtocol,
+ EfiHashAlgorithmGuid, num_elem, addr, len, (UINT8*)&mImageDigest);
+
+TRACE((TRACE_ALWAYS,"Found HashElements %d\nImageHash: [%2X],[%2X],..\n", num_elem, mImageDigest[0], mImageDigest[1]));
+
+ if(!EFI_ERROR(EfiStatus))
+ Status = TRUE;
+
+Done:
+
+ if (SectionHeader != NULL) {
+ pBS->FreePool (SectionHeader);
+ }
+ // Security review EIP[104046]: 4.HashPeImage returns TRUE even in error case
+ // Status = FALSE unless updated to TRUE in the final Hash step before "Done" label
+ return Status;
+}
+
+/**
+ 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
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.
+ @param[in] AuthDataSize Size of the Authenticode Signature in bytes.
+
+ @retval EFI_UNSUPPORTED Hash algorithm is not supported.
+ @retval EFI_SUCCESS Hash successfully.
+
+**/
+EFI_STATUS
+HashPeImageByType (
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DigestAlgo;
+ UINT8 *pDigestAlgo;
+ UINTN Size;
+
+// get Digest Algorithm
+ Size = 0;
+ pDigestAlgo = (UINT8*)&DigestAlgo;
+ Status = mDigitalSigProtocol->Pkcs7Verify (
+ mDigitalSigProtocol,
+ AuthData,
+ AuthDataSize,
+ NULL,
+ 0,
+ &pDigestAlgo, // returns DER Ptr to Sign Cert
+ &Size,
+ Pkcs7GetDigestAlgorithm,
+ LOCK
+ );
+ if (EFI_ERROR(Status))
+ return Status;
+
+ switch(DigestAlgo) {
+ case SHA1:
+ if (!HashPeImage (HASHALG_SHA1)) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ break;
+ case SHA256:
+ if (!HashPeImage (HASHALG_SHA256)) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ break;
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Returns the size of a given image execution info table in bytes.
+
+ This function returns the size, in bytes, of the image execution info table specified by
+ 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.
+
+**/
+UINTN
+GetImageExeInfoTableSize (
+ EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable
+ )
+{
+ UINTN Index;
+ EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;
+ UINTN TotalSize;
+
+ if (ImageExeInfoTable == NULL) {
+ return 0;
+ }
+
+ ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));
+ TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
+ for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {
+ TotalSize += ImageExeInfoItem->InfoSize;
+ ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ImageExeInfoItem->InfoSize);
+ }
+
+ return TotalSize;
+}
+
+/**
+ Create an Image Execution Information Table entry and add it to system configuration table.
+
+ @param[in] Action Describes the action taken by the firmware regarding this image.
+ @param[in] Name Input a null-terminated, user-friendly name.
+ @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 CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_SIGNATURE_LIST *Signature OPTIONAL,
+ IN UINTN SignatureSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;
+ EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;
+ EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;
+ UINTN ImageExeInfoTableSize;
+ UINTN NewImageExeInfoEntrySize;
+ UINTN NameStringLen;
+ UINTN DevicePathSize;
+
+ NewImageExeInfoTable = NULL;
+ ImageExeInfoEntry = NULL;
+ NameStringLen = sizeof (CHAR16);
+
+ if (DevicePath == NULL) {
+ return ;
+ }
+
+ if (Name != NULL) {
+ NameStringLen = StrSize (Name);
+ }
+
+ ImageExeInfoTable = GetEfiConfigurationTable(pST, &gEfiImageSecurityDatabaseGuid);
+ if (ImageExeInfoTable != NULL) {
+ //
+ // The table has been found!
+ // We must enlarge the table to accmodate the new exe info entry.
+ //
+ ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);
+ } else {
+ //
+ // Not Found!
+ // We should create a new table to append to the configuration table.
+ //
+ ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
+ }
+
+ DevicePathSize = DPLength(DevicePath);
+ NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
+
+ Status = pBS->AllocatePool(EfiRuntimeServicesData, ImageExeInfoTableSize + NewImageExeInfoEntrySize, &NewImageExeInfoTable);
+ if(EFI_ERROR(Status)) return;
+
+ if (ImageExeInfoTable != NULL) {
+ CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);
+ } else {
+ NewImageExeInfoTable->NumberOfImages = 0;
+ }
+ NewImageExeInfoTable->NumberOfImages++;
+ ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);
+ //
+ // Update new item's infomation.
+ //
+ ImageExeInfoEntry->Action = Action;
+ ImageExeInfoEntry->InfoSize = (UINT32) NewImageExeInfoEntrySize;
+
+ if (Name != NULL) {
+ CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);
+ } else {
+ ZeroMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), NameStringLen);
+ }
+ CopyMem (
+ (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,
+ DevicePath,
+ DevicePathSize
+ );
+ if (Signature != NULL) {
+ CopyMem (
+ (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,
+ Signature,
+ SignatureSize
+ );
+ }
+ //
+ // Update/replace the image execution table.
+ //
+ Status = pBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Free Old table data!
+ //
+ if (ImageExeInfoTable != NULL) {
+ pBS->FreePool (ImageExeInfoTable);
+ }
+}
+
+/**
+ Create a Boot Image Certificate table entry and add it to system configuration table.
+
+ @param[in] Name Input a null-terminated, user-friendly name.
+ @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
+AddBootImageCertInfo (
+ IN CHAR16 *Name OPTIONAL,
+ IN UINT32 SignatureOffs,
+ IN UINT32 SignatureSize
+ )
+{
+ EFI_STATUS Status;
+ AMI_VALID_CERT_IN_SIG_DB *BootImageCertInfoTable;
+ UINTN BootImageCertInfoTableSize;
+
+ if(SignatureOffs == 0 || SignatureSize == 0)
+ return;
+
+ BootImageCertInfoTable = GetEfiConfigurationTable(pST, &gBootImageCertTblGuid);
+ if (BootImageCertInfoTable == NULL) {
+ //
+ // Not Found!
+ // We should create a new table.
+ //
+ BootImageCertInfoTableSize = sizeof (AMI_VALID_CERT_IN_SIG_DB);
+ Status = pBS->AllocatePool(EfiRuntimeServicesData, BootImageCertInfoTableSize, &BootImageCertInfoTable);
+ if(EFI_ERROR(Status)) return;
+ //
+ // Update/replace the image execution table.
+ //
+ Status = pBS->InstallConfigurationTable (&gBootImageCertTblGuid, (VOID *) BootImageCertInfoTable);
+ ASSERT_EFI_ERROR (Status);
+ TRACE((TRACE_ALWAYS,"Install BootImageCert Table ...%r\n", Status));
+ if (EFI_ERROR (Status)) return;
+ }
+ //
+ // Update Table's infomation.
+ //
+ BootImageCertInfoTable->SigOffset = SignatureOffs;
+ BootImageCertInfoTable->SigLength = SignatureSize;
+
+TRACE((TRACE_ALWAYS,"BootImage Cert in db\nOffset=%X\nLength=%X\n", BootImageCertInfoTable->SigOffset, BootImageCertInfoTable->SigLength));
+}
+
+/**
+ Discover if the UEFI image is authorized by user's policy setting.
+
+ @param[in] Policy Specify platform's policy setting.
+ @param[in] Action Image Validation status.
+
+ @retval EFI_ACCESS_DENIED Image is not allowed to run.
+ @retval EFI_SECURITY_VIOLATION Image is deferred.
+ @retval EFI_SUCCESS Image is authorized to run.
+
+**/
+EFI_STATUS
+ImageAuthorization (
+ IN UINT32 Policy,
+ IN UINT32 Action
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key = {0,0};
+ UINTN Index;
+ BOOLEAN bQuery;
+
+ Status = EFI_ACCESS_DENIED;
+
+ switch (Policy) {
+
+ case QUERY_USER_ON_SECURITY_VIOLATION:
+ // Conditions to allow overwrite of Execution Policy:
+ // 1. Output Console available
+ if((pST->ConIn != NULL && pST->ConOut != NULL))
+ {
+ pST->ConOut->OutputString(pST->ConOut, mNotifyString1);
+ bQuery = TRUE;
+ switch(Action) {
+ case EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND: // not found in db
+ pST->ConOut->OutputString(pST->ConOut, mNotifyString3);
+ break;
+ case EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND: // found in dbx
+ pST->ConOut->OutputString(pST->ConOut, mNotifyString4);
+ break;
+ case EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED:
+ case EFI_IMAGE_EXECUTION_AUTH_UNTESTED:
+ pST->ConOut->OutputString(pST->ConOut, mNotifyString5);
+ break;
+ default:
+ bQuery = FALSE;
+ break;
+ }
+ if(!bQuery) break;
+ //Wait for key
+ pST->ConOut->OutputString(pST->ConOut, mNotifyString2);
+Repeat:
+ pBS->WaitForEvent( 1, &pST->ConIn->WaitForKey, &Index );
+ Status = pST->ConIn->ReadKeyStroke( pST->ConIn, &Key );
+ if (!EFI_ERROR (Status)) {
+ if ((Key.UnicodeChar == L'y') || (Key.UnicodeChar == L'Y')) { //yes
+ Status = EFI_SUCCESS;
+ } else if ((Key.UnicodeChar == L'n') || (Key.UnicodeChar == L'N')) { //no
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ goto Repeat;
+ }
+ }
+ pST->ConOut->OutputString(pST->ConOut, L"\r\n");
+ }
+ break;
+
+ case DEFER_EXECUTE_ON_SECURITY_VIOLATION:
+ Status = EFI_SECURITY_VIOLATION;
+ break;
+
+ // case DENY_EXECUTE_ON_SECURITY_VIOLATION:
+ default:
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+TRACE((TRACE_ALWAYS,"Image Authorization policy...%r\n", Status));
+
+ return Status;
+}
+
+/**
+ Advanced check in Signature Database
+ Check whether signature is located in target database
+
+ @param[in] Signature Pointer to signature that is searched for.
+ @param[in] SignatureSize Size of Signature.
+ @param[in] SignatureType Type of the Certificate, Guid
+
+ @return TRUE - found in IsSigForbidden
+ @return FALSE
+
+**/
+BOOLEAN
+IsSignatureFoundInDatabase (
+ IN CHAR16 *Name,
+ EFI_GUID *SignatureType,
+ IN UINT8 *Signature,
+ IN UINTN SignatureSize
+ )
+{
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINTN Index;
+ UINTN CertCount;
+ BOOLEAN IsSigFound;
+
+ //
+ // Read signature database variable.
+ //
+ IsSigFound = FALSE;
+
+ //
+ // Get Signature Database variable.
+ //
+
+ Data = GetEfiImageSecurityDatabaseVariableEx (Name, &DataSize);
+
+ if (Data != NULL) {
+// not an error if no "dbx" defined
+ //
+ // Enumerate all signature data in SigDB to check if executable's signature exists.
+ //
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while (!IsSigFound && (DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
+ if (!guidcmp(&CertList->SignatureType, SignatureType)) { // Cert types do match
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ if (CertList->SignatureSize == (sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize)) {
+ for (Index = 0; Index < CertCount; Index++) {
+ if (MemCmp(Cert->SignatureData, Signature, SignatureSize) == 0) {
+ //
+ // Find the signature in database.
+ //
+ IsSigFound = TRUE;
+ break;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+ } // next CertList
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+ pBS->FreePool (Data);
+ }
+
+ return IsSigFound;
+}
+
+
+/**
+ Verify PKCS#7 SignedData using certificate found in Variable which formatted
+ as EFI_SIGNATURE_LIST. The Variable may be PK, KEK, DB or DBX.
+
+ @param VariableName Name of Variable to search for Certificate.
+
+ @retval TRUE Image pass verification.
+ @retval FALSE Image fail verification.
+
+**/
+BOOLEAN
+IsPkcsSignedDataVerifiedBySignatureList (
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize,
+ IN CHAR16 *VariableName,
+ IN UINT8 Operation
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINT32 CertCount;
+ UINT32 Index;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINT8 *SigCert;
+ UINTN SigCertSize;
+ BOOLEAN IsVerified;
+ EFI_TIME *TimeStamp;
+ INT32 TimeOfRevocationLong;
+ UINT8 ValidCertType;
+ BOOLEAN bVerifyTimeStampStatus;
+ BOOLEAN bProcessVerifyTimeStampStatus;
+
+ CertList = NULL;
+ Cert = NULL;
+ RootCert = NULL;
+ RootCertSize = 0;
+ IsVerified = FALSE;
+ ValidCertType = CertUndefined;
+ bVerifyTimeStampStatus= FALSE;
+ bProcessVerifyTimeStampStatus = FALSE;
+
+ mTimeOfSigningLong = 0;
+ TimeOfRevocationLong = 0;
+ // Verify the certificate's header
+ //
+ // Find certificate in store and verify authenticode struct.
+ //
+ Data = GetEfiImageSecurityDatabaseVariableEx (VariableName, &DataSize);
+
+ if (!Data)
+ return IsVerified;
+
+TRACE((TRACE_ALWAYS,"\nLook for a match in '%S'===>\n\n", VariableName));
+
+ CertList = (EFI_SIGNATURE_LIST *)Data;
+
+ //
+ // TO DO Optimization.
+ // 1. Find Root CA Cert Ptr or Signer Cert if Root is not found
+ // 2. loop thru Trust Cert list and compare each one against Root CA cert(verify SignCert signature with Trust Cert)
+ // 3. If found, break the 'while' loop and Pkcs7Verify with Trust Cert
+ //
+ //
+ // Find Cert Enrolled in database to verify the signature in pkcs7 signed data.
+ //
+ // here should be a loop thru Cert list till CertCount
+ while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
+
+ if(!guidcmp(&CertList->SignatureType, &gEfiCertX509Guid))
+ ValidCertType = CertX509;
+ else
+ if(!guidcmp(&CertList->SignatureType, mCertType))
+ ValidCertType = CertSha256;
+ else
+ if(!guidcmp(&CertList->SignatureType, &gEfiCertX509Sha256Guid))
+ ValidCertType = CertX509Sha256;
+ else
+ if(!guidcmp(&CertList->SignatureType, &gEfiCertX509Sha384Guid))
+ ValidCertType = CertX509Sha384;
+ else
+ if(!guidcmp(&CertList->SignatureType, &gEfiCertX509Sha512Guid))
+ ValidCertType = CertX509Sha512;
+
+ if (ValidCertType)
+ {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ RootCertSize = CertList->SignatureSize-sizeof(EFI_GUID); // sig data structure starts with SigOwner Guid
+TRACE((TRACE_ALWAYS,"Signature Type %g\nRootCertSize = %X\n",CertList->SignatureType, RootCertSize));
+
+ for (Index = 0; Index < CertCount; Index++) {
+ //
+ // Iterate each Signature Data Node within this CertList for verify.
+ //
+ RootCert = Cert->SignatureData;
+ switch(ValidCertType) {
+// is Sha256/Sha1
+ case CertSha256:
+ if(RootCertSize == mImageDigestSize &&
+ MemCmp(RootCert, mImageDigest, mImageDigestSize) == 0) {
+TRACE((TRACE_ALWAYS,"Hash Cert match found...\n"));
+ //
+ // Found the signature in database.
+ //
+ IsVerified = TRUE;
+ }
+ break;
+// x509, x509_ShaXXX
+/*
+Revocation is true:
+- return success && Time = 0
+- return success && Time != 0 && VerifyTimeStampStatus
+- success
+if success but mVerifyTimeStampStatus = ACCESS_DENIED = return FAIL
+timestamp non-0 Year > 0
+*/
+ case CertX509Sha256:
+ case CertX509Sha384:
+ case CertX509Sha512:
+ switch(ValidCertType) {
+ case CertX509Sha256:
+ TimeStamp = &((EFI_CERT_X509_SHA256*)RootCert)->TimeOfRevocation;
+ break;
+ case CertX509Sha384:
+ TimeStamp = &((EFI_CERT_X509_SHA384*)RootCert)->TimeOfRevocation;
+ break;
+ case CertX509Sha512:
+ TimeStamp = &((EFI_CERT_X509_SHA512*)RootCert)->TimeOfRevocation;
+ break;
+ }
+ // Check the timestamp cert validity the valid certificate in allowed database (dbt).
+ if(!bProcessVerifyTimeStampStatus) {
+ bVerifyTimeStampStatus = IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE2, Pkcs7TimeStampCertValidateGet);
+ bProcessVerifyTimeStampStatus = TRUE;
+ }
+ if(os_mktime(TimeStamp->Year, TimeStamp->Month, TimeStamp->Day, TimeStamp->Hour, TimeStamp->Minute, TimeStamp->Second,&TimeOfRevocationLong))
+ TimeOfRevocationLong = 0;
+TRACE((TRACE_ALWAYS,"\nTimeStamp cert validate %s\nTimeOfSigning %X\nTimeOfRevocation %X\n", (!bVerifyTimeStampStatus?"FAIL":"PASS"), mTimeOfSigningLong, TimeOfRevocationLong));
+ if(TimeOfRevocationLong) {
+ if(!bVerifyTimeStampStatus) {
+ IsVerified = TRUE; // found in dbx -> image is revoked!
+ break;
+ }
+ // keep looking for cert with sign time passed revocation
+ if(mTimeOfSigningLong < TimeOfRevocationLong)
+ break;
+ }
+ case CertX509:
+TRACE((TRACE_ALWAYS,"proceed with Pkcs7Verify...\n"));
+ //
+ //
+ // Verify Authenticode struct for image's current certificate.
+ //
+ // using protocol
+ SigCert = mImageDigest;
+ SigCertSize = mImageDigestSize;
+ Status = mDigitalSigProtocol->Pkcs7Verify (
+ mDigitalSigProtocol,
+ AuthData,
+ AuthDataSize,
+ RootCert,
+ RootCertSize,
+ // mDigest, DigestLen
+ &SigCert,
+ &SigCertSize,
+ Operation, // Operation; Pkcs7CertValidate OR Pkcs7CertGetMatchInCertChain
+ KEEP // Flags
+ );
+TRACE((TRACE_ALWAYS,"====> %r\n", Status));
+ if (!EFI_ERROR(Status)) {
+ IsVerified = TRUE; // found matching certificate in the image
+ switch(Operation) {
+ case Pkcs7TimeStampCertValidateGet:
+ mTimeOfSigningLong = (INT32)SigCertSize;
+ break;
+ case Pkcs7CertValidate:
+ // only x509 certs frm db are measured in PCR[7]
+ mTrustSigDbOffs = (UINT32)(UINT8*)(((UINT8*)Cert-Data));
+ mTrustSigDbSize = CertList->SignatureSize;
+ break;
+ }
+ }
+ break;
+ default :
+ goto Exit;
+ } // switch
+ if (IsVerified)
+ {
+ goto Exit;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ } // end for
+ } // end If
+
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ } // end while
+Exit:
+ pBS->FreePool (Data);
+TRACE((TRACE_ALWAYS,"\n<===%s cert match in '%S'\n",(IsVerified?"Got":"No"), VariableName));
+ return IsVerified;
+}
+
+
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: DxeImageVerificationHandler
+//
+// Description: Handle for Security Architectural Protocol
+// 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
+// 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.
+//
+// The image verification policy is:
+// If the image is signed,
+// At least one valid signature or at least one hash value of the image must match a record
+// in the security database "db", and no valid signature nor any hash value of the image may
+// be reflected in the security database "dbx".
+// Otherwise, the 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".
+//
+// Caution: This function may receive untrusted input.
+// PE/COFF image is external input, so this function will validate its data structure
+// within this image buffer before use.
+//
+// Input:
+// File This is a pointer to the device path of the file that is
+// being dispatched. This will optionally be used for logging.
+// FileBuffer File buffer matches the input file device path.
+// FileSize Size of File buffer matches the input file device path.
+//
+// Output: EFI_STATUS
+//
+// EFI_SUCCESS The file specified by File did authenticate, and the
+// platform policy dictates that the DXE Core may use File.
+// EFI_INVALID_PARAMETER File is NULL.
+// EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+// the platform policy dictates that File should be placed
+// in the untrusted state. A file may be promoted from
+// the untrusted to the trusted state at a future time
+// with a call to the Trust() DXE Service.
+// EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+// the platform policy dictates that File should not be
+// used for any purpose.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+
+EFI_STATUS
+DxeImageVerificationHandler (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+
+{
+ EFI_STATUS Status;
+ UINT16 Magic;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_STATUS VerifyStatus;
+ EFI_SIGNATURE_LIST *SignatureList;
+ UINTN SignatureListSize;
+ EFI_SIGNATURE_DATA *Signature;
+ EFI_IMAGE_EXECUTION_ACTION Action;
+ WIN_CERTIFICATE *WinCertificate;
+ UINT32 Policy;
+ BOOLEAN bFileRead;
+
+ EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINT32 NumberOfRvaAndSizes;
+
+ WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
+ WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;
+ UINT8 *AuthData;
+ UINTN AuthDataSize;
+ EFI_IMAGE_DATA_DIRECTORY *SecDataDir;
+ UINT32 OffSet;
+
+
+ SignatureList = NULL;
+ SignatureListSize = 0;
+ WinCertificate = NULL;
+ SecDataDir = NULL;
+ PkcsCertData = NULL;
+ Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
+ VerifyStatus = EFI_ACCESS_DENIED;
+ Status = EFI_ACCESS_DENIED;
+ bFileRead = FALSE;
+
+ mImageDigestSize = 0;
+ mCertType = NULL;
+ //
+ // Check the image type and get policy setting.
+ //
+ switch (GetImageType (File)) {
+
+ case IMAGE_FROM_FV:
+ Policy = ALWAYS_EXECUTE;
+ break;
+
+ case IMAGE_FROM_OPTION_ROM:
+ Policy = mSecureBootSetup.Load_from_OROM;
+ break;
+
+ case IMAGE_FROM_REMOVABLE_MEDIA:
+ Policy = mSecureBootSetup.Load_from_REMOVABLE_MEDIA;
+ break;
+
+ case IMAGE_FROM_FIXED_MEDIA:
+ Policy = mSecureBootSetup.Load_from_FIXED_MEDIA;
+ break;
+
+ default:
+TRACE((TRACE_ALWAYS,"Unknown Image Path\n"));
+ Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
+ break;
+ }
+
+ //
+ // If policy is always/never execute, return directly.
+ //
+ if (Policy == ALWAYS_EXECUTE) {
+ return EFI_SUCCESS;
+ } else
+ if (Policy == NEVER_EXECUTE) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (FileBuffer == NULL) {
+ //
+ // Read the PE/COFF file.
+ //
+ TRACE((TRACE_ALWAYS,"FileAuthentication\nFileType = %x, SubType = %x\n", File->Type, File->SubType));
+ Status = ReadImage(FALSE, File, &FileBuffer, &FileSize, NULL, NULL, NULL);
+ TRACE((TRACE_ALWAYS,"File read(1)...%r\n", Status));
+ if(EFI_ERROR(Status)) {
+ Status = ReadImage(TRUE, File, &FileBuffer, &FileSize, NULL, NULL, NULL);
+ TRACE((TRACE_ALWAYS,"File read(2)...%r\n", Status));
+ if(EFI_ERROR(Status))
+ return EFI_ACCESS_DENIED;
+ }
+
+ bFileRead = TRUE;
+ }
+ //
+ // Read the Dos header.
+ //
+ ASSERT (FileBuffer != NULL);
+ if (FileBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ mImageBase = (UINT8 *) FileBuffer;
+ mImageSize = FileSize;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ if (EFI_ERROR (PeCoffLoaderGetImageInfo (NULL, &ImageContext)) ||
+ ( mImageSize< sizeof(EFI_IMAGE_DOS_HEADER)) ) {
+ //
+ // The information can't be gotten from the invalid PeImage
+ //
+ TRACE((TRACE_ALWAYS,"PeCoffLoaderGetImageInfo Error\n"));
+ goto Done;
+ }
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) mImageBase;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present,
+ // so read the PE header after the DOS image header.
+ //
+ mPeCoffHeaderOffset = DosHdr->e_lfanew;
+ } else {
+ mPeCoffHeaderOffset = 0;
+ }
+ // Security review EIP[104046]: 3.HashPeImage does not validate minimum image size
+ // Validate mPeCoffHeaderOffset is within the Image size range
+ if(((UINT64)mPeCoffHeaderOffset+sizeof(EFI_IMAGE_NT_HEADERS32)) > mImageSize) {
+ TRACE((TRACE_ALWAYS,"EFI_IMAGE_NT_SIGNATURE Error\n"));
+ goto Done;
+ }
+
+ //
+ // Check PE/COFF image.
+ //
+ mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);
+ if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ //
+ // It is not a valid Pe/Coff file.
+ //
+ TRACE((TRACE_ALWAYS,"EFI_IMAGE_NT_SIGNATURE Error\n"));
+ goto Done;
+ }
+
+ if (mNtHeader.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;
+ }
+
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ }
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ }
+ }
+
+ TRACE((TRACE_ALWAYS,"mImageSize %x\n", mImageSize));
+
+ //
+ // Start Image Validation.
+ //
+ if (SecDataDir && SecDataDir->Size) {
+ //
+ // Image is possibly signed
+ //
+ TRACE((TRACE_ALWAYS,"SecDataDir->VirtualAddress %x\nSecDataDir->Size = %x\nIMAGE is Signed\n",
+ SecDataDir->VirtualAddress, SecDataDir->Size));
+ // Security review EIP[104046]: 2.Multiple integer underflows calculating size of certificate data in PE file
+ if(((UINT64)SecDataDir->VirtualAddress+SecDataDir->Size) > mImageSize)
+ goto Done;
+
+ //
+ // 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.
+ //
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
+ for (OffSet = SecDataDir->VirtualAddress;
+ OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
+// OffSet += WinCertificate->dwLength, OffSet += ALIGN_SIZE (OffSet)) {
+ OffSet +=(WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {
+
+ WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
+ TRACE((TRACE_ALWAYS,"\nOffSet = %x, WinCertificate->dwLength %x\n\n", OffSet, WinCertificate->dwLength));
+ if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||
+ (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {
+ break;
+ }
+ //
+ // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.
+ //
+ //
+ // Verify signature of executables.
+ //
+
+ if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+ //
+ // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the
+ // Authenticode specification.
+ //
+ PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
+ if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
+ break;
+ }
+ AuthData = PkcsCertData->CertData;
+ AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
+
+ } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
+ //
+ // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
+ //
+ WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
+ if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+ break;
+ }
+ if (guidcmp (&WinCertUefiGuid->CertType, &gEfiCertTypePkcs7Guid)) {
+ continue;
+ }
+ AuthData = WinCertUefiGuid->CertData;
+ AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
+
+ } else {
+ if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
+ break;
+ }
+ continue;
+ }
+ //
+ // Verify Pkcs signed data type.
+ //
+ // At least 1 Cert from Pe Image should be in DB
+ // None of Certs should be found in DBX
+ //
+ // get Digest Algorithm, set mCertType
+ // lock mutex, preserve Pkcs7 context
+ Status = HashPeImageByType (AuthData, AuthDataSize);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Check the digital signature against the revoked certificate in forbidden database (dbx).
+ //
+ if (IsPkcsSignedDataVerifiedBySignatureList (AuthData, AuthDataSize, EFI_IMAGE_SECURITY_DATABASE1, Pkcs7CertGetMatchInCertChain)) {
+
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
+ 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, Pkcs7CertValidate)) {
+
+ VerifyStatus = EFI_SUCCESS;
+ }
+ }
+ // clear context
+ Status = mDigitalSigProtocol->Pkcs7Verify (
+ mDigitalSigProtocol,
+ AuthData, AuthDataSize,
+ NULL, 0,
+ NULL, NULL,
+ Pkcs7Arg0, // Dummy op
+ RESET // Flags
+ );
+
+ } // end multi-sig for
+
+// if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size + ALIGN_SIZE(SecDataDir->Size))) {
+ if(Action != EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
+ if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
+ TRACE((TRACE_ALWAYS,"Offset outside of CertDir boundary %X != %x\n", OffSet, SecDataDir->VirtualAddress + SecDataDir->Size));
+ //
+ // The Size in Certificate Table or the attribute certificate table is corrupted.
+ //
+ VerifyStatus = EFI_ACCESS_DENIED;
+ } else
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND;
+ }
+
+ } // end Signed cert branch
+
+ // Image not Signed or
+ // Image is Signed, its Cert verified in db but not found in DBX
+ if(mCertType != &gEfiCertSha256Guid &&
+ Action != EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
+
+ //
+ // This image is not signed or signed but found only in db or failed previous checks.
+ // Expected:
+ // 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".
+ //
+ TRACE((TRACE_ALWAYS,"IMAGE not Signed\n\tor signed with non-Sha256, Try Sha256 Hash Cert...\n"));
+
+ if(!HashPeImage (HASHALG_SHA256)) // init Hash type and calculate PE hash if not done already
+ goto Done;
+
+ if(IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, &gEfiCertSha256Guid, mImageDigest, mImageDigestSize)) {
+ //
+ // Image Hash in forbidden database (DBX)
+ //
+ VerifyStatus = EFI_ACCESS_DENIED;
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
+ } else
+ // no - try in allowed db if not there already
+ if(EFI_ERROR (VerifyStatus) &&
+ IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, &gEfiCertSha256Guid, mImageDigest, mImageDigestSize)) {
+ //
+ // Image Hash is in allowed database (DB).
+ //
+ VerifyStatus = EFI_SUCCESS;
+ }
+ }
+ //
+ // Signature database check after verification.
+ //
+ if(!EFI_ERROR (VerifyStatus) ) {
+ //
+ // Executable signature is found in authorized signature database.
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_ACCESS_DENIED;
+
+ if(Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
+ //
+ // Executable signature is found in forbidden signature database.
+ //
+ TRACE((TRACE_ALWAYS,"Certificate IS FOUND in Forbidden database!\n"));
+ } else
+ //
+ // Verification failure.
+ //
+ if(Action == EFI_IMAGE_EXECUTION_AUTH_SIG_NOT_FOUND) {
+ //
+ // Executable signature cannot be found in authorized signature database.
+ // Use platform policy to determine the action.
+ //
+ TRACE((TRACE_ALWAYS,"Certificate NOT FOUND in authorized database!\n"));
+ }
+ else
+ TRACE((TRACE_ALWAYS,"Image Certificate is Invalid!\n"));
+
+ TRACE((TRACE_ALWAYS,"%r Record added to Image Execution Table\n", Status));
+
+ if(!mCertType || !mImageDigestSize ) {
+ goto Done;
+ }
+ SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;
+
+ // Security review EIP[104046]:7. Unchecked AllocatePool may result in NULL pointer dereference
+ if (!EFI_ERROR(pBS->AllocatePool(EfiBootServicesData, SignatureListSize, &SignatureList)))
+ {
+ MemSet(SignatureList, SignatureListSize, 0);
+ SignatureList->SignatureHeaderSize = 0;
+ SignatureList->SignatureListSize = (UINT32) SignatureListSize;
+ SignatureList->SignatureSize = (UINT32) mImageDigestSize;
+ CopyMem (&SignatureList->SignatureType, mCertType, sizeof (EFI_GUID));
+ Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));
+ CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);
+ }
+ if (SignatureList != NULL) {
+ pBS->FreePool (SignatureList);
+ }
+ }
+Done:
+ if (Status != EFI_SUCCESS) {
+ //
+ // Policy decides to defer or reject the image; add its information in image executable information table.
+ //
+ AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);
+ // Treat unsecured images according to Image Authorization policy
+ Status = ImageAuthorization (Policy, Action);
+ }
+ if(bFileRead)
+ pBS->FreePool (FileBuffer);
+
+TRACE((TRACE_ALWAYS,"Image Verification ...%r\n", Status));
+ return Status;
+}
+
+//===================== Security Architectural Protocol ======================
+#ifndef EFI_SECURITY2_ARCH_PROTOCOL_GUID
+#define EFI_SECURITY2_ARCH_PROTOCOL_GUID \
+ { 0x94ab2f58, 0x1438, 0x4ef1, 0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0xe, 0x68 }
+
+typedef struct _EFI_SECURITY2_ARCH_PROTOCOL EFI_SECURITY2_ARCH_PROTOCOL;
+
+typedef EFI_STATUS (EFIAPI *EFI_SECURITY2_FILE_AUTHENTICATION) (
+ IN CONST EFI_SECURITY2_ARCH_PROTOCOL *This,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+);
+
+struct _EFI_SECURITY2_ARCH_PROTOCOL {
+ EFI_SECURITY2_FILE_AUTHENTICATION FileAuthentication;
+};
+
+static EFI_GUID gEfiSecurity2ArchProtocolGuid = EFI_SECURITY2_ARCH_PROTOCOL_GUID;
+#endif
+
+EFI_STATUS SecureFileAuthentication2(
+ IN CONST EFI_SECURITY2_ARCH_PROTOCOL *This,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ EFI_STATUS Status;
+
+ TRACE((TRACE_ALWAYS,"...............Call Security2 Arch proto.. File=%x, FileBuffer=%x, FileSize=%d\n",File,FileBuffer,FileSize ));
+
+ //
+ // skip verification if platform is NOT in SECURE BOOT MODE
+ //
+ if(mSecureBootEnable == 0)
+ return EFI_SUCCESS;
+
+ //
+ // Protocol should have been installed by AmiDigitalSig Driver once it's dispatched
+ //
+ if( mDigitalSigProtocol == NULL )
+ return EFI_ACCESS_DENIED;
+
+ Status = DxeImageVerificationHandler(File, FileBuffer, FileSize, BootPolicy);
+ // Install Tbl only on the Boot Loader launch
+ if (!EFI_ERROR (Status)/* && BootPolicy*/) {
+ AddBootImageCertInfo(NULL, mTrustSigDbOffs, mTrustSigDbSize);
+ mTrustSigDbOffs = 0;
+ mTrustSigDbSize = 0;
+ }
+ TRACE((TRACE_ALWAYS,"...............return status %r\n",Status));
+ return Status;
+}
+
+EFI_STATUS SecureFileAuthentication(
+ IN EFI_SECURITY_ARCH_PROTOCOL *This,
+ IN UINT32 AuthenticationStatus,
+ IN EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ BOOLEAN BootPolicy;
+ VOID *FileBuffer;
+ UINTN FileSize;
+
+ BootPolicy = TRUE;
+ FileBuffer = NULL;
+ FileSize = 0;
+
+ TRACE((TRACE_ALWAYS,".........Call Security Arch proto.. File=%x\n",File));
+
+ if (File == NULL)
+ return EFI_INVALID_PARAMETER;
+
+ //Security Protocol w/a: BootPolicy == 1 if File->Type == 4 Media Dev Path
+// if(File->Type == 4) // Media Dev Path
+// BootPolicy=TRUE;
+
+ return SecureFileAuthentication2(NULL, File, FileBuffer, FileSize, BootPolicy);
+}
+
+EFI_SECURITY2_ARCH_PROTOCOL mSecurity2 = {SecureFileAuthentication2};
+EFI_SECURITY_ARCH_PROTOCOL mSecurity = {SecureFileAuthentication};
+
+//----------------------------------------------------------------------------
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: InitDigitalProtocolCallback
+//
+// Description: This function initialize mDigitalSigProtocol ptr
+//
+//
+// Input: IN EFI_EVENT Event - Event that was triggered
+// IN VOID *Context - data pointer to information that is defined
+// when the event is registered
+//
+// Output: EFI_STATUS
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+static EFI_STATUS InitDigitalProtocolCallback(IN EFI_EVENT Event, IN VOID *Context)
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT8 *pSecureBootEnable=NULL;
+ //
+ // Look up for image authorization policy in "SetupData" variable
+ //
+#if (defined(ENABLE_IMAGE_EXEC_POLICY_OVERRIDE) && ENABLE_IMAGE_EXEC_POLICY_OVERRIDE == 1)
+ DataSize = sizeof(mSecureBootSetup);
+ Status = pRS->GetVariable (AMI_SECURE_BOOT_SETUP_VAR,&gSecureSetupGuid,NULL,&DataSize,&mSecureBootSetup);
+ if(EFI_ERROR(Status) ||
+ // Standard boot mode policy->apply defaults
+ mSecureBootSetup.SecureBootMode == STANDARD_SECURE_BOOT ||
+ // Policy check against fixed settings
+ mSecureBootSetup.Load_from_OROM < LOAD_FROM_OROM ||
+ mSecureBootSetup.Load_from_REMOVABLE_MEDIA < LOAD_FROM_REMOVABLE_MEDIA ||
+ mSecureBootSetup.Load_from_FIXED_MEDIA < LOAD_FROM_FIXED_MEDIA
+ )
+#endif
+ {
+ mSecureBootSetup.Load_from_OROM = LOAD_FROM_OROM;
+ mSecureBootSetup.Load_from_REMOVABLE_MEDIA = LOAD_FROM_REMOVABLE_MEDIA;
+ mSecureBootSetup.Load_from_FIXED_MEDIA = LOAD_FROM_FIXED_MEDIA;
+ }
+ //
+ // SecureBoot variable to be installed along with NVRAM driver
+ //
+ pSecureBootEnable = GetEfiGlobalVariableEx (EFI_SECURE_BOOT_NAME, &DataSize);
+ if(pSecureBootEnable && DataSize==1)
+ mSecureBootEnable = *pSecureBootEnable;
+ //
+ // will skip verification if platform is NOT in SECURE BOOT MODE
+ //
+ if(mSecureBootEnable == 0)
+ return EFI_SUCCESS;
+
+ Status = pBS->LocateHandleBuffer (
+ ByProtocol,
+ #if (PI_SPECIFICATION_VERSION < 0x00010000)
+ &gEfiFirmwareVolumeProtocolGuid,
+ #else
+ &gEfiFirmwareVolume2ProtocolGuid,
+ #endif
+ NULL,
+ &mFvHandlesCount,
+ &mFvHandles
+ );
+ if(!EFI_ERROR(Status)){
+ gImageLoadingAfterBDS = TRUE;
+ }
+
+ return pBS->LocateProtocol( &gAmiDigitalSignatureProtocolGuid, NULL, &mDigitalSigProtocol );
+}
+
+extern BOOLEAN const InstallDummySecurityProtocol;
+//<AMI_PHDR_START>
+//----------------------------------------------------------------------------
+// Procedure: InstallSecurityArchProtocol
+//
+// Description: This function installs the EFI_SECURITY_ARCH_PROTOCOL.
+// It is called at DxeCoreInitialize.
+//
+// Input:
+// EFI_HANDLE ImageHandle Image handle.
+// EFI_SYSTEM_TABLE *SystemTable Pointer to the EFI system table.
+//
+// Output:
+// EFI_SUCCESS : Security Architecture protocols are successfully installed.
+//
+//----------------------------------------------------------------------------
+//<AMI_PHDR_END>
+VOID InstallSecurityArchProtocol(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_HANDLE Handle = NULL;
+ EFI_EVENT Event;
+ VOID *p;
+
+ if (InstallDummySecurityProtocol)
+ return;
+
+ // Enable Security verification at beginning of BDS connect controller phase,
+ // We assume all drivers before the event were launched from internal FV
+ // !!! This bds event is only available since core 4.6.3.5.
+ RegisterProtocolCallback(
+ &BdsConnectDriversProtocolGuid,
+ InitDigitalProtocolCallback,
+ NULL,
+ &Event,
+ &p
+ );
+ // Security2 Arch protocol must be installed before Security Arch protocol
+ pBS->InstallMultipleProtocolInterfaces(
+ &Handle,
+ &gEfiSecurity2ArchProtocolGuid, &mSecurity2,
+ &gEfiSecurityArchProtocolGuid, &mSecurity,
+ NULL
+ );
+}
+
+#pragma warning (default : 4090)
+//**********************************************************************
+//**********************************************************************
+//** **
+//** (C)Copyright 1985-2011, American Megatrends, Inc. **
+//** **
+//** All Rights Reserved. **
+//** **
+//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
+//** **
+//** Phone: (770)-246-8600 **
+//** **
+//**********************************************************************
+//**********************************************************************
+//**********************************************************************