12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384 |
- /** @file
- Implement authentication services for the authenticated variables.
- Caution: This module requires additional review when modified.
- This driver will have external input - variable data. It may be input in SMM mode.
- This external input must be validated carefully to avoid security issue like
- buffer overflow, integer overflow.
- Variable attribute should also be checked to avoid authentication bypass.
- The whole SMM authentication variable design relies on the integrity of flash part and SMM.
- which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
- may not be modified without authorization. If platform fails to protect these resources,
- the authentication service provided in this driver will be broken, and the behavior is undefined.
- ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
- variable authentication.
- VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.
- They will do basic validation for authentication data structure, then call crypto library
- to verify the signature.
- Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
- Copyright (c) Microsoft Corporation.
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "AuthServiceInternal.h"
- #include <Protocol/VariablePolicy.h>
- #include <Library/VariablePolicyLib.h>
- //
- // Public Exponent of RSA Key.
- //
- CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
- CONST UINT8 mSha256OidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
- //
- // Requirement for different signature type which have been defined in UEFI spec.
- // These data are used to perform SignatureList format check while setting PK/KEK variable.
- //
- EFI_SIGNATURE_ITEM mSupportSigItem[] = {
- // {SigType, SigHeaderSize, SigDataSize }
- { EFI_CERT_SHA256_GUID, 0, 32 },
- { EFI_CERT_RSA2048_GUID, 0, 256 },
- { EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },
- { EFI_CERT_SHA1_GUID, 0, 20 },
- { EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },
- { EFI_CERT_X509_GUID, 0, ((UINT32) ~0) },
- { EFI_CERT_SHA224_GUID, 0, 28 },
- { EFI_CERT_SHA384_GUID, 0, 48 },
- { EFI_CERT_SHA512_GUID, 0, 64 },
- { EFI_CERT_X509_SHA256_GUID, 0, 48 },
- { EFI_CERT_X509_SHA384_GUID, 0, 64 },
- { EFI_CERT_X509_SHA512_GUID, 0, 80 }
- };
- /**
- Finds variable in storage blocks of volatile and non-volatile storage areas.
- This code finds variable in storage blocks of volatile and non-volatile storage areas.
- If VariableName is an empty string, then we just return the first
- qualified variable without comparing VariableName and VendorGuid.
- @param[in] VariableName Name of the variable to be found.
- @param[in] VendorGuid Variable vendor GUID to be found.
- @param[out] Data Pointer to data address.
- @param[out] DataSize Pointer to data size.
- @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
- while VendorGuid is NULL.
- @retval EFI_SUCCESS Variable successfully found.
- @retval EFI_NOT_FOUND Variable not found
- **/
- EFI_STATUS
- AuthServiceInternalFindVariable (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- OUT VOID **Data,
- OUT UINTN *DataSize
- )
- {
- EFI_STATUS Status;
- AUTH_VARIABLE_INFO AuthVariableInfo;
- ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
- Status = mAuthVarLibContextIn->FindVariable (
- VariableName,
- VendorGuid,
- &AuthVariableInfo
- );
- *Data = AuthVariableInfo.Data;
- *DataSize = AuthVariableInfo.DataSize;
- return Status;
- }
- /**
- Update the variable region with Variable information.
- @param[in] VariableName Name of variable.
- @param[in] VendorGuid Guid of variable.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data.
- @param[in] Attributes Attribute value of the variable.
- @retval EFI_SUCCESS The update operation is success.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_WRITE_PROTECTED Variable is write-protected.
- @retval EFI_OUT_OF_RESOURCES There is not enough resource.
- **/
- EFI_STATUS
- AuthServiceInternalUpdateVariable (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes
- )
- {
- AUTH_VARIABLE_INFO AuthVariableInfo;
- ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
- AuthVariableInfo.VariableName = VariableName;
- AuthVariableInfo.VendorGuid = VendorGuid;
- AuthVariableInfo.Data = Data;
- AuthVariableInfo.DataSize = DataSize;
- AuthVariableInfo.Attributes = Attributes;
- return mAuthVarLibContextIn->UpdateVariable (
- &AuthVariableInfo
- );
- }
- /**
- Update the variable region with Variable information.
- @param[in] VariableName Name of variable.
- @param[in] VendorGuid Guid of variable.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data.
- @param[in] Attributes Attribute value of the variable.
- @param[in] TimeStamp Value of associated TimeStamp.
- @retval EFI_SUCCESS The update operation is success.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_WRITE_PROTECTED Variable is write-protected.
- @retval EFI_OUT_OF_RESOURCES There is not enough resource.
- **/
- EFI_STATUS
- AuthServiceInternalUpdateVariableWithTimeStamp (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes,
- IN EFI_TIME *TimeStamp
- )
- {
- EFI_STATUS FindStatus;
- VOID *OrgData;
- UINTN OrgDataSize;
- AUTH_VARIABLE_INFO AuthVariableInfo;
- FindStatus = AuthServiceInternalFindVariable (
- VariableName,
- VendorGuid,
- &OrgData,
- &OrgDataSize
- );
- //
- // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
- //
- if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
- if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
- ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
- (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
- (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)))
- {
- //
- // For variables with 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.
- //
- FilterSignatureList (
- OrgData,
- OrgDataSize,
- Data,
- &DataSize
- );
- }
- }
- ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
- AuthVariableInfo.VariableName = VariableName;
- AuthVariableInfo.VendorGuid = VendorGuid;
- AuthVariableInfo.Data = Data;
- AuthVariableInfo.DataSize = DataSize;
- AuthVariableInfo.Attributes = Attributes;
- AuthVariableInfo.TimeStamp = TimeStamp;
- return mAuthVarLibContextIn->UpdateVariable (
- &AuthVariableInfo
- );
- }
- /**
- Determine whether this operation needs a physical present user.
- @param[in] VariableName Name of the Variable.
- @param[in] VendorGuid GUID of the Variable.
- @retval TRUE This variable is protected, only a physical present user could set this variable.
- @retval FALSE This variable is not protected.
- **/
- BOOLEAN
- NeedPhysicallyPresent (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid
- )
- {
- // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables.
- if (IsVariablePolicyEnabled ()) {
- if ( (CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
- || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0)))
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- /**
- Determine whether the platform is operating in Custom Secure Boot mode.
- @retval TRUE The platform is operating in Custom mode.
- @retval FALSE The platform is operating in Standard mode.
- **/
- BOOLEAN
- InCustomMode (
- VOID
- )
- {
- EFI_STATUS Status;
- VOID *Data;
- UINTN DataSize;
- Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);
- if (!EFI_ERROR (Status) && (*(UINT8 *)Data == CUSTOM_SECURE_BOOT_MODE)) {
- return TRUE;
- }
- return FALSE;
- }
- /**
- Update platform mode.
- @param[in] Mode SETUP_MODE or USER_MODE.
- @return EFI_INVALID_PARAMETER Invalid parameter.
- @return EFI_SUCCESS Update platform mode successfully.
- **/
- EFI_STATUS
- UpdatePlatformMode (
- IN UINT32 Mode
- )
- {
- EFI_STATUS Status;
- VOID *Data;
- UINTN DataSize;
- UINT8 SecureBootMode;
- UINT8 SecureBootEnable;
- UINTN VariableDataSize;
- Status = AuthServiceInternalFindVariable (
- EFI_SETUP_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
- // variable storage reclaim at runtime.
- //
- mPlatformMode = (UINT8)Mode;
- CopyMem (Data, &mPlatformMode, sizeof (UINT8));
- if (mAuthVarLibContextIn->AtRuntime ()) {
- //
- // SecureBoot Variable indicates whether the platform firmware is operating
- // in Secure boot mode (1) or not (0), so we should not change SecureBoot
- // Variable in runtime.
- //
- return Status;
- }
- //
- // Check "SecureBoot" variable's existence.
- // If it doesn't exist, firmware has no capability to perform driver signing verification,
- // then set "SecureBoot" to 0.
- //
- Status = AuthServiceInternalFindVariable (
- EFI_SECURE_BOOT_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &Data,
- &DataSize
- );
- //
- // If "SecureBoot" variable exists, then check "SetupMode" variable update.
- // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
- // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
- //
- if (EFI_ERROR (Status)) {
- SecureBootMode = SECURE_BOOT_MODE_DISABLE;
- } else {
- if (mPlatformMode == USER_MODE) {
- SecureBootMode = SECURE_BOOT_MODE_ENABLE;
- } else if (mPlatformMode == SETUP_MODE) {
- SecureBootMode = SECURE_BOOT_MODE_DISABLE;
- } else {
- return EFI_NOT_FOUND;
- }
- }
- Status = AuthServiceInternalUpdateVariable (
- EFI_SECURE_BOOT_MODE_NAME,
- &gEfiGlobalVariableGuid,
- &SecureBootMode,
- sizeof (UINT8),
- EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
- //
- Status = AuthServiceInternalFindVariable (
- EFI_SECURE_BOOT_ENABLE_NAME,
- &gEfiSecureBootEnableDisableGuid,
- &Data,
- &DataSize
- );
- if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
- //
- // Create the "SecureBootEnable" variable as secure boot is enabled.
- //
- SecureBootEnable = SECURE_BOOT_ENABLE;
- VariableDataSize = sizeof (SecureBootEnable);
- } else {
- //
- // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
- // variable is not in secure boot state.
- //
- if (EFI_ERROR (Status)) {
- return EFI_SUCCESS;
- }
- SecureBootEnable = SECURE_BOOT_DISABLE;
- VariableDataSize = 0;
- }
- Status = AuthServiceInternalUpdateVariable (
- EFI_SECURE_BOOT_ENABLE_NAME,
- &gEfiSecureBootEnableDisableGuid,
- &SecureBootEnable,
- VariableDataSize,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
- );
- return Status;
- }
- /**
- Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
- @param[in] VariableName Name of Variable to be check.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Data Point to the variable data to be checked.
- @param[in] DataSize Size of Data.
- @return EFI_INVALID_PARAMETER Invalid signature list format.
- @return EFI_SUCCESS Passed signature list format check successfully.
- **/
- EFI_STATUS
- CheckSignatureListFormat (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize
- )
- {
- EFI_SIGNATURE_LIST *SigList;
- UINTN SigDataSize;
- UINT32 Index;
- UINT32 SigCount;
- BOOLEAN IsPk;
- VOID *RsaContext;
- EFI_SIGNATURE_DATA *CertData;
- UINTN CertLen;
- if (DataSize == 0) {
- return EFI_SUCCESS;
- }
- ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
- if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)) {
- IsPk = TRUE;
- } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||
- (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
- ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
- (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))))
- {
- IsPk = FALSE;
- } else {
- return EFI_SUCCESS;
- }
- SigCount = 0;
- SigList = (EFI_SIGNATURE_LIST *)Data;
- SigDataSize = DataSize;
- RsaContext = NULL;
- //
- // Walk through the input signature list and check the data format.
- // If any signature is incorrectly formed, the whole check will fail.
- //
- while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
- for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
- if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
- //
- // The value of SignatureSize should always be 16 (size of SignatureOwner
- // component) add the data length according to signature type.
- //
- if ((mSupportSigItem[Index].SigDataSize != ((UINT32) ~0)) &&
- ((SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize))
- {
- return EFI_INVALID_PARAMETER;
- }
- if ((mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0)) &&
- (SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize))
- {
- return EFI_INVALID_PARAMETER;
- }
- break;
- }
- }
- if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
- //
- // Undefined signature type.
- //
- return EFI_INVALID_PARAMETER;
- }
- if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
- //
- // Try to retrieve the RSA public key from the X.509 certificate.
- // If this operation fails, it's not a valid certificate.
- //
- RsaContext = RsaNew ();
- if (RsaContext == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- CertData = (EFI_SIGNATURE_DATA *)((UINT8 *)SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
- CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
- if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
- RsaFree (RsaContext);
- return EFI_INVALID_PARAMETER;
- }
- RsaFree (RsaContext);
- }
- if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
- return EFI_INVALID_PARAMETER;
- }
- SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
- SigDataSize -= SigList->SignatureListSize;
- SigList = (EFI_SIGNATURE_LIST *)((UINT8 *)SigList + SigList->SignatureListSize);
- }
- if (((UINTN)SigList - (UINTN)Data) != DataSize) {
- return EFI_INVALID_PARAMETER;
- }
- if (IsPk && (SigCount > 1)) {
- return EFI_INVALID_PARAMETER;
- }
- return EFI_SUCCESS;
- }
- /**
- Update "VendorKeys" variable to record the out of band secure boot key modification.
- @return EFI_SUCCESS Variable is updated successfully.
- @return Others Failed to update variable.
- **/
- EFI_STATUS
- VendorKeyIsModified (
- VOID
- )
- {
- EFI_STATUS Status;
- if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
- return EFI_SUCCESS;
- }
- mVendorKeyState = VENDOR_KEYS_MODIFIED;
- Status = AuthServiceInternalUpdateVariable (
- EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
- &gEfiVendorKeysNvGuid,
- &mVendorKeyState,
- sizeof (UINT8),
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- return AuthServiceInternalUpdateVariable (
- EFI_VENDOR_KEYS_VARIABLE_NAME,
- &gEfiGlobalVariableGuid,
- &mVendorKeyState,
- sizeof (UINT8),
- EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
- );
- }
- /**
- Process variable with platform key for verification.
- Caution: This function may receive untrusted input.
- This function may be invoked in SMM mode, and datasize and data are external input.
- This function will do basic validation, before parse the data.
- This function will parse the authentication carefully to avoid security issues, like
- buffer overflow, integer overflow.
- This function will check attribute carefully to avoid authentication bypass.
- @param[in] VariableName Name of Variable to be found.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data found. If size is less than the
- data, this value contains the required size.
- @param[in] Attributes Attribute value of the variable
- @param[in] IsPk Indicate whether it is to process pk.
- @return EFI_INVALID_PARAMETER Invalid parameter.
- @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
- check carried out by the firmware.
- @return EFI_SUCCESS Variable passed validation successfully.
- **/
- EFI_STATUS
- ProcessVarWithPk (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes OPTIONAL,
- IN BOOLEAN IsPk
- )
- {
- EFI_STATUS Status;
- BOOLEAN Del;
- UINT8 *Payload;
- UINTN PayloadSize;
- if (((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) ||
- ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0))
- {
- //
- // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
- // authenticated variable.
- //
- return EFI_INVALID_PARAMETER;
- }
- //
- // Init state of Del. State may change due to secure check
- //
- Del = FALSE;
- if ( (InCustomMode () && UserPhysicalPresent ())
- || ( (mPlatformMode == SETUP_MODE)
- && !(FeaturePcdGet (PcdRequireSelfSignedPk) && IsPk)))
- {
- Payload = (UINT8 *)Data + AUTHINFO2_SIZE (Data);
- PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
- if (PayloadSize == 0) {
- Del = TRUE;
- }
- Status = CheckSignatureListFormat (VariableName, VendorGuid, Payload, PayloadSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = AuthServiceInternalUpdateVariableWithTimeStamp (
- VariableName,
- VendorGuid,
- Payload,
- PayloadSize,
- Attributes,
- &((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->TimeStamp
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if ( (mPlatformMode != SETUP_MODE)
- || (FeaturePcdGet (PcdRequireSelfSignedPk) && IsPk))
- {
- Status = VendorKeyIsModified ();
- }
- } else if (mPlatformMode == USER_MODE) {
- //
- // Verify against X509 Cert in PK database.
- //
- Status = VerifyTimeBasedPayloadAndUpdate (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- Attributes,
- AuthVarTypePk,
- &Del
- );
- } else {
- //
- // Verify against the certificate in data payload.
- //
- Status = VerifyTimeBasedPayloadAndUpdate (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- Attributes,
- AuthVarTypePayload,
- &Del
- );
- }
- if (!EFI_ERROR (Status) && IsPk) {
- if ((mPlatformMode == SETUP_MODE) && !Del) {
- //
- // If enroll PK in setup mode, need change to user mode.
- //
- Status = UpdatePlatformMode (USER_MODE);
- } else if ((mPlatformMode == USER_MODE) && Del) {
- //
- // If delete PK in user mode, need change to setup mode.
- //
- Status = UpdatePlatformMode (SETUP_MODE);
- }
- }
- return Status;
- }
- /**
- Process variable with key exchange key for verification.
- Caution: This function may receive untrusted input.
- This function may be invoked in SMM mode, and datasize and data are external input.
- This function will do basic validation, before parse the data.
- This function will parse the authentication carefully to avoid security issues, like
- buffer overflow, integer overflow.
- This function will check attribute carefully to avoid authentication bypass.
- @param[in] VariableName Name of Variable to be found.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data found. If size is less than the
- data, this value contains the required size.
- @param[in] Attributes Attribute value of the variable.
- @return EFI_INVALID_PARAMETER Invalid parameter.
- @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
- check carried out by the firmware.
- @return EFI_SUCCESS Variable pass validation successfully.
- **/
- EFI_STATUS
- ProcessVarWithKek (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes OPTIONAL
- )
- {
- EFI_STATUS Status;
- UINT8 *Payload;
- UINTN PayloadSize;
- if (((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) ||
- ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0))
- {
- //
- // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
- // authenticated variable.
- //
- return EFI_INVALID_PARAMETER;
- }
- Status = EFI_SUCCESS;
- if ((mPlatformMode == USER_MODE) && !(InCustomMode () && UserPhysicalPresent ())) {
- //
- // Time-based, verify against X509 Cert KEK.
- //
- return VerifyTimeBasedPayloadAndUpdate (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- Attributes,
- AuthVarTypeKek,
- NULL
- );
- } else {
- //
- // If in setup mode or custom secure boot mode, no authentication needed.
- //
- Payload = (UINT8 *)Data + AUTHINFO2_SIZE (Data);
- PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
- Status = CheckSignatureListFormat (VariableName, VendorGuid, Payload, PayloadSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- Status = AuthServiceInternalUpdateVariableWithTimeStamp (
- VariableName,
- VendorGuid,
- Payload,
- PayloadSize,
- Attributes,
- &((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->TimeStamp
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (mPlatformMode != SETUP_MODE) {
- Status = VendorKeyIsModified ();
- }
- }
- return Status;
- }
- /**
- Check if it is to delete auth variable.
- @param[in] OrgAttributes Original attribute value of the variable.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data.
- @param[in] Attributes Attribute value of the variable.
- @retval TRUE It is to delete auth variable.
- @retval FALSE It is not to delete auth variable.
- **/
- BOOLEAN
- IsDeleteAuthVariable (
- IN UINT32 OrgAttributes,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes
- )
- {
- BOOLEAN Del;
- UINTN PayloadSize;
- Del = FALSE;
- //
- // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
- // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
- // SetVariable must be used with attributes matching the existing variable
- // and the DataSize set to the size of the AuthInfo descriptor.
- //
- if ((Attributes == OrgAttributes) &&
- ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0))
- {
- if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
- PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
- if (PayloadSize == 0) {
- Del = TRUE;
- }
- } else {
- PayloadSize = DataSize - AUTHINFO_SIZE;
- if (PayloadSize == 0) {
- Del = TRUE;
- }
- }
- }
- return Del;
- }
- /**
- Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
- Caution: This function may receive untrusted input.
- This function may be invoked in SMM mode, and datasize and data are external input.
- This function will do basic validation, before parse the data.
- This function will parse the authentication carefully to avoid security issues, like
- buffer overflow, integer overflow.
- This function will check attribute carefully to avoid authentication bypass.
- @param[in] VariableName Name of the variable.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data.
- @param[in] Attributes Attribute value of the variable.
- @return EFI_INVALID_PARAMETER Invalid parameter.
- @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
- EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
- @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
- @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
- set, but the AuthInfo does NOT pass the validation
- check carried out by the firmware.
- @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
- **/
- EFI_STATUS
- ProcessVariable (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes
- )
- {
- EFI_STATUS Status;
- AUTH_VARIABLE_INFO OrgVariableInfo;
- Status = EFI_SUCCESS;
- ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
- Status = mAuthVarLibContextIn->FindVariable (
- VariableName,
- VendorGuid,
- &OrgVariableInfo
- );
- // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables.
- if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && (UserPhysicalPresent () || !IsVariablePolicyEnabled ())) {
- //
- // Allow the delete operation of common authenticated variable(AT or AW) at user physical presence.
- //
- Status = AuthServiceInternalUpdateVariable (
- VariableName,
- VendorGuid,
- NULL,
- 0,
- 0
- );
- if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
- Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
- }
- return Status;
- }
- if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent ()) {
- //
- // This variable is protected, only physical present user could modify its value.
- //
- return EFI_SECURITY_VIOLATION;
- }
- //
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
- //
- // Reject Counter Based Auth Variable processing request.
- //
- return EFI_UNSUPPORTED;
- } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
- //
- // Process Time-based Authenticated variable.
- //
- return VerifyTimeBasedPayloadAndUpdate (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- Attributes,
- AuthVarTypePriv,
- NULL
- );
- }
- if ((OrgVariableInfo.Data != NULL) &&
- ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0))
- {
- //
- // If the variable is already write-protected, it always needs authentication before update.
- //
- return EFI_WRITE_PROTECTED;
- }
- //
- // Not authenticated variable, just update variable as usual.
- //
- Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
- return Status;
- }
- /**
- Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
- @param[in] Data Pointer to original EFI_SIGNATURE_LIST.
- @param[in] DataSize Size of Data buffer.
- @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.
- @param[in, out] NewDataSize Size of NewData buffer.
- **/
- EFI_STATUS
- FilterSignatureList (
- IN VOID *Data,
- IN UINTN DataSize,
- IN OUT VOID *NewData,
- IN OUT UINTN *NewDataSize
- )
- {
- EFI_SIGNATURE_LIST *CertList;
- EFI_SIGNATURE_DATA *Cert;
- UINTN CertCount;
- EFI_SIGNATURE_LIST *NewCertList;
- EFI_SIGNATURE_DATA *NewCert;
- UINTN NewCertCount;
- UINTN Index;
- UINTN Index2;
- UINTN Size;
- UINT8 *Tail;
- UINTN CopiedCount;
- UINTN SignatureListSize;
- BOOLEAN IsNewCert;
- UINT8 *TempData;
- UINTN TempDataSize;
- EFI_STATUS Status;
- if (*NewDataSize == 0) {
- return EFI_SUCCESS;
- }
- TempDataSize = *NewDataSize;
- Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **)&TempData);
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
- Tail = TempData;
- NewCertList = (EFI_SIGNATURE_LIST *)NewData;
- while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {
- NewCert = (EFI_SIGNATURE_DATA *)((UINT8 *)NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
- NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
- CopiedCount = 0;
- for (Index = 0; Index < NewCertCount; Index++) {
- IsNewCert = TRUE;
- Size = DataSize;
- CertList = (EFI_SIGNATURE_LIST *)Data;
- while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
- if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
- (CertList->SignatureSize == NewCertList->SignatureSize))
- {
- Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
- CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
- for (Index2 = 0; Index2 < CertCount; Index2++) {
- //
- // Iterate each Signature Data in this Signature List.
- //
- if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
- IsNewCert = FALSE;
- break;
- }
- Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);
- }
- }
- if (!IsNewCert) {
- break;
- }
- Size -= CertList->SignatureListSize;
- CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);
- }
- if (IsNewCert) {
- //
- // New EFI_SIGNATURE_DATA, keep it.
- //
- if (CopiedCount == 0) {
- //
- // Copy EFI_SIGNATURE_LIST header for only once.
- //
- CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
- Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
- }
- CopyMem (Tail, NewCert, NewCertList->SignatureSize);
- Tail += NewCertList->SignatureSize;
- CopiedCount++;
- }
- NewCert = (EFI_SIGNATURE_DATA *)((UINT8 *)NewCert + NewCertList->SignatureSize);
- }
- //
- // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
- //
- if (CopiedCount != 0) {
- SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
- CertList = (EFI_SIGNATURE_LIST *)(Tail - SignatureListSize);
- CertList->SignatureListSize = (UINT32)SignatureListSize;
- }
- *NewDataSize -= NewCertList->SignatureListSize;
- NewCertList = (EFI_SIGNATURE_LIST *)((UINT8 *)NewCertList + NewCertList->SignatureListSize);
- }
- TempDataSize = (Tail - (UINT8 *)TempData);
- CopyMem (NewData, TempData, TempDataSize);
- *NewDataSize = TempDataSize;
- return EFI_SUCCESS;
- }
- /**
- Compare two EFI_TIME data.
- @param FirstTime A pointer to the first EFI_TIME data.
- @param SecondTime A pointer to the second EFI_TIME data.
- @retval TRUE The FirstTime is not later than the SecondTime.
- @retval FALSE The FirstTime is later than the SecondTime.
- **/
- BOOLEAN
- AuthServiceInternalCompareTimeStamp (
- IN EFI_TIME *FirstTime,
- IN EFI_TIME *SecondTime
- )
- {
- if (FirstTime->Year != SecondTime->Year) {
- return (BOOLEAN)(FirstTime->Year < SecondTime->Year);
- } else if (FirstTime->Month != SecondTime->Month) {
- return (BOOLEAN)(FirstTime->Month < SecondTime->Month);
- } else if (FirstTime->Day != SecondTime->Day) {
- return (BOOLEAN)(FirstTime->Day < SecondTime->Day);
- } else if (FirstTime->Hour != SecondTime->Hour) {
- return (BOOLEAN)(FirstTime->Hour < SecondTime->Hour);
- } else if (FirstTime->Minute != SecondTime->Minute) {
- return (BOOLEAN)(FirstTime->Minute < SecondTime->Minute);
- }
- return (BOOLEAN)(FirstTime->Second <= SecondTime->Second);
- }
- /**
- Calculate SHA256 digest of SignerCert CommonName + ToplevelCert tbsCertificate
- SignerCert and ToplevelCert are inside the signer certificate chain.
- @param[in] SignerCert A pointer to SignerCert data.
- @param[in] SignerCertSize Length of SignerCert data.
- @param[in] TopLevelCert A pointer to TopLevelCert data.
- @param[in] TopLevelCertSize Length of TopLevelCert data.
- @param[out] Sha256Digest Sha256 digest calculated.
- @return EFI_ABORTED Digest process failed.
- @return EFI_SUCCESS SHA256 Digest is successfully calculated.
- **/
- EFI_STATUS
- CalculatePrivAuthVarSignChainSHA256Digest (
- IN UINT8 *SignerCert,
- IN UINTN SignerCertSize,
- IN UINT8 *TopLevelCert,
- IN UINTN TopLevelCertSize,
- OUT UINT8 *Sha256Digest
- )
- {
- UINT8 *TbsCert;
- UINTN TbsCertSize;
- CHAR8 CertCommonName[128];
- UINTN CertCommonNameSize;
- BOOLEAN CryptoStatus;
- EFI_STATUS Status;
- CertCommonNameSize = sizeof (CertCommonName);
- //
- // Get SignerCert CommonName
- //
- Status = X509GetCommonName (SignerCert, SignerCertSize, CertCommonName, &CertCommonNameSize);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_INFO, "%a Get SignerCert CommonName failed with status %x\n", __FUNCTION__, Status));
- return EFI_ABORTED;
- }
- //
- // Get TopLevelCert tbsCertificate
- //
- if (!X509GetTBSCert (TopLevelCert, TopLevelCertSize, &TbsCert, &TbsCertSize)) {
- DEBUG ((DEBUG_INFO, "%a Get Top-level Cert tbsCertificate failed!\n", __FUNCTION__));
- return EFI_ABORTED;
- }
- //
- // Digest SignerCert CN + TopLevelCert tbsCertificate
- //
- ZeroMem (Sha256Digest, SHA256_DIGEST_SIZE);
- CryptoStatus = Sha256Init (mHashCtx);
- if (!CryptoStatus) {
- return EFI_ABORTED;
- }
- //
- // '\0' is forced in CertCommonName. No overflow issue
- //
- CryptoStatus = Sha256Update (
- mHashCtx,
- CertCommonName,
- AsciiStrLen (CertCommonName)
- );
- if (!CryptoStatus) {
- return EFI_ABORTED;
- }
- CryptoStatus = Sha256Update (mHashCtx, TbsCert, TbsCertSize);
- if (!CryptoStatus) {
- return EFI_ABORTED;
- }
- CryptoStatus = Sha256Final (mHashCtx, Sha256Digest);
- if (!CryptoStatus) {
- return EFI_ABORTED;
- }
- return EFI_SUCCESS;
- }
- /**
- Find matching signer's certificates for common authenticated variable
- by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
- The data format of "certdb" or "certdbv":
- //
- // UINT32 CertDbListSize;
- // /// AUTH_CERT_DB_DATA Certs1[];
- // /// AUTH_CERT_DB_DATA Certs2[];
- // /// ...
- // /// AUTH_CERT_DB_DATA Certsn[];
- //
- @param[in] VariableName Name of authenticated Variable.
- @param[in] VendorGuid Vendor GUID of authenticated Variable.
- @param[in] Data Pointer to variable "certdb" or "certdbv".
- @param[in] DataSize Size of variable "certdb" or "certdbv".
- @param[out] CertOffset Offset of matching CertData, from starting of Data.
- @param[out] CertDataSize Length of CertData in bytes.
- @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
- starting of Data.
- @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- @retval EFI_NOT_FOUND Fail to find matching certs.
- @retval EFI_SUCCESS Find matching certs and output parameters.
- **/
- EFI_STATUS
- FindCertsFromDb (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT8 *Data,
- IN UINTN DataSize,
- OUT UINT32 *CertOffset OPTIONAL,
- OUT UINT32 *CertDataSize OPTIONAL,
- OUT UINT32 *CertNodeOffset OPTIONAL,
- OUT UINT32 *CertNodeSize OPTIONAL
- )
- {
- UINT32 Offset;
- AUTH_CERT_DB_DATA *Ptr;
- UINT32 CertSize;
- UINT32 NameSize;
- UINT32 NodeSize;
- UINT32 CertDbListSize;
- if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Check whether DataSize matches recorded CertDbListSize.
- //
- if (DataSize < sizeof (UINT32)) {
- return EFI_INVALID_PARAMETER;
- }
- CertDbListSize = ReadUnaligned32 ((UINT32 *)Data);
- if (CertDbListSize != (UINT32)DataSize) {
- return EFI_INVALID_PARAMETER;
- }
- Offset = sizeof (UINT32);
- //
- // Get corresponding certificates by VendorGuid and VariableName.
- //
- while (Offset < (UINT32)DataSize) {
- Ptr = (AUTH_CERT_DB_DATA *)(Data + Offset);
- //
- // Check whether VendorGuid matches.
- //
- if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
- NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
- NameSize = ReadUnaligned32 (&Ptr->NameSize);
- CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
- if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
- sizeof (CHAR16) * NameSize)
- {
- return EFI_INVALID_PARAMETER;
- }
- Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
- //
- // Check whether VariableName matches.
- //
- if ((NameSize == StrLen (VariableName)) &&
- (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0))
- {
- Offset = Offset + NameSize * sizeof (CHAR16);
- if (CertOffset != NULL) {
- *CertOffset = Offset;
- }
- if (CertDataSize != NULL) {
- *CertDataSize = CertSize;
- }
- if (CertNodeOffset != NULL) {
- *CertNodeOffset = (UINT32)((UINT8 *)Ptr - Data);
- }
- if (CertNodeSize != NULL) {
- *CertNodeSize = NodeSize;
- }
- return EFI_SUCCESS;
- } else {
- Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
- }
- } else {
- NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
- Offset = Offset + NodeSize;
- }
- }
- return EFI_NOT_FOUND;
- }
- /**
- Retrieve signer's certificates for common authenticated variable
- by corresponding VariableName and VendorGuid from "certdb"
- or "certdbv" according to authenticated variable attributes.
- @param[in] VariableName Name of authenticated Variable.
- @param[in] VendorGuid Vendor GUID of authenticated Variable.
- @param[in] Attributes Attributes of authenticated variable.
- @param[out] CertData Pointer to signer's certificates.
- @param[out] CertDataSize Length of CertData in bytes.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
- @retval EFI_SUCCESS Get signer's certificates successfully.
- **/
- EFI_STATUS
- GetCertsFromDb (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT32 Attributes,
- OUT UINT8 **CertData,
- OUT UINT32 *CertDataSize
- )
- {
- EFI_STATUS Status;
- UINT8 *Data;
- UINTN DataSize;
- UINT32 CertOffset;
- CHAR16 *DbName;
- if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Get variable "certdb".
- //
- DbName = EFI_CERT_DB_NAME;
- } else {
- //
- // Get variable "certdbv".
- //
- DbName = EFI_CERT_DB_VOLATILE_NAME;
- }
- //
- // Get variable "certdb" or "certdbv".
- //
- Status = AuthServiceInternalFindVariable (
- DbName,
- &gEfiCertDbGuid,
- (VOID **)&Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if ((DataSize == 0) || (Data == NULL)) {
- ASSERT (FALSE);
- return EFI_NOT_FOUND;
- }
- Status = FindCertsFromDb (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- &CertOffset,
- CertDataSize,
- NULL,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- *CertData = Data + CertOffset;
- return EFI_SUCCESS;
- }
- /**
- Delete matching signer's certificates when deleting common authenticated
- variable by corresponding VariableName and VendorGuid from "certdb" or
- "certdbv" according to authenticated variable attributes.
- @param[in] VariableName Name of authenticated Variable.
- @param[in] VendorGuid Vendor GUID of authenticated Variable.
- @param[in] Attributes Attributes of authenticated variable.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
- @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
- @retval EFI_SUCCESS The operation is completed successfully.
- **/
- EFI_STATUS
- DeleteCertsFromDb (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT32 Attributes
- )
- {
- EFI_STATUS Status;
- UINT8 *Data;
- UINTN DataSize;
- UINT32 VarAttr;
- UINT32 CertNodeOffset;
- UINT32 CertNodeSize;
- UINT8 *NewCertDb;
- UINT32 NewCertDbSize;
- CHAR16 *DbName;
- if ((VariableName == NULL) || (VendorGuid == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Get variable "certdb".
- //
- DbName = EFI_CERT_DB_NAME;
- VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
- } else {
- //
- // Get variable "certdbv".
- //
- DbName = EFI_CERT_DB_VOLATILE_NAME;
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
- }
- Status = AuthServiceInternalFindVariable (
- DbName,
- &gEfiCertDbGuid,
- (VOID **)&Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if ((DataSize == 0) || (Data == NULL)) {
- ASSERT (FALSE);
- return EFI_NOT_FOUND;
- }
- if (DataSize == sizeof (UINT32)) {
- //
- // There is no certs in "certdb" or "certdbv".
- //
- return EFI_SUCCESS;
- }
- //
- // Get corresponding cert node from "certdb" or "certdbv".
- //
- Status = FindCertsFromDb (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- NULL,
- NULL,
- &CertNodeOffset,
- &CertNodeSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if (DataSize < (CertNodeOffset + CertNodeSize)) {
- return EFI_NOT_FOUND;
- }
- //
- // Construct new data content of variable "certdb" or "certdbv".
- //
- NewCertDbSize = (UINT32)DataSize - CertNodeSize;
- NewCertDb = (UINT8 *)mCertDbStore;
- //
- // Copy the DB entries before deleting node.
- //
- CopyMem (NewCertDb, Data, CertNodeOffset);
- //
- // Update CertDbListSize.
- //
- CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
- //
- // Copy the DB entries after deleting node.
- //
- if (DataSize > (CertNodeOffset + CertNodeSize)) {
- CopyMem (
- NewCertDb + CertNodeOffset,
- Data + CertNodeOffset + CertNodeSize,
- DataSize - CertNodeOffset - CertNodeSize
- );
- }
- //
- // Set "certdb" or "certdbv".
- //
- Status = AuthServiceInternalUpdateVariable (
- DbName,
- &gEfiCertDbGuid,
- NewCertDb,
- NewCertDbSize,
- VarAttr
- );
- return Status;
- }
- /**
- Insert signer's certificates for common authenticated variable with VariableName
- and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
- time based authenticated variable attributes. CertData is the SHA256 digest of
- SignerCert CommonName + TopLevelCert tbsCertificate.
- @param[in] VariableName Name of authenticated Variable.
- @param[in] VendorGuid Vendor GUID of authenticated Variable.
- @param[in] Attributes Attributes of authenticated variable.
- @param[in] SignerCert Signer certificate data.
- @param[in] SignerCertSize Length of signer certificate.
- @param[in] TopLevelCert Top-level certificate data.
- @param[in] TopLevelCertSize Length of top-level certificate.
- @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
- @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
- and VendorGuid already exists.
- @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
- @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
- **/
- EFI_STATUS
- InsertCertsToDb (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN UINT32 Attributes,
- IN UINT8 *SignerCert,
- IN UINTN SignerCertSize,
- IN UINT8 *TopLevelCert,
- IN UINTN TopLevelCertSize
- )
- {
- EFI_STATUS Status;
- UINT8 *Data;
- UINTN DataSize;
- UINT32 VarAttr;
- UINT8 *NewCertDb;
- UINT32 NewCertDbSize;
- UINT32 CertNodeSize;
- UINT32 NameSize;
- UINT32 CertDataSize;
- AUTH_CERT_DB_DATA *Ptr;
- CHAR16 *DbName;
- UINT8 Sha256Digest[SHA256_DIGEST_SIZE];
- if ((VariableName == NULL) || (VendorGuid == NULL) || (SignerCert == NULL) || (TopLevelCert == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
- //
- // Get variable "certdb".
- //
- DbName = EFI_CERT_DB_NAME;
- VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
- } else {
- //
- // Get variable "certdbv".
- //
- DbName = EFI_CERT_DB_VOLATILE_NAME;
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
- }
- //
- // Get variable "certdb" or "certdbv".
- //
- Status = AuthServiceInternalFindVariable (
- DbName,
- &gEfiCertDbGuid,
- (VOID **)&Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if ((DataSize == 0) || (Data == NULL)) {
- ASSERT (FALSE);
- return EFI_NOT_FOUND;
- }
- //
- // Find whether matching cert node already exists in "certdb" or "certdbv".
- // If yes return error.
- //
- Status = FindCertsFromDb (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- NULL,
- NULL,
- NULL,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- ASSERT (FALSE);
- return EFI_ACCESS_DENIED;
- }
- //
- // Construct new data content of variable "certdb" or "certdbv".
- //
- NameSize = (UINT32)StrLen (VariableName);
- CertDataSize = sizeof (Sha256Digest);
- CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32)CertDataSize + NameSize * sizeof (CHAR16);
- NewCertDbSize = (UINT32)DataSize + CertNodeSize;
- if (NewCertDbSize > mMaxCertDbSize) {
- return EFI_OUT_OF_RESOURCES;
- }
- Status = CalculatePrivAuthVarSignChainSHA256Digest (
- SignerCert,
- SignerCertSize,
- TopLevelCert,
- TopLevelCertSize,
- Sha256Digest
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- NewCertDb = (UINT8 *)mCertDbStore;
- //
- // Copy the DB entries before inserting node.
- //
- CopyMem (NewCertDb, Data, DataSize);
- //
- // Update CertDbListSize.
- //
- CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
- //
- // Construct new cert node.
- //
- Ptr = (AUTH_CERT_DB_DATA *)(NewCertDb + DataSize);
- CopyGuid (&Ptr->VendorGuid, VendorGuid);
- CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
- CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
- CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
- CopyMem (
- (UINT8 *)Ptr + sizeof (AUTH_CERT_DB_DATA),
- VariableName,
- NameSize * sizeof (CHAR16)
- );
- CopyMem (
- (UINT8 *)Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
- Sha256Digest,
- CertDataSize
- );
- //
- // Set "certdb" or "certdbv".
- //
- Status = AuthServiceInternalUpdateVariable (
- DbName,
- &gEfiCertDbGuid,
- NewCertDb,
- NewCertDbSize,
- VarAttr
- );
- return Status;
- }
- /**
- Clean up signer's certificates for common authenticated variable
- by corresponding VariableName and VendorGuid from "certdb".
- System may break down during Timebased Variable update & certdb update,
- make them inconsistent, this function is called in AuthVariable Init
- to ensure consistency.
- @retval EFI_NOT_FOUND Fail to find variable "certdb".
- @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
- @retval EFI_SUCCESS The operation is completed successfully.
- **/
- EFI_STATUS
- CleanCertsFromDb (
- VOID
- )
- {
- UINT32 Offset;
- AUTH_CERT_DB_DATA *Ptr;
- UINT32 NameSize;
- UINT32 NodeSize;
- CHAR16 *VariableName;
- EFI_STATUS Status;
- BOOLEAN CertCleaned;
- UINT8 *Data;
- UINTN DataSize;
- EFI_GUID AuthVarGuid;
- AUTH_VARIABLE_INFO AuthVariableInfo;
- Status = EFI_SUCCESS;
- //
- // Get corresponding certificates by VendorGuid and VariableName.
- //
- do {
- CertCleaned = FALSE;
- //
- // Get latest variable "certdb"
- //
- Status = AuthServiceInternalFindVariable (
- EFI_CERT_DB_NAME,
- &gEfiCertDbGuid,
- (VOID **)&Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if ((DataSize == 0) || (Data == NULL)) {
- ASSERT (FALSE);
- return EFI_NOT_FOUND;
- }
- Offset = sizeof (UINT32);
- while (Offset < (UINT32)DataSize) {
- Ptr = (AUTH_CERT_DB_DATA *)(Data + Offset);
- NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
- NameSize = ReadUnaligned32 (&Ptr->NameSize);
- //
- // Get VarName tailed with '\0'
- //
- VariableName = AllocateZeroPool ((NameSize + 1) * sizeof (CHAR16));
- if (VariableName == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- CopyMem (VariableName, (UINT8 *)Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof (CHAR16));
- //
- // Keep VarGuid aligned
- //
- CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof (EFI_GUID));
- //
- // Find corresponding time auth variable
- //
- ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
- Status = mAuthVarLibContextIn->FindVariable (
- VariableName,
- &AuthVarGuid,
- &AuthVariableInfo
- );
- if (EFI_ERROR (Status) || ((AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)) {
- //
- // While cleaning certdb, always delete the variable in certdb regardless of it attributes.
- //
- Status = DeleteCertsFromDb (
- VariableName,
- &AuthVarGuid,
- AuthVariableInfo.Attributes | EFI_VARIABLE_NON_VOLATILE
- );
- CertCleaned = TRUE;
- DEBUG ((DEBUG_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
- FreePool (VariableName);
- break;
- }
- FreePool (VariableName);
- Offset = Offset + NodeSize;
- }
- } while (CertCleaned);
- return Status;
- }
- /**
- Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
- Caution: This function may receive untrusted input.
- This function may be invoked in SMM mode, and datasize and data are external input.
- This function will do basic validation, before parse the data.
- This function will parse the authentication carefully to avoid security issues, like
- buffer overflow, integer overflow.
- @param[in] VariableName Name of Variable to be found.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data found. If size is less than the
- data, this value contains the required size.
- @param[in] Attributes Attribute value of the variable.
- @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
- @param[in] OrgTimeStamp Pointer to original time stamp,
- original variable is not found if NULL.
- @param[out] VarPayloadPtr Pointer to variable payload address.
- @param[out] VarPayloadSize Pointer to variable payload size.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
- check carried out by the firmware.
- @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
- of resources.
- @retval EFI_SUCCESS Variable pass validation successfully.
- **/
- EFI_STATUS
- VerifyTimeBasedPayload (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes,
- IN AUTHVAR_TYPE AuthVarType,
- IN EFI_TIME *OrgTimeStamp,
- OUT UINT8 **VarPayloadPtr,
- OUT UINTN *VarPayloadSize
- )
- {
- EFI_VARIABLE_AUTHENTICATION_2 *CertData;
- UINT8 *SigData;
- UINT32 SigDataSize;
- UINT8 *PayloadPtr;
- UINTN PayloadSize;
- UINT32 Attr;
- BOOLEAN VerifyStatus;
- EFI_STATUS Status;
- EFI_SIGNATURE_LIST *CertList;
- EFI_SIGNATURE_DATA *Cert;
- UINTN Index;
- UINTN CertCount;
- UINT32 KekDataSize;
- UINT8 *NewData;
- UINTN NewDataSize;
- UINT8 *Buffer;
- UINTN Length;
- UINT8 *TopLevelCert;
- UINTN TopLevelCertSize;
- UINT8 *TrustedCert;
- UINTN TrustedCertSize;
- UINT8 *SignerCerts;
- UINTN CertStackSize;
- UINT8 *CertsInCertDb;
- UINT32 CertsSizeinDb;
- UINT8 Sha256Digest[SHA256_DIGEST_SIZE];
- EFI_CERT_DATA *CertDataPtr;
- //
- // 1. TopLevelCert is the top-level issuer certificate in signature Signer Cert Chain
- // 2. TrustedCert is the certificate which firmware trusts. It could be saved in protected
- // storage or PK payload on PK init
- //
- VerifyStatus = FALSE;
- CertData = NULL;
- NewData = NULL;
- Attr = Attributes;
- SignerCerts = NULL;
- TopLevelCert = NULL;
- CertsInCertDb = NULL;
- CertDataPtr = NULL;
- //
- // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
- // set, then the Data buffer shall begin with an instance of a complete (and serialized)
- // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
- // variable value and DataSize shall reflect the combined size of the descriptor and the new
- // variable value. The authentication descriptor is not part of the variable data and is not
- // returned by subsequent calls to GetVariable().
- //
- CertData = (EFI_VARIABLE_AUTHENTICATION_2 *)Data;
- //
- // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
- // TimeStamp value are set to zero.
- //
- if ((CertData->TimeStamp.Pad1 != 0) ||
- (CertData->TimeStamp.Nanosecond != 0) ||
- (CertData->TimeStamp.TimeZone != 0) ||
- (CertData->TimeStamp.Daylight != 0) ||
- (CertData->TimeStamp.Pad2 != 0))
- {
- return EFI_SECURITY_VIOLATION;
- }
- if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
- if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {
- //
- // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
- //
- return EFI_SECURITY_VIOLATION;
- }
- }
- //
- // 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) ||
- !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid))
- {
- //
- // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
- //
- return EFI_SECURITY_VIOLATION;
- }
- //
- // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
- // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
- //
- SigData = CertData->AuthInfo.CertData;
- SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
- //
- // SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the
- // signature. Only a digest algorithm of SHA-256 is accepted.
- //
- // According to PKCS#7 Definition (https://www.rfc-editor.org/rfc/rfc2315):
- // SignedData ::= SEQUENCE {
- // version Version,
- // digestAlgorithms DigestAlgorithmIdentifiers,
- // contentInfo ContentInfo,
- // .... }
- // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm
- // in VARIABLE_AUTHENTICATION_2 descriptor.
- // This field has the fixed offset (+13) or (+32) based on whether the DER-encoded
- // ContentInfo structure is present or not, and can be calculated based on two
- // bytes of length encoding.
- //
- // Both condition can be handled in WrapPkcs7Data() in CryptPkcs7VerifyCommon.c.
- //
- // See below examples:
- //
- // 1. Without ContentInfo
- // 30 82 0c da // SEQUENCE (5 element) (3294 BYTES) -- SignedData
- // 02 01 01 // INTEGER 1 -- Version
- // 31 0f // SET (1 element) (15 BYTES) -- DigestAlgorithmIdentifiers
- // 30 0d // SEQUENCE (2 element) (13 BYTES) -- AlgorithmIdentifier
- // 06 09 // OBJECT-IDENTIFIER (9 BYTES) -- algorithm
- // 60 86 48 01 65 03 04 02 01 // sha256 [2.16.840.1.101.3.4.2.1]
- // 05 00 // NULL (0 BYTES) -- parameters
- //
- // Example from: https://uefi.org/revocationlistfile
- //
- // 2. With ContentInfo
- // 30 82 05 90 // SEQUENCE (1424 BYTES) -- ContentInfo
- // 06 09 // OBJECT-IDENTIFIER (9 BYTES) -- ContentType
- // 2a 86 48 86 f7 0d 01 07 02 // signedData [1.2.840.113549.1.7.2]
- // a0 82 05 81 // CONTEXT-SPECIFIC CONSTRUCTED TAG 0 (1409 BYTES) -- content
- // 30 82 05 7d // SEQUENCE (1405 BYTES) -- SignedData
- // 02 01 01 // INTEGER 1 -- Version
- // 31 0f // SET (1 element) (15 BYTES) -- DigestAlgorithmIdentifiers
- // 30 0d // SEQUENCE (13 BYTES) -- AlgorithmIdentifier
- // 06 09 // OBJECT-IDENTIFIER (9 BYTES) -- algorithm
- // 60 86 48 01 65 03 04 02 01 // sha256 [2.16.840.1.101.3.4.2.1]
- // 05 00 // NULL (0 BYTES) -- parameters
- //
- // Example generated with: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Manual_process
- //
- if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
- if ( ( (SigDataSize >= (13 + sizeof (mSha256OidValue)))
- && ( ((*(SigData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE)
- || (CompareMem (SigData + 13, &mSha256OidValue, sizeof (mSha256OidValue)) != 0)))
- && ( (SigDataSize >= (32 + sizeof (mSha256OidValue)))
- && ( ((*(SigData + 20) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE)
- || (CompareMem (SigData + 32, &mSha256OidValue, sizeof (mSha256OidValue)) != 0))))
- {
- return EFI_SECURITY_VIOLATION;
- }
- }
- //
- // Find out the new data payload which follows Pkcs7 SignedData directly.
- //
- PayloadPtr = SigData + SigDataSize;
- PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN)SigDataSize;
- // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables.
- if ((PayloadSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && !IsVariablePolicyEnabled ()) {
- VerifyStatus = TRUE;
- goto Exit;
- }
- //
- // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
- // parameters of the SetVariable() call and the TimeStamp component of the
- // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
- // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
- //
- NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
- sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
- //
- // Here is to reuse scratch data area(at the end of volatile variable store)
- // to reduce SMRAM consumption for SMM variable driver.
- // The scratch buffer is enough to hold the serialized data and safe to use,
- // because it is only used at here to do verification temporarily first
- // and then used in UpdateVariable() for a time based auth variable set.
- //
- Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **)&NewData);
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
- Buffer = NewData;
- Length = StrLen (VariableName) * sizeof (CHAR16);
- CopyMem (Buffer, VariableName, Length);
- Buffer += Length;
- Length = sizeof (EFI_GUID);
- CopyMem (Buffer, VendorGuid, Length);
- Buffer += Length;
- Length = sizeof (UINT32);
- CopyMem (Buffer, &Attr, Length);
- Buffer += Length;
- Length = sizeof (EFI_TIME);
- CopyMem (Buffer, &CertData->TimeStamp, Length);
- Buffer += Length;
- CopyMem (Buffer, PayloadPtr, PayloadSize);
- if (AuthVarType == AuthVarTypePk) {
- //
- // Verify that the signature has been made with the current Platform Key (no chaining for PK).
- // First, get signer's certificates from SignedData.
- //
- VerifyStatus = Pkcs7GetSigners (
- SigData,
- SigDataSize,
- &SignerCerts,
- &CertStackSize,
- &TopLevelCert,
- &TopLevelCertSize
- );
- if (!VerifyStatus) {
- goto Exit;
- }
- //
- // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
- // in SignedData. If not, return error immediately.
- //
- Status = AuthServiceInternalFindVariable (
- EFI_PLATFORM_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- VerifyStatus = FALSE;
- goto Exit;
- }
- CertList = (EFI_SIGNATURE_LIST *)Data;
- Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
- if ((TopLevelCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
- (CompareMem (Cert->SignatureData, TopLevelCert, TopLevelCertSize) != 0))
- {
- VerifyStatus = FALSE;
- goto Exit;
- }
- //
- // Verify Pkcs7 SignedData via Pkcs7Verify library.
- //
- VerifyStatus = Pkcs7Verify (
- SigData,
- SigDataSize,
- TopLevelCert,
- TopLevelCertSize,
- NewData,
- NewDataSize
- );
- } else if (AuthVarType == AuthVarTypeKek) {
- //
- // Get KEK database from variable.
- //
- Status = AuthServiceInternalFindVariable (
- EFI_KEY_EXCHANGE_KEY_NAME,
- &gEfiGlobalVariableGuid,
- &Data,
- &DataSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- //
- // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
- //
- KekDataSize = (UINT32)DataSize;
- CertList = (EFI_SIGNATURE_LIST *)Data;
- while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
- if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
- Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
- CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
- for (Index = 0; Index < CertCount; Index++) {
- //
- // Iterate each Signature Data Node within this CertList for a verify
- //
- TrustedCert = Cert->SignatureData;
- TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
- //
- // Verify Pkcs7 SignedData via Pkcs7Verify library.
- //
- VerifyStatus = Pkcs7Verify (
- SigData,
- SigDataSize,
- TrustedCert,
- TrustedCertSize,
- NewData,
- NewDataSize
- );
- if (VerifyStatus) {
- goto Exit;
- }
- Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);
- }
- }
- KekDataSize -= CertList->SignatureListSize;
- CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);
- }
- } else if (AuthVarType == AuthVarTypePriv) {
- //
- // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
- // Get signer's certificates from SignedData.
- //
- VerifyStatus = Pkcs7GetSigners (
- SigData,
- SigDataSize,
- &SignerCerts,
- &CertStackSize,
- &TopLevelCert,
- &TopLevelCertSize
- );
- if (!VerifyStatus) {
- goto Exit;
- }
- //
- // Get previously stored signer's certificates from certdb or certdbv for existing
- // variable. Check whether they are identical with signer's certificates
- // in SignedData. If not, return error immediately.
- //
- if (OrgTimeStamp != NULL) {
- VerifyStatus = FALSE;
- Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);
- if (EFI_ERROR (Status)) {
- goto Exit;
- }
- if (CertsSizeinDb == SHA256_DIGEST_SIZE) {
- //
- // Check hash of signer cert CommonName + Top-level issuer tbsCertificate against data in CertDb
- //
- CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);
- Status = CalculatePrivAuthVarSignChainSHA256Digest (
- CertDataPtr->CertDataBuffer,
- ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),
- TopLevelCert,
- TopLevelCertSize,
- Sha256Digest
- );
- if (EFI_ERROR (Status) || (CompareMem (Sha256Digest, CertsInCertDb, CertsSizeinDb) != 0)) {
- goto Exit;
- }
- } else {
- //
- // Keep backward compatible with previous solution which saves whole signer certs stack in CertDb
- //
- if ((CertStackSize != CertsSizeinDb) ||
- (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0))
- {
- goto Exit;
- }
- }
- }
- VerifyStatus = Pkcs7Verify (
- SigData,
- SigDataSize,
- TopLevelCert,
- TopLevelCertSize,
- NewData,
- NewDataSize
- );
- if (!VerifyStatus) {
- goto Exit;
- }
- if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
- //
- // When adding a new common authenticated variable, always save Hash of cn of signer cert + tbsCertificate of Top-level issuer
- //
- CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);
- Status = InsertCertsToDb (
- VariableName,
- VendorGuid,
- Attributes,
- CertDataPtr->CertDataBuffer,
- ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),
- TopLevelCert,
- TopLevelCertSize
- );
- if (EFI_ERROR (Status)) {
- VerifyStatus = FALSE;
- goto Exit;
- }
- }
- } else if (AuthVarType == AuthVarTypePayload) {
- CertList = (EFI_SIGNATURE_LIST *)PayloadPtr;
- Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
- TrustedCert = Cert->SignatureData;
- TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
- //
- // Verify Pkcs7 SignedData via Pkcs7Verify library.
- //
- VerifyStatus = Pkcs7Verify (
- SigData,
- SigDataSize,
- TrustedCert,
- TrustedCertSize,
- NewData,
- NewDataSize
- );
- } else {
- return EFI_SECURITY_VIOLATION;
- }
- Exit:
- if ((AuthVarType == AuthVarTypePk) || (AuthVarType == AuthVarTypePriv)) {
- if (TopLevelCert != NULL) {
- Pkcs7FreeSigners (TopLevelCert);
- }
- if (SignerCerts != NULL) {
- Pkcs7FreeSigners (SignerCerts);
- }
- }
- if (!VerifyStatus) {
- return EFI_SECURITY_VIOLATION;
- }
- Status = CheckSignatureListFormat (VariableName, VendorGuid, PayloadPtr, PayloadSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- *VarPayloadPtr = PayloadPtr;
- *VarPayloadSize = PayloadSize;
- return EFI_SUCCESS;
- }
- /**
- Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
- Caution: This function may receive untrusted input.
- This function may be invoked in SMM mode, and datasize and data are external input.
- This function will do basic validation, before parse the data.
- This function will parse the authentication carefully to avoid security issues, like
- buffer overflow, integer overflow.
- @param[in] VariableName Name of Variable to be found.
- @param[in] VendorGuid Variable vendor GUID.
- @param[in] Data Data pointer.
- @param[in] DataSize Size of Data found. If size is less than the
- data, this value contains the required size.
- @param[in] Attributes Attribute value of the variable.
- @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
- @param[out] VarDel Delete the variable or not.
- @retval EFI_INVALID_PARAMETER Invalid parameter.
- @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
- check carried out by the firmware.
- @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
- of resources.
- @retval EFI_SUCCESS Variable pass validation successfully.
- **/
- EFI_STATUS
- VerifyTimeBasedPayloadAndUpdate (
- IN CHAR16 *VariableName,
- IN EFI_GUID *VendorGuid,
- IN VOID *Data,
- IN UINTN DataSize,
- IN UINT32 Attributes,
- IN AUTHVAR_TYPE AuthVarType,
- OUT BOOLEAN *VarDel
- )
- {
- EFI_STATUS Status;
- EFI_STATUS FindStatus;
- UINT8 *PayloadPtr;
- UINTN PayloadSize;
- EFI_VARIABLE_AUTHENTICATION_2 *CertData;
- AUTH_VARIABLE_INFO OrgVariableInfo;
- BOOLEAN IsDel;
- ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
- FindStatus = mAuthVarLibContextIn->FindVariable (
- VariableName,
- VendorGuid,
- &OrgVariableInfo
- );
- Status = VerifyTimeBasedPayload (
- VariableName,
- VendorGuid,
- Data,
- DataSize,
- Attributes,
- AuthVarType,
- (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,
- &PayloadPtr,
- &PayloadSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- if ( !EFI_ERROR (FindStatus)
- && (PayloadSize == 0)
- && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0))
- {
- IsDel = TRUE;
- } else {
- IsDel = FALSE;
- }
- CertData = (EFI_VARIABLE_AUTHENTICATION_2 *)Data;
- //
- // Final step: Update/Append Variable if it pass Pkcs7Verify
- //
- Status = AuthServiceInternalUpdateVariableWithTimeStamp (
- VariableName,
- VendorGuid,
- PayloadPtr,
- PayloadSize,
- Attributes,
- &CertData->TimeStamp
- );
- //
- // Delete signer's certificates when delete the common authenticated variable.
- //
- if (IsDel && (AuthVarType == AuthVarTypePriv) && !EFI_ERROR (Status)) {
- Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
- }
- if (VarDel != NULL) {
- if (IsDel && !EFI_ERROR (Status)) {
- *VarDel = TRUE;
- } else {
- *VarDel = FALSE;
- }
- }
- return Status;
- }
|