2 Implement authentication services for the authenticated variable
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable data. It may be input in SMM mode.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9 Variable attribute should also be checked to avoid authentication bypass.
10 The whole SMM authentication variable design relies on the integrity of flash part and SMM.
11 which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
12 may not be modified without authorization. If platform fails to protect these resources,
13 the authentication service provided in this driver will be broken, and the behavior is undefined.
15 ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
16 variable authentication.
18 VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.
19 They will do basic validation for authentication data structure, then call crypto library
20 to verify the signature.
22 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
23 This program and the accompanying materials
24 are licensed and made available under the terms and conditions of the BSD License
25 which accompanies this distribution. The full text of the license may be found at
26 http://opensource.org/licenses/bsd-license.php
28 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
29 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
34 #include "AuthService.h"
37 /// Global database array for scratch
44 UINT32 mMaxCertDbSize
;
46 UINT8 mVendorKeyState
;
48 EFI_GUID mSignatureSupport
[] = {EFI_CERT_SHA1_GUID
, EFI_CERT_SHA256_GUID
, EFI_CERT_RSA2048_GUID
, EFI_CERT_X509_GUID
};
50 // Public Exponent of RSA Key.
52 CONST UINT8 mRsaE
[] = { 0x01, 0x00, 0x01 };
54 // Hash context pointer
56 VOID
*mHashCtx
= NULL
;
59 // The serialization of the values of the VariableName, VendorGuid and Attributes
60 // parameters of the SetVariable() call and the TimeStamp component of the
61 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
62 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
64 UINT8
*mSerializationRuntimeBuffer
= NULL
;
67 // Requirement for different signature type which have been defined in UEFI spec.
68 // These data are used to peform SignatureList format check while setting PK/KEK variable.
70 EFI_SIGNATURE_ITEM mSupportSigItem
[] = {
71 //{SigType, SigHeaderSize, SigDataSize }
72 {EFI_CERT_SHA256_GUID
, 0, 32 },
73 {EFI_CERT_RSA2048_GUID
, 0, 256 },
74 {EFI_CERT_RSA2048_SHA256_GUID
, 0, 256 },
75 {EFI_CERT_SHA1_GUID
, 0, 20 },
76 {EFI_CERT_RSA2048_SHA1_GUID
, 0, 256 },
77 {EFI_CERT_X509_GUID
, 0, ((UINT32
) ~0)},
78 {EFI_CERT_SHA224_GUID
, 0, 28 },
79 {EFI_CERT_SHA384_GUID
, 0, 48 },
80 {EFI_CERT_SHA512_GUID
, 0, 64 }
84 Determine whether this operation needs a physical present user.
86 @param[in] VariableName Name of the Variable.
87 @param[in] VendorGuid GUID of the Variable.
89 @retval TRUE This variable is protected, only a physical present user could set this variable.
90 @retval FALSE This variable is not protected.
94 NeedPhysicallyPresent(
95 IN CHAR16
*VariableName
,
96 IN EFI_GUID
*VendorGuid
99 if ((CompareGuid (VendorGuid
, &gEfiSecureBootEnableDisableGuid
) && (StrCmp (VariableName
, EFI_SECURE_BOOT_ENABLE_NAME
) == 0))
100 || (CompareGuid (VendorGuid
, &gEfiCustomModeEnableGuid
) && (StrCmp (VariableName
, EFI_CUSTOM_MODE_NAME
) == 0))) {
108 Determine whether the platform is operating in Custom Secure Boot mode.
110 @retval TRUE The platform is operating in Custom mode.
111 @retval FALSE The platform is operating in Standard mode.
119 VARIABLE_POINTER_TRACK Variable
;
121 FindVariable (EFI_CUSTOM_MODE_NAME
, &gEfiCustomModeEnableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
122 if (Variable
.CurrPtr
!= NULL
&& *(GetVariableDataPtr (Variable
.CurrPtr
)) == CUSTOM_SECURE_BOOT_MODE
) {
131 Internal function to delete a Variable given its name and GUID, no authentication
134 @param[in] VariableName Name of the Variable.
135 @param[in] VendorGuid GUID of the Variable.
137 @retval EFI_SUCCESS Variable deleted successfully.
138 @retval Others The driver failded to start the device.
143 IN CHAR16
*VariableName
,
144 IN EFI_GUID
*VendorGuid
148 VARIABLE_POINTER_TRACK Variable
;
150 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
151 if (EFI_ERROR (Status
)) {
155 ASSERT (Variable
.CurrPtr
!= NULL
);
156 return UpdateVariable (VariableName
, VendorGuid
, NULL
, 0, 0, 0, 0, &Variable
, NULL
);
160 Initializes for authenticated varibale service.
162 @retval EFI_SUCCESS Function successfully executed.
163 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
167 AutenticatedVariableServiceInitialize (
172 VARIABLE_POINTER_TRACK Variable
;
173 VARIABLE_POINTER_TRACK PkVariable
;
179 UINT8 SecureBootMode
;
180 UINT8 SecureBootEnable
;
185 // Initialize hash context.
187 CtxSize
= Sha256GetContextSize ();
188 mHashCtx
= AllocateRuntimePool (CtxSize
);
189 if (mHashCtx
== NULL
) {
190 return EFI_OUT_OF_RESOURCES
;
194 // Reserve runtime buffer for public key database. The size excludes variable header and name size.
196 mMaxKeyDbSize
= PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
) - sizeof (AUTHVAR_KEYDB_NAME
);
197 mMaxKeyNumber
= mMaxKeyDbSize
/ EFI_CERT_TYPE_RSA2048_SIZE
;
198 mPubKeyStore
= AllocateRuntimePool (mMaxKeyDbSize
);
199 if (mPubKeyStore
== NULL
) {
200 return EFI_OUT_OF_RESOURCES
;
204 // Reserve runtime buffer for certificate database. The size excludes variable header and name size.
206 mMaxCertDbSize
= PcdGet32 (PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
) - sizeof (EFI_CERT_DB_NAME
);
207 mCertDbStore
= AllocateRuntimePool (mMaxCertDbSize
);
208 if (mCertDbStore
== NULL
) {
209 return EFI_OUT_OF_RESOURCES
;
213 // Prepare runtime buffer for serialized data of time-based authenticated
214 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).
216 mSerializationRuntimeBuffer
= AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize
) + sizeof (EFI_GUID
) + sizeof (UINT32
) + sizeof (EFI_TIME
));
217 if (mSerializationRuntimeBuffer
== NULL
) {
218 return EFI_OUT_OF_RESOURCES
;
222 // Check "AuthVarKeyDatabase" variable's existence.
223 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
225 Status
= FindVariable (
227 &gEfiAuthenticatedVariableGuid
,
229 &mVariableModuleGlobal
->VariableGlobal
,
233 if (Variable
.CurrPtr
== NULL
) {
234 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
237 Status
= UpdateVariable (
239 &gEfiAuthenticatedVariableGuid
,
248 if (EFI_ERROR (Status
)) {
253 // Load database in global variable for cache.
255 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
256 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
257 ASSERT ((DataSize
!= 0) && (Data
!= NULL
));
259 // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
260 // Therefore, there is no memory overflow in underlying CopyMem.
262 CopyMem (mPubKeyStore
, (UINT8
*) Data
, DataSize
);
263 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
266 FindVariable (EFI_PLATFORM_KEY_NAME
, &gEfiGlobalVariableGuid
, &PkVariable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
267 if (PkVariable
.CurrPtr
== NULL
) {
268 DEBUG ((EFI_D_INFO
, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME
));
270 DEBUG ((EFI_D_INFO
, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME
));
274 // Create "SetupMode" variable with BS+RT attribute set.
276 FindVariable (EFI_SETUP_MODE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
277 if (PkVariable
.CurrPtr
== NULL
) {
278 mPlatformMode
= SETUP_MODE
;
280 mPlatformMode
= USER_MODE
;
282 Status
= UpdateVariable (
284 &gEfiGlobalVariableGuid
,
287 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
293 if (EFI_ERROR (Status
)) {
298 // Create "SignatureSupport" variable with BS+RT attribute set.
300 FindVariable (EFI_SIGNATURE_SUPPORT_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
301 Status
= UpdateVariable (
302 EFI_SIGNATURE_SUPPORT_NAME
,
303 &gEfiGlobalVariableGuid
,
305 sizeof(mSignatureSupport
),
306 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
312 if (EFI_ERROR (Status
)) {
317 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
318 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
319 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
321 SecureBootEnable
= SECURE_BOOT_DISABLE
;
322 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME
, &gEfiSecureBootEnableDisableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
323 if (Variable
.CurrPtr
!= NULL
) {
324 SecureBootEnable
= *(GetVariableDataPtr (Variable
.CurrPtr
));
325 } else if (mPlatformMode
== USER_MODE
) {
327 // "SecureBootEnable" not exist, initialize it in USER_MODE.
329 SecureBootEnable
= SECURE_BOOT_ENABLE
;
330 Status
= UpdateVariable (
331 EFI_SECURE_BOOT_ENABLE_NAME
,
332 &gEfiSecureBootEnableDisableGuid
,
335 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
341 if (EFI_ERROR (Status
)) {
347 // Create "SecureBoot" variable with BS+RT attribute set.
349 if (SecureBootEnable
== SECURE_BOOT_ENABLE
&& mPlatformMode
== USER_MODE
) {
350 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
352 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
354 FindVariable (EFI_SECURE_BOOT_MODE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
355 Status
= UpdateVariable (
356 EFI_SECURE_BOOT_MODE_NAME
,
357 &gEfiGlobalVariableGuid
,
360 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
366 if (EFI_ERROR (Status
)) {
370 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SETUP_MODE_NAME
, mPlatformMode
));
371 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME
, SecureBootMode
));
372 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME
, SecureBootEnable
));
375 // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
377 FindVariable (EFI_CUSTOM_MODE_NAME
, &gEfiCustomModeEnableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
378 CustomMode
= STANDARD_SECURE_BOOT_MODE
;
379 Status
= UpdateVariable (
380 EFI_CUSTOM_MODE_NAME
,
381 &gEfiCustomModeEnableGuid
,
384 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
390 if (EFI_ERROR (Status
)) {
394 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME
, CustomMode
));
397 // Check "certdb" variable's existence.
398 // If it doesn't exist, then create a new one with
399 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
401 Status
= FindVariable (
405 &mVariableModuleGlobal
->VariableGlobal
,
409 if (Variable
.CurrPtr
== NULL
) {
410 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
411 ListSize
= sizeof (UINT32
);
412 Status
= UpdateVariable (
423 if (EFI_ERROR (Status
)) {
429 // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.
431 FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME
, &gEfiVendorKeysNvGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
432 if (Variable
.CurrPtr
!= NULL
) {
433 mVendorKeyState
= *(GetVariableDataPtr (Variable
.CurrPtr
));
436 // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.
438 mVendorKeyState
= VENDOR_KEYS_VALID
;
439 Status
= UpdateVariable (
440 EFI_VENDOR_KEYS_NV_VARIABLE_NAME
,
441 &gEfiVendorKeysNvGuid
,
444 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
,
450 if (EFI_ERROR (Status
)) {
456 // Create "VendorKeys" variable with BS+RT attribute set.
458 FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
459 Status
= UpdateVariable (
460 EFI_VENDOR_KEYS_VARIABLE_NAME
,
461 &gEfiGlobalVariableGuid
,
464 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
470 if (EFI_ERROR (Status
)) {
474 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME
, mVendorKeyState
));
480 Add public key in store and return its index.
482 @param[in] PubKey Input pointer to Public Key data
483 @param[in] VariableDataEntry The variable data entry
485 @return Index of new added item
491 IN VARIABLE_ENTRY_CONSISTENCY
*VariableDataEntry
497 VARIABLE_POINTER_TRACK Variable
;
501 VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry
;
504 if (PubKey
== NULL
) {
508 Status
= FindVariable (
510 &gEfiAuthenticatedVariableGuid
,
512 &mVariableModuleGlobal
->VariableGlobal
,
515 if (EFI_ERROR (Status
)) {
516 DEBUG ((EFI_D_ERROR
, "Get public key database variable failure, Status = %r\n", Status
));
521 // Check whether the public key entry does exist.
524 for (Ptr
= mPubKeyStore
, Index
= 1; Index
<= mPubKeyNumber
; Index
++) {
525 if (CompareMem (Ptr
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
529 Ptr
+= EFI_CERT_TYPE_RSA2048_SIZE
;
534 // Add public key in database.
536 if (mPubKeyNumber
== mMaxKeyNumber
) {
538 // Public key dadatase is full, try to reclaim invalid key.
542 // NV storage can't reclaim at runtime.
548 mVariableModuleGlobal
->VariableGlobal
.NonVolatileVariableBase
,
549 &mVariableModuleGlobal
->NonVolatileLastVariableOffset
,
556 if (EFI_ERROR (Status
)) {
560 Status
= FindVariable (
562 &gEfiAuthenticatedVariableGuid
,
564 &mVariableModuleGlobal
->VariableGlobal
,
567 if (EFI_ERROR (Status
)) {
568 DEBUG ((EFI_D_ERROR
, "Get public key database variable failure, Status = %r\n", Status
));
572 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
573 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
574 ASSERT ((DataSize
!= 0) && (Data
!= NULL
));
576 // "AuthVarKeyDatabase" is an internal used variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
577 // Therefore, there is no memory overflow in underlying CopyMem.
579 CopyMem (mPubKeyStore
, (UINT8
*) Data
, DataSize
);
580 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
582 if (mPubKeyNumber
== mMaxKeyNumber
) {
588 // Check the variable space for both public key and variable data.
590 PublicKeyEntry
.VariableSize
= (mPubKeyNumber
+ 1) * EFI_CERT_TYPE_RSA2048_SIZE
;
591 PublicKeyEntry
.Guid
= &gEfiAuthenticatedVariableGuid
;
592 PublicKeyEntry
.Name
= AUTHVAR_KEYDB_NAME
;
593 Attributes
= VARIABLE_ATTRIBUTE_NV_BS_RT
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
595 if (!CheckRemainingSpaceForConsistency (Attributes
, &PublicKeyEntry
, VariableDataEntry
, NULL
)) {
597 // No enough variable space.
602 CopyMem (mPubKeyStore
+ mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
603 Index
= ++mPubKeyNumber
;
605 // Update public key database variable.
607 Status
= UpdateVariable (
609 &gEfiAuthenticatedVariableGuid
,
611 mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
,
618 if (EFI_ERROR (Status
)) {
619 DEBUG ((EFI_D_ERROR
, "Update public key database variable failure, Status = %r\n", Status
));
628 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
629 Follow the steps in UEFI2.2.
631 Caution: This function may receive untrusted input.
632 This function may be invoked in SMM mode, and datasize and data are external input.
633 This function will do basic validation, before parse the data.
634 This function will parse the authentication carefully to avoid security issues, like
635 buffer overflow, integer overflow.
637 @param[in] Data Pointer to data with AuthInfo.
638 @param[in] DataSize Size of Data.
639 @param[in] PubKey Public key used for verification.
641 @retval EFI_INVALID_PARAMETER Invalid parameter.
642 @retval EFI_SECURITY_VIOLATION If authentication failed.
643 @retval EFI_SUCCESS Authentication successful.
647 VerifyCounterBasedPayload (
654 EFI_VARIABLE_AUTHENTICATION
*CertData
;
655 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
656 UINT8 Digest
[SHA256_DIGEST_SIZE
];
660 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
665 if (Data
== NULL
|| PubKey
== NULL
) {
666 return EFI_INVALID_PARAMETER
;
669 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
670 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
673 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
674 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
676 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
677 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertTypeRsa2048Sha256Guid
)
680 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
682 return EFI_SECURITY_VIOLATION
;
685 // Hash data payload with SHA256.
687 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
688 Status
= Sha256Init (mHashCtx
);
692 Status
= Sha256Update (mHashCtx
, Data
+ AUTHINFO_SIZE
, PayloadSize
);
699 Status
= Sha256Update (mHashCtx
, &PayloadSize
, sizeof (UINTN
));
704 // Hash Monotonic Count.
706 Status
= Sha256Update (mHashCtx
, &CertData
->MonotonicCount
, sizeof (UINT64
));
710 Status
= Sha256Final (mHashCtx
, Digest
);
715 // Generate & Initialize RSA Context.
718 ASSERT (Rsa
!= NULL
);
720 // Set RSA Key Components.
721 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
723 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
727 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
732 // Verify the signature.
734 Status
= RsaPkcs1Verify (
738 CertBlock
->Signature
,
739 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
749 return EFI_SECURITY_VIOLATION
;
754 Update platform mode.
756 @param[in] Mode SETUP_MODE or USER_MODE.
758 @return EFI_INVALID_PARAMETER Invalid parameter.
759 @return EFI_SUCCESS Update platform mode successfully.
768 VARIABLE_POINTER_TRACK Variable
;
769 UINT8 SecureBootMode
;
770 UINT8 SecureBootEnable
;
771 UINTN VariableDataSize
;
773 Status
= FindVariable (
775 &gEfiGlobalVariableGuid
,
777 &mVariableModuleGlobal
->VariableGlobal
,
780 if (EFI_ERROR (Status
)) {
785 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
786 // variable storage reclaim at runtime.
788 mPlatformMode
= (UINT8
) Mode
;
789 CopyMem (GetVariableDataPtr (Variable
.CurrPtr
), &mPlatformMode
, sizeof(UINT8
));
793 // SecureBoot Variable indicates whether the platform firmware is operating
794 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
795 // Variable in runtime.
801 // Check "SecureBoot" variable's existence.
802 // If it doesn't exist, firmware has no capability to perform driver signing verification,
803 // then set "SecureBoot" to 0.
805 Status
= FindVariable (
806 EFI_SECURE_BOOT_MODE_NAME
,
807 &gEfiGlobalVariableGuid
,
809 &mVariableModuleGlobal
->VariableGlobal
,
813 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
814 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
815 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
817 if (Variable
.CurrPtr
== NULL
) {
818 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
820 if (mPlatformMode
== USER_MODE
) {
821 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
822 } else if (mPlatformMode
== SETUP_MODE
) {
823 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
825 return EFI_NOT_FOUND
;
829 Status
= UpdateVariable (
830 EFI_SECURE_BOOT_MODE_NAME
,
831 &gEfiGlobalVariableGuid
,
834 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
840 if (EFI_ERROR (Status
)) {
845 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
847 Status
= FindVariable (
848 EFI_SECURE_BOOT_ENABLE_NAME
,
849 &gEfiSecureBootEnableDisableGuid
,
851 &mVariableModuleGlobal
->VariableGlobal
,
855 if (SecureBootMode
== SECURE_BOOT_MODE_ENABLE
) {
857 // Create the "SecureBootEnable" variable as secure boot is enabled.
859 SecureBootEnable
= SECURE_BOOT_ENABLE
;
860 VariableDataSize
= sizeof (SecureBootEnable
);
863 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
864 // variable is not in secure boot state.
866 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
869 SecureBootEnable
= SECURE_BOOT_DISABLE
;
870 VariableDataSize
= 0;
873 Status
= UpdateVariable (
874 EFI_SECURE_BOOT_ENABLE_NAME
,
875 &gEfiSecureBootEnableDisableGuid
,
878 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
888 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx variable.
890 @param[in] VariableName Name of Variable to be check.
891 @param[in] VendorGuid Variable vendor GUID.
892 @param[in] Data Point to the variable data to be checked.
893 @param[in] DataSize Size of Data.
895 @return EFI_INVALID_PARAMETER Invalid signature list format.
896 @return EFI_SUCCESS Passed signature list format check successfully.
900 CheckSignatureListFormat(
901 IN CHAR16
*VariableName
,
902 IN EFI_GUID
*VendorGuid
,
907 EFI_SIGNATURE_LIST
*SigList
;
913 EFI_SIGNATURE_DATA
*CertData
;
920 ASSERT (VariableName
!= NULL
&& VendorGuid
!= NULL
&& Data
!= NULL
);
922 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_PLATFORM_KEY_NAME
) == 0)){
924 } else if ((CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0) ||
925 (CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
926 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0 || StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0))){
933 SigList
= (EFI_SIGNATURE_LIST
*) Data
;
934 SigDataSize
= DataSize
;
938 // Walk throuth the input signature list and check the data format.
939 // If any signature is incorrectly formed, the whole check will fail.
941 while ((SigDataSize
> 0) && (SigDataSize
>= SigList
->SignatureListSize
)) {
942 for (Index
= 0; Index
< (sizeof (mSupportSigItem
) / sizeof (EFI_SIGNATURE_ITEM
)); Index
++ ) {
943 if (CompareGuid (&SigList
->SignatureType
, &mSupportSigItem
[Index
].SigType
)) {
945 // The value of SignatureSize should always be 16 (size of SignatureOwner
946 // component) add the data length according to signature type.
948 if (mSupportSigItem
[Index
].SigDataSize
!= ((UINT32
) ~0) &&
949 (SigList
->SignatureSize
- sizeof (EFI_GUID
)) != mSupportSigItem
[Index
].SigDataSize
) {
950 return EFI_INVALID_PARAMETER
;
952 if (mSupportSigItem
[Index
].SigHeaderSize
!= ((UINTN
) ~0) &&
953 SigList
->SignatureHeaderSize
!= mSupportSigItem
[Index
].SigHeaderSize
) {
954 return EFI_INVALID_PARAMETER
;
960 if (Index
== (sizeof (mSupportSigItem
) / sizeof (EFI_SIGNATURE_ITEM
))) {
962 // Undefined signature type.
964 return EFI_INVALID_PARAMETER
;
967 if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
969 // Try to retrieve the RSA public key from the X.509 certificate.
970 // If this operation fails, it's not a valid certificate.
972 RsaContext
= RsaNew ();
973 if (RsaContext
== NULL
) {
974 return EFI_INVALID_PARAMETER
;
976 CertData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) + SigList
->SignatureHeaderSize
);
977 CertLen
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
978 if (!RsaGetPublicKeyFromX509 (CertData
->SignatureData
, CertLen
, &RsaContext
)) {
979 RsaFree (RsaContext
);
980 return EFI_INVALID_PARAMETER
;
982 RsaFree (RsaContext
);
985 if ((SigList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - SigList
->SignatureHeaderSize
) % SigList
->SignatureSize
!= 0) {
986 return EFI_INVALID_PARAMETER
;
988 SigCount
+= (SigList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - SigList
->SignatureHeaderSize
) / SigList
->SignatureSize
;
990 SigDataSize
-= SigList
->SignatureListSize
;
991 SigList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) SigList
+ SigList
->SignatureListSize
);
994 if (((UINTN
) SigList
- (UINTN
) Data
) != DataSize
) {
995 return EFI_INVALID_PARAMETER
;
998 if (IsPk
&& SigCount
> 1) {
999 return EFI_INVALID_PARAMETER
;
1006 Update "VendorKeys" variable to record the out of band secure boot key modification.
1008 @return EFI_SUCCESS Variable is updated successfully.
1009 @return Others Failed to update variable.
1013 VendorKeyIsModified (
1018 VARIABLE_POINTER_TRACK Variable
;
1020 if (mVendorKeyState
== VENDOR_KEYS_MODIFIED
) {
1023 mVendorKeyState
= VENDOR_KEYS_MODIFIED
;
1025 FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME
, &gEfiVendorKeysNvGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1026 Status
= UpdateVariable (
1027 EFI_VENDOR_KEYS_NV_VARIABLE_NAME
,
1028 &gEfiVendorKeysNvGuid
,
1031 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
,
1037 if (EFI_ERROR (Status
)) {
1041 FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
1042 return UpdateVariable (
1043 EFI_VENDOR_KEYS_VARIABLE_NAME
,
1044 &gEfiGlobalVariableGuid
,
1047 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1056 Process variable with platform key for verification.
1058 Caution: This function may receive untrusted input.
1059 This function may be invoked in SMM mode, and datasize and data are external input.
1060 This function will do basic validation, before parse the data.
1061 This function will parse the authentication carefully to avoid security issues, like
1062 buffer overflow, integer overflow.
1063 This function will check attribute carefully to avoid authentication bypass.
1065 @param[in] VariableName Name of Variable to be found.
1066 @param[in] VendorGuid Variable vendor GUID.
1067 @param[in] Data Data pointer.
1068 @param[in] DataSize Size of Data found. If size is less than the
1069 data, this value contains the required size.
1070 @param[in] Variable The variable information which is used to keep track of variable usage.
1071 @param[in] Attributes Attribute value of the variable
1072 @param[in] IsPk Indicate whether it is to process pk.
1074 @return EFI_INVALID_PARAMETER Invalid parameter.
1075 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
1076 check carried out by the firmware.
1077 @return EFI_SUCCESS Variable passed validation successfully.
1082 IN CHAR16
*VariableName
,
1083 IN EFI_GUID
*VendorGuid
,
1086 IN VARIABLE_POINTER_TRACK
*Variable
,
1087 IN UINT32 Attributes OPTIONAL
,
1096 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0 ||
1097 (Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == 0) {
1099 // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
1100 // authenticated variable.
1102 return EFI_INVALID_PARAMETER
;
1106 if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode
== SETUP_MODE
&& !IsPk
)) {
1107 Payload
= (UINT8
*) Data
+ AUTHINFO2_SIZE (Data
);
1108 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
1109 if (PayloadSize
== 0) {
1113 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, Payload
, PayloadSize
);
1114 if (EFI_ERROR (Status
)) {
1118 Status
= UpdateVariable (
1127 &((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->TimeStamp
1129 if (EFI_ERROR(Status
)) {
1133 if ((mPlatformMode
!= SETUP_MODE
) || IsPk
) {
1134 Status
= VendorKeyIsModified ();
1136 } else if (mPlatformMode
== USER_MODE
) {
1138 // Verify against X509 Cert in PK database.
1140 Status
= VerifyTimeBasedPayload (
1152 // Verify against the certificate in data payload.
1154 Status
= VerifyTimeBasedPayload (
1166 if (!EFI_ERROR(Status
) && IsPk
) {
1167 if (mPlatformMode
== SETUP_MODE
&& !Del
) {
1169 // If enroll PK in setup mode, need change to user mode.
1171 Status
= UpdatePlatformMode (USER_MODE
);
1172 } else if (mPlatformMode
== USER_MODE
&& Del
){
1174 // If delete PK in user mode, need change to setup mode.
1176 Status
= UpdatePlatformMode (SETUP_MODE
);
1184 Process variable with key exchange key for verification.
1186 Caution: This function may receive untrusted input.
1187 This function may be invoked in SMM mode, and datasize and data are external input.
1188 This function will do basic validation, before parse the data.
1189 This function will parse the authentication carefully to avoid security issues, like
1190 buffer overflow, integer overflow.
1191 This function will check attribute carefully to avoid authentication bypass.
1193 @param[in] VariableName Name of Variable to be found.
1194 @param[in] VendorGuid Variable vendor GUID.
1195 @param[in] Data Data pointer.
1196 @param[in] DataSize Size of Data found. If size is less than the
1197 data, this value contains the required size.
1198 @param[in] Variable The variable information which is used to keep track of variable usage.
1199 @param[in] Attributes Attribute value of the variable.
1201 @return EFI_INVALID_PARAMETER Invalid parameter.
1202 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1203 check carried out by the firmware.
1204 @return EFI_SUCCESS Variable pass validation successfully.
1209 IN CHAR16
*VariableName
,
1210 IN EFI_GUID
*VendorGuid
,
1213 IN VARIABLE_POINTER_TRACK
*Variable
,
1214 IN UINT32 Attributes OPTIONAL
1221 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0 ||
1222 (Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == 0) {
1224 // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
1225 // authenticated variable.
1227 return EFI_INVALID_PARAMETER
;
1230 Status
= EFI_SUCCESS
;
1231 if (mPlatformMode
== USER_MODE
&& !(InCustomMode() && UserPhysicalPresent())) {
1233 // Time-based, verify against X509 Cert KEK.
1235 return VerifyTimeBasedPayload (
1247 // If in setup mode or custom secure boot mode, no authentication needed.
1249 Payload
= (UINT8
*) Data
+ AUTHINFO2_SIZE (Data
);
1250 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
1252 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, Payload
, PayloadSize
);
1253 if (EFI_ERROR (Status
)) {
1257 Status
= UpdateVariable (
1266 &((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->TimeStamp
1268 if (EFI_ERROR (Status
)) {
1272 if (mPlatformMode
!= SETUP_MODE
) {
1273 Status
= VendorKeyIsModified ();
1281 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1283 Caution: This function may receive untrusted input.
1284 This function may be invoked in SMM mode, and datasize and data are external input.
1285 This function will do basic validation, before parse the data.
1286 This function will parse the authentication carefully to avoid security issues, like
1287 buffer overflow, integer overflow.
1288 This function will check attribute carefully to avoid authentication bypass.
1290 @param[in] VariableName Name of Variable to be found.
1291 @param[in] VendorGuid Variable vendor GUID.
1293 @param[in] Data Data pointer.
1294 @param[in] DataSize Size of Data found. If size is less than the
1295 data, this value contains the required size.
1296 @param[in] Variable The variable information which is used to keep track of variable usage.
1297 @param[in] Attributes Attribute value of the variable.
1299 @return EFI_INVALID_PARAMETER Invalid parameter.
1300 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
1301 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1302 @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
1303 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1304 set, but the AuthInfo does NOT pass the validation
1305 check carried out by the firmware.
1306 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
1311 IN CHAR16
*VariableName
,
1312 IN EFI_GUID
*VendorGuid
,
1315 IN VARIABLE_POINTER_TRACK
*Variable
,
1316 IN UINT32 Attributes
1321 BOOLEAN IsFirstTime
;
1323 EFI_VARIABLE_AUTHENTICATION
*CertData
;
1324 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
1326 UINT64 MonotonicCount
;
1327 VARIABLE_ENTRY_CONSISTENCY VariableDataEntry
;
1335 if (NeedPhysicallyPresent(VariableName
, VendorGuid
) && !UserPhysicalPresent()) {
1337 // This variable is protected, only physical present user could modify its value.
1339 return EFI_SECURITY_VIOLATION
;
1343 // A time-based authenticated variable and a count-based authenticated variable
1344 // can't be updated by each other.
1346 if (Variable
->CurrPtr
!= NULL
) {
1347 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
1348 ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0)) {
1349 return EFI_SECURITY_VIOLATION
;
1352 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
1353 ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0)) {
1354 return EFI_SECURITY_VIOLATION
;
1359 // Process Time-based Authenticated variable.
1361 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
1362 return VerifyTimeBasedPayload (
1375 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
1377 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
1379 // Determine current operation type.
1381 if (DataSize
== AUTHINFO_SIZE
) {
1385 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1387 if (Variable
->CurrPtr
== NULL
) {
1389 } else if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
1392 KeyIndex
= Variable
->CurrPtr
->PubKeyIndex
;
1393 IsFirstTime
= FALSE
;
1395 } else if ((Variable
->CurrPtr
!= NULL
) &&
1396 ((Variable
->CurrPtr
->Attributes
& (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) != 0)
1399 // If the variable is already write-protected, it always needs authentication before update.
1401 return EFI_WRITE_PROTECTED
;
1404 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
1405 // That means it is not authenticated variable, just update variable as usual.
1407 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, Variable
, NULL
);
1412 // Get PubKey and check Monotonic Count value corresponding to the variable.
1414 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
1415 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
1416 PubKey
= CertBlock
->PublicKey
;
1419 // Update Monotonic Count value.
1421 MonotonicCount
= CertData
->MonotonicCount
;
1425 // 2 cases need to check here
1426 // 1. Internal PubKey variable. PubKeyIndex is always 0
1427 // 2. Other counter-based AuthVariable. Check input PubKey.
1429 if (KeyIndex
== 0 || CompareMem (PubKey
, mPubKeyStore
+ (KeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
, EFI_CERT_TYPE_RSA2048_SIZE
) != 0) {
1430 return EFI_SECURITY_VIOLATION
;
1433 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
1434 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
1436 if (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
) {
1438 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1440 return EFI_SECURITY_VIOLATION
;
1444 // Verify the certificate in Data payload.
1446 Status
= VerifyCounterBasedPayload (Data
, DataSize
, PubKey
);
1447 if (EFI_ERROR (Status
)) {
1452 // Now, the signature has been verified!
1454 if (IsFirstTime
&& !IsDeletion
) {
1455 VariableDataEntry
.VariableSize
= DataSize
- AUTHINFO_SIZE
;
1456 VariableDataEntry
.Guid
= VendorGuid
;
1457 VariableDataEntry
.Name
= VariableName
;
1460 // Update public key database variable if need.
1462 KeyIndex
= AddPubKeyInStore (PubKey
, &VariableDataEntry
);
1463 if (KeyIndex
== 0) {
1464 return EFI_OUT_OF_RESOURCES
;
1469 // Verification pass.
1471 return UpdateVariable (VariableName
, VendorGuid
, (UINT8
*)Data
+ AUTHINFO_SIZE
, DataSize
- AUTHINFO_SIZE
, Attributes
, KeyIndex
, MonotonicCount
, Variable
, NULL
);
1475 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
1476 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
1479 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
1480 @param[in] DataSize Size of Data buffer.
1481 @param[in] FreeBufSize Size of free data buffer
1482 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
1483 @param[in] NewDataSize Size of NewData buffer.
1484 @param[out] MergedBufSize Size of the merged buffer
1486 @return EFI_BUFFER_TOO_SMALL if input Data buffer overflowed
1490 AppendSignatureList (
1493 IN UINTN FreeBufSize
,
1495 IN UINTN NewDataSize
,
1496 OUT UINTN
*MergedBufSize
1499 EFI_SIGNATURE_LIST
*CertList
;
1500 EFI_SIGNATURE_DATA
*Cert
;
1502 EFI_SIGNATURE_LIST
*NewCertList
;
1503 EFI_SIGNATURE_DATA
*NewCert
;
1510 UINTN SignatureListSize
;
1513 Tail
= (UINT8
*) Data
+ DataSize
;
1515 NewCertList
= (EFI_SIGNATURE_LIST
*) NewData
;
1516 while ((NewDataSize
> 0) && (NewDataSize
>= NewCertList
->SignatureListSize
)) {
1517 NewCert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) NewCertList
+ sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
);
1518 NewCertCount
= (NewCertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - NewCertList
->SignatureHeaderSize
) / NewCertList
->SignatureSize
;
1521 for (Index
= 0; Index
< NewCertCount
; Index
++) {
1525 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
1526 while ((Size
> 0) && (Size
>= CertList
->SignatureListSize
)) {
1527 if (CompareGuid (&CertList
->SignatureType
, &NewCertList
->SignatureType
) &&
1528 (CertList
->SignatureSize
== NewCertList
->SignatureSize
)) {
1529 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1530 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
1531 for (Index2
= 0; Index2
< CertCount
; Index2
++) {
1533 // Iterate each Signature Data in this Signature List.
1535 if (CompareMem (NewCert
, Cert
, CertList
->SignatureSize
) == 0) {
1539 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
1546 Size
-= CertList
->SignatureListSize
;
1547 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
1552 // New EFI_SIGNATURE_DATA, append it.
1554 if (CopiedCount
== 0) {
1555 if (FreeBufSize
< sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
) {
1556 return EFI_BUFFER_TOO_SMALL
;
1560 // Copy EFI_SIGNATURE_LIST header for only once.
1563 CopyMem (Tail
, NewCertList
, sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
);
1564 Tail
= Tail
+ sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
;
1565 FreeBufSize
-= sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
;
1568 if (FreeBufSize
< NewCertList
->SignatureSize
) {
1569 return EFI_BUFFER_TOO_SMALL
;
1571 CopyMem (Tail
, NewCert
, NewCertList
->SignatureSize
);
1572 Tail
+= NewCertList
->SignatureSize
;
1573 FreeBufSize
-= NewCertList
->SignatureSize
;
1577 NewCert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) NewCert
+ NewCertList
->SignatureSize
);
1581 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
1583 if (CopiedCount
!= 0) {
1584 SignatureListSize
= sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
+ (CopiedCount
* NewCertList
->SignatureSize
);
1585 CertList
= (EFI_SIGNATURE_LIST
*) (Tail
- SignatureListSize
);
1586 CertList
->SignatureListSize
= (UINT32
) SignatureListSize
;
1589 NewDataSize
-= NewCertList
->SignatureListSize
;
1590 NewCertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) NewCertList
+ NewCertList
->SignatureListSize
);
1593 *MergedBufSize
= (Tail
- (UINT8
*) Data
);
1598 Compare two EFI_TIME data.
1601 @param FirstTime A pointer to the first EFI_TIME data.
1602 @param SecondTime A pointer to the second EFI_TIME data.
1604 @retval TRUE The FirstTime is not later than the SecondTime.
1605 @retval FALSE The FirstTime is later than the SecondTime.
1610 IN EFI_TIME
*FirstTime
,
1611 IN EFI_TIME
*SecondTime
1614 if (FirstTime
->Year
!= SecondTime
->Year
) {
1615 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
1616 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
1617 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
1618 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
1619 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
1620 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
1621 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
1622 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
1623 return (BOOLEAN
) (FirstTime
->Minute
< SecondTime
->Minute
);
1626 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
1630 Find matching signer's certificates for common authenticated variable
1631 by corresponding VariableName and VendorGuid from "certdb".
1633 The data format of "certdb":
1635 // UINT32 CertDbListSize;
1636 // /// AUTH_CERT_DB_DATA Certs1[];
1637 // /// AUTH_CERT_DB_DATA Certs2[];
1639 // /// AUTH_CERT_DB_DATA Certsn[];
1642 @param[in] VariableName Name of authenticated Variable.
1643 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1644 @param[in] Data Pointer to variable "certdb".
1645 @param[in] DataSize Size of variable "certdb".
1646 @param[out] CertOffset Offset of matching CertData, from starting of Data.
1647 @param[out] CertDataSize Length of CertData in bytes.
1648 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
1650 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
1652 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1653 @retval EFI_NOT_FOUND Fail to find matching certs.
1654 @retval EFI_SUCCESS Find matching certs and output parameters.
1659 IN CHAR16
*VariableName
,
1660 IN EFI_GUID
*VendorGuid
,
1663 OUT UINT32
*CertOffset
, OPTIONAL
1664 OUT UINT32
*CertDataSize
, OPTIONAL
1665 OUT UINT32
*CertNodeOffset
,OPTIONAL
1666 OUT UINT32
*CertNodeSize OPTIONAL
1670 AUTH_CERT_DB_DATA
*Ptr
;
1674 UINT32 CertDbListSize
;
1676 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
)) {
1677 return EFI_INVALID_PARAMETER
;
1681 // Check whether DataSize matches recorded CertDbListSize.
1683 if (DataSize
< sizeof (UINT32
)) {
1684 return EFI_INVALID_PARAMETER
;
1687 CertDbListSize
= ReadUnaligned32 ((UINT32
*) Data
);
1689 if (CertDbListSize
!= (UINT32
) DataSize
) {
1690 return EFI_INVALID_PARAMETER
;
1693 Offset
= sizeof (UINT32
);
1696 // Get corresponding certificates by VendorGuid and VariableName.
1698 while (Offset
< (UINT32
) DataSize
) {
1699 Ptr
= (AUTH_CERT_DB_DATA
*) (Data
+ Offset
);
1701 // Check whether VendorGuid matches.
1703 if (CompareGuid (&Ptr
->VendorGuid
, VendorGuid
)) {
1704 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
1705 NameSize
= ReadUnaligned32 (&Ptr
->NameSize
);
1706 CertSize
= ReadUnaligned32 (&Ptr
->CertDataSize
);
1708 if (NodeSize
!= sizeof (EFI_GUID
) + sizeof (UINT32
) * 3 + CertSize
+
1709 sizeof (CHAR16
) * NameSize
) {
1710 return EFI_INVALID_PARAMETER
;
1713 Offset
= Offset
+ sizeof (EFI_GUID
) + sizeof (UINT32
) * 3;
1715 // Check whether VariableName matches.
1717 if ((NameSize
== StrLen (VariableName
)) &&
1718 (CompareMem (Data
+ Offset
, VariableName
, NameSize
* sizeof (CHAR16
)) == 0)) {
1719 Offset
= Offset
+ NameSize
* sizeof (CHAR16
);
1721 if (CertOffset
!= NULL
) {
1722 *CertOffset
= Offset
;
1725 if (CertDataSize
!= NULL
) {
1726 *CertDataSize
= CertSize
;
1729 if (CertNodeOffset
!= NULL
) {
1730 *CertNodeOffset
= (UINT32
) ((UINT8
*) Ptr
- Data
);
1733 if (CertNodeSize
!= NULL
) {
1734 *CertNodeSize
= NodeSize
;
1739 Offset
= Offset
+ NameSize
* sizeof (CHAR16
) + CertSize
;
1742 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
1743 Offset
= Offset
+ NodeSize
;
1747 return EFI_NOT_FOUND
;
1751 Retrieve signer's certificates for common authenticated variable
1752 by corresponding VariableName and VendorGuid from "certdb".
1754 @param[in] VariableName Name of authenticated Variable.
1755 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1756 @param[out] CertData Pointer to signer's certificates.
1757 @param[out] CertDataSize Length of CertData in bytes.
1759 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1760 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1761 @retval EFI_SUCCESS Get signer's certificates successfully.
1766 IN CHAR16
*VariableName
,
1767 IN EFI_GUID
*VendorGuid
,
1768 OUT UINT8
**CertData
,
1769 OUT UINT32
*CertDataSize
1772 VARIABLE_POINTER_TRACK CertDbVariable
;
1778 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (CertData
== NULL
) || (CertDataSize
== NULL
)) {
1779 return EFI_INVALID_PARAMETER
;
1783 // Get variable "certdb".
1785 Status
= FindVariable (
1789 &mVariableModuleGlobal
->VariableGlobal
,
1792 if (EFI_ERROR (Status
)) {
1796 DataSize
= DataSizeOfVariable (CertDbVariable
.CurrPtr
);
1797 Data
= GetVariableDataPtr (CertDbVariable
.CurrPtr
);
1798 if ((DataSize
== 0) || (Data
== NULL
)) {
1800 return EFI_NOT_FOUND
;
1803 Status
= FindCertsFromDb (
1814 if (EFI_ERROR (Status
)) {
1818 *CertData
= Data
+ CertOffset
;
1823 Delete matching signer's certificates when deleting common authenticated
1824 variable by corresponding VariableName and VendorGuid from "certdb".
1826 @param[in] VariableName Name of authenticated Variable.
1827 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1829 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1830 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1831 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1832 @retval EFI_SUCCESS The operation is completed successfully.
1837 IN CHAR16
*VariableName
,
1838 IN EFI_GUID
*VendorGuid
1841 VARIABLE_POINTER_TRACK CertDbVariable
;
1846 UINT32 CertNodeOffset
;
1847 UINT32 CertNodeSize
;
1849 UINT32 NewCertDbSize
;
1851 if ((VariableName
== NULL
) || (VendorGuid
== NULL
)) {
1852 return EFI_INVALID_PARAMETER
;
1856 // Get variable "certdb".
1858 Status
= FindVariable (
1862 &mVariableModuleGlobal
->VariableGlobal
,
1865 if (EFI_ERROR (Status
)) {
1869 DataSize
= DataSizeOfVariable (CertDbVariable
.CurrPtr
);
1870 Data
= GetVariableDataPtr (CertDbVariable
.CurrPtr
);
1871 if ((DataSize
== 0) || (Data
== NULL
)) {
1873 return EFI_NOT_FOUND
;
1876 if (DataSize
== sizeof (UINT32
)) {
1878 // There is no certs in certdb.
1884 // Get corresponding cert node from certdb.
1886 Status
= FindCertsFromDb (
1897 if (EFI_ERROR (Status
)) {
1901 if (DataSize
< (CertNodeOffset
+ CertNodeSize
)) {
1902 return EFI_NOT_FOUND
;
1906 // Construct new data content of variable "certdb".
1908 NewCertDbSize
= (UINT32
) DataSize
- CertNodeSize
;
1909 NewCertDb
= (UINT8
*) mCertDbStore
;
1912 // Copy the DB entries before deleting node.
1914 CopyMem (NewCertDb
, Data
, CertNodeOffset
);
1916 // Update CertDbListSize.
1918 CopyMem (NewCertDb
, &NewCertDbSize
, sizeof (UINT32
));
1920 // Copy the DB entries after deleting node.
1922 if (DataSize
> (CertNodeOffset
+ CertNodeSize
)) {
1924 NewCertDb
+ CertNodeOffset
,
1925 Data
+ CertNodeOffset
+ CertNodeSize
,
1926 DataSize
- CertNodeOffset
- CertNodeSize
1933 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
1934 Status
= UpdateVariable (
1950 Insert signer's certificates for common authenticated variable with VariableName
1951 and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
1953 @param[in] VariableName Name of authenticated Variable.
1954 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1955 @param[in] CertData Pointer to signer's certificates.
1956 @param[in] CertDataSize Length of CertData in bytes.
1958 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1959 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
1960 and VendorGuid already exists.
1961 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1962 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"
1967 IN CHAR16
*VariableName
,
1968 IN EFI_GUID
*VendorGuid
,
1970 IN UINTN CertDataSize
1973 VARIABLE_POINTER_TRACK CertDbVariable
;
1979 UINT32 NewCertDbSize
;
1980 UINT32 CertNodeSize
;
1982 AUTH_CERT_DB_DATA
*Ptr
;
1984 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (CertData
== NULL
)) {
1985 return EFI_INVALID_PARAMETER
;
1989 // Get variable "certdb".
1991 Status
= FindVariable (
1995 &mVariableModuleGlobal
->VariableGlobal
,
1998 if (EFI_ERROR (Status
)) {
2002 DataSize
= DataSizeOfVariable (CertDbVariable
.CurrPtr
);
2003 Data
= GetVariableDataPtr (CertDbVariable
.CurrPtr
);
2004 if ((DataSize
== 0) || (Data
== NULL
)) {
2006 return EFI_NOT_FOUND
;
2010 // Find whether matching cert node already exists in "certdb".
2011 // If yes return error.
2013 Status
= FindCertsFromDb (
2024 if (!EFI_ERROR (Status
)) {
2026 return EFI_ACCESS_DENIED
;
2030 // Construct new data content of variable "certdb".
2032 NameSize
= (UINT32
) StrLen (VariableName
);
2033 CertNodeSize
= sizeof (AUTH_CERT_DB_DATA
) + (UINT32
) CertDataSize
+ NameSize
* sizeof (CHAR16
);
2034 NewCertDbSize
= (UINT32
) DataSize
+ CertNodeSize
;
2035 if (NewCertDbSize
> mMaxCertDbSize
) {
2036 return EFI_OUT_OF_RESOURCES
;
2038 NewCertDb
= (UINT8
*) mCertDbStore
;
2041 // Copy the DB entries before deleting node.
2043 CopyMem (NewCertDb
, Data
, DataSize
);
2045 // Update CertDbListSize.
2047 CopyMem (NewCertDb
, &NewCertDbSize
, sizeof (UINT32
));
2049 // Construct new cert node.
2051 Ptr
= (AUTH_CERT_DB_DATA
*) (NewCertDb
+ DataSize
);
2052 CopyGuid (&Ptr
->VendorGuid
, VendorGuid
);
2053 CopyMem (&Ptr
->CertNodeSize
, &CertNodeSize
, sizeof (UINT32
));
2054 CopyMem (&Ptr
->NameSize
, &NameSize
, sizeof (UINT32
));
2055 CopyMem (&Ptr
->CertDataSize
, &CertDataSize
, sizeof (UINT32
));
2058 (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
),
2060 NameSize
* sizeof (CHAR16
)
2064 (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
) + NameSize
* sizeof (CHAR16
),
2072 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
2073 Status
= UpdateVariable (
2089 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
2091 Caution: This function may receive untrusted input.
2092 This function may be invoked in SMM mode, and datasize and data are external input.
2093 This function will do basic validation, before parse the data.
2094 This function will parse the authentication carefully to avoid security issues, like
2095 buffer overflow, integer overflow.
2097 @param[in] VariableName Name of Variable to be found.
2098 @param[in] VendorGuid Variable vendor GUID.
2099 @param[in] Data Data pointer.
2100 @param[in] DataSize Size of Data found. If size is less than the
2101 data, this value contains the required size.
2102 @param[in] Variable The variable information which is used to keep track of variable usage.
2103 @param[in] Attributes Attribute value of the variable.
2104 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
2105 @param[out] VarDel Delete the variable or not.
2107 @retval EFI_INVALID_PARAMETER Invalid parameter.
2108 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
2109 check carried out by the firmware.
2110 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
2112 @retval EFI_SUCCESS Variable pass validation successfully.
2116 VerifyTimeBasedPayload (
2117 IN CHAR16
*VariableName
,
2118 IN EFI_GUID
*VendorGuid
,
2121 IN VARIABLE_POINTER_TRACK
*Variable
,
2122 IN UINT32 Attributes
,
2123 IN AUTHVAR_TYPE AuthVarType
,
2137 BOOLEAN VerifyStatus
;
2139 EFI_SIGNATURE_LIST
*CertList
;
2140 EFI_SIGNATURE_DATA
*Cert
;
2141 VARIABLE_POINTER_TRACK KekVariable
;
2142 EFI_VARIABLE_AUTHENTICATION_2
*CertData
;
2145 VARIABLE_POINTER_TRACK PkVariable
;
2150 UINTN CertStackSize
;
2151 UINT8
*CertsInCertDb
;
2152 UINT32 CertsSizeinDb
;
2154 VerifyStatus
= FALSE
;
2161 CertsInCertDb
= NULL
;
2164 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
2165 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
2166 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
2167 // variable value and DataSize shall reflect the combined size of the descriptor and the new
2168 // variable value. The authentication descriptor is not part of the variable data and is not
2169 // returned by subsequent calls to GetVariable().
2171 CertData
= (EFI_VARIABLE_AUTHENTICATION_2
*) Data
;
2174 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
2175 // TimeStamp value are set to zero.
2177 if ((CertData
->TimeStamp
.Pad1
!= 0) ||
2178 (CertData
->TimeStamp
.Nanosecond
!= 0) ||
2179 (CertData
->TimeStamp
.TimeZone
!= 0) ||
2180 (CertData
->TimeStamp
.Daylight
!= 0) ||
2181 (CertData
->TimeStamp
.Pad2
!= 0)) {
2182 return EFI_SECURITY_VIOLATION
;
2185 if ((Variable
->CurrPtr
!= NULL
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
2186 if (CompareTimeStamp (&CertData
->TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
2188 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
2190 return EFI_SECURITY_VIOLATION
;
2195 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
2196 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
2198 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
2199 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
)) {
2201 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
2203 return EFI_SECURITY_VIOLATION
;
2207 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2208 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
2210 SigData
= CertData
->AuthInfo
.CertData
;
2211 SigDataSize
= CertData
->AuthInfo
.Hdr
.dwLength
- (UINT32
) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
2214 // Find out the new data payload which follows Pkcs7 SignedData directly.
2216 PayloadPtr
= SigData
+ SigDataSize
;
2217 PayloadSize
= DataSize
- OFFSET_OF_AUTHINFO2_CERT_DATA
- (UINTN
) SigDataSize
;
2220 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
2222 NewDataSize
= PayloadSize
+ sizeof (EFI_TIME
) + sizeof (UINT32
) +
2223 sizeof (EFI_GUID
) + StrSize (VariableName
) - sizeof (CHAR16
);
2224 NewData
= mSerializationRuntimeBuffer
;
2227 Length
= StrLen (VariableName
) * sizeof (CHAR16
);
2228 CopyMem (Buffer
, VariableName
, Length
);
2231 Length
= sizeof (EFI_GUID
);
2232 CopyMem (Buffer
, VendorGuid
, Length
);
2235 Length
= sizeof (UINT32
);
2236 CopyMem (Buffer
, &Attr
, Length
);
2239 Length
= sizeof (EFI_TIME
);
2240 CopyMem (Buffer
, &CertData
->TimeStamp
, Length
);
2243 CopyMem (Buffer
, PayloadPtr
, PayloadSize
);
2245 if (AuthVarType
== AuthVarTypePk
) {
2247 // Verify that the signature has been made with the current Platform Key (no chaining for PK).
2248 // First, get signer's certificates from SignedData.
2250 VerifyStatus
= Pkcs7GetSigners (
2258 if (!VerifyStatus
) {
2263 // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
2264 // in SignedData. If not, return error immediately.
2266 Status
= FindVariable (
2267 EFI_PLATFORM_KEY_NAME
,
2268 &gEfiGlobalVariableGuid
,
2270 &mVariableModuleGlobal
->VariableGlobal
,
2273 if (EFI_ERROR (Status
)) {
2274 VerifyStatus
= FALSE
;
2277 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (PkVariable
.CurrPtr
);
2278 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
2279 if ((RootCertSize
!= (CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1))) ||
2280 (CompareMem (Cert
->SignatureData
, RootCert
, RootCertSize
) != 0)) {
2281 VerifyStatus
= FALSE
;
2286 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2288 VerifyStatus
= Pkcs7Verify (
2297 } else if (AuthVarType
== AuthVarTypeKek
) {
2300 // Get KEK database from variable.
2302 Status
= FindVariable (
2303 EFI_KEY_EXCHANGE_KEY_NAME
,
2304 &gEfiGlobalVariableGuid
,
2306 &mVariableModuleGlobal
->VariableGlobal
,
2309 if (EFI_ERROR (Status
)) {
2314 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
2316 KekDataSize
= KekVariable
.CurrPtr
->DataSize
;
2317 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (KekVariable
.CurrPtr
);
2318 while ((KekDataSize
> 0) && (KekDataSize
>= CertList
->SignatureListSize
)) {
2319 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
2320 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
2321 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
2322 for (Index
= 0; Index
< CertCount
; Index
++) {
2324 // Iterate each Signature Data Node within this CertList for a verify
2326 RootCert
= Cert
->SignatureData
;
2327 RootCertSize
= CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1);
2330 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2332 VerifyStatus
= Pkcs7Verify (
2343 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
2346 KekDataSize
-= CertList
->SignatureListSize
;
2347 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
2349 } else if (AuthVarType
== AuthVarTypePriv
) {
2352 // Process common authenticated variable except PK/KEK/DB/DBX.
2353 // Get signer's certificates from SignedData.
2355 VerifyStatus
= Pkcs7GetSigners (
2363 if (!VerifyStatus
) {
2368 // Get previously stored signer's certificates from certdb for existing
2369 // variable. Check whether they are identical with signer's certificates
2370 // in SignedData. If not, return error immediately.
2372 if ((Variable
->CurrPtr
!= NULL
)) {
2373 VerifyStatus
= FALSE
;
2375 Status
= GetCertsFromDb (VariableName
, VendorGuid
, &CertsInCertDb
, &CertsSizeinDb
);
2376 if (EFI_ERROR (Status
)) {
2380 if ((CertStackSize
!= CertsSizeinDb
) ||
2381 (CompareMem (SignerCerts
, CertsInCertDb
, CertsSizeinDb
) != 0)) {
2386 VerifyStatus
= Pkcs7Verify (
2394 if (!VerifyStatus
) {
2399 // Delete signer's certificates when delete the common authenticated variable.
2401 if ((PayloadSize
== 0) && (Variable
->CurrPtr
!= NULL
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
2402 Status
= DeleteCertsFromDb (VariableName
, VendorGuid
);
2403 if (EFI_ERROR (Status
)) {
2404 VerifyStatus
= FALSE
;
2407 } else if (Variable
->CurrPtr
== NULL
&& PayloadSize
!= 0) {
2409 // Insert signer's certificates when adding a new common authenticated variable.
2411 Status
= InsertCertsToDb (VariableName
, VendorGuid
, SignerCerts
, CertStackSize
);
2412 if (EFI_ERROR (Status
)) {
2413 VerifyStatus
= FALSE
;
2417 } else if (AuthVarType
== AuthVarTypePayload
) {
2418 CertList
= (EFI_SIGNATURE_LIST
*) PayloadPtr
;
2419 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
2420 RootCert
= Cert
->SignatureData
;
2421 RootCertSize
= CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1);
2423 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2425 VerifyStatus
= Pkcs7Verify (
2434 return EFI_SECURITY_VIOLATION
;
2439 if (AuthVarType
== AuthVarTypePk
|| AuthVarType
== AuthVarTypePriv
) {
2440 Pkcs7FreeSigners (RootCert
);
2441 Pkcs7FreeSigners (SignerCerts
);
2444 if (!VerifyStatus
) {
2445 return EFI_SECURITY_VIOLATION
;
2448 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, PayloadPtr
, PayloadSize
);
2449 if (EFI_ERROR (Status
)) {
2453 if ((PayloadSize
== 0) && (VarDel
!= NULL
)) {
2458 // Final step: Update/Append Variable if it pass Pkcs7Verify
2460 return UpdateVariable (
2469 &CertData
->TimeStamp