2 Implement authentication services for the authenticated variable
5 Copyright (c) 2009 - 2011, 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
[SIGSUPPORT_NUM
] = {EFI_CERT_RSA2048_SHA256_GUID
, EFI_CERT_RSA2048_SHA1_GUID
};
27 // Public Exponent of RSA Key.
29 CONST UINT8 mRsaE
[] = { 0x01, 0x00, 0x01 };
31 // Hash context pointer
33 VOID
*mHashCtx
= NULL
;
37 // Pointer to runtime buffer.
38 // For "Append" operation to an existing variable, a read/modify/write operation
39 // is supported by firmware internally. Reserve runtime buffer to cache previous
40 // variable data in runtime phase because memory allocation is forbidden in virtual mode.
42 VOID
*mStorageArea
= NULL
;
47 @param[in] Mode SETUP_MODE or USER_MODE.
49 @return EFI_INVALID_PARAMETER Invalid parameter.
50 @return EFI_SUCCESS Update platform mode successfully.
59 Initializes for authenticated varibale service.
61 @retval EFI_SUCCESS Function successfully executed.
62 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
66 AutenticatedVariableServiceInitialize (
71 VARIABLE_POINTER_TRACK Variable
;
78 // Initialize hash context.
80 CtxSize
= Sha256GetContextSize ();
81 mHashCtx
= AllocateRuntimePool (CtxSize
);
82 if (mHashCtx
== NULL
) {
83 return EFI_OUT_OF_RESOURCES
;
87 // Reserved runtime buffer for "Append" operation in virtual mode.
89 mStorageArea
= AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize
));
90 if (mStorageArea
== NULL
) {
91 return EFI_OUT_OF_RESOURCES
;
95 // Check "AuthVarKeyDatabase" variable's existence.
96 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
98 Status
= FindVariable (
100 &gEfiAuthenticatedVariableGuid
,
102 &mVariableModuleGlobal
->VariableGlobal
105 if (Variable
.CurrPtr
== NULL
) {
106 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
109 Status
= UpdateVariable (
111 &gEfiAuthenticatedVariableGuid
,
120 if (EFI_ERROR (Status
)) {
125 // Load database in global variable for cache.
127 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
128 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
129 ASSERT ((DataSize
!= 0) && (Data
!= NULL
));
130 CopyMem (mPubKeyStore
, (UINT8
*) Data
, DataSize
);
131 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
134 // Check "SetupMode" variable's existence.
135 // If it doesn't exist, check PK database's existence to determine the value.
136 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
138 Status
= FindVariable (
140 &gEfiGlobalVariableGuid
,
142 &mVariableModuleGlobal
->VariableGlobal
145 if (Variable
.CurrPtr
== NULL
) {
146 Status
= FindVariable (
147 EFI_PLATFORM_KEY_NAME
,
148 &gEfiGlobalVariableGuid
,
150 &mVariableModuleGlobal
->VariableGlobal
152 if (Variable
.CurrPtr
== NULL
) {
153 mPlatformMode
= SETUP_MODE
;
155 mPlatformMode
= USER_MODE
;
158 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
159 Status
= UpdateVariable (
161 &gEfiGlobalVariableGuid
,
170 if (EFI_ERROR (Status
)) {
174 mPlatformMode
= *(GetVariableDataPtr (Variable
.CurrPtr
));
177 // Check "SignatureSupport" variable's existence.
178 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
180 Status
= FindVariable (
181 EFI_SIGNATURE_SUPPORT_NAME
,
182 &gEfiGlobalVariableGuid
,
184 &mVariableModuleGlobal
->VariableGlobal
187 if (Variable
.CurrPtr
== NULL
) {
188 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
189 Status
= UpdateVariable (
190 EFI_SIGNATURE_SUPPORT_NAME
,
191 &gEfiGlobalVariableGuid
,
193 SIGSUPPORT_NUM
* sizeof(EFI_GUID
),
203 // Detect whether a secure platform-specific method to clear PK(Platform Key)
204 // is configured by platform owner. This method is provided for users force to clear PK
205 // in case incorrect enrollment mis-haps.
207 if (ForceClearPK ()) {
209 // 1. Check whether PK is existing, and clear PK if existing
212 EFI_PLATFORM_KEY_NAME
,
213 &gEfiGlobalVariableGuid
,
215 &mVariableModuleGlobal
->VariableGlobal
217 if (Variable
.CurrPtr
!= NULL
) {
218 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
219 Status
= UpdateVariable (
220 EFI_PLATFORM_KEY_NAME
,
221 &gEfiGlobalVariableGuid
,
230 if (EFI_ERROR (Status
)) {
236 // 2. Update "SetupMode" variable to SETUP_MODE
238 UpdatePlatformMode (SETUP_MODE
);
244 Add public key in store and return its index.
246 @param[in] PubKey Input pointer to Public Key data
248 @return Index of new added item
259 VARIABLE_POINTER_TRACK Variable
;
262 if (PubKey
== NULL
) {
266 Status
= FindVariable (
268 &gEfiAuthenticatedVariableGuid
,
270 &mVariableModuleGlobal
->VariableGlobal
272 ASSERT_EFI_ERROR (Status
);
274 // Check whether the public key entry does exist.
277 for (Ptr
= mPubKeyStore
, Index
= 1; Index
<= mPubKeyNumber
; Index
++) {
278 if (CompareMem (Ptr
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
282 Ptr
+= EFI_CERT_TYPE_RSA2048_SIZE
;
287 // Add public key in database.
289 if (mPubKeyNumber
== MAX_KEY_NUM
) {
291 // Notes: Database is full, need enhancement here, currently just return 0.
296 CopyMem (mPubKeyStore
+ mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
297 Index
= ++mPubKeyNumber
;
299 // Update public key database variable.
301 Status
= UpdateVariable (
303 &gEfiAuthenticatedVariableGuid
,
305 mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
,
306 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
312 ASSERT_EFI_ERROR (Status
);
319 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
320 Follow the steps in UEFI2.2.
322 @param[in] Data Pointer to data with AuthInfo.
323 @param[in] DataSize Size of Data.
324 @param[in] PubKey Public key used for verification.
326 @return EFI_INVALID_PARAMETER Invalid parameter.
327 @retval EFI_SECURITY_VIOLATION If authentication failed.
328 @return EFI_SUCCESS Authentication successful.
332 VerifyCounterBasedPayload (
339 EFI_VARIABLE_AUTHENTICATION
*CertData
;
340 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
341 UINT8 Digest
[SHA256_DIGEST_SIZE
];
348 if (Data
== NULL
|| PubKey
== NULL
) {
349 return EFI_INVALID_PARAMETER
;
352 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
353 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
356 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
357 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
359 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
360 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertRsa2048Sha256Guid
)
363 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
365 return EFI_SECURITY_VIOLATION
;
368 // Hash data payload with SHA256.
370 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
371 Status
= Sha256Init (mHashCtx
);
375 Status
= Sha256Update (mHashCtx
, Data
+ AUTHINFO_SIZE
, (UINTN
) (DataSize
- AUTHINFO_SIZE
));
380 // Hash Monotonic Count.
382 Status
= Sha256Update (mHashCtx
, &CertData
->MonotonicCount
, sizeof (UINT64
));
386 Status
= Sha256Final (mHashCtx
, Digest
);
391 // Generate & Initialize RSA Context.
394 ASSERT (Rsa
!= NULL
);
396 // Set RSA Key Components.
397 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
399 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
403 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
408 // Verify the signature.
410 Status
= RsaPkcs1Verify (
414 CertBlock
->Signature
,
415 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
425 return EFI_SECURITY_VIOLATION
;
431 Update platform mode.
433 @param[in] Mode SETUP_MODE or USER_MODE.
435 @return EFI_INVALID_PARAMETER Invalid parameter.
436 @return EFI_SUCCESS Update platform mode successfully.
445 VARIABLE_POINTER_TRACK Variable
;
447 UINT8 SecureBootMode
;
449 Status
= FindVariable (
451 &gEfiGlobalVariableGuid
,
453 &mVariableModuleGlobal
->VariableGlobal
455 if (EFI_ERROR (Status
)) {
459 mPlatformMode
= Mode
;
460 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
461 Status
= UpdateVariable (
463 &gEfiGlobalVariableGuid
,
472 if (EFI_ERROR (Status
)) {
477 // Check "SecureBoot" variable's existence.
478 // If it doesn't exist, firmware has no capability to perform driver signing verification,
479 // then set "SecureBoot" to 0.
481 Status
= FindVariable (
482 EFI_SECURE_BOOT_MODE_NAME
,
483 &gEfiGlobalVariableGuid
,
485 &mVariableModuleGlobal
->VariableGlobal
488 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
489 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
490 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
492 if (Variable
.CurrPtr
== NULL
) {
493 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
495 if (mPlatformMode
== USER_MODE
) {
496 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
497 } else if (mPlatformMode
== SETUP_MODE
) {
498 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
500 return EFI_NOT_FOUND
;
504 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
505 return UpdateVariable (
506 EFI_SECURE_BOOT_MODE_NAME
,
507 &gEfiGlobalVariableGuid
,
519 Process variable with platform key for verification.
521 @param[in] VariableName Name of Variable to be found.
522 @param[in] VendorGuid Variable vendor GUID.
523 @param[in] Data Data pointer.
524 @param[in] DataSize Size of Data found. If size is less than the
525 data, this value contains the required size.
526 @param[in] Variable The variable information which is used to keep track of variable usage.
527 @param[in] Attributes Attribute value of the variable
528 @param[in] IsPk Indicate whether it is to process pk.
530 @return EFI_INVALID_PARAMETER Invalid parameter.
531 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
532 check carried out by the firmware.
533 @return EFI_SUCCESS Variable passed validation successfully.
538 IN CHAR16
*VariableName
,
539 IN EFI_GUID
*VendorGuid
,
542 IN VARIABLE_POINTER_TRACK
*Variable
,
543 IN UINT32 Attributes OPTIONAL
,
548 VARIABLE_POINTER_TRACK PkVariable
;
549 EFI_SIGNATURE_LIST
*OldPkList
;
550 EFI_SIGNATURE_DATA
*OldPkData
;
551 EFI_VARIABLE_AUTHENTICATION
*CertData
;
555 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
557 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
559 return EFI_INVALID_PARAMETER
;
562 if (mPlatformMode
== USER_MODE
) {
564 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
566 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.
569 } else if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
571 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.
575 return EFI_INVALID_PARAMETER
;
580 // Verify against X509 Cert PK.
583 Status
= VerifyTimeBasedPayload (VariableName
, VendorGuid
, Data
, DataSize
, Variable
, Attributes
, TRUE
, &Del
);
584 if (!EFI_ERROR (Status
)) {
586 // If delete PK in user mode, need change to setup mode.
589 Status
= UpdatePlatformMode (SETUP_MODE
);
595 // Verify against RSA2048 Cert PK.
597 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
598 if ((Variable
->CurrPtr
!= NULL
) && (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
)) {
600 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
602 return EFI_SECURITY_VIOLATION
;
605 // Get platform key from variable.
607 Status
= FindVariable (
608 EFI_PLATFORM_KEY_NAME
,
609 &gEfiGlobalVariableGuid
,
611 &mVariableModuleGlobal
->VariableGlobal
613 ASSERT_EFI_ERROR (Status
);
615 OldPkList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (PkVariable
.CurrPtr
);
616 OldPkData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) OldPkList
+ sizeof (EFI_SIGNATURE_LIST
) + OldPkList
->SignatureHeaderSize
);
617 Status
= VerifyCounterBasedPayload (Data
, DataSize
, OldPkData
->SignatureData
);
618 if (!EFI_ERROR (Status
)) {
619 Status
= UpdateVariable (
622 (UINT8
*)Data
+ AUTHINFO_SIZE
,
623 DataSize
- AUTHINFO_SIZE
,
626 CertData
->MonotonicCount
,
631 if (!EFI_ERROR (Status
)) {
633 // If delete PK in user mode, need change to setup mode.
635 if ((DataSize
== AUTHINFO_SIZE
) && IsPk
) {
636 Status
= UpdatePlatformMode (SETUP_MODE
);
642 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, Variable
, NULL
);
644 // If enroll PK in setup mode, need change to user mode.
646 if ((DataSize
!= 0) && IsPk
) {
647 Status
= UpdatePlatformMode (USER_MODE
);
655 Process variable with key exchange key for verification.
657 @param[in] VariableName Name of Variable to be found.
658 @param[in] VendorGuid Variable vendor GUID.
659 @param[in] Data Data pointer.
660 @param[in] DataSize Size of Data found. If size is less than the
661 data, this value contains the required size.
662 @param[in] Variable The variable information which is used to keep track of variable usage.
663 @param[in] Attributes Attribute value of the variable.
665 @return EFI_INVALID_PARAMETER Invalid parameter.
666 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
667 check carried out by the firmware.
668 @return EFI_SUCCESS Variable pass validation successfully.
673 IN CHAR16
*VariableName
,
674 IN EFI_GUID
*VendorGuid
,
677 IN VARIABLE_POINTER_TRACK
*Variable
,
678 IN UINT32 Attributes OPTIONAL
682 VARIABLE_POINTER_TRACK KekVariable
;
683 EFI_SIGNATURE_LIST
*KekList
;
684 EFI_SIGNATURE_DATA
*KekItem
;
686 EFI_VARIABLE_AUTHENTICATION
*CertData
;
687 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
692 if (mPlatformMode
== USER_MODE
) {
693 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
695 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
697 return EFI_INVALID_PARAMETER
;
700 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
701 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
702 if ((Variable
->CurrPtr
!= NULL
) && (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
)) {
704 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
706 return EFI_SECURITY_VIOLATION
;
709 // Get KEK database from variable.
711 Status
= FindVariable (
712 EFI_KEY_EXCHANGE_KEY_NAME
,
713 &gEfiGlobalVariableGuid
,
715 &mVariableModuleGlobal
->VariableGlobal
717 ASSERT_EFI_ERROR (Status
);
719 KekDataSize
= KekVariable
.CurrPtr
->DataSize
;
720 KekList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (KekVariable
.CurrPtr
);
723 // Enumerate all Kek items in this list to verify the variable certificate data.
724 // If anyone is authenticated successfully, it means the variable is correct!
727 while ((KekDataSize
> 0) && (KekDataSize
>= KekList
->SignatureListSize
)) {
728 if (CompareGuid (&KekList
->SignatureType
, &gEfiCertRsa2048Guid
)) {
729 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekList
+ sizeof (EFI_SIGNATURE_LIST
) + KekList
->SignatureHeaderSize
);
730 KekCount
= (KekList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - KekList
->SignatureHeaderSize
) / KekList
->SignatureSize
;
731 for (Index
= 0; Index
< KekCount
; Index
++) {
732 if (CompareMem (KekItem
->SignatureData
, CertBlock
->PublicKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
736 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekItem
+ KekList
->SignatureSize
);
739 KekDataSize
-= KekList
->SignatureListSize
;
740 KekList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) KekList
+ KekList
->SignatureListSize
);
744 return EFI_SECURITY_VIOLATION
;
747 Status
= VerifyCounterBasedPayload (Data
, DataSize
, CertBlock
->PublicKey
);
748 if (!EFI_ERROR (Status
)) {
749 Status
= UpdateVariable (
752 (UINT8
*)Data
+ AUTHINFO_SIZE
,
753 DataSize
- AUTHINFO_SIZE
,
756 CertData
->MonotonicCount
,
763 // If in setup mode, no authentication needed.
765 Status
= UpdateVariable (
782 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
784 @param[in] VariableName Name of Variable to be found.
785 @param[in] VendorGuid Variable vendor GUID.
787 @param[in] Data Data pointer.
788 @param[in] DataSize Size of Data found. If size is less than the
789 data, this value contains the required size.
790 @param[in] Variable The variable information which is used to keep track of variable usage.
791 @param[in] Attributes Attribute value of the variable.
793 @return EFI_INVALID_PARAMETER Invalid parameter.
794 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
795 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
796 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
797 set, but the AuthInfo does NOT pass the validation
798 check carried out by the firmware.
799 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
804 IN CHAR16
*VariableName
,
805 IN EFI_GUID
*VendorGuid
,
808 IN VARIABLE_POINTER_TRACK
*Variable
,
816 EFI_VARIABLE_AUTHENTICATION
*CertData
;
817 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
819 UINT64 MonotonicCount
;
828 // Process Time-based Authenticated variable.
830 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
831 return VerifyTimeBasedPayload (VariableName
, VendorGuid
, Data
, DataSize
, Variable
, Attributes
, FALSE
, NULL
);
835 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
837 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
839 // Determine current operation type.
841 if (DataSize
== AUTHINFO_SIZE
) {
845 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
847 if (Variable
->CurrPtr
== NULL
) {
849 } else if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
852 KeyIndex
= Variable
->CurrPtr
->PubKeyIndex
;
855 } else if ((Variable
->CurrPtr
!= NULL
) &&
856 (Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0
859 // If the variable is already write-protected, it always needs authentication before update.
861 return EFI_WRITE_PROTECTED
;
864 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
865 // That means it is not authenticated variable, just update variable as usual.
867 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, Variable
, NULL
);
872 // Get PubKey and check Monotonic Count value corresponding to the variable.
874 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
875 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
876 PubKey
= CertBlock
->PublicKey
;
879 // Update Monotonic Count value.
881 MonotonicCount
= CertData
->MonotonicCount
;
885 // Check input PubKey.
887 if (CompareMem (PubKey
, mPubKeyStore
+ (KeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
, EFI_CERT_TYPE_RSA2048_SIZE
) != 0) {
888 return EFI_SECURITY_VIOLATION
;
891 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
892 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
894 if (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
) {
896 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
898 return EFI_SECURITY_VIOLATION
;
902 // Verify the certificate in Data payload.
904 Status
= VerifyCounterBasedPayload (Data
, DataSize
, PubKey
);
905 if (EFI_ERROR (Status
)) {
910 // Now, the signature has been verified!
912 if (IsFirstTime
&& !IsDeletion
) {
914 // Update public key database variable if need.
916 KeyIndex
= AddPubKeyInStore (PubKey
);
920 // Verification pass.
922 return UpdateVariable (VariableName
, VendorGuid
, (UINT8
*)Data
+ AUTHINFO_SIZE
, DataSize
- AUTHINFO_SIZE
, Attributes
, KeyIndex
, MonotonicCount
, Variable
, NULL
);
926 Compare two EFI_TIME data.
929 @param FirstTime A pointer to the first EFI_TIME data.
930 @param SecondTime A pointer to the second EFI_TIME data.
932 @retval TRUE The FirstTime is not later than the SecondTime.
933 @retval FALSE The FirstTime is later than the SecondTime.
938 IN EFI_TIME
*FirstTime
,
939 IN EFI_TIME
*SecondTime
942 if (FirstTime
->Year
!= SecondTime
->Year
) {
943 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
944 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
945 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
946 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
947 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
948 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
949 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
950 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
951 return (BOOLEAN
) (FirstTime
->Minute
< FirstTime
->Minute
);
954 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
958 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
960 @param[in] VariableName Name of Variable to be found.
961 @param[in] VendorGuid Variable vendor GUID.
962 @param[in] Data Data pointer.
963 @param[in] DataSize Size of Data found. If size is less than the
964 data, this value contains the required size.
965 @param[in] Variable The variable information which is used to keep track of variable usage.
966 @param[in] Attributes Attribute value of the variable.
967 @param[in] Pk Verify against PK or KEK database.
968 @param[out] VarDel Delete the variable or not.
970 @retval EFI_INVALID_PARAMETER Invalid parameter.
971 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
972 check carried out by the firmware.
973 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
975 @retval EFI_SUCCESS Variable pass validation successfully.
979 VerifyTimeBasedPayload (
980 IN CHAR16
*VariableName
,
981 IN EFI_GUID
*VendorGuid
,
984 IN VARIABLE_POINTER_TRACK
*Variable
,
985 IN UINT32 Attributes
,
1001 BOOLEAN VerifyStatus
;
1003 EFI_SIGNATURE_LIST
*CertList
;
1004 EFI_SIGNATURE_DATA
*Cert
;
1005 VARIABLE_POINTER_TRACK KekVariable
;
1006 EFI_VARIABLE_AUTHENTICATION_2
*CertData
;
1009 VARIABLE_POINTER_TRACK PkVariable
;
1013 VerifyStatus
= FALSE
;
1019 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1020 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1021 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1022 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1023 // variable value. The authentication descriptor is not part of the variable data and is not
1024 // returned by subsequent calls to GetVariable().
1026 CertData
= (EFI_VARIABLE_AUTHENTICATION_2
*) Data
;
1028 if ((Variable
->CurrPtr
!= NULL
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
1029 if (CompareTimeStamp (&CertData
->TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
1031 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1033 return EFI_SECURITY_VIOLATION
;
1038 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1039 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1041 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
1042 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
)
1045 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1047 return EFI_SECURITY_VIOLATION
;
1051 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1052 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1054 SigData
= (UINT8
*) ((UINTN
)Data
+ OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
1057 // Sanity check to avoid corrupted certificate input.
1059 if (CertData
->AuthInfo
.Hdr
.dwLength
< (UINT32
)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
))) {
1060 return EFI_SECURITY_VIOLATION
;
1065 SigDataSize
= CertData
->AuthInfo
.Hdr
.dwLength
- (UINT32
)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
1068 // Find out the new data payload which follows Pkcs7 SignedData directly.
1070 PayLoadPtr
= (UINT8
*) ((UINTN
) SigData
+ (UINTN
) SigDataSize
);
1073 // Sanity check to avoid corrupted certificate input.
1075 if (DataSize
< (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)+ (UINTN
) SigDataSize
)) {
1076 return EFI_SECURITY_VIOLATION
;
1079 PayLoadSize
= DataSize
- OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) - OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
) - (UINTN
) SigDataSize
;
1083 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
1085 NewDataSize
= PayLoadSize
+ sizeof (EFI_TIME
) + sizeof (UINT32
) +
1086 sizeof (EFI_GUID
) + StrSize (VariableName
);
1087 NewData
= (UINT8
*) AllocateZeroPool (NewDataSize
);
1089 if (NewData
== NULL
) {
1090 return EFI_OUT_OF_RESOURCES
;
1093 CopyMem (NewData
, VariableName
, StrSize (VariableName
));
1095 CopyMem (NewData
+ StrSize (VariableName
), VendorGuid
, sizeof (EFI_GUID
));
1098 NewData
+ StrSize (VariableName
) + sizeof (EFI_GUID
),
1104 NewData
+ StrSize (VariableName
) + sizeof (EFI_GUID
) + sizeof (UINT32
),
1105 &CertData
->TimeStamp
,
1109 CopyMem (NewData
+ (NewDataSize
- PayLoadSize
), PayLoadPtr
, PayLoadSize
);
1114 // Get platform key from variable.
1116 Status
= FindVariable (
1117 EFI_PLATFORM_KEY_NAME
,
1118 &gEfiGlobalVariableGuid
,
1120 &mVariableModuleGlobal
->VariableGlobal
1122 if (EFI_ERROR (Status
)) {
1126 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (PkVariable
.CurrPtr
);
1127 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1128 RootCert
= Cert
->SignatureData
;
1129 RootCertSize
= CertList
->SignatureSize
;
1133 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1135 VerifyStatus
= Pkcs7Verify (
1147 // Get KEK database from variable.
1149 Status
= FindVariable (
1150 EFI_KEY_EXCHANGE_KEY_NAME
,
1151 &gEfiGlobalVariableGuid
,
1153 &mVariableModuleGlobal
->VariableGlobal
1155 if (EFI_ERROR (Status
)) {
1160 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
1162 KekDataSize
= KekVariable
.CurrPtr
->DataSize
;
1163 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (KekVariable
.CurrPtr
);
1164 while ((KekDataSize
> 0) && (KekDataSize
>= CertList
->SignatureListSize
)) {
1165 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
1166 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1167 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
1168 for (Index
= 0; Index
< CertCount
; Index
++) {
1170 // Iterate each Signature Data Node within this CertList for a verify
1172 RootCert
= Cert
->SignatureData
;
1173 RootCertSize
= CertList
->SignatureSize
;
1176 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1178 VerifyStatus
= Pkcs7Verify (
1189 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
1192 KekDataSize
-= CertList
->SignatureListSize
;
1193 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
1201 if (!VerifyStatus
) {
1202 return EFI_SECURITY_VIOLATION
;
1205 if ((PayLoadSize
== 0) && (VarDel
!= NULL
)) {
1210 // Final step: Update/Append Variable if it pass Pkcs7Verify
1212 return UpdateVariable (
1221 &CertData
->TimeStamp