edk2/SecurityPkg/Library/DxeImageVerificationLib/GoogleTest/DxeImageVerificationLibGoogleTest.cpp
Alexander Gryanko 1dc6b5e3dd SecurityPkg: added image verification tests for signed images
Previous changes introduced tests for unsigned
images verified by hash entries in DB/DBX. This commit adds
tests covering verification of signed images, including
certificate chain validation as well as cases where image
hashes are checked against entries in DB/DBX.

Signed-off-by: Alexander Gryanko <xpahos@gmail.com>
2026-07-16 02:33:17 +00:00

1617 lines
50 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @file
Unit tests for the implementation of DxeImageVerificationLib.
Copyright (c) 2025, Yandex. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <GoogleTest/Library/MockDevicePathLib.h>
#include <GoogleTest/Library/MockUefiBootServicesTableLib.h>
#include <GoogleTest/Library/MockUefiLib.h>
#include <GoogleTest/Library/MockUefiRuntimeServicesTableLib.h>
#include <Library/GoogleTestLib.h>
extern "C" {
#include "Library/MemoryAllocationLib.h"
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Uefi.h>
#include "DxeImageVerificationLibGoogleTest.h"
}
//////////////////////////////////////////////////////////////////////////////
void
PrepareCertList (
UINTN Size,
UINTN BufferSize,
CONST EFI_GUID *SignatureType,
CONST UINT8 *Src,
EFI_SIGNATURE_LIST *Dst
)
{
Dst->SignatureListSize = (UINT32)BufferSize;
Dst->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + Size);
Dst->SignatureHeaderSize = 0;
CopyGuid (&Dst->SignatureType, SignatureType);
EFI_SIGNATURE_DATA *Data = (EFI_SIGNATURE_DATA *)(Dst + 1);
CopyGuid (&Data->SignatureOwner, &gEfiGlobalVariableGuid);
CopyMem (&Data->SignatureData[0], Src, Size);
}
void
ExpectBeforeHashCheck (
MockUefiBootServicesTableLib &BsMock,
MockDevicePathLib &DevicePathMock,
MockUefiRuntimeServicesTableLib &RtServicesMock
)
{
// Skip all checks that are called before hash verification. This also applies
// to signed binary files, as no additional mocks are needed before the
// signature verification starts.
// Do not allocate on stack
static UINT8 SetupMode = SECURE_BOOT_MODE_ENABLE;
EXPECT_CALL (BsMock, gBS_LocateDevicePath)
.Times (3)
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
EXPECT_CALL (DevicePathMock, IsDevicePathEndType)
.WillOnce (testing::Return ((BOOLEAN)TRUE));
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_SECURE_BOOT_MODE_NAME),
BufferEq (&gEfiGlobalVariableGuid, sizeof (EFI_GUID)),
testing::NotNull (),
testing::Pointee (testing::Eq (sizeof (SetupMode))),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (sizeof (SetupMode)),
SetArgBuffer<4> (&SetupMode, sizeof (SetupMode)),
testing::Return (EFI_SUCCESS)
)
);
}
void
ExpectHashCheckSkip (
MockUefiRuntimeServicesTableLib &RtServicesMock,
int n
)
{
// Here, the cycle and WillOnce are used because InSequence must be specified
// in the main function. When using InSequence, Times will retire.
for (int i = 0; i < n; i++) {
// Return not found for DBx to exit from the first
// IsSignatureFoundInDatabase
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (
&gEfiImageSecurityDatabaseGuid,
sizeof (EFI_GUID)
),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// IsFound is false, EFI_NOT_FOUND will proceed to the next algorithm
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (
&gEfiImageSecurityDatabaseGuid,
sizeof (EFI_GUID)
),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
}
}
template <size_t N>
void
ExpectHashDBValue (
MockUefiRuntimeServicesTableLib &RtServicesMock,
UINT8 (&CertListBuffer)[N],
UINTN BufferSize
)
{
// Return not found for DBx to exit from the first
// IsSignatureFoundInDatabase
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// Second call of IsSignatureFoundInDatabase for DB
// Get Size
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
// Return hash
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)BufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
SetArgBuffer<4> (&CertListBuffer[0], BufferSize),
testing::Return (EFI_SUCCESS)
)
);
// Hash verification does't exit the loop upon the first match
EXPECT_CALL (RtServicesMock, gRT_GetVariable)
.Times (testing::AnyNumber ())
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
}
EFI_STATUS
MockInstallConfigurationTable (
EFI_GUID *Guid,
VOID *Table
)
{
// LeakSanitizer workaround for AddImageExeInfo
if (Table != NULL) {
FreePool (Table);
}
return EFI_SUCCESS;
}
void
ExpectFailureJump (
MockDevicePathLib &DevicePathMock,
MockUefiLib &UefiMock,
MockUefiBootServicesTableLib &BsMock
)
{
EXPECT_CALL (DevicePathMock, ConvertDevicePathToText)
.WillRepeatedly (testing::Return ((CHAR16 *)NULL));
EXPECT_CALL (UefiMock, EfiGetSystemConfigurationTable)
.WillRepeatedly (testing::Return (EFI_SUCCESS));
EXPECT_CALL (DevicePathMock, GetDevicePathSize)
.WillRepeatedly (testing::Return ((UINTN)0));
EXPECT_CALL (BsMock, gBS_InstallConfigurationTable)
.WillRepeatedly (testing::Invoke (MockInstallConfigurationTable));
}
template <size_t N, size_t M>
void
ExpectForbiddenByDBxHash (
MockUefiRuntimeServicesTableLib &RtServicesMock,
UINT8 (&CertListBuffer)[N],
UINTN BufferSize,
UINT8 (&HashListBuffer)[M],
UINTN HashBufferSize
)
{
// Signature DBx check - EFI_NOT_FOUND
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// IsAllowedByDb - DB size check
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
// IsAllowedByDb - DB data (X509 certs entries)
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)BufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
SetArgBuffer<4> (&CertListBuffer[0], BufferSize),
testing::Return (EFI_SUCCESS)
)
);
// IsAllowedByDb DBx check root cert revoked
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// IsSignatureFoundInDatabase prepare buffer
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (HashBufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
// IsSignatureFoundInDatabase prohibit hash
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)HashBufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (HashBufferSize),
SetArgBuffer<4> (&HashListBuffer[0], HashBufferSize),
testing::Return (EFI_SUCCESS)
)
);
EXPECT_CALL (RtServicesMock, gRT_GetVariable)
.Times (testing::AnyNumber ())
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
}
template <size_t N>
void
ExpectNoSignatureHashDBValue (
MockUefiRuntimeServicesTableLib &RtServicesMock,
UINT8 (&HashCertListBuffer)[N],
UINTN HashBufferSize
)
{
// Signature DBx check - EFI_NOT_FOUND
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// IsAllowedByDb - DB size check
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (
&gEfiImageSecurityDatabaseGuid,
sizeof (EFI_GUID)
),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (HashBufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
// IsAllowedByDb - DB data (hash entries, no X509 certs)
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (
&gEfiImageSecurityDatabaseGuid,
sizeof (EFI_GUID)
),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)HashBufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (HashBufferSize),
SetArgBuffer<4> (&HashCertListBuffer[0], HashBufferSize),
testing::Return (EFI_SUCCESS)
)
);
// IsAllowedByDb (DBX) - NOT FOUND
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// IsSignatureFoundInDatabase (DBX) - NOT FOUND
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (testing::Return (EFI_NOT_FOUND));
// IsSignatureFoundInDatabase (DB) - size check
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (HashBufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
// IsSignatureFoundInDatabase (DB) - data (hash found)
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)HashBufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (HashBufferSize),
SetArgBuffer<4> (&HashCertListBuffer[0], HashBufferSize),
testing::Return (EFI_SUCCESS)
)
);
EXPECT_CALL (RtServicesMock, gRT_GetVariable)
.Times (testing::AnyNumber ())
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
}
template <size_t N>
void
ExpectCertForbiddenByDbx (
MockUefiRuntimeServicesTableLib &RtServicesMock,
UINT8 (&CertListBuffer)[N],
UINTN BufferSize
)
{
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)BufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
SetArgBuffer<4> (&CertListBuffer[0], BufferSize),
testing::Return (EFI_SUCCESS)
)
);
}
//////////////////////////////////////////////////////////////////////////////
class CheckImageTypeResult : public ::testing::Test
{
public:
EFI_DEVICE_PATH_PROTOCOL File;
protected:
MockUefiRuntimeServicesTableLib RtServicesMock;
MockUefiBootServicesTableLib BsMock;
MockDevicePathLib DevicePathMock;
EFI_STATUS Status;
UINT32 AuthenticationStatus;
VOID *FileBuffer;
UINTN FileSize;
BOOLEAN BootPolicy;
virtual void
SetUp (
)
{
AuthenticationStatus = 0;
FileBuffer = NULL;
FileSize = 0;
BootPolicy = FALSE;
}
};
TEST_F (CheckImageTypeResult, ImageTypeVerifySanity) {
// Sanity check
Status = DxeImageVerificationHandler (
AuthenticationStatus,
NULL,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_INVALID_PARAMETER);
}
TEST_F (CheckImageTypeResult, ImageTypeVerifyImageFromFv) {
EXPECT_CALL (BsMock, gBS_LocateDevicePath)
.WillRepeatedly (testing::Return (EFI_SUCCESS));
EXPECT_CALL (BsMock, gBS_OpenProtocol)
.WillRepeatedly (testing::Return (EFI_SUCCESS));
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
TEST_F (CheckImageTypeResult, ImageTypeVerifyImageFromOptionRom) {
auto TestFunc = [&] (EFI_STATUS ExpectedStatus) {
EXPECT_CALL (BsMock, gBS_LocateDevicePath)
.Times (3)
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
EXPECT_CALL (BsMock, gBS_OpenProtocol)
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
EXPECT_CALL (DevicePathMock, IsDevicePathEndType)
.WillOnce (testing::Return ((BOOLEAN)FALSE));
EXPECT_CALL (DevicePathMock, DevicePathType)
.WillOnce (testing::Return ((UINT8)MEDIA_DEVICE_PATH));
EXPECT_CALL (DevicePathMock, DevicePathSubType)
.WillOnce (testing::Return ((UINT8)MEDIA_RELATIVE_OFFSET_RANGE_DP));
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, ExpectedStatus);
};
PatchPcdSet32 (PcdOptionRomImageVerificationPolicy, ALWAYS_EXECUTE);
TestFunc (EFI_SUCCESS);
PatchPcdSet32 (PcdOptionRomImageVerificationPolicy, NEVER_EXECUTE);
TestFunc (EFI_ACCESS_DENIED);
}
TEST_F (CheckImageTypeResult, ImageTypeVerifyImageFromRemovableMedia) {
auto TestFunc = [&] (EFI_STATUS ExpectedStatus) {
EXPECT_CALL (BsMock, gBS_LocateDevicePath)
.Times (3)
.WillRepeatedly (testing::Return (EFI_NOT_FOUND));
EXPECT_CALL (DevicePathMock, IsDevicePathEndType)
.WillOnce (testing::Return ((BOOLEAN)FALSE));
EXPECT_CALL (DevicePathMock, DevicePathType)
.WillOnce (testing::Return ((UINT8)MESSAGING_DEVICE_PATH));
EXPECT_CALL (DevicePathMock, DevicePathSubType)
.WillOnce (testing::Return ((UINT8)MSG_MAC_ADDR_DP));
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, ExpectedStatus);
};
PatchPcdSet32 (PcdRemovableMediaImageVerificationPolicy, ALWAYS_EXECUTE);
TestFunc (EFI_SUCCESS);
PatchPcdSet32 (PcdRemovableMediaImageVerificationPolicy, NEVER_EXECUTE);
TestFunc (EFI_ACCESS_DENIED);
}
TEST_F (CheckImageTypeResult, ImageTypeVerifyImageFromFixedMedia) {
auto TestFunc = [&] (EFI_STATUS ExpectedStatus) {
EXPECT_CALL (BsMock, gBS_LocateDevicePath)
.WillOnce (testing::Return (EFI_NOT_FOUND))
.WillOnce (testing::Return (EFI_NOT_FOUND))
.WillOnce (testing::Return (EFI_SUCCESS));
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, ExpectedStatus);
};
PatchPcdSet32 (PcdFixedMediaImageVerificationPolicy, ALWAYS_EXECUTE);
TestFunc (EFI_SUCCESS);
PatchPcdSet32 (PcdFixedMediaImageVerificationPolicy, NEVER_EXECUTE);
TestFunc (EFI_ACCESS_DENIED);
}
//////////////////////////////////////////////////////////////////////////////
class CheckUnsignedImage : public ::testing::Test
{
public:
EFI_DEVICE_PATH_PROTOCOL File;
protected:
MockUefiRuntimeServicesTableLib RtServicesMock;
MockUefiBootServicesTableLib BsMock;
MockDevicePathLib DevicePathMock;
MockUefiLib UefiMock;
EFI_STATUS Status;
UINT32 AuthenticationStatus;
VOID *FileBuffer;
UINTN FileSize;
BOOLEAN BootPolicy;
virtual void
SetUp (
)
{
AuthenticationStatus = 0;
FileBuffer = NULL;
FileSize = 0;
BootPolicy = FALSE;
}
};
TEST_F (CheckUnsignedImage, HashNormalFlow) {
constexpr UINTN Hash512Size = sizeof (images::UnsignedCOFFSha512);
constexpr UINTN Hash384Size = sizeof (images::UnsignedCOFFSha384);
constexpr UINTN Hash256Size = sizeof (images::UnsignedCOFFSha256);
constexpr UINTN Hash1Size = sizeof (images::UnsignedCOFFSha1);
constexpr UINTN Hash512BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash512Size;
constexpr UINTN Hash384BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash384Size;
constexpr UINTN Hash256BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash256Size;
constexpr UINTN Hash1BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Hash1Size;
UINT8 Hash512CertListBuffer[Hash512BufferSize] = { 0 };
UINT8 Hash384CertListBuffer[Hash384BufferSize] = { 0 };
UINT8 Hash256CertListBuffer[Hash256BufferSize] = { 0 };
UINT8 Hash1CertListBuffer[Hash1BufferSize] = { 0 };
PrepareCertList (
Hash512Size,
Hash512BufferSize,
&gEfiCertSha512Guid,
&images::UnsignedCOFFSha512[0],
(EFI_SIGNATURE_LIST *)&Hash512CertListBuffer
);
{
// Do not delete this. Otherwise, GetVariable from ExpectHashDBValue will
// match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectHashDBValue<Hash512BufferSize> (
RtServicesMock,
Hash512CertListBuffer,
Hash512BufferSize
);
FileBuffer = (VOID *)&images::UnsignedCOFF;
FileSize = sizeof (images::UnsignedCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
PrepareCertList (
Hash384Size,
Hash384BufferSize,
&gEfiCertSha384Guid,
&images::UnsignedCOFFSha384[0],
(EFI_SIGNATURE_LIST *)&Hash384CertListBuffer
);
{
// Do not delete this. Otherwise, GetVariable from ExpectHashDBValue will
// match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
// Skip SHA512 check
ExpectHashCheckSkip (RtServicesMock, 1);
// SHA384 check
ExpectHashDBValue<Hash384BufferSize> (
RtServicesMock,
Hash384CertListBuffer,
Hash384BufferSize
);
FileBuffer = (VOID *)&images::UnsignedCOFF;
FileSize = sizeof (images::UnsignedCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
PrepareCertList (
Hash256Size,
Hash256BufferSize,
&gEfiCertSha256Guid,
&images::UnsignedCOFFSha256[0],
(EFI_SIGNATURE_LIST *)&Hash256CertListBuffer
);
{
// Do not delete this. Otherwise, GetVariable from ExpectHashDBValue will
// match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
// Skip SHA512, SHA384 check
ExpectHashCheckSkip (RtServicesMock, 2);
// SHA256 check
ExpectHashDBValue<Hash256BufferSize> (
RtServicesMock,
Hash256CertListBuffer,
Hash256BufferSize
);
FileBuffer = (VOID *)&images::UnsignedCOFF;
FileSize = sizeof (images::UnsignedCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
PrepareCertList (
Hash1Size,
Hash1BufferSize,
&gEfiCertSha1Guid,
&images::UnsignedCOFFSha1[0],
(EFI_SIGNATURE_LIST *)&Hash1CertListBuffer
);
{
// Do not delete this. Otherwise, GetVariable from ExpectHashDBValue will
// match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
// Skip SHA512, SHA384, SHA256 check
ExpectHashCheckSkip (RtServicesMock, 3);
ExpectHashDBValue<Hash1BufferSize> (
RtServicesMock,
Hash1CertListBuffer,
Hash1BufferSize
);
// Last check. No need to loop.
FileBuffer = (VOID *)&images::UnsignedCOFF;
FileSize = sizeof (images::UnsignedCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
}
TEST_F (CheckUnsignedImage, HashNoDBRecods) {
// Do not delete this. Otherwise, GetVariable from ExpectHashDBValue will
// match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
// Skip SHA512, SHA384, SHA256, SHA1 check
ExpectHashCheckSkip (RtServicesMock, 4);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
// Last check. No need to loop.
FileBuffer = (VOID *)&images::UnsignedCOFF;
FileSize = sizeof (images::UnsignedCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
TEST_F (CheckUnsignedImage, HashFoundDBx) {
constexpr UINTN Size = sizeof (images::UnsignedCOFFSha512);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Size;
UINT8 CertListBuffer[BufferSize] = { 0 };
PrepareCertList (
Size,
BufferSize,
&gEfiCertSha512Guid,
&images::UnsignedCOFFSha512[0],
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
// Do not delete this. Otherwise, GetVariable from ExpectHashDBValue will
// match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
// DBx routines
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)0)),
testing::IsNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
testing::Return (EFI_BUFFER_TOO_SMALL)
)
);
// Return hash
EXPECT_CALL (
RtServicesMock,
gRT_GetVariable (
Char16StrEq (EFI_IMAGE_SECURITY_DATABASE1),
BufferEq (&gEfiImageSecurityDatabaseGuid, sizeof (EFI_GUID)),
testing::IsNull (),
testing::Pointee (testing::Eq ((UINTN)BufferSize)),
testing::NotNull ()
)
)
.WillOnce (
testing::DoAll (
testing::SetArgPointee<3> (BufferSize),
SetArgBuffer<4> (&CertListBuffer[0], BufferSize),
testing::Return (EFI_SUCCESS)
)
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
// Last check. No need to loop.
FileBuffer = (VOID *)&images::UnsignedCOFF;
FileSize = sizeof (images::UnsignedCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
//////////////////////////////////////////////////////////////////////////////
class CheckSignedImage : public ::testing::Test
{
public:
EFI_DEVICE_PATH_PROTOCOL File;
protected:
MockUefiRuntimeServicesTableLib RtServicesMock;
MockUefiBootServicesTableLib BsMock;
MockDevicePathLib DevicePathMock;
MockUefiLib UefiMock;
EFI_STATUS Status;
UINT32 AuthenticationStatus;
VOID *FileBuffer;
UINTN FileSize;
BOOLEAN BootPolicy;
virtual void
SetUp (
)
{
AuthenticationStatus = 0;
FileBuffer = NULL;
FileSize = 0;
BootPolicy = FALSE;
}
};
TEST_F (CheckSignedImage, NormalFlowPkcs7) {
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + CertSize;
UINT8 CertListBuffer[BufferSize] = { 0 };
PrepareCertList (
CertSize,
BufferSize,
&gEfiCertX509Guid,
&certs::TestCertDer[0],
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
// Do not delete this. Otherwise, GetVariable from ExpectSignatureFoundInDb
// will match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectHashDBValue<BufferSize> (RtServicesMock, CertListBuffer, BufferSize);
FileBuffer = (VOID *)&images::PkcsCOFF;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
TEST_F (CheckSignedImage, NormalFlowUefiGuid) {
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + CertSize;
UINT8 CertListBuffer[BufferSize] = { 0 };
PrepareCertList (
CertSize,
BufferSize,
&gEfiCertX509Guid,
&certs::TestCertDer[0],
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
// Do not delete this. Otherwise, GetVariable from ExpectSignatureFoundInDb
// will match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectHashDBValue<BufferSize> (RtServicesMock, CertListBuffer, BufferSize);
FileBuffer = (VOID *)&images::CertGuidCOFF;
FileSize = sizeof (images::CertGuidCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
TEST_F (CheckSignedImage, NormalFlowTwoCerts) {
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN SignatureDataSize = sizeof (EFI_GUID) + CertSize;
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + (SignatureDataSize * 2);
UINT8 CertListBuffer[BufferSize] = { 0 };
UINT8 InvalidCert[CertSize] = { 0 };
CopyMem (InvalidCert, certs::TestCertDer, CertSize);
InvalidCert[0] = 0xAA;
EFI_SIGNATURE_LIST *CertList = (EFI_SIGNATURE_LIST *)&CertListBuffer;
CertList->SignatureListSize = (UINT32)BufferSize;
CertList->SignatureHeaderSize = 0;
CertList->SignatureSize = (UINT32)SignatureDataSize;
CopyGuid (&CertList->SignatureType, &gEfiCertX509Guid);
EFI_SIGNATURE_DATA *Cert1 = (EFI_SIGNATURE_DATA *)(CertList + 1);
CopyGuid (&Cert1->SignatureOwner, &gEfiGlobalVariableGuid);
CopyMem (Cert1->SignatureData, InvalidCert, CertSize);
EFI_SIGNATURE_DATA *Cert2 = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert1 + SignatureDataSize);
CopyGuid (&Cert2->SignatureOwner, &gEfiGlobalVariableGuid);
CopyMem (Cert2->SignatureData, certs::TestCertDer, CertSize);
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectHashDBValue<BufferSize> (RtServicesMock, CertListBuffer, BufferSize);
FileBuffer = (VOID *)&images::PkcsCOFF;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
void
UpdatePeAuthCodeHash (
UINT8 *PkcsCopy,
UINT32 HashType,
CONST UINT8 *HashValue,
UINTN HashSize
)
{
constexpr UINTN HashOidOffset = 0x408; // AuthData(0x3e8) + 32
constexpr UINTN HashTagOffset = 0x470; // AuthData + 132
constexpr UINTN HashValueOffset = 0x472; // AuthData + 134
static const UINT8 OidSha1[] = { 0x2B, 0x0E, 0x03, 0x02, 0x1A };
static const UINT8 OidSha256[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
static const UINT8 OidSha384[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 };
static const UINT8 OidSha512[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 };
const UINT8 *Oid;
UINTN OidLength;
switch (HashType) {
case HASHALG_SHA1:
Oid = OidSha1;
OidLength = sizeof (OidSha1);
break;
case HASHALG_SHA256:
Oid = OidSha256;
OidLength = sizeof (OidSha256);
break;
case HASHALG_SHA384:
Oid = OidSha384;
OidLength = sizeof (OidSha384);
break;
case HASHALG_SHA512:
Oid = OidSha512;
OidLength = sizeof (OidSha512);
break;
default:
return;
}
CopyMem (PkcsCopy + HashOidOffset, Oid, OidLength);
PkcsCopy[HashTagOffset] = 0x04; // ASN.1 Octet(value 0x04) string
PkcsCopy[HashTagOffset + 1] = (UINT8)HashSize;
CopyMem (PkcsCopy + HashValueOffset, HashValue, HashSize);
}
TEST_F (CheckSignedImage, NormalFlowPkcsNoCertHashAllowed) {
constexpr UINTN Hash512Size = sizeof (images::PkcsCOFFSha512);
constexpr UINTN Hash384Size = sizeof (images::PkcsCOFFSha384);
constexpr UINTN Hash256Size = sizeof (images::PkcsCOFFSha256);
constexpr UINTN Hash1Size = sizeof (images::PkcsCOFFSha1);
constexpr UINTN Hash512BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash512Size;
constexpr UINTN Hash384BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash384Size;
constexpr UINTN Hash256BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash256Size;
constexpr UINTN Hash1BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Hash1Size;
UINT8 Hash512CertListBuffer[Hash512BufferSize] = { 0 };
UINT8 Hash384CertListBuffer[Hash384BufferSize] = { 0 };
UINT8 Hash256CertListBuffer[Hash256BufferSize] = { 0 };
UINT8 Hash1CertListBuffer[Hash1BufferSize] = { 0 };
UINT8 PkcsSha1Copy[sizeof (images::PkcsCOFF)];
UINT8 PkcsSha256Copy[sizeof (images::PkcsCOFF)];
UINT8 PkcsSha384Copy[sizeof (images::PkcsCOFF)];
UINT8 PkcsSha512Copy[sizeof (images::PkcsCOFF)];
CopyMem (PkcsSha1Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
CopyMem (PkcsSha256Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
CopyMem (PkcsSha384Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
CopyMem (PkcsSha512Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
UpdatePeAuthCodeHash (PkcsSha1Copy, HASHALG_SHA1, images::PkcsCOFFSha1, Hash1Size);
UpdatePeAuthCodeHash (PkcsSha256Copy, HASHALG_SHA256, images::PkcsCOFFSha256, Hash256Size);
UpdatePeAuthCodeHash (PkcsSha384Copy, HASHALG_SHA384, images::PkcsCOFFSha384, Hash384Size);
UpdatePeAuthCodeHash (PkcsSha512Copy, HASHALG_SHA512, images::PkcsCOFFSha512, Hash512Size);
PrepareCertList (
Hash512Size,
Hash512BufferSize,
&gEfiCertSha512Guid,
&images::PkcsCOFFSha512[0],
(EFI_SIGNATURE_LIST *)&Hash512CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectNoSignatureHashDBValue<Hash512BufferSize> (
RtServicesMock,
Hash512CertListBuffer,
Hash512BufferSize
);
FileBuffer = (VOID *)&PkcsSha512Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
PrepareCertList (
Hash384Size,
Hash384BufferSize,
&gEfiCertSha384Guid,
&images::PkcsCOFFSha384[0],
(EFI_SIGNATURE_LIST *)&Hash384CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectNoSignatureHashDBValue<Hash384BufferSize> (
RtServicesMock,
Hash384CertListBuffer,
Hash384BufferSize
);
FileBuffer = (VOID *)&PkcsSha384Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
PrepareCertList (
Hash256Size,
Hash256BufferSize,
&gEfiCertSha256Guid,
&images::PkcsCOFFSha256[0],
(EFI_SIGNATURE_LIST *)&Hash256CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectNoSignatureHashDBValue<Hash256BufferSize> (
RtServicesMock,
Hash256CertListBuffer,
Hash256BufferSize
);
FileBuffer = (VOID *)&PkcsSha256Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
PrepareCertList (
Hash1Size,
Hash1BufferSize,
&gEfiCertSha1Guid,
&images::PkcsCOFFSha1[0],
(EFI_SIGNATURE_LIST *)&Hash1CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectNoSignatureHashDBValue<Hash1BufferSize> (
RtServicesMock,
Hash1CertListBuffer,
Hash1BufferSize
);
FileBuffer = (VOID *)&PkcsSha1Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_SUCCESS);
}
}
TEST_F (CheckSignedImage, ForbiddenByDbxPkcs7Sign) {
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + CertSize;
UINT8 CertListBuffer[BufferSize] = { 0 };
PrepareCertList (
CertSize,
BufferSize,
&gEfiCertX509Guid,
&certs::TestCertDer[0],
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
// Do not delete this. Otherwise, GetVariable from ExpectCertForbiddenByDbx
// will match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectCertForbiddenByDbx<BufferSize> (
RtServicesMock,
CertListBuffer,
BufferSize
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&images::PkcsCOFF;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
TEST_F (CheckSignedImage, ForbiddenByDbxUefiGuidSign) {
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + CertSize;
UINT8 CertListBuffer[BufferSize] = { 0 };
PrepareCertList (
CertSize,
BufferSize,
&gEfiCertX509Guid,
&certs::TestCertDer[0],
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
// Do not delete this. Otherwise, GetVariable from ExpectCertForbiddenByDbx
// will match all calls.
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectCertForbiddenByDbx<BufferSize> (
RtServicesMock,
CertListBuffer,
BufferSize
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&images::CertGuidCOFF;
FileSize = sizeof (images::CertGuidCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
TEST_F (CheckSignedImage, NoCertPkcs7SignNoHash) {
// This test also covers the code path for when a perfectly valid signature is
// missing from the 'db' variable, resulting in the error: "Image is signed
// but signature is not allowed by DB and %s hash of image is not found in
// DB/DBX."
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + CertSize;
UINT8 InvalidCert[CertSize] = { 0 };
CopyMem (InvalidCert, images::PkcsCOFF, CertSize);
InvalidCert[0] = 0xAA;
UINT8 CertListBuffer[BufferSize] = { 0 };
PrepareCertList (
CertSize,
BufferSize,
&gEfiCertX509Guid,
InvalidCert,
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectHashDBValue<BufferSize> (RtServicesMock, CertListBuffer, BufferSize);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&images::PkcsCOFF;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
TEST_F (CheckSignedImage, ForbiddenByDBxHash) {
constexpr UINTN CertSize = sizeof (certs::TestCertDer);
constexpr UINTN Hash512Size = sizeof (images::PkcsCOFFSha512);
constexpr UINTN Hash384Size = sizeof (images::PkcsCOFFSha384);
constexpr UINTN Hash256Size = sizeof (images::PkcsCOFFSha256);
constexpr UINTN Hash1Size = sizeof (images::PkcsCOFFSha1);
constexpr UINTN BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + CertSize;
constexpr UINTN Hash512BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash512Size;
constexpr UINTN Hash384BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash384Size;
constexpr UINTN Hash256BufferSize = sizeof (EFI_SIGNATURE_LIST) +
sizeof (EFI_SIGNATURE_DATA) - 1 +
Hash256Size;
constexpr UINTN Hash1BufferSize =
sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Hash1Size;
UINT8 CertListBuffer[BufferSize] = { 0 };
UINT8 Hash512CertListBuffer[Hash512BufferSize] = { 0 };
UINT8 Hash384CertListBuffer[Hash384BufferSize] = { 0 };
UINT8 Hash256CertListBuffer[Hash256BufferSize] = { 0 };
UINT8 Hash1CertListBuffer[Hash1BufferSize] = { 0 };
UINT8 PkcsSha1Copy[sizeof (images::PkcsCOFF)];
UINT8 PkcsSha256Copy[sizeof (images::PkcsCOFF)];
UINT8 PkcsSha384Copy[sizeof (images::PkcsCOFF)];
UINT8 PkcsSha512Copy[sizeof (images::PkcsCOFF)];
CopyMem (PkcsSha1Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
CopyMem (PkcsSha256Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
CopyMem (PkcsSha384Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
CopyMem (PkcsSha512Copy, images::PkcsCOFF, sizeof (images::PkcsCOFF));
UpdatePeAuthCodeHash (PkcsSha1Copy, HASHALG_SHA1, images::PkcsCOFFSha1, Hash1Size);
UpdatePeAuthCodeHash (PkcsSha256Copy, HASHALG_SHA256, images::PkcsCOFFSha256, Hash256Size);
UpdatePeAuthCodeHash (PkcsSha384Copy, HASHALG_SHA384, images::PkcsCOFFSha384, Hash384Size);
UpdatePeAuthCodeHash (PkcsSha512Copy, HASHALG_SHA512, images::PkcsCOFFSha512, Hash512Size);
PrepareCertList (
CertSize,
BufferSize,
&gEfiCertX509Guid,
certs::TestCertDer,
(EFI_SIGNATURE_LIST *)&CertListBuffer
);
PrepareCertList (
Hash512Size,
Hash512BufferSize,
&gEfiCertSha512Guid,
&images::PkcsCOFFSha512[0],
(EFI_SIGNATURE_LIST *)&Hash512CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectForbiddenByDBxHash<BufferSize, Hash512BufferSize> (
RtServicesMock,
CertListBuffer,
BufferSize,
Hash512CertListBuffer,
Hash512BufferSize
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&PkcsSha512Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
PrepareCertList (
Hash384Size,
Hash384BufferSize,
&gEfiCertSha384Guid,
&images::PkcsCOFFSha384[0],
(EFI_SIGNATURE_LIST *)&Hash384CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectForbiddenByDBxHash<BufferSize, Hash384BufferSize> (
RtServicesMock,
CertListBuffer,
BufferSize,
Hash384CertListBuffer,
Hash384BufferSize
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&PkcsSha384Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
PrepareCertList (
Hash256Size,
Hash256BufferSize,
&gEfiCertSha256Guid,
&images::PkcsCOFFSha256[0],
(EFI_SIGNATURE_LIST *)&Hash256CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectForbiddenByDBxHash<BufferSize, Hash256BufferSize> (
RtServicesMock,
CertListBuffer,
BufferSize,
Hash256CertListBuffer,
Hash256BufferSize
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&PkcsSha256Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
PrepareCertList (
Hash1Size,
Hash1BufferSize,
&gEfiCertSha1Guid,
&images::PkcsCOFFSha1[0],
(EFI_SIGNATURE_LIST *)&Hash1CertListBuffer
);
{
testing::InSequence s;
ExpectBeforeHashCheck (BsMock, DevicePathMock, RtServicesMock);
ExpectForbiddenByDBxHash<BufferSize, Hash1BufferSize> (
RtServicesMock,
CertListBuffer,
BufferSize,
Hash1CertListBuffer,
Hash1BufferSize
);
ExpectFailureJump (DevicePathMock, UefiMock, BsMock);
FileBuffer = (VOID *)&PkcsSha1Copy;
FileSize = sizeof (images::PkcsCOFF);
Status = DxeImageVerificationHandler (
AuthenticationStatus,
&File,
FileBuffer,
FileSize,
BootPolicy
);
EXPECT_EQ (Status, EFI_ACCESS_DENIED);
}
}
int
main (
int argc,
char *argv[]
)
{
testing::InitGoogleTest (&argc, argv);
return RUN_ALL_TESTS ();
}