mirror of https://github.com/acidanthera/audk.git
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
This commit is contained in:
parent
af9af05bec
commit
4fc08e8d68
File diff suppressed because it is too large
Load Diff
|
@ -117,6 +117,54 @@ typedef struct {
|
||||||
} AUTH_CERT_DB_DATA;
|
} AUTH_CERT_DB_DATA;
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
|
|
||||||
|
///
|
||||||
|
/// "SecureBootMode" variable stores current secure boot mode.
|
||||||
|
/// The value type is SECURE_BOOT_MODE_TYPE.
|
||||||
|
///
|
||||||
|
#define EDKII_SECURE_BOOT_MODE_NAME L"SecureBootMode"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SecureBootModeTypeUserMode,
|
||||||
|
SecureBootModeTypeSetupMode,
|
||||||
|
SecureBootModeTypeAuditMode,
|
||||||
|
SecureBootModeTypeDeployedMode,
|
||||||
|
SecureBootModeTypeMax
|
||||||
|
} SECURE_BOOT_MODE_TYPE;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Record status info of Customized Secure Boot Mode.
|
||||||
|
//
|
||||||
|
typedef struct {
|
||||||
|
///
|
||||||
|
/// AuditMode variable value
|
||||||
|
///
|
||||||
|
UINT8 AuditMode;
|
||||||
|
///
|
||||||
|
/// AuditMode variable RW
|
||||||
|
///
|
||||||
|
BOOLEAN IsAuditModeRO;
|
||||||
|
///
|
||||||
|
/// DeployedMode variable value
|
||||||
|
///
|
||||||
|
UINT8 DeployedMode;
|
||||||
|
///
|
||||||
|
/// AuditMode variable RW
|
||||||
|
///
|
||||||
|
BOOLEAN IsDeployedModeRO;
|
||||||
|
///
|
||||||
|
/// SetupMode variable value
|
||||||
|
///
|
||||||
|
UINT8 SetupMode;
|
||||||
|
///
|
||||||
|
/// SetupMode is always RO. Skip IsSetupModeRO;
|
||||||
|
///
|
||||||
|
|
||||||
|
///
|
||||||
|
/// SecureBoot variable value
|
||||||
|
///
|
||||||
|
UINT8 SecureBoot;
|
||||||
|
} SECURE_BOOT_MODE;
|
||||||
|
|
||||||
extern UINT8 *mPubKeyStore;
|
extern UINT8 *mPubKeyStore;
|
||||||
extern UINT32 mPubKeyNumber;
|
extern UINT32 mPubKeyNumber;
|
||||||
extern UINT32 mMaxKeyNumber;
|
extern UINT32 mMaxKeyNumber;
|
||||||
|
@ -130,6 +178,18 @@ extern VOID *mHashCtx;
|
||||||
|
|
||||||
extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn;
|
extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialize Secure Boot variables.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The initialization operation is successful.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES There is not enough resource.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
InitSecureBootVariables (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
|
Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
|
||||||
|
|
||||||
|
@ -219,6 +279,39 @@ FilterSignatureList (
|
||||||
IN OUT UINTN *NewDataSize
|
IN OUT UINTN *NewDataSize
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Process Secure Boot Mode variable.
|
||||||
|
|
||||||
|
Caution: This function may receive untrusted input.
|
||||||
|
This function may be invoked in SMM mode, and datasize and data are external input.
|
||||||
|
This function will do basic validation, before parse the data.
|
||||||
|
This function will parse the authentication carefully to avoid security issues, like
|
||||||
|
buffer overflow, integer overflow.
|
||||||
|
This function will check attribute carefully to avoid authentication bypass.
|
||||||
|
|
||||||
|
@param[in] VariableName Name of Variable to be found.
|
||||||
|
@param[in] VendorGuid Variable vendor GUID.
|
||||||
|
@param[in] Data Data pointer.
|
||||||
|
@param[in] DataSize Size of Data found. If size is less than the
|
||||||
|
data, this value contains the required size.
|
||||||
|
@param[in] Attributes Attribute value of the variable
|
||||||
|
|
||||||
|
@return EFI_INVALID_PARAMETER Invalid parameter
|
||||||
|
@return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
|
||||||
|
check carried out by the firmware.
|
||||||
|
@return EFI_WRITE_PROTECTED Variable is Read-Only.
|
||||||
|
@return EFI_SUCCESS Variable passed validation successfully.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ProcessSecureBootModeVar (
|
||||||
|
IN CHAR16 *VariableName,
|
||||||
|
IN EFI_GUID *VendorGuid,
|
||||||
|
IN VOID *Data,
|
||||||
|
IN UINTN DataSize,
|
||||||
|
IN UINT32 Attributes OPTIONAL
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Process variable with platform key for verification.
|
Process variable with platform key for verification.
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ UINT32 mMaxKeyNumber;
|
||||||
UINT32 mMaxKeyDbSize;
|
UINT32 mMaxKeyDbSize;
|
||||||
UINT8 *mCertDbStore;
|
UINT8 *mCertDbStore;
|
||||||
UINT32 mMaxCertDbSize;
|
UINT32 mMaxCertDbSize;
|
||||||
UINT32 mPlatformMode;
|
|
||||||
UINT8 mVendorKeyState;
|
UINT8 mVendorKeyState;
|
||||||
|
|
||||||
EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
|
EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
|
||||||
|
@ -99,6 +98,17 @@ VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = {
|
||||||
MAX_UINTN
|
MAX_UINTN
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
&gEdkiiSecureBootModeGuid,
|
||||||
|
L"SecureBootMode",
|
||||||
|
{
|
||||||
|
VAR_CHECK_VARIABLE_PROPERTY_REVISION,
|
||||||
|
VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
|
||||||
|
VARIABLE_ATTRIBUTE_NV_BS_RT,
|
||||||
|
sizeof (UINT8),
|
||||||
|
sizeof (UINT8)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VOID **mAuthVarAddressPointer[10];
|
VOID **mAuthVarAddressPointer[10];
|
||||||
|
@ -132,8 +142,6 @@ AuthVariableLibInitialize (
|
||||||
UINT8 *Data;
|
UINT8 *Data;
|
||||||
UINTN DataSize;
|
UINTN DataSize;
|
||||||
UINTN CtxSize;
|
UINTN CtxSize;
|
||||||
UINT8 SecureBootMode;
|
|
||||||
UINT8 SecureBootEnable;
|
|
||||||
UINT8 CustomMode;
|
UINT8 CustomMode;
|
||||||
UINT32 ListSize;
|
UINT32 ListSize;
|
||||||
|
|
||||||
|
@ -208,31 +216,11 @@ AuthVariableLibInitialize (
|
||||||
mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));
|
mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);
|
//
|
||||||
if (EFI_ERROR (Status)) {
|
// Init Secure Boot variables
|
||||||
DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
|
//
|
||||||
} else {
|
Status = InitSecureBootVariables ();
|
||||||
DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Create "SetupMode" variable with BS+RT attribute set.
|
|
||||||
//
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
mPlatformMode = SETUP_MODE;
|
|
||||||
} else {
|
|
||||||
mPlatformMode = USER_MODE;
|
|
||||||
}
|
|
||||||
Status = AuthServiceInternalUpdateVariable (
|
|
||||||
EFI_SETUP_MODE_NAME,
|
|
||||||
&gEfiGlobalVariableGuid,
|
|
||||||
&mPlatformMode,
|
|
||||||
sizeof(UINT8),
|
|
||||||
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Create "SignatureSupport" variable with BS+RT attribute set.
|
// Create "SignatureSupport" variable with BS+RT attribute set.
|
||||||
|
@ -248,69 +236,6 @@ AuthVariableLibInitialize (
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
|
|
||||||
// If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
|
|
||||||
// If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
|
|
||||||
//
|
|
||||||
SecureBootEnable = SECURE_BOOT_DISABLE;
|
|
||||||
Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize);
|
|
||||||
if (!EFI_ERROR (Status)) {
|
|
||||||
if (mPlatformMode == SETUP_MODE){
|
|
||||||
//
|
|
||||||
// PK is cleared in runtime. "SecureBootMode" is not updated before reboot
|
|
||||||
// Delete "SecureBootMode" in SetupMode
|
|
||||||
//
|
|
||||||
Status = AuthServiceInternalUpdateVariable (
|
|
||||||
EFI_SECURE_BOOT_ENABLE_NAME,
|
|
||||||
&gEfiSecureBootEnableDisableGuid,
|
|
||||||
&SecureBootEnable,
|
|
||||||
0,
|
|
||||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
SecureBootEnable = *(UINT8 *) Data;
|
|
||||||
}
|
|
||||||
} else if (mPlatformMode == USER_MODE) {
|
|
||||||
//
|
|
||||||
// "SecureBootEnable" not exist, initialize it in USER_MODE.
|
|
||||||
//
|
|
||||||
SecureBootEnable = SECURE_BOOT_ENABLE;
|
|
||||||
Status = AuthServiceInternalUpdateVariable (
|
|
||||||
EFI_SECURE_BOOT_ENABLE_NAME,
|
|
||||||
&gEfiSecureBootEnableDisableGuid,
|
|
||||||
&SecureBootEnable,
|
|
||||||
sizeof (UINT8),
|
|
||||||
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Create "SecureBoot" variable with BS+RT attribute set.
|
|
||||||
//
|
|
||||||
if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
|
|
||||||
SecureBootMode = SECURE_BOOT_MODE_ENABLE;
|
|
||||||
} else {
|
|
||||||
SecureBootMode = SECURE_BOOT_MODE_DISABLE;
|
|
||||||
}
|
|
||||||
Status = AuthServiceInternalUpdateVariable (
|
|
||||||
EFI_SECURE_BOOT_MODE_NAME,
|
|
||||||
&gEfiGlobalVariableGuid,
|
|
||||||
&SecureBootMode,
|
|
||||||
sizeof (UINT8),
|
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
|
|
||||||
);
|
|
||||||
if (EFI_ERROR (Status)) {
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));
|
|
||||||
DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));
|
|
||||||
DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
|
// Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
|
||||||
//
|
//
|
||||||
|
@ -455,10 +380,16 @@ AuthVariableLibProcessVariable (
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process PK, KEK, Sigdb, AuditMode, DeployedMode separately.
|
||||||
|
//
|
||||||
if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
|
if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
|
||||||
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE);
|
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE);
|
||||||
} else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
|
} else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
|
||||||
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
|
Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
|
||||||
|
} else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)
|
||||||
|
&& (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0 || StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0)) {
|
||||||
|
Status = ProcessSecureBootModeVar(VariableName, VendorGuid, Data, DataSize, Attributes);
|
||||||
} else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
|
} else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
|
||||||
((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) ||
|
((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) ||
|
||||||
(StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
|
(StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
|
||||||
|
|
|
@ -85,6 +85,10 @@
|
||||||
## PRODUCES ## Variable:L"AuthVarKeyDatabase"
|
## PRODUCES ## Variable:L"AuthVarKeyDatabase"
|
||||||
gEfiAuthenticatedVariableGuid
|
gEfiAuthenticatedVariableGuid
|
||||||
|
|
||||||
|
## CONSUMES ## Variable:L"SecureBootMode"
|
||||||
|
## PRODUCES ## Variable:L"SecureBootMode"
|
||||||
|
gEdkiiSecureBootModeGuid
|
||||||
|
|
||||||
gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
|
gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
|
||||||
gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
|
gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
|
||||||
gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
|
gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
|
||||||
|
|
|
@ -711,6 +711,58 @@ GetImageExeInfoTableSize (
|
||||||
return TotalSize;
|
return TotalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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.
|
Create an Image Execution Information Table entry and add it to system configuration table.
|
||||||
|
|
||||||
|
@ -737,11 +789,13 @@ AddImageExeInfo (
|
||||||
UINTN NewImageExeInfoEntrySize;
|
UINTN NewImageExeInfoEntrySize;
|
||||||
UINTN NameStringLen;
|
UINTN NameStringLen;
|
||||||
UINTN DevicePathSize;
|
UINTN DevicePathSize;
|
||||||
|
CHAR16 *NameStr;
|
||||||
|
|
||||||
ImageExeInfoTable = NULL;
|
ImageExeInfoTable = NULL;
|
||||||
NewImageExeInfoTable = NULL;
|
NewImageExeInfoTable = NULL;
|
||||||
ImageExeInfoEntry = NULL;
|
ImageExeInfoEntry = NULL;
|
||||||
NameStringLen = 0;
|
NameStringLen = 0;
|
||||||
|
NameStr = NULL;
|
||||||
|
|
||||||
if (DevicePath == NULL) {
|
if (DevicePath == NULL) {
|
||||||
return ;
|
return ;
|
||||||
|
@ -769,7 +823,12 @@ AddImageExeInfo (
|
||||||
}
|
}
|
||||||
|
|
||||||
DevicePathSize = GetDevicePathSize (DevicePath);
|
DevicePathSize = GetDevicePathSize (DevicePath);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align
|
||||||
|
//
|
||||||
NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
|
NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
|
||||||
|
|
||||||
NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
|
NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
|
||||||
if (NewImageExeInfoTable == NULL) {
|
if (NewImageExeInfoTable == NULL) {
|
||||||
return ;
|
return ;
|
||||||
|
@ -788,19 +847,21 @@ AddImageExeInfo (
|
||||||
WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
|
WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
|
||||||
WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);
|
WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);
|
||||||
|
|
||||||
|
NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);
|
||||||
if (Name != NULL) {
|
if (Name != NULL) {
|
||||||
CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen);
|
CopyMem ((UINT8 *) NameStr, Name, NameStringLen);
|
||||||
} else {
|
} else {
|
||||||
ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16));
|
ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyMem (
|
CopyMem (
|
||||||
(UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen,
|
(UINT8 *) NameStr + NameStringLen,
|
||||||
DevicePath,
|
DevicePath,
|
||||||
DevicePathSize
|
DevicePathSize
|
||||||
);
|
);
|
||||||
if (Signature != NULL) {
|
if (Signature != NULL) {
|
||||||
CopyMem (
|
CopyMem (
|
||||||
(UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen + DevicePathSize,
|
(UINT8 *) NameStr + NameStringLen + DevicePathSize,
|
||||||
Signature,
|
Signature,
|
||||||
SignatureSize
|
SignatureSize
|
||||||
);
|
);
|
||||||
|
@ -1087,6 +1148,53 @@ IsTimeZero (
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
Check whether the timestamp signature is valid and the signing time is also earlier than
|
||||||
the revocation time.
|
the revocation time.
|
||||||
|
@ -1199,6 +1307,9 @@ Done:
|
||||||
|
|
||||||
@param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.
|
@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] 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 TRUE Image is forbidden by dbx.
|
||||||
@retval FALSE Image is not forbidden by dbx.
|
@retval FALSE Image is not forbidden by dbx.
|
||||||
|
@ -1207,7 +1318,10 @@ Done:
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
IsForbiddenByDbx (
|
IsForbiddenByDbx (
|
||||||
IN UINT8 *AuthData,
|
IN UINT8 *AuthData,
|
||||||
IN UINTN AuthDataSize
|
IN UINTN AuthDataSize,
|
||||||
|
IN BOOLEAN IsAuditMode,
|
||||||
|
IN CHAR16 *ImageName OPTIONAL,
|
||||||
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
|
@ -1230,7 +1344,10 @@ IsForbiddenByDbx (
|
||||||
UINT8 *Cert;
|
UINT8 *Cert;
|
||||||
UINTN CertSize;
|
UINTN CertSize;
|
||||||
EFI_TIME RevocationTime;
|
EFI_TIME RevocationTime;
|
||||||
|
UINT8 *SignerCert;
|
||||||
|
UINTN SignerCertLength;
|
||||||
|
UINT8 *UnchainCert;
|
||||||
|
UINTN UnchainCertLength;
|
||||||
//
|
//
|
||||||
// Variable Initialization
|
// Variable Initialization
|
||||||
//
|
//
|
||||||
|
@ -1245,6 +1362,10 @@ IsForbiddenByDbx (
|
||||||
BufferLength = 0;
|
BufferLength = 0;
|
||||||
TrustedCert = NULL;
|
TrustedCert = NULL;
|
||||||
TrustedCertLength = 0;
|
TrustedCertLength = 0;
|
||||||
|
SignerCert = NULL;
|
||||||
|
SignerCertLength = 0;
|
||||||
|
UnchainCert = NULL;
|
||||||
|
UnchainCertLength = 0;
|
||||||
|
|
||||||
//
|
//
|
||||||
// The image will not be forbidden if dbx can't be got.
|
// The image will not be forbidden if dbx can't be got.
|
||||||
|
@ -1352,21 +1473,54 @@ IsForbiddenByDbx (
|
||||||
}
|
}
|
||||||
|
|
||||||
Done:
|
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) {
|
if (Data != NULL) {
|
||||||
FreePool (Data);
|
FreePool (Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pkcs7FreeSigners (CertBuffer);
|
Pkcs7FreeSigners (CertBuffer);
|
||||||
Pkcs7FreeSigners (TrustedCert);
|
Pkcs7FreeSigners (TrustedCert);
|
||||||
|
Pkcs7FreeSigners (SignerCert);
|
||||||
|
Pkcs7FreeSigners (UnchainCert);
|
||||||
|
|
||||||
return IsForbidden;
|
return IsForbidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check whether the image signature can be verified by the trusted certificates in DB database.
|
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] AuthData Pointer to the Authenticode signature retrieved from signed image.
|
||||||
@param[in] AuthDataSize Size of the Authenticode signature in bytes.
|
@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 TRUE Image passed verification using certificate in db.
|
||||||
@retval FALSE Image didn't pass verification using certificate in db.
|
@retval FALSE Image didn't pass verification using certificate in db.
|
||||||
|
@ -1375,13 +1529,16 @@ Done:
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
IsAllowedByDb (
|
IsAllowedByDb (
|
||||||
IN UINT8 *AuthData,
|
IN UINT8 *AuthData,
|
||||||
IN UINTN AuthDataSize
|
IN UINTN AuthDataSize,
|
||||||
|
IN BOOLEAN IsAuditMode,
|
||||||
|
IN CHAR16 *ImageName OPTIONAL,
|
||||||
|
IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath OPTIONAL
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
EFI_STATUS Status;
|
EFI_STATUS Status;
|
||||||
BOOLEAN VerifyStatus;
|
BOOLEAN VerifyStatus;
|
||||||
EFI_SIGNATURE_LIST *CertList;
|
EFI_SIGNATURE_LIST *CertList;
|
||||||
EFI_SIGNATURE_DATA *Cert;
|
EFI_SIGNATURE_DATA *CertData;
|
||||||
UINTN DataSize;
|
UINTN DataSize;
|
||||||
UINT8 *Data;
|
UINT8 *Data;
|
||||||
UINT8 *RootCert;
|
UINT8 *RootCert;
|
||||||
|
@ -1391,14 +1548,22 @@ IsAllowedByDb (
|
||||||
UINTN DbxDataSize;
|
UINTN DbxDataSize;
|
||||||
UINT8 *DbxData;
|
UINT8 *DbxData;
|
||||||
EFI_TIME RevocationTime;
|
EFI_TIME RevocationTime;
|
||||||
|
UINT8 *SignerCert;
|
||||||
|
UINTN SignerCertLength;
|
||||||
|
UINT8 *UnchainCert;
|
||||||
|
UINTN UnchainCertLength;
|
||||||
|
|
||||||
Data = NULL;
|
Data = NULL;
|
||||||
CertList = NULL;
|
CertList = NULL;
|
||||||
Cert = NULL;
|
CertData = NULL;
|
||||||
RootCert = NULL;
|
RootCert = NULL;
|
||||||
DbxData = NULL;
|
DbxData = NULL;
|
||||||
RootCertSize = 0;
|
RootCertSize = 0;
|
||||||
VerifyStatus = FALSE;
|
VerifyStatus = FALSE;
|
||||||
|
SignerCert = NULL;
|
||||||
|
SignerCertLength = 0;
|
||||||
|
UnchainCert = NULL;
|
||||||
|
UnchainCertLength = 0;
|
||||||
|
|
||||||
DataSize = 0;
|
DataSize = 0;
|
||||||
Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
|
Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
|
||||||
|
@ -1419,14 +1584,14 @@ IsAllowedByDb (
|
||||||
CertList = (EFI_SIGNATURE_LIST *) Data;
|
CertList = (EFI_SIGNATURE_LIST *) Data;
|
||||||
while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
|
while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
|
||||||
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
|
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
|
||||||
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
|
CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
|
||||||
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
||||||
|
|
||||||
for (Index = 0; Index < CertCount; Index++) {
|
for (Index = 0; Index < CertCount; Index++) {
|
||||||
//
|
//
|
||||||
// Iterate each Signature Data Node within this CertList for verify.
|
// Iterate each Signature Data Node within this CertList for verify.
|
||||||
//
|
//
|
||||||
RootCert = Cert->SignatureData;
|
RootCert = CertData->SignatureData;
|
||||||
RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
|
RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1468,7 +1633,7 @@ IsAllowedByDb (
|
||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
|
CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1478,10 +1643,67 @@ IsAllowedByDb (
|
||||||
}
|
}
|
||||||
|
|
||||||
Done:
|
Done:
|
||||||
|
|
||||||
if (VerifyStatus) {
|
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) {
|
if (Data != NULL) {
|
||||||
FreePool (Data);
|
FreePool (Data);
|
||||||
}
|
}
|
||||||
|
@ -1489,9 +1711,369 @@ Done:
|
||||||
FreePool (DbxData);
|
FreePool (DbxData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pkcs7FreeSigners (SignerCert);
|
||||||
|
Pkcs7FreeSigners (UnchainCert);
|
||||||
|
|
||||||
return VerifyStatus;
|
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
|
Provide verification service for signed images, which include both signature validation
|
||||||
and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
|
and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
|
||||||
|
@ -1559,7 +2141,9 @@ DxeImageVerificationHandler (
|
||||||
EFI_IMAGE_EXECUTION_ACTION Action;
|
EFI_IMAGE_EXECUTION_ACTION Action;
|
||||||
WIN_CERTIFICATE *WinCertificate;
|
WIN_CERTIFICATE *WinCertificate;
|
||||||
UINT32 Policy;
|
UINT32 Policy;
|
||||||
UINT8 *SecureBoot;
|
UINT8 *VarData;
|
||||||
|
UINT8 SecureBoot;
|
||||||
|
UINT8 AuditMode;
|
||||||
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
|
||||||
UINT32 NumberOfRvaAndSizes;
|
UINT32 NumberOfRvaAndSizes;
|
||||||
WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
|
WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
|
||||||
|
@ -1579,6 +2163,20 @@ DxeImageVerificationHandler (
|
||||||
Status = EFI_ACCESS_DENIED;
|
Status = EFI_ACCESS_DENIED;
|
||||||
VerifyStatus = 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.
|
// Check the image type and get policy setting.
|
||||||
//
|
//
|
||||||
|
@ -1622,22 +2220,22 @@ DxeImageVerificationHandler (
|
||||||
CpuDeadLoop ();
|
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.
|
// Skip verification if SecureBoot variable doesn't exist.
|
||||||
//
|
//
|
||||||
if (SecureBoot == NULL) {
|
if (VarData == NULL) {
|
||||||
return EFI_SUCCESS;
|
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) {
|
if (SecureBoot == SECURE_BOOT_MODE_DISABLE) {
|
||||||
FreePool (SecureBoot);
|
|
||||||
return EFI_SUCCESS;
|
return EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
FreePool (SecureBoot);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Read the Dos header.
|
// Read the Dos header.
|
||||||
|
@ -1808,7 +2406,7 @@ DxeImageVerificationHandler (
|
||||||
//
|
//
|
||||||
// Check the digital signature against the revoked certificate in forbidden database (dbx).
|
// 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;
|
Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
|
||||||
VerifyStatus = EFI_ACCESS_DENIED;
|
VerifyStatus = EFI_ACCESS_DENIED;
|
||||||
break;
|
break;
|
||||||
|
@ -1818,7 +2416,7 @@ DxeImageVerificationHandler (
|
||||||
// Check the digital signature against the valid certificate in allowed database (db).
|
// Check the digital signature against the valid certificate in allowed database (db).
|
||||||
//
|
//
|
||||||
if (EFI_ERROR (VerifyStatus)) {
|
if (EFI_ERROR (VerifyStatus)) {
|
||||||
if (IsAllowedByDb (AuthData, AuthDataSize)) {
|
if (IsAllowedByDb (AuthData, AuthDataSize, FALSE, NULL, NULL)) {
|
||||||
VerifyStatus = EFI_SUCCESS;
|
VerifyStatus = EFI_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue