X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FVariableAuthenticated%2FRuntimeDxe%2FAuthService.c;h=07a41b06f8ad01a52d5e232d63cc4357d0986d66;hp=ff5c6539125af152a47bedfaf276107c492fec22;hb=e3ff137e3652a85944ba1ba91ad61f09ef1ff248;hpb=beda2356f5128efa4461046f882b6516ece6afc7
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
index ff5c653912..07a41b06f8 100644
--- a/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
+++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
@@ -2,13 +2,26 @@
Implement authentication services for the authenticated variable
service in UEFI2.2.
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
-This program and the accompanying materials
-are licensed and made available under the terms and conditions of the BSD License
-which accompanies this distribution. The full text of the license may be found at
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. It may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+ Variable attribute should also be checked to avoid authentication bypass.
+
+ ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
+ variable authentication.
+
+ VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.
+ They will do basic validation for authentication data structure, then call crypto library
+ to verify the signature.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
@@ -18,11 +31,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
///
/// Global database array for scratch
-///
+///
UINT8 mPubKeyStore[MAX_KEYDB_SIZE];
UINT32 mPubKeyNumber;
+UINT8 mCertDbStore[MAX_CERTDB_SIZE];
UINT32 mPlatformMode;
-EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
+UINT8 mVendorKeyState;
+
+EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
//
// Public Exponent of RSA Key.
//
@@ -32,28 +48,106 @@ CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
//
VOID *mHashCtx = NULL;
+//
+// The serialization of the values of the VariableName, VendorGuid and Attributes
+// parameters of the SetVariable() call and the TimeStamp component of the
+// EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
+// i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
+//
+UINT8 *mSerializationRuntimeBuffer = NULL;
//
-// Pointer to runtime buffer.
-// For "Append" operation to an existing variable, a read/modify/write operation
-// is supported by firmware internally. Reserve runtime buffer to cache previous
-// variable data in runtime phase because memory allocation is forbidden in virtual mode.
+// Requirement for different signature type which have been defined in UEFI spec.
+// These data are used to peform SignatureList format check while setting PK/KEK variable.
//
-VOID *mStorageArea = NULL;
+EFI_SIGNATURE_ITEM mSupportSigItem[] = {
+//{SigType, SigHeaderSize, SigDataSize }
+ {EFI_CERT_SHA256_GUID, 0, 32 },
+ {EFI_CERT_RSA2048_GUID, 0, 256 },
+ {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },
+ {EFI_CERT_SHA1_GUID, 0, 20 },
+ {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },
+ {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},
+ {EFI_CERT_SHA224_GUID, 0, 28 },
+ {EFI_CERT_SHA384_GUID, 0, 48 },
+ {EFI_CERT_SHA512_GUID, 0, 64 }
+};
/**
- Update platform mode.
+ Determine whether this operation needs a physical present user.
- @param[in] Mode SETUP_MODE or USER_MODE.
+ @param[in] VariableName Name of the Variable.
+ @param[in] VendorGuid GUID of the Variable.
- @return EFI_INVALID_PARAMETER Invalid parameter.
- @return EFI_SUCCESS Update platform mode successfully.
+ @retval TRUE This variable is protected, only a physical present user could set this variable.
+ @retval FALSE This variable is not protected.
+
+**/
+BOOLEAN
+NeedPhysicallyPresent(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
+ || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Determine whether the platform is operating in Custom Secure Boot mode.
+
+ @retval TRUE The platform is operating in Custom mode.
+ @retval FALSE The platform is operating in Standard mode.
+
+**/
+BOOLEAN
+InCustomMode (
+ VOID
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+
+ FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Internal function to delete a Variable given its name and GUID, no authentication
+ required.
+
+ @param[in] VariableName Name of the Variable.
+ @param[in] VendorGuid GUID of the Variable.
+
+ @retval EFI_SUCCESS Variable deleted successfully.
+ @retval Others The driver failded to start the device.
**/
EFI_STATUS
-UpdatePlatformMode (
- IN UINT32 Mode
- );
+DeleteVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (Variable.CurrPtr != NULL);
+ return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);
+}
/**
Initializes for authenticated varibale service.
@@ -69,7 +163,7 @@ AutenticatedVariableServiceInitialize (
{
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
- VARIABLE_POINTER_TRACK Variable2;
+ VARIABLE_POINTER_TRACK PkVariable;
UINT8 VarValue;
UINT32 VarAttr;
UINT8 *Data;
@@ -77,7 +171,9 @@ AutenticatedVariableServiceInitialize (
UINTN CtxSize;
UINT8 SecureBootMode;
UINT8 SecureBootEnable;
-
+ UINT8 CustomMode;
+ UINT32 ListSize;
+
//
// Initialize hash context.
//
@@ -88,22 +184,24 @@ AutenticatedVariableServiceInitialize (
}
//
- // Reserved runtime buffer for "Append" operation in virtual mode.
+ // Prepare runtime buffer for serialized data of time-based authenticated
+ // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).
//
- mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize));
- if (mStorageArea == NULL) {
+ mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));
+ if (mSerializationRuntimeBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
- // Check "AuthVarKeyDatabase" variable's existence.
- // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ // Check "AuthVarKeyDatabase" variable's existence.
+ // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
//
Status = FindVariable (
- AUTHVAR_KEYDB_NAME,
- &gEfiAuthenticatedVariableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
+ AUTHVAR_KEYDB_NAME,
+ &gEfiAuthenticatedVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
if (Variable.CurrPtr == NULL) {
@@ -134,98 +232,188 @@ AutenticatedVariableServiceInitialize (
CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
}
+
+ FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (PkVariable.CurrPtr == NULL) {
+ DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
+ } else {
+ DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
+ }
+
//
- // Check "SetupMode" variable's existence.
- // If it doesn't exist, check PK database's existence to determine the value.
- // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ // Create "SetupMode" variable with BS+RT attribute set.
//
- Status = FindVariable (
- EFI_SETUP_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
+ FindVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (PkVariable.CurrPtr == NULL) {
+ mPlatformMode = SETUP_MODE;
+ } else {
+ mPlatformMode = USER_MODE;
+ }
+ Status = UpdateVariable (
+ EFI_SETUP_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &mPlatformMode,
+ sizeof(UINT8),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create "SignatureSupport" variable with BS+RT attribute set.
+ //
+ FindVariable (EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ Status = UpdateVariable (
+ EFI_SIGNATURE_SUPPORT_NAME,
+ &gEfiGlobalVariableGuid,
+ mSignatureSupport,
+ sizeof(mSignatureSupport),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
- if (Variable.CurrPtr == NULL) {
- Status = FindVariable (
- EFI_PLATFORM_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &Variable2,
- &mVariableModuleGlobal->VariableGlobal
+ //
+ // 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;
+ FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ if (Variable.CurrPtr != NULL) {
+ SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));
+ } else if (mPlatformMode == USER_MODE) {
+ //
+ // "SecureBootEnable" not exist, initialize it in USER_MODE.
+ //
+ SecureBootEnable = SECURE_BOOT_ENABLE;
+ Status = UpdateVariable (
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ &SecureBootEnable,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
);
- if (Variable2.CurrPtr == NULL) {
- mPlatformMode = SETUP_MODE;
- } else {
- mPlatformMode = USER_MODE;
- }
-
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
- Status = UpdateVariable (
- EFI_SETUP_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &mPlatformMode,
- sizeof(UINT8),
- VarAttr,
- 0,
- 0,
- &Variable,
- NULL
- );
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 {
- mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));
+ SecureBootMode = SECURE_BOOT_MODE_DISABLE;
+ }
+ FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ Status = UpdateVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &SecureBootMode,
+ sizeof (UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+ 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.
+ //
+ FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ CustomMode = STANDARD_SECURE_BOOT_MODE;
+ Status = UpdateVariable (
+ EFI_CUSTOM_MODE_NAME,
+ &gEfiCustomModeEnableGuid,
+ &CustomMode,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
}
+
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
+
//
- // Check "SignatureSupport" variable's existence.
- // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ // Check "certdb" variable's existence.
+ // If it doesn't exist, then create a new one with
+ // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
//
Status = FindVariable (
- EFI_SIGNATURE_SUPPORT_NAME,
- &gEfiGlobalVariableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
-
if (Variable.CurrPtr == NULL) {
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
- Status = UpdateVariable (
- EFI_SIGNATURE_SUPPORT_NAME,
- &gEfiGlobalVariableGuid,
- mSignatureSupport,
- SIGSUPPORT_NUM * sizeof(EFI_GUID),
- VarAttr,
- 0,
- 0,
- &Variable,
- NULL
- );
- }
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ ListSize = sizeof (UINT32);
+ Status = UpdateVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ &ListSize,
+ sizeof (UINT32),
+ VarAttr,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
//
- // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
- // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
- // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
+ // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.
//
- FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
+ FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
if (Variable.CurrPtr != NULL) {
- SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));
- if (SecureBootEnable == SECURE_BOOT_ENABLE) {
- SecureBootMode = SECURE_BOOT_MODE_ENABLE;
- } else {
- SecureBootMode = SECURE_BOOT_MODE_DISABLE;
- }
- FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
+ mVendorKeyState = *(GetVariableDataPtr (Variable.CurrPtr));
+ } else {
+ //
+ // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.
+ //
+ mVendorKeyState = VENDOR_KEYS_VALID;
Status = UpdateVariable (
- EFI_SECURE_BOOT_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &SecureBootMode,
- sizeof(UINT8),
- EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
- 0,
- 0,
+ EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
+ &gEfiVendorKeysNvGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
+ 0,
+ 0,
&Variable,
NULL
);
@@ -235,43 +423,26 @@ AutenticatedVariableServiceInitialize (
}
//
- // Detect whether a secure platform-specific method to clear PK(Platform Key)
- // is configured by platform owner. This method is provided for users force to clear PK
- // in case incorrect enrollment mis-haps.
+ // Create "VendorKeys" variable with BS+RT attribute set.
//
- if (ForceClearPK ()) {
- //
- // 1. Check whether PK is existing, and clear PK if existing
- //
- FindVariable (
- EFI_PLATFORM_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
- );
- if (Variable.CurrPtr != NULL) {
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
- Status = UpdateVariable (
- EFI_PLATFORM_KEY_NAME,
- &gEfiGlobalVariableGuid,
- NULL,
- 0,
- VarAttr,
- 0,
- 0,
- &Variable,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- }
-
- //
- // 2. Update "SetupMode" variable to SETUP_MODE
- //
- UpdatePlatformMode (SETUP_MODE);
+ FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ Status = UpdateVariable (
+ EFI_VENDOR_KEYS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
}
+
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState));
+
return Status;
}
@@ -279,20 +450,26 @@ AutenticatedVariableServiceInitialize (
Add public key in store and return its index.
@param[in] PubKey Input pointer to Public Key data
+ @param[in] VariableDataEntry The variable data entry
@return Index of new added item
**/
UINT32
AddPubKeyInStore (
- IN UINT8 *PubKey
+ IN UINT8 *PubKey,
+ IN VARIABLE_ENTRY_CONSISTENCY *VariableDataEntry
)
{
- EFI_STATUS Status;
- BOOLEAN IsFound;
- UINT32 Index;
- VARIABLE_POINTER_TRACK Variable;
- UINT8 *Ptr;
+ EFI_STATUS Status;
+ BOOLEAN IsFound;
+ UINT32 Index;
+ VARIABLE_POINTER_TRACK Variable;
+ UINT8 *Ptr;
+ UINT8 *Data;
+ UINTN DataSize;
+ VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry;
+ UINT32 Attributes;
if (PubKey == NULL) {
return 0;
@@ -302,9 +479,14 @@ AddPubKeyInStore (
AUTHVAR_KEYDB_NAME,
&gEfiAuthenticatedVariableGuid,
&Variable,
- &mVariableModuleGlobal->VariableGlobal
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
- ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
+ return 0;
+ }
+
//
// Check whether the public key entry does exist.
//
@@ -323,7 +505,62 @@ AddPubKeyInStore (
//
if (mPubKeyNumber == MAX_KEY_NUM) {
//
- // Notes: Database is full, need enhancement here, currently just return 0.
+ // Public key dadatase is full, try to reclaim invalid key.
+ //
+ if (AtRuntime ()) {
+ //
+ // NV storage can't reclaim at runtime.
+ //
+ return 0;
+ }
+
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ FALSE,
+ NULL,
+ NULL,
+ 0,
+ TRUE
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ Status = FindVariable (
+ AUTHVAR_KEYDB_NAME,
+ &gEfiAuthenticatedVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
+ return 0;
+ }
+
+ DataSize = DataSizeOfVariable (Variable.CurrPtr);
+ Data = GetVariableDataPtr (Variable.CurrPtr);
+ ASSERT ((DataSize != 0) && (Data != NULL));
+ CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
+ mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
+
+ if (mPubKeyNumber == MAX_KEY_NUM) {
+ return 0;
+ }
+ }
+
+ //
+ // Check the variable space for both public key and variable data.
+ //
+ PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * EFI_CERT_TYPE_RSA2048_SIZE;
+ PublicKeyEntry.Guid = &gEfiAuthenticatedVariableGuid;
+ PublicKeyEntry.Name = AUTHVAR_KEYDB_NAME;
+ Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+
+ if (!CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {
+ //
+ // No enough variable space.
//
return 0;
}
@@ -338,29 +575,38 @@ AddPubKeyInStore (
&gEfiAuthenticatedVariableGuid,
mPubKeyStore,
mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
+ Attributes,
0,
0,
&Variable,
NULL
);
- ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));
+ return 0;
+ }
}
return Index;
}
/**
- Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
+ Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
Follow the steps in UEFI2.2.
+ 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.
+
@param[in] Data Pointer to data with AuthInfo.
@param[in] DataSize Size of Data.
@param[in] PubKey Public key used for verification.
- @return EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
@retval EFI_SECURITY_VIOLATION If authentication failed.
- @return EFI_SUCCESS Authentication successful.
+ @retval EFI_SUCCESS Authentication successful.
**/
EFI_STATUS
@@ -375,7 +621,9 @@ VerifyCounterBasedPayload (
EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
UINT8 Digest[SHA256_DIGEST_SIZE];
VOID *Rsa;
-
+ UINTN PayloadSize;
+
+ PayloadSize = DataSize - AUTHINFO_SIZE;
Rsa = NULL;
CertData = NULL;
CertBlock = NULL;
@@ -389,10 +637,10 @@ VerifyCounterBasedPayload (
//
// wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
- // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
+ // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
//
if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
- !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)
+ !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)
) {
//
// Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
@@ -407,7 +655,14 @@ VerifyCounterBasedPayload (
if (!Status) {
goto Done;
}
- Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
+ Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Hash Size.
+ //
+ Status = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
if (!Status) {
goto Done;
}
@@ -427,7 +682,7 @@ VerifyCounterBasedPayload (
//
Rsa = RsaNew ();
ASSERT (Rsa != NULL);
- //
+ //
// Set RSA Key Components.
// NOTE: Only N and E are needed to be set as RSA public key for signature verification.
//
@@ -443,10 +698,10 @@ VerifyCounterBasedPayload (
// Verify the signature.
//
Status = RsaPkcs1Verify (
- Rsa,
- Digest,
- SHA256_DIGEST_SIZE,
- CertBlock->Signature,
+ Rsa,
+ Digest,
+ SHA256_DIGEST_SIZE,
+ CertBlock->Signature,
EFI_CERT_TYPE_RSA2048_SHA256_SIZE
);
@@ -461,7 +716,6 @@ Done:
}
}
-
/**
Update platform mode.
@@ -478,35 +732,34 @@ UpdatePlatformMode (
{
EFI_STATUS Status;
VARIABLE_POINTER_TRACK Variable;
- UINT32 VarAttr;
UINT8 SecureBootMode;
UINT8 SecureBootEnable;
UINTN VariableDataSize;
-
+
Status = FindVariable (
- EFI_SETUP_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
+ EFI_SETUP_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
if (EFI_ERROR (Status)) {
return Status;
}
- mPlatformMode = Mode;
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
- Status = UpdateVariable (
- EFI_SETUP_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &mPlatformMode,
- sizeof(UINT8),
- VarAttr,
- 0,
- 0,
- &Variable,
- NULL
- );
- if (EFI_ERROR (Status)) {
+ //
+ // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
+ // variable storage reclaim at runtime.
+ //
+ mPlatformMode = (UINT8) Mode;
+ CopyMem (GetVariableDataPtr (Variable.CurrPtr), &mPlatformMode, sizeof(UINT8));
+
+ if (AtRuntime ()) {
+ //
+ // SecureBoot Variable indicates whether the platform firmware is operating
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot
+ // Variable in runtime.
+ //
return Status;
}
@@ -516,10 +769,11 @@ UpdatePlatformMode (
// then set "SecureBoot" to 0.
//
Status = FindVariable (
- EFI_SECURE_BOOT_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
//
// If "SecureBoot" variable exists, then check "SetupMode" variable update.
@@ -538,19 +792,17 @@ UpdatePlatformMode (
}
}
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
Status = UpdateVariable (
EFI_SECURE_BOOT_MODE_NAME,
&gEfiGlobalVariableGuid,
&SecureBootMode,
sizeof(UINT8),
- VarAttr,
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
0,
0,
&Variable,
NULL
);
-
if (EFI_ERROR (Status)) {
return Status;
}
@@ -559,12 +811,13 @@ UpdatePlatformMode (
// Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
//
Status = FindVariable (
- EFI_SECURE_BOOT_ENABLE_NAME,
- &gEfiSecureBootEnableDisableGuid,
- &Variable,
- &mVariableModuleGlobal->VariableGlobal
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
-
+
if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
//
// Create the "SecureBootEnable" variable as secure boot is enabled.
@@ -573,7 +826,7 @@ UpdatePlatformMode (
VariableDataSize = sizeof (SecureBootEnable);
} else {
//
- // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
+ // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
// variable is not in secure boot state.
//
if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
@@ -582,15 +835,15 @@ UpdatePlatformMode (
SecureBootEnable = SECURE_BOOT_DISABLE;
VariableDataSize = 0;
}
-
+
Status = UpdateVariable (
- EFI_SECURE_BOOT_ENABLE_NAME,
- &gEfiSecureBootEnableDisableGuid,
- &SecureBootEnable,
- VariableDataSize,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
- 0,
- 0,
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ &SecureBootEnable,
+ VariableDataSize,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ 0,
&Variable,
NULL
);
@@ -598,135 +851,295 @@ UpdatePlatformMode (
}
/**
- Process variable with platform key for verification.
+ Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx variable.
- @param[in] VariableName Name of Variable to be found.
+ @param[in] VariableName Name of Variable to be check.
@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] Variable The variable information which is used to keep track of variable usage.
- @param[in] Attributes Attribute value of the variable
- @param[in] IsPk Indicate whether it is to process pk.
-
- @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_SUCCESS Variable passed validation successfully.
+ @param[in] Data Point to the variable data to be checked.
+ @param[in] DataSize Size of Data.
+ @return EFI_INVALID_PARAMETER Invalid signature list format.
+ @return EFI_SUCCESS Passed signature list format check successfully.
+
**/
EFI_STATUS
-ProcessVarWithPk (
+CheckSignatureListFormat(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid,
IN VOID *Data,
- IN UINTN DataSize,
- IN VARIABLE_POINTER_TRACK *Variable,
- IN UINT32 Attributes OPTIONAL,
- IN BOOLEAN IsPk
+ IN UINTN DataSize
)
{
- EFI_STATUS Status;
- VARIABLE_POINTER_TRACK PkVariable;
- EFI_SIGNATURE_LIST *OldPkList;
- EFI_SIGNATURE_DATA *OldPkData;
- EFI_VARIABLE_AUTHENTICATION *CertData;
- BOOLEAN TimeBase;
- BOOLEAN Del;
+ EFI_SIGNATURE_LIST *SigList;
+ UINTN SigDataSize;
+ UINT32 Index;
+ UINT32 SigCount;
+ BOOLEAN IsPk;
+ VOID *RsaContext;
+ EFI_SIGNATURE_DATA *CertData;
+ UINTN CertLen;
+
+ if (DataSize == 0) {
+ return EFI_SUCCESS;
+ }
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
- //
- // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
- //
- return EFI_INVALID_PARAMETER;
+ ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
+
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
+ IsPk = TRUE;
+ } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0) ||
+ (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0 || StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))){
+ IsPk = FALSE;
+ } else {
+ return EFI_SUCCESS;
}
- if (mPlatformMode == USER_MODE) {
+ SigCount = 0;
+ SigList = (EFI_SIGNATURE_LIST *) Data;
+ SigDataSize = DataSize;
+ RsaContext = NULL;
- if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
- //
- // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.
- //
- TimeBase = TRUE;
- } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ //
+ // Walk throuth the input signature list and check the data format.
+ // If any signature is incorrectly formed, the whole check will fail.
+ //
+ while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
+ for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
+ if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
+ //
+ // The value of SignatureSize should always be 16 (size of SignatureOwner
+ // component) add the data length according to signature type.
+ //
+ if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
+ (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&
+ SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ }
+
+ if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
//
- // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.
+ // Undefined signature type.
//
- TimeBase = FALSE;
- } else {
return EFI_INVALID_PARAMETER;
}
- if (TimeBase) {
+ if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
//
- // Verify against X509 Cert PK.
+ // Try to retrieve the RSA public key from the X.509 certificate.
+ // If this operation fails, it's not a valid certificate.
//
- Del = FALSE;
- Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);
- if (!EFI_ERROR (Status)) {
- //
- // If delete PK in user mode, need change to setup mode.
- //
- if (Del && IsPk) {
- Status = UpdatePlatformMode (SETUP_MODE);
- }
+ RsaContext = RsaNew ();
+ if (RsaContext == NULL) {
+ return EFI_INVALID_PARAMETER;
}
- return Status;
- } else {
- //
- // Verify against RSA2048 Cert PK.
- //
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
- if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
- //
- // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
- //
- return EFI_SECURITY_VIOLATION;
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
+ CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
+ if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
+ RsaFree (RsaContext);
+ return EFI_INVALID_PARAMETER;
}
- //
- // Get platform key from variable.
- //
- Status = FindVariable (
- EFI_PLATFORM_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &PkVariable,
- &mVariableModuleGlobal->VariableGlobal
- );
- ASSERT_EFI_ERROR (Status);
+ RsaFree (RsaContext);
+ }
+
+ if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
+
+ SigDataSize -= SigList->SignatureListSize;
+ SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
+ }
+
+ if (((UINTN) SigList - (UINTN) Data) != DataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsPk && SigCount > 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update "VendorKeys" variable to record the out of band secure boot key modification.
+
+ @return EFI_SUCCESS Variable is updated successfully.
+ @return Others Failed to update variable.
- OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
- OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
- Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);
- if (!EFI_ERROR (Status)) {
- Status = UpdateVariable (
- VariableName,
- VendorGuid,
- (UINT8*)Data + AUTHINFO_SIZE,
- DataSize - AUTHINFO_SIZE,
- Attributes,
- 0,
- CertData->MonotonicCount,
- Variable,
- NULL
- );
+**/
+EFI_STATUS
+VendorKeyIsModified (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+
+ if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
+ return EFI_SUCCESS;
+ }
+ mVendorKeyState = VENDOR_KEYS_MODIFIED;
- if (!EFI_ERROR (Status)) {
- //
- // If delete PK in user mode, need change to setup mode.
- //
- if ((DataSize == AUTHINFO_SIZE) && IsPk) {
- Status = UpdatePlatformMode (SETUP_MODE);
- }
- }
- }
+ FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ Status = UpdateVariable (
+ EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
+ &gEfiVendorKeysNvGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
+ return UpdateVariable (
+ EFI_VENDOR_KEYS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ 0,
+ &Variable,
+ NULL
+ );
+}
+
+/**
+ Process variable with platform key for verification.
+
+ 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] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes Attribute value of the variable
+ @param[in] IsPk Indicate whether it is to process pk.
+
+ @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_SUCCESS Variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithPk (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL,
+ IN BOOLEAN IsPk
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Del;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
+ (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ //
+ // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
+ // authenticated variable.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Del = FALSE;
+ if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+ if (PayloadSize == 0) {
+ Del = TRUE;
+ }
+
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
}
+
+ Status = UpdateVariable (
+ VariableName,
+ VendorGuid,
+ Payload,
+ PayloadSize,
+ Attributes,
+ 0,
+ 0,
+ Variable,
+ &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if ((mPlatformMode != SETUP_MODE) || IsPk) {
+ Status = VendorKeyIsModified ();
+ }
+ } else if (mPlatformMode == USER_MODE) {
+ //
+ // Verify against X509 Cert in PK database.
+ //
+ Status = VerifyTimeBasedPayload (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Variable,
+ Attributes,
+ AuthVarTypePk,
+ &Del
+ );
} else {
- Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
//
- // If enroll PK in setup mode, need change to user mode.
+ // Verify against the certificate in data payload.
//
- if ((DataSize != 0) && IsPk) {
+ Status = VerifyTimeBasedPayload (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Variable,
+ Attributes,
+ AuthVarTypePayload,
+ &Del
+ );
+ }
+
+ if (!EFI_ERROR(Status) && IsPk) {
+ if (mPlatformMode == SETUP_MODE && !Del) {
+ //
+ // If enroll PK in setup mode, need change to user mode.
+ //
Status = UpdatePlatformMode (USER_MODE);
+ } else if (mPlatformMode == USER_MODE && Del){
+ //
+ // If delete PK in user mode, need change to setup mode.
+ //
+ Status = UpdatePlatformMode (SETUP_MODE);
}
}
@@ -736,6 +1149,13 @@ ProcessVarWithPk (
/**
Process variable with key exchange key for verification.
+ 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.
@@ -745,8 +1165,8 @@ ProcessVarWithPk (
@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_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
@return EFI_SUCCESS Variable pass validation successfully.
**/
@@ -761,100 +1181,63 @@ ProcessVarWithKek (
)
{
EFI_STATUS Status;
- VARIABLE_POINTER_TRACK KekVariable;
- EFI_SIGNATURE_LIST *KekList;
- EFI_SIGNATURE_DATA *KekItem;
- UINT32 KekCount;
- EFI_VARIABLE_AUTHENTICATION *CertData;
- EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
- BOOLEAN IsFound;
- UINT32 Index;
- UINT32 KekDataSize;
-
- if (mPlatformMode == USER_MODE) {
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
- //
- // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
- //
- return EFI_INVALID_PARAMETER;
- }
+ UINT8 *Payload;
+ UINTN PayloadSize;
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
- CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
- if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
- //
- // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
- //
- return EFI_SECURITY_VIOLATION;
- }
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
+ (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
//
- // Get KEK database from variable.
+ // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
+ // authenticated variable.
//
- Status = FindVariable (
- EFI_KEY_EXCHANGE_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &KekVariable,
- &mVariableModuleGlobal->VariableGlobal
- );
- ASSERT_EFI_ERROR (Status);
-
- KekDataSize = KekVariable.CurrPtr->DataSize;
- KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = EFI_SUCCESS;
+ if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
//
- // Enumerate all Kek items in this list to verify the variable certificate data.
- // If anyone is authenticated successfully, it means the variable is correct!
+ // Time-based, verify against X509 Cert KEK.
//
- IsFound = FALSE;
- while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {
- if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
- KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
- for (Index = 0; Index < KekCount; Index++) {
- if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
- IsFound = TRUE;
- break;
- }
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
- }
- }
- KekDataSize -= KekList->SignatureListSize;
- KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
- }
-
- if (!IsFound) {
- return EFI_SECURITY_VIOLATION;
- }
-
- Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);
- if (!EFI_ERROR (Status)) {
- Status = UpdateVariable (
- VariableName,
- VendorGuid,
- (UINT8*)Data + AUTHINFO_SIZE,
- DataSize - AUTHINFO_SIZE,
- Attributes,
- 0,
- CertData->MonotonicCount,
- Variable,
- NULL
- );
- }
+ return VerifyTimeBasedPayload (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Variable,
+ Attributes,
+ AuthVarTypeKek,
+ NULL
+ );
} else {
//
- // If in setup mode, no authentication needed.
+ // If in setup mode or custom secure boot mode, no authentication needed.
//
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
Status = UpdateVariable (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- Attributes,
- 0,
- 0,
+ VariableName,
+ VendorGuid,
+ Payload,
+ PayloadSize,
+ Attributes,
+ 0,
+ 0,
Variable,
- NULL
+ &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mPlatformMode != SETUP_MODE) {
+ Status = VendorKeyIsModified ();
+ }
}
return Status;
@@ -863,6 +1246,13 @@ ProcessVarWithKek (
/**
Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+ 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.
@@ -875,9 +1265,10 @@ ProcessVarWithKek (
@return EFI_INVALID_PARAMETER Invalid parameter.
@return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
@return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
- set, but the AuthInfo does NOT pass the validation
- check carried out by the firmware.
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
@return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
**/
@@ -899,20 +1290,53 @@ ProcessVariable (
EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
UINT32 KeyIndex;
UINT64 MonotonicCount;
+ VARIABLE_ENTRY_CONSISTENCY VariableDataEntry;
- KeyIndex = 0;
+ KeyIndex = 0;
CertData = NULL;
CertBlock = NULL;
PubKey = NULL;
IsDeletion = FALSE;
+ if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {
+ //
+ // This variable is protected, only physical present user could modify its value.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // A time-based authenticated variable and a count-based authenticated variable
+ // can't be updated by each other.
+ //
+ if (Variable->CurrPtr != NULL) {
+ if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
+ ((Variable->CurrPtr->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
+ ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+
//
// Process Time-based Authenticated variable.
//
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
- return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);
+ return VerifyTimeBasedPayload (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Variable,
+ Attributes,
+ AuthVarTypePriv,
+ NULL
+ );
}
-
+
//
// Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
//
@@ -934,9 +1358,9 @@ ProcessVariable (
KeyIndex = Variable->CurrPtr->PubKeyIndex;
IsFirstTime = FALSE;
}
- } else if ((Variable->CurrPtr != NULL) &&
- (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0
- ) {
+ } else if ((Variable->CurrPtr != NULL) &&
+ ((Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
+ ) {
//
// If the variable is already write-protected, it always needs authentication before update.
//
@@ -979,7 +1403,7 @@ ProcessVariable (
//
return EFI_SECURITY_VIOLATION;
}
- }
+ }
//
// Verify the certificate in Data payload.
//
@@ -987,15 +1411,22 @@ ProcessVariable (
if (EFI_ERROR (Status)) {
return Status;
}
-
+
//
// Now, the signature has been verified!
//
if (IsFirstTime && !IsDeletion) {
+ VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;
+ VariableDataEntry.Guid = VendorGuid;
+ VariableDataEntry.Name = VariableName;
+
//
// Update public key database variable if need.
//
- KeyIndex = AddPubKeyInStore (PubKey);
+ KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);
+ if (KeyIndex == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
}
//
@@ -1004,6 +1435,129 @@ ProcessVariable (
return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
}
+/**
+ Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
+ will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
+ will be ignored.
+
+ @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
+ @param[in] DataSize Size of Data buffer.
+ @param[in] FreeBufSize Size of free data buffer
+ @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
+ @param[in] NewDataSize Size of NewData buffer.
+ @param[out] MergedBufSize Size of the merged buffer
+
+ @return EFI_BUFFER_TOO_SMALL if input Data buffer overflowed
+
+**/
+EFI_STATUS
+AppendSignatureList (
+ IN OUT VOID *Data,
+ IN UINTN DataSize,
+ IN UINTN FreeBufSize,
+ IN VOID *NewData,
+ IN UINTN NewDataSize,
+ OUT UINTN *MergedBufSize
+ )
+{
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN CertCount;
+ EFI_SIGNATURE_LIST *NewCertList;
+ EFI_SIGNATURE_DATA *NewCert;
+ UINTN NewCertCount;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Size;
+ UINT8 *Tail;
+ UINTN CopiedCount;
+ UINTN SignatureListSize;
+ BOOLEAN IsNewCert;
+
+ Tail = (UINT8 *) Data + DataSize;
+
+ NewCertList = (EFI_SIGNATURE_LIST *) NewData;
+ while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {
+ NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
+ NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
+
+ CopiedCount = 0;
+ for (Index = 0; Index < NewCertCount; Index++) {
+ IsNewCert = TRUE;
+
+ Size = DataSize;
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
+ (CertList->SignatureSize == NewCertList->SignatureSize)) {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ for (Index2 = 0; Index2 < CertCount; Index2++) {
+ //
+ // Iterate each Signature Data in this Signature List.
+ //
+ if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
+ IsNewCert = FALSE;
+ break;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+
+ if (!IsNewCert) {
+ break;
+ }
+ Size -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ if (IsNewCert) {
+ //
+ // New EFI_SIGNATURE_DATA, append it.
+ //
+ if (CopiedCount == 0) {
+ if (FreeBufSize < sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Copy EFI_SIGNATURE_LIST header for only once.
+ //
+
+ CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
+ Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
+ FreeBufSize -= sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
+ }
+
+ if (FreeBufSize < NewCertList->SignatureSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (Tail, NewCert, NewCertList->SignatureSize);
+ Tail += NewCertList->SignatureSize;
+ FreeBufSize -= NewCertList->SignatureSize;
+ CopiedCount++;
+ }
+
+ NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
+ }
+
+ //
+ // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
+ //
+ if (CopiedCount != 0) {
+ SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
+ CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
+ CertList->SignatureListSize = (UINT32) SignatureListSize;
+ }
+
+ NewDataSize -= NewCertList->SignatureListSize;
+ NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
+ }
+
+ *MergedBufSize = (Tail - (UINT8 *) Data);
+ return EFI_SUCCESS;
+}
+
/**
Compare two EFI_TIME data.
@@ -1030,56 +1584,520 @@ CompareTimeStamp (
} else if (FirstTime->Hour != SecondTime->Hour) {
return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
} else if (FirstTime->Minute != SecondTime->Minute) {
- return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
- }
+ return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
+ }
return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
}
/**
- Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+ Find matching signer's certificates for common authenticated variable
+ by corresponding VariableName and VendorGuid from "certdb".
- @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] Variable The variable information which is used to keep track of variable usage.
- @param[in] Attributes Attribute value of the variable.
- @param[in] Pk Verify against PK or KEK database.
- @param[out] VarDel Delete the variable or not.
+ The data format of "certdb":
+ //
+ // UINT32 CertDbListSize;
+ // /// AUTH_CERT_DB_DATA Certs1[];
+ // /// AUTH_CERT_DB_DATA Certs2[];
+ // /// ...
+ // /// AUTH_CERT_DB_DATA Certsn[];
+ //
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
- check carried out by the firmware.
- @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
- of resources.
- @retval EFI_SUCCESS Variable pass validation successfully.
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] Data Pointer to variable "certdb".
+ @param[in] DataSize Size of variable "certdb".
+ @param[out] CertOffset Offset of matching CertData, from starting of Data.
+ @param[out] CertDataSize Length of CertData in bytes.
+ @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
+ starting of Data.
+ @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find matching certs.
+ @retval EFI_SUCCESS Find matching certs and output parameters.
**/
EFI_STATUS
-VerifyTimeBasedPayload (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN VARIABLE_POINTER_TRACK *Variable,
- IN UINT32 Attributes,
- IN BOOLEAN Pk,
- OUT BOOLEAN *VarDel
+FindCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT8 *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *CertOffset, OPTIONAL
+ OUT UINT32 *CertDataSize, OPTIONAL
+ OUT UINT32 *CertNodeOffset,OPTIONAL
+ OUT UINT32 *CertNodeSize OPTIONAL
)
{
- UINT8 *RootCert;
- UINT8 *SigData;
- UINT8 *PayLoadPtr;
- UINTN RootCertSize;
- UINTN Index;
- UINTN CertCount;
- UINTN PayLoadSize;
- UINT32 Attr;
- UINT32 SigDataSize;
- UINT32 KekDataSize;
- BOOLEAN Result;
+ UINT32 Offset;
+ AUTH_CERT_DB_DATA *Ptr;
+ UINT32 CertSize;
+ UINT32 NameSize;
+ UINT32 NodeSize;
+ UINT32 CertDbListSize;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether DataSize matches recorded CertDbListSize.
+ //
+ if (DataSize < sizeof (UINT32)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
+
+ if (CertDbListSize != (UINT32) DataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = sizeof (UINT32);
+
+ //
+ // Get corresponding certificates by VendorGuid and VariableName.
+ //
+ while (Offset < (UINT32) DataSize) {
+ Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
+ //
+ // Check whether VendorGuid matches.
+ //
+ if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
+ NameSize = ReadUnaligned32 (&Ptr->NameSize);
+ CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
+
+ if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
+ sizeof (CHAR16) * NameSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
+ //
+ // Check whether VariableName matches.
+ //
+ if ((NameSize == StrLen (VariableName)) &&
+ (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
+ Offset = Offset + NameSize * sizeof (CHAR16);
+
+ if (CertOffset != NULL) {
+ *CertOffset = Offset;
+ }
+
+ if (CertDataSize != NULL) {
+ *CertDataSize = CertSize;
+ }
+
+ if (CertNodeOffset != NULL) {
+ *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
+ }
+
+ if (CertNodeSize != NULL) {
+ *CertNodeSize = NodeSize;
+ }
+
+ return EFI_SUCCESS;
+ } else {
+ Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
+ }
+ } else {
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
+ Offset = Offset + NodeSize;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieve signer's certificates for common authenticated variable
+ by corresponding VariableName and VendorGuid from "certdb".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[out] CertData Pointer to signer's certificates.
+ @param[out] CertDataSize Length of CertData in bytes.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
+ @retval EFI_SUCCESS Get signer's certificates successfully.
+
+**/
+EFI_STATUS
+GetCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT8 **CertData,
+ OUT UINT32 *CertDataSize
+ )
+{
+ VARIABLE_POINTER_TRACK CertDbVariable;
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 CertOffset;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get variable "certdb".
+ //
+ Status = FindVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ &CertDbVariable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
+ Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ Status = FindCertsFromDb (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ &CertOffset,
+ CertDataSize,
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *CertData = Data + CertOffset;
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete matching signer's certificates when deleting common authenticated
+ variable by corresponding VariableName and VendorGuid from "certdb".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS The operation is completed successfully.
+
+**/
+EFI_STATUS
+DeleteCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ VARIABLE_POINTER_TRACK CertDbVariable;
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 VarAttr;
+ UINT32 CertNodeOffset;
+ UINT32 CertNodeSize;
+ UINT8 *NewCertDb;
+ UINT32 NewCertDbSize;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get variable "certdb".
+ //
+ Status = FindVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ &CertDbVariable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
+ Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ if (DataSize == sizeof (UINT32)) {
+ //
+ // There is no certs in certdb.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get corresponding cert node from certdb.
+ //
+ Status = FindCertsFromDb (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ NULL,
+ NULL,
+ &CertNodeOffset,
+ &CertNodeSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DataSize < (CertNodeOffset + CertNodeSize)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Construct new data content of variable "certdb".
+ //
+ NewCertDbSize = (UINT32) DataSize - CertNodeSize;
+ NewCertDb = (UINT8*) mCertDbStore;
+
+ //
+ // Copy the DB entries before deleting node.
+ //
+ CopyMem (NewCertDb, Data, CertNodeOffset);
+ //
+ // Update CertDbListSize.
+ //
+ CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
+ //
+ // Copy the DB entries after deleting node.
+ //
+ if (DataSize > (CertNodeOffset + CertNodeSize)) {
+ CopyMem (
+ NewCertDb + CertNodeOffset,
+ Data + CertNodeOffset + CertNodeSize,
+ DataSize - CertNodeOffset - CertNodeSize
+ );
+ }
+
+ //
+ // Set "certdb".
+ //
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = UpdateVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ NewCertDb,
+ NewCertDbSize,
+ VarAttr,
+ 0,
+ 0,
+ &CertDbVariable,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Insert signer's certificates for common authenticated variable with VariableName
+ and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] CertData Pointer to signer's certificates.
+ @param[in] CertDataSize Length of CertData in bytes.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
+ and VendorGuid already exists.
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"
+
+**/
+EFI_STATUS
+InsertCertsToDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT8 *CertData,
+ IN UINTN CertDataSize
+ )
+{
+ VARIABLE_POINTER_TRACK CertDbVariable;
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 VarAttr;
+ UINT8 *NewCertDb;
+ UINT32 NewCertDbSize;
+ UINT32 CertNodeSize;
+ UINT32 NameSize;
+ AUTH_CERT_DB_DATA *Ptr;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get variable "certdb".
+ //
+ Status = FindVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ &CertDbVariable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
+ Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find whether matching cert node already exists in "certdb".
+ // If yes return error.
+ //
+ Status = FindCertsFromDb (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (FALSE);
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Construct new data content of variable "certdb".
+ //
+ NameSize = (UINT32) StrLen (VariableName);
+ CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
+ NewCertDbSize = (UINT32) DataSize + CertNodeSize;
+ if (NewCertDbSize > MAX_CERTDB_SIZE) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewCertDb = (UINT8*) mCertDbStore;
+
+ //
+ // Copy the DB entries before deleting node.
+ //
+ CopyMem (NewCertDb, Data, DataSize);
+ //
+ // Update CertDbListSize.
+ //
+ CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
+ //
+ // Construct new cert node.
+ //
+ Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
+ CopyGuid (&Ptr->VendorGuid, VendorGuid);
+ CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
+ CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
+ CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
+
+ CopyMem (
+ (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
+ VariableName,
+ NameSize * sizeof (CHAR16)
+ );
+
+ CopyMem (
+ (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
+ CertData,
+ CertDataSize
+ );
+
+ //
+ // Set "certdb".
+ //
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = UpdateVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ NewCertDb,
+ NewCertDbSize,
+ VarAttr,
+ 0,
+ 0,
+ &CertDbVariable,
+ NULL
+ );
+
+ return Status;
+}
+
+/**
+ Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+
+ 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.
+
+ @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] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
+ @param[out] VarDel Delete the variable or not.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
+ of resources.
+ @retval EFI_SUCCESS Variable pass validation successfully.
+
+**/
+EFI_STATUS
+VerifyTimeBasedPayload (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes,
+ IN AUTHVAR_TYPE AuthVarType,
+ OUT BOOLEAN *VarDel
+ )
+{
+ UINT8 *RootCert;
+ UINT8 *SigData;
+ UINT8 *PayloadPtr;
+ UINTN RootCertSize;
+ UINTN Index;
+ UINTN CertCount;
+ UINTN PayloadSize;
+ UINT32 Attr;
+ UINT32 SigDataSize;
+ UINT32 KekDataSize;
BOOLEAN VerifyStatus;
EFI_STATUS Status;
EFI_SIGNATURE_LIST *CertList;
@@ -1089,24 +2107,44 @@ VerifyTimeBasedPayload (
UINT8 *NewData;
UINTN NewDataSize;
VARIABLE_POINTER_TRACK PkVariable;
+ UINT8 *Buffer;
+ UINTN Length;
+ UINT8 *SignerCerts;
+ UINT8 *WrapSigData;
+ UINTN CertStackSize;
+ UINT8 *CertsInCertDb;
+ UINT32 CertsSizeinDb;
-
- Result = FALSE;
VerifyStatus = FALSE;
CertData = NULL;
NewData = NULL;
Attr = Attributes;
+ WrapSigData = NULL;
+ SignerCerts = NULL;
+ RootCert = NULL;
//
- // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
+ // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
// set, then the Data buffer shall begin with an instance of a complete (and serialized)
- // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
- // variable value and DataSize shall reflect the combined size of the descriptor and the new
- // variable value. The authentication descriptor is not part of the variable data and is not
+ // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
+ // variable value and DataSize shall reflect the combined size of the descriptor and the new
+ // variable value. The authentication descriptor is not part of the variable data and is not
// returned by subsequent calls to GetVariable().
//
CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
-
+
+ //
+ // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
+ // TimeStamp value are set to zero.
+ //
+ if ((CertData->TimeStamp.Pad1 != 0) ||
+ (CertData->TimeStamp.Nanosecond != 0) ||
+ (CertData->TimeStamp.TimeZone != 0) ||
+ (CertData->TimeStamp.Daylight != 0) ||
+ (CertData->TimeStamp.Pad2 != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
//
@@ -1121,95 +2159,91 @@ VerifyTimeBasedPayload (
// Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
//
if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
- !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)
- ) {
+ !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
//
// Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
//
return EFI_SECURITY_VIOLATION;
}
-
+
//
// Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
// AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
//
- SigData = (UINT8*) ((UINTN)Data + OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
+ SigData = CertData->AuthInfo.CertData;
+ SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
- //
- // Sanity check to avoid corrupted certificate input.
- //
- if (CertData->AuthInfo.Hdr.dwLength < (UINT32)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData))) {
- return EFI_SECURITY_VIOLATION;
- }
-
-
-
- SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
-
//
// Find out the new data payload which follows Pkcs7 SignedData directly.
//
- PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);
-
- //
- // Sanity check to avoid corrupted certificate input.
- //
- if (DataSize < (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)+ (UINTN) SigDataSize)) {
- return EFI_SECURITY_VIOLATION;
- }
-
- PayLoadSize = DataSize - OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) - OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) - (UINTN) SigDataSize;
-
+ PayloadPtr = SigData + SigDataSize;
+ PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
//
// Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
//
- NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
- sizeof (EFI_GUID) + StrSize (VariableName);
- NewData = (UINT8 *) AllocateZeroPool (NewDataSize);
+ NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
+ sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
+ NewData = mSerializationRuntimeBuffer;
- if (NewData == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
+ Buffer = NewData;
+ Length = StrLen (VariableName) * sizeof (CHAR16);
+ CopyMem (Buffer, VariableName, Length);
+ Buffer += Length;
- CopyMem (NewData, VariableName, StrSize (VariableName));
+ Length = sizeof (EFI_GUID);
+ CopyMem (Buffer, VendorGuid, Length);
+ Buffer += Length;
- CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID));
+ Length = sizeof (UINT32);
+ CopyMem (Buffer, &Attr, Length);
+ Buffer += Length;
- CopyMem (
- NewData + StrSize (VariableName) + sizeof (EFI_GUID),
- &Attr,
- sizeof (UINT32)
- );
+ Length = sizeof (EFI_TIME);
+ CopyMem (Buffer, &CertData->TimeStamp, Length);
+ Buffer += Length;
- CopyMem (
- NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32),
- &CertData->TimeStamp,
- sizeof (EFI_TIME)
- );
-
- CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize);
+ CopyMem (Buffer, PayloadPtr, PayloadSize);
+ if (AuthVarType == AuthVarTypePk) {
+ //
+ // Verify that the signature has been made with the current Platform Key (no chaining for PK).
+ // First, get signer's certificates from SignedData.
+ //
+ VerifyStatus = Pkcs7GetSigners (
+ SigData,
+ SigDataSize,
+ &SignerCerts,
+ &CertStackSize,
+ &RootCert,
+ &RootCertSize
+ );
+ if (!VerifyStatus) {
+ goto Exit;
+ }
- if (Pk) {
//
- // Get platform key from variable.
+ // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
+ // in SignedData. If not, return error immediately.
//
Status = FindVariable (
- EFI_PLATFORM_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &PkVariable,
- &mVariableModuleGlobal->VariableGlobal
+ EFI_PLATFORM_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &PkVariable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
if (EFI_ERROR (Status)) {
- return Status;
+ VerifyStatus = FALSE;
+ goto Exit;
}
-
CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
- RootCert = Cert->SignatureData;
- RootCertSize = CertList->SignatureSize;
-
+ if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
+ (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {
+ VerifyStatus = FALSE;
+ goto Exit;
+ }
//
// Verify Pkcs7 SignedData via Pkcs7Verify library.
@@ -1223,16 +2257,17 @@ VerifyTimeBasedPayload (
NewDataSize
);
- } else {
-
+ } else if (AuthVarType == AuthVarTypeKek) {
+
//
// Get KEK database from variable.
//
Status = FindVariable (
- EFI_KEY_EXCHANGE_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &KekVariable,
- &mVariableModuleGlobal->VariableGlobal
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &KekVariable,
+ &mVariableModuleGlobal->VariableGlobal,
+ FALSE
);
if (EFI_ERROR (Status)) {
return Status;
@@ -1240,7 +2275,7 @@ VerifyTimeBasedPayload (
//
// Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
- //
+ //
KekDataSize = KekVariable.CurrPtr->DataSize;
CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
@@ -1252,8 +2287,8 @@ VerifyTimeBasedPayload (
// Iterate each Signature Data Node within this CertList for a verify
//
RootCert = Cert->SignatureData;
- RootCertSize = CertList->SignatureSize;
-
+ RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
+
//
// Verify Pkcs7 SignedData via Pkcs7Verify library.
//
@@ -1274,32 +2309,127 @@ VerifyTimeBasedPayload (
KekDataSize -= CertList->SignatureListSize;
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
}
+ } else if (AuthVarType == AuthVarTypePriv) {
+
+ //
+ // Process common authenticated variable except PK/KEK/DB/DBX.
+ // Get signer's certificates from SignedData.
+ //
+ VerifyStatus = Pkcs7GetSigners (
+ SigData,
+ SigDataSize,
+ &SignerCerts,
+ &CertStackSize,
+ &RootCert,
+ &RootCertSize
+ );
+ if (!VerifyStatus) {
+ goto Exit;
+ }
+
+ //
+ // Get previously stored signer's certificates from certdb for existing
+ // variable. Check whether they are identical with signer's certificates
+ // in SignedData. If not, return error immediately.
+ //
+ if ((Variable->CurrPtr != NULL)) {
+ VerifyStatus = FALSE;
+
+ Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((CertStackSize != CertsSizeinDb) ||
+ (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
+ goto Exit;
+ }
+ }
+
+ VerifyStatus = Pkcs7Verify (
+ SigData,
+ SigDataSize,
+ RootCert,
+ RootCertSize,
+ NewData,
+ NewDataSize
+ );
+ if (!VerifyStatus) {
+ goto Exit;
+ }
+
+ //
+ // Delete signer's certificates when delete the common authenticated variable.
+ //
+ if ((PayloadSize == 0) && (Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
+ Status = DeleteCertsFromDb (VariableName, VendorGuid);
+ if (EFI_ERROR (Status)) {
+ VerifyStatus = FALSE;
+ goto Exit;
+ }
+ } else if (Variable->CurrPtr == NULL && PayloadSize != 0) {
+ //
+ // Insert signer's certificates when adding a new common authenticated variable.
+ //
+ Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);
+ if (EFI_ERROR (Status)) {
+ VerifyStatus = FALSE;
+ goto Exit;
+ }
+ }
+ } else if (AuthVarType == AuthVarTypePayload) {
+ CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ RootCert = Cert->SignatureData;
+ RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
+
+ // Verify Pkcs7 SignedData via Pkcs7Verify library.
+ //
+ VerifyStatus = Pkcs7Verify (
+ SigData,
+ SigDataSize,
+ RootCert,
+ RootCertSize,
+ NewData,
+ NewDataSize
+ );
+ } else {
+ return EFI_SECURITY_VIOLATION;
}
Exit:
- FreePool (NewData);
+ if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {
+ Pkcs7FreeSigners (RootCert);
+ Pkcs7FreeSigners (SignerCerts);
+ }
if (!VerifyStatus) {
return EFI_SECURITY_VIOLATION;
}
- if ((PayLoadSize == 0) && (VarDel != NULL)) {
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PayloadSize == 0) && (VarDel != NULL)) {
*VarDel = TRUE;
}
-
+
//
// Final step: Update/Append Variable if it pass Pkcs7Verify
//
- return UpdateVariable (
- VariableName,
- VendorGuid,
- PayLoadPtr,
- PayLoadSize,
- Attributes,
- 0,
- 0,
- Variable,
- &CertData->TimeStamp
- );
+ return UpdateVariable (
+ VariableName,
+ VendorGuid,
+ PayloadPtr,
+ PayloadSize,
+ Attributes,
+ 0,
+ 0,
+ Variable,
+ &CertData->TimeStamp
+ );
}
+