blob: fa0928d7e7bebccd7c990a1163b2b67cd33e7118 [file]
/** @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 ();
}