Implement authentication services for the authenticated variable\r
service in UEFI2.2.\r
\r
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
+Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
http://opensource.org/licenses/bsd-license.php\r
\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
\r
**/\r
\r
///\r
/// Global database array for scratch\r
-/// \r
+///\r
UINT8 mPubKeyStore[MAX_KEYDB_SIZE];\r
UINT32 mPubKeyNumber;\r
UINT32 mPlatformMode;\r
-EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
+EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};\r
//\r
// Public Exponent of RSA Key.\r
//\r
//\r
VOID *mHashCtx = NULL;\r
\r
-\r
//\r
-// Pointer to runtime buffer. \r
-// For "Append" operation to an existing variable, a read/modify/write operation \r
-// is supported by firmware internally. Reserve runtime buffer to cache previous \r
+// Pointer to runtime buffer.\r
+// For "Append" operation to an existing variable, a read/modify/write operation\r
+// is supported by firmware internally. Reserve runtime buffer to cache previous\r
// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
//\r
VOID *mStorageArea = NULL;\r
\r
+//\r
+// The serialization of the values of the VariableName, VendorGuid and Attributes\r
+// parameters of the SetVariable() call and the TimeStamp component of the\r
+// EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r
+// i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r
+//\r
+UINT8 *mSerializationRuntimeBuffer = NULL;\r
+\r
+//\r
+// Requirement for different signature type which have been defined in UEFI spec.\r
+// These data are used to peform SignatureList format check while setting PK/KEK variable.\r
+//\r
+EFI_SIGNATURE_ITEM mSupportSigItem[] = {\r
+//{SigType, SigHeaderSize, SigDataSize }\r
+ {EFI_CERT_SHA256_GUID, 0, 32 },\r
+ {EFI_CERT_RSA2048_GUID, 0, 256 },\r
+ {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },\r
+ {EFI_CERT_SHA1_GUID, 0, 20 },\r
+ {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },\r
+ {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},\r
+ {EFI_CERT_SHA224_GUID, 0, 28 },\r
+ {EFI_CERT_SHA384_GUID, 0, 48 },\r
+ {EFI_CERT_SHA512_GUID, 0, 64 }\r
+};\r
+\r
/**\r
- Update platform mode.\r
+ Determine whether this operation needs a physical present user.\r
\r
- @param[in] Mode SETUP_MODE or USER_MODE.\r
+ @param[in] VariableName Name of the Variable.\r
+ @param[in] VendorGuid GUID of the Variable.\r
\r
- @return EFI_INVALID_PARAMETER Invalid parameter.\r
- @return EFI_SUCCESS Update platform mode successfully.\r
+ @retval TRUE This variable is protected, only a physical present user could set this variable.\r
+ @retval FALSE This variable is not protected.\r
+ \r
+**/\r
+BOOLEAN\r
+NeedPhysicallyPresent(\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))\r
+ || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {\r
+ return TRUE;\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Determine whether the platform is operating in Custom Secure Boot mode.\r
+\r
+ @retval TRUE The platform is operating in Custom mode.\r
+ @retval FALSE The platform is operating in Standard mode.\r
+\r
+**/\r
+BOOLEAN\r
+InCustomMode (\r
+ VOID\r
+ )\r
+{\r
+ VARIABLE_POINTER_TRACK Variable;\r
+\r
+ FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {\r
+ return TRUE;\r
+ }\r
+ \r
+ return FALSE;\r
+}\r
+\r
+\r
+/**\r
+ Internal function to delete a Variable given its name and GUID, no authentication\r
+ required.\r
+\r
+ @param[in] VariableName Name of the Variable.\r
+ @param[in] VendorGuid GUID of the Variable.\r
+\r
+ @retval EFI_SUCCESS Variable deleted successfully.\r
+ @retval Others The driver failded to start the device.\r
\r
**/\r
EFI_STATUS\r
-UpdatePlatformMode (\r
- IN UINT32 Mode\r
- );\r
+DeleteVariable (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_POINTER_TRACK Variable;\r
+\r
+ Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ ASSERT (Variable.CurrPtr != NULL);\r
+ return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);\r
+}\r
\r
/**\r
Initializes for authenticated varibale service.\r
{\r
EFI_STATUS Status;\r
VARIABLE_POINTER_TRACK Variable;\r
+ VARIABLE_POINTER_TRACK PkVariable;\r
UINT8 VarValue;\r
UINT32 VarAttr;\r
UINT8 *Data;\r
UINTN DataSize;\r
UINTN CtxSize;\r
+ UINT8 SecureBootMode;\r
+ UINT8 SecureBootEnable;\r
+ UINT8 CustomMode;\r
+ UINT32 ListSize;\r
+\r
//\r
// Initialize hash context.\r
//\r
//\r
// Reserved runtime buffer for "Append" operation in virtual mode.\r
//\r
- mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize));\r
+ mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));\r
if (mStorageArea == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
//\r
- // Check "AuthVarKeyDatabase" variable's existence. \r
- // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+ // Prepare runtime buffer for serialized data of time-based authenticated\r
+ // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
+ //\r
+ mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));\r
+ if (mSerializationRuntimeBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Check "AuthVarKeyDatabase" variable's existence.\r
+ // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
//\r
Status = FindVariable (\r
- AUTHVAR_KEYDB_NAME, \r
- &gEfiAuthenticatedVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ AUTHVAR_KEYDB_NAME,\r
+ &gEfiAuthenticatedVariableGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
\r
if (Variable.CurrPtr == NULL) {\r
CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
}\r
+\r
+ FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (PkVariable.CurrPtr == NULL) {\r
+ DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
+ }\r
+ \r
//\r
- // Check "SetupMode" variable's existence. \r
+ // Check "SetupMode" variable's existence.\r
// If it doesn't exist, check PK database's existence to determine the value.\r
- // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+ // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
//\r
Status = FindVariable (\r
- EFI_SETUP_MODE_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
\r
if (Variable.CurrPtr == NULL) {\r
- Status = FindVariable (\r
- EFI_PLATFORM_KEY_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
- );\r
- if (Variable.CurrPtr == NULL) {\r
+ if (PkVariable.CurrPtr == NULL) {\r
mPlatformMode = SETUP_MODE;\r
} else {\r
mPlatformMode = USER_MODE;\r
}\r
\r
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
Status = UpdateVariable (\r
EFI_SETUP_MODE_NAME,\r
&gEfiGlobalVariableGuid,\r
mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
}\r
//\r
- // Check "SignatureSupport" variable's existence. \r
- // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+ // Check "SignatureSupport" variable's existence.\r
+ // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
//\r
Status = FindVariable (\r
- EFI_SIGNATURE_SUPPORT_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_SIGNATURE_SUPPORT_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
\r
if (Variable.CurrPtr == NULL) {\r
EFI_SIGNATURE_SUPPORT_NAME,\r
&gEfiGlobalVariableGuid,\r
mSignatureSupport,\r
- SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
+ sizeof(mSignatureSupport),\r
VarAttr,\r
0,\r
0,\r
NULL\r
);\r
}\r
- \r
+\r
//\r
- // Detect whether a secure platform-specific method to clear PK(Platform Key)\r
- // is configured by platform owner. This method is provided for users force to clear PK \r
- // in case incorrect enrollment mis-haps.\r
+ // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
+ // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
+ // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
//\r
- if (ForceClearPK ()) {\r
+ SecureBootEnable = SECURE_BOOT_MODE_DISABLE;\r
+ FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (Variable.CurrPtr != NULL) {\r
+ SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
+ } else if (mPlatformMode == USER_MODE) {\r
//\r
- // 1. Check whether PK is existing, and clear PK if existing\r
+ // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
//\r
- FindVariable (\r
- EFI_PLATFORM_KEY_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
- );\r
- if (Variable.CurrPtr != NULL) {\r
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
- Status = UpdateVariable (\r
- EFI_PLATFORM_KEY_NAME,\r
- &gEfiGlobalVariableGuid,\r
- NULL,\r
- 0,\r
- VarAttr,\r
- 0,\r
- 0,\r
- &Variable,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ SecureBootEnable = SECURE_BOOT_MODE_ENABLE;\r
+ Status = UpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ 0,\r
+ &Variable,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
+ }\r
+\r
+ if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
+ SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
+ } else {\r
+ SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+ }\r
+ FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ Status = UpdateVariable (\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &SecureBootMode,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
+ 0,\r
+ 0,\r
+ &Variable,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));\r
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));\r
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
+\r
+ //\r
+ // Check "CustomMode" variable's existence.\r
+ //\r
+ FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (Variable.CurrPtr != NULL) {\r
+ CustomMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
+ } else {\r
//\r
- // 2. Update "SetupMode" variable to SETUP_MODE\r
+ // "CustomMode" not exist, initialize it in STANDARD_SECURE_BOOT_MODE.\r
//\r
- UpdatePlatformMode (SETUP_MODE);\r
+ CustomMode = STANDARD_SECURE_BOOT_MODE;\r
+ Status = UpdateVariable (\r
+ EFI_CUSTOM_MODE_NAME,\r
+ &gEfiCustomModeEnableGuid,\r
+ &CustomMode,\r
+ sizeof (UINT8),\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ 0,\r
+ &Variable,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
}\r
+ \r
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));\r
+\r
+ //\r
+ // Check "certdb" variable's existence.\r
+ // If it doesn't exist, then create a new one with \r
+ // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.\r
+ //\r
+ Status = FindVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
+ );\r
+\r
+ if (Variable.CurrPtr == NULL) {\r
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+ ListSize = 0;\r
+ Status = UpdateVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ &ListSize,\r
+ sizeof (UINT32),\r
+ VarAttr,\r
+ 0,\r
+ 0,\r
+ &Variable,\r
+ NULL\r
+ );\r
+\r
+ } \r
+\r
return Status;\r
}\r
\r
AUTHVAR_KEYDB_NAME,\r
&gEfiAuthenticatedVariableGuid,\r
&Variable,\r
- &mVariableModuleGlobal->VariableGlobal\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
ASSERT_EFI_ERROR (Status);\r
//\r
}\r
\r
/**\r
- Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
+ Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.\r
Follow the steps in UEFI2.2.\r
\r
@param[in] Data Pointer to data with AuthInfo.\r
@param[in] DataSize Size of Data.\r
@param[in] PubKey Public key used for verification.\r
\r
- @return EFI_INVALID_PARAMETER Invalid parameter.\r
+ @retval EFI_INVALID_PARAMETER Invalid parameter.\r
@retval EFI_SECURITY_VIOLATION If authentication failed.\r
- @return EFI_SUCCESS Authentication successful.\r
+ @retval EFI_SUCCESS Authentication successful.\r
\r
**/\r
EFI_STATUS\r
\r
//\r
// wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
- // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
+ // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.\r
//\r
if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
- !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)\r
+ !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)\r
) {\r
//\r
// Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
//\r
Rsa = RsaNew ();\r
ASSERT (Rsa != NULL);\r
- // \r
+ //\r
// Set RSA Key Components.\r
// NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
//\r
// Verify the signature.\r
//\r
Status = RsaPkcs1Verify (\r
- Rsa, \r
- Digest, \r
- SHA256_DIGEST_SIZE, \r
- CertBlock->Signature, \r
+ Rsa,\r
+ Digest,\r
+ SHA256_DIGEST_SIZE,\r
+ CertBlock->Signature,\r
EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
);\r
\r
}\r
}\r
\r
-\r
/**\r
Update platform mode.\r
\r
VARIABLE_POINTER_TRACK Variable;\r
UINT32 VarAttr;\r
UINT8 SecureBootMode;\r
+ UINT8 SecureBootEnable;\r
+ UINTN VariableDataSize;\r
\r
Status = FindVariable (\r
- EFI_SETUP_MODE_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_SETUP_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
return Status;\r
}\r
\r
+ if (AtRuntime ()) {\r
+ //\r
+ // SecureBoot Variable indicates whether the platform firmware is operating\r
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
+ // Variable in runtime.\r
+ //\r
+ return Status;\r
+ }\r
+\r
//\r
// Check "SecureBoot" variable's existence.\r
// If it doesn't exist, firmware has no capability to perform driver signing verification,\r
// then set "SecureBoot" to 0.\r
//\r
Status = FindVariable (\r
- EFI_SECURE_BOOT_MODE_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &Variable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_SECURE_BOOT_MODE_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
//\r
// If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
}\r
\r
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
- return UpdateVariable (\r
+ Status = UpdateVariable (\r
EFI_SECURE_BOOT_MODE_NAME,\r
&gEfiGlobalVariableGuid,\r
&SecureBootMode,\r
&Variable,\r
NULL\r
);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r
+ //\r
+ Status = FindVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &Variable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
+ );\r
+\r
+ if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r
+ //\r
+ // Create the "SecureBootEnable" variable as secure boot is enabled.\r
+ //\r
+ SecureBootEnable = SECURE_BOOT_ENABLE;\r
+ VariableDataSize = sizeof (SecureBootEnable);\r
+ } else {\r
+ //\r
+ // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r
+ // variable is not in secure boot state.\r
+ //\r
+ if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ SecureBootEnable = SECURE_BOOT_DISABLE;\r
+ VariableDataSize = 0;\r
+ }\r
+\r
+ Status = UpdateVariable (\r
+ EFI_SECURE_BOOT_ENABLE_NAME,\r
+ &gEfiSecureBootEnableDisableGuid,\r
+ &SecureBootEnable,\r
+ VariableDataSize,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+ 0,\r
+ 0,\r
+ &Variable,\r
+ NULL\r
+ );\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.\r
+\r
+ @param[in] VariableName Name of Variable to be check.\r
+ @param[in] VendorGuid Variable vendor GUID.\r
+ @param[in] Data Point to the variable data to be checked.\r
+ @param[in] DataSize Size of Data.\r
+\r
+ @return EFI_INVALID_PARAMETER Invalid signature list format.\r
+ @return EFI_SUCCESS Passed signature list format check successfully.\r
+ \r
+**/\r
+EFI_STATUS\r
+CheckSignatureListFormat(\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN VOID *Data,\r
+ IN UINTN DataSize\r
+ )\r
+{\r
+ EFI_SIGNATURE_LIST *SigList;\r
+ UINTN SigDataSize;\r
+ UINT32 Index;\r
+ UINT32 SigCount;\r
+ BOOLEAN IsPk;\r
+\r
+ if (DataSize == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);\r
+\r
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
+ IsPk = TRUE;\r
+ } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
+ IsPk = FALSE;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ SigCount = 0;\r
+ SigList = (EFI_SIGNATURE_LIST *) Data;\r
+ SigDataSize = DataSize;\r
+\r
+ //\r
+ // Walk throuth the input signature list and check the data format.\r
+ // If any signature is incorrectly formed, the whole check will fail.\r
+ //\r
+ while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {\r
+ for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {\r
+ if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {\r
+ //\r
+ // The value of SignatureSize should always be 16 (size of SignatureOwner \r
+ // component) add the data length according to signature type.\r
+ //\r
+ if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) && \r
+ (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&\r
+ SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {\r
+ //\r
+ // Undefined signature type.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;\r
+ \r
+ SigDataSize -= SigList->SignatureListSize;\r
+ SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
+ }\r
+\r
+ if (((UINTN) SigList - (UINTN) Data) != DataSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IsPk && SigCount > 1) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
@param[in] IsPk Indicate whether it is to process pk.\r
\r
@return EFI_INVALID_PARAMETER Invalid parameter.\r
- @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation. \r
- check carried out by the firmware. \r
+ @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.\r
+ check carried out by the firmware.\r
@return EFI_SUCCESS Variable passed validation successfully.\r
\r
**/\r
EFI_VARIABLE_AUTHENTICATION *CertData;\r
BOOLEAN TimeBase;\r
BOOLEAN Del;\r
+ UINT8 *Payload;\r
+ UINTN PayloadSize;\r
+ UINT64 MonotonicCount;\r
+ EFI_TIME *TimeStamp;\r
\r
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (mPlatformMode == USER_MODE) {\r
+ if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
\r
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
//\r
// Verify against X509 Cert PK.\r
//\r
Del = FALSE;\r
- Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);\r
+ Status = VerifyTimeBasedPayload (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ Variable,\r
+ Attributes,\r
+ AuthVarTypePk,\r
+ &Del\r
+ );\r
if (!EFI_ERROR (Status)) {\r
//\r
// If delete PK in user mode, need change to setup mode.\r
// Get platform key from variable.\r
//\r
Status = FindVariable (\r
- EFI_PLATFORM_KEY_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &PkVariable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_PLATFORM_KEY_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &PkVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
ASSERT_EFI_ERROR (Status);\r
- \r
+\r
OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
if (!EFI_ERROR (Status)) {\r
+ Status = CheckSignatureListFormat(\r
+ VariableName,\r
+ VendorGuid,\r
+ (UINT8*)Data + AUTHINFO_SIZE,\r
+ DataSize - AUTHINFO_SIZE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
Status = UpdateVariable (\r
- VariableName, \r
- VendorGuid, \r
- (UINT8*)Data + AUTHINFO_SIZE, \r
- DataSize - AUTHINFO_SIZE, \r
- Attributes, \r
- 0, \r
- CertData->MonotonicCount, \r
+ VariableName,\r
+ VendorGuid,\r
+ (UINT8*)Data + AUTHINFO_SIZE,\r
+ DataSize - AUTHINFO_SIZE,\r
+ Attributes,\r
+ 0,\r
+ CertData->MonotonicCount,\r
Variable,\r
NULL\r
);\r
- \r
+\r
if (!EFI_ERROR (Status)) {\r
//\r
// If delete PK in user mode, need change to setup mode.\r
}\r
}\r
} else {\r
- Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
//\r
- // If enroll PK in setup mode, need change to user mode.\r
+ // Process PK or KEK in Setup mode or Custom Secure Boot mode.\r
//\r
- if ((DataSize != 0) && IsPk) {\r
- Status = UpdatePlatformMode (USER_MODE);\r
+ if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Time-based Authentication descriptor.\r
+ //\r
+ MonotonicCount = 0;\r
+ TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;\r
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
+ } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Counter-based Authentication descriptor.\r
+ //\r
+ MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
+ TimeStamp = NULL;\r
+ Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
+ PayloadSize = DataSize - AUTHINFO_SIZE;\r
+ } else {\r
+ //\r
+ // No Authentication descriptor.\r
+ //\r
+ MonotonicCount = 0;\r
+ TimeStamp = NULL;\r
+ Payload = Data;\r
+ PayloadSize = DataSize;\r
+ }\r
+\r
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
+\r
+ Status = UpdateVariable (\r
+ VariableName,\r
+ VendorGuid,\r
+ Payload,\r
+ PayloadSize,\r
+ Attributes,\r
+ 0,\r
+ MonotonicCount,\r
+ Variable,\r
+ TimeStamp\r
+ );\r
+\r
+ if (IsPk) {\r
+ if (PayloadSize != 0) {\r
+ //\r
+ // If enroll PK in setup mode, need change to user mode.\r
+ //\r
+ Status = UpdatePlatformMode (USER_MODE);\r
+ } else {\r
+ //\r
+ // If delete PK in custom mode, need change to setup mode.\r
+ //\r
+ UpdatePlatformMode (SETUP_MODE);\r
+ }\r
+ } \r
}\r
\r
return Status;\r
@param[in] Attributes Attribute value of the variable.\r
\r
@return EFI_INVALID_PARAMETER Invalid parameter.\r
- @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation \r
- check carried out by the firmware. \r
+ @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
+ check carried out by the firmware.\r
@return EFI_SUCCESS Variable pass validation successfully.\r
\r
**/\r
BOOLEAN IsFound;\r
UINT32 Index;\r
UINT32 KekDataSize;\r
+ UINT8 *Payload;\r
+ UINTN PayloadSize;\r
+ UINT64 MonotonicCount;\r
+ EFI_TIME *TimeStamp;\r
+\r
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+ //\r
+ // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+ //\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- if (mPlatformMode == USER_MODE) {\r
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+ Status = EFI_SUCCESS;\r
+ if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
+ if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) &&\r
+ ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)){\r
//\r
- // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
+ // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or\r
+ // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute.\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
- CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
- if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
+ if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
//\r
- // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+ // Time-based, verify against X509 Cert KEK.\r
//\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- //\r
- // Get KEK database from variable.\r
- //\r
- Status = FindVariable (\r
- EFI_KEY_EXCHANGE_KEY_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &KekVariable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ return VerifyTimeBasedPayload (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ Variable,\r
+ Attributes,\r
+ AuthVarTypeKek,\r
+ NULL\r
);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- KekDataSize = KekVariable.CurrPtr->DataSize;\r
- KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
-\r
- //\r
- // Enumerate all Kek items in this list to verify the variable certificate data.\r
- // If anyone is authenticated successfully, it means the variable is correct!\r
- //\r
- IsFound = FALSE;\r
- while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
- if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
- KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
- for (Index = 0; Index < KekCount; Index++) {\r
- if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
- IsFound = TRUE;\r
- break;\r
- }\r
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
- }\r
+ } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Counter-based, verify against RSA2048 Cert KEK.\r
+ //\r
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+ if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
+ //\r
+ // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+ //\r
+ return EFI_SECURITY_VIOLATION;\r
}\r
- KekDataSize -= KekList->SignatureListSize;\r
- KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
- }\r
- \r
- if (!IsFound) {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-\r
- Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
- if (!EFI_ERROR (Status)) {\r
- Status = UpdateVariable (\r
- VariableName, \r
- VendorGuid, \r
- (UINT8*)Data + AUTHINFO_SIZE, \r
- DataSize - AUTHINFO_SIZE, \r
- Attributes, \r
- 0, \r
- CertData->MonotonicCount, \r
- Variable,\r
- NULL\r
+ //\r
+ // Get KEK database from variable.\r
+ //\r
+ Status = FindVariable (\r
+ EFI_KEY_EXCHANGE_KEY_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &KekVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ KekDataSize = KekVariable.CurrPtr->DataSize;\r
+ KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
+\r
+ //\r
+ // Enumerate all Kek items in this list to verify the variable certificate data.\r
+ // If anyone is authenticated successfully, it means the variable is correct!\r
+ //\r
+ IsFound = FALSE;\r
+ while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
+ if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
+ KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
+ KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
+ for (Index = 0; Index < KekCount; Index++) {\r
+ if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+ IsFound = TRUE;\r
+ break;\r
+ }\r
+ KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
+ }\r
+ }\r
+ KekDataSize -= KekList->SignatureListSize;\r
+ KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
+ }\r
+\r
+ if (!IsFound) {\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\r
+\r
+ Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = UpdateVariable (\r
+ VariableName,\r
+ VendorGuid,\r
+ (UINT8*)Data + AUTHINFO_SIZE,\r
+ DataSize - AUTHINFO_SIZE,\r
+ Attributes,\r
+ 0,\r
+ CertData->MonotonicCount,\r
+ Variable,\r
+ NULL\r
+ );\r
+ }\r
}\r
} else {\r
//\r
- // If in setup mode, no authentication needed.\r
+ // If in setup mode or custom secure boot mode, no authentication needed.\r
//\r
+ if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Time-based Authentication descriptor.\r
+ //\r
+ MonotonicCount = 0;\r
+ TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;\r
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
+ } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ //\r
+ // Counter-based Authentication descriptor.\r
+ //\r
+ MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
+ TimeStamp = NULL;\r
+ Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
+ PayloadSize = DataSize - AUTHINFO_SIZE;\r
+ } else {\r
+ //\r
+ // No Authentication descriptor.\r
+ //\r
+ MonotonicCount = 0;\r
+ TimeStamp = NULL;\r
+ Payload = Data;\r
+ PayloadSize = DataSize;\r
+ }\r
+\r
Status = UpdateVariable (\r
- VariableName, \r
- VendorGuid, \r
- Data, \r
- DataSize, \r
- Attributes, \r
- 0, \r
- 0, \r
+ VariableName,\r
+ VendorGuid,\r
+ Payload,\r
+ PayloadSize,\r
+ Attributes,\r
+ 0,\r
+ MonotonicCount,\r
Variable,\r
- NULL\r
+ TimeStamp\r
);\r
}\r
\r
@return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with\r
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
@return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
- set, but the AuthInfo does NOT pass the validation \r
- check carried out by the firmware. \r
+ set, but the AuthInfo does NOT pass the validation\r
+ check carried out by the firmware.\r
@return EFI_SUCCESS Variable is not write-protected or pass validation successfully.\r
\r
**/\r
UINT32 KeyIndex;\r
UINT64 MonotonicCount;\r
\r
- KeyIndex = 0; \r
+ KeyIndex = 0;\r
CertData = NULL;\r
CertBlock = NULL;\r
PubKey = NULL;\r
IsDeletion = FALSE;\r
\r
+ if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {\r
+ //\r
+ // This variable is protected, only physical present user could modify its value.\r
+ //\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\r
+ \r
//\r
// Process Time-based Authenticated variable.\r
//\r
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
- return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);\r
+ return VerifyTimeBasedPayload (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ Variable,\r
+ Attributes,\r
+ AuthVarTypePriv,\r
+ NULL\r
+ );\r
}\r
- \r
+\r
//\r
// Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
//\r
//\r
return EFI_SECURITY_VIOLATION;\r
}\r
- } \r
+ }\r
//\r
// Verify the certificate in Data payload.\r
//\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- \r
+\r
//\r
// Now, the signature has been verified!\r
//\r
return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
}\r
\r
+/**\r
+ Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA\r
+ will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA\r
+ will be ignored.\r
+\r
+ @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.\r
+ @param[in] DataSize Size of Data buffer.\r
+ @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.\r
+ @param[in] NewDataSize Size of NewData buffer.\r
+\r
+ @return Size of the merged buffer.\r
+\r
+**/\r
+UINTN\r
+AppendSignatureList (\r
+ IN OUT VOID *Data,\r
+ IN UINTN DataSize,\r
+ IN VOID *NewData,\r
+ IN UINTN NewDataSize\r
+ )\r
+{\r
+ EFI_SIGNATURE_LIST *CertList;\r
+ EFI_SIGNATURE_DATA *Cert;\r
+ UINTN CertCount;\r
+ EFI_SIGNATURE_LIST *NewCertList;\r
+ EFI_SIGNATURE_DATA *NewCert;\r
+ UINTN NewCertCount;\r
+ UINTN Index;\r
+ UINTN Index2;\r
+ UINTN Size;\r
+ UINT8 *Tail;\r
+ UINTN CopiedCount;\r
+ UINTN SignatureListSize;\r
+ BOOLEAN IsNewCert;\r
+\r
+ Tail = (UINT8 *) Data + DataSize;\r
+\r
+ NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r
+ while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {\r
+ NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
+ NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r
+\r
+ CopiedCount = 0;\r
+ for (Index = 0; Index < NewCertCount; Index++) {\r
+ IsNewCert = TRUE;\r
+\r
+ Size = DataSize;\r
+ CertList = (EFI_SIGNATURE_LIST *) Data;\r
+ while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r
+ if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r
+ (CertList->SignatureSize == NewCertList->SignatureSize)) {\r
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+ for (Index2 = 0; Index2 < CertCount; Index2++) {\r
+ //\r
+ // Iterate each Signature Data in this Signature List.\r
+ //\r
+ if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r
+ IsNewCert = FALSE;\r
+ break;\r
+ }\r
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+ }\r
+ }\r
+\r
+ if (!IsNewCert) {\r
+ break;\r
+ }\r
+ Size -= CertList->SignatureListSize;\r
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+ }\r
+\r
+ if (IsNewCert) {\r
+ //\r
+ // New EFI_SIGNATURE_DATA, append it.\r
+ //\r
+ if (CopiedCount == 0) {\r
+ //\r
+ // Copy EFI_SIGNATURE_LIST header for only once.\r
+ //\r
+ CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
+ Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
+ }\r
+\r
+ CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
+ Tail += NewCertList->SignatureSize;\r
+ CopiedCount++;\r
+ }\r
+\r
+ NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
+ }\r
+\r
+ //\r
+ // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.\r
+ //\r
+ if (CopiedCount != 0) {\r
+ SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r
+ CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r
+ CertList->SignatureListSize = (UINT32) SignatureListSize;\r
+ }\r
+\r
+ NewDataSize -= NewCertList->SignatureListSize;\r
+ NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r
+ }\r
+\r
+ return (Tail - (UINT8 *) Data);\r
+}\r
+\r
/**\r
Compare two EFI_TIME data.\r
\r
return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
} else if (FirstTime->Minute != SecondTime->Minute) {\r
return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
- } \r
+ }\r
\r
return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
}\r
\r
+/**\r
+ Find matching signer's certificates for common authenticated variable\r
+ by corresponding VariableName and VendorGuid from "certdb".\r
+\r
+ The data format of "certdb":\r
+ //\r
+ // UINT32 CertDbListSize;\r
+ // /// AUTH_CERT_DB_DATA Certs1[];\r
+ // /// AUTH_CERT_DB_DATA Certs2[];\r
+ // /// ...\r
+ // /// AUTH_CERT_DB_DATA Certsn[];\r
+ //\r
+\r
+ @param[in] VariableName Name of authenticated Variable.\r
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
+ @param[in] Data Pointer to variable "certdb".\r
+ @param[in] DataSize Size of variable "certdb".\r
+ @param[out] CertOffset Offset of matching CertData, from starting of Data.\r
+ @param[out] CertDataSize Length of CertData in bytes.\r
+ @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from\r
+ starting of Data.\r
+ @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+ @retval EFI_NOT_FOUND Fail to find matching certs.\r
+ @retval EFI_SUCCESS Find matching certs and output parameters.\r
+\r
+**/\r
+EFI_STATUS\r
+FindCertsFromDb (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT8 *Data,\r
+ IN UINTN DataSize,\r
+ OUT UINT32 *CertOffset, OPTIONAL\r
+ OUT UINT32 *CertDataSize, OPTIONAL\r
+ OUT UINT32 *CertNodeOffset,OPTIONAL\r
+ OUT UINT32 *CertNodeSize OPTIONAL\r
+ )\r
+{\r
+ UINT32 Offset;\r
+ AUTH_CERT_DB_DATA *Ptr;\r
+ UINT32 CertSize;\r
+ UINT32 NameSize;\r
+ UINT32 NodeSize;\r
+ UINT32 CertDbListSize;\r
+\r
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check whether DataSize matches recorded CertDbListSize.\r
+ //\r
+ if (DataSize < sizeof (UINT32)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);\r
+\r
+ if (CertDbListSize != (UINT32) DataSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset = sizeof (UINT32);\r
+\r
+ //\r
+ // Get corresponding certificates by VendorGuid and VariableName.\r
+ //\r
+ while (Offset < (UINT32) DataSize) {\r
+ Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r
+ //\r
+ // Check whether VendorGuid matches.\r
+ //\r
+ if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {\r
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
+ NameSize = ReadUnaligned32 (&Ptr->NameSize);\r
+ CertSize = ReadUnaligned32 (&Ptr->CertDataSize);\r
+\r
+ if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +\r
+ sizeof (CHAR16) * NameSize) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;\r
+ //\r
+ // Check whether VariableName matches.\r
+ //\r
+ if ((NameSize == StrLen (VariableName)) && \r
+ (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {\r
+ Offset = Offset + NameSize * sizeof (CHAR16);\r
+\r
+ if (CertOffset != NULL) {\r
+ *CertOffset = Offset;\r
+ }\r
+\r
+ if (CertDataSize != NULL) {\r
+ *CertDataSize = CertSize; \r
+ }\r
+\r
+ if (CertNodeOffset != NULL) {\r
+ *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);\r
+ }\r
+\r
+ if (CertNodeSize != NULL) {\r
+ *CertNodeSize = NodeSize;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;\r
+ }\r
+ } else {\r
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
+ Offset = Offset + NodeSize;\r
+ }\r
+ }\r
+\r
+ return EFI_NOT_FOUND; \r
+}\r
+\r
+/**\r
+ Retrieve signer's certificates for common authenticated variable\r
+ by corresponding VariableName and VendorGuid from "certdb".\r
+\r
+ @param[in] VariableName Name of authenticated Variable.\r
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
+ @param[out] CertData Pointer to signer's certificates.\r
+ @param[out] CertDataSize Length of CertData in bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+ @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.\r
+ @retval EFI_SUCCESS Get signer's certificates successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetCertsFromDb (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ OUT UINT8 **CertData,\r
+ OUT UINT32 *CertDataSize\r
+ )\r
+{\r
+ VARIABLE_POINTER_TRACK CertDbVariable;\r
+ EFI_STATUS Status;\r
+ UINT8 *Data;\r
+ UINTN DataSize;\r
+ UINT32 CertOffset;\r
+\r
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Get variable "certdb".\r
+ //\r
+ Status = FindVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ &CertDbVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
+ Data = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
+ if ((DataSize == 0) || (Data == NULL)) {\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Status = FindCertsFromDb (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ &CertOffset,\r
+ CertDataSize,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *CertData = Data + CertOffset;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Delete matching signer's certificates when deleting common authenticated\r
+ variable by corresponding VariableName and VendorGuid from "certdb".\r
+\r
+ @param[in] VariableName Name of authenticated Variable.\r
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
+\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+ @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.\r
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
+ @retval EFI_SUCCESS The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DeleteCertsFromDb (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid\r
+ )\r
+{\r
+ VARIABLE_POINTER_TRACK CertDbVariable;\r
+ EFI_STATUS Status;\r
+ UINT8 *Data;\r
+ UINTN DataSize;\r
+ UINT32 VarAttr;\r
+ UINT32 CertNodeOffset;\r
+ UINT32 CertNodeSize;\r
+ UINT8 *NewCertDb;\r
+ UINT32 NewCertDbSize;\r
+\r
+ if ((VariableName == NULL) || (VendorGuid == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Get variable "certdb".\r
+ //\r
+ Status = FindVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ &CertDbVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
+ Data = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
+ if ((DataSize == 0) || (Data == NULL)) {\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (DataSize == sizeof (UINT32)) {\r
+ //\r
+ // There is no certs in certdb.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Get corresponding cert node from certdb.\r
+ //\r
+ Status = FindCertsFromDb (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ NULL,\r
+ NULL,\r
+ &CertNodeOffset,\r
+ &CertNodeSize\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (DataSize < (CertNodeOffset + CertNodeSize)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Construct new data content of variable "certdb".\r
+ //\r
+ NewCertDbSize = (UINT32) DataSize - CertNodeSize;\r
+ NewCertDb = AllocateZeroPool (NewCertDbSize);\r
+ if (NewCertDb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the DB entries before deleting node.\r
+ //\r
+ CopyMem (NewCertDb, Data, CertNodeOffset);\r
+ //\r
+ // Update CertDbListSize.\r
+ //\r
+ CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
+ //\r
+ // Copy the DB entries after deleting node.\r
+ //\r
+ if (DataSize > (CertNodeOffset + CertNodeSize)) {\r
+ CopyMem (\r
+ NewCertDb + CertNodeOffset,\r
+ Data + CertNodeOffset + CertNodeSize,\r
+ DataSize - CertNodeOffset - CertNodeSize\r
+ );\r
+ }\r
+\r
+ //\r
+ // Set "certdb".\r
+ // \r
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; \r
+ Status = UpdateVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ NewCertDb,\r
+ NewCertDbSize,\r
+ VarAttr,\r
+ 0,\r
+ 0,\r
+ &CertDbVariable,\r
+ NULL\r
+ );\r
+\r
+ FreePool (NewCertDb);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Insert signer's certificates for common authenticated variable with VariableName\r
+ and VendorGuid in AUTH_CERT_DB_DATA to "certdb".\r
+\r
+ @param[in] VariableName Name of authenticated Variable.\r
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.\r
+ @param[in] CertData Pointer to signer's certificates.\r
+ @param[in] CertDataSize Length of CertData in bytes.\r
+\r
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+ @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName\r
+ and VendorGuid already exists.\r
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.\r
+ @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"\r
+\r
+**/\r
+EFI_STATUS\r
+InsertCertsToDb (\r
+ IN CHAR16 *VariableName,\r
+ IN EFI_GUID *VendorGuid,\r
+ IN UINT8 *CertData,\r
+ IN UINTN CertDataSize\r
+ )\r
+{\r
+ VARIABLE_POINTER_TRACK CertDbVariable;\r
+ EFI_STATUS Status;\r
+ UINT8 *Data;\r
+ UINTN DataSize;\r
+ UINT32 VarAttr;\r
+ UINT8 *NewCertDb;\r
+ UINT32 NewCertDbSize;\r
+ UINT32 CertNodeSize;\r
+ UINT32 NameSize;\r
+ AUTH_CERT_DB_DATA *Ptr;\r
+\r
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ \r
+ //\r
+ // Get variable "certdb".\r
+ //\r
+ Status = FindVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ &CertDbVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
+ ); \r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
+ Data = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
+ if ((DataSize == 0) || (Data == NULL)) {\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Find whether matching cert node already exists in "certdb".\r
+ // If yes return error.\r
+ //\r
+ Status = FindCertsFromDb (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ ASSERT (FALSE);\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Construct new data content of variable "certdb".\r
+ //\r
+ NameSize = (UINT32) StrLen (VariableName);\r
+ CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16); \r
+ NewCertDbSize = (UINT32) DataSize + CertNodeSize; \r
+ NewCertDb = AllocateZeroPool (NewCertDbSize);\r
+ if (NewCertDb == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Copy the DB entries before deleting node.\r
+ //\r
+ CopyMem (NewCertDb, Data, DataSize);\r
+ //\r
+ // Update CertDbListSize.\r
+ //\r
+ CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
+ //\r
+ // Construct new cert node.\r
+ //\r
+ Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);\r
+ CopyGuid (&Ptr->VendorGuid, VendorGuid);\r
+ CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));\r
+ CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));\r
+ CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));\r
+ \r
+ CopyMem (\r
+ (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),\r
+ VariableName,\r
+ NameSize * sizeof (CHAR16)\r
+ );\r
+\r
+ CopyMem (\r
+ (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),\r
+ CertData,\r
+ CertDataSize\r
+ );\r
+ \r
+ //\r
+ // Set "certdb".\r
+ // \r
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; \r
+ Status = UpdateVariable (\r
+ EFI_CERT_DB_NAME,\r
+ &gEfiCertDbGuid,\r
+ NewCertDb,\r
+ NewCertDbSize,\r
+ VarAttr,\r
+ 0,\r
+ 0,\r
+ &CertDbVariable,\r
+ NULL\r
+ );\r
+\r
+ FreePool (NewCertDb);\r
+ return Status;\r
+}\r
+\r
/**\r
Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
\r
data, this value contains the required size.\r
@param[in] Variable The variable information which is used to keep track of variable usage.\r
@param[in] Attributes Attribute value of the variable.\r
- @param[in] Pk Verify against PK or KEK database.\r
+ @param[in] AuthVarType Verify against PK or KEK database or private database.\r
@param[out] VarDel Delete the variable or not.\r
\r
@retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation \r
- check carried out by the firmware. \r
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
+ check carried out by the firmware.\r
@retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack\r
of resources.\r
@retval EFI_SUCCESS Variable pass validation successfully.\r
IN UINTN DataSize,\r
IN VARIABLE_POINTER_TRACK *Variable,\r
IN UINT32 Attributes,\r
- IN BOOLEAN Pk,\r
+ IN AUTHVAR_TYPE AuthVarType,\r
OUT BOOLEAN *VarDel\r
)\r
{\r
UINT8 *RootCert;\r
UINT8 *SigData;\r
- UINT8 *PayLoadPtr;\r
+ UINT8 *PayloadPtr;\r
UINTN RootCertSize;\r
UINTN Index;\r
- UINTN CertCount; \r
- UINTN PayLoadSize; \r
+ UINTN CertCount;\r
+ UINTN PayloadSize;\r
UINT32 Attr;\r
UINT32 SigDataSize;\r
UINT32 KekDataSize;\r
- BOOLEAN Result;\r
BOOLEAN VerifyStatus;\r
EFI_STATUS Status;\r
EFI_SIGNATURE_LIST *CertList;\r
UINT8 *NewData;\r
UINTN NewDataSize;\r
VARIABLE_POINTER_TRACK PkVariable;\r
+ UINT8 *Buffer;\r
+ UINTN Length;\r
+ UINT8 *SignerCerts;\r
+ UINT8 *WrapSigData;\r
+ UINTN CertStackSize;\r
+ UINT8 *CertsInCertDb;\r
+ UINT32 CertsSizeinDb;\r
\r
-\r
- Result = FALSE;\r
VerifyStatus = FALSE;\r
CertData = NULL;\r
NewData = NULL;\r
Attr = Attributes;\r
+ WrapSigData = NULL;\r
+ SignerCerts = NULL;\r
+ RootCert = NULL;\r
\r
//\r
- // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is \r
+ // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
// set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
- // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new \r
- // variable value and DataSize shall reflect the combined size of the descriptor and the new \r
- // variable value. The authentication descriptor is not part of the variable data and is not \r
+ // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r
+ // variable value and DataSize shall reflect the combined size of the descriptor and the new\r
+ // variable value. The authentication descriptor is not part of the variable data and is not\r
// returned by subsequent calls to GetVariable().\r
//\r
CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
- \r
+\r
+ //\r
+ // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r
+ // TimeStamp value are set to zero.\r
+ //\r
+ if ((CertData->TimeStamp.Pad1 != 0) ||\r
+ (CertData->TimeStamp.Nanosecond != 0) ||\r
+ (CertData->TimeStamp.TimeZone != 0) ||\r
+ (CertData->TimeStamp.Daylight != 0) ||\r
+ (CertData->TimeStamp.Pad2 != 0)) {\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\r
+\r
if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
//\r
// Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
//\r
if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
- !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)\r
- ) {\r
+ !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r
//\r
// Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
//\r
// Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
// AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
//\r
- SigData = (UINT8*) ((UINTN)Data + (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData));\r
- SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(UINTN)(((WIN_CERTIFICATE_UEFI_GUID *) 0)->CertData);\r
- \r
+ SigData = CertData->AuthInfo.CertData;\r
+ SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
+\r
//\r
// Find out the new data payload which follows Pkcs7 SignedData directly.\r
//\r
- PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);\r
- PayLoadSize = DataSize - (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData) - (UINTN) SigDataSize;\r
-\r
+ PayloadPtr = SigData + SigDataSize;\r
+ PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
\r
//\r
// Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
//\r
- NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
- sizeof (EFI_GUID) + StrSize (VariableName);\r
- NewData = (UINT8 *) AllocateZeroPool (NewDataSize);\r
+ NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
+ sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
+ NewData = mSerializationRuntimeBuffer;\r
\r
- if (NewData == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
+ Buffer = NewData;\r
+ Length = StrLen (VariableName) * sizeof (CHAR16);\r
+ CopyMem (Buffer, VariableName, Length);\r
+ Buffer += Length;\r
\r
- CopyMem (NewData, VariableName, StrSize (VariableName));\r
+ Length = sizeof (EFI_GUID);\r
+ CopyMem (Buffer, VendorGuid, Length);\r
+ Buffer += Length;\r
\r
- CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID));\r
+ Length = sizeof (UINT32);\r
+ CopyMem (Buffer, &Attr, Length);\r
+ Buffer += Length;\r
\r
- CopyMem (\r
- NewData + StrSize (VariableName) + sizeof (EFI_GUID),\r
- &Attr,\r
- sizeof (UINT32)\r
- );\r
+ Length = sizeof (EFI_TIME);\r
+ CopyMem (Buffer, &CertData->TimeStamp, Length);\r
+ Buffer += Length;\r
\r
- CopyMem (\r
- NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32),\r
- &CertData->TimeStamp,\r
- sizeof (EFI_TIME)\r
- );\r
-\r
- CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize);\r
+ CopyMem (Buffer, PayloadPtr, PayloadSize);\r
\r
-\r
- if (Pk) {\r
+ if (AuthVarType == AuthVarTypePk) {\r
//\r
// Get platform key from variable.\r
//\r
Status = FindVariable (\r
- EFI_PLATFORM_KEY_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &PkVariable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_PLATFORM_KEY_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &PkVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
NewDataSize\r
);\r
\r
- } else {\r
- \r
+ } else if (AuthVarType == AuthVarTypeKek) {\r
+\r
//\r
// Get KEK database from variable.\r
//\r
Status = FindVariable (\r
- EFI_KEY_EXCHANGE_KEY_NAME, \r
- &gEfiGlobalVariableGuid, \r
- &KekVariable, \r
- &mVariableModuleGlobal->VariableGlobal\r
+ EFI_KEY_EXCHANGE_KEY_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ &KekVariable,\r
+ &mVariableModuleGlobal->VariableGlobal,\r
+ FALSE\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
\r
//\r
// Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
- // \r
+ //\r
KekDataSize = KekVariable.CurrPtr->DataSize;\r
CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
//\r
RootCert = Cert->SignatureData;\r
RootCertSize = CertList->SignatureSize;\r
- \r
+\r
//\r
// Verify Pkcs7 SignedData via Pkcs7Verify library.\r
//\r
KekDataSize -= CertList->SignatureListSize;\r
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
}\r
+ } else if (AuthVarType == AuthVarTypePriv) {\r
+\r
+ //\r
+ // Process common authenticated variable except PK/KEK/DB/DBX.\r
+ // Get signer's certificates from SignedData.\r
+ //\r
+ VerifyStatus = Pkcs7GetSigners (\r
+ SigData,\r
+ SigDataSize,\r
+ &SignerCerts,\r
+ &CertStackSize,\r
+ &RootCert,\r
+ &RootCertSize\r
+ );\r
+ if (!VerifyStatus) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Get previously stored signer's certificates from certdb for existing\r
+ // variable. Check whether they are identical with signer's certificates\r
+ // in SignedData. If not, return error immediately.\r
+ //\r
+ if ((Variable->CurrPtr != NULL)) {\r
+ VerifyStatus = FALSE;\r
+\r
+ Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ \r
+ if ((CertStackSize != CertsSizeinDb) ||\r
+ (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ VerifyStatus = Pkcs7Verify (\r
+ SigData,\r
+ SigDataSize,\r
+ RootCert,\r
+ RootCertSize,\r
+ NewData,\r
+ NewDataSize\r
+ );\r
+ if (!VerifyStatus) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Delete signer's certificates when delete the common authenticated variable.\r
+ //\r
+ if ((PayloadSize == 0) && (Variable->CurrPtr != NULL)) {\r
+ Status = DeleteCertsFromDb (VariableName, VendorGuid);\r
+ if (EFI_ERROR (Status)) {\r
+ VerifyStatus = FALSE;\r
+ goto Exit;\r
+ }\r
+ } else if (Variable->CurrPtr == NULL) {\r
+ //\r
+ // Insert signer's certificates when adding a new common authenticated variable.\r
+ //\r
+ Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);\r
+ if (EFI_ERROR (Status)) {\r
+ VerifyStatus = FALSE;\r
+ goto Exit;\r
+ }\r
+ }\r
+ } else {\r
+ return EFI_SECURITY_VIOLATION;\r
}\r
\r
Exit:\r
\r
- FreePool (NewData);\r
+ if (AuthVarType == AuthVarTypePriv) {\r
+ Pkcs7FreeSigners (RootCert);\r
+ Pkcs7FreeSigners (SignerCerts);\r
+ }\r
\r
if (!VerifyStatus) {\r
return EFI_SECURITY_VIOLATION;\r
}\r
\r
- if ((PayLoadSize == 0) && (VarDel != NULL)) {\r
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if ((PayloadSize == 0) && (VarDel != NULL)) {\r
*VarDel = TRUE;\r
}\r
- \r
+\r
//\r
// Final step: Update/Append Variable if it pass Pkcs7Verify\r
//\r
- return UpdateVariable (\r
- VariableName, \r
- VendorGuid, \r
- PayLoadPtr, \r
- PayLoadSize, \r
- Attributes, \r
- 0, \r
- 0, \r
- Variable,\r
- &CertData->TimeStamp\r
- );\r
+ return UpdateVariable (\r
+ VariableName,\r
+ VendorGuid,\r
+ PayloadPtr,\r
+ PayloadSize,\r
+ Attributes,\r
+ 0,\r
+ 0,\r
+ Variable,\r
+ &CertData->TimeStamp\r
+ );\r
}\r
+\r