summaryrefslogtreecommitdiffstats
path: root/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
diff options
context:
space:
mode:
authorChao Zhang <chao.b.zhang@intel.com>2015-12-07 06:20:02 +0000
committerczhang46 <czhang46@Edk2>2015-12-07 06:20:02 +0000
commit4fc08e8d683522f255727626197d919a40d4836c (patch)
tree6358202293021f6508e1417ebf68d3530037b185 /SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
parentaf9af05bec5b1880f8e4f9142ecc0044fd0acb33 (diff)
downloadedk2-4fc08e8d683522f255727626197d919a40d4836c.tar.gz
edk2-4fc08e8d683522f255727626197d919a40d4836c.tar.bz2
edk2-4fc08e8d683522f255727626197d919a40d4836c.zip
SecurityPkg: AuthVariableLib: Customized SecureBoot Mode transition.
Implement Customized SecureBoot Mode transition logic according to Mantis 1263, including AuditMode/DeployedMode/PK update management. Also implement image verification logic in AuditMode. Image Certificate & Hash are recorded to EFI Image Execution Table. https://mantis.uefi.org/mantis/view.php?id=1263 Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Chao Zhang <chao.b.zhang@intel.com> Reviewed-by: Zeng Star <star.zeng@intel.com> Reviewed-by: Long Qin <qin.long@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19133 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c')
-rw-r--r--SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c670
1 files changed, 634 insertions, 36 deletions
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
index 5cb9f8144e..4b4d3bf77d 100644
--- a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -712,6 +712,58 @@ GetImageExeInfoTableSize (
}
/**
+ Create signature list based on input signature data and certificate type GUID. Caller is reposible
+ to free new created SignatureList.
+
+ @param[in] SignatureData Signature data in SignatureList.
+ @param[in] SignatureDataSize Signature data size.
+ @param[in] CertType Certificate Type.
+ @param[out] SignatureList Created SignatureList.
+ @param[out] SignatureListSize Created SignatureListSize.
+
+ @return EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS Successfully create signature list.
+
+**/
+EFI_STATUS
+CreateSignatureList(
+ IN UINT8 *SignatureData,
+ IN UINTN SignatureDataSize,
+ IN EFI_GUID *CertType,
+ OUT EFI_SIGNATURE_LIST **SignatureList,
+ OUT UINTN *SignatureListSize
+ )
+{
+ EFI_SIGNATURE_LIST *SignList;
+ UINTN SignListSize;
+ EFI_SIGNATURE_DATA *Signature;
+
+ SignList = NULL;
+ *SignatureList = NULL;
+
+ SignListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + SignatureDataSize;
+ SignList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignListSize);
+ if (SignList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SignList->SignatureHeaderSize = 0;
+ SignList->SignatureListSize = (UINT32) SignListSize;
+ SignList->SignatureSize = (UINT32) SignatureDataSize + sizeof (EFI_SIGNATURE_DATA) - 1;
+ CopyMem (&SignList->SignatureType, CertType, sizeof (EFI_GUID));
+
+ DEBUG((EFI_D_INFO, "SignatureDataSize %x\n", SignatureDataSize));
+ Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignList + sizeof (EFI_SIGNATURE_LIST));
+ CopyMem (Signature->SignatureData, SignatureData, SignatureDataSize);
+
+ *SignatureList = SignList;
+ *SignatureListSize = SignListSize;
+
+ return EFI_SUCCESS;
+
+}
+
+/**
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.
@@ -737,11 +789,13 @@ AddImageExeInfo (
UINTN NewImageExeInfoEntrySize;
UINTN NameStringLen;
UINTN DevicePathSize;
+ CHAR16 *NameStr;
ImageExeInfoTable = NULL;
NewImageExeInfoTable = NULL;
ImageExeInfoEntry = NULL;
NameStringLen = 0;
+ NameStr = NULL;
if (DevicePath == NULL) {
return ;
@@ -769,7 +823,12 @@ AddImageExeInfo (
}
DevicePathSize = GetDevicePathSize (DevicePath);
- NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
+
+ //
+ // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align
+ //
+ NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
+
NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
if (NewImageExeInfoTable == NULL) {
return ;
@@ -788,19 +847,21 @@ AddImageExeInfo (
WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);
+ NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);
if (Name != NULL) {
- CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen);
+ CopyMem ((UINT8 *) NameStr, Name, NameStringLen);
} else {
- ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16));
+ ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));
}
+
CopyMem (
- (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen,
+ (UINT8 *) NameStr + NameStringLen,
DevicePath,
DevicePathSize
);
if (Signature != NULL) {
CopyMem (
- (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen + DevicePathSize,
+ (UINT8 *) NameStr + NameStringLen + DevicePathSize,
Signature,
SignatureSize
);
@@ -1088,6 +1149,53 @@ IsTimeZero (
}
/**
+ Record multiple certificate list & verification state of a verified image to
+ IMAGE_EXECUTION_TABLE.
+
+ @param[in] CertBuf Certificate list buffer.
+ @param[in] CertBufLength Certificate list buffer.
+ @param[in] Action Certificate list action to be record.
+ @param[in] ImageName Image name.
+ @param[in] ImageDevicePath Image device path.
+
+**/
+VOID
+RecordCertListToImageExeuctionTable(
+ IN UINT8 *CertBuf,
+ IN UINTN CertBufLength,
+ IN EFI_IMAGE_EXECUTION_ACTION Action,
+ IN CHAR16 *ImageName OPTIONAL,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
+ )
+{
+ UINT8 CertNumber;
+ UINT8 *CertPtr;
+ UINTN Index;
+ UINT8 *Cert;
+ UINTN CertSize;
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *SignatureList;
+ UINTN SignatureListSize;
+
+ CertNumber = (UINT8) (*CertBuf);
+ CertPtr = CertBuf + 1;
+ for (Index = 0; Index < CertNumber; Index++) {
+ CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);
+ Cert = (UINT8 *)CertPtr + sizeof (UINT32);
+
+ //
+ // Record all cert in cert chain to be passed
+ //
+ Status = CreateSignatureList(Cert, CertSize, &gEfiCertX509Guid, &SignatureList, &SignatureListSize);
+ if (!EFI_ERROR(Status)) {
+ AddImageExeInfo (Action, ImageName, ImageDevicePath, SignatureList, SignatureListSize);
+ FreePool (SignatureList);
+ }
+ }
+}
+
+
+/**
Check whether the timestamp signature is valid and the signing time is also earlier than
the revocation time.
@@ -1197,8 +1305,11 @@ Done:
Check whether the image signature is forbidden by the forbidden database (dbx).
The image is forbidden to load if any certificates for signing are revoked before signing time.
- @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.
- @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+ @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.
+ @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+ @param[in] IsAuditMode Whether system Secure Boot Mode is in AuditMode.
+ @param[in] ImageName Name of the image to verify.
+ @param[in] ImageDevicePath DevicePath of the image to verify.
@retval TRUE Image is forbidden by dbx.
@retval FALSE Image is not forbidden by dbx.
@@ -1206,8 +1317,11 @@ Done:
**/
BOOLEAN
IsForbiddenByDbx (
- IN UINT8 *AuthData,
- IN UINTN AuthDataSize
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize,
+ IN BOOLEAN IsAuditMode,
+ IN CHAR16 *ImageName OPTIONAL,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
)
{
EFI_STATUS Status;
@@ -1230,7 +1344,10 @@ IsForbiddenByDbx (
UINT8 *Cert;
UINTN CertSize;
EFI_TIME RevocationTime;
-
+ UINT8 *SignerCert;
+ UINTN SignerCertLength;
+ UINT8 *UnchainCert;
+ UINTN UnchainCertLength;
//
// Variable Initialization
//
@@ -1245,6 +1362,10 @@ IsForbiddenByDbx (
BufferLength = 0;
TrustedCert = NULL;
TrustedCertLength = 0;
+ SignerCert = NULL;
+ SignerCertLength = 0;
+ UnchainCert = NULL;
+ UnchainCertLength = 0;
//
// The image will not be forbidden if dbx can't be got.
@@ -1352,21 +1473,54 @@ IsForbiddenByDbx (
}
Done:
+ if (IsForbidden && IsAuditMode) {
+ Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, &UnchainCert, &UnchainCertLength);
+
+ //
+ // Record all certs in image to be failed
+ //
+ if ((SignerCertLength != 0) && (SignerCert != NULL)) {
+ RecordCertListToImageExeuctionTable(
+ SignerCert,
+ SignerCertLength,
+ EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+ ImageName,
+ ImageDevicePath
+ );
+ }
+
+ if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
+ RecordCertListToImageExeuctionTable(
+ UnchainCert,
+ UnchainCertLength,
+ EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+ ImageName,
+ ImageDevicePath
+ );
+ }
+ }
+
if (Data != NULL) {
FreePool (Data);
}
Pkcs7FreeSigners (CertBuffer);
Pkcs7FreeSigners (TrustedCert);
+ Pkcs7FreeSigners (SignerCert);
+ Pkcs7FreeSigners (UnchainCert);
return IsForbidden;
}
+
/**
Check whether the image signature can be verified by the trusted certificates in DB database.
- @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.
- @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+ @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.
+ @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+ @param[in] IsAuditMode Whether system Secure Boot Mode is in AuditMode.
+ @param[in] ImageName Name of the image to verify.
+ @param[in] ImageDevicePath DevicePath of the image to verify.
@retval TRUE Image passed verification using certificate in db.
@retval FALSE Image didn't pass verification using certificate in db.
@@ -1374,14 +1528,17 @@ Done:
**/
BOOLEAN
IsAllowedByDb (
- IN UINT8 *AuthData,
- IN UINTN AuthDataSize
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize,
+ IN BOOLEAN IsAuditMode,
+ IN CHAR16 *ImageName OPTIONAL,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
)
{
EFI_STATUS Status;
BOOLEAN VerifyStatus;
EFI_SIGNATURE_LIST *CertList;
- EFI_SIGNATURE_DATA *Cert;
+ EFI_SIGNATURE_DATA *CertData;
UINTN DataSize;
UINT8 *Data;
UINT8 *RootCert;
@@ -1391,14 +1548,22 @@ IsAllowedByDb (
UINTN DbxDataSize;
UINT8 *DbxData;
EFI_TIME RevocationTime;
+ UINT8 *SignerCert;
+ UINTN SignerCertLength;
+ UINT8 *UnchainCert;
+ UINTN UnchainCertLength;
- Data = NULL;
- CertList = NULL;
- Cert = NULL;
- RootCert = NULL;
- DbxData = NULL;
- RootCertSize = 0;
- VerifyStatus = FALSE;
+ Data = NULL;
+ CertList = NULL;
+ CertData = NULL;
+ RootCert = NULL;
+ DbxData = NULL;
+ RootCertSize = 0;
+ VerifyStatus = FALSE;
+ SignerCert = NULL;
+ SignerCertLength = 0;
+ UnchainCert = NULL;
+ UnchainCertLength = 0;
DataSize = 0;
Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
@@ -1419,14 +1584,14 @@ IsAllowedByDb (
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;
+ CertData = (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 verify.
//
- RootCert = Cert->SignatureData;
+ RootCert = CertData->SignatureData;
RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
//
@@ -1468,7 +1633,7 @@ IsAllowedByDb (
goto Done;
}
- Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
}
}
@@ -1478,10 +1643,67 @@ IsAllowedByDb (
}
Done:
+
if (VerifyStatus) {
- SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);
+ SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);
+ }
+
+ if (IsAuditMode) {
+
+ Pkcs7GetCertificatesList(AuthData, AuthDataSize, &SignerCert, &SignerCertLength, &UnchainCert, &UnchainCertLength);
+ if (VerifyStatus) {
+ if ((SignerCertLength != 0) && (SignerCert != NULL)) {
+ //
+ // Record all cert in signer's cert chain to be passed
+ //
+ RecordCertListToImageExeuctionTable(
+ SignerCert,
+ SignerCertLength,
+ EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED,
+ ImageName,
+ ImageDevicePath
+ );
+ }
+
+ if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
+ //
+ // Record all certs in unchained certificates lists to be failed
+ //
+ RecordCertListToImageExeuctionTable(
+ UnchainCert,
+ UnchainCertLength,
+ EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+ ImageName,
+ ImageDevicePath
+ );
+ }
+ } else {
+ //
+ // Record all certs in image to be failed
+ //
+ if ((SignerCertLength != 0) && (SignerCert != NULL)) {
+ RecordCertListToImageExeuctionTable(
+ SignerCert,
+ SignerCertLength,
+ EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+ ImageName,
+ ImageDevicePath
+ );
+ }
+
+ if ((UnchainCertLength != 0) && (UnchainCert != NULL)) {
+ RecordCertListToImageExeuctionTable(
+ UnchainCert,
+ UnchainCertLength,
+ EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED,
+ ImageName,
+ ImageDevicePath
+ );
+ }
+ }
}
+
if (Data != NULL) {
FreePool (Data);
}
@@ -1489,10 +1711,370 @@ Done:
FreePool (DbxData);
}
+ Pkcs7FreeSigners (SignerCert);
+ Pkcs7FreeSigners (UnchainCert);
+
return VerifyStatus;
}
/**
+ Provide verification service for signed images in AuditMode, 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 AuditMode.
+ Executables from FV is bypass, so pass in AuthenticationStatus is ignored. Other authentication status
+ are record into IMAGE_EXECUTION_TABLE.
+
+ 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.
+
+ @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
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer File buffer matches the input file device path.
+ @param[in] FileSize Size of File buffer matches the input file device path.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The authenticate info is sucessfully stored for the file
+ specified by DevicePath and non-NULL FileBuffer
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation many not use File.
+
+**/
+EFI_STATUS
+EFIAPI
+ImageVerificationInAuditMode (
+ IN UINT32 AuthenticationStatus,
+ 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_SIGNATURE_LIST *SignatureList;
+ EFI_IMAGE_EXECUTION_ACTION Action;
+ WIN_CERTIFICATE *WinCertificate;
+ UINT32 Policy;
+ 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;
+ CHAR16 *FilePathStr;
+ UINTN SignatureListSize;
+
+ SignatureList = NULL;
+ WinCertificate = NULL;
+ SecDataDir = NULL;
+ PkcsCertData = NULL;
+ FilePathStr = NULL;
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED;
+ Status = EFI_ACCESS_DENIED;
+
+
+ //
+ // 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 = PcdGet32 (PcdOptionRomImageVerificationPolicy);
+ break;
+
+ case IMAGE_FROM_REMOVABLE_MEDIA:
+ Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
+ break;
+
+ case IMAGE_FROM_FIXED_MEDIA:
+ Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
+ break;
+
+ default:
+ Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
+ break;
+ }
+
+ //
+ // If policy is always/never execute, return directly.
+ //
+ if (Policy == ALWAYS_EXECUTE) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get Image Device Path Str
+ //
+ FilePathStr = ConvertDevicePathToText (File, FALSE, TRUE);
+
+ //
+ // Authentication failed because of (unspecified) firmware security policy
+ //
+ if (Policy == NEVER_EXECUTE) {
+ //
+ // No signature, record FilePath/FilePathStr only
+ //
+ AddImageExeInfo (EFI_IMAGE_EXECUTION_POLICY_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED, FilePathStr, File, NULL, 0);
+ goto END;
+ }
+
+ //
+ // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION
+ // violates the UEFI spec and has been removed.
+ //
+ ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);
+ if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {
+ CpuDeadLoop ();
+ }
+
+ //
+ // Read the Dos header.
+ //
+ if (FileBuffer == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto END;
+ }
+
+ mImageBase = (UINT8 *) FileBuffer;
+ mImageSize = FileSize;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ //
+ // The information can't be got from the invalid PeImage
+ //
+ goto END;
+ }
+
+
+ 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;
+ }
+
+ //
+ // 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.
+ //
+ Status = EFI_ACCESS_DENIED;
+ goto END;
+ }
+
+ if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_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];
+ }
+ }
+
+ //
+ // Start Image Validation.
+ //
+ if (SecDataDir == NULL || SecDataDir->Size == 0) {
+ //
+ // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
+ // and not be reflected in the security data base "dbx".
+ //
+ if (!HashPeImage (HASHALG_SHA256)) {
+ Status = EFI_ACCESS_DENIED;
+ goto END;
+ }
+
+ //
+ // Image Hash is in forbidden database (DBX).
+ //
+ if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
+ //
+ // Image Hash is in allowed database (DB).
+ //
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED;
+ }
+ }
+
+ //
+ // Add HASH digest for image without signature
+ //
+ Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, &SignatureList, &SignatureListSize);
+ if (!EFI_ERROR(Status)) {
+ AddImageExeInfo (Action, FilePathStr, File, SignatureList, SignatureListSize);
+ FreePool (SignatureList);
+ }
+ goto END;
+ }
+
+ //
+ // 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.
+ //
+ for (OffSet = SecDataDir->VirtualAddress;
+ OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
+ OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {
+ WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
+ 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.
+ //
+ 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 (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
+ continue;
+ }
+ AuthData = WinCertUefiGuid->CertData;
+ AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
+ } else {
+ if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
+ break;
+ }
+ continue;
+ }
+
+ Status = HashPeImageByType (AuthData, AuthDataSize);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED | EFI_IMAGE_EXECUTION_INITIALIZED;
+
+ //
+ // Check the digital signature against the revoked certificate in forbidden database (dbx).
+ // Check the digital signature against the valid certificate in allowed database (db).
+ //
+ if (!IsForbiddenByDbx (AuthData, AuthDataSize, TRUE, FilePathStr, File)) {
+ IsAllowedByDb (AuthData, AuthDataSize, TRUE, FilePathStr, File);
+ }
+
+ //
+ // Check the image's hash value.
+ //
+ if (!IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED | EFI_IMAGE_EXECUTION_INITIALIZED;
+ }
+ }
+
+ //
+ // Add HASH digest for image with signature
+ //
+ Status = CreateSignatureList(mImageDigest, mImageDigestSize, &mCertType, &SignatureList, &SignatureListSize);
+
+ if (!EFI_ERROR(Status)) {
+ AddImageExeInfo (Action, FilePathStr, File, SignatureList, SignatureListSize);
+ FreePool (SignatureList);
+ } else {
+ goto END;
+ }
+ }
+
+
+ if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
+ //
+ // The Size in Certificate Table or the attribute certicate table is corrupted.
+ //
+ Status = EFI_ACCESS_DENIED;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+END:
+
+ if (FilePathStr != NULL) {
+ FreePool(FilePathStr);
+ FilePathStr = NULL;
+ }
+
+ return Status;
+}
+
+/**
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.
@@ -1559,7 +2141,9 @@ DxeImageVerificationHandler (
EFI_IMAGE_EXECUTION_ACTION Action;
WIN_CERTIFICATE *WinCertificate;
UINT32 Policy;
- UINT8 *SecureBoot;
+ UINT8 *VarData;
+ UINT8 SecureBoot;
+ UINT8 AuditMode;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
UINT32 NumberOfRvaAndSizes;
WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
@@ -1579,6 +2163,20 @@ DxeImageVerificationHandler (
Status = EFI_ACCESS_DENIED;
VerifyStatus = EFI_ACCESS_DENIED;
+ GetEfiGlobalVariable2 (EFI_AUDIT_MODE_NAME, (VOID**)&VarData, NULL);
+ //
+ // Skip verification if AuditMode variable doesn't exist. AuditMode should always exist
+ //
+ if (VarData == NULL) {
+ return EFI_SUCCESS;
+ }
+ AuditMode = *VarData;
+ FreePool(VarData);
+
+ if (AuditMode == AUDIT_MODE_ENABLE) {
+ return ImageVerificationInAuditMode(AuthenticationStatus, File, FileBuffer, FileSize, BootPolicy);
+ }
+
//
// Check the image type and get policy setting.
//
@@ -1622,22 +2220,22 @@ DxeImageVerificationHandler (
CpuDeadLoop ();
}
- GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
+ GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&VarData, NULL);
//
// Skip verification if SecureBoot variable doesn't exist.
//
- if (SecureBoot == NULL) {
+ if (VarData == NULL) {
return EFI_SUCCESS;
}
+ SecureBoot = *VarData;
+ FreePool(VarData);
//
- // Skip verification if SecureBoot is disabled.
+ // Skip verification if SecureBoot is disabled but not AuditMode
//
- if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
- FreePool (SecureBoot);
+ if (SecureBoot == SECURE_BOOT_MODE_DISABLE) {
return EFI_SUCCESS;
}
- FreePool (SecureBoot);
//
// Read the Dos header.
@@ -1808,7 +2406,7 @@ DxeImageVerificationHandler (
//
// Check the digital signature against the revoked certificate in forbidden database (dbx).
//
- if (IsForbiddenByDbx (AuthData, AuthDataSize)) {
+ if (IsForbiddenByDbx (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
VerifyStatus = EFI_ACCESS_DENIED;
break;
@@ -1818,7 +2416,7 @@ DxeImageVerificationHandler (
// Check the digital signature against the valid certificate in allowed database (db).
//
if (EFI_ERROR (VerifyStatus)) {
- if (IsAllowedByDb (AuthData, AuthDataSize)) {
+ if (IsAllowedByDb (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
VerifyStatus = EFI_SUCCESS;
}
}