2 Implement authentication services for the authenticated variable
5 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "AuthService.h"
20 /// Global database array for scratch
22 UINT8 mPubKeyStore
[MAX_KEYDB_SIZE
];
25 EFI_GUID mSignatureSupport
[] = {EFI_CERT_SHA1_GUID
, EFI_CERT_SHA256_GUID
, EFI_CERT_RSA2048_GUID
, EFI_CERT_X509_GUID
};
27 // Public Exponent of RSA Key.
29 CONST UINT8 mRsaE
[] = { 0x01, 0x00, 0x01 };
31 // Hash context pointer
33 VOID
*mHashCtx
= NULL
;
36 // Pointer to runtime buffer.
37 // For "Append" operation to an existing variable, a read/modify/write operation
38 // is supported by firmware internally. Reserve runtime buffer to cache previous
39 // variable data in runtime phase because memory allocation is forbidden in virtual mode.
41 VOID
*mStorageArea
= NULL
;
44 // The serialization of the values of the VariableName, VendorGuid and Attributes
45 // parameters of the SetVariable() call and the TimeStamp component of the
46 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
47 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
49 UINT8
*mSerializationRuntimeBuffer
= NULL
;
52 // Requirement for different signature type which have been defined in UEFI spec.
53 // These data are used to peform SignatureList format check while setting PK/KEK variable.
55 EFI_SIGNATURE_ITEM mSupportSigItem
[] = {
56 //{SigType, SigHeaderSize, SigDataSize }
57 {EFI_CERT_SHA256_GUID
, 0, 32 },
58 {EFI_CERT_RSA2048_GUID
, 0, 256 },
59 {EFI_CERT_RSA2048_SHA256_GUID
, 0, 256 },
60 {EFI_CERT_SHA1_GUID
, 0, 20 },
61 {EFI_CERT_RSA2048_SHA1_GUID
, 0, 256 },
62 {EFI_CERT_X509_GUID
, 0, ((UINT32
) ~0)},
63 {EFI_CERT_SHA224_GUID
, 0, 28 },
64 {EFI_CERT_SHA384_GUID
, 0, 48 },
65 {EFI_CERT_SHA512_GUID
, 0, 64 }
69 Determine whether this operation needs a physical present user.
71 @param[in] VariableName Name of the Variable.
72 @param[in] VendorGuid GUID of the Variable.
74 @retval TRUE This variable is protected, only a physical present user could set this variable.
75 @retval FALSE This variable is not protected.
79 NeedPhysicallyPresent(
80 IN CHAR16
*VariableName
,
81 IN EFI_GUID
*VendorGuid
84 if ((CompareGuid (VendorGuid
, &gEfiSecureBootEnableDisableGuid
) && (StrCmp (VariableName
, EFI_SECURE_BOOT_ENABLE_NAME
) == 0))
85 || (CompareGuid (VendorGuid
, &gEfiCustomModeEnableGuid
) && (StrCmp (VariableName
, EFI_CUSTOM_MODE_NAME
) == 0))) {
93 Determine whether the platform is operating in Custom Secure Boot mode.
95 @retval TRUE The platform is operating in Custom mode.
96 @retval FALSE The platform is operating in Standard mode.
104 VARIABLE_POINTER_TRACK Variable
;
106 FindVariable (EFI_CUSTOM_MODE_NAME
, &gEfiCustomModeEnableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
107 if (Variable
.CurrPtr
!= NULL
&& *(GetVariableDataPtr (Variable
.CurrPtr
)) == CUSTOM_SECURE_BOOT_MODE
) {
116 Internal function to delete a Variable given its name and GUID, no authentication
119 @param[in] VariableName Name of the Variable.
120 @param[in] VendorGuid GUID of the Variable.
122 @retval EFI_SUCCESS Variable deleted successfully.
123 @retval Others The driver failded to start the device.
128 IN CHAR16
*VariableName
,
129 IN EFI_GUID
*VendorGuid
133 VARIABLE_POINTER_TRACK Variable
;
135 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
136 if (EFI_ERROR (Status
)) {
140 ASSERT (Variable
.CurrPtr
!= NULL
);
141 return UpdateVariable (VariableName
, VendorGuid
, NULL
, 0, 0, 0, 0, &Variable
, NULL
);
145 Initializes for authenticated varibale service.
147 @retval EFI_SUCCESS Function successfully executed.
148 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
152 AutenticatedVariableServiceInitialize (
157 VARIABLE_POINTER_TRACK Variable
;
158 VARIABLE_POINTER_TRACK PkVariable
;
164 UINT8 SecureBootMode
;
165 UINT8 SecureBootEnable
;
170 // Initialize hash context.
172 CtxSize
= Sha256GetContextSize ();
173 mHashCtx
= AllocateRuntimePool (CtxSize
);
174 if (mHashCtx
== NULL
) {
175 return EFI_OUT_OF_RESOURCES
;
179 // Reserved runtime buffer for "Append" operation in virtual mode.
181 mStorageArea
= AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize
));
182 if (mStorageArea
== NULL
) {
183 return EFI_OUT_OF_RESOURCES
;
187 // Prepare runtime buffer for serialized data of time-based authenticated
188 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).
190 mSerializationRuntimeBuffer
= AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize
) + sizeof (EFI_GUID
) + sizeof (UINT32
) + sizeof (EFI_TIME
));
191 if (mSerializationRuntimeBuffer
== NULL
) {
192 return EFI_OUT_OF_RESOURCES
;
196 // Check "AuthVarKeyDatabase" variable's existence.
197 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
199 Status
= FindVariable (
201 &gEfiAuthenticatedVariableGuid
,
203 &mVariableModuleGlobal
->VariableGlobal
,
207 if (Variable
.CurrPtr
== NULL
) {
208 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
211 Status
= UpdateVariable (
213 &gEfiAuthenticatedVariableGuid
,
222 if (EFI_ERROR (Status
)) {
227 // Load database in global variable for cache.
229 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
230 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
231 ASSERT ((DataSize
!= 0) && (Data
!= NULL
));
232 CopyMem (mPubKeyStore
, (UINT8
*) Data
, DataSize
);
233 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
236 FindVariable (EFI_PLATFORM_KEY_NAME
, &gEfiGlobalVariableGuid
, &PkVariable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
237 if (PkVariable
.CurrPtr
== NULL
) {
238 DEBUG ((EFI_D_INFO
, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME
));
240 DEBUG ((EFI_D_INFO
, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME
));
244 // Check "SetupMode" variable's existence.
245 // If it doesn't exist, check PK database's existence to determine the value.
246 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
248 Status
= FindVariable (
250 &gEfiGlobalVariableGuid
,
252 &mVariableModuleGlobal
->VariableGlobal
,
256 if (Variable
.CurrPtr
== NULL
) {
257 if (PkVariable
.CurrPtr
== NULL
) {
258 mPlatformMode
= SETUP_MODE
;
260 mPlatformMode
= USER_MODE
;
263 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
264 Status
= UpdateVariable (
266 &gEfiGlobalVariableGuid
,
275 if (EFI_ERROR (Status
)) {
279 mPlatformMode
= *(GetVariableDataPtr (Variable
.CurrPtr
));
282 // Check "SignatureSupport" variable's existence.
283 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
285 Status
= FindVariable (
286 EFI_SIGNATURE_SUPPORT_NAME
,
287 &gEfiGlobalVariableGuid
,
289 &mVariableModuleGlobal
->VariableGlobal
,
293 if (Variable
.CurrPtr
== NULL
) {
294 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
295 Status
= UpdateVariable (
296 EFI_SIGNATURE_SUPPORT_NAME
,
297 &gEfiGlobalVariableGuid
,
299 sizeof(mSignatureSupport
),
309 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
310 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
311 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
313 SecureBootEnable
= SECURE_BOOT_MODE_DISABLE
;
314 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME
, &gEfiSecureBootEnableDisableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
315 if (Variable
.CurrPtr
!= NULL
) {
316 SecureBootEnable
= *(GetVariableDataPtr (Variable
.CurrPtr
));
317 } else if (mPlatformMode
== USER_MODE
) {
319 // "SecureBootEnable" not exist, initialize it in USER_MODE.
321 SecureBootEnable
= SECURE_BOOT_MODE_ENABLE
;
322 Status
= UpdateVariable (
323 EFI_SECURE_BOOT_ENABLE_NAME
,
324 &gEfiSecureBootEnableDisableGuid
,
327 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
333 if (EFI_ERROR (Status
)) {
338 if (SecureBootEnable
== SECURE_BOOT_ENABLE
&& mPlatformMode
== USER_MODE
) {
339 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
341 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
343 FindVariable (EFI_SECURE_BOOT_MODE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
344 Status
= UpdateVariable (
345 EFI_SECURE_BOOT_MODE_NAME
,
346 &gEfiGlobalVariableGuid
,
349 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
355 if (EFI_ERROR (Status
)) {
359 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SETUP_MODE_NAME
, mPlatformMode
));
360 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME
, SecureBootMode
));
361 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME
, SecureBootEnable
));
364 // Check "CustomMode" variable's existence.
366 FindVariable (EFI_CUSTOM_MODE_NAME
, &gEfiCustomModeEnableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
, FALSE
);
367 if (Variable
.CurrPtr
!= NULL
) {
368 CustomMode
= *(GetVariableDataPtr (Variable
.CurrPtr
));
371 // "CustomMode" not exist, initialize it in STANDARD_SECURE_BOOT_MODE.
373 CustomMode
= STANDARD_SECURE_BOOT_MODE
;
374 Status
= UpdateVariable (
375 EFI_CUSTOM_MODE_NAME
,
376 &gEfiCustomModeEnableGuid
,
379 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
385 if (EFI_ERROR (Status
)) {
390 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME
, CustomMode
));
393 // Check "certdb" variable's existence.
394 // If it doesn't exist, then create a new one with
395 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
397 Status
= FindVariable (
401 &mVariableModuleGlobal
->VariableGlobal
,
405 if (Variable
.CurrPtr
== NULL
) {
406 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
408 Status
= UpdateVariable (
426 Add public key in store and return its index.
428 @param[in] PubKey Input pointer to Public Key data
430 @return Index of new added item
441 VARIABLE_POINTER_TRACK Variable
;
444 if (PubKey
== NULL
) {
448 Status
= FindVariable (
450 &gEfiAuthenticatedVariableGuid
,
452 &mVariableModuleGlobal
->VariableGlobal
,
455 ASSERT_EFI_ERROR (Status
);
457 // Check whether the public key entry does exist.
460 for (Ptr
= mPubKeyStore
, Index
= 1; Index
<= mPubKeyNumber
; Index
++) {
461 if (CompareMem (Ptr
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
465 Ptr
+= EFI_CERT_TYPE_RSA2048_SIZE
;
470 // Add public key in database.
472 if (mPubKeyNumber
== MAX_KEY_NUM
) {
474 // Notes: Database is full, need enhancement here, currently just return 0.
479 CopyMem (mPubKeyStore
+ mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
480 Index
= ++mPubKeyNumber
;
482 // Update public key database variable.
484 Status
= UpdateVariable (
486 &gEfiAuthenticatedVariableGuid
,
488 mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
,
489 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
495 ASSERT_EFI_ERROR (Status
);
502 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
503 Follow the steps in UEFI2.2.
505 @param[in] Data Pointer to data with AuthInfo.
506 @param[in] DataSize Size of Data.
507 @param[in] PubKey Public key used for verification.
509 @retval EFI_INVALID_PARAMETER Invalid parameter.
510 @retval EFI_SECURITY_VIOLATION If authentication failed.
511 @retval EFI_SUCCESS Authentication successful.
515 VerifyCounterBasedPayload (
522 EFI_VARIABLE_AUTHENTICATION
*CertData
;
523 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
524 UINT8 Digest
[SHA256_DIGEST_SIZE
];
531 if (Data
== NULL
|| PubKey
== NULL
) {
532 return EFI_INVALID_PARAMETER
;
535 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
536 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
539 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
540 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
542 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
543 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertTypeRsa2048Sha256Guid
)
546 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
548 return EFI_SECURITY_VIOLATION
;
551 // Hash data payload with SHA256.
553 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
554 Status
= Sha256Init (mHashCtx
);
558 Status
= Sha256Update (mHashCtx
, Data
+ AUTHINFO_SIZE
, (UINTN
) (DataSize
- AUTHINFO_SIZE
));
563 // Hash Monotonic Count.
565 Status
= Sha256Update (mHashCtx
, &CertData
->MonotonicCount
, sizeof (UINT64
));
569 Status
= Sha256Final (mHashCtx
, Digest
);
574 // Generate & Initialize RSA Context.
577 ASSERT (Rsa
!= NULL
);
579 // Set RSA Key Components.
580 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
582 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
586 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
591 // Verify the signature.
593 Status
= RsaPkcs1Verify (
597 CertBlock
->Signature
,
598 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
608 return EFI_SECURITY_VIOLATION
;
613 Update platform mode.
615 @param[in] Mode SETUP_MODE or USER_MODE.
617 @return EFI_INVALID_PARAMETER Invalid parameter.
618 @return EFI_SUCCESS Update platform mode successfully.
627 VARIABLE_POINTER_TRACK Variable
;
629 UINT8 SecureBootMode
;
630 UINT8 SecureBootEnable
;
631 UINTN VariableDataSize
;
633 Status
= FindVariable (
635 &gEfiGlobalVariableGuid
,
637 &mVariableModuleGlobal
->VariableGlobal
,
640 if (EFI_ERROR (Status
)) {
644 mPlatformMode
= Mode
;
645 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
646 Status
= UpdateVariable (
648 &gEfiGlobalVariableGuid
,
657 if (EFI_ERROR (Status
)) {
663 // SecureBoot Variable indicates whether the platform firmware is operating
664 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
665 // Variable in runtime.
671 // Check "SecureBoot" variable's existence.
672 // If it doesn't exist, firmware has no capability to perform driver signing verification,
673 // then set "SecureBoot" to 0.
675 Status
= FindVariable (
676 EFI_SECURE_BOOT_MODE_NAME
,
677 &gEfiGlobalVariableGuid
,
679 &mVariableModuleGlobal
->VariableGlobal
,
683 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
684 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
685 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
687 if (Variable
.CurrPtr
== NULL
) {
688 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
690 if (mPlatformMode
== USER_MODE
) {
691 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
692 } else if (mPlatformMode
== SETUP_MODE
) {
693 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
695 return EFI_NOT_FOUND
;
699 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
700 Status
= UpdateVariable (
701 EFI_SECURE_BOOT_MODE_NAME
,
702 &gEfiGlobalVariableGuid
,
711 if (EFI_ERROR (Status
)) {
716 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
718 Status
= FindVariable (
719 EFI_SECURE_BOOT_ENABLE_NAME
,
720 &gEfiSecureBootEnableDisableGuid
,
722 &mVariableModuleGlobal
->VariableGlobal
,
726 if (SecureBootMode
== SECURE_BOOT_MODE_ENABLE
) {
728 // Create the "SecureBootEnable" variable as secure boot is enabled.
730 SecureBootEnable
= SECURE_BOOT_ENABLE
;
731 VariableDataSize
= sizeof (SecureBootEnable
);
734 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
735 // variable is not in secure boot state.
737 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
740 SecureBootEnable
= SECURE_BOOT_DISABLE
;
741 VariableDataSize
= 0;
744 Status
= UpdateVariable (
745 EFI_SECURE_BOOT_ENABLE_NAME
,
746 &gEfiSecureBootEnableDisableGuid
,
749 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
759 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.
761 @param[in] VariableName Name of Variable to be check.
762 @param[in] VendorGuid Variable vendor GUID.
763 @param[in] Data Point to the variable data to be checked.
764 @param[in] DataSize Size of Data.
766 @return EFI_INVALID_PARAMETER Invalid signature list format.
767 @return EFI_SUCCESS Passed signature list format check successfully.
771 CheckSignatureListFormat(
772 IN CHAR16
*VariableName
,
773 IN EFI_GUID
*VendorGuid
,
778 EFI_SIGNATURE_LIST
*SigList
;
788 ASSERT (VariableName
!= NULL
&& VendorGuid
!= NULL
&& Data
!= NULL
);
790 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_PLATFORM_KEY_NAME
) == 0)){
792 } else if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0)) {
799 SigList
= (EFI_SIGNATURE_LIST
*) Data
;
800 SigDataSize
= DataSize
;
803 // Walk throuth the input signature list and check the data format.
804 // If any signature is incorrectly formed, the whole check will fail.
806 while ((SigDataSize
> 0) && (SigDataSize
>= SigList
->SignatureListSize
)) {
807 for (Index
= 0; Index
< (sizeof (mSupportSigItem
) / sizeof (EFI_SIGNATURE_ITEM
)); Index
++ ) {
808 if (CompareGuid (&SigList
->SignatureType
, &mSupportSigItem
[Index
].SigType
)) {
810 // The value of SignatureSize should always be 16 (size of SignatureOwner
811 // component) add the data length according to signature type.
813 if (mSupportSigItem
[Index
].SigDataSize
!= ((UINT32
) ~0) &&
814 (SigList
->SignatureSize
- sizeof (EFI_GUID
)) != mSupportSigItem
[Index
].SigDataSize
) {
815 return EFI_INVALID_PARAMETER
;
817 if (mSupportSigItem
[Index
].SigHeaderSize
!= ((UINTN
) ~0) &&
818 SigList
->SignatureHeaderSize
!= mSupportSigItem
[Index
].SigHeaderSize
) {
819 return EFI_INVALID_PARAMETER
;
825 if (Index
== (sizeof (mSupportSigItem
) / sizeof (EFI_SIGNATURE_ITEM
))) {
827 // Undefined signature type.
829 return EFI_INVALID_PARAMETER
;
832 if ((SigList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - SigList
->SignatureHeaderSize
) % SigList
->SignatureSize
!= 0) {
833 return EFI_INVALID_PARAMETER
;
835 SigCount
+= (SigList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - SigList
->SignatureHeaderSize
) / SigList
->SignatureSize
;
837 SigDataSize
-= SigList
->SignatureListSize
;
838 SigList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) SigList
+ SigList
->SignatureListSize
);
841 if (((UINTN
) SigList
- (UINTN
) Data
) != DataSize
) {
842 return EFI_INVALID_PARAMETER
;
845 if (IsPk
&& SigCount
> 1) {
846 return EFI_INVALID_PARAMETER
;
853 Process variable with platform key for verification.
855 @param[in] VariableName Name of Variable to be found.
856 @param[in] VendorGuid Variable vendor GUID.
857 @param[in] Data Data pointer.
858 @param[in] DataSize Size of Data found. If size is less than the
859 data, this value contains the required size.
860 @param[in] Variable The variable information which is used to keep track of variable usage.
861 @param[in] Attributes Attribute value of the variable
862 @param[in] IsPk Indicate whether it is to process pk.
864 @return EFI_INVALID_PARAMETER Invalid parameter.
865 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
866 check carried out by the firmware.
867 @return EFI_SUCCESS Variable passed validation successfully.
872 IN CHAR16
*VariableName
,
873 IN EFI_GUID
*VendorGuid
,
876 IN VARIABLE_POINTER_TRACK
*Variable
,
877 IN UINT32 Attributes OPTIONAL
,
886 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0 ||
887 (Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == 0) {
889 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
890 // authenticated variable.
892 return EFI_INVALID_PARAMETER
;
895 if (mPlatformMode
== USER_MODE
&& !(InCustomMode() && UserPhysicalPresent())) {
897 // Verify against X509 Cert PK.
900 Status
= VerifyTimeBasedPayload (
910 if (!EFI_ERROR (Status
)) {
912 // If delete PK in user mode, need change to setup mode.
915 Status
= UpdatePlatformMode (SETUP_MODE
);
921 // Process PK or KEK in Setup mode or Custom Secure Boot mode.
923 Payload
= (UINT8
*) Data
+ AUTHINFO2_SIZE (Data
);
924 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
926 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, Payload
, PayloadSize
);
927 if (EFI_ERROR (Status
)) {
931 Status
= UpdateVariable (
940 &((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->TimeStamp
944 if (PayloadSize
!= 0) {
946 // If enroll PK in setup mode, need change to user mode.
948 Status
= UpdatePlatformMode (USER_MODE
);
951 // If delete PK in custom mode, need change to setup mode.
953 UpdatePlatformMode (SETUP_MODE
);
962 Process variable with key exchange key for verification.
964 @param[in] VariableName Name of Variable to be found.
965 @param[in] VendorGuid Variable vendor GUID.
966 @param[in] Data Data pointer.
967 @param[in] DataSize Size of Data found. If size is less than the
968 data, this value contains the required size.
969 @param[in] Variable The variable information which is used to keep track of variable usage.
970 @param[in] Attributes Attribute value of the variable.
972 @return EFI_INVALID_PARAMETER Invalid parameter.
973 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
974 check carried out by the firmware.
975 @return EFI_SUCCESS Variable pass validation successfully.
980 IN CHAR16
*VariableName
,
981 IN EFI_GUID
*VendorGuid
,
984 IN VARIABLE_POINTER_TRACK
*Variable
,
985 IN UINT32 Attributes OPTIONAL
992 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0 ||
993 (Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == 0) {
995 // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
996 // authenticated variable.
998 return EFI_INVALID_PARAMETER
;
1001 Status
= EFI_SUCCESS
;
1002 if (mPlatformMode
== USER_MODE
&& !(InCustomMode() && UserPhysicalPresent())) {
1004 // Time-based, verify against X509 Cert KEK.
1006 return VerifyTimeBasedPayload (
1018 // If in setup mode or custom secure boot mode, no authentication needed.
1020 Payload
= (UINT8
*) Data
+ AUTHINFO2_SIZE (Data
);
1021 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
1023 Status
= UpdateVariable (
1032 &((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->TimeStamp
1040 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1042 @param[in] VariableName Name of Variable to be found.
1043 @param[in] VendorGuid Variable vendor GUID.
1045 @param[in] Data Data pointer.
1046 @param[in] DataSize Size of Data found. If size is less than the
1047 data, this value contains the required size.
1048 @param[in] Variable The variable information which is used to keep track of variable usage.
1049 @param[in] Attributes Attribute value of the variable.
1051 @return EFI_INVALID_PARAMETER Invalid parameter.
1052 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
1053 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1054 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1055 set, but the AuthInfo does NOT pass the validation
1056 check carried out by the firmware.
1057 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
1062 IN CHAR16
*VariableName
,
1063 IN EFI_GUID
*VendorGuid
,
1066 IN VARIABLE_POINTER_TRACK
*Variable
,
1067 IN UINT32 Attributes
1072 BOOLEAN IsFirstTime
;
1074 EFI_VARIABLE_AUTHENTICATION
*CertData
;
1075 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
1077 UINT64 MonotonicCount
;
1085 if (NeedPhysicallyPresent(VariableName
, VendorGuid
) && !UserPhysicalPresent()) {
1087 // This variable is protected, only physical present user could modify its value.
1089 return EFI_SECURITY_VIOLATION
;
1093 // Process Time-based Authenticated variable.
1095 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
1096 return VerifyTimeBasedPayload (
1109 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
1111 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
1113 // Determine current operation type.
1115 if (DataSize
== AUTHINFO_SIZE
) {
1119 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1121 if (Variable
->CurrPtr
== NULL
) {
1123 } else if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
1126 KeyIndex
= Variable
->CurrPtr
->PubKeyIndex
;
1127 IsFirstTime
= FALSE
;
1129 } else if ((Variable
->CurrPtr
!= NULL
) &&
1130 ((Variable
->CurrPtr
->Attributes
& (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) != 0)
1133 // If the variable is already write-protected, it always needs authentication before update.
1135 return EFI_WRITE_PROTECTED
;
1138 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
1139 // That means it is not authenticated variable, just update variable as usual.
1141 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, Variable
, NULL
);
1146 // Get PubKey and check Monotonic Count value corresponding to the variable.
1148 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
1149 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
1150 PubKey
= CertBlock
->PublicKey
;
1153 // Update Monotonic Count value.
1155 MonotonicCount
= CertData
->MonotonicCount
;
1159 // Check input PubKey.
1161 if (CompareMem (PubKey
, mPubKeyStore
+ (KeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
, EFI_CERT_TYPE_RSA2048_SIZE
) != 0) {
1162 return EFI_SECURITY_VIOLATION
;
1165 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
1166 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
1168 if (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
) {
1170 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1172 return EFI_SECURITY_VIOLATION
;
1176 // Verify the certificate in Data payload.
1178 Status
= VerifyCounterBasedPayload (Data
, DataSize
, PubKey
);
1179 if (EFI_ERROR (Status
)) {
1184 // Now, the signature has been verified!
1186 if (IsFirstTime
&& !IsDeletion
) {
1188 // Update public key database variable if need.
1190 KeyIndex
= AddPubKeyInStore (PubKey
);
1191 if (KeyIndex
== 0) {
1192 return EFI_SECURITY_VIOLATION
;
1197 // Verification pass.
1199 return UpdateVariable (VariableName
, VendorGuid
, (UINT8
*)Data
+ AUTHINFO_SIZE
, DataSize
- AUTHINFO_SIZE
, Attributes
, KeyIndex
, MonotonicCount
, Variable
, NULL
);
1203 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
1204 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
1207 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
1208 @param[in] DataSize Size of Data buffer.
1209 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
1210 @param[in] NewDataSize Size of NewData buffer.
1212 @return Size of the merged buffer.
1216 AppendSignatureList (
1220 IN UINTN NewDataSize
1223 EFI_SIGNATURE_LIST
*CertList
;
1224 EFI_SIGNATURE_DATA
*Cert
;
1226 EFI_SIGNATURE_LIST
*NewCertList
;
1227 EFI_SIGNATURE_DATA
*NewCert
;
1234 UINTN SignatureListSize
;
1237 Tail
= (UINT8
*) Data
+ DataSize
;
1239 NewCertList
= (EFI_SIGNATURE_LIST
*) NewData
;
1240 while ((NewDataSize
> 0) && (NewDataSize
>= NewCertList
->SignatureListSize
)) {
1241 NewCert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) NewCertList
+ sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
);
1242 NewCertCount
= (NewCertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - NewCertList
->SignatureHeaderSize
) / NewCertList
->SignatureSize
;
1245 for (Index
= 0; Index
< NewCertCount
; Index
++) {
1249 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
1250 while ((Size
> 0) && (Size
>= CertList
->SignatureListSize
)) {
1251 if (CompareGuid (&CertList
->SignatureType
, &NewCertList
->SignatureType
) &&
1252 (CertList
->SignatureSize
== NewCertList
->SignatureSize
)) {
1253 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1254 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
1255 for (Index2
= 0; Index2
< CertCount
; Index2
++) {
1257 // Iterate each Signature Data in this Signature List.
1259 if (CompareMem (NewCert
, Cert
, CertList
->SignatureSize
) == 0) {
1263 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
1270 Size
-= CertList
->SignatureListSize
;
1271 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
1276 // New EFI_SIGNATURE_DATA, append it.
1278 if (CopiedCount
== 0) {
1280 // Copy EFI_SIGNATURE_LIST header for only once.
1282 CopyMem (Tail
, NewCertList
, sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
);
1283 Tail
= Tail
+ sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
;
1286 CopyMem (Tail
, NewCert
, NewCertList
->SignatureSize
);
1287 Tail
+= NewCertList
->SignatureSize
;
1291 NewCert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) NewCert
+ NewCertList
->SignatureSize
);
1295 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
1297 if (CopiedCount
!= 0) {
1298 SignatureListSize
= sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
+ (CopiedCount
* NewCertList
->SignatureSize
);
1299 CertList
= (EFI_SIGNATURE_LIST
*) (Tail
- SignatureListSize
);
1300 CertList
->SignatureListSize
= (UINT32
) SignatureListSize
;
1303 NewDataSize
-= NewCertList
->SignatureListSize
;
1304 NewCertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) NewCertList
+ NewCertList
->SignatureListSize
);
1307 return (Tail
- (UINT8
*) Data
);
1311 Compare two EFI_TIME data.
1314 @param FirstTime A pointer to the first EFI_TIME data.
1315 @param SecondTime A pointer to the second EFI_TIME data.
1317 @retval TRUE The FirstTime is not later than the SecondTime.
1318 @retval FALSE The FirstTime is later than the SecondTime.
1323 IN EFI_TIME
*FirstTime
,
1324 IN EFI_TIME
*SecondTime
1327 if (FirstTime
->Year
!= SecondTime
->Year
) {
1328 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
1329 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
1330 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
1331 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
1332 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
1333 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
1334 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
1335 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
1336 return (BOOLEAN
) (FirstTime
->Minute
< FirstTime
->Minute
);
1339 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
1343 Find matching signer's certificates for common authenticated variable
1344 by corresponding VariableName and VendorGuid from "certdb".
1346 The data format of "certdb":
1348 // UINT32 CertDbListSize;
1349 // /// AUTH_CERT_DB_DATA Certs1[];
1350 // /// AUTH_CERT_DB_DATA Certs2[];
1352 // /// AUTH_CERT_DB_DATA Certsn[];
1355 @param[in] VariableName Name of authenticated Variable.
1356 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1357 @param[in] Data Pointer to variable "certdb".
1358 @param[in] DataSize Size of variable "certdb".
1359 @param[out] CertOffset Offset of matching CertData, from starting of Data.
1360 @param[out] CertDataSize Length of CertData in bytes.
1361 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
1363 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
1365 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1366 @retval EFI_NOT_FOUND Fail to find matching certs.
1367 @retval EFI_SUCCESS Find matching certs and output parameters.
1372 IN CHAR16
*VariableName
,
1373 IN EFI_GUID
*VendorGuid
,
1376 OUT UINT32
*CertOffset
, OPTIONAL
1377 OUT UINT32
*CertDataSize
, OPTIONAL
1378 OUT UINT32
*CertNodeOffset
,OPTIONAL
1379 OUT UINT32
*CertNodeSize OPTIONAL
1383 AUTH_CERT_DB_DATA
*Ptr
;
1387 UINT32 CertDbListSize
;
1389 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
)) {
1390 return EFI_INVALID_PARAMETER
;
1394 // Check whether DataSize matches recorded CertDbListSize.
1396 if (DataSize
< sizeof (UINT32
)) {
1397 return EFI_INVALID_PARAMETER
;
1400 CertDbListSize
= ReadUnaligned32 ((UINT32
*) Data
);
1402 if (CertDbListSize
!= (UINT32
) DataSize
) {
1403 return EFI_INVALID_PARAMETER
;
1406 Offset
= sizeof (UINT32
);
1409 // Get corresponding certificates by VendorGuid and VariableName.
1411 while (Offset
< (UINT32
) DataSize
) {
1412 Ptr
= (AUTH_CERT_DB_DATA
*) (Data
+ Offset
);
1414 // Check whether VendorGuid matches.
1416 if (CompareGuid (&Ptr
->VendorGuid
, VendorGuid
)) {
1417 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
1418 NameSize
= ReadUnaligned32 (&Ptr
->NameSize
);
1419 CertSize
= ReadUnaligned32 (&Ptr
->CertDataSize
);
1421 if (NodeSize
!= sizeof (EFI_GUID
) + sizeof (UINT32
) * 3 + CertSize
+
1422 sizeof (CHAR16
) * NameSize
) {
1423 return EFI_INVALID_PARAMETER
;
1426 Offset
= Offset
+ sizeof (EFI_GUID
) + sizeof (UINT32
) * 3;
1428 // Check whether VariableName matches.
1430 if ((NameSize
== StrLen (VariableName
)) &&
1431 (CompareMem (Data
+ Offset
, VariableName
, NameSize
* sizeof (CHAR16
)) == 0)) {
1432 Offset
= Offset
+ NameSize
* sizeof (CHAR16
);
1434 if (CertOffset
!= NULL
) {
1435 *CertOffset
= Offset
;
1438 if (CertDataSize
!= NULL
) {
1439 *CertDataSize
= CertSize
;
1442 if (CertNodeOffset
!= NULL
) {
1443 *CertNodeOffset
= (UINT32
) ((UINT8
*) Ptr
- Data
);
1446 if (CertNodeSize
!= NULL
) {
1447 *CertNodeSize
= NodeSize
;
1452 Offset
= Offset
+ NameSize
* sizeof (CHAR16
) + CertSize
;
1455 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
1456 Offset
= Offset
+ NodeSize
;
1460 return EFI_NOT_FOUND
;
1464 Retrieve signer's certificates for common authenticated variable
1465 by corresponding VariableName and VendorGuid from "certdb".
1467 @param[in] VariableName Name of authenticated Variable.
1468 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1469 @param[out] CertData Pointer to signer's certificates.
1470 @param[out] CertDataSize Length of CertData in bytes.
1472 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1473 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1474 @retval EFI_SUCCESS Get signer's certificates successfully.
1479 IN CHAR16
*VariableName
,
1480 IN EFI_GUID
*VendorGuid
,
1481 OUT UINT8
**CertData
,
1482 OUT UINT32
*CertDataSize
1485 VARIABLE_POINTER_TRACK CertDbVariable
;
1491 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (CertData
== NULL
) || (CertDataSize
== NULL
)) {
1492 return EFI_INVALID_PARAMETER
;
1496 // Get variable "certdb".
1498 Status
= FindVariable (
1502 &mVariableModuleGlobal
->VariableGlobal
,
1505 if (EFI_ERROR (Status
)) {
1509 DataSize
= DataSizeOfVariable (CertDbVariable
.CurrPtr
);
1510 Data
= GetVariableDataPtr (CertDbVariable
.CurrPtr
);
1511 if ((DataSize
== 0) || (Data
== NULL
)) {
1513 return EFI_NOT_FOUND
;
1516 Status
= FindCertsFromDb (
1527 if (EFI_ERROR (Status
)) {
1531 *CertData
= Data
+ CertOffset
;
1536 Delete matching signer's certificates when deleting common authenticated
1537 variable by corresponding VariableName and VendorGuid from "certdb".
1539 @param[in] VariableName Name of authenticated Variable.
1540 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1542 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1543 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1544 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1545 @retval EFI_SUCCESS The operation is completed successfully.
1550 IN CHAR16
*VariableName
,
1551 IN EFI_GUID
*VendorGuid
1554 VARIABLE_POINTER_TRACK CertDbVariable
;
1559 UINT32 CertNodeOffset
;
1560 UINT32 CertNodeSize
;
1562 UINT32 NewCertDbSize
;
1564 if ((VariableName
== NULL
) || (VendorGuid
== NULL
)) {
1565 return EFI_INVALID_PARAMETER
;
1569 // Get variable "certdb".
1571 Status
= FindVariable (
1575 &mVariableModuleGlobal
->VariableGlobal
,
1578 if (EFI_ERROR (Status
)) {
1582 DataSize
= DataSizeOfVariable (CertDbVariable
.CurrPtr
);
1583 Data
= GetVariableDataPtr (CertDbVariable
.CurrPtr
);
1584 if ((DataSize
== 0) || (Data
== NULL
)) {
1586 return EFI_NOT_FOUND
;
1589 if (DataSize
== sizeof (UINT32
)) {
1591 // There is no certs in certdb.
1597 // Get corresponding cert node from certdb.
1599 Status
= FindCertsFromDb (
1610 if (EFI_ERROR (Status
)) {
1614 if (DataSize
< (CertNodeOffset
+ CertNodeSize
)) {
1615 return EFI_NOT_FOUND
;
1619 // Construct new data content of variable "certdb".
1621 NewCertDbSize
= (UINT32
) DataSize
- CertNodeSize
;
1622 NewCertDb
= AllocateZeroPool (NewCertDbSize
);
1623 if (NewCertDb
== NULL
) {
1624 return EFI_OUT_OF_RESOURCES
;
1628 // Copy the DB entries before deleting node.
1630 CopyMem (NewCertDb
, Data
, CertNodeOffset
);
1632 // Update CertDbListSize.
1634 CopyMem (NewCertDb
, &NewCertDbSize
, sizeof (UINT32
));
1636 // Copy the DB entries after deleting node.
1638 if (DataSize
> (CertNodeOffset
+ CertNodeSize
)) {
1640 NewCertDb
+ CertNodeOffset
,
1641 Data
+ CertNodeOffset
+ CertNodeSize
,
1642 DataSize
- CertNodeOffset
- CertNodeSize
1649 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
1650 Status
= UpdateVariable (
1662 FreePool (NewCertDb
);
1667 Insert signer's certificates for common authenticated variable with VariableName
1668 and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
1670 @param[in] VariableName Name of authenticated Variable.
1671 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1672 @param[in] CertData Pointer to signer's certificates.
1673 @param[in] CertDataSize Length of CertData in bytes.
1675 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1676 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
1677 and VendorGuid already exists.
1678 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1679 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"
1684 IN CHAR16
*VariableName
,
1685 IN EFI_GUID
*VendorGuid
,
1687 IN UINTN CertDataSize
1690 VARIABLE_POINTER_TRACK CertDbVariable
;
1696 UINT32 NewCertDbSize
;
1697 UINT32 CertNodeSize
;
1699 AUTH_CERT_DB_DATA
*Ptr
;
1701 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (CertData
== NULL
)) {
1702 return EFI_INVALID_PARAMETER
;
1706 // Get variable "certdb".
1708 Status
= FindVariable (
1712 &mVariableModuleGlobal
->VariableGlobal
,
1715 if (EFI_ERROR (Status
)) {
1719 DataSize
= DataSizeOfVariable (CertDbVariable
.CurrPtr
);
1720 Data
= GetVariableDataPtr (CertDbVariable
.CurrPtr
);
1721 if ((DataSize
== 0) || (Data
== NULL
)) {
1723 return EFI_NOT_FOUND
;
1727 // Find whether matching cert node already exists in "certdb".
1728 // If yes return error.
1730 Status
= FindCertsFromDb (
1741 if (!EFI_ERROR (Status
)) {
1743 return EFI_ACCESS_DENIED
;
1747 // Construct new data content of variable "certdb".
1749 NameSize
= (UINT32
) StrLen (VariableName
);
1750 CertNodeSize
= sizeof (AUTH_CERT_DB_DATA
) + (UINT32
) CertDataSize
+ NameSize
* sizeof (CHAR16
);
1751 NewCertDbSize
= (UINT32
) DataSize
+ CertNodeSize
;
1752 NewCertDb
= AllocateZeroPool (NewCertDbSize
);
1753 if (NewCertDb
== NULL
) {
1754 return EFI_OUT_OF_RESOURCES
;
1758 // Copy the DB entries before deleting node.
1760 CopyMem (NewCertDb
, Data
, DataSize
);
1762 // Update CertDbListSize.
1764 CopyMem (NewCertDb
, &NewCertDbSize
, sizeof (UINT32
));
1766 // Construct new cert node.
1768 Ptr
= (AUTH_CERT_DB_DATA
*) (NewCertDb
+ DataSize
);
1769 CopyGuid (&Ptr
->VendorGuid
, VendorGuid
);
1770 CopyMem (&Ptr
->CertNodeSize
, &CertNodeSize
, sizeof (UINT32
));
1771 CopyMem (&Ptr
->NameSize
, &NameSize
, sizeof (UINT32
));
1772 CopyMem (&Ptr
->CertDataSize
, &CertDataSize
, sizeof (UINT32
));
1775 (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
),
1777 NameSize
* sizeof (CHAR16
)
1781 (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
) + NameSize
* sizeof (CHAR16
),
1789 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
1790 Status
= UpdateVariable (
1802 FreePool (NewCertDb
);
1807 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1809 @param[in] VariableName Name of Variable to be found.
1810 @param[in] VendorGuid Variable vendor GUID.
1811 @param[in] Data Data pointer.
1812 @param[in] DataSize Size of Data found. If size is less than the
1813 data, this value contains the required size.
1814 @param[in] Variable The variable information which is used to keep track of variable usage.
1815 @param[in] Attributes Attribute value of the variable.
1816 @param[in] AuthVarType Verify against PK or KEK database or private database.
1817 @param[out] VarDel Delete the variable or not.
1819 @retval EFI_INVALID_PARAMETER Invalid parameter.
1820 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1821 check carried out by the firmware.
1822 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
1824 @retval EFI_SUCCESS Variable pass validation successfully.
1828 VerifyTimeBasedPayload (
1829 IN CHAR16
*VariableName
,
1830 IN EFI_GUID
*VendorGuid
,
1833 IN VARIABLE_POINTER_TRACK
*Variable
,
1834 IN UINT32 Attributes
,
1835 IN AUTHVAR_TYPE AuthVarType
,
1849 BOOLEAN VerifyStatus
;
1851 EFI_SIGNATURE_LIST
*CertList
;
1852 EFI_SIGNATURE_DATA
*Cert
;
1853 VARIABLE_POINTER_TRACK KekVariable
;
1854 EFI_VARIABLE_AUTHENTICATION_2
*CertData
;
1857 VARIABLE_POINTER_TRACK PkVariable
;
1862 UINTN CertStackSize
;
1863 UINT8
*CertsInCertDb
;
1864 UINT32 CertsSizeinDb
;
1866 VerifyStatus
= FALSE
;
1875 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1876 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1877 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1878 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1879 // variable value. The authentication descriptor is not part of the variable data and is not
1880 // returned by subsequent calls to GetVariable().
1882 CertData
= (EFI_VARIABLE_AUTHENTICATION_2
*) Data
;
1885 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
1886 // TimeStamp value are set to zero.
1888 if ((CertData
->TimeStamp
.Pad1
!= 0) ||
1889 (CertData
->TimeStamp
.Nanosecond
!= 0) ||
1890 (CertData
->TimeStamp
.TimeZone
!= 0) ||
1891 (CertData
->TimeStamp
.Daylight
!= 0) ||
1892 (CertData
->TimeStamp
.Pad2
!= 0)) {
1893 return EFI_SECURITY_VIOLATION
;
1896 if ((Variable
->CurrPtr
!= NULL
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
1897 if (CompareTimeStamp (&CertData
->TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
1899 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1901 return EFI_SECURITY_VIOLATION
;
1906 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1907 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1909 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
1910 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
)) {
1912 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1914 return EFI_SECURITY_VIOLATION
;
1918 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1919 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1921 SigData
= CertData
->AuthInfo
.CertData
;
1922 SigDataSize
= CertData
->AuthInfo
.Hdr
.dwLength
- (UINT32
) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
1925 // Find out the new data payload which follows Pkcs7 SignedData directly.
1927 PayloadPtr
= SigData
+ SigDataSize
;
1928 PayloadSize
= DataSize
- OFFSET_OF_AUTHINFO2_CERT_DATA
- (UINTN
) SigDataSize
;
1931 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
1933 NewDataSize
= PayloadSize
+ sizeof (EFI_TIME
) + sizeof (UINT32
) +
1934 sizeof (EFI_GUID
) + StrSize (VariableName
) - sizeof (CHAR16
);
1935 NewData
= mSerializationRuntimeBuffer
;
1938 Length
= StrLen (VariableName
) * sizeof (CHAR16
);
1939 CopyMem (Buffer
, VariableName
, Length
);
1942 Length
= sizeof (EFI_GUID
);
1943 CopyMem (Buffer
, VendorGuid
, Length
);
1946 Length
= sizeof (UINT32
);
1947 CopyMem (Buffer
, &Attr
, Length
);
1950 Length
= sizeof (EFI_TIME
);
1951 CopyMem (Buffer
, &CertData
->TimeStamp
, Length
);
1954 CopyMem (Buffer
, PayloadPtr
, PayloadSize
);
1956 if (AuthVarType
== AuthVarTypePk
) {
1958 // Get platform key from variable.
1960 Status
= FindVariable (
1961 EFI_PLATFORM_KEY_NAME
,
1962 &gEfiGlobalVariableGuid
,
1964 &mVariableModuleGlobal
->VariableGlobal
,
1967 if (EFI_ERROR (Status
)) {
1971 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (PkVariable
.CurrPtr
);
1972 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1973 RootCert
= Cert
->SignatureData
;
1974 RootCertSize
= CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1);
1978 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1980 VerifyStatus
= Pkcs7Verify (
1989 } else if (AuthVarType
== AuthVarTypeKek
) {
1992 // Get KEK database from variable.
1994 Status
= FindVariable (
1995 EFI_KEY_EXCHANGE_KEY_NAME
,
1996 &gEfiGlobalVariableGuid
,
1998 &mVariableModuleGlobal
->VariableGlobal
,
2001 if (EFI_ERROR (Status
)) {
2006 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
2008 KekDataSize
= KekVariable
.CurrPtr
->DataSize
;
2009 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (KekVariable
.CurrPtr
);
2010 while ((KekDataSize
> 0) && (KekDataSize
>= CertList
->SignatureListSize
)) {
2011 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
2012 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
2013 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
2014 for (Index
= 0; Index
< CertCount
; Index
++) {
2016 // Iterate each Signature Data Node within this CertList for a verify
2018 RootCert
= Cert
->SignatureData
;
2019 RootCertSize
= CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1);
2022 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2024 VerifyStatus
= Pkcs7Verify (
2035 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
2038 KekDataSize
-= CertList
->SignatureListSize
;
2039 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
2041 } else if (AuthVarType
== AuthVarTypePriv
) {
2044 // Process common authenticated variable except PK/KEK/DB/DBX.
2045 // Get signer's certificates from SignedData.
2047 VerifyStatus
= Pkcs7GetSigners (
2055 if (!VerifyStatus
) {
2060 // Get previously stored signer's certificates from certdb for existing
2061 // variable. Check whether they are identical with signer's certificates
2062 // in SignedData. If not, return error immediately.
2064 if ((Variable
->CurrPtr
!= NULL
)) {
2065 VerifyStatus
= FALSE
;
2067 Status
= GetCertsFromDb (VariableName
, VendorGuid
, &CertsInCertDb
, &CertsSizeinDb
);
2068 if (EFI_ERROR (Status
)) {
2072 if ((CertStackSize
!= CertsSizeinDb
) ||
2073 (CompareMem (SignerCerts
, CertsInCertDb
, CertsSizeinDb
) != 0)) {
2078 VerifyStatus
= Pkcs7Verify (
2086 if (!VerifyStatus
) {
2091 // Delete signer's certificates when delete the common authenticated variable.
2093 if ((PayloadSize
== 0) && (Variable
->CurrPtr
!= NULL
)) {
2094 Status
= DeleteCertsFromDb (VariableName
, VendorGuid
);
2095 if (EFI_ERROR (Status
)) {
2096 VerifyStatus
= FALSE
;
2099 } else if (Variable
->CurrPtr
== NULL
) {
2101 // Insert signer's certificates when adding a new common authenticated variable.
2103 Status
= InsertCertsToDb (VariableName
, VendorGuid
, SignerCerts
, CertStackSize
);
2104 if (EFI_ERROR (Status
)) {
2105 VerifyStatus
= FALSE
;
2110 return EFI_SECURITY_VIOLATION
;
2115 if (AuthVarType
== AuthVarTypePriv
) {
2116 Pkcs7FreeSigners (RootCert
);
2117 Pkcs7FreeSigners (SignerCerts
);
2120 if (!VerifyStatus
) {
2121 return EFI_SECURITY_VIOLATION
;
2124 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, PayloadPtr
, PayloadSize
);
2125 if (EFI_ERROR (Status
)) {
2129 if ((PayloadSize
== 0) && (VarDel
!= NULL
)) {
2134 // Final step: Update/Append Variable if it pass Pkcs7Verify
2136 return UpdateVariable (
2145 &CertData
->TimeStamp