diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /Core/EM/SecurityPkg/AuthenticatedVariable | |
download | zprj-master.tar.xz |
Diffstat (limited to 'Core/EM/SecurityPkg/AuthenticatedVariable')
6 files changed, 3094 insertions, 0 deletions
diff --git a/Core/EM/SecurityPkg/AuthenticatedVariable/Auth2Variable.c b/Core/EM/SecurityPkg/AuthenticatedVariable/Auth2Variable.c new file mode 100644 index 0000000..e979531 --- /dev/null +++ b/Core/EM/SecurityPkg/AuthenticatedVariable/Auth2Variable.c @@ -0,0 +1,869 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/Auth2Variable.c 30 3/09/15 4:31p Alexp $ +// +// $Revision: 30 $ +// +// $Date: 3/09/15 4:31p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/Auth2Variable.c $ +// +// 30 3/09/15 4:31p Alexp +// Compliancy with UEFI spec: +// EFI_VARIABLE_AUTHENTICATION_2.TimeStamp - +// during Append operations the TimeStamp value may be set to '0' +// +// 29 10/08/14 3:16p Alexp +// Introduced global mCustomMode flag passing the status from +// PhysicalUserPresent() +// +// 28 8/15/13 11:27a Alexp +// Link AmyCryptoLib. Replaced locally defined mkLongTime() with generic +// AmiCryptoLib defined os_mktime() +// +// 27 2/08/13 5:15p Alexp +// Optimized the code flow fro Auth2 Variables. +// +// 26 12/07/12 3:48p Alexp +// - Replaced TRACE macro with AVAR_TRACE. Stop debug traces in Virtual +// address mode +// - VerifyVariable2() Fix final check for IsPk and run +// ValidateSignatureList() +// +// 25 12/04/12 6:56p Alexp +// VerifyVariable2() +// IsPk -> skip ValidateSignatureList if *DataSize =0 +// +// 24 11/29/12 3:08p Alexp +// ValidateSelfSigned(): keep *x509_SignCert ptr to non-0 for +// Pkcs7CertValidateGetSignerKeyHash operation +// Will trigger an error in old CryptoDxe.c Pkcs7Verify() +// +// 22 11/16/12 7:11p Alexp +// Fixed ValidateSignatureList() return status for Zero Data or Size +// +// 21 11/16/12 5:09p Alexp +// EIP:104961 UEFI 2.3.1 SCTc test failed in Generic\EfiCompliant case. +// Fix for SelfSigned variables. +// +// 19 9/17/12 4:50p Alexp +// add Time Stamp traces +// +// 18 9/06/12 5:14p Alexp +// ConstructDataParameter() Fix debug messages. +// +// 17 9/04/12 3:35p Alexp +// EIP#99648: SCT will fail when enable Secure Boot in setup menu. +// Fix: Use globally defined buffer to pass calculated Key Hash for +// SelfSigned Variables +// +// 15 8/22/12 6:19p Alexp +// ProcessVarWithPk2() +// Properly implemented the case for PK variable carrying RSA2048 Key. +// Requires CryptoPkg Label 009 or later. +// +// 12 4/26/12 7:29p Alexp +// fix debug trace messages +// +// 11 4/16/12 5:28p Alexp +// Add debug traces in ConstructDataParameter to display serialization +// data +// +// 10 11/30/11 7:58p Alexp +// According to UEFI 2.3.1 Sec 7.2.1 : "db" vars can be validated either +// by KEK key or by PK key. +// The fix adds the check for PK if none of KEKs can validate new "db" +// +// 9 8/19/11 5:06p Alexp +// +// 8 8/18/11 4:54p Alexp +// restored use of global variable mPlatformMode instead of a field in +// AuthVarMaibox +// +// 7 8/16/11 7:18p Alexp +// added Mailbox variable AuthVarMAilbox to syncronize local state between +// DXE and SMM AuthVariable services +// +// 6 7/18/11 10:17a Alexp +// made gEfiGlobalVariableGuid static to prevent linker issues +// +// 5 6/27/11 6:16p Alexp +// code optimization: moved ValidateSignatureList () call in the main +// VerifyVariable1(2) function. +// +// 4 6/24/11 7:04p Alexp +// fixed ValidateSignatureList () logic. Added Certificate RSA2048 to +// supported Signatures +// +// 3 6/24/11 3:23p Alexp +// test PK, KEK, db(x) for valid Signatuer List header with +// ValidateSignatureList() +// run test only if other tests passed +// +// 2 6/23/11 6:19p Alexp +// Added ValidateSigList() function +// +// 1 6/13/11 5:25p Alexp +// +// 13 6/13/11 4:29p Alexp +// +// 12 6/10/11 6:24p Alexp +// Update SelfSigned variable: Pkcs7CertValidateGetSignerKeyHash +// +// 11 6/09/11 5:51p Alexp +// add new parameter to ValidateSelfSigned - Operation. +// test for self-signed variables: hash CA certificate instead of Signer +// certificate. +// +// 10 6/03/11 10:36a Alexp +// Add alternative cert verify logic in ProcessVarWithPk2 (). Keep it +// commented for now +// +// 9 6/02/11 5:53p Alexp +// add new function to ValidateSelfSigned certificates +// add processing for Time BAsed self signed variables +// succesfully Verified Msft Win8 PK-KEK test keys +// +// 8 5/31/11 3:11p Alexp +// Use UpdatePlatformMode() to update SetupMode variable +// +// 7 5/25/11 8:34p Alexp +// draft fix for TimeBased auth variables. More work w Msft needed +// +// 6 5/19/11 4:59p Alexp +// Major code revamp to be able to handle of handling Secure vars in Setup +// Mode +// TBD: TimeBased certificates from Msft fail to process. Not compiled as +// Authenticode format +// +// 5 5/17/11 12:48p Alexp +// fix WDK level4 compiler warnings +// +// 4 5/13/11 3:43p Alexp +// add dependency on Core rev. +// +// 3 5/11/11 7:20p Alexp +// VarData init for FindVariable +// +// 2 5/10/11 5:07p Alexp +// removed local Hash Guid defines +// intermediate check in befor implementing Auth2 var verify logic +// +//********************************************************************** + +#include "NVRAM.h" +#include <AmiDxeLib.h> +#include <AmiCspLib.h> +#include <Protocol/AmiDigitalSignature.h> + +#include "AuthVariable.h" +#include <cryptlib.h> + +/// +/// Global database array for scratch +/// +extern BOOLEAN AVarRuntime; +extern UINT8 mCustomMode; +extern UINT8 mPlatformMode; +extern UINT8 PublicKeyHashArray[HASH_SHA256_LEN]; + +extern AMI_DIGITAL_SIGNATURE_PROTOCOL *mDigitalSigProtocol; +static EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE; + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ProcessVarWithPk2 +// +// Description: Process variable with platform key for verification. +// Called for PK or KEK Variables +// +// +// Input: +// Pkcs7Cert Pointer to Pkcs#7 cert. +// Pkcs7Cert_len Size of Pkcs7 cert +// pDigest Digest of serialized data block +// Digest_len size of the digest (20 or 32 bytes) +// Output: +// Status +// EFI_SUCCESS Variable passed validation successfully. +// EFI_INVALID_PARAMETER Invalid parameter. +// EFI_SECURITY_VIOLATION The variable does NOT pass the validation. +// check carried out by the firmware. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +ProcessVarWithPk2 ( + IN UINT8 *Pkcs7Cert, + IN UINTN Pkcs7Cert_len, + IN UINT8 *pDigest, + IN UINTN Digest_len + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *OldPkList; + EFI_SIGNATURE_DATA *OldPkData; + UINT32 VarAttr; + UINT8 *VarData; + UINTN VarDataSize=0; + UINT8 *x509_TrustCert, *TrustCert; + UINTN x509_TrustCert_len, TrustCert_len; + UINT8 Pkcs7Operation; + + // + // Get platform key from variable. + // + Status = FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &VarAttr, + &VarDataSize, + &VarData + ); +// PK should have been set when we were in SETUP_MODE. This condition is INVALID. +// ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status) || VarData==NULL || !VarDataSize) + return EFI_SECURITY_VIOLATION; + + OldPkList = (EFI_SIGNATURE_LIST *) VarData; + OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize); + +// Verify the PK SignatureType GUID + + if (!guidcmp ((EFI_GUID*) &(OldPkList->SignatureType), &gEfiCertRsa2048Guid)) + { + //Process x509 cert and load Raw Key for Root cert comparison + Pkcs7Operation = Pkcs7CertValidateGetSignerKey; + x509_TrustCert = NULL; + x509_TrustCert_len = 0; + } + else if(!guidcmp ((EFI_GUID*) &(OldPkList->SignatureType), &gEfiCertX509Guid)) + { + Pkcs7Operation = Pkcs7CertValidateGetSignerCert; + x509_TrustCert = (UINT8*)OldPkData->SignatureData; + x509_TrustCert_len = (UINTN)OldPkList->SignatureSize-sizeof(EFI_GUID); + } else + // + // Unsupported Sig Type, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + + TrustCert = (UINT8*)OldPkData->SignatureData; + TrustCert_len = (UINTN)OldPkList->SignatureSize-sizeof(EFI_GUID); + +/* +// Validate Self-Signed +// + x509_TrustCert = &pDigest; // Init with addr to global var + //&PublicKeyHashArray[0]; + x509_TrustCert_len = Digest_len; + Status = mDigitalSigProtocol->Pkcs7Verify ( + mDigitalSigProtocol, + Pkcs7Cert, Pkcs7Cert_len, // Pkcs7Cert + NULL, 0, // use Internal Cert + &x509_TrustCert, &x509_TrustCert_len, // Input->Digest, Output->DER Ptr to Signing Cert + Pkcs7Operation, + RESET + ); + if (!EFI_ERROR (Status)) { + Status = ( TrustCert_len == x509_TrustCert_len && + !(MemCmp(TrustCert, x509_TrustCert, x509_TrustCert_len))) ? + EFI_SUCCESS:EFI_SECURITY_VIOLATION; + } +*/ + Status = mDigitalSigProtocol->Pkcs7Verify ( + mDigitalSigProtocol, + Pkcs7Cert, Pkcs7Cert_len, // Pkcs7Cert + x509_TrustCert, x509_TrustCert_len, // TrustCert + &pDigest, &Digest_len, // In/OutData + Pkcs7Operation, + RELEASE // Flags, mutex + ); + if (!EFI_ERROR (Status)) { + + Status = ( TrustCert_len == Digest_len && + !(MemCmp(TrustCert, pDigest, Digest_len))) ? + EFI_SUCCESS:EFI_SECURITY_VIOLATION; + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ProcessVarWithKek2 +// +// Description: Process variable with key exchange key for verification. +// Called for DB or DBx variables +// +// +// Input: +// Pkcs7Cert Pointer to Pkcs#7 cert. +// Pkcs7Cert_len Size of Pkcs7 cert +// pDigest Digest of serialized data block +// Digest_len size of the digest (20 or 32 bytes) +// +// Output: +// Status +// EFI_SUCCESS Variable passed validation successfully. +// EFI_INVALID_PARAMETER Invalid parameter. +// EFI_SECURITY_VIOLATION The variable does NOT pass the validation. +// check carried out by the firmware. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +ProcessVarWithKek2 ( + IN UINT8 *Pkcs7Cert, + IN UINTN Pkcs7Cert_len, + IN UINT8 *pDigest, + IN UINTN Digest_len + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *KekList; + EFI_SIGNATURE_DATA *KekItem; + UINT32 KekCount; + BOOLEAN IsFound; + UINT32 Index; + UINT32 VarAttr; + UINT8 *VarData; + UINTN VarDataSize=0; + + // + // Get KEK database from variable. + // + Status = FindVariable ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + &VarAttr, + &VarDataSize, + &VarData + ); + if (EFI_ERROR (Status) || VarData==NULL || !VarDataSize) + return EFI_SECURITY_VIOLATION; + + KekList = (EFI_SIGNATURE_LIST *) VarData; + + // + // Enumerate all Kek items in this list to verify the variable certificate data. + // If anyone is authenticated successfully, it means the variable is correct! + // + IsFound = FALSE; + // + // scan thru multiple Sig Lists if exist. Add 1 more loop.... + // + while (!IsFound && (VarDataSize > 0) && (VarDataSize >= KekList->SignatureListSize)) { + if (!guidcmp ((EFI_GUID*) &(KekList->SignatureType), &gEfiCertX509Guid)) + { + KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize; + KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize); + for (Index = 0; Index < KekCount; Index++) { + // find x509 cert and compare against one from Kek + Status = mDigitalSigProtocol->Pkcs7Verify ( + mDigitalSigProtocol, + Pkcs7Cert, Pkcs7Cert_len, // Pkcs7Cert + KekItem->SignatureData, // TrustCert Cert + KekList->SignatureSize, + &pDigest, &Digest_len, // In/OutData + Pkcs7CertValidate, + RELEASE + ); + if (!EFI_ERROR(Status)) { + IsFound = TRUE; + break; + } + KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize); + } + }// else + // Auth2 Vars must be signed with x509 Certs +// if (!guidcmp ((EFI_GUID*) &(KekList->SignatureType), &gEfiCertRsa2048Guid)) +// return EFI_SECURITY_VIOLATION; + VarDataSize -= KekList->SignatureListSize; + KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize); + } + + if (!IsFound) + return EFI_SECURITY_VIOLATION; + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ValidateSelfSigned +// +// Description: Extract Signer certificate and verify Pkcs#7 SignedData signature. +// Called for Private Authenticated variables +// +// +// Input: +// Pkcs7Cert Pointer to Pkcs#7 cert. +// Pkcs7Cert_len Size of Pkcs7 cert +// pDigest Digest of serialized data block +// Digest_len size of the digest (20 or 32 bytes) +// Operation type of Pkcs operation:Pkcs7CertValidateGetSignerCert... +// +// Output: EFI_SUCCESS SignedData passed validation successfully. +// EFI_INVALID_PARAMETER Invalid parameter. +// EFI_SECURITY_VIOLATION The data does NOT pass the validation. +// check carried out by the firmware. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +ValidateSelfSigned ( + IN UINT8 *Pkcs7Cert, + IN UINTN Pkcs7Cert_len, + IN OUT UINT8 **pDigest, + IN OUT UINTN *Digest_len, + IN UINT8 Operation + ) +{ + EFI_STATUS Status; + UINT8 *x509_SignCert; + UINTN x509_SignCert_len=0; + + // + // Extract x509 Signing Cert and validate self-signed data + // + x509_SignCert=(UINT8*)&x509_SignCert_len; // non-zero ptr + Status = mDigitalSigProtocol->Pkcs7Verify ( + mDigitalSigProtocol, + Pkcs7Cert, Pkcs7Cert_len, + NULL, 0, // RootCert + &x509_SignCert, &x509_SignCert_len, + Pkcs7GetSignerCert, + KEEP + ); + // + // Authenticate using internal Signer Cert, Extract Cert or Key Hash + // + if (!EFI_ERROR (Status)) + { + Status = mDigitalSigProtocol->Pkcs7Verify ( + mDigitalSigProtocol, + Pkcs7Cert, Pkcs7Cert_len, // Pkcs7Cert + x509_SignCert, x509_SignCert_len, // RootCert + pDigest, Digest_len, // Input->Digest, Output->DER Ptr to Signing Cert + Operation, + RELEASE + ); + +// Status = mDigitalSigProtocol->Hash(mDigitalSigProtocol, &gEfiHashAlgorithmSha256Guid, 1 &x509_SignCert, (const UINTN*)&x509_SignCert_len, pDigest); +// *Digest_len = HASH_SHA256_LEN; + } + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ConstructDataParameter +// +// Description: +// Generates the Hash (SHA256) out of serialized data block +// Hash(VariableName, VendorGuid, Attributes, TimeStamp, Data) +// +// Input: +// CHAR16 *VariableName Name of Variable to be found. +// EFI_GUID *VendorGuid Variable vendor GUID. +// IN UINT32 Attributes - Attributes of the Var +// VOID *Data - pointer to data block within AutVar Data +// UINTN DataSize - size of data block +// +// Output: EFI_STATUS +// UINT8 Digest - Hash of the serialized data block +// UINTN Digest_len - size of data block +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ConstructDataParameter ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID *Data, + IN UINTN DataSize, + OUT UINT8 *pDigest, + OUT UINTN *Digest_len, + IN UINT8 Mutex +) +{ + EFI_STATUS Status; + + EFI_GUID *HashAlgorithm; + UINT8 *Addr[5]; + UINTN Len[5]; + EFI_VARIABLE_AUTHENTICATION_2 *CertData; + UINTN CertHdrSize, Pkcs7Cert_len; + UINT8 *Pkcs7Cert; + UINT8 HashType=SHA1; + UINT8 *pHash=&HashType; + +#ifdef EFI_DEBUG + UINTN j, i; +#endif + + CertData = (EFI_VARIABLE_AUTHENTICATION_2 *)Data; + CertHdrSize = AUTHINFO_2_SIZE(Data); + +// !!!sha256 is the only digest algorithm supported. +// temp w/a: determine the digest algorithm from contentInfo hdr +// + // quick cheat. CertBlock->CerData is a begining of Pkcs7 Cert + Pkcs7Cert = (UINT8*)&(CertData->AuthInfo.CertData); + Pkcs7Cert_len = CertHdrSize - ((UINTN)Pkcs7Cert - (UINTN)Data); + + Status = mDigitalSigProtocol->Pkcs7Verify ( + mDigitalSigProtocol, + Pkcs7Cert, + Pkcs7Cert_len, + NULL, + 0, + &pHash, // returns DER Ptr to Sign Cert + &Len[0], + Pkcs7GetDigestAlgorithm, + Mutex + ); + if (EFI_ERROR(Status)) + return Status; + + switch(*pHash) { + case SHA1: + *Digest_len = HASH_SHA1_LEN; + HashAlgorithm = &gEfiHashAlgorithmSha1Guid; + break; + case SHA256: + *Digest_len = HASH_SHA256_LEN; + HashAlgorithm = &gEfiHashAlgorithmSha256Guid; + break; + default: + return EFI_UNSUPPORTED; + break; + } + // + // Hash data payload with SHA. + // + Addr[0] = (UINT8*)VariableName; + Len[0] = StrSize16(VariableName); + Addr[1] = (UINT8*)VendorGuid; + Len[1] = sizeof(EFI_GUID); + Addr[2] = (UINT8*)&Attributes; + Len[2] = sizeof(UINT32); + Addr[3] = (UINT8*)&(CertData->TimeStamp); + Len[3] = sizeof(EFI_TIME); + Addr[4] = (UINT8*) Data + (CertHdrSize) ; + Len[4] = DataSize - (CertHdrSize); +// zero out unused Time fields: +/* CertData->TimeStamp.Pad1 = 0; + CertData->TimeStamp.Pad2 = 0; + CertData->TimeStamp.Nanosecond = 0; + CertData->TimeStamp.TimeZone = 0; + CertData->TimeStamp.Daylight = 0;*/ +#ifdef EFI_DEBUG +AVAR_TRACE((TRACE_ALWAYS,"Hash Serialization")); + for (j=0; j<5; j++) { + AVAR_TRACE((TRACE_ALWAYS,"\nArg%d, Len=0x%x\n0000: ", j, Len[j])); + for (i=0; i<Len[j]; i++) + { + AVAR_TRACE((TRACE_ALWAYS,"%02X ", *(UINT8*)(Addr[j]+i) )); + if(Len[j]>16 && i>=15){ + AVAR_TRACE((TRACE_ALWAYS,"\n....\n%04X: ",Len[j]-16)); + for (i=Len[j]-16; i<Len[j]; i++) + AVAR_TRACE((TRACE_ALWAYS,"%02X ", *(UINT8*)(Addr[j]+i) )); + } + } + } +#endif + Status = mDigitalSigProtocol->Hash(mDigitalSigProtocol, HashAlgorithm, 5, Addr, Len, pDigest); +#ifdef EFI_DEBUG +AVAR_TRACE((TRACE_ALWAYS,"\nOutput Digest\n")); + for (i=0; i<16; i++) + AVAR_TRACE((TRACE_ALWAYS,"%02X ", (pDigest[i]) )); +AVAR_TRACE((TRACE_ALWAYS,"...\n")); +#endif + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyVariable2 +// +// Description: +// Verify data payload with AuthInfo in EFI_VARIABLE_AUTHENTICATION_2 type. +// Follow the steps in UEFI2.3.1. This function is called every time variable with +// EFI_VARIABLE_AUTHENTICATED_TIME_BASED_ACCESS attribute is +// created, updated or deleted. This function does all necessary +// authetication checks and based on the results returns Status. +// Also it updates the ExtFlags.KeyHash with the hash the Signer's +// certificate from Variable's AuthInfo Hdr +// +// Input: +// CHAR16 *VariableName Name of Variable to be found. +// EFI_GUID *VendorGuid Variable vendor GUID. +// IN UINT32 Attributes - Attributes of the Var +// VOID **Data - pointer to data block within AutVar Data +// UINTN *DataSize - size of data block +// VOID *OldData - pointer to Existing in NVRAM data block +// UINTN OldDataSize - size of data block +// UINT64 ExtFlags.MonotonicCount - value of MC or TIME stamp +// UINT8 ExtFlags.KeyHash[32] - pointer to memory, allocated by caller, +// where Hash of Signer's certificate will be returned. +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS VerifyVariable2 ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID **Data, + IN UINTN *DataSize, + IN VOID *OldData, + IN UINTN OldDataSize, + IN OUT EXT_SEC_FLAGS *ExtFlags +){ + EFI_STATUS Status; + VOID *RealData; + EFI_VARIABLE_AUTHENTICATION_2 *CertData; + UINTN CertHdrSize, Pkcs7Cert_len, i; + UINT8 *Pkcs7Cert; + INT32 TimeStamp, NonZeroTime; + UINT8 *PubKeyHash; + UINTN PubKeyHashLen; + UINT8 AuthVarType; + +/* + common algo for all Auth2 Vars + +1. Verify that the correct AuthInfo.CertType (EFI_CERT_TYPE_PKCS7_GUID) has been +used and that the AuthInfo.CertData value parses correctly as a PKCS #7 SignedData +value + +2. Verify the signature by: +-extracting the EFI_VARIABLE_AUTHENTICATION_2 descriptor from the Data buffer; +-using the descriptor contents and other parameters to +- construct the input to the digest algorithm; +-computing the digest; + digest = hash (VariableName, VendorGuid, Attributes, TimeStamp, DataNew_variable_content). + and +-comparing the digest with the result of applying the signer's public key to the signature +!!!!Signer must have at least one Cert!!!! + +3. Verify that the signer's certificate chains to a certificate in the Key Exchange Key database (or +the Platform Key) +!!!! +!!!! branch off to handle special Vars for PK or KEK-> Use PK Cert to verify Signer's key +!!!! all other vars including DB and DBx should be looking for Cert chains in KEK db!!!! +!!!! + +4. Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify that the TimeStamp value +is later than the current timestamp value associated with the variable. + +5. For variables with GUID EFI_IMAGE_SECURITY_DATABASE_GUID (i.e. where the data buffer is formatted + as EFI_SIGNATURE_LIST), the driver shall not perform an append of EFI_SIGNATURE_DATA values that + are already part of the existing variable value +*/ +// must have Auth attribute to go deeper + if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)==0) + return EFI_INVALID_PARAMETER; + + RealData = *Data; + + CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) *Data; + CertHdrSize = AUTHINFO_2_SIZE(CertData);//(CertData->AuthInfo.Hdr.Hdr.dwLength + sizeof(EFI_TIME)); + + if(*DataSize < CertHdrSize) + return EFI_SECURITY_VIOLATION; + + // CertBlock->CerData is a begining of Pkcs7 Cert + Pkcs7Cert = (UINT8*)&(CertData->AuthInfo.CertData); + Pkcs7Cert_len = CertHdrSize - ((UINTN)Pkcs7Cert - (UINTN)*Data); + + // + // wCertificateType should be WIN_CERT_TYPE_EFI_GUID. + // Cert type should be EFI_CERT_TYPE_PKCS7_GUID. + // + if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) || + guidcmp ((EFI_GUID*) &(CertData->AuthInfo.CertType), &gEfiCertTypePkcs7Guid) + ) { + // + // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + + // + // Time check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // + TimeStamp = 0; + if(os_mktime( CertData->TimeStamp.Year, CertData->TimeStamp.Month, + CertData->TimeStamp.Day, CertData->TimeStamp.Hour, + CertData->TimeStamp.Minute, CertData->TimeStamp.Second, &TimeStamp )) + { + NonZeroTime = 0; + for(i=0;i < sizeof(EFI_TIME); i++) + NonZeroTime+=(INT32)((UINT8*)CertData)[i]; + + if(NonZeroTime || ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) { + AVAR_TRACE((TRACE_ALWAYS,"Invalid Time Stamp\n")); + return EFI_SECURITY_VIOLATION; + } + } + AVAR_TRACE((TRACE_ALWAYS,"Update Time Stamp\nOld=%x\nNew=%x\n", ExtFlags->Mc, TimeStamp)); + if( (Attributes & EFI_VARIABLE_APPEND_WRITE) == EFI_VARIABLE_APPEND_WRITE) { + // AppendWrite: Only update Timestamp if New one is greater then current + if(OldData && (INT32)ExtFlags->Mc > TimeStamp) + TimeStamp = (INT32)ExtFlags->Mc; + } else { + //Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify that the TimeStamp value + //is later than the current timestamp value associated with the variable. + // and reserved TimeStamp fields must be set to 0 + if( CertData->TimeStamp.Pad1 || + CertData->TimeStamp.Pad2 || + CertData->TimeStamp.Nanosecond || + CertData->TimeStamp.TimeZone || + CertData->TimeStamp.Daylight || + (OldData && (INT32)ExtFlags->Mc >= TimeStamp) + ) { + AVAR_TRACE((TRACE_ALWAYS,"Failed\n")); + return EFI_SECURITY_VIOLATION; + } + } + ExtFlags->Mc = TimeStamp; + AVAR_TRACE((TRACE_ALWAYS,"Upd=%x\n", ExtFlags->Mc)); + // + // Process PK, KEK, seperately. + // + if (IsDbVar(VendorGuid)) + AuthVarType = IsDbVarType; + else + if (IsPkVar(VariableName, VendorGuid)) + AuthVarType = IsPkVarType; + else + if (IsKekVar(VariableName, VendorGuid)) + AuthVarType = IsKekVarType; + else + AuthVarType = IsPrivateVarType; + + if(AuthVarType != IsPrivateVarType) { + + // + // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute + // authenticated variable. + // + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + return EFI_INVALID_PARAMETER; + } + if (mPlatformMode == SETUP_MODE || mCustomMode == 1 ) { + Status = EFI_SUCCESS; + goto Exit_SetupMode; + } + } + + PubKeyHash = &PublicKeyHashArray[0]; + Status = ConstructDataParameter ( + VariableName, VendorGuid, Attributes, + *Data, *DataSize, + PublicKeyHashArray, &PubKeyHashLen, + LOCK // first time Pkcs7 cert process. + ); + if (EFI_ERROR(Status)) + return EFI_SECURITY_VIOLATION; + +// +// Process UEFI Private TimeBased Authenticated Variables +// + if (AuthVarType == IsPrivateVarType){ + /* + Extract x509 Signing Cert(hash) and validate self signed data + Updating Cert hash Existing Variable + */ + Status = ValidateSelfSigned ( + Pkcs7Cert, Pkcs7Cert_len, // Pkcs7Cert + &PubKeyHash, &PubKeyHashLen, // Input->Digest, Output->DER Ptr to Signing Cert + Pkcs7CertValidateGetSignerKeyHash + ); + if (!EFI_ERROR(Status)) { + // Updating Existing Variable + if (OldData && MemCmp(&ExtFlags->KeyHash[0], PubKeyHash, PubKeyHashLen)){ + AVAR_TRACE((TRACE_ALWAYS,"Private Var Key Compare FAILED!\n")); + return EFI_SECURITY_VIOLATION; + } + // Setting Hash for self signed variables + MemCpy(&ExtFlags->KeyHash[0], PubKeyHash, PubKeyHashLen); + + *DataSize = *DataSize - CertHdrSize; + *Data = (UINT8*)RealData + CertHdrSize; + } + } else { +// +// Process UEFI TimeBased PK, KEK and db(x) variables +// + if (AuthVarType == IsDbVarType) { + Status = ProcessVarWithKek2 (Pkcs7Cert, Pkcs7Cert_len, PubKeyHash, PubKeyHashLen); + // verify process db(x) with one of KEK keys or if not found within KEK - with PK + AVAR_TRACE((TRACE_ALWAYS,"kek for db check %r\n", Status)); + if (Status == EFI_SECURITY_VIOLATION) { + Status = ProcessVarWithPk2 (Pkcs7Cert, Pkcs7Cert_len, PubKeyHash, PubKeyHashLen); + AVAR_TRACE((TRACE_ALWAYS,"PK for db check %r\n", Status)); + } + // + // Process PK, KEK separately. + // + } else + if (AuthVarType == IsPkVarType || AuthVarType == IsKekVarType) + Status = ProcessVarWithPk2 (Pkcs7Cert, Pkcs7Cert_len, PubKeyHash, PubKeyHashLen); + + if (EFI_ERROR(Status)) + return EFI_SECURITY_VIOLATION; + +Exit_SetupMode: + + *DataSize = *DataSize - CertHdrSize; + *Data = (UINT8*)RealData + CertHdrSize; + + // Validate Signature List integrity + if(*DataSize && EFI_ERROR(ValidateSignatureList (*Data, *DataSize))) + return EFI_SECURITY_VIOLATION; + // + // If delete PK in user mode -> change to setup mode. + // If enroll PK in setup mode -> change to user mode. + // + if(AuthVarType == IsPkVarType) { + if (*DataSize == 0) + UpdatePlatformMode (SETUP_MODE); + else + UpdatePlatformMode (USER_MODE); + } + } + + return Status; +} +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.c b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.c new file mode 100644 index 0000000..a8489f9 --- /dev/null +++ b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.c @@ -0,0 +1,1729 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/AuthVariable.c 90 3/09/15 4:28p Alexp $ +// +// $Revision: 90 $ +// +// $Date: 3/09/15 4:28p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/AuthVariable.c $ +// +// 90 3/09/15 4:28p Alexp +// Update year 2015 in the file header +// +// 88 10/08/14 3:16p Alexp +// Introduced global mCustomMode flag passing the status from +// PhysicalUserPresent() +// +// 87 10/17/13 12:58p Alexp +// +// 85 6/25/13 1:52p Alexp +// GetmSecureBootSupport() Init SecureBootVar structure with SDL defaults. +// +// 84 5/17/13 4:37p Alexp +// EIP:122063 CSM related: failure to boot UEFI if DefaultKeyProvision is +// set without system reset +// change: SecureBoot variable is set once during AuthVar Init() +// +// 83 4/15/13 11:07a Alexp +// Restore the code to install "SignatureSupport" variable. +// It was mistakenly removed due to a discussin at USWG that +// the Var should have been deprectated. +// +// 82 3/06/13 6:52p Alexp +// AuthVariableServiceInitSMM() +// verify if gAmiSmmDigitalSignatureProtocol already installed before +// installing a callback on protocol +// +// 79 2/20/13 6:31p Alexp +// EIP[115120]:Secureboot Firmware does not verify duplication before +// Appending to the variable. +// Fix: Update FindInSignatureDb() to process combination of SigData and +// SigLists +// +// 77 2/08/13 5:14p Alexp +// removed unused arguments from ProcessVarWithPk & ProcessVarWithKek +// +// 76 12/18/12 10:58a Alexp +// code fixes according to "cppcheck" style & performance suggestions +// +// 73 12/11/12 6:31p Alexp +// - Replaced TRACE macro with AVAR_TRACE. Stop debug traces in Virtual +// address mode +// - VerifyVariable() Fix final check for IsPk and run +// ValidateSignatureList() +// +// 71 12/06/12 7:36p Alexp +// EIP#98995, EIP#102807 : WHCK tests fail +// -removed AuthVarLock logic, +// -use PhysicalUserPresent() hook +// to unlock Secure Variables for write/erase +// +// 70 12/04/12 6:54p Alexp +// EIP#98995, EIP#102807 : Secure Boot WHCK tests fail +// temp fix in PhysicalUserPresent()->return NOT_DETECTED if var not found +// +// 69 11/26/12 10:46a Alexp +// replaced hardwired Var name L"SecureBootSetup" to generic Var define +// +// 68 11/21/12 3:33p Alexp +// Fix for Win8 SecureBoot logo requirement: restore Secure Boot state +// across flash updates. +// Move all secure boot Setup settings to a separate varstore variable +// in order to preserve settings across re-flash +// +// 66 11/16/12 7:11p Alexp +// Fixed ValidateSignatureList() return status for Zero Data or Size +// +// 65 11/09/12 4:30p Alexp +// EIP:104961 UEFI 2.3.1 SCTc test failed in Generic\EfiCompliant case. +// Fix for SelfSigned variables. +// +// 64 11/01/12 5:45p Alexp +// bug fix: ValidateSignatureList () returned Success +// even if no sig detected if file size = 0( line 1015) +// +// 63 10/22/12 10:32a Alexp +// fixed SetupMode overwrite while updating RO vars:SetupMode and +// SecureBoot. +// +// 62 10/19/12 5:07p Alexp +// Implemented R/O Variables support via fixed and OEM defined (eLink) +// lists. Secure Boot RO Variable logic includes Vendor GUID check +// Reserved Secure Boot RO variables are gEfiGlobalVariableGuid. +// +// 58 9/25/12 11:20a Alexp +// Add New feature: +// include facility to link external Physical User Presence +// detect hooks via eLink:PhysicalUserPresenceDetect +// +// 55 9/14/12 3:40p Alexp +// 1. removed unused code for setting Pk/Kek/db vars +// 2. optimized mAuthVarLock logic +// +// 54 9/12/12 12:16p Alexp +// removed dependency on mSecureBootMode. AuthVar is locked always at +// ReadyTo boot +// +// 53 8/29/12 5:02p Alexp +// SetVariable(): return status matched to UEFI Spec: if both +// Authenticated Attributes are set returns INVALID_PARAMETER (old +// UNSUPPORTED) +// +// 52 8/27/12 6:55p Alexp +// GetmSecureBootSupport(): +// Add input parameter SetupMode to disable +// Setup Flag:SecureBootSupport when platform in Setup Mode +// Logic enabled by DEFAULT_SECURE_BOOT_ENABLE = 0 +// +// 50 8/23/12 5:36p Alexp +// UEFI ECR change. +// Don't install SignatureSupport Variable. It's obsolete in UEFI 2.3.1+ +// +// 49 8/22/12 9:23a Alexp +// difined CUSTOM_BOOT_MODE = 2 to match value in Setup Variable +// +// 47 7/27/12 4:36p Alexp +// Changed Auth Var rules override policy: no need for Admin var checking +// Further enhancement will introduce physical user presence detection +// +// 45 7/25/12 6:37p Alexp +// enhance ValidateSignatureList() checking. SigList.Size field must be of +// valid size. +// +// 44 5/17/12 4:21p Alexp +// Fix for SCT 5/12 test for Auth Variables. SCT ignores rules for +// reserved Secure Boot variables always be formatted as Authenticated +// Variable with proper attributes. +// +// 42 4/30/12 10:53a Alexp +// EIP88439: irrespective of SetupMode, only properly formatted +// Authenticated Variable can be erased +// +// 40 4/10/12 6:53p Alexp +// comment clean up +// +// 36 3/14/12 1:02p Alexp +// AuthServiceVirtualFixup: fixup addresses within AmiSigAPI +// +// 35 3/13/12 2:36p Alexp +// Add check for System in Admin mode while allowing Var Security override +// +// 33 3/09/12 3:37p Alexp +// -add logic to process new Secure Boot mode-Custom +// -just a temp change - will be reviewed in later releases +// +// 13 3/09/12 3:35p Alexp +// -add logic to process new Secure Boot mode-Custom +// -just a temp change - will be reviewed in later releases +// +// 32 2/27/12 6:48p Alexp +// +// 31 2/15/12 11:00a Alexp +// added traces for Signature List validation. +// +// 30 2/03/12 9:56a Alexp +// EIP#82122. WHCK "Secure Boot Manual Logo Test" fails +// Fixed Append logic to process multiple sig data instances in a single +// Signature List block +// New logic will remove dupplicated certs and update new SigList header. +// +// 29 12/29/11 6:52p Alexp +// Updated logic for handling cases with mAuthVarLock = FALSE. +// +// 28 12/16/11 4:44p Alexp +// Add build time switch USER_MODE_POLICY_OVERRIDE +// AuthVariable logic will allow override/erase Secure Variables without +// enforcing Authentication rules until receiving EFI ReadyToBoot event. +// +// 26 11/30/11 7:58p Alexp +// According to UEFI 2.3.1 Sec 7.2.1 : "db" vars can be validated either +// by KEK key or by PK key. +// The fix adds the check for PK if none of KEKs can validate new "db" +// +// 25 11/08/11 3:03p Alexp +// 1. ValidateSignatureList: add check for invalid parameter Data== NULL +// 2. VerifyVariable: ignore check for AuthAttribute match if in Setup +// Mode +// 3. VerifyVariable: Always set TimeBased Attributes for reserved Sec +// variables +// +// 24 11/02/11 10:53a Alexp +// 1. EIP#71452. Due to a bug in FindVariable() in NVRAMDXE.C SecureBootSetup +// Variable cannot be located at first boot. +// Changed GetmSecureBootSupport() to use +// DxeGetVariable instead of FindVariable +// 2. Made temp fixes to pass SCT 2.3.1 TW UEFI Plugfest build. +// a. MC Based Variable. Length of the CertHdr reported wrongly +// 22b vs 230 bytes +// b. MC based Variable. CertType GUID is reported wrongly +// c. Allow to set reserved Sec Variables KEK, db(x) without Auth +// attributes in Setup Mode +// +// 22 8/24/11 8:45a Alexp +// added Mailbox variable AuthVarMailbox to inform SMM AuthVariable code +// of ReadyToBoot event. Needed to prevent erase of Signed Variables in +// runtime +// +// +// 19 8/22/11 11:11a Alexp +// UpdatePlatformMode() - moved mPlatformMode=Mode at the end +// VerifyVar - move back door code inside AuthAttribute branch +// +// 17 8/18/11 5:59p Alexp +// renamed SecureBootMode to more appropriate SecureBootSupport +// renamed BeforeBoot to AuthVarLock. +// Keep unlocked in DXE phase and locked while in SMM +// +// 16 8/18/11 4:57p Alexp +// 1. Removed use of Mailbox varaible to communicate state to SMM copy of +// AuthVar service +// 2. Removed Callback event to erase Secure Variables. +// 3. Optimized logic to exchange local data between DXE and SMM copies of +// AuthVar +// 4. Add provision to erase of Auth Variables before +// BdsConnect(ReadyToBoot) lock event +// +// 15 8/16/11 7:18p Alexp +// added Mailbox variable AuthVarMAilbox to syncronize local state between +// DXE and SMM AuthVariable services +// +// 14 8/12/11 1:49p Alexp +// comment out getplatfmode() in VerifyVariable call. Not needed as we do +// not want to change the SetupMode in runtime +// +// 13 8/05/11 3:13p Alexp +// VerifyVariable->Set current time as TimeStamp for Signed Variables (PK, +// KEK..) if they are set in User mode +// +// 12 8/04/11 7:15p Alexp +// 1. UpdatePlatformMode. Moved Get SecureBootSetup to Init function. +// 2. Fix detection of IsPk() in VerifyVariable for SetupMode control flow +// +// 11 7/18/11 10:09a Alexp +// 1. Made gEfiGlobalVariableGuid static. Fixes link issues in older Aptio +// cores +// 2. Update Append verify with added check for the new data to be in +// SignatureList format +// +// 10 6/30/11 4:02p Alexp +// added Callback event on Setup Mode change request form Security Setup +// Page. +// +// 9 6/27/11 6:16p Alexp +// code optimization: moved ValidateSignatureList () call in the main +// VerifyVariable1(2) function. +// +// 8 6/24/11 7:03p Alexp +// fixed ValidateSignatureList () logic. Added Certificate RSA2048 to +// supported Signatures +// +// 7 6/24/11 3:22p Alexp +// test PK, KEK, db(x) for valid Signatuer List header with +// ValidateSignatureList() +// +// 6 6/24/11 2:24p Alexp +// 1. Call Auth Variable init in smm callback. need to initialize global +// variables for SetupMode and SecureBoot +// 2. Enable SignatureList header validation for PK-KEK-db payload +// +// 5 6/23/11 6:19p Alexp +// Added ValidateSigList() function +// +// 4 6/23/11 10:05a Alexp +// add dependency on ImageAuthentication token for SecureBoot Variable +// installation +// +// 3 6/22/11 5:42p Alexp +// ignore Authenticated Variable rules while in non SecureBoot mode +// +// 2 6/15/11 3:01p Alexp +// Add checks for variables with zero parameters: Attributes, Data, Size +// +// 1 6/13/11 5:25p Alexp +// +// 18 6/13/11 4:28p Alexp +// rearranged calls to VerifyVariable1 & 2 from main VerifyVariable() +// +// 17 6/09/11 5:49p Alexp +// add AuthServiceVirtualFixup +// +// 16 6/06/11 6:01p Alexp +// UpdatePlatformMode: update both SetupMode and SecureBoot at once +// +// 15 6/03/11 4:12p Alexp +// bug fix: when changing SetupMode check for PK file attribute to have +// Auth flag +// set TimeBased attrib for non-signed generic Secured variables (Win8 +// w/a) +// +// +// 13 6/02/11 5:50p Alexp +// fix a bug with self signed key hash compare +// +// 12 6/02/11 1:06p Alexp +// fix failed case with Append db logic if certificate already existed +// +// 11 6/01/11 1:06p Alexp +// removed GetSecureVars hook. Use UpdatePlatformMode() instead +// cleaned Append logic +// +// 9 5/25/11 8:34p Alexp +// draft fix for TimeBased auth variables. More work w Msft needed +// +// 8 5/19/11 4:59p Alexp +// Major code revamp to be able to handle of handling Secure vars in Setup +// Mode +// TBD: TimeBased certificates from Msft fail to process. Not compiled as +// Authenticode format +// +// 7 5/17/11 12:48p Alexp +// fix WDK level4 compiler warnings +// +// 6 5/13/11 3:43p Alexp +// add dependency on Core rev. +// +// 5 5/12/11 5:53p Alexp +// fix tobuld for Aptio core 4.6.4. and older. +// +// 4 5/11/11 7:20p Alexp +// VarData init for FindVariable +// +// 3 5/10/11 5:07p Alexp +// removed local Hash Guid defines +// +// 2 5/10/11 3:56p Alexp +// move FindVariable to NVRAMDXE.c +// +// 1 5/09/11 10:00a Alexp +// +// 9 5/05/11 12:10p Alexp +// make it as eModule, replace TRACE call to TRACE macro. Only dump TRACEs +// in Debug mode +// +// 8 3/31/11 6:27p Alexp +// removed asserts on missing DB, KEK +// +//********************************************************************** + +#include "NVRAM.h" +#include <AmiDxeLib.h> +#include <AmiCspLib.h> +#include <Setup.h> +#include <SecureBootMod.h> + +#include <Protocol/AmiDigitalSignature.h> + +#include "AuthVariable.h" + +// +// Global defines and variables +// + +BOOLEAN AVarRuntime = FALSE; + +#define BDS_CONNECT_DRIVERS_PROTOCOL_GUID \ +{0x3aa83745, 0x9454, 0x4f7a, 0xa7, 0xc0, 0x90, 0xdb, 0xd0, 0x2f, 0xab, 0x8e} +static EFI_GUID gBdsConnectDriversProtocolGuid = BDS_CONNECT_DRIVERS_PROTOCOL_GUID; +static EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE; +static EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {SIGSUPPORT_LIST}; +static EFI_GUID gSecureSetupGuid = SECURITY_FORM_SET_GUID; +static EFI_GUID gSystemAccessGuid = SYSTEM_ACCESS_GUID; +static SECURE_BOOT_SETUP_VAR mSecureBootSetup; + +UINT8 PublicKeyHashArray[HASH_SHA256_LEN]; +UINT8 mPlatformMode = SETUP_MODE; +UINT8 mSetupMode = USER_MODE; +UINT8 mCustomMode = 0; +static UINT8 mSecureBootSupport = NONSECURE_BOOT; + +AMI_DIGITAL_SIGNATURE_PROTOCOL *mDigitalSigProtocol = NULL; + +static CHAR16* ReservedReadOnlyVarNameList[] = { + EFI_SETUP_MODE_NAME, + EFI_SECURE_BOOT_NAME, + EFI_SIGNATURE_SUPPORT_NAME, + EFI_IMAGE_SECURITY_DATABASE_DEFAULT, + EFI_IMAGE_SECURITY_DATABASE1_DEFAULT, + EFI_PLATFORM_KEY_NAME_DEFAULT, + EFI_KEY_EXCHANGE_KEY_NAME_DEFAULT, + NULL +}; +static CHAR16* OemReadOnlyVariableList[] = {OEM_READONLY_VAR_LIST NULL}; + +#if USER_MODE_POLICY_OVERRIDE == 1 + +typedef BOOLEAN (HOOK_PHYSICAL_USER_PRESENCE_DETECT)( + VOID +); + +extern HOOK_PHYSICAL_USER_PRESENCE_DETECT PHYSICAL_USER_PRESENCE_DETECT_LIST EndOfPhysicalUserPresentHook; + +HOOK_PHYSICAL_USER_PRESENCE_DETECT* PhysicalUserPresentHookList[]= + {PHYSICAL_USER_PRESENCE_DETECT_LIST NULL}; + +BOOLEAN PhysicalUserPresent( VOID ) +{ + UINTN i; + BOOLEAN Result = FALSE; + for(i=0; PhysicalUserPresentHookList[i] && (Result == FALSE); i++) + Result = PhysicalUserPresentHookList[i](); + return Result; +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AuthVarAdminUserPresent +// +// Description: Default implementation for Physical User Presense detection. +// Detects if Admin User signed in by checking "SystemAccess" Variable +// +// Input: NONE +// +// Output: BOOLEAN +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN AuthVarAdminUserPresent ( VOID ) +{ + SYSTEM_ACCESS SystemAccess = {SYSTEM_PASSWORD_USER}; + UINTN Size = sizeof(SYSTEM_ACCESS); + UINT32 Attributes = 0; + EFI_STATUS Status; + // TBD. Replace Admin User mode with true Physical user presence detection + Status = DxeGetVariable(L"SystemAccess", &gSystemAccessGuid, &Attributes, &Size, &SystemAccess); + if (!EFI_ERROR(Status) + && !(Attributes & EFI_VARIABLE_NON_VOLATILE) + && SystemAccess.Access==SYSTEM_PASSWORD_ADMIN) + { + return TRUE; + } + + return FALSE; +} +#endif + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AuthServiceVirtualFixup +// +// Description: This function will be invoked to convert +// runtime pointers to virtual address +// +// Input: none +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID AuthServiceVirtualFixup() +{ + + static BOOLEAN bSigProtoVirtual = FALSE; + VOID **p; + UINT8 i; + + //if mDigitalSigProtocol is NULL, nothing to fix up + if (!mDigitalSigProtocol) return; + + // This function gets called from Nvramdxe.c, do nothing when + // the function is called second time. + if (bSigProtoVirtual == TRUE) return; + else bSigProtoVirtual = TRUE; +//AVAR_TRACE((-1,"AuthVarService mDigitalSig Virtual addr Fixup\n")); + //Fixup mDigitalSigProtocol member functions + for(i=0,p = (VOID**)mDigitalSigProtocol; p < (VOID**)(mDigitalSigProtocol + 1); i++,p++) +// { +//AVAR_TRACE((-1,"mSigAPI[%d] before Virtual MemFixup = %lx (%lx), ", i, p)); + pRS->ConvertPointer(0, p); +//AVAR_TRACE((-1,"After = %lx\n", p)); +// } + pRS->ConvertPointer(0,&mDigitalSigProtocol); + AVarRuntime = TRUE; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitSmmAuthServiceCallback +// +// Description: This function initialize mDigitalSigProtocol in SMM +// +// +// Input: IN EFI_EVENT Event - Event that was triggered +// IN VOID *Context - data pointer to information that is defined +// when the event is registered +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +static EFI_STATUS InitSmmAuthServiceCallback (IN EFI_EVENT Event, IN VOID *Context) +{ + return pBS->LocateProtocol( + &gAmiSmmDigitalSignatureProtocolGuid, NULL, &mDigitalSigProtocol + ); +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitSmmAuthService +// +// Description: This function calls InitSmmAuthServiceCallback to initialaze +// DigitalSigProtocol in SMM by trying to Locate +// DigitalSigProtocol. If Protocol is not installed yet +// RegisterProtocolCallback will be called. +// +// +// Input: None +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID AuthVariableServiceInitSMM () +{ + EFI_STATUS Status; + EFI_EVENT SmmHashEvent; + VOID *pSmm; + + // temp w/a: don't print debug traces from SMM + AVarRuntime = TRUE; + // + // Authenticated variable initialize. + // + // Check PK database's existence to determine the value. + // Then create "SetupMode" with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + // + // Update mPlatformMode + GetPlatformMode(); + + // Update mSecureBootSupport global variable + GetmSecureBootSupport(mPlatformMode); + + Status = InitSmmAuthServiceCallback (NULL, NULL); + if (EFI_ERROR(Status)) + RegisterProtocolCallback( + &gAmiSmmDigitalSignatureProtocolGuid, + InitSmmAuthServiceCallback, + NULL, + &SmmHashEvent, + &pSmm + ); +} + +//------------------------------------------------------------------------------ +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: InitAuthServiceCallback +// +// Description: This function initialize mDigitalSigProtocol not in SMM +// +// +// Input: IN EFI_EVENT Event - Event that was triggered +// IN VOID *Context - data pointer to information that is defined +// when the event is registered +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +static EFI_STATUS InitAuthServiceCallback (IN EFI_EVENT Event, IN VOID *Context) +{ + return pBS->LocateProtocol( + &gAmiDigitalSignatureProtocolGuid, NULL, &mDigitalSigProtocol + ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: AuthVariableServiceInit +// +// Description: This function calls InitAuthServiceCallback to initialaze +// DigitalSigProtocol not in SMM by trying to Locate +// DigitalSigProtocol. If Protocol is not installed yet +// RegisterProtocolCallback will be called. +// +// +// Input: None +// +// Output: VOID +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID AuthVariableServiceInit () +{ + EFI_EVENT Event; + VOID *p; + UINT8 Data; + + // + // Create "SignatureSupport" with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + // + DxeSetVariable(EFI_SIGNATURE_SUPPORT_NAME,&gEfiGlobalVariableGuid, + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + SIGSUPPORT_NUM * sizeof(EFI_GUID), &mSignatureSupport + ); + // + // Check presence of PK database to determine the value. + // Then create "SetupMode" with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + // Update mPlatformMode + GetPlatformMode(); + + // Update mSecureBootSupport global variable + GetmSecureBootSupport(mPlatformMode); + + // Set SecureBoot, both conditions must be met + Data = (mPlatformMode==USER_MODE && mSecureBootSupport==SECURE_BOOT)?1:0; + DxeSetVariable(EFI_SECURE_BOOT_NAME,&gEfiGlobalVariableGuid, + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(UINT8), &Data); + + // Create "SetupMode" variable with RO access + UpdatePlatformMode(mPlatformMode); + + if (EFI_ERROR(InitAuthServiceCallback (NULL, NULL))) + RegisterProtocolCallback( + &gAmiDigitalSignatureProtocolGuid, + InitAuthServiceCallback, + NULL, + &Event, + &p + ); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: StrSize16 +// +// Description: +// This function returns UNICODE string size in bytes +// +// Input: +// CHAR16 *String - Pointer to string +// +// Output: +// UINT32 - Size of string in bytes excluding the nul-terminator +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +UINT32 StrSize16(CHAR16 *String) +{ + UINT32 Size = 0;//2; + while(*String++) + Size += 2; + return Size; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: StrCmp16 +// +// Description: +// This function compares two UNICODE strings +// +// Input: +// IN CHAR16 *Dest - Pointer to destination string +// IN CHAR16 *Src - Pointer to source string +// +// Output: +// INTN - Zero if strings are equal, non-zero otherwise +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +INTN StrCmp16(CHAR16 *Dest, CHAR16 *Src) +{ + return MemCmp(Dest, Src, StrSize16(Src)); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsPkVar +// +// Description: +// This function compares two UNICODE strings +// +// Input: +// CHAR16 - Pointer to UNICODE Variable Name +// EFI_GUID - Pointer to Variable GUID +// +// Output: +// BOOLEAN - TRUE if strings are equal +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN IsPkVar( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid +) +{ + return ((guidcmp(VendorGuid, &gEfiGlobalVariableGuid) == 0) && + (StrCmp16 ((CHAR16 *)VariableName, (CHAR16 *)EFI_PLATFORM_KEY_NAME) == 0)); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsKekVar +// +// Description: +// This function compares two UNICODE strings +// +// Input: +// CHAR16 - Pointer to UNICODE Variable Name +// EFI_GUID - Pointer to Variable GUID +// +// Output: +// BOOLEAN - TRUE if strings are equal +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN IsKekVar( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid +) +{ + return ((guidcmp(VendorGuid, &gEfiGlobalVariableGuid) == 0) && + (StrCmp16 ((CHAR16 *)VariableName, (CHAR16 *)EFI_KEY_EXCHANGE_KEY_NAME) == 0)); +} + + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsReservedVariableName +// +// Description: +// Check if Variable name matches one from Predefined Read-Only Variable Name list +// +// Input: +// CHAR16 - Pointer to UNICODE Variable Name +// EFI_GUID *VendorGuid - Variable GUID +// +// Output: +// BOOLEAN +// TRUE if Variable name found in the Predefined Read-Only Variable Name lists +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +IsReservedVariableName( + CHAR16 *VariableName, + EFI_GUID *VendorGuid +) +{ + UINT8 Index; + Index = 0; + + while(ReservedReadOnlyVarNameList[Index] != NULL) + { + if(StrCmp16 (VariableName, ReservedReadOnlyVarNameList[Index]) == 0) + { +// Reserved Secure Boot RO variables are gEfiGlobalVariableGuid. + return (guidcmp(VendorGuid, &gEfiGlobalVariableGuid) == 0); + } + Index++; + } + Index = 0; + while(OemReadOnlyVariableList[Index] != NULL) + { + if(StrCmp16 (VariableName, OemReadOnlyVariableList[Index]) == 0) + return TRUE; + Index++; + } + + return FALSE; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: IsDbVar +// +// Description: +// This function compares two UNICODE strings +// +// Input: +// IN CHAR16 *Dest - Pointer to destination string +// IN CHAR16 *Src - Pointer to source string +// +// Output: +// INTN - Zero if strings are equal, non-zero otherwise +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +BOOLEAN IsDbVar( + IN EFI_GUID *VendorGuid +) +{ + return (!guidcmp (VendorGuid, &gEfiImageSecurityDatabaseGuid)); +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetPlatformMode +// +// Description: +// Initializes for authenticated varibale service. +// +// Input: +// UINT8 *PlatformMode +// +// Output: EFI_STATUS Function successfully executed. +// UINT8 *PlatformMode +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +GetPlatformMode ( + VOID +) +{ + EFI_STATUS Status; + UINT32 VarAttr; + UINTN VarDataSize; + VOID *Data; + + mPlatformMode = USER_MODE; + + // + // Check PK database's existence to determine the value. + // + VarDataSize = 0; + Status = FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &VarAttr, + &VarDataSize, + &Data + ); + if (Status != EFI_SUCCESS || Data == NULL || VarDataSize == 0 || + !(VarAttr & UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES) + ) { + mPlatformMode = SETUP_MODE; + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: GetmSecureBootSupport +// +// Description: +// Initializes for authenticated varibale service. +// +// Input: +// SetupMode Disable SecureBoot control if Platform runs in SetupMode (no PK) +// +// Output: EFI_STATUS Function successfully executed. +// EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +GetmSecureBootSupport ( + UINT8 SetupMode +) +{ + EFI_STATUS Status = EFI_SUCCESS; +//#if defined(ImageVerification_SUPPORT) && ImageVerification_SUPPORT==1 + UINTN DataSize=0; + // + // Get Setup variable, check SecureBoot and set the EFI Var + // + Status = DxeGetVariable( + AMI_SECURE_BOOT_SETUP_VAR, + &gSecureSetupGuid, + NULL, + &DataSize, + &mSecureBootSetup + ); + if(Status == EFI_BUFFER_TOO_SMALL) + Status = DxeGetVariable( + AMI_SECURE_BOOT_SETUP_VAR, + &gSecureSetupGuid, + NULL, + &DataSize, + &mSecureBootSetup + ); + ASSERT_EFI_ERROR (Status); + mSecureBootSupport = (mSecureBootSetup.SecureBootSupport); +// Disable SecureBoot Setup Option if system is in Setup mode +#if DEFAULT_SECURE_BOOT_ENABLE == 0 + if(mSecureBootSupport == 1 && + (SetupMode == SETUP_MODE && mSecureBootSetup.DefaultKeyProvision == 0) + ) + { + mSecureBootSupport = NONSECURE_BOOT; + } +#endif +//#else +// mSecureBootSupport = NONSECURE_BOOT; +//#endif + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: UpdatePlatformMode +// +// Description: Update mPlatformMode & "SetupMode" Efi var +// +// Input: Mode SETUP_MODE or USER_MODE. +// +// Output: none +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +VOID +UpdatePlatformMode( + IN UINT8 Mode +) +{ +AVAR_TRACE((TRACE_ALWAYS,"Update Setup Mode\nCurrent=%x, New=%x\n", mPlatformMode, Mode)); + // + // update global mPlatformMode var + // + mPlatformMode = Mode; + // + // Set "SetupMode" variable. + // + // Setting of mSetupMode=SETUP_MODE will un-lock access to runtime R/O vars + mSetupMode = SETUP_MODE; + + DxeSetVariable(EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(UINT8), &mPlatformMode); + +// Re-lock access to runtime protected vars + mSetupMode = USER_MODE; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ValidateSignatureList +// +// Description: +// Validate the data payload begins with valid Signature List header +// and based on the results returns Status. +// +// Input: +// IN VOID *Data - pointer to the Var data +// IN UINTN DataSize - size of Var data +// +// Output: EFI_STATUS +// UINTN RealDataSize - only the size of the combined length of Signature Lists +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS ValidateSignatureList ( + IN VOID *Data, + IN UINTN DataSize +) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *SigList; + UINTN Index; + + Status = EFI_SECURITY_VIOLATION; + + if(Data == NULL || DataSize == 0) + return Status; // Sig not found + + SigList = (EFI_SIGNATURE_LIST *)Data; + +// loop till end of DataSize for all available SigLists + +// Verify signature is one from SigDatabase list mSignatureSupport / sizeof(EFI_GUID) +// SigData begins with SigOwner GUID +// SignatureHdrSize = 0 for known Sig Types + + while ((DataSize > 0) && (DataSize >= SigList->SignatureListSize)) { + + for (Index = 0; Index < SIGSUPPORT_NUM; Index++) { + if (!guidcmp ((EFI_GUID*) &(SigList->SignatureType), &mSignatureSupport[Index])) + break; + } +AVAR_TRACE((TRACE_ALWAYS,"SigList.Type-")); + if(Index >= SIGSUPPORT_NUM) + return EFI_SECURITY_VIOLATION; // Sig not found + +AVAR_TRACE((TRACE_ALWAYS,"OK\nSigList.Size-")); + if(SigList->SignatureListSize < 0x4c || // Min size for SHA2 Hash Certificate sig list + SigList->SignatureListSize > NVRAM_SIZE) + return EFI_SECURITY_VIOLATION; + +AVAR_TRACE((TRACE_ALWAYS,"OK\nSigList.HdrSize-")); + if(SigList->SignatureHeaderSize != 0) + return EFI_SECURITY_VIOLATION; // Sig not found +AVAR_TRACE((TRACE_ALWAYS,"OK\n")); + DataSize -= SigList->SignatureListSize; + SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize); + + Status = EFI_SUCCESS; + } + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ProcessVarWithPk +// +// Description: Process variable with platform key for verification. +// +// +// Input: +// VariableName Name of Variable to be found. +// VendorGuid Variable vendor GUID. +// Data Data pointer. +// DataSize Size of Data found. If size is less than the +// data, this value contains the required size. +// Variable The variable information which is used to +// keep track of variable usage. +// Attributes Attribute value of the variable +// IsPk Indicate whether it is to process pk. +// +// Output: EFI_SUCCESS Variable passed validation successfully. +// EFI_INVALID_PARAMETER Invalid parameter. +// EFI_SECURITY_VIOLATION The variable does NOT pass the validation. +// check carried out by the firmware. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +ProcessVarWithPk ( + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN BOOLEAN IsPk + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_SIGNATURE_LIST *OldPkList; + EFI_SIGNATURE_DATA *OldPkData; + UINT32 VarAttr; + UINT8 *VarData; + UINTN VarDataSize=0; + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + // + // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute. + // +//AVAR_TRACE((TRACE_ALWAYS,"PK NOT_VOLITILE\n")); + return EFI_INVALID_PARAMETER; + } + + if (mPlatformMode == SETUP_MODE || mCustomMode == 1) + return Status; + // + // Get platform key from variable. + // + Status = FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &VarAttr, + &VarDataSize, + &VarData + ); +// PK should have been set when we were in SETUP_MODE. This condition is INVALID. + if (EFI_ERROR (Status) || VarData==NULL || !VarDataSize) + return EFI_SECURITY_VIOLATION; + + OldPkList = (EFI_SIGNATURE_LIST *) VarData; + OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize); + +// Authenticate + Status = VerifyDataPayload (Data, DataSize, OldPkData->SignatureData); +//AVAR_TRACE((TRACE_ALWAYS,"PK VerifyPayload %r\n",Status)); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: ProcessVarWithKek +// +// Description: Process variable with key exchange key for verification. +// +// +// Input: +// Data Data pointer. +// DataSize Size of Data found. If size is less than the +// data, this value contains the required size. +// Variable The variable information which is used to +// keep track of variable usage. +// Attributes Attribute value of the variable +// +// Output: EFI_SUCCESS Variable passed validation successfully. +// EFI_INVALID_PARAMETER Invalid parameter. +// EFI_SECURITY_VIOLATION The variable does NOT pass the validation. +// check carried out by the firmware. +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS +ProcessVarWithKek ( + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes + ) +{ +// so far can be DB or DBx variables + + EFI_STATUS Status = EFI_SUCCESS; + 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 VarAttr; + UINT8 *VarData; + UINTN VarDataSize = 0; + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + // + // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute. + // + return EFI_INVALID_PARAMETER; + } + +// +// If in setup mode, no authentication needed. +// + if (mPlatformMode == SETUP_MODE || mCustomMode == 1) + return Status; + + CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *)&(CertData->AuthInfo.CertData); + // + // Get Key database from KEK variable. + // + Status = FindVariable ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + &VarAttr, + &VarDataSize, + &VarData + ); + + KekList = (EFI_SIGNATURE_LIST *) VarData; + if (EFI_ERROR(Status) || guidcmp ((EFI_GUID*) &(KekList->SignatureType), &gEfiCertRsa2048Guid)) + return EFI_SECURITY_VIOLATION; + // + // Enumerate all Kek items in this list to verify the variable certificate data. + // If anyone is authenticated successfully, it means the variable is correct! + // +// IsFound = FALSE; +// +// scan thru multiple Sig Lists if exist. Add 1 more loop.... +// actually, KEK would have one list since KEK owner may club all Kek keys together before signing with PK +// do { + KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize; + KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize); + for (Index = 0; Index < KekCount; Index++) { + if (MemCmp (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) { +// IsFound = TRUE; + break; + } + KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize); + } +// KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize); +// } while (!IsFound || (UINT8*)KekList < (VarData+VarDataSize)); +// if (!IsFound) { + if (Index >= KekCount) { + return EFI_SECURITY_VIOLATION; + } +// Authenticate + Status = VerifyDataPayload (Data, DataSize, CertBlock->PublicKey); +//AVAR_TRACE((TRACE_ALWAYS,"KEK VerifyPayload %r\n",Status)); + + return Status; +} +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyDataPayload +// +// Description: +// Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type. +// Follow the steps in UEFI2.2. This function does signature +// authetication and based on the results returns Status. +// +// Input: +// IN VOID *Data - pointer to the Var data +// IN UINTN DataSize - size of Var data +// UINT8 *PubKey - PublicKey used for Sig verification. +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS VerifyDataPayload ( + IN VOID *Data, + IN UINTN DataSize, + IN UINT8 *PubKey +) +{ + EFI_STATUS Status; + EFI_VARIABLE_AUTHENTICATION *CertData; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + UINT8 Digest[HASH_SHA256_LEN]; + UINT8 *Addr[2]; + UINTN Len[2]; + UINTN CertHdrSize; + + CRYPT_HANDLE PublicKey; + CRYPT_HANDLE HashToVerify; + + CertData = (EFI_VARIABLE_AUTHENTICATION *)Data; +// CertHdrSize = AUTHINFO_SIZE(Data); +// SCT 2.3.1. TW UEFI Plugfest BUG with listing of a Cert Size in Cert->AuthInfo.Hdr.dwLength + CertHdrSize = 0x230; + + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256*)&(CertData->AuthInfo.CertData); + + // + // Hash data payload with SHA256. + // + Addr[0] = (UINT8*) Data + (CertHdrSize) ; + Len[0] = DataSize - (CertHdrSize); + Addr[1] = (UINT8*)&(CertData->MonotonicCount); + Len[1] = sizeof(UINT64); + Status = mDigitalSigProtocol->Hash(mDigitalSigProtocol, + &gEfiHashAlgorithmSha256Guid, + 2, Addr, Len, (UINT8*)&Digest[0]); + if (EFI_ERROR(Status)) + return Status; + + PublicKey.AlgGuid = gEfiCertRsa2048Guid; + PublicKey.BlobSize = EFI_CERT_TYPE_RSA2048_SIZE; + PublicKey.Blob = PubKey;//(UINT8*)&(CertData->AuthInfo.CertData.PublicKey); + + HashToVerify.AlgGuid = gEfiHashAlgorithmSha256Guid; + HashToVerify.BlobSize = SHA256_DIGEST_SIZE; + HashToVerify.Blob = &Digest[0]; + + Status = mDigitalSigProtocol->Pkcs1Verify( + mDigitalSigProtocol, + &PublicKey, + &HashToVerify, + (UINT8*)&(CertBlock->Signature), + EFI_CERT_TYPE_RSA2048_SHA256_SIZE, EFI_CRYPT_RSASSA_PKCS1V15/*EFI_CRYPT_RSASSA_PSS*/); + + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: FindInSignatureDb +// +// Description: +// For variables with GUID EFI_IMAGE_SECURITY_DATABASE_GUID +// (i.e. where the data buffer is formatted as EFI_SIGNATURE_LIST), +// the driver shall not perform an append of EFI_SIGNATURE_DATA values +// that are already part of the existing variable value (Note: This situation +// is not considered an error, and shall in itself not cause a status code other +// than EFI_SUCCESS to be returned or the timestamp associated with the variable not +// to be updated). +// +// Input: +// EFI_GUID *VendorGuid Variable vendor GUID. +// IN UINT32 Attributes - Attributes of the Var +// VOID *Data - pointer to data block within AutVar Data +// UINTN *DataSize - ptr to size of data block +// VOID *SigDb - current SigDb +// UINTN SigDbSize +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS FindInSignatureDb ( + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID *Data, + IN OUT UINTN *DataSize, + IN VOID *SigDb, + IN UINTN SigDbSize +){ + EFI_SIGNATURE_LIST *SigList; + EFI_SIGNATURE_LIST *SigListNew; + EFI_SIGNATURE_DATA *SigItem; + EFI_SIGNATURE_DATA *SigItemNew; + UINT32 SigCount; + UINT32 Index; + UINT32 SigCountNew; + UINT32 IndexNew; + + UINTN SigNewSize; + BOOLEAN bSigMatch; + // Is Append & SigDB + if ( (SigDb && SigDbSize) && + ((Data != SigDb) && (Attributes & EFI_VARIABLE_APPEND_WRITE)) && + // Validate Signature List integrity + !EFI_ERROR(ValidateSignatureList (Data, *DataSize)) + ) { + SigList = (EFI_SIGNATURE_LIST *)SigDb; + SigListNew = (EFI_SIGNATURE_LIST *)Data; +AVAR_TRACE((TRACE_ALWAYS,"FindInDB(x)\nDataSize In %d (0x%X)\n",*DataSize,*DataSize)); + // + // Enumerate all Sig items in this list to verify the variable certificate data. + // + // + // scan through multiple Sig Lists in DB exist. + while ((SigDbSize > 0) && (SigDbSize >= SigList->SignatureListSize)) { + SigCount = (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize; + SigItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize); +//AVAR_TRACE((TRACE_ALWAYS,"Org SigList Count: %d, SigSize %X\n", SigCount, SigList->SignatureSize)); + // scan through multiple Sig Lists in NewSigList. + for (Index = 1; Index <= SigCount; Index++) { +////AVAR_TRACE((TRACE_ALWAYS,"OrgCert %d, Data %X\n",Index, *(UINT32*)SigItem->SignatureData)); + SigListNew = (EFI_SIGNATURE_LIST *)Data; + SigNewSize = *DataSize; + while ((SigNewSize > 0) && (SigNewSize >= SigListNew->SignatureListSize)) { + bSigMatch = FALSE; + SigItemNew = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigListNew + sizeof (EFI_SIGNATURE_LIST) + SigListNew->SignatureHeaderSize); + SigCountNew = (SigListNew->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigListNew->SignatureHeaderSize) / SigListNew->SignatureSize; + if (!guidcmp ((EFI_GUID*) &(SigList->SignatureType), (EFI_GUID*)&(SigListNew->SignatureType)) && + SigList->SignatureSize == SigListNew->SignatureSize) { +//AVAR_TRACE((TRACE_ALWAYS,"New SigDb Size %X\nNew SigList Count: %d, SigSize %X\n", SigNewSize, SigNewCount, SigNewList->SignatureSize)); + // loop through all instances of NewSigList->SigData. + for (IndexNew = 1; IndexNew <= SigCountNew; IndexNew++) { +////AVAR_TRACE((TRACE_ALWAYS,"NewCert %d, Data %X\n",IndexNew, *(UINT32*)SigNewItem->SignatureData)); + if (MemCmp (SigItem->SignatureData, SigItemNew->SignatureData, SigList->SignatureSize-sizeof(EFI_GUID)) == 0) { +//AVAR_TRACE((TRACE_ALWAYS,"---> match found!!!\n")); +//AVAR_TRACE((TRACE_ALWAYS,"OrgCert %4d, Data %X\n",Index, *(UINT32*)SigItem->SignatureData)); +//AVAR_TRACE((TRACE_ALWAYS,"NewCert %4d, Data %X\n",IndexNew, *(UINT32*)SigNewItem->SignatureData)); + if(SigCountNew == 1) { + // only 1 SigData per SigList - discard this SigList + bSigMatch = TRUE; +//AVAR_TRACE((TRACE_ALWAYS,"Before: DataSize=%x\nAfter : DataSize=%x\n", *DataSize, *DataSize-SigNewList->SignatureListSize)); + // 1. Decrease *Datasize by SigNewList->SignatureSize + SigNewSize -= SigListNew->SignatureListSize; + *DataSize -= SigListNew->SignatureListSize; + // 2. replace this SigData block with data following it + MemCpy (SigListNew, (void*)((UINTN)SigListNew+SigListNew->SignatureListSize), SigNewSize); + // 3. Skip to next SigListNew + break; + } else { + // more then 1 - discard this SigData + // 1. replace this SigData block with data following it + MemCpy (SigItemNew, (void*)((UINTN)SigItemNew+SigListNew->SignatureSize), ((UINTN)Data+*DataSize)-((UINTN)SigItemNew+SigListNew->SignatureSize)); + // 2. Decrease SigNewList->SignatureListSize by SigNewList->SignatureSize + SigListNew->SignatureListSize-=SigListNew->SignatureSize; + *DataSize-=SigListNew->SignatureSize; +//AVAR_TRACE((TRACE_ALWAYS,"Upd SignatureListSize=%x, DataSize=%x\n",SigNewList->SignatureListSize, *DataSize)); + // 3. If this is last SigData element + if((SigListNew->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigListNew->SignatureHeaderSize)==0) + { +//AVAR_TRACE((TRACE_ALWAYS,"SigList is Empty!\n")); + break; + } + // 4. Skip incrementing of SigNewItem + continue; + } + } // if cmp + SigItemNew = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigItemNew + SigListNew->SignatureSize); + } // for SigNewItem + } // if guid + // Skip incrementing of SigNewList if bSigListMatch is found - we already on next siglist + if(!bSigMatch) { + SigNewSize -= SigListNew->SignatureListSize; + SigListNew = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigListNew + SigListNew->SignatureListSize); + } + } // while SigNewList + SigItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigItem + SigList->SignatureSize); + } // for SigItem + SigDbSize -= SigList->SignatureListSize; + SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize); + } // while SigList + +AVAR_TRACE((TRACE_ALWAYS,"DataSize Out: %d (0x%X)\n",*DataSize, *DataSize)); + if(*DataSize==0) + return EFI_ALREADY_STARTED; + +AVAR_TRACE((TRACE_ALWAYS,"APPEND OK!\n")); + } + + return EFI_SUCCESS; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyVariable1 +// +// Description: +// Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type. +// Follow the steps in UEFI2.2. +// This function is called every time variable with +// EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute is +// created, updated or deleted. This function does all necessary +// authetication checks and based on the results returns Status. +// Also it returns the Mc Hash of PublicKey from Variable's AuthInfo Hdr +// +// Input: +// CHAR16 *VariableName Name of Variable to be found. +// EFI_GUID *VendorGuid Variable vendor GUID. +// IN UINT32 Attributes - Attributes of the Var +// VOID **Data - pointer to data block within AutVar Data +// UINTN *DataSize - size of data block +// VOID *OldData - pointer to Existing in NVRAM data block +// UINTN OldDataSize - size of data block +// UINT64 ExtFlags.MonotonicCount - value of MC or TIME stamp +// UINT8 ExtFlags.KeyHash[32] - pointer to memory, allocated by caller, +// where Hash of Public Key will be returned. +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS VerifyVariable1 ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID **Data, + IN UINTN *DataSize, + IN VOID *OldData, + IN UINTN OldDataSize, + IN OUT EXT_SEC_FLAGS *ExtFlags +){ + EFI_STATUS Status; + + VOID *RealData; + EFI_VARIABLE_AUTHENTICATION *CertData; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + UINT8 *PubKey, *PubKeyHash; + UINTN CertHdrSize; + UINTN Size; + BOOLEAN IsSigListVar; + BOOLEAN IsPk; + + RealData = *Data; + Status = EFI_SUCCESS; + IsSigListVar = TRUE; + IsPk = FALSE; + +// must have Auth attribute to go deeper + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) + return EFI_INVALID_PARAMETER; + + if(*DataSize < sizeof(EFI_VARIABLE_AUTHENTICATION)) + return EFI_SECURITY_VIOLATION; + +// specific for EFI_VARIABLE_AUTHENTICATION mode variables +//--->>> + CertData = (EFI_VARIABLE_AUTHENTICATION *) *Data; + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256*)&(CertData->AuthInfo.CertData); +// SCT 2.3.1 TW Plugfest BUG with listing of a Cert Size in Cert->AuthInfo.Hdr.dwLength +// 0x22b vs 0x230 +// CertHdrSize = AUTHINFO_SIZE(CertData);//(CertData->AuthInfo.Hdr.Hdr.dwLength + sizeof(CertData->MonotonicCount)); + AVAR_TRACE((TRACE_ALWAYS,"VerifyVariable CertHdr Size 0x%x (expected(0x230)\n",AUTHINFO_SIZE(CertData))); + + CertHdrSize = 0x230; + + // + // wCertificateType should be WIN_CERT_TYPE_EFI_GUID. + // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256. + // + if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) || + guidcmp ((EFI_GUID*) &(CertData->AuthInfo.CertType), &gEfiCertTypeRsa2048Sha256Guid) + ) { + // + // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION. + // + AVAR_TRACE((TRACE_ALWAYS,"VerifyVariable AuthHdr GUID test Fails\nWinCert_Type\nExpected %x\nReceived %x\nGUID\nExpected %g\nReceived %g\n",WIN_CERT_TYPE_EFI_GUID, CertData->AuthInfo.Hdr.wCertificateType, gEfiCertTypeRsa2048Sha256Guid, &(CertData->AuthInfo.CertType))); +// SCT 2.3.1 TW Plugfest uses wrong GUID + return EFI_SECURITY_VIOLATION; + } + + if(*DataSize < CertHdrSize) + { +AVAR_TRACE((TRACE_ALWAYS,"VerifyVariable DataSize test fails: DataSize(%x) < AuthHdrSize (%x)\n", *DataSize, CertHdrSize)); + return EFI_SECURITY_VIOLATION; + } + // + // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // +AVAR_TRACE((TRACE_ALWAYS,"Check MC:\nOld=%x\nNew=%x\n",ExtFlags->Mc, CertData->MonotonicCount)); + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && + (OldData && ExtFlags->Mc >= CertData->MonotonicCount) + ) { + AVAR_TRACE((TRACE_ALWAYS,"Failed\n")); + return EFI_SECURITY_VIOLATION; + } +AVAR_TRACE((TRACE_ALWAYS,"Pass\n")); + +// AppendWrite: Only update Timestamp if New one is greater then current + if( (Attributes & EFI_VARIABLE_APPEND_WRITE) && + (OldData && ExtFlags->Mc > CertData->MonotonicCount) + ); + else + ExtFlags->Mc = CertData->MonotonicCount; + // + // Process PK, KEK, Sig db separately. + // + if (IsPkVar(VariableName, VendorGuid)){ + IsPk = TRUE; + Status = ProcessVarWithPk (*Data, *DataSize, Attributes, TRUE); + } else if (IsKekVar(VariableName, VendorGuid)) { + Status = ProcessVarWithPk (*Data, *DataSize, Attributes, FALSE); + } else if (IsDbVar(VendorGuid)) { + Status = ProcessVarWithKek (*Data, *DataSize, Attributes); + // verify process db(x) with one of KEK keys or if not found within KEK - with PK + if (Status == EFI_SECURITY_VIOLATION) + Status = ProcessVarWithPk (*Data, *DataSize, Attributes, FALSE); + } else { + IsSigListVar = FALSE; + PubKey = &(CertBlock->PublicKey[0]); + PubKeyHash = &PublicKeyHashArray[0]; + // Verify SelfSigned variable is signed with a valid Key + Status = VerifyDataPayload (*Data, *DataSize, PubKey); + if (!EFI_ERROR(Status)) { + + Size = RSA2048_PUB_KEY_LEN; + Status = mDigitalSigProtocol->Hash(mDigitalSigProtocol, + &gEfiHashAlgorithmSha256Guid, + 1, &PubKey, (const UINTN*)&Size, PubKeyHash); + + if (OldData && MemCmp(&ExtFlags->KeyHash[0], PubKeyHash, HASH_SHA256_LEN)){ +//AVAR_TRACE((TRACE_ALWAYS,"Self Signed MC Var Key Compare FAILED!\n")); + return EFI_SECURITY_VIOLATION; + } + // Setting key Hash for self signed variables + MemCpy(&ExtFlags->KeyHash[0], PubKeyHash, HASH_SHA256_LEN); + } + } + if (EFI_ERROR(Status)) + return EFI_SECURITY_VIOLATION; + + *DataSize = *DataSize - CertHdrSize; + *Data = (UINT8*)RealData + CertHdrSize; + + if(IsSigListVar == TRUE) { + + // Validate Signature List integrity + if(*DataSize && EFI_ERROR(ValidateSignatureList (*Data, *DataSize))) + return EFI_SECURITY_VIOLATION; + // + // If delete PK in user mode -> change to setup mode. + // If enroll PK in setup mode -> change to user mode. + // + if(IsPk) { + if (*DataSize == 0) + UpdatePlatformMode (SETUP_MODE); + else + UpdatePlatformMode (USER_MODE); + } + } + return Status; +} + +//<AMI_PHDR_START> +//---------------------------------------------------------------------------- +// Procedure: VerifyVariable +// +// Description: +// This function is called every time variable with +// EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and +// EFI_VARIABLE_AUTHENTICATED_TIME_BASED_ACCESS attributes +// created, updated or deleted. This function does all necessary +// authetication checks and based on the results returns Status. +// Also it returns the Mc Hash of PublicKey from Variable's AuthInfo Hdr +// +// Input: +// CHAR16 *VariableName Name of Variable to be found. +// EFI_GUID *VendorGuid Variable vendor GUID. +// IN UINT32 Attributes - Attributes of the Var +// VOID **Data - pointer to data block within AutVar Data +// UINTN *DataSize - size of data block +// VOID *OldData - pointer to Existing in NVRAM data block +// UINTN OldDataSize - size of data block +// UINT64 ExtFlags.MonotonicCount - value of MC or TIME stamp +// UINT8 ExtFlags.KeyHash[32] - pointer to memory, allocated by caller, +// where Hash of Public Key will be returned. +// +// Output: EFI_STATUS +// +//---------------------------------------------------------------------------- +//<AMI_PHDR_END> +EFI_STATUS VerifyVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 *Attributes, + IN VOID **Data, + IN UINTN *DataSize, + IN VOID *OldData, + IN UINTN OldDataSize, + IN OUT EXT_SEC_FLAGS *ExtSecFlags +){ + EFI_STATUS Status; + UINT32 AuthAttributes; + UINT64 OldMC; + + Status = EFI_SUCCESS; + mCustomMode = 0; + +//AVAR_TRACE((TRACE_ALWAYS,"Var Name: %S, Attr=%X, Data=%X, Size=%d\n", VariableName, *Attributes, *Data, *DataSize)); + + // bypass Var R/O check when updating + // SetupMode and SecureBoot variables after changing of a PK + if(mSetupMode == SETUP_MODE) { +// Faking presense of NV attribute for SetupMode in order to meet UEFI requirement +// to display SetupMode state even in runtime (after exit boot services) +// AuthAttributes = *Attributes & (~EFI_VARIABLE_NON_VOLATILE); +// *Attributes = AuthAttributes; +// *Attributes &= (UINT32)(~EFI_VARIABLE_NON_VOLATILE); + // Re-lock access to runtime protected vars + mSetupMode = USER_MODE; + return Status;//EFI_SUCCESS; + } + + // existing reserved variables are RO!!! + if(OldData && OldDataSize && IsReservedVariableName(VariableName, VendorGuid)) + return EFI_WRITE_PROTECTED; + + AuthAttributes = ExtSecFlags->AuthFlags & UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES; + + while ((*Attributes & UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES) + // Old Variable with no attributes can be erased after proper AuthHeader validation + // EIP88439: irrespective of SetupMode, only properly formatted Auth Variable can be erased + || (AuthAttributes) + ){ + // get mPlatformMode + GetPlatformMode (); + + // check if both attributes are set + if ((*Attributes & UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES) == + UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES + ) + { Status = EFI_INVALID_PARAMETER; break;} + +#if USER_MODE_POLICY_OVERRIDE == 1 + // ignore Variable Authentication rules while in Physical User Presence + mCustomMode = PhysicalUserPresent(); + AVAR_TRACE((TRACE_ALWAYS,"Physical User %s\n", + (mCustomMode?"detected - suppress Variable Authentication":"not detected"))); + if (mCustomMode) { + if(*DataSize==0 || *Data==NULL) { + if(IsPkVar(VariableName, VendorGuid)) + UpdatePlatformMode(SETUP_MODE); + + Status = EFI_SUCCESS; + break; + } + } +#endif +// Old - nonAuth, New - nonAuth - exit with EFI_SUCCESS +// Old - nonAuth, New - Auth - Continue with new Auth attr +// Old - Auth, New - nonAuth - if *Attribs=0 - Erase in progress if in SetupMode +// else EFI_SECURITY_VIOLATION +// Old - Auth, New - Auth - Continue if AuthAttr matching +// else EFI_SECURITY_VIOLATION +// OldVar AuthAttributes mismatch + if( AuthAttributes && *Attributes && + !(AuthAttributes & (*Attributes & UEFI23_1_AUTHENTICATED_VARIABLE_ATTRIBUTES)) + ) + // Attribute mismatch + { Status = EFI_SECURITY_VIOLATION; break;} + + // else in process of erasing or Setting AuthVar + + AuthAttributes |= *Attributes; + OldMC = ExtSecFlags->Mc; + + if(*DataSize==0 || *Data==NULL) + { Status = EFI_SECURITY_VIOLATION; break;} + + if(!mDigitalSigProtocol) + { Status = EFI_UNSUPPORTED; break;} + +//AVAR_TRACE((TRACE_ALWAYS,"Verify AuthVar: %S, Attr=%X, Data=%X, Size=%d\n", VariableName, *Attributes, *Data, *DataSize)); + if (AuthAttributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + Status = VerifyVariable2(VariableName, VendorGuid, AuthAttributes, Data, DataSize, OldData, OldDataSize, ExtSecFlags); + else + Status = VerifyVariable1(VariableName, VendorGuid, AuthAttributes, Data, DataSize, OldData, OldDataSize, ExtSecFlags); +//AVAR_TRACE((TRACE_ALWAYS, "Exit - %r, Data - %X, Size %d, Attributes %x\n",Status, *Data, *DataSize, *Attributes)); + if (EFI_ERROR(Status)) + break; + + // Find out if New Var is a Signature Db and the Sig already present in current Sig DB Variable + // bail out SetVar if present - nothing to change + Status = FindInSignatureDb(VendorGuid, *Attributes, *Data, DataSize, OldData, OldDataSize); + if (EFI_ERROR(Status)) { + // Only update the Timestamp if new Sig found in OldSig list + if(OldMC != ExtSecFlags->Mc) + { + *DataSize = 0; + Status = EFI_SUCCESS; + + } + // else Variable not changed, abort the SetVar + } + + break; + } // end while loop + + return Status; // variable not changed +} + +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.cif b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.cif new file mode 100644 index 0000000..4bc04f6 --- /dev/null +++ b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.cif @@ -0,0 +1,12 @@ +<component> + name = "NVRAM. Authenticated Variables" + category = ModulePart + LocalRoot = "Core\EM\SecurityPkg\AuthenticatedVariable\" + RefName = "AuthVariable" +[files] +"AuthVariable.sdl" +"AuthVariable.mak" +"AuthVariable.c" +"Auth2Variable.c" +"AuthVariable.h" +<endComponent> diff --git a/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.h b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.h new file mode 100644 index 0000000..38a4cfa --- /dev/null +++ b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.h @@ -0,0 +1,351 @@ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Pkwy, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** + +//********************************************************************** +// $Header: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/AuthVariable.h 17 3/09/15 4:27p Alexp $ +// +// $Revision: 17 $ +// +// $Date: 3/09/15 4:27p $ +//********************************************************************** +// Revision History +// ---------------- +// $Log: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/AuthVariable.h $ +// +// 17 3/09/15 4:27p Alexp +// Update year 2015 in the file header +// +// 16 2/08/13 5:15p Alexp +// Optimized the code flow fro Auth2 Variables. +// +// 15 12/07/12 3:45p Alexp +// define AVAR_TRACE macro +// +// 14 11/19/12 4:41p Alexp +// Fix for Win8 SecureBoot logo requirement: restore Secure Boot state +// across flash updates. +// Move all secure boot Setup settings to a separate varstore variable. +// Preserve var across re-flash +// +// 13 10/16/12 3:45p Alexp +// Implemented R/O Variables support via fixed and OEM defined (eLink) +// lists +// +// 12 8/27/12 10:42a Alexp +// GetmSecureBootSupport(): +// Add input parameter SetupMode to control state of +// Setup Flag:SecureBootSupport +// +// 11 2/27/12 6:52p Alexp +// removed AuthenticatedVariableServiceInitialize() +// +// 10 2/03/12 9:56a Alexp +// EIP#82122. WHCK "Secure Boot Manual Logo Test" fails +// Fixed Append logic to process multiple sig data instances in a single +// Signature List block +// New logic will remove dupplicated certs and update new SigList header. +// +// 9 8/18/11 5:59p Alexp +// renamed func SecureBootSupport() +// +// 8 8/18/11 4:53p Alexp +// removed AuthVar mailbox +// +// 7 8/16/11 7:18p Alexp +// added Mailbox variable AuthVarMAilbox to syncronize local state between +// DXE and SMM AuthVariable services +// +// 6 8/05/11 3:12p Alexp +// add mkime prototyte define +// +// 5 8/04/11 7:12p Alexp +// +// 4 6/30/11 4:02p Alexp +// added Callback event on Setup Mode change request form Security Setup +// Page. +// +// 3 6/24/11 7:04p Alexp +// fixed ValidateSignatureList () logic. Added Certificate RSA2048 to +// supported Signatures +// +// 2 6/23/11 6:19p Alexp +// Added ValidateSigList() function +// +// 5 6/09/11 5:49p Alexp +// add new parameter to ValidateSelfSigned - Operation. +// +// 4 6/02/11 5:52p Alexp +// add ValidateSelfSigned certificates func definition +// +// 2 5/19/11 4:59p Alexp +// Major code revamp to be able to handle of handling Secure vars in Setup +// Mode +// TBD: TimeBased certificates from Msft fail to process. Not compiled as +// Authenticode format +// +// 4 3/31/11 6:28p Alexp +// Add SHA256 to supported SignatureList +// +// +//********************************************************************** +//<AMI_FHDR_START> +// +// Name: AuthVariable.h Implement authentication services for the authenticated variable +// service in UEFI2.2+ +// +// Description: +// +//<AMI_FHDR_END> +//********************************************************************** + +#ifndef _AUTHVARIABLE_H_ +#define _AUTHVARIABLE_H_ + +#include <Efi.h> +// All are EDKII defined headers +#include "WinCertificate.h" +#include "ImageAuthentication.h" +#include <Protocol/Hash.h> + +#define HASH_SHA256_LEN sizeof(EFI_SHA256_HASH) // 32 +#define HASH_SHA1_LEN sizeof(EFI_SHA1_HASH) +#define RSA2048_PUB_KEY_LEN DEFAULT_RSA_KEY_MODULUS_LEN // 256 +#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE RSA2048_PUB_KEY_LEN +#define EFI_CERT_TYPE_RSA2048_SIZE RSA2048_PUB_KEY_LEN + +// +// EFI_VARIABLE_AUTHENTICATION descriptor +// +// A authentication authentication method descriptor template +// AuthInfo is a WIN_CERTIFICATE using the wCertificateType +// WIN_CERTIFICATE_UEFI_GUID and the CertType +// EFI_CERT_TYPE_RSA2048_SHA256. +// +#ifndef EFI_VARIABLE_AUTHENTICATION +typedef struct { + UINT64 MonotonicCount; + WIN_CERTIFICATE_UEFI_GUID AuthInfo; +} EFI_VARIABLE_AUTHENTICATION; +#endif + +// +// EFI_VARIABLE_AUTHENTICATION_2 descriptor +// +// A time-based authentication method descriptor template +// +#ifndef EFI_VARIABLE_AUTHENTICATION_2 +typedef struct { + EFI_TIME TimeStamp; + WIN_CERTIFICATE_UEFI_GUID AuthInfo; +} EFI_VARIABLE_AUTHENTICATION_2; +#endif + +/// +/// Size of AuthInfo prior to the data payload +/// +#define AUTHINFO_SIZE(Cert) (((UINTN)(((EFI_VARIABLE_AUTHENTICATION *) Cert)->AuthInfo.Hdr.dwLength)) + sizeof(UINT64)) +#define AUTHINFO_2_SIZE(Cert) (((UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) Cert)->AuthInfo.Hdr.dwLength)) + sizeof(EFI_TIME)) + +#ifdef EFI_DEBUG +#define AVAR_TRACE(Arguments) { if (!AVarRuntime) TRACE(Arguments); } +#else +#define AVAR_TRACE(Arguments) +#endif + + +typedef enum { + IsPkVarType = 0, + IsKekVarType, + IsDbVarType, + IsPrivateVarType +} AUTHVAR_TYPE; + +VOID AuthVariableServiceInitSMM (VOID ); +VOID AuthVariableServiceInit ( VOID ); + +EFI_STATUS VerifyVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 *Attributes, + IN VOID **Data, + IN UINTN *DataSize, + IN VOID *OldData, + IN UINTN OldDataSize, + IN OUT EXT_SEC_FLAGS *ExtFlags + ); + +EFI_STATUS FindInSignatureDb ( + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID *Data, + IN UINTN *DataSize, + IN VOID *SigDB, + IN UINTN SigDBSize + ); + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Variable Auth Hdr EFI_VARIABLE_AUTHENTICATION +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EFI_STATUS VerifyVariable1 ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID **Data, + IN UINTN *DataSize, + IN VOID *OldData, + IN UINTN OldDataSize, + IN OUT EXT_SEC_FLAGS *ExtFlags + ); + +EFI_STATUS VerifyDataPayload ( + IN VOID *Data, + IN UINTN DataSize, + IN UINT8 *PubKey + ); + +EFI_STATUS ProcessVarWithPk ( + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN BOOLEAN IsPk + ); + +EFI_STATUS ProcessVarWithKek ( + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes + ); + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Variable Auth Hdr EFI_VARIABLE_AUTHENTICATION_2 +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EFI_STATUS VerifyVariable2 ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID **Data, + IN UINTN *DataSize, + IN VOID *OldData, + IN UINTN OldDataSize, + IN OUT EXT_SEC_FLAGS *ExtFlags + ); + +EFI_STATUS ValidateSelfSigned ( + IN UINT8 *Pkcs7Cert, + IN UINTN Pkcs7Cert_len, + IN OUT UINT8 **pDigest, + IN OUT UINTN *Digest_len, + IN UINT8 Operation + ); + +EFI_STATUS ConstructDataParameter ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN VOID *Data, + IN UINTN DataSize, + OUT UINT8 *pDigest, + OUT UINTN *Digest_len, + IN UINT8 Mutex + ); + +EFI_STATUS ProcessVarWithPk2 ( + IN UINT8 *Pkcs7Cert, + IN UINTN Pkcs7Cert_len, + IN UINT8 *pDigest, + IN UINTN Digest_len + ); + +EFI_STATUS ProcessVarWithKek2 ( + IN UINT8 *Pkcs7Cert, + IN UINTN Pkcs7Cert_len, + IN UINT8 *pDigest, + IN UINTN Digest_len + ); + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Misc auxilary functions +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +INTN StrCmp16(CHAR16 *Dest, CHAR16 *Src); +UINT32 StrSize16(CHAR16 *String); + +BOOLEAN IsPkVar( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ); + +BOOLEAN IsKekVar( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ); + +BOOLEAN IsDbVar( + IN EFI_GUID *VendorGuid + ); + +EFI_STATUS GetPlatformMode ( + VOID + ); + +EFI_STATUS GetmSecureBootSupport ( + UINT8 + ); + +VOID UpdatePlatformMode ( + IN UINT8 Mode + ); + +EFI_STATUS ValidateSignatureList ( + IN VOID *Data, + IN UINTN DataSize +); + +UINT64 mkLongTime ( + EFI_TIME *TimeStamp +); +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// NVRAM module defined auxilary functions +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +EFI_STATUS FindVariable( + IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, OUT VOID **Data + ); + +EFI_STATUS DxeSetVariable( + IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data +); +EFI_STATUS DxeGetVariable( + IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, OUT VOID *Data +); + +#endif // _AUTHVARIABLE_H_ +//********************************************************************** +//********************************************************************** +//** ** +//** (C)Copyright 1985-2015, American Megatrends, Inc. ** +//** ** +//** All Rights Reserved. ** +//** ** +//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +//** ** +//** Phone: (770)-246-8600 ** +//** ** +//********************************************************************** +//********************************************************************** diff --git a/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.mak b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.mak new file mode 100644 index 0000000..5633611 --- /dev/null +++ b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.mak @@ -0,0 +1,89 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2012, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/AuthVariable.mak 6 8/15/13 11:26a Alexp $ +# +# $Revision: 6 $ +# +# $Date: 8/15/13 11:26a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/SOURCE/Modules/SecureBoot_WIN8/AuthenticatedVariable_efi/AuthVariable.mak $ +# +# 6 8/15/13 11:26a Alexp +# Link AmyCryptoLib +# +# 5 11/19/12 4:41p Alexp +# Fix for Win8 SecureBoot logo requirement: restore Secure Boot state +# across flash updates. +# Move all secure boot Setup settings to a separate varstore variable. +# Preserve var across re-flash +# +# 4 10/16/12 3:45p Alexp +# Implemented R/O Variables support via fixed and OEM defined (eLink) +# lists +# +# 3 9/19/12 4:29p Alexp +# New feature: add facility to link external Physical User Presence +# detect hooks via eLink:PhysicalUserPresenceDetect +# +# 2 6/30/11 4:02p Alexp +# added Callback event on Setup Mode change request form Security Setup +# Page. +# +# 1 6/13/11 5:25p Alexp +# +# 2 5/11/11 1:03p Alexp +# filled in file header text +#************************************************************************* +#<AMI_FHDR_START> +# +# Name: AuthVariable.mak +# +# Description: +# Link Authenticated Variable extension to NVRAM driver +# +#<AMI_FHDR_END> +#************************************************************************* +NvramDxeBin : $(BUILD_DIR)\$(NVRAM_DIR)\AUTHVARIABLE.obj $(BUILD_DIR)\$(NVRAM_DIR)\AUTH2VARIABLE.obj $(CRYPTOLIB) + +AuthVariable_INCLUDES= \ + /I $(AuthVariable_DIR) \ + /I $(SecureBoot_DIR) \ + /I $(NVRAM_DIR) + +AuthVariable_LISTS= \ + /D PHYSICAL_USER_PRESENCE_DETECT_LIST=$(PhysicalUserPresenceDetect) \ + /D OEM_READONLY_VAR_LIST=$(OemReadOnlyVariableList) + +$(BUILD_DIR)\$(NVRAM_DIR)\AUTHVARIABLE.obj $(BUILD_DIR)\$(NVRAM_DIR)\AUTH2VARIABLE.obj: \ + $(AuthVariable_DIR)\AUTHVARIABLE.c $(AuthVariable_DIR)\AUTH2VARIABLE.c + if not exist $(*D) mkdir $(*D) + $(CC) $(CFLAGS) $(AuthVariable_LISTS) $(AuthVariable_INCLUDES) /Fo$@ $(AuthVariable_DIR)\$(*B).c + +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2012, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.sdl b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.sdl new file mode 100644 index 0000000..e90eddc --- /dev/null +++ b/Core/EM/SecurityPkg/AuthenticatedVariable/AuthVariable.sdl @@ -0,0 +1,44 @@ +TOKEN + Name = "AuthVariable_SUPPORT" + Value = "1" + Help = "Main switch to enable AuthVariable support in Project" + TokenType = Boolean + TargetH = Yes + TargetMAK = Yes + Master = Yes +End + +TOKEN + Name = "USER_MODE_POLICY_OVERRIDE" + Value = "1" + Help = "Ignore Variable Authentication rules until AuthVarLock(ready to boot) event\A back door for Administrative Users to modify Secure Variables from Key Management Setup Page" + TokenType = Boolean + TargetH = Yes +End + +PATH + Name = "AuthVariable_DIR" + Help = "Path to AuthVariable Module in Project" +End + +MODULE + Help = "Includes AuthVariable.mak to Project" + File = "AuthVariable.mak" +End + + +ELINK + Name = "PhysicalUserPresenceDetect" + InvokeOrder = ReplaceParent +End + +ELINK + Name = "AuthVarAdminUserPresent," + InvokeOrder = AfterParent + Parent = PhysicalUserPresenceDetect +End + +ELINK + Name = "OemReadOnlyVariableList" + InvokeOrder = ReplaceParent +End |