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
;
72 VARIABLE_POINTER_TRACK Variable2
;
79 UINT8 SecureBootEnable
;
82 // Initialize hash context.
84 CtxSize
= Sha256GetContextSize ();
85 mHashCtx
= AllocateRuntimePool (CtxSize
);
86 if (mHashCtx
== NULL
) {
87 return EFI_OUT_OF_RESOURCES
;
91 // Reserved runtime buffer for "Append" operation in virtual mode.
93 mStorageArea
= AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize
));
94 if (mStorageArea
== NULL
) {
95 return EFI_OUT_OF_RESOURCES
;
99 // Check "AuthVarKeyDatabase" variable's existence.
100 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
102 Status
= FindVariable (
104 &gEfiAuthenticatedVariableGuid
,
106 &mVariableModuleGlobal
->VariableGlobal
109 if (Variable
.CurrPtr
== NULL
) {
110 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
113 Status
= UpdateVariable (
115 &gEfiAuthenticatedVariableGuid
,
124 if (EFI_ERROR (Status
)) {
129 // Load database in global variable for cache.
131 DataSize
= DataSizeOfVariable (Variable
.CurrPtr
);
132 Data
= GetVariableDataPtr (Variable
.CurrPtr
);
133 ASSERT ((DataSize
!= 0) && (Data
!= NULL
));
134 CopyMem (mPubKeyStore
, (UINT8
*) Data
, DataSize
);
135 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
138 // Check "SetupMode" variable's existence.
139 // If it doesn't exist, check PK database's existence to determine the value.
140 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
142 Status
= FindVariable (
144 &gEfiGlobalVariableGuid
,
146 &mVariableModuleGlobal
->VariableGlobal
149 if (Variable
.CurrPtr
== NULL
) {
150 Status
= FindVariable (
151 EFI_PLATFORM_KEY_NAME
,
152 &gEfiGlobalVariableGuid
,
154 &mVariableModuleGlobal
->VariableGlobal
156 if (Variable2
.CurrPtr
== NULL
) {
157 mPlatformMode
= SETUP_MODE
;
159 mPlatformMode
= USER_MODE
;
162 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
163 Status
= UpdateVariable (
165 &gEfiGlobalVariableGuid
,
174 if (EFI_ERROR (Status
)) {
178 mPlatformMode
= *(GetVariableDataPtr (Variable
.CurrPtr
));
181 // Check "SignatureSupport" variable's existence.
182 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
184 Status
= FindVariable (
185 EFI_SIGNATURE_SUPPORT_NAME
,
186 &gEfiGlobalVariableGuid
,
188 &mVariableModuleGlobal
->VariableGlobal
192 if (Variable
.CurrPtr
== NULL
) {
193 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
194 Status
= UpdateVariable (
195 EFI_SIGNATURE_SUPPORT_NAME
,
196 &gEfiGlobalVariableGuid
,
198 SIGSUPPORT_NUM
* sizeof(EFI_GUID
),
208 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
209 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
210 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
212 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME
, &gEfiSecureBootEnableDisableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
213 if (Variable
.CurrPtr
!= NULL
) {
214 SecureBootEnable
= *(GetVariableDataPtr (Variable
.CurrPtr
));
215 if (SecureBootEnable
== SECURE_BOOT_ENABLE
) {
216 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
218 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
220 FindVariable (EFI_SECURE_BOOT_MODE_NAME
, &gEfiGlobalVariableGuid
, &Variable
, &mVariableModuleGlobal
->VariableGlobal
);
221 Status
= UpdateVariable (
222 EFI_SECURE_BOOT_MODE_NAME
,
223 &gEfiGlobalVariableGuid
,
226 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
232 if (EFI_ERROR (Status
)) {
238 // Detect whether a secure platform-specific method to clear PK(Platform Key)
239 // is configured by platform owner. This method is provided for users force to clear PK
240 // in case incorrect enrollment mis-haps.
242 if (ForceClearPK ()) {
244 // 1. Check whether PK is existing, and clear PK if existing
247 EFI_PLATFORM_KEY_NAME
,
248 &gEfiGlobalVariableGuid
,
250 &mVariableModuleGlobal
->VariableGlobal
252 if (Variable
.CurrPtr
!= NULL
) {
253 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
254 Status
= UpdateVariable (
255 EFI_PLATFORM_KEY_NAME
,
256 &gEfiGlobalVariableGuid
,
265 if (EFI_ERROR (Status
)) {
271 // 2. Update "SetupMode" variable to SETUP_MODE
273 UpdatePlatformMode (SETUP_MODE
);
279 Add public key in store and return its index.
281 @param[in] PubKey Input pointer to Public Key data
283 @return Index of new added item
294 VARIABLE_POINTER_TRACK Variable
;
297 if (PubKey
== NULL
) {
301 Status
= FindVariable (
303 &gEfiAuthenticatedVariableGuid
,
305 &mVariableModuleGlobal
->VariableGlobal
307 ASSERT_EFI_ERROR (Status
);
309 // Check whether the public key entry does exist.
312 for (Ptr
= mPubKeyStore
, Index
= 1; Index
<= mPubKeyNumber
; Index
++) {
313 if (CompareMem (Ptr
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
317 Ptr
+= EFI_CERT_TYPE_RSA2048_SIZE
;
322 // Add public key in database.
324 if (mPubKeyNumber
== MAX_KEY_NUM
) {
326 // Notes: Database is full, need enhancement here, currently just return 0.
331 CopyMem (mPubKeyStore
+ mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
332 Index
= ++mPubKeyNumber
;
334 // Update public key database variable.
336 Status
= UpdateVariable (
338 &gEfiAuthenticatedVariableGuid
,
340 mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
,
341 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
347 ASSERT_EFI_ERROR (Status
);
354 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
355 Follow the steps in UEFI2.2.
357 @param[in] Data Pointer to data with AuthInfo.
358 @param[in] DataSize Size of Data.
359 @param[in] PubKey Public key used for verification.
361 @return EFI_INVALID_PARAMETER Invalid parameter.
362 @retval EFI_SECURITY_VIOLATION If authentication failed.
363 @return EFI_SUCCESS Authentication successful.
367 VerifyCounterBasedPayload (
374 EFI_VARIABLE_AUTHENTICATION
*CertData
;
375 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
376 UINT8 Digest
[SHA256_DIGEST_SIZE
];
383 if (Data
== NULL
|| PubKey
== NULL
) {
384 return EFI_INVALID_PARAMETER
;
387 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
388 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
391 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
392 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
394 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
395 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertRsa2048Sha256Guid
)
398 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
400 return EFI_SECURITY_VIOLATION
;
403 // Hash data payload with SHA256.
405 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
406 Status
= Sha256Init (mHashCtx
);
410 Status
= Sha256Update (mHashCtx
, Data
+ AUTHINFO_SIZE
, (UINTN
) (DataSize
- AUTHINFO_SIZE
));
415 // Hash Monotonic Count.
417 Status
= Sha256Update (mHashCtx
, &CertData
->MonotonicCount
, sizeof (UINT64
));
421 Status
= Sha256Final (mHashCtx
, Digest
);
426 // Generate & Initialize RSA Context.
429 ASSERT (Rsa
!= NULL
);
431 // Set RSA Key Components.
432 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
434 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
438 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
443 // Verify the signature.
445 Status
= RsaPkcs1Verify (
449 CertBlock
->Signature
,
450 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
460 return EFI_SECURITY_VIOLATION
;
466 Update platform mode.
468 @param[in] Mode SETUP_MODE or USER_MODE.
470 @return EFI_INVALID_PARAMETER Invalid parameter.
471 @return EFI_SUCCESS Update platform mode successfully.
480 VARIABLE_POINTER_TRACK Variable
;
482 UINT8 SecureBootMode
;
483 UINT8 SecureBootEnable
;
484 UINTN VariableDataSize
;
486 Status
= FindVariable (
488 &gEfiGlobalVariableGuid
,
490 &mVariableModuleGlobal
->VariableGlobal
492 if (EFI_ERROR (Status
)) {
496 mPlatformMode
= Mode
;
497 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
498 Status
= UpdateVariable (
500 &gEfiGlobalVariableGuid
,
509 if (EFI_ERROR (Status
)) {
514 // Check "SecureBoot" variable's existence.
515 // If it doesn't exist, firmware has no capability to perform driver signing verification,
516 // then set "SecureBoot" to 0.
518 Status
= FindVariable (
519 EFI_SECURE_BOOT_MODE_NAME
,
520 &gEfiGlobalVariableGuid
,
522 &mVariableModuleGlobal
->VariableGlobal
525 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
526 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
527 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
529 if (Variable
.CurrPtr
== NULL
) {
530 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
532 if (mPlatformMode
== USER_MODE
) {
533 SecureBootMode
= SECURE_BOOT_MODE_ENABLE
;
534 } else if (mPlatformMode
== SETUP_MODE
) {
535 SecureBootMode
= SECURE_BOOT_MODE_DISABLE
;
537 return EFI_NOT_FOUND
;
541 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
542 Status
= UpdateVariable (
543 EFI_SECURE_BOOT_MODE_NAME
,
544 &gEfiGlobalVariableGuid
,
554 if (EFI_ERROR (Status
)) {
559 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
561 Status
= FindVariable (
562 EFI_SECURE_BOOT_ENABLE_NAME
,
563 &gEfiSecureBootEnableDisableGuid
,
565 &mVariableModuleGlobal
->VariableGlobal
568 if (SecureBootMode
== SECURE_BOOT_MODE_ENABLE
) {
570 // Create the "SecureBootEnable" variable as secure boot is enabled.
572 SecureBootEnable
= SECURE_BOOT_ENABLE
;
573 VariableDataSize
= sizeof (SecureBootEnable
);
576 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
577 // variable is not in secure boot state.
579 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
582 SecureBootEnable
= SECURE_BOOT_DISABLE
;
583 VariableDataSize
= 0;
586 Status
= UpdateVariable (
587 EFI_SECURE_BOOT_ENABLE_NAME
,
588 &gEfiSecureBootEnableDisableGuid
,
591 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
601 Process variable with platform key for verification.
603 @param[in] VariableName Name of Variable to be found.
604 @param[in] VendorGuid Variable vendor GUID.
605 @param[in] Data Data pointer.
606 @param[in] DataSize Size of Data found. If size is less than the
607 data, this value contains the required size.
608 @param[in] Variable The variable information which is used to keep track of variable usage.
609 @param[in] Attributes Attribute value of the variable
610 @param[in] IsPk Indicate whether it is to process pk.
612 @return EFI_INVALID_PARAMETER Invalid parameter.
613 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
614 check carried out by the firmware.
615 @return EFI_SUCCESS Variable passed validation successfully.
620 IN CHAR16
*VariableName
,
621 IN EFI_GUID
*VendorGuid
,
624 IN VARIABLE_POINTER_TRACK
*Variable
,
625 IN UINT32 Attributes OPTIONAL
,
630 VARIABLE_POINTER_TRACK PkVariable
;
631 EFI_SIGNATURE_LIST
*OldPkList
;
632 EFI_SIGNATURE_DATA
*OldPkData
;
633 EFI_VARIABLE_AUTHENTICATION
*CertData
;
637 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
639 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
641 return EFI_INVALID_PARAMETER
;
644 if (mPlatformMode
== USER_MODE
) {
646 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
648 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.
651 } else if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
653 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.
657 return EFI_INVALID_PARAMETER
;
662 // Verify against X509 Cert PK.
665 Status
= VerifyTimeBasedPayload (VariableName
, VendorGuid
, Data
, DataSize
, Variable
, Attributes
, TRUE
, &Del
);
666 if (!EFI_ERROR (Status
)) {
668 // If delete PK in user mode, need change to setup mode.
671 Status
= UpdatePlatformMode (SETUP_MODE
);
677 // Verify against RSA2048 Cert PK.
679 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
680 if ((Variable
->CurrPtr
!= NULL
) && (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
)) {
682 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
684 return EFI_SECURITY_VIOLATION
;
687 // Get platform key from variable.
689 Status
= FindVariable (
690 EFI_PLATFORM_KEY_NAME
,
691 &gEfiGlobalVariableGuid
,
693 &mVariableModuleGlobal
->VariableGlobal
695 ASSERT_EFI_ERROR (Status
);
697 OldPkList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (PkVariable
.CurrPtr
);
698 OldPkData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) OldPkList
+ sizeof (EFI_SIGNATURE_LIST
) + OldPkList
->SignatureHeaderSize
);
699 Status
= VerifyCounterBasedPayload (Data
, DataSize
, OldPkData
->SignatureData
);
700 if (!EFI_ERROR (Status
)) {
701 Status
= UpdateVariable (
704 (UINT8
*)Data
+ AUTHINFO_SIZE
,
705 DataSize
- AUTHINFO_SIZE
,
708 CertData
->MonotonicCount
,
713 if (!EFI_ERROR (Status
)) {
715 // If delete PK in user mode, need change to setup mode.
717 if ((DataSize
== AUTHINFO_SIZE
) && IsPk
) {
718 Status
= UpdatePlatformMode (SETUP_MODE
);
724 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, Variable
, NULL
);
726 // If enroll PK in setup mode, need change to user mode.
728 if ((DataSize
!= 0) && IsPk
) {
729 Status
= UpdatePlatformMode (USER_MODE
);
737 Process variable with key exchange key for verification.
739 @param[in] VariableName Name of Variable to be found.
740 @param[in] VendorGuid Variable vendor GUID.
741 @param[in] Data Data pointer.
742 @param[in] DataSize Size of Data found. If size is less than the
743 data, this value contains the required size.
744 @param[in] Variable The variable information which is used to keep track of variable usage.
745 @param[in] Attributes Attribute value of the variable.
747 @return EFI_INVALID_PARAMETER Invalid parameter.
748 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
749 check carried out by the firmware.
750 @return EFI_SUCCESS Variable pass validation successfully.
755 IN CHAR16
*VariableName
,
756 IN EFI_GUID
*VendorGuid
,
759 IN VARIABLE_POINTER_TRACK
*Variable
,
760 IN UINT32 Attributes OPTIONAL
764 VARIABLE_POINTER_TRACK KekVariable
;
765 EFI_SIGNATURE_LIST
*KekList
;
766 EFI_SIGNATURE_DATA
*KekItem
;
768 EFI_VARIABLE_AUTHENTICATION
*CertData
;
769 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
774 if (mPlatformMode
== USER_MODE
) {
775 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
777 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
779 return EFI_INVALID_PARAMETER
;
782 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
783 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
784 if ((Variable
->CurrPtr
!= NULL
) && (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
)) {
786 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
788 return EFI_SECURITY_VIOLATION
;
791 // Get KEK database from variable.
793 Status
= FindVariable (
794 EFI_KEY_EXCHANGE_KEY_NAME
,
795 &gEfiGlobalVariableGuid
,
797 &mVariableModuleGlobal
->VariableGlobal
799 ASSERT_EFI_ERROR (Status
);
801 KekDataSize
= KekVariable
.CurrPtr
->DataSize
;
802 KekList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (KekVariable
.CurrPtr
);
805 // Enumerate all Kek items in this list to verify the variable certificate data.
806 // If anyone is authenticated successfully, it means the variable is correct!
809 while ((KekDataSize
> 0) && (KekDataSize
>= KekList
->SignatureListSize
)) {
810 if (CompareGuid (&KekList
->SignatureType
, &gEfiCertRsa2048Guid
)) {
811 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekList
+ sizeof (EFI_SIGNATURE_LIST
) + KekList
->SignatureHeaderSize
);
812 KekCount
= (KekList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - KekList
->SignatureHeaderSize
) / KekList
->SignatureSize
;
813 for (Index
= 0; Index
< KekCount
; Index
++) {
814 if (CompareMem (KekItem
->SignatureData
, CertBlock
->PublicKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
818 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekItem
+ KekList
->SignatureSize
);
821 KekDataSize
-= KekList
->SignatureListSize
;
822 KekList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) KekList
+ KekList
->SignatureListSize
);
826 return EFI_SECURITY_VIOLATION
;
829 Status
= VerifyCounterBasedPayload (Data
, DataSize
, CertBlock
->PublicKey
);
830 if (!EFI_ERROR (Status
)) {
831 Status
= UpdateVariable (
834 (UINT8
*)Data
+ AUTHINFO_SIZE
,
835 DataSize
- AUTHINFO_SIZE
,
838 CertData
->MonotonicCount
,
845 // If in setup mode, no authentication needed.
847 Status
= UpdateVariable (
864 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
866 @param[in] VariableName Name of Variable to be found.
867 @param[in] VendorGuid Variable vendor GUID.
869 @param[in] Data Data pointer.
870 @param[in] DataSize Size of Data found. If size is less than the
871 data, this value contains the required size.
872 @param[in] Variable The variable information which is used to keep track of variable usage.
873 @param[in] Attributes Attribute value of the variable.
875 @return EFI_INVALID_PARAMETER Invalid parameter.
876 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
877 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
878 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
879 set, but the AuthInfo does NOT pass the validation
880 check carried out by the firmware.
881 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
886 IN CHAR16
*VariableName
,
887 IN EFI_GUID
*VendorGuid
,
890 IN VARIABLE_POINTER_TRACK
*Variable
,
898 EFI_VARIABLE_AUTHENTICATION
*CertData
;
899 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
901 UINT64 MonotonicCount
;
910 // Process Time-based Authenticated variable.
912 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
913 return VerifyTimeBasedPayload (VariableName
, VendorGuid
, Data
, DataSize
, Variable
, Attributes
, FALSE
, NULL
);
917 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
919 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
921 // Determine current operation type.
923 if (DataSize
== AUTHINFO_SIZE
) {
927 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
929 if (Variable
->CurrPtr
== NULL
) {
931 } else if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
934 KeyIndex
= Variable
->CurrPtr
->PubKeyIndex
;
937 } else if ((Variable
->CurrPtr
!= NULL
) &&
938 (Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0
941 // If the variable is already write-protected, it always needs authentication before update.
943 return EFI_WRITE_PROTECTED
;
946 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
947 // That means it is not authenticated variable, just update variable as usual.
949 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, Variable
, NULL
);
954 // Get PubKey and check Monotonic Count value corresponding to the variable.
956 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
957 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
958 PubKey
= CertBlock
->PublicKey
;
961 // Update Monotonic Count value.
963 MonotonicCount
= CertData
->MonotonicCount
;
967 // Check input PubKey.
969 if (CompareMem (PubKey
, mPubKeyStore
+ (KeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
, EFI_CERT_TYPE_RSA2048_SIZE
) != 0) {
970 return EFI_SECURITY_VIOLATION
;
973 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
974 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
976 if (CertData
->MonotonicCount
<= Variable
->CurrPtr
->MonotonicCount
) {
978 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
980 return EFI_SECURITY_VIOLATION
;
984 // Verify the certificate in Data payload.
986 Status
= VerifyCounterBasedPayload (Data
, DataSize
, PubKey
);
987 if (EFI_ERROR (Status
)) {
992 // Now, the signature has been verified!
994 if (IsFirstTime
&& !IsDeletion
) {
996 // Update public key database variable if need.
998 KeyIndex
= AddPubKeyInStore (PubKey
);
1002 // Verification pass.
1004 return UpdateVariable (VariableName
, VendorGuid
, (UINT8
*)Data
+ AUTHINFO_SIZE
, DataSize
- AUTHINFO_SIZE
, Attributes
, KeyIndex
, MonotonicCount
, Variable
, NULL
);
1008 Compare two EFI_TIME data.
1011 @param FirstTime A pointer to the first EFI_TIME data.
1012 @param SecondTime A pointer to the second EFI_TIME data.
1014 @retval TRUE The FirstTime is not later than the SecondTime.
1015 @retval FALSE The FirstTime is later than the SecondTime.
1020 IN EFI_TIME
*FirstTime
,
1021 IN EFI_TIME
*SecondTime
1024 if (FirstTime
->Year
!= SecondTime
->Year
) {
1025 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
1026 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
1027 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
1028 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
1029 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
1030 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
1031 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
1032 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
1033 return (BOOLEAN
) (FirstTime
->Minute
< FirstTime
->Minute
);
1036 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
1040 Process variable with 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.
1044 @param[in] Data Data pointer.
1045 @param[in] DataSize Size of Data found. If size is less than the
1046 data, this value contains the required size.
1047 @param[in] Variable The variable information which is used to keep track of variable usage.
1048 @param[in] Attributes Attribute value of the variable.
1049 @param[in] Pk Verify against PK or KEK database.
1050 @param[out] VarDel Delete the variable or not.
1052 @retval EFI_INVALID_PARAMETER Invalid parameter.
1053 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1054 check carried out by the firmware.
1055 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
1057 @retval EFI_SUCCESS Variable pass validation successfully.
1061 VerifyTimeBasedPayload (
1062 IN CHAR16
*VariableName
,
1063 IN EFI_GUID
*VendorGuid
,
1066 IN VARIABLE_POINTER_TRACK
*Variable
,
1067 IN UINT32 Attributes
,
1083 BOOLEAN VerifyStatus
;
1085 EFI_SIGNATURE_LIST
*CertList
;
1086 EFI_SIGNATURE_DATA
*Cert
;
1087 VARIABLE_POINTER_TRACK KekVariable
;
1088 EFI_VARIABLE_AUTHENTICATION_2
*CertData
;
1091 VARIABLE_POINTER_TRACK PkVariable
;
1095 VerifyStatus
= FALSE
;
1101 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1102 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1103 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1104 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1105 // variable value. The authentication descriptor is not part of the variable data and is not
1106 // returned by subsequent calls to GetVariable().
1108 CertData
= (EFI_VARIABLE_AUTHENTICATION_2
*) Data
;
1110 if ((Variable
->CurrPtr
!= NULL
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
1111 if (CompareTimeStamp (&CertData
->TimeStamp
, &Variable
->CurrPtr
->TimeStamp
)) {
1113 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1115 return EFI_SECURITY_VIOLATION
;
1120 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1121 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1123 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
1124 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
)
1127 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1129 return EFI_SECURITY_VIOLATION
;
1133 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1134 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1136 SigData
= (UINT8
*) ((UINTN
)Data
+ OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
1139 // Sanity check to avoid corrupted certificate input.
1141 if (CertData
->AuthInfo
.Hdr
.dwLength
< (UINT32
)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
))) {
1142 return EFI_SECURITY_VIOLATION
;
1147 SigDataSize
= CertData
->AuthInfo
.Hdr
.dwLength
- (UINT32
)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
1150 // Find out the new data payload which follows Pkcs7 SignedData directly.
1152 PayLoadPtr
= (UINT8
*) ((UINTN
) SigData
+ (UINTN
) SigDataSize
);
1155 // Sanity check to avoid corrupted certificate input.
1157 if (DataSize
< (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
)+ (UINTN
) SigDataSize
)) {
1158 return EFI_SECURITY_VIOLATION
;
1161 PayLoadSize
= DataSize
- OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2
, AuthInfo
) - OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
) - (UINTN
) SigDataSize
;
1165 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
1167 NewDataSize
= PayLoadSize
+ sizeof (EFI_TIME
) + sizeof (UINT32
) +
1168 sizeof (EFI_GUID
) + StrSize (VariableName
);
1169 NewData
= (UINT8
*) AllocateZeroPool (NewDataSize
);
1171 if (NewData
== NULL
) {
1172 return EFI_OUT_OF_RESOURCES
;
1175 CopyMem (NewData
, VariableName
, StrSize (VariableName
));
1177 CopyMem (NewData
+ StrSize (VariableName
), VendorGuid
, sizeof (EFI_GUID
));
1180 NewData
+ StrSize (VariableName
) + sizeof (EFI_GUID
),
1186 NewData
+ StrSize (VariableName
) + sizeof (EFI_GUID
) + sizeof (UINT32
),
1187 &CertData
->TimeStamp
,
1191 CopyMem (NewData
+ (NewDataSize
- PayLoadSize
), PayLoadPtr
, PayLoadSize
);
1196 // Get platform key from variable.
1198 Status
= FindVariable (
1199 EFI_PLATFORM_KEY_NAME
,
1200 &gEfiGlobalVariableGuid
,
1202 &mVariableModuleGlobal
->VariableGlobal
1204 if (EFI_ERROR (Status
)) {
1208 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (PkVariable
.CurrPtr
);
1209 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1210 RootCert
= Cert
->SignatureData
;
1211 RootCertSize
= CertList
->SignatureSize
;
1215 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1217 VerifyStatus
= Pkcs7Verify (
1229 // Get KEK database from variable.
1231 Status
= FindVariable (
1232 EFI_KEY_EXCHANGE_KEY_NAME
,
1233 &gEfiGlobalVariableGuid
,
1235 &mVariableModuleGlobal
->VariableGlobal
1237 if (EFI_ERROR (Status
)) {
1242 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
1244 KekDataSize
= KekVariable
.CurrPtr
->DataSize
;
1245 CertList
= (EFI_SIGNATURE_LIST
*) GetVariableDataPtr (KekVariable
.CurrPtr
);
1246 while ((KekDataSize
> 0) && (KekDataSize
>= CertList
->SignatureListSize
)) {
1247 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
1248 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
1249 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
1250 for (Index
= 0; Index
< CertCount
; Index
++) {
1252 // Iterate each Signature Data Node within this CertList for a verify
1254 RootCert
= Cert
->SignatureData
;
1255 RootCertSize
= CertList
->SignatureSize
;
1258 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1260 VerifyStatus
= Pkcs7Verify (
1271 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
1274 KekDataSize
-= CertList
->SignatureListSize
;
1275 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
1283 if (!VerifyStatus
) {
1284 return EFI_SECURITY_VIOLATION
;
1287 if ((PayLoadSize
== 0) && (VarDel
!= NULL
)) {
1292 // Final step: Update/Append Variable if it pass Pkcs7Verify
1294 return UpdateVariable (
1303 &CertData
->TimeStamp