Implement authentication services for the authenticated variable\r
service in UEFI2.2.\r
\r
+ Caution: This module requires additional review when modified.\r
+ This driver will have external input - variable data. It may be input in SMM mode.\r
+ This external input must be validated carefully to avoid security issue like\r
+ buffer overflow, integer overflow.\r
+ Variable attribute should also be checked to avoid authentication bypass.\r
+\r
+ ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
+ variable authentication.\r
+\r
+ VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.\r
+ They will do basic validation for authentication data structure, then call crypto library\r
+ to verify the signature.\r
+\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
///\r
UINT8 mPubKeyStore[MAX_KEYDB_SIZE];\r
UINT32 mPubKeyNumber;\r
+UINT8 mCertDbStore[MAX_CERTDB_SIZE];\r
UINT32 mPlatformMode;\r
EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};\r
//\r
}\r
\r
//\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
+ // Create "SetupMode" varable with BS+RT attribute set.\r
//\r
- Status = FindVariable (\r
+ FindVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ if (PkVariable.CurrPtr == NULL) {\r
+ mPlatformMode = SETUP_MODE;\r
+ } else {\r
+ mPlatformMode = USER_MODE;\r
+ }\r
+ Status = UpdateVariable (\r
EFI_SETUP_MODE_NAME,\r
&gEfiGlobalVariableGuid,\r
+ &mPlatformMode,\r
+ sizeof(UINT8),\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ 0,\r
+ 0,\r
&Variable,\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE\r
+ NULL\r
);\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_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,\r
- sizeof(UINT8),\r
- VarAttr,\r
- 0,\r
- 0,\r
- &Variable,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } else {\r
- mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\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
+ // Create "SignatureSupport" varable with BS+RT attribute set.\r
//\r
- Status = FindVariable (\r
- EFI_SIGNATURE_SUPPORT_NAME,\r
- &gEfiGlobalVariableGuid,\r
- &Variable,\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE\r
- );\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_SIGNATURE_SUPPORT_NAME,\r
- &gEfiGlobalVariableGuid,\r
- mSignatureSupport,\r
- sizeof(mSignatureSupport),\r
- VarAttr,\r
- 0,\r
- 0,\r
- &Variable,\r
- NULL\r
- );\r
+ FindVariable (EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+ Status = UpdateVariable (\r
+ EFI_SIGNATURE_SUPPORT_NAME,\r
+ &gEfiGlobalVariableGuid,\r
+ mSignatureSupport,\r
+ sizeof(mSignatureSupport),\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ 0,\r
+ 0,\r
+ &Variable,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
//\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
- SecureBootEnable = SECURE_BOOT_MODE_DISABLE;\r
+ SecureBootEnable = SECURE_BOOT_DISABLE;\r
FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
if (Variable.CurrPtr != NULL) {\r
SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
//\r
// "SecureBootEnable" not exist, initialize it in USER_MODE.\r
//\r
- SecureBootEnable = SECURE_BOOT_MODE_ENABLE;\r
+ SecureBootEnable = SECURE_BOOT_ENABLE;\r
Status = UpdateVariable (\r
EFI_SECURE_BOOT_ENABLE_NAME,\r
&gEfiSecureBootEnableDisableGuid,\r
}\r
}\r
\r
+ //\r
+ // Create "SecureBoot" varable with BS+RT attribute set.\r
+ //\r
if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
} else {\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
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
0,\r
0,\r
&Variable,\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
+ ListSize = sizeof (UINT32);\r
Status = UpdateVariable (\r
EFI_CERT_DB_NAME,\r
&gEfiCertDbGuid,\r
&Variable,\r
NULL\r
);\r
-\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
} \r
\r
return Status;\r
Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.\r
Follow the steps in UEFI2.2.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\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
return Status;\r
}\r
\r
- mPlatformMode = Mode;\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,\r
- sizeof(UINT8),\r
- VarAttr,\r
- 0,\r
- 0,\r
- &Variable,\r
- NULL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ //\r
+ // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
+ // variable storage reclaim at runtime.\r
+ //\r
+ mPlatformMode = (UINT8) Mode;\r
+ CopyMem (GetVariableDataPtr (Variable.CurrPtr), &mPlatformMode, sizeof(UINT8));\r
\r
if (AtRuntime ()) {\r
//\r
}\r
\r
/**\r
- Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.\r
+ Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx variable.\r
\r
@param[in] VariableName Name of Variable to be check.\r
@param[in] VendorGuid Variable vendor GUID.\r
UINT32 Index;\r
UINT32 SigCount;\r
BOOLEAN IsPk;\r
+ VOID *RsaContext;\r
+ EFI_SIGNATURE_DATA *CertData;\r
+ UINTN CertLen;\r
\r
if (DataSize == 0) {\r
return EFI_SUCCESS;\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
+ } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0) ||\r
+ (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0 || StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))){\r
IsPk = FALSE;\r
} else {\r
return EFI_SUCCESS;\r
SigCount = 0;\r
SigList = (EFI_SIGNATURE_LIST *) Data;\r
SigDataSize = DataSize;\r
+ RsaContext = NULL;\r
\r
//\r
// Walk throuth the input signature list and check the data format.\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
+ //\r
+ // Try to retrieve the RSA public key from the X.509 certificate.\r
+ // If this operation fails, it's not a valid certificate.\r
+ //\r
+ RsaContext = RsaNew ();\r
+ if (RsaContext == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);\r
+ CertLen = SigList->SignatureSize - sizeof (EFI_GUID);\r
+ if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {\r
+ RsaFree (RsaContext);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ RsaFree (RsaContext);\r
+ }\r
+\r
if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
/**\r
Process variable with platform key for verification.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\r
+ This function will check attribute carefully to avoid authentication bypass.\r
+\r
@param[in] VariableName Name of Variable to be found.\r
@param[in] VendorGuid Variable vendor GUID.\r
@param[in] Data Data pointer.\r
)\r
{\r
EFI_STATUS Status;\r
- VARIABLE_POINTER_TRACK PkVariable;\r
- EFI_SIGNATURE_LIST *OldPkList;\r
- EFI_SIGNATURE_DATA *OldPkData;\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
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || \r
+ (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
//\r
- // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+ // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
+ // authenticated variable.\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
-\r
- if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
- //\r
- // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
- //\r
- TimeBase = TRUE;\r
- } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
- //\r
- // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
- //\r
- TimeBase = FALSE;\r
- } else {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (TimeBase) {\r
- //\r
- // Verify against X509 Cert PK.\r
- //\r
- Del = FALSE;\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
- //\r
- if (Del && IsPk) {\r
- Status = UpdatePlatformMode (SETUP_MODE);\r
- }\r
- }\r
- return Status;\r
- } else {\r
- //\r
- // Verify against RSA2048 Cert PK.\r
- //\r
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\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
- //\r
- // Get platform key from variable.\r
- //\r
- Status = FindVariable (\r
- EFI_PLATFORM_KEY_NAME,\r
- &gEfiGlobalVariableGuid,\r
- &PkVariable,\r
- &mVariableModuleGlobal->VariableGlobal,\r
- FALSE\r
- );\r
- ASSERT_EFI_ERROR (Status);\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
- Variable,\r
- NULL\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // If delete PK in user mode, need change to setup mode.\r
- //\r
- if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
- Status = UpdatePlatformMode (SETUP_MODE);\r
- }\r
- }\r
- }\r
- }\r
- } else {\r
- //\r
- // Process PK or KEK in Setup mode or Custom Secure Boot mode.\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
+ Del = FALSE;\r
+ if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {\r
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
+ if (PayloadSize == 0) {\r
+ Del = TRUE;\r
}\r
\r
Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
PayloadSize,\r
Attributes,\r
0,\r
- MonotonicCount,\r
+ 0,\r
Variable,\r
- TimeStamp\r
+ &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
);\r
+ } else if (mPlatformMode == USER_MODE) {\r
+ //\r
+ // Verify against X509 Cert in PK database.\r
+ //\r
+ Status = VerifyTimeBasedPayload (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ Variable,\r
+ Attributes,\r
+ AuthVarTypePk,\r
+ &Del\r
+ );\r
+ } else {\r
+ //\r
+ // Verify against the certificate in data payload.\r
+ //\r
+ Status = VerifyTimeBasedPayload (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ Variable,\r
+ Attributes,\r
+ AuthVarTypePayload,\r
+ &Del\r
+ );\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
+ if (!EFI_ERROR(Status) && IsPk) {\r
+ if (mPlatformMode == SETUP_MODE && !Del) {\r
+ //\r
+ // If enroll PK in setup mode, need change to user mode.\r
+ //\r
+ Status = UpdatePlatformMode (USER_MODE);\r
+ } else if (mPlatformMode == USER_MODE && Del){\r
+ //\r
+ // If delete PK in user mode, need change to setup mode.\r
+ //\r
+ Status = UpdatePlatformMode (SETUP_MODE);\r
+ }\r
}\r
\r
return Status;\r
/**\r
Process variable with key exchange key for verification.\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\r
+ This function will check attribute carefully to avoid authentication bypass.\r
+\r
@param[in] VariableName Name of Variable to be found.\r
@param[in] VendorGuid Variable vendor GUID.\r
@param[in] Data Data pointer.\r
)\r
{\r
EFI_STATUS Status;\r
- VARIABLE_POINTER_TRACK KekVariable;\r
- EFI_SIGNATURE_LIST *KekList;\r
- EFI_SIGNATURE_DATA *KekItem;\r
- UINT32 KekCount;\r
- EFI_VARIABLE_AUTHENTICATION *CertData;\r
- EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\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
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r
+ (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
//\r
- // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+ // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
+ // authenticated variable.\r
//\r
return EFI_INVALID_PARAMETER;\r
}\r
\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 or\r
- // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute.\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
- //\r
- // Time-based, verify against X509 Cert KEK.\r
- //\r
- return VerifyTimeBasedPayload (\r
- VariableName,\r
- VendorGuid,\r
- Data,\r
- DataSize,\r
- Variable,\r
- Attributes,\r
- AuthVarTypeKek,\r
- NULL\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
- //\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
+ //\r
+ // Time-based, verify against X509 Cert KEK.\r
+ //\r
+ return VerifyTimeBasedPayload (\r
+ VariableName,\r
+ VendorGuid,\r
+ Data,\r
+ DataSize,\r
+ Variable,\r
+ Attributes,\r
+ AuthVarTypeKek,\r
+ NULL\r
+ );\r
} else {\r
//\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
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\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
PayloadSize,\r
Attributes,\r
0,\r
- MonotonicCount,\r
+ 0,\r
Variable,\r
- TimeStamp\r
+ &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
);\r
}\r
\r
/**\r
Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
\r
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\r
+ This function will check attribute carefully to avoid authentication bypass.\r
+\r
@param[in] VariableName Name of Variable to be found.\r
@param[in] VendorGuid Variable vendor GUID.\r
\r
// Update public key database variable if need.\r
//\r
KeyIndex = AddPubKeyInStore (PubKey);\r
+ if (KeyIndex == 0) {\r
+ return EFI_SECURITY_VIOLATION;\r
+ }\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
+ NewCertDb = (UINT8*) mCertDbStore;\r
\r
//\r
// Copy the DB entries before deleting node.\r
NULL\r
);\r
\r
- FreePool (NewCertDb);\r
return Status;\r
}\r
\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
+ NewCertDbSize = (UINT32) DataSize + CertNodeSize;\r
+ if (NewCertDbSize > MAX_CERTDB_SIZE) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
+ NewCertDb = (UINT8*) mCertDbStore;\r
\r
//\r
// Copy the DB entries before deleting node.\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
+ Caution: This function may receive untrusted input.\r
+ This function may be invoked in SMM mode, and datasize and data are external input.\r
+ This function will do basic validation, before parse the data.\r
+ This function will parse the authentication carefully to avoid security issues, like\r
+ buffer overflow, integer overflow.\r
+\r
@param[in] VariableName Name of Variable to be found.\r
@param[in] VendorGuid Variable vendor GUID.\r
@param[in] Data Data pointer.\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] AuthVarType Verify against PK or KEK database or private database.\r
+ @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.\r
@param[out] VarDel Delete the variable or not.\r
\r
@retval EFI_INVALID_PARAMETER Invalid parameter.\r
CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
RootCert = Cert->SignatureData;\r
- RootCertSize = CertList->SignatureSize;\r
+ RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
\r
\r
//\r
// Iterate each Signature Data Node within this CertList for a verify\r
//\r
RootCert = Cert->SignatureData;\r
- RootCertSize = CertList->SignatureSize;\r
+ RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
\r
//\r
// Verify Pkcs7 SignedData via Pkcs7Verify library.\r
goto Exit;\r
}\r
}\r
+ } else if (AuthVarType == AuthVarTypePayload) {\r
+ CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;\r
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+ RootCert = Cert->SignatureData;\r
+ RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
+ \r
+ // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
+ //\r
+ VerifyStatus = Pkcs7Verify (\r
+ SigData,\r
+ SigDataSize,\r
+ RootCert,\r
+ RootCertSize,\r
+ NewData,\r
+ NewDataSize\r
+ );\r
} else {\r
return EFI_SECURITY_VIOLATION;\r
}\r