2 Implement authentication services for the authenticated variables.
4 Caution: This module requires additional review when modified.
5 This driver will have external input - variable data. It may be input in SMM mode.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8 Variable attribute should also be checked to avoid authentication bypass.
9 The whole SMM authentication variable design relies on the integrity of flash part and SMM.
10 which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
11 may not be modified without authorization. If platform fails to protect these resources,
12 the authentication service provided in this driver will be broken, and the behavior is undefined.
14 ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
15 variable authentication.
17 VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.
18 They will do basic validation for authentication data structure, then call crypto library
19 to verify the signature.
21 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
22 This program and the accompanying materials
23 are licensed and made available under the terms and conditions of the BSD License
24 which accompanies this distribution. The full text of the license may be found at
25 http://opensource.org/licenses/bsd-license.php
27 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
28 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
32 #include "AuthServiceInternal.h"
35 // Public Exponent of RSA Key.
37 CONST UINT8 mRsaE
[] = { 0x01, 0x00, 0x01 };
40 // Requirement for different signature type which have been defined in UEFI spec.
41 // These data are used to perform SignatureList format check while setting PK/KEK variable.
43 EFI_SIGNATURE_ITEM mSupportSigItem
[] = {
44 //{SigType, SigHeaderSize, SigDataSize }
45 {EFI_CERT_SHA256_GUID
, 0, 32 },
46 {EFI_CERT_RSA2048_GUID
, 0, 256 },
47 {EFI_CERT_RSA2048_SHA256_GUID
, 0, 256 },
48 {EFI_CERT_SHA1_GUID
, 0, 20 },
49 {EFI_CERT_RSA2048_SHA1_GUID
, 0, 256 },
50 {EFI_CERT_X509_GUID
, 0, ((UINT32
) ~0)},
51 {EFI_CERT_SHA224_GUID
, 0, 28 },
52 {EFI_CERT_SHA384_GUID
, 0, 48 },
53 {EFI_CERT_SHA512_GUID
, 0, 64 },
54 {EFI_CERT_X509_SHA256_GUID
, 0, 48 },
55 {EFI_CERT_X509_SHA384_GUID
, 0, 64 },
56 {EFI_CERT_X509_SHA512_GUID
, 0, 80 }
60 // Secure Boot Mode state machine
62 SECURE_BOOT_MODE mSecureBootState
[SecureBootModeTypeMax
] = {
65 AUDIT_MODE_DISABLE
, // AuditMode
66 FALSE
, // IsAuditModeRO, AuditMode is RW
67 DEPLOYED_MODE_DISABLE
, // DeployedMode
68 FALSE
, // IsDeployedModeRO, DeployedMode is RW
69 SETUP_MODE_DISABLE
, // SetupMode
70 // SetupMode is always RO
71 SECURE_BOOT_MODE_ENABLE
// SecureBoot
75 AUDIT_MODE_DISABLE
, // AuditMode
76 FALSE
, // IsAuditModeRO, AuditMode is RW
77 DEPLOYED_MODE_DISABLE
, // DeployedMode
78 TRUE
, // IsDeployedModeRO, DeployedMode is RO
79 SETUP_MODE_ENABLE
, // SetupMode
80 // SetupMode is always RO
81 SECURE_BOOT_MODE_DISABLE
// SecureBoot
85 AUDIT_MODE_ENABLE
, // AuditMode
86 TRUE
, // AuditModeValAttr RO, AuditMode is RO
87 DEPLOYED_MODE_DISABLE
, // DeployedMode
88 TRUE
, // DeployedModeValAttr RO, DeployedMode is RO
89 SETUP_MODE_ENABLE
, // SetupMode
90 // SetupMode is always RO
91 SECURE_BOOT_MODE_DISABLE
// SecureBoot
95 AUDIT_MODE_DISABLE
, // AuditMode, AuditMode is RO
96 TRUE
, // AuditModeValAttr RO
97 DEPLOYED_MODE_ENABLE
, // DeployedMode
98 TRUE
, // DeployedModeValAttr RO, DeployedMode is RO
99 SETUP_MODE_DISABLE
, // SetupMode
100 // SetupMode is always RO
101 SECURE_BOOT_MODE_ENABLE
// SecureBoot
105 SECURE_BOOT_MODE_TYPE mSecureBootMode
;
108 Finds variable in storage blocks of volatile and non-volatile storage areas.
110 This code finds variable in storage blocks of volatile and non-volatile storage areas.
111 If VariableName is an empty string, then we just return the first
112 qualified variable without comparing VariableName and VendorGuid.
114 @param[in] VariableName Name of the variable to be found.
115 @param[in] VendorGuid Variable vendor GUID to be found.
116 @param[out] Data Pointer to data address.
117 @param[out] DataSize Pointer to data size.
119 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
120 while VendorGuid is NULL.
121 @retval EFI_SUCCESS Variable successfully found.
122 @retval EFI_NOT_FOUND Variable not found
126 AuthServiceInternalFindVariable (
127 IN CHAR16
*VariableName
,
128 IN EFI_GUID
*VendorGuid
,
134 AUTH_VARIABLE_INFO AuthVariableInfo
;
136 ZeroMem (&AuthVariableInfo
, sizeof (AuthVariableInfo
));
137 Status
= mAuthVarLibContextIn
->FindVariable (
142 *Data
= AuthVariableInfo
.Data
;
143 *DataSize
= AuthVariableInfo
.DataSize
;
148 Update the variable region with Variable information.
150 @param[in] VariableName Name of variable.
151 @param[in] VendorGuid Guid of variable.
152 @param[in] Data Data pointer.
153 @param[in] DataSize Size of Data.
154 @param[in] Attributes Attribute value of the variable.
156 @retval EFI_SUCCESS The update operation is success.
157 @retval EFI_INVALID_PARAMETER Invalid parameter.
158 @retval EFI_WRITE_PROTECTED Variable is write-protected.
159 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
163 AuthServiceInternalUpdateVariable (
164 IN CHAR16
*VariableName
,
165 IN EFI_GUID
*VendorGuid
,
171 AUTH_VARIABLE_INFO AuthVariableInfo
;
173 ZeroMem (&AuthVariableInfo
, sizeof (AuthVariableInfo
));
174 AuthVariableInfo
.VariableName
= VariableName
;
175 AuthVariableInfo
.VendorGuid
= VendorGuid
;
176 AuthVariableInfo
.Data
= Data
;
177 AuthVariableInfo
.DataSize
= DataSize
;
178 AuthVariableInfo
.Attributes
= Attributes
;
180 return mAuthVarLibContextIn
->UpdateVariable (
186 Update the variable region with Variable information.
188 @param[in] VariableName Name of variable.
189 @param[in] VendorGuid Guid of variable.
190 @param[in] Data Data pointer.
191 @param[in] DataSize Size of Data.
192 @param[in] Attributes Attribute value of the variable.
193 @param[in] KeyIndex Index of associated public key.
194 @param[in] MonotonicCount Value of associated monotonic count.
196 @retval EFI_SUCCESS The update operation is success.
197 @retval EFI_INVALID_PARAMETER Invalid parameter.
198 @retval EFI_WRITE_PROTECTED Variable is write-protected.
199 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
203 AuthServiceInternalUpdateVariableWithMonotonicCount (
204 IN CHAR16
*VariableName
,
205 IN EFI_GUID
*VendorGuid
,
208 IN UINT32 Attributes
,
210 IN UINT64 MonotonicCount
213 AUTH_VARIABLE_INFO AuthVariableInfo
;
215 ZeroMem (&AuthVariableInfo
, sizeof (AuthVariableInfo
));
216 AuthVariableInfo
.VariableName
= VariableName
;
217 AuthVariableInfo
.VendorGuid
= VendorGuid
;
218 AuthVariableInfo
.Data
= Data
;
219 AuthVariableInfo
.DataSize
= DataSize
;
220 AuthVariableInfo
.Attributes
= Attributes
;
221 AuthVariableInfo
.PubKeyIndex
= KeyIndex
;
222 AuthVariableInfo
.MonotonicCount
= MonotonicCount
;
224 return mAuthVarLibContextIn
->UpdateVariable (
230 Update the variable region with Variable information.
232 @param[in] VariableName Name of variable.
233 @param[in] VendorGuid Guid of variable.
234 @param[in] Data Data pointer.
235 @param[in] DataSize Size of Data.
236 @param[in] Attributes Attribute value of the variable.
237 @param[in] TimeStamp Value of associated TimeStamp.
239 @retval EFI_SUCCESS The update operation is success.
240 @retval EFI_INVALID_PARAMETER Invalid parameter.
241 @retval EFI_WRITE_PROTECTED Variable is write-protected.
242 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
246 AuthServiceInternalUpdateVariableWithTimeStamp (
247 IN CHAR16
*VariableName
,
248 IN EFI_GUID
*VendorGuid
,
251 IN UINT32 Attributes
,
252 IN EFI_TIME
*TimeStamp
255 EFI_STATUS FindStatus
;
258 AUTH_VARIABLE_INFO AuthVariableInfo
;
260 FindStatus
= AuthServiceInternalFindVariable (
268 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
270 if (!EFI_ERROR (FindStatus
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) != 0)) {
271 if ((CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
272 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) || (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0) ||
273 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE2
) == 0))) ||
274 (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0))) {
276 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
277 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
279 FilterSignatureList (
288 ZeroMem (&AuthVariableInfo
, sizeof (AuthVariableInfo
));
289 AuthVariableInfo
.VariableName
= VariableName
;
290 AuthVariableInfo
.VendorGuid
= VendorGuid
;
291 AuthVariableInfo
.Data
= Data
;
292 AuthVariableInfo
.DataSize
= DataSize
;
293 AuthVariableInfo
.Attributes
= Attributes
;
294 AuthVariableInfo
.TimeStamp
= TimeStamp
;
295 return mAuthVarLibContextIn
->UpdateVariable (
301 Initialize Secure Boot variables.
303 @retval EFI_SUCCESS The initialization operation is successful.
304 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
308 InitSecureBootVariables (
316 UINT8 SecureBootEnable
;
317 SECURE_BOOT_MODE_TYPE SecureBootMode
;
321 // Find "PK" variable
323 Status
= AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME
, &gEfiGlobalVariableGuid
, (VOID
**) &Data
, &DataSize
);
324 if (EFI_ERROR (Status
)) {
326 DEBUG ((EFI_D_INFO
, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME
));
329 DEBUG ((EFI_D_INFO
, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME
));
333 // Init "SecureBootMode" variable.
335 // SecureBootMode doesn't exist. Init it with PK state
336 // 3 inconsistency cases need to sync
337 // 1.1 Add PK -> system break -> update SecureBootMode Var
338 // 1.2 Delete PK -> system break -> update SecureBootMode Var
339 // 1.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var
341 Status
= AuthServiceInternalFindVariable (EDKII_SECURE_BOOT_MODE_NAME
, &gEdkiiSecureBootModeGuid
, (VOID
**)&Data
, &DataSize
);
342 if (EFI_ERROR(Status
)) {
344 // Variable driver Initial Case
347 SecureBootMode
= SecureBootModeTypeUserMode
;
349 SecureBootMode
= SecureBootModeTypeSetupMode
;
353 // 3 inconsistency cases need to sync
355 SecureBootMode
= (SECURE_BOOT_MODE_TYPE
)*Data
;
356 ASSERT(SecureBootMode
< SecureBootModeTypeMax
);
360 // 3.1 Add PK -> system break -> update SecureBootMode Var
362 if (SecureBootMode
== SecureBootModeTypeSetupMode
) {
363 SecureBootMode
= SecureBootModeTypeUserMode
;
364 } else if (SecureBootMode
== SecureBootModeTypeAuditMode
) {
365 SecureBootMode
= SecureBootModeTypeDeployedMode
;
369 // 3.2 Delete PK -> system break -> update SecureBootMode Var
370 // 3.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var. Reinit to be SetupMode
372 if ((SecureBootMode
== SecureBootModeTypeUserMode
) || (SecureBootMode
== SecureBootModeTypeDeployedMode
)) {
373 SecureBootMode
= SecureBootModeTypeSetupMode
;
378 if (EFI_ERROR(Status
) || (SecureBootMode
!= (SECURE_BOOT_MODE_TYPE
)*Data
)) {
380 // Update SecureBootMode Var
382 Status
= AuthServiceInternalUpdateVariable (
383 EDKII_SECURE_BOOT_MODE_NAME
,
384 &gEdkiiSecureBootModeGuid
,
387 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
389 if (EFI_ERROR(Status
)) {
397 Status
= AuthServiceInternalUpdateVariable (
399 &gEfiGlobalVariableGuid
,
400 &mSecureBootState
[SecureBootMode
].AuditMode
,
402 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
404 if (EFI_ERROR(Status
)) {
409 // Init "DeployedMode"
411 Status
= AuthServiceInternalUpdateVariable (
412 EFI_DEPLOYED_MODE_NAME
,
413 &gEfiGlobalVariableGuid
,
414 &mSecureBootState
[SecureBootMode
].DeployedMode
,
416 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
418 if (EFI_ERROR(Status
)) {
425 Status
= AuthServiceInternalUpdateVariable (
427 &gEfiGlobalVariableGuid
,
428 &mSecureBootState
[SecureBootMode
].SetupMode
,
430 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
432 if (EFI_ERROR(Status
)) {
437 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
438 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
439 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
441 SecureBootEnable
= SECURE_BOOT_DISABLE
;
442 Status
= AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME
, &gEfiSecureBootEnableDisableGuid
, (VOID
**)&Data
, &DataSize
);
443 if (!EFI_ERROR(Status
)) {
445 SecureBootEnable
= *Data
;
447 } else if ((SecureBootMode
== SecureBootModeTypeUserMode
) || (SecureBootMode
== SecureBootModeTypeDeployedMode
)) {
449 // "SecureBootEnable" not exist, initialize it in User Mode or Deployed Mode.
451 SecureBootEnable
= SECURE_BOOT_ENABLE
;
452 Status
= AuthServiceInternalUpdateVariable (
453 EFI_SECURE_BOOT_ENABLE_NAME
,
454 &gEfiSecureBootEnableDisableGuid
,
457 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
459 if (EFI_ERROR (Status
)) {
465 // Create "SecureBoot" variable with BS+RT attribute set.
467 if ((SecureBootEnable
== SECURE_BOOT_ENABLE
)
468 && ((SecureBootMode
== SecureBootModeTypeUserMode
) || (SecureBootMode
== SecureBootModeTypeDeployedMode
))) {
469 SecureBoot
= SECURE_BOOT_MODE_ENABLE
;
471 SecureBoot
= SECURE_BOOT_MODE_DISABLE
;
473 Status
= AuthServiceInternalUpdateVariable (
474 EFI_SECURE_BOOT_MODE_NAME
,
475 &gEfiGlobalVariableGuid
,
478 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
481 DEBUG ((EFI_D_INFO
, "SecureBootMode is %x\n", SecureBootMode
));
482 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME
, SecureBoot
));
483 DEBUG ((EFI_D_INFO
, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME
, SecureBootEnable
));
486 // Save SecureBootMode in global space
488 mSecureBootMode
= SecureBootMode
;
494 Update SecureBootMode variable.
496 @param[in] NewMode New Secure Boot Mode.
498 @retval EFI_SUCCESS The initialization operation is successful.
499 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
503 UpdateSecureBootMode(
504 IN SECURE_BOOT_MODE_TYPE NewMode
510 // Update "SecureBootMode" variable to new Secure Boot Mode
512 Status
= AuthServiceInternalUpdateVariable (
513 EDKII_SECURE_BOOT_MODE_NAME
,
514 &gEdkiiSecureBootModeGuid
,
517 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
520 if (!EFI_ERROR(Status
)) {
521 DEBUG((EFI_D_INFO
, "SecureBootMode Update to %x\n", NewMode
));
522 mSecureBootMode
= NewMode
;
524 DEBUG((EFI_D_ERROR
, "SecureBootMode Update failure %x\n", Status
));
531 Current secure boot mode is AuditMode. This function performs secure boot mode transition
534 @param[in] NewMode New Secure Boot Mode.
536 @retval EFI_SUCCESS The initialization operation is successful.
537 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
541 TransitionFromAuditMode(
542 IN SECURE_BOOT_MODE_TYPE NewMode
547 VOID
*DeployedVarData
;
549 VOID
*SecureBootVarData
;
550 UINT8 SecureBootEnable
;
554 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
555 // they can be RW. but can't be deleted. so they can always be found.
557 Status
= AuthServiceInternalFindVariable (
559 &gEfiGlobalVariableGuid
,
563 if (EFI_ERROR (Status
)) {
567 Status
= AuthServiceInternalFindVariable (
568 EFI_DEPLOYED_MODE_NAME
,
569 &gEfiGlobalVariableGuid
,
573 if (EFI_ERROR (Status
)) {
577 Status
= AuthServiceInternalFindVariable (
579 &gEfiGlobalVariableGuid
,
583 if (EFI_ERROR (Status
)) {
587 Status
= AuthServiceInternalFindVariable (
588 EFI_SECURE_BOOT_MODE_NAME
,
589 &gEfiGlobalVariableGuid
,
593 if (EFI_ERROR (Status
)) {
598 // Make Secure Boot Mode transition ATOMIC
599 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
600 // other tranisition logic are all memory operations.
602 Status
= UpdateSecureBootMode(NewMode
);
603 if (EFI_ERROR(Status
)) {
604 DEBUG((EFI_D_ERROR
, "Update SecureBootMode Variable fail %x\n", Status
));
607 if (NewMode
== SecureBootModeTypeDeployedMode
) {
609 // Since PK is enrolled, can't rollback, always update SecureBootMode in memory
611 mSecureBootMode
= NewMode
;
612 Status
= EFI_SUCCESS
;
615 // AuditMode ----> DeployedMode
617 // AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0
619 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
620 // variable storage reclaim at runtime.
622 CopyMem (AuditVarData
, &mSecureBootState
[NewMode
].AuditMode
, sizeof(UINT8
));
624 // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible
625 // variable storage reclaim at runtime.
627 CopyMem (DeployedVarData
, &mSecureBootState
[NewMode
].DeployedMode
, sizeof(UINT8
));
629 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
630 // variable storage reclaim at runtime.
632 CopyMem (SetupVarData
, &mSecureBootState
[NewMode
].SetupMode
, sizeof(UINT8
));
634 if (mAuthVarLibContextIn
->AtRuntime ()) {
636 // SecureBoot Variable indicates whether the platform firmware is operating
637 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
638 // Variable in runtime.
644 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
645 // variable storage reclaim at runtime.
647 CopyMem (SecureBootVarData
, &mSecureBootState
[NewMode
].SecureBoot
, sizeof(UINT8
));
650 // Create "SecureBootEnable" variable as secure boot is enabled.
652 SecureBootEnable
= SECURE_BOOT_ENABLE
;
653 AuthServiceInternalUpdateVariable (
654 EFI_SECURE_BOOT_ENABLE_NAME
,
655 &gEfiSecureBootEnableDisableGuid
,
657 sizeof (SecureBootEnable
),
658 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
661 DEBUG((EFI_D_ERROR
, "Invalid state tranition from %x to %x\n", SecureBootModeTypeAuditMode
, NewMode
));
669 Current secure boot mode is DeployedMode. This function performs secure boot mode transition
672 @param[in] NewMode New Secure Boot Mode.
674 @retval EFI_SUCCESS The initialization operation is successful.
675 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
679 TransitionFromDeployedMode(
680 IN SECURE_BOOT_MODE_TYPE NewMode
684 VOID
*DeployedVarData
;
686 VOID
*SecureBootVarData
;
687 UINT8 SecureBootEnable
;
691 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
692 // they can be RW. but can't be deleted. so they can always be found.
694 Status
= AuthServiceInternalFindVariable (
695 EFI_DEPLOYED_MODE_NAME
,
696 &gEfiGlobalVariableGuid
,
700 if (EFI_ERROR (Status
)) {
704 Status
= AuthServiceInternalFindVariable (
706 &gEfiGlobalVariableGuid
,
710 if (EFI_ERROR (Status
)) {
714 Status
= AuthServiceInternalFindVariable (
715 EFI_SECURE_BOOT_MODE_NAME
,
716 &gEfiGlobalVariableGuid
,
720 if (EFI_ERROR (Status
)) {
725 // Make Secure Boot Mode transition ATOMIC
726 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
727 // other tranisition logic are all memory operations.
729 Status
= UpdateSecureBootMode(NewMode
);
730 if (EFI_ERROR(Status
)) {
731 DEBUG((EFI_D_ERROR
, "Update SecureBootMode Variable fail %x\n", Status
));
735 case SecureBootModeTypeUserMode
:
737 // DeployedMode ----> UserMode
741 // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
743 if (EFI_ERROR(Status
)) {
746 CopyMem (DeployedVarData
, &mSecureBootState
[NewMode
].DeployedMode
, sizeof(UINT8
));
750 case SecureBootModeTypeSetupMode
:
752 // Since PK is processed before, can't rollback, still update SecureBootMode in memory
754 mSecureBootMode
= NewMode
;
755 Status
= EFI_SUCCESS
;
758 // DeployedMode ----> SetupMode
760 // Platform Specific PKpub clear or Delete Pkpub
762 // DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0
764 // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible
765 // variable storage reclaim at runtime.
767 CopyMem (DeployedVarData
, &mSecureBootState
[NewMode
].DeployedMode
, sizeof(UINT8
));
769 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
770 // variable storage reclaim at runtime.
772 CopyMem (SetupVarData
, &mSecureBootState
[NewMode
].SetupMode
, sizeof(UINT8
));
774 if (mAuthVarLibContextIn
->AtRuntime ()) {
776 // SecureBoot Variable indicates whether the platform firmware is operating
777 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
778 // Variable in runtime.
784 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
785 // variable storage reclaim at runtime.
787 CopyMem (SecureBootVarData
, &mSecureBootState
[NewMode
].SecureBoot
, sizeof(UINT8
));
790 // Delete the "SecureBootEnable" variable as secure boot is Disabled.
792 SecureBootEnable
= SECURE_BOOT_DISABLE
;
793 AuthServiceInternalUpdateVariable (
794 EFI_SECURE_BOOT_ENABLE_NAME
,
795 &gEfiSecureBootEnableDisableGuid
,
798 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
803 DEBUG((EFI_D_ERROR
, "Invalid state tranition from %x to %x\n", SecureBootModeTypeDeployedMode
, NewMode
));
811 Current secure boot mode is UserMode. This function performs secure boot mode transition
814 @param[in] NewMode New Secure Boot Mode.
816 @retval EFI_SUCCESS The initialization operation is successful.
817 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
821 TransitionFromUserMode(
822 IN SECURE_BOOT_MODE_TYPE NewMode
827 VOID
*DeployedVarData
;
830 VOID
*SecureBootVarData
;
831 UINT8 SecureBootEnable
;
833 VARIABLE_ENTRY_CONSISTENCY VariableEntry
;
836 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
837 // they can be RW. but can't be deleted. so they can always be found.
839 Status
= AuthServiceInternalFindVariable (
841 &gEfiGlobalVariableGuid
,
845 if (EFI_ERROR (Status
)) {
849 Status
= AuthServiceInternalFindVariable (
850 EFI_DEPLOYED_MODE_NAME
,
851 &gEfiGlobalVariableGuid
,
855 if (EFI_ERROR (Status
)) {
859 Status
= AuthServiceInternalFindVariable (
861 &gEfiGlobalVariableGuid
,
865 if (EFI_ERROR (Status
)) {
869 Status
= AuthServiceInternalFindVariable (
870 EFI_SECURE_BOOT_MODE_NAME
,
871 &gEfiGlobalVariableGuid
,
875 if (EFI_ERROR (Status
)) {
880 // Make Secure Boot Mode transition ATOMIC
881 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
882 // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.
884 if (NewMode
!= SecureBootModeTypeAuditMode
) {
885 Status
= UpdateSecureBootMode(NewMode
);
886 if (EFI_ERROR(Status
)) {
887 DEBUG((EFI_D_ERROR
, "Update SecureBootMode Variable fail %x\n", Status
));
891 // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var first.
892 // Will update SecureBootMode after DeletePK logic
894 VariableEntry
.VariableSize
= sizeof(UINT8
);
895 VariableEntry
.Guid
= &gEdkiiSecureBootModeGuid
;
896 VariableEntry
.Name
= EDKII_SECURE_BOOT_MODE_NAME
;
897 if (!mAuthVarLibContextIn
->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
, NULL
)) {
898 return EFI_OUT_OF_RESOURCES
;
903 case SecureBootModeTypeDeployedMode
:
905 // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
907 if (EFI_ERROR(Status
)) {
912 // UserMode ----> DeployedMode
916 CopyMem (DeployedVarData
, &mSecureBootState
[NewMode
].DeployedMode
, sizeof(UINT8
));
919 case SecureBootModeTypeAuditMode
:
921 // UserMode ----> AuditMode
923 // Delete PKpub / SetupMode := 1 / SecureBoot := 0
925 // Delete PKpub without verification. Should always succeed.
928 Status
= AuthServiceInternalUpdateVariable (
929 EFI_PLATFORM_KEY_NAME
,
930 &gEfiGlobalVariableGuid
,
933 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
935 if (EFI_ERROR(Status
)) {
936 DEBUG((EFI_D_ERROR
, "UserMode -> AuditMode. Delete PK fail %x\n", Status
));
941 // Update Private NV SecureBootMode Variable
943 Status
= UpdateSecureBootMode(NewMode
);
944 if (EFI_ERROR(Status
)) {
946 // Since PK is deleted successfully, Doesn't break, continue to update other variable.
948 DEBUG((EFI_D_ERROR
, "Update SecureBootMode Variable fail %x\n", Status
));
950 CopyMem (AuditVarData
, &mSecureBootState
[NewMode
].AuditMode
, sizeof(UINT8
));
953 // Fall into SetupMode logic
955 case SecureBootModeTypeSetupMode
:
957 // Since PK is deleted before , can't rollback, still update SecureBootMode in memory
959 mSecureBootMode
= NewMode
;
960 Status
= EFI_SUCCESS
;
963 // UserMode ----> SetupMode
965 // DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0
967 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
968 // variable storage reclaim at runtime.
970 CopyMem (SetupVarData
, &mSecureBootState
[NewMode
].SetupMode
, sizeof(UINT8
));
972 if (mAuthVarLibContextIn
->AtRuntime ()) {
974 // SecureBoot Variable indicates whether the platform firmware is operating
975 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
976 // Variable in runtime.
982 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
983 // variable storage reclaim at runtime.
985 CopyMem (SecureBootVarData
, &mSecureBootState
[NewMode
].SecureBoot
, sizeof(UINT8
));
988 // Delete the "SecureBootEnable" variable as secure boot is Disabled.
990 SecureBootEnable
= SECURE_BOOT_DISABLE
;
991 AuthServiceInternalUpdateVariable (
992 EFI_SECURE_BOOT_ENABLE_NAME
,
993 &gEfiSecureBootEnableDisableGuid
,
996 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1002 DEBUG((EFI_D_ERROR
, "Invalid state tranition from %x to %x\n", SecureBootModeTypeUserMode
, NewMode
));
1010 Current secure boot mode is SetupMode. This function performs secure boot mode transition
1013 @param[in] NewMode New Secure Boot Mode.
1015 @retval EFI_SUCCESS The initialization operation is successful.
1016 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
1020 TransitionFromSetupMode(
1021 IN SECURE_BOOT_MODE_TYPE NewMode
1027 VOID
*SecureBootVarData
;
1028 UINT8 SecureBootEnable
;
1032 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
1033 // they can be RW. but can't be deleted. so they can always be found.
1035 Status
= AuthServiceInternalFindVariable (
1036 EFI_AUDIT_MODE_NAME
,
1037 &gEfiGlobalVariableGuid
,
1041 if (EFI_ERROR (Status
)) {
1045 Status
= AuthServiceInternalFindVariable (
1046 EFI_SETUP_MODE_NAME
,
1047 &gEfiGlobalVariableGuid
,
1051 if (EFI_ERROR (Status
)) {
1055 Status
= AuthServiceInternalFindVariable (
1056 EFI_SECURE_BOOT_MODE_NAME
,
1057 &gEfiGlobalVariableGuid
,
1061 if (EFI_ERROR (Status
)) {
1066 // Make Secure Boot Mode transition ATOMIC
1067 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
1068 // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.
1070 Status
= UpdateSecureBootMode(NewMode
);
1071 if (EFI_ERROR(Status
)) {
1072 DEBUG((EFI_D_ERROR
, "Update SecureBootMode Variable fail %x\n", Status
));
1076 case SecureBootModeTypeAuditMode
:
1078 // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
1080 if (EFI_ERROR(Status
)) {
1085 // SetupMode ----> AuditMode
1089 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
1090 // variable storage reclaim at runtime.
1092 CopyMem (AuditVarData
, &mSecureBootState
[NewMode
].AuditMode
, sizeof(UINT8
));
1095 case SecureBootModeTypeUserMode
:
1097 // Since PK is enrolled before, can't rollback, still update SecureBootMode in memory
1099 mSecureBootMode
= NewMode
;
1100 Status
= EFI_SUCCESS
;
1103 // SetupMode ----> UserMode
1105 // SetupMode := 0 / SecureBoot := 1
1107 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
1108 // variable storage reclaim at runtime.
1110 CopyMem (SetupVarData
, &mSecureBootState
[NewMode
].SetupMode
, sizeof(UINT8
));
1112 if (mAuthVarLibContextIn
->AtRuntime ()) {
1114 // SecureBoot Variable indicates whether the platform firmware is operating
1115 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
1116 // Variable in runtime.
1122 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
1123 // variable storage reclaim at runtime.
1125 CopyMem (SecureBootVarData
, &mSecureBootState
[NewMode
].SecureBoot
, sizeof(UINT8
));
1128 // Create the "SecureBootEnable" variable as secure boot is enabled.
1130 SecureBootEnable
= SECURE_BOOT_ENABLE
;
1131 AuthServiceInternalUpdateVariable (
1132 EFI_SECURE_BOOT_ENABLE_NAME
,
1133 &gEfiSecureBootEnableDisableGuid
,
1135 sizeof (SecureBootEnable
),
1136 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1141 DEBUG((EFI_D_ERROR
, "Invalid state tranition from %x to %x\n", SecureBootModeTypeSetupMode
, NewMode
));
1149 This function performs main secure boot mode transition logic.
1151 @param[in] CurMode Current Secure Boot Mode.
1152 @param[in] NewMode New Secure Boot Mode.
1154 @retval EFI_SUCCESS The initialization operation is successful.
1155 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
1156 @retval EFI_INVALID_PARAMETER The Current Secure Boot Mode is wrong.
1160 SecureBootModeTransition(
1161 IN SECURE_BOOT_MODE_TYPE CurMode
,
1162 IN SECURE_BOOT_MODE_TYPE NewMode
1168 // SecureBootMode transition
1171 case SecureBootModeTypeUserMode
:
1172 Status
= TransitionFromUserMode(NewMode
);
1175 case SecureBootModeTypeSetupMode
:
1176 Status
= TransitionFromSetupMode(NewMode
);
1179 case SecureBootModeTypeAuditMode
:
1180 Status
= TransitionFromAuditMode(NewMode
);
1183 case SecureBootModeTypeDeployedMode
:
1184 Status
= TransitionFromDeployedMode(NewMode
);
1188 Status
= EFI_INVALID_PARAMETER
;
1197 Determine whether this operation needs a physical present user.
1199 @param[in] VariableName Name of the Variable.
1200 @param[in] VendorGuid GUID of the Variable.
1202 @retval TRUE This variable is protected, only a physical present user could set this variable.
1203 @retval FALSE This variable is not protected.
1207 NeedPhysicallyPresent(
1208 IN CHAR16
*VariableName
,
1209 IN EFI_GUID
*VendorGuid
1212 if ((CompareGuid (VendorGuid
, &gEfiSecureBootEnableDisableGuid
) && (StrCmp (VariableName
, EFI_SECURE_BOOT_ENABLE_NAME
) == 0))
1213 || (CompareGuid (VendorGuid
, &gEfiCustomModeEnableGuid
) && (StrCmp (VariableName
, EFI_CUSTOM_MODE_NAME
) == 0))) {
1221 Determine whether the platform is operating in Custom Secure Boot mode.
1223 @retval TRUE The platform is operating in Custom mode.
1224 @retval FALSE The platform is operating in Standard mode.
1236 Status
= AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME
, &gEfiCustomModeEnableGuid
, &Data
, &DataSize
);
1237 if (!EFI_ERROR (Status
) && (*(UINT8
*) Data
== CUSTOM_SECURE_BOOT_MODE
)) {
1245 Get available public key index.
1247 @param[in] PubKey Pointer to Public Key data.
1249 @return Public key index, 0 if no any public key index available.
1253 GetAvailableKeyIndex (
1263 EFI_GUID VendorGuid
;
1265 AUTH_VARIABLE_INFO AuthVariableInfo
;
1268 Status
= AuthServiceInternalFindVariable (
1270 &gEfiAuthenticatedVariableGuid
,
1274 if (EFI_ERROR (Status
)) {
1275 DEBUG ((EFI_D_ERROR
, "Get public key database variable failure, Status = %r\n", Status
));
1279 if (mPubKeyNumber
== mMaxKeyNumber
) {
1281 AuthVariableInfo
.VariableName
= Name
;
1282 ZeroMem (&VendorGuid
, sizeof (VendorGuid
));
1283 AuthVariableInfo
.VendorGuid
= &VendorGuid
;
1286 // Collect valid key data.
1289 Status
= mAuthVarLibContextIn
->FindNextVariable (AuthVariableInfo
.VariableName
, AuthVariableInfo
.VendorGuid
, &AuthVariableInfo
);
1290 if (!EFI_ERROR (Status
)) {
1291 if (AuthVariableInfo
.PubKeyIndex
!= 0) {
1292 for (Ptr
= Data
; Ptr
< (Data
+ DataSize
); Ptr
+= sizeof (AUTHVAR_KEY_DB_DATA
)) {
1293 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA
*) Ptr
)->KeyIndex
)) == AuthVariableInfo
.PubKeyIndex
) {
1295 // Check if the key data has been collected.
1297 for (Index
= 0; Index
< mPubKeyNumber
; Index
++) {
1298 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ Index
)->KeyIndex
)) == AuthVariableInfo
.PubKeyIndex
) {
1302 if (Index
== mPubKeyNumber
) {
1306 CopyMem ((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ mPubKeyNumber
, Ptr
, sizeof (AUTHVAR_KEY_DB_DATA
));
1314 } while (Status
!= EFI_NOT_FOUND
);
1317 // No available space to add new public key.
1319 if (mPubKeyNumber
== mMaxKeyNumber
) {
1325 // Find available public key index.
1327 for (KeyIndex
= 1; KeyIndex
<= mMaxKeyNumber
; KeyIndex
++) {
1329 for (Ptr
= mPubKeyStore
; Ptr
< (mPubKeyStore
+ mPubKeyNumber
* sizeof (AUTHVAR_KEY_DB_DATA
)); Ptr
+= sizeof (AUTHVAR_KEY_DB_DATA
)) {
1330 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA
*) Ptr
)->KeyIndex
)) == KeyIndex
) {
1344 Add public key in store and return its index.
1346 @param[in] PubKey Input pointer to Public Key data.
1347 @param[in] VariableDataEntry The variable data entry.
1349 @return Index of new added public key.
1355 IN VARIABLE_ENTRY_CONSISTENCY
*VariableDataEntry
1360 VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry
;
1364 if (PubKey
== NULL
) {
1369 // Check whether the public key entry does exist.
1371 for (Index
= 0; Index
< mPubKeyNumber
; Index
++) {
1372 if (CompareMem (((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ Index
)->KeyData
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
1373 return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ Index
)->KeyIndex
));
1377 KeyIndex
= GetAvailableKeyIndex (PubKey
);
1378 if (KeyIndex
== 0) {
1383 // Check the variable space for both public key and variable data.
1385 PublicKeyEntry
.VariableSize
= (mPubKeyNumber
+ 1) * sizeof (AUTHVAR_KEY_DB_DATA
);
1386 PublicKeyEntry
.Guid
= &gEfiAuthenticatedVariableGuid
;
1387 PublicKeyEntry
.Name
= AUTHVAR_KEYDB_NAME
;
1388 Attributes
= VARIABLE_ATTRIBUTE_NV_BS_RT
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
1390 if (!mAuthVarLibContextIn
->CheckRemainingSpaceForConsistency (Attributes
, &PublicKeyEntry
, VariableDataEntry
, NULL
)) {
1392 // No enough variable space.
1397 WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ mPubKeyNumber
)->KeyIndex
), KeyIndex
);
1398 CopyMem (((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ mPubKeyNumber
)->KeyData
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
1402 // Update public key database variable.
1404 Status
= AuthServiceInternalUpdateVariable (
1406 &gEfiAuthenticatedVariableGuid
,
1408 mPubKeyNumber
* sizeof (AUTHVAR_KEY_DB_DATA
),
1411 if (EFI_ERROR (Status
)) {
1412 DEBUG ((EFI_D_ERROR
, "Update public key database variable failure, Status = %r\n", Status
));
1420 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
1421 Follow the steps in UEFI2.2.
1423 Caution: This function may receive untrusted input.
1424 This function may be invoked in SMM mode, and datasize and data are external input.
1425 This function will do basic validation, before parse the data.
1426 This function will parse the authentication carefully to avoid security issues, like
1427 buffer overflow, integer overflow.
1429 @param[in] Data Pointer to data with AuthInfo.
1430 @param[in] DataSize Size of Data.
1431 @param[in] PubKey Public key used for verification.
1433 @retval EFI_INVALID_PARAMETER Invalid parameter.
1434 @retval EFI_SECURITY_VIOLATION If authentication failed.
1435 @retval EFI_SUCCESS Authentication successful.
1439 VerifyCounterBasedPayload (
1446 EFI_VARIABLE_AUTHENTICATION
*CertData
;
1447 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
1448 UINT8 Digest
[SHA256_DIGEST_SIZE
];
1452 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
1457 if (Data
== NULL
|| PubKey
== NULL
) {
1458 return EFI_INVALID_PARAMETER
;
1461 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
1462 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
1465 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1466 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
1468 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
1469 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertTypeRsa2048Sha256Guid
)) {
1471 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1473 return EFI_SECURITY_VIOLATION
;
1476 // Hash data payload with SHA256.
1478 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
1479 Status
= Sha256Init (mHashCtx
);
1483 Status
= Sha256Update (mHashCtx
, Data
+ AUTHINFO_SIZE
, PayloadSize
);
1490 Status
= Sha256Update (mHashCtx
, &PayloadSize
, sizeof (UINTN
));
1495 // Hash Monotonic Count.
1497 Status
= Sha256Update (mHashCtx
, &CertData
->MonotonicCount
, sizeof (UINT64
));
1501 Status
= Sha256Final (mHashCtx
, Digest
);
1506 // Generate & Initialize RSA Context.
1509 ASSERT (Rsa
!= NULL
);
1511 // Set RSA Key Components.
1512 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
1514 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
1518 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
1523 // Verify the signature.
1525 Status
= RsaPkcs1Verify (
1529 CertBlock
->Signature
,
1530 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
1540 return EFI_SECURITY_VIOLATION
;
1546 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
1548 @param[in] VariableName Name of Variable to be check.
1549 @param[in] VendorGuid Variable vendor GUID.
1550 @param[in] Data Point to the variable data to be checked.
1551 @param[in] DataSize Size of Data.
1553 @return EFI_INVALID_PARAMETER Invalid signature list format.
1554 @return EFI_SUCCESS Passed signature list format check successfully.
1558 CheckSignatureListFormat(
1559 IN CHAR16
*VariableName
,
1560 IN EFI_GUID
*VendorGuid
,
1565 EFI_SIGNATURE_LIST
*SigList
;
1571 EFI_SIGNATURE_DATA
*CertData
;
1574 if (DataSize
== 0) {
1578 ASSERT (VariableName
!= NULL
&& VendorGuid
!= NULL
&& Data
!= NULL
);
1580 if (CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_PLATFORM_KEY_NAME
) == 0)){
1582 } else if ((CompareGuid (VendorGuid
, &gEfiGlobalVariableGuid
) && (StrCmp (VariableName
, EFI_KEY_EXCHANGE_KEY_NAME
) == 0)) ||
1583 (CompareGuid (VendorGuid
, &gEfiImageSecurityDatabaseGuid
) &&
1584 ((StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE
) == 0) || (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE1
) == 0) ||
1585 (StrCmp (VariableName
, EFI_IMAGE_SECURITY_DATABASE2
) == 0)))) {
1592 SigList
= (EFI_SIGNATURE_LIST
*) Data
;
1593 SigDataSize
= DataSize
;
1597 // Walk throuth the input signature list and check the data format.
1598 // If any signature is incorrectly formed, the whole check will fail.
1600 while ((SigDataSize
> 0) && (SigDataSize
>= SigList
->SignatureListSize
)) {
1601 for (Index
= 0; Index
< (sizeof (mSupportSigItem
) / sizeof (EFI_SIGNATURE_ITEM
)); Index
++ ) {
1602 if (CompareGuid (&SigList
->SignatureType
, &mSupportSigItem
[Index
].SigType
)) {
1604 // The value of SignatureSize should always be 16 (size of SignatureOwner
1605 // component) add the data length according to signature type.
1607 if (mSupportSigItem
[Index
].SigDataSize
!= ((UINT32
) ~0) &&
1608 (SigList
->SignatureSize
- sizeof (EFI_GUID
)) != mSupportSigItem
[Index
].SigDataSize
) {
1609 return EFI_INVALID_PARAMETER
;
1611 if (mSupportSigItem
[Index
].SigHeaderSize
!= ((UINT32
) ~0) &&
1612 SigList
->SignatureHeaderSize
!= mSupportSigItem
[Index
].SigHeaderSize
) {
1613 return EFI_INVALID_PARAMETER
;
1619 if (Index
== (sizeof (mSupportSigItem
) / sizeof (EFI_SIGNATURE_ITEM
))) {
1621 // Undefined signature type.
1623 return EFI_INVALID_PARAMETER
;
1626 if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
1628 // Try to retrieve the RSA public key from the X.509 certificate.
1629 // If this operation fails, it's not a valid certificate.
1631 RsaContext
= RsaNew ();
1632 if (RsaContext
== NULL
) {
1633 return EFI_INVALID_PARAMETER
;
1635 CertData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) + SigList
->SignatureHeaderSize
);
1636 CertLen
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
1637 if (!RsaGetPublicKeyFromX509 (CertData
->SignatureData
, CertLen
, &RsaContext
)) {
1638 RsaFree (RsaContext
);
1639 return EFI_INVALID_PARAMETER
;
1641 RsaFree (RsaContext
);
1644 if ((SigList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - SigList
->SignatureHeaderSize
) % SigList
->SignatureSize
!= 0) {
1645 return EFI_INVALID_PARAMETER
;
1647 SigCount
+= (SigList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - SigList
->SignatureHeaderSize
) / SigList
->SignatureSize
;
1649 SigDataSize
-= SigList
->SignatureListSize
;
1650 SigList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) SigList
+ SigList
->SignatureListSize
);
1653 if (((UINTN
) SigList
- (UINTN
) Data
) != DataSize
) {
1654 return EFI_INVALID_PARAMETER
;
1657 if (IsPk
&& SigCount
> 1) {
1658 return EFI_INVALID_PARAMETER
;
1665 Update "VendorKeys" variable to record the out of band secure boot key modification.
1667 @return EFI_SUCCESS Variable is updated successfully.
1668 @return Others Failed to update variable.
1672 VendorKeyIsModified (
1678 if (mVendorKeyState
== VENDOR_KEYS_MODIFIED
) {
1681 mVendorKeyState
= VENDOR_KEYS_MODIFIED
;
1683 Status
= AuthServiceInternalUpdateVariable (
1684 EFI_VENDOR_KEYS_NV_VARIABLE_NAME
,
1685 &gEfiVendorKeysNvGuid
,
1688 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
1690 if (EFI_ERROR (Status
)) {
1694 return AuthServiceInternalUpdateVariable (
1695 EFI_VENDOR_KEYS_VARIABLE_NAME
,
1696 &gEfiGlobalVariableGuid
,
1699 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
1704 Process Secure Boot Mode variable.
1706 Caution: This function may receive untrusted input.
1707 This function may be invoked in SMM mode, and datasize and data are external input.
1708 This function will do basic validation, before parse the data.
1709 This function will parse the authentication carefully to avoid security issues, like
1710 buffer overflow, integer overflow.
1711 This function will check attribute carefully to avoid authentication bypass.
1713 @param[in] VariableName Name of Variable to be found.
1714 @param[in] VendorGuid Variable vendor GUID.
1715 @param[in] Data Data pointer.
1716 @param[in] DataSize Size of Data found. If size is less than the
1717 data, this value contains the required size.
1718 @param[in] Attributes Attribute value of the variable
1720 @return EFI_INVALID_PARAMETER Invalid parameter
1721 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1722 check carried out by the firmware.
1723 @return EFI_WRITE_PROTECTED Variable is Read-Only.
1724 @return EFI_SUCCESS Variable passed validation successfully.
1728 ProcessSecureBootModeVar (
1729 IN CHAR16
*VariableName
,
1730 IN EFI_GUID
*VendorGuid
,
1733 IN UINT32 Attributes OPTIONAL
1741 // Check "AuditMode", "DeployedMode" Variable ReadWrite Attributes
1742 // if in Runtime, Always RO
1743 // if in Boottime, Depends on current Secure Boot Mode
1745 if (mAuthVarLibContextIn
->AtRuntime()) {
1746 return EFI_WRITE_PROTECTED
;
1752 if ((DataSize
!= sizeof(UINT8
)) || (Attributes
== 0)) {
1753 return EFI_INVALID_PARAMETER
;
1756 if (StrCmp (VariableName
, EFI_AUDIT_MODE_NAME
) == 0) {
1757 if(mSecureBootState
[mSecureBootMode
].IsAuditModeRO
) {
1758 return EFI_WRITE_PROTECTED
;
1762 // Platform specific deployedMode clear. Set DeployedMode = RW
1764 if (!InCustomMode() || !UserPhysicalPresent() || mSecureBootMode
!= SecureBootModeTypeDeployedMode
) {
1765 if(mSecureBootState
[mSecureBootMode
].IsDeployedModeRO
) {
1766 return EFI_WRITE_PROTECTED
;
1771 if (*(UINT8
*)Data
!= 0 && *(UINT8
*)Data
!= 1) {
1772 return EFI_INVALID_PARAMETER
;
1776 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
1777 // they can be RW. but can't be deleted. so they can always be found.
1779 Status
= AuthServiceInternalFindVariable (
1785 if (EFI_ERROR(Status
)) {
1790 // If AuditMode/DeployedMode is assigned same value. Simply return EFI_SUCCESS
1792 if (*(UINT8
*)VarData
== *(UINT8
*)Data
) {
1797 // Perform SecureBootMode transition
1799 if (StrCmp (VariableName
, EFI_AUDIT_MODE_NAME
) == 0) {
1800 DEBUG((EFI_D_INFO
, "Current SecureBootMode %x Transfer to SecureBootMode %x\n", mSecureBootMode
, SecureBootModeTypeAuditMode
));
1801 return SecureBootModeTransition(mSecureBootMode
, SecureBootModeTypeAuditMode
);
1802 } else if (StrCmp (VariableName
, EFI_DEPLOYED_MODE_NAME
) == 0) {
1803 if (mSecureBootMode
== SecureBootModeTypeDeployedMode
) {
1805 // Platform specific DeployedMode clear. InCustomMode() && UserPhysicalPresent() is checked before
1807 DEBUG((EFI_D_INFO
, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode
, SecureBootModeTypeUserMode
));
1808 return SecureBootModeTransition(mSecureBootMode
, SecureBootModeTypeUserMode
);
1810 DEBUG((EFI_D_INFO
, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode
, SecureBootModeTypeDeployedMode
));
1811 return SecureBootModeTransition(mSecureBootMode
, SecureBootModeTypeDeployedMode
);
1815 return EFI_INVALID_PARAMETER
;
1819 Process variable with platform key for verification.
1821 Caution: This function may receive untrusted input.
1822 This function may be invoked in SMM mode, and datasize and data are external input.
1823 This function will do basic validation, before parse the data.
1824 This function will parse the authentication carefully to avoid security issues, like
1825 buffer overflow, integer overflow.
1826 This function will check attribute carefully to avoid authentication bypass.
1828 @param[in] VariableName Name of Variable to be found.
1829 @param[in] VendorGuid Variable vendor GUID.
1830 @param[in] Data Data pointer.
1831 @param[in] DataSize Size of Data found. If size is less than the
1832 data, this value contains the required size.
1833 @param[in] Attributes Attribute value of the variable
1834 @param[in] IsPk Indicate whether it is to process pk.
1836 @return EFI_INVALID_PARAMETER Invalid parameter.
1837 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
1838 check carried out by the firmware.
1839 @return EFI_SUCCESS Variable passed validation successfully.
1844 IN CHAR16
*VariableName
,
1845 IN EFI_GUID
*VendorGuid
,
1848 IN UINT32 Attributes OPTIONAL
,
1856 VARIABLE_ENTRY_CONSISTENCY VariableEntry
[2];
1858 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0 ||
1859 (Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == 0) {
1861 // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
1862 // authenticated variable.
1864 return EFI_INVALID_PARAMETER
;
1868 // Init state of Del. State may change due to secure check
1871 Payload
= (UINT8
*) Data
+ AUTHINFO2_SIZE (Data
);
1872 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
1873 if (PayloadSize
== 0) {
1878 // Check the variable space for both PKpub and SecureBootMode variable.
1880 VariableEntry
[0].VariableSize
= PayloadSize
;
1881 VariableEntry
[0].Guid
= &gEfiGlobalVariableGuid
;
1882 VariableEntry
[0].Name
= EFI_PLATFORM_KEY_NAME
;
1884 VariableEntry
[1].VariableSize
= sizeof(UINT8
);
1885 VariableEntry
[1].Guid
= &gEdkiiSecureBootModeGuid
;
1886 VariableEntry
[1].Name
= EDKII_SECURE_BOOT_MODE_NAME
;
1888 if ((InCustomMode() && UserPhysicalPresent()) ||
1889 (((mSecureBootMode
== SecureBootModeTypeSetupMode
) || (mSecureBootMode
== SecureBootModeTypeAuditMode
)) && !IsPk
)) {
1891 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, Payload
, PayloadSize
);
1892 if (EFI_ERROR (Status
)) {
1897 // If delete PKpub, only check for "SecureBootMode" only
1898 // if update / add PKpub, check both NewPKpub & "SecureBootMode"
1904 if (Del
&& ((mSecureBootMode
== SecureBootModeTypeUserMode
) || (mSecureBootMode
== SecureBootModeTypeDeployedMode
))
1905 && !mAuthVarLibContextIn
->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[1], NULL
)){
1906 return EFI_OUT_OF_RESOURCES
;
1910 } else if (!Del
&& ((mSecureBootMode
== SecureBootModeTypeSetupMode
) || (mSecureBootMode
== SecureBootModeTypeAuditMode
))
1911 && !mAuthVarLibContextIn
->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1912 return EFI_OUT_OF_RESOURCES
;
1916 Status
= AuthServiceInternalUpdateVariableWithTimeStamp (
1922 &((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->TimeStamp
1924 if (EFI_ERROR(Status
)) {
1928 if (((mSecureBootMode
!= SecureBootModeTypeSetupMode
) && (mSecureBootMode
!= SecureBootModeTypeAuditMode
)) || IsPk
) {
1929 Status
= VendorKeyIsModified ();
1931 } else if (mSecureBootMode
== SecureBootModeTypeUserMode
|| mSecureBootMode
== SecureBootModeTypeDeployedMode
) {
1933 // If delete PKpub, check "SecureBootMode" only
1935 if (IsPk
&& Del
&& !mAuthVarLibContextIn
->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[1], NULL
)){
1936 return EFI_OUT_OF_RESOURCES
;
1940 // Verify against X509 Cert in PK database.
1942 Status
= VerifyTimeBasedPayloadAndUpdate (
1953 // SetupMode or AuditMode to add PK
1954 // Verify against the certificate in data payload.
1957 // Check PKpub & SecureBootMode variable space consistency
1959 if (!mAuthVarLibContextIn
->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT
, &VariableEntry
[0], &VariableEntry
[1], NULL
)) {
1961 // No enough variable space to set PK successfully.
1963 return EFI_OUT_OF_RESOURCES
;
1966 Status
= VerifyTimeBasedPayloadAndUpdate (
1977 if (!EFI_ERROR(Status
) && IsPk
) {
1979 // Delete or Enroll PK causes SecureBootMode change
1982 if (mSecureBootMode
== SecureBootModeTypeSetupMode
) {
1984 // If enroll PK in setup mode, change to user mode.
1986 Status
= SecureBootModeTransition (mSecureBootMode
, SecureBootModeTypeUserMode
);
1987 } else if (mSecureBootMode
== SecureBootModeTypeAuditMode
) {
1989 // If enroll PK in Audit mode, change to Deployed mode.
1991 Status
= SecureBootModeTransition (mSecureBootMode
, SecureBootModeTypeDeployedMode
);
1993 DEBUG((EFI_D_INFO
, "PK is updated in %x mode. No SecureBootMode change.\n", mSecureBootMode
));
1996 if ((mSecureBootMode
== SecureBootModeTypeUserMode
) || (mSecureBootMode
== SecureBootModeTypeDeployedMode
)) {
1998 // If delete PK in User Mode or DeployedMode, change to Setup Mode.
2000 Status
= SecureBootModeTransition (mSecureBootMode
, SecureBootModeTypeSetupMode
);
2009 Process variable with key exchange key for verification.
2011 Caution: This function may receive untrusted input.
2012 This function may be invoked in SMM mode, and datasize and data are external input.
2013 This function will do basic validation, before parse the data.
2014 This function will parse the authentication carefully to avoid security issues, like
2015 buffer overflow, integer overflow.
2016 This function will check attribute carefully to avoid authentication bypass.
2018 @param[in] VariableName Name of Variable to be found.
2019 @param[in] VendorGuid Variable vendor GUID.
2020 @param[in] Data Data pointer.
2021 @param[in] DataSize Size of Data found. If size is less than the
2022 data, this value contains the required size.
2023 @param[in] Attributes Attribute value of the variable.
2025 @return EFI_INVALID_PARAMETER Invalid parameter.
2026 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
2027 check carried out by the firmware.
2028 @return EFI_SUCCESS Variable pass validation successfully.
2033 IN CHAR16
*VariableName
,
2034 IN EFI_GUID
*VendorGuid
,
2037 IN UINT32 Attributes OPTIONAL
2044 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0 ||
2045 (Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) == 0) {
2047 // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
2048 // authenticated variable.
2050 return EFI_INVALID_PARAMETER
;
2053 Status
= EFI_SUCCESS
;
2054 if ((mSecureBootMode
== SecureBootModeTypeUserMode
|| mSecureBootMode
== SecureBootModeTypeDeployedMode
)
2055 && !(InCustomMode() && UserPhysicalPresent())) {
2057 // Time-based, verify against X509 Cert KEK.
2059 return VerifyTimeBasedPayloadAndUpdate (
2070 // If in setup mode or custom secure boot mode, no authentication needed.
2072 Payload
= (UINT8
*) Data
+ AUTHINFO2_SIZE (Data
);
2073 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
2075 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, Payload
, PayloadSize
);
2076 if (EFI_ERROR (Status
)) {
2080 Status
= AuthServiceInternalUpdateVariableWithTimeStamp (
2086 &((EFI_VARIABLE_AUTHENTICATION_2
*) Data
)->TimeStamp
2088 if (EFI_ERROR (Status
)) {
2092 if ((mSecureBootMode
!= SecureBootModeTypeSetupMode
) && (mSecureBootMode
!= SecureBootModeTypeAuditMode
)) {
2093 Status
= VendorKeyIsModified ();
2101 Check if it is to delete auth variable.
2103 @param[in] OrgAttributes Original attribute value of the variable.
2104 @param[in] Data Data pointer.
2105 @param[in] DataSize Size of Data.
2106 @param[in] Attributes Attribute value of the variable.
2108 @retval TRUE It is to delete auth variable.
2109 @retval FALSE It is not to delete auth variable.
2113 IsDeleteAuthVariable (
2114 IN UINT32 OrgAttributes
,
2117 IN UINT32 Attributes
2126 // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
2127 // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
2128 // SetVariable must be used with attributes matching the existing variable
2129 // and the DataSize set to the size of the AuthInfo descriptor.
2131 if ((Attributes
== OrgAttributes
) &&
2132 ((Attributes
& (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) != 0)) {
2133 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2134 PayloadSize
= DataSize
- AUTHINFO2_SIZE (Data
);
2135 if (PayloadSize
== 0) {
2139 PayloadSize
= DataSize
- AUTHINFO_SIZE
;
2140 if (PayloadSize
== 0) {
2150 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
2152 Caution: This function may receive untrusted input.
2153 This function may be invoked in SMM mode, and datasize and data are external input.
2154 This function will do basic validation, before parse the data.
2155 This function will parse the authentication carefully to avoid security issues, like
2156 buffer overflow, integer overflow.
2157 This function will check attribute carefully to avoid authentication bypass.
2159 @param[in] VariableName Name of the variable.
2160 @param[in] VendorGuid Variable vendor GUID.
2161 @param[in] Data Data pointer.
2162 @param[in] DataSize Size of Data.
2163 @param[in] Attributes Attribute value of the variable.
2165 @return EFI_INVALID_PARAMETER Invalid parameter.
2166 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
2167 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
2168 @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
2169 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
2170 set, but the AuthInfo does NOT pass the validation
2171 check carried out by the firmware.
2172 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
2177 IN CHAR16
*VariableName
,
2178 IN EFI_GUID
*VendorGuid
,
2181 IN UINT32 Attributes
2186 BOOLEAN IsFirstTime
;
2188 EFI_VARIABLE_AUTHENTICATION
*CertData
;
2189 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
2191 UINT64 MonotonicCount
;
2192 VARIABLE_ENTRY_CONSISTENCY VariableDataEntry
;
2194 AUTH_VARIABLE_INFO OrgVariableInfo
;
2201 Status
= EFI_SUCCESS
;
2203 ZeroMem (&OrgVariableInfo
, sizeof (OrgVariableInfo
));
2204 Status
= mAuthVarLibContextIn
->FindVariable (
2210 if ((!EFI_ERROR (Status
)) && IsDeleteAuthVariable (OrgVariableInfo
.Attributes
, Data
, DataSize
, Attributes
) && UserPhysicalPresent()) {
2212 // Allow the delete operation of common authenticated variable at user physical presence.
2214 Status
= AuthServiceInternalUpdateVariable (
2221 if (!EFI_ERROR (Status
) && ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0)) {
2222 Status
= DeleteCertsFromDb (VariableName
, VendorGuid
, Attributes
);
2228 if (NeedPhysicallyPresent (VariableName
, VendorGuid
) && !UserPhysicalPresent()) {
2230 // This variable is protected, only physical present user could modify its value.
2232 return EFI_SECURITY_VIOLATION
;
2236 // A time-based authenticated variable and a count-based authenticated variable
2237 // can't be updated by each other.
2239 if (OrgVariableInfo
.Data
!= NULL
) {
2240 if (((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2241 ((OrgVariableInfo
.Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0)) {
2242 return EFI_SECURITY_VIOLATION
;
2245 if (((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) &&
2246 ((OrgVariableInfo
.Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0)) {
2247 return EFI_SECURITY_VIOLATION
;
2252 // Process Time-based Authenticated variable.
2254 if ((Attributes
& EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2255 return VerifyTimeBasedPayloadAndUpdate (
2267 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
2269 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
2271 // Determine current operation type.
2273 if (DataSize
== AUTHINFO_SIZE
) {
2277 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
2279 if (OrgVariableInfo
.Data
== NULL
) {
2281 } else if ((OrgVariableInfo
.Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
2284 KeyIndex
= OrgVariableInfo
.PubKeyIndex
;
2285 IsFirstTime
= FALSE
;
2287 } else if ((OrgVariableInfo
.Data
!= NULL
) &&
2288 ((OrgVariableInfo
.Attributes
& (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
)) != 0)
2291 // If the variable is already write-protected, it always needs authentication before update.
2293 return EFI_WRITE_PROTECTED
;
2296 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
2297 // That means it is not authenticated variable, just update variable as usual.
2299 Status
= AuthServiceInternalUpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
);
2304 // Get PubKey and check Monotonic Count value corresponding to the variable.
2306 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
2307 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
2308 PubKey
= CertBlock
->PublicKey
;
2311 // Update Monotonic Count value.
2313 MonotonicCount
= CertData
->MonotonicCount
;
2317 // 2 cases need to check here
2318 // 1. Internal PubKey variable. PubKeyIndex is always 0
2319 // 2. Other counter-based AuthVariable. Check input PubKey.
2321 if (KeyIndex
== 0) {
2322 return EFI_SECURITY_VIOLATION
;
2324 for (Index
= 0; Index
< mPubKeyNumber
; Index
++) {
2325 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ Index
)->KeyIndex
)) == KeyIndex
) {
2326 if (CompareMem (((AUTHVAR_KEY_DB_DATA
*) mPubKeyStore
+ Index
)->KeyData
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
2329 return EFI_SECURITY_VIOLATION
;
2333 if (Index
== mPubKeyNumber
) {
2334 return EFI_SECURITY_VIOLATION
;
2338 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
2339 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
2341 if (MonotonicCount
<= OrgVariableInfo
.MonotonicCount
) {
2343 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
2345 return EFI_SECURITY_VIOLATION
;
2349 // Verify the certificate in Data payload.
2351 Status
= VerifyCounterBasedPayload (Data
, DataSize
, PubKey
);
2352 if (EFI_ERROR (Status
)) {
2357 // Now, the signature has been verified!
2359 if (IsFirstTime
&& !IsDeletion
) {
2360 VariableDataEntry
.VariableSize
= DataSize
- AUTHINFO_SIZE
;
2361 VariableDataEntry
.Guid
= VendorGuid
;
2362 VariableDataEntry
.Name
= VariableName
;
2365 // Update public key database variable if need.
2367 KeyIndex
= AddPubKeyInStore (PubKey
, &VariableDataEntry
);
2368 if (KeyIndex
== 0) {
2369 return EFI_OUT_OF_RESOURCES
;
2374 // Verification pass.
2376 return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName
, VendorGuid
, (UINT8
*)Data
+ AUTHINFO_SIZE
, DataSize
- AUTHINFO_SIZE
, Attributes
, KeyIndex
, MonotonicCount
);
2380 Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
2382 @param[in] Data Pointer to original EFI_SIGNATURE_LIST.
2383 @param[in] DataSize Size of Data buffer.
2384 @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.
2385 @param[in, out] NewDataSize Size of NewData buffer.
2389 FilterSignatureList (
2392 IN OUT VOID
*NewData
,
2393 IN OUT UINTN
*NewDataSize
2396 EFI_SIGNATURE_LIST
*CertList
;
2397 EFI_SIGNATURE_DATA
*Cert
;
2399 EFI_SIGNATURE_LIST
*NewCertList
;
2400 EFI_SIGNATURE_DATA
*NewCert
;
2407 UINTN SignatureListSize
;
2413 if (*NewDataSize
== 0) {
2417 TempDataSize
= *NewDataSize
;
2418 Status
= mAuthVarLibContextIn
->GetScratchBuffer (&TempDataSize
, (VOID
**) &TempData
);
2419 if (EFI_ERROR (Status
)) {
2420 return EFI_OUT_OF_RESOURCES
;
2425 NewCertList
= (EFI_SIGNATURE_LIST
*) NewData
;
2426 while ((*NewDataSize
> 0) && (*NewDataSize
>= NewCertList
->SignatureListSize
)) {
2427 NewCert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) NewCertList
+ sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
);
2428 NewCertCount
= (NewCertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - NewCertList
->SignatureHeaderSize
) / NewCertList
->SignatureSize
;
2431 for (Index
= 0; Index
< NewCertCount
; Index
++) {
2435 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
2436 while ((Size
> 0) && (Size
>= CertList
->SignatureListSize
)) {
2437 if (CompareGuid (&CertList
->SignatureType
, &NewCertList
->SignatureType
) &&
2438 (CertList
->SignatureSize
== NewCertList
->SignatureSize
)) {
2439 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
2440 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
2441 for (Index2
= 0; Index2
< CertCount
; Index2
++) {
2443 // Iterate each Signature Data in this Signature List.
2445 if (CompareMem (NewCert
, Cert
, CertList
->SignatureSize
) == 0) {
2449 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
2456 Size
-= CertList
->SignatureListSize
;
2457 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
2462 // New EFI_SIGNATURE_DATA, keep it.
2464 if (CopiedCount
== 0) {
2466 // Copy EFI_SIGNATURE_LIST header for only once.
2468 CopyMem (Tail
, NewCertList
, sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
);
2469 Tail
= Tail
+ sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
;
2472 CopyMem (Tail
, NewCert
, NewCertList
->SignatureSize
);
2473 Tail
+= NewCertList
->SignatureSize
;
2477 NewCert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) NewCert
+ NewCertList
->SignatureSize
);
2481 // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
2483 if (CopiedCount
!= 0) {
2484 SignatureListSize
= sizeof (EFI_SIGNATURE_LIST
) + NewCertList
->SignatureHeaderSize
+ (CopiedCount
* NewCertList
->SignatureSize
);
2485 CertList
= (EFI_SIGNATURE_LIST
*) (Tail
- SignatureListSize
);
2486 CertList
->SignatureListSize
= (UINT32
) SignatureListSize
;
2489 *NewDataSize
-= NewCertList
->SignatureListSize
;
2490 NewCertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) NewCertList
+ NewCertList
->SignatureListSize
);
2493 TempDataSize
= (Tail
- (UINT8
*) TempData
);
2495 CopyMem (NewData
, TempData
, TempDataSize
);
2496 *NewDataSize
= TempDataSize
;
2502 Compare two EFI_TIME data.
2505 @param FirstTime A pointer to the first EFI_TIME data.
2506 @param SecondTime A pointer to the second EFI_TIME data.
2508 @retval TRUE The FirstTime is not later than the SecondTime.
2509 @retval FALSE The FirstTime is later than the SecondTime.
2513 AuthServiceInternalCompareTimeStamp (
2514 IN EFI_TIME
*FirstTime
,
2515 IN EFI_TIME
*SecondTime
2518 if (FirstTime
->Year
!= SecondTime
->Year
) {
2519 return (BOOLEAN
) (FirstTime
->Year
< SecondTime
->Year
);
2520 } else if (FirstTime
->Month
!= SecondTime
->Month
) {
2521 return (BOOLEAN
) (FirstTime
->Month
< SecondTime
->Month
);
2522 } else if (FirstTime
->Day
!= SecondTime
->Day
) {
2523 return (BOOLEAN
) (FirstTime
->Day
< SecondTime
->Day
);
2524 } else if (FirstTime
->Hour
!= SecondTime
->Hour
) {
2525 return (BOOLEAN
) (FirstTime
->Hour
< SecondTime
->Hour
);
2526 } else if (FirstTime
->Minute
!= SecondTime
->Minute
) {
2527 return (BOOLEAN
) (FirstTime
->Minute
< SecondTime
->Minute
);
2530 return (BOOLEAN
) (FirstTime
->Second
<= SecondTime
->Second
);
2534 Find matching signer's certificates for common authenticated variable
2535 by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
2537 The data format of "certdb" or "certdbv":
2539 // UINT32 CertDbListSize;
2540 // /// AUTH_CERT_DB_DATA Certs1[];
2541 // /// AUTH_CERT_DB_DATA Certs2[];
2543 // /// AUTH_CERT_DB_DATA Certsn[];
2546 @param[in] VariableName Name of authenticated Variable.
2547 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2548 @param[in] Data Pointer to variable "certdb" or "certdbv".
2549 @param[in] DataSize Size of variable "certdb" or "certdbv".
2550 @param[out] CertOffset Offset of matching CertData, from starting of Data.
2551 @param[out] CertDataSize Length of CertData in bytes.
2552 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
2554 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
2556 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2557 @retval EFI_NOT_FOUND Fail to find matching certs.
2558 @retval EFI_SUCCESS Find matching certs and output parameters.
2563 IN CHAR16
*VariableName
,
2564 IN EFI_GUID
*VendorGuid
,
2567 OUT UINT32
*CertOffset
, OPTIONAL
2568 OUT UINT32
*CertDataSize
, OPTIONAL
2569 OUT UINT32
*CertNodeOffset
,OPTIONAL
2570 OUT UINT32
*CertNodeSize OPTIONAL
2574 AUTH_CERT_DB_DATA
*Ptr
;
2578 UINT32 CertDbListSize
;
2580 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
)) {
2581 return EFI_INVALID_PARAMETER
;
2585 // Check whether DataSize matches recorded CertDbListSize.
2587 if (DataSize
< sizeof (UINT32
)) {
2588 return EFI_INVALID_PARAMETER
;
2591 CertDbListSize
= ReadUnaligned32 ((UINT32
*) Data
);
2593 if (CertDbListSize
!= (UINT32
) DataSize
) {
2594 return EFI_INVALID_PARAMETER
;
2597 Offset
= sizeof (UINT32
);
2600 // Get corresponding certificates by VendorGuid and VariableName.
2602 while (Offset
< (UINT32
) DataSize
) {
2603 Ptr
= (AUTH_CERT_DB_DATA
*) (Data
+ Offset
);
2605 // Check whether VendorGuid matches.
2607 if (CompareGuid (&Ptr
->VendorGuid
, VendorGuid
)) {
2608 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
2609 NameSize
= ReadUnaligned32 (&Ptr
->NameSize
);
2610 CertSize
= ReadUnaligned32 (&Ptr
->CertDataSize
);
2612 if (NodeSize
!= sizeof (EFI_GUID
) + sizeof (UINT32
) * 3 + CertSize
+
2613 sizeof (CHAR16
) * NameSize
) {
2614 return EFI_INVALID_PARAMETER
;
2617 Offset
= Offset
+ sizeof (EFI_GUID
) + sizeof (UINT32
) * 3;
2619 // Check whether VariableName matches.
2621 if ((NameSize
== StrLen (VariableName
)) &&
2622 (CompareMem (Data
+ Offset
, VariableName
, NameSize
* sizeof (CHAR16
)) == 0)) {
2623 Offset
= Offset
+ NameSize
* sizeof (CHAR16
);
2625 if (CertOffset
!= NULL
) {
2626 *CertOffset
= Offset
;
2629 if (CertDataSize
!= NULL
) {
2630 *CertDataSize
= CertSize
;
2633 if (CertNodeOffset
!= NULL
) {
2634 *CertNodeOffset
= (UINT32
) ((UINT8
*) Ptr
- Data
);
2637 if (CertNodeSize
!= NULL
) {
2638 *CertNodeSize
= NodeSize
;
2643 Offset
= Offset
+ NameSize
* sizeof (CHAR16
) + CertSize
;
2646 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
2647 Offset
= Offset
+ NodeSize
;
2651 return EFI_NOT_FOUND
;
2655 Retrieve signer's certificates for common authenticated variable
2656 by corresponding VariableName and VendorGuid from "certdb"
2657 or "certdbv" according to authenticated variable attributes.
2659 @param[in] VariableName Name of authenticated Variable.
2660 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2661 @param[in] Attributes Attributes of authenticated variable.
2662 @param[out] CertData Pointer to signer's certificates.
2663 @param[out] CertDataSize Length of CertData in bytes.
2665 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2666 @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
2667 @retval EFI_SUCCESS Get signer's certificates successfully.
2672 IN CHAR16
*VariableName
,
2673 IN EFI_GUID
*VendorGuid
,
2674 IN UINT32 Attributes
,
2675 OUT UINT8
**CertData
,
2676 OUT UINT32
*CertDataSize
2685 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (CertData
== NULL
) || (CertDataSize
== NULL
)) {
2686 return EFI_INVALID_PARAMETER
;
2690 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2692 // Get variable "certdb".
2694 DbName
= EFI_CERT_DB_NAME
;
2697 // Get variable "certdbv".
2699 DbName
= EFI_CERT_DB_VOLATILE_NAME
;
2703 // Get variable "certdb" or "certdbv".
2705 Status
= AuthServiceInternalFindVariable (
2711 if (EFI_ERROR (Status
)) {
2715 if ((DataSize
== 0) || (Data
== NULL
)) {
2717 return EFI_NOT_FOUND
;
2720 Status
= FindCertsFromDb (
2731 if (EFI_ERROR (Status
)) {
2735 *CertData
= Data
+ CertOffset
;
2740 Delete matching signer's certificates when deleting common authenticated
2741 variable by corresponding VariableName and VendorGuid from "certdb" or
2742 "certdbv" according to authenticated variable attributes.
2744 @param[in] VariableName Name of authenticated Variable.
2745 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2746 @param[in] Attributes Attributes of authenticated variable.
2748 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2749 @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
2750 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
2751 @retval EFI_SUCCESS The operation is completed successfully.
2756 IN CHAR16
*VariableName
,
2757 IN EFI_GUID
*VendorGuid
,
2758 IN UINT32 Attributes
2765 UINT32 CertNodeOffset
;
2766 UINT32 CertNodeSize
;
2768 UINT32 NewCertDbSize
;
2771 if ((VariableName
== NULL
) || (VendorGuid
== NULL
)) {
2772 return EFI_INVALID_PARAMETER
;
2775 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2777 // Get variable "certdb".
2779 DbName
= EFI_CERT_DB_NAME
;
2780 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
2783 // Get variable "certdbv".
2785 DbName
= EFI_CERT_DB_VOLATILE_NAME
;
2786 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
2789 Status
= AuthServiceInternalFindVariable (
2796 if (EFI_ERROR (Status
)) {
2800 if ((DataSize
== 0) || (Data
== NULL
)) {
2802 return EFI_NOT_FOUND
;
2805 if (DataSize
== sizeof (UINT32
)) {
2807 // There is no certs in "certdb" or "certdbv".
2813 // Get corresponding cert node from "certdb" or "certdbv".
2815 Status
= FindCertsFromDb (
2826 if (EFI_ERROR (Status
)) {
2830 if (DataSize
< (CertNodeOffset
+ CertNodeSize
)) {
2831 return EFI_NOT_FOUND
;
2835 // Construct new data content of variable "certdb" or "certdbv".
2837 NewCertDbSize
= (UINT32
) DataSize
- CertNodeSize
;
2838 NewCertDb
= (UINT8
*) mCertDbStore
;
2841 // Copy the DB entries before deleting node.
2843 CopyMem (NewCertDb
, Data
, CertNodeOffset
);
2845 // Update CertDbListSize.
2847 CopyMem (NewCertDb
, &NewCertDbSize
, sizeof (UINT32
));
2849 // Copy the DB entries after deleting node.
2851 if (DataSize
> (CertNodeOffset
+ CertNodeSize
)) {
2853 NewCertDb
+ CertNodeOffset
,
2854 Data
+ CertNodeOffset
+ CertNodeSize
,
2855 DataSize
- CertNodeOffset
- CertNodeSize
2860 // Set "certdb" or "certdbv".
2862 Status
= AuthServiceInternalUpdateVariable (
2874 Insert signer's certificates for common authenticated variable with VariableName
2875 and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
2876 time based authenticated variable attributes.
2878 @param[in] VariableName Name of authenticated Variable.
2879 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2880 @param[in] Attributes Attributes of authenticated variable.
2881 @param[in] CertData Pointer to signer's certificates.
2882 @param[in] CertDataSize Length of CertData in bytes.
2884 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2885 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
2886 and VendorGuid already exists.
2887 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
2888 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
2893 IN CHAR16
*VariableName
,
2894 IN EFI_GUID
*VendorGuid
,
2895 IN UINT32 Attributes
,
2897 IN UINTN CertDataSize
2905 UINT32 NewCertDbSize
;
2906 UINT32 CertNodeSize
;
2908 AUTH_CERT_DB_DATA
*Ptr
;
2911 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (CertData
== NULL
)) {
2912 return EFI_INVALID_PARAMETER
;
2915 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
2917 // Get variable "certdb".
2919 DbName
= EFI_CERT_DB_NAME
;
2920 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
2923 // Get variable "certdbv".
2925 DbName
= EFI_CERT_DB_VOLATILE_NAME
;
2926 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
2930 // Get variable "certdb" or "certdbv".
2932 Status
= AuthServiceInternalFindVariable (
2938 if (EFI_ERROR (Status
)) {
2942 if ((DataSize
== 0) || (Data
== NULL
)) {
2944 return EFI_NOT_FOUND
;
2948 // Find whether matching cert node already exists in "certdb" or "certdbv".
2949 // If yes return error.
2951 Status
= FindCertsFromDb (
2962 if (!EFI_ERROR (Status
)) {
2964 return EFI_ACCESS_DENIED
;
2968 // Construct new data content of variable "certdb" or "certdbv".
2970 NameSize
= (UINT32
) StrLen (VariableName
);
2971 CertNodeSize
= sizeof (AUTH_CERT_DB_DATA
) + (UINT32
) CertDataSize
+ NameSize
* sizeof (CHAR16
);
2972 NewCertDbSize
= (UINT32
) DataSize
+ CertNodeSize
;
2973 if (NewCertDbSize
> mMaxCertDbSize
) {
2974 return EFI_OUT_OF_RESOURCES
;
2976 NewCertDb
= (UINT8
*) mCertDbStore
;
2979 // Copy the DB entries before inserting node.
2981 CopyMem (NewCertDb
, Data
, DataSize
);
2983 // Update CertDbListSize.
2985 CopyMem (NewCertDb
, &NewCertDbSize
, sizeof (UINT32
));
2987 // Construct new cert node.
2989 Ptr
= (AUTH_CERT_DB_DATA
*) (NewCertDb
+ DataSize
);
2990 CopyGuid (&Ptr
->VendorGuid
, VendorGuid
);
2991 CopyMem (&Ptr
->CertNodeSize
, &CertNodeSize
, sizeof (UINT32
));
2992 CopyMem (&Ptr
->NameSize
, &NameSize
, sizeof (UINT32
));
2993 CopyMem (&Ptr
->CertDataSize
, &CertDataSize
, sizeof (UINT32
));
2996 (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
),
2998 NameSize
* sizeof (CHAR16
)
3002 (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
) + NameSize
* sizeof (CHAR16
),
3008 // Set "certdb" or "certdbv".
3010 Status
= AuthServiceInternalUpdateVariable (
3022 Clean up signer's certificates for common authenticated variable
3023 by corresponding VariableName and VendorGuid from "certdb".
3024 System may break down during Timebased Variable update & certdb update,
3025 make them inconsistent, this function is called in AuthVariable Init
3026 to ensure consistency.
3028 @retval EFI_NOT_FOUND Fail to find variable "certdb".
3029 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
3030 @retval EFI_SUCCESS The operation is completed successfully.
3039 AUTH_CERT_DB_DATA
*Ptr
;
3042 CHAR16
*VariableName
;
3044 BOOLEAN CertCleaned
;
3047 EFI_GUID AuthVarGuid
;
3048 AUTH_VARIABLE_INFO AuthVariableInfo
;
3050 Status
= EFI_SUCCESS
;
3053 // Get corresponding certificates by VendorGuid and VariableName.
3056 CertCleaned
= FALSE
;
3059 // Get latest variable "certdb"
3061 Status
= AuthServiceInternalFindVariable (
3067 if (EFI_ERROR (Status
)) {
3071 if ((DataSize
== 0) || (Data
== NULL
)) {
3073 return EFI_NOT_FOUND
;
3076 Offset
= sizeof (UINT32
);
3078 while (Offset
< (UINT32
) DataSize
) {
3079 Ptr
= (AUTH_CERT_DB_DATA
*) (Data
+ Offset
);
3080 NodeSize
= ReadUnaligned32 (&Ptr
->CertNodeSize
);
3081 NameSize
= ReadUnaligned32 (&Ptr
->NameSize
);
3084 // Get VarName tailed with '\0'
3086 VariableName
= AllocateZeroPool((NameSize
+ 1) * sizeof(CHAR16
));
3087 if (VariableName
== NULL
) {
3088 return EFI_OUT_OF_RESOURCES
;
3090 CopyMem (VariableName
, (UINT8
*) Ptr
+ sizeof (AUTH_CERT_DB_DATA
), NameSize
* sizeof(CHAR16
));
3092 // Keep VarGuid aligned
3094 CopyMem (&AuthVarGuid
, &Ptr
->VendorGuid
, sizeof(EFI_GUID
));
3097 // Find corresponding time auth variable
3099 ZeroMem (&AuthVariableInfo
, sizeof (AuthVariableInfo
));
3100 Status
= mAuthVarLibContextIn
->FindVariable (
3106 if (EFI_ERROR(Status
)) {
3107 Status
= DeleteCertsFromDb(
3110 AuthVariableInfo
.Attributes
3113 DEBUG((EFI_D_INFO
, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName
, &AuthVarGuid
));
3114 FreePool(VariableName
);
3118 FreePool(VariableName
);
3119 Offset
= Offset
+ NodeSize
;
3121 } while (CertCleaned
);
3127 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
3129 Caution: This function may receive untrusted input.
3130 This function may be invoked in SMM mode, and datasize and data are external input.
3131 This function will do basic validation, before parse the data.
3132 This function will parse the authentication carefully to avoid security issues, like
3133 buffer overflow, integer overflow.
3135 @param[in] VariableName Name of Variable to be found.
3136 @param[in] VendorGuid Variable vendor GUID.
3137 @param[in] Data Data pointer.
3138 @param[in] DataSize Size of Data found. If size is less than the
3139 data, this value contains the required size.
3140 @param[in] Attributes Attribute value of the variable.
3141 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
3142 @param[in] OrgTimeStamp Pointer to original time stamp,
3143 original variable is not found if NULL.
3144 @param[out] VarPayloadPtr Pointer to variable payload address.
3145 @param[out] VarPayloadSize Pointer to variable payload size.
3147 @retval EFI_INVALID_PARAMETER Invalid parameter.
3148 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
3149 check carried out by the firmware.
3150 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
3152 @retval EFI_SUCCESS Variable pass validation successfully.
3156 VerifyTimeBasedPayload (
3157 IN CHAR16
*VariableName
,
3158 IN EFI_GUID
*VendorGuid
,
3161 IN UINT32 Attributes
,
3162 IN AUTHVAR_TYPE AuthVarType
,
3163 IN EFI_TIME
*OrgTimeStamp
,
3164 OUT UINT8
**VarPayloadPtr
,
3165 OUT UINTN
*VarPayloadSize
3168 EFI_VARIABLE_AUTHENTICATION_2
*CertData
;
3174 BOOLEAN VerifyStatus
;
3176 EFI_SIGNATURE_LIST
*CertList
;
3177 EFI_SIGNATURE_DATA
*Cert
;
3188 UINTN CertStackSize
;
3189 UINT8
*CertsInCertDb
;
3190 UINT32 CertsSizeinDb
;
3192 VerifyStatus
= FALSE
;
3198 CertsInCertDb
= NULL
;
3201 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
3202 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
3203 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
3204 // variable value and DataSize shall reflect the combined size of the descriptor and the new
3205 // variable value. The authentication descriptor is not part of the variable data and is not
3206 // returned by subsequent calls to GetVariable().
3208 CertData
= (EFI_VARIABLE_AUTHENTICATION_2
*) Data
;
3211 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
3212 // TimeStamp value are set to zero.
3214 if ((CertData
->TimeStamp
.Pad1
!= 0) ||
3215 (CertData
->TimeStamp
.Nanosecond
!= 0) ||
3216 (CertData
->TimeStamp
.TimeZone
!= 0) ||
3217 (CertData
->TimeStamp
.Daylight
!= 0) ||
3218 (CertData
->TimeStamp
.Pad2
!= 0)) {
3219 return EFI_SECURITY_VIOLATION
;
3222 if ((OrgTimeStamp
!= NULL
) && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
3223 if (AuthServiceInternalCompareTimeStamp (&CertData
->TimeStamp
, OrgTimeStamp
)) {
3225 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
3227 return EFI_SECURITY_VIOLATION
;
3232 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
3233 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
3235 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
3236 !CompareGuid (&CertData
->AuthInfo
.CertType
, &gEfiCertPkcs7Guid
)) {
3238 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
3240 return EFI_SECURITY_VIOLATION
;
3244 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3245 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
3247 SigData
= CertData
->AuthInfo
.CertData
;
3248 SigDataSize
= CertData
->AuthInfo
.Hdr
.dwLength
- (UINT32
) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID
, CertData
));
3251 // Find out the new data payload which follows Pkcs7 SignedData directly.
3253 PayloadPtr
= SigData
+ SigDataSize
;
3254 PayloadSize
= DataSize
- OFFSET_OF_AUTHINFO2_CERT_DATA
- (UINTN
) SigDataSize
;
3257 // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
3258 // parameters of the SetVariable() call and the TimeStamp component of the
3259 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
3260 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
3262 NewDataSize
= PayloadSize
+ sizeof (EFI_TIME
) + sizeof (UINT32
) +
3263 sizeof (EFI_GUID
) + StrSize (VariableName
) - sizeof (CHAR16
);
3266 // Here is to reuse scratch data area(at the end of volatile variable store)
3267 // to reduce SMRAM consumption for SMM variable driver.
3268 // The scratch buffer is enough to hold the serialized data and safe to use,
3269 // because it is only used at here to do verification temporarily first
3270 // and then used in UpdateVariable() for a time based auth variable set.
3272 Status
= mAuthVarLibContextIn
->GetScratchBuffer (&NewDataSize
, (VOID
**) &NewData
);
3273 if (EFI_ERROR (Status
)) {
3274 return EFI_OUT_OF_RESOURCES
;
3278 Length
= StrLen (VariableName
) * sizeof (CHAR16
);
3279 CopyMem (Buffer
, VariableName
, Length
);
3282 Length
= sizeof (EFI_GUID
);
3283 CopyMem (Buffer
, VendorGuid
, Length
);
3286 Length
= sizeof (UINT32
);
3287 CopyMem (Buffer
, &Attr
, Length
);
3290 Length
= sizeof (EFI_TIME
);
3291 CopyMem (Buffer
, &CertData
->TimeStamp
, Length
);
3294 CopyMem (Buffer
, PayloadPtr
, PayloadSize
);
3296 if (AuthVarType
== AuthVarTypePk
) {
3298 // Verify that the signature has been made with the current Platform Key (no chaining for PK).
3299 // First, get signer's certificates from SignedData.
3301 VerifyStatus
= Pkcs7GetSigners (
3309 if (!VerifyStatus
) {
3314 // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
3315 // in SignedData. If not, return error immediately.
3317 Status
= AuthServiceInternalFindVariable (
3318 EFI_PLATFORM_KEY_NAME
,
3319 &gEfiGlobalVariableGuid
,
3323 if (EFI_ERROR (Status
)) {
3324 VerifyStatus
= FALSE
;
3327 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
3328 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
3329 if ((RootCertSize
!= (CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1))) ||
3330 (CompareMem (Cert
->SignatureData
, RootCert
, RootCertSize
) != 0)) {
3331 VerifyStatus
= FALSE
;
3336 // Verify Pkcs7 SignedData via Pkcs7Verify library.
3338 VerifyStatus
= Pkcs7Verify (
3347 } else if (AuthVarType
== AuthVarTypeKek
) {
3350 // Get KEK database from variable.
3352 Status
= AuthServiceInternalFindVariable (
3353 EFI_KEY_EXCHANGE_KEY_NAME
,
3354 &gEfiGlobalVariableGuid
,
3358 if (EFI_ERROR (Status
)) {
3363 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
3365 KekDataSize
= (UINT32
) DataSize
;
3366 CertList
= (EFI_SIGNATURE_LIST
*) Data
;
3367 while ((KekDataSize
> 0) && (KekDataSize
>= CertList
->SignatureListSize
)) {
3368 if (CompareGuid (&CertList
->SignatureType
, &gEfiCertX509Guid
)) {
3369 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
3370 CertCount
= (CertList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - CertList
->SignatureHeaderSize
) / CertList
->SignatureSize
;
3371 for (Index
= 0; Index
< CertCount
; Index
++) {
3373 // Iterate each Signature Data Node within this CertList for a verify
3375 RootCert
= Cert
->SignatureData
;
3376 RootCertSize
= CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1);
3379 // Verify Pkcs7 SignedData via Pkcs7Verify library.
3381 VerifyStatus
= Pkcs7Verify (
3392 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) Cert
+ CertList
->SignatureSize
);
3395 KekDataSize
-= CertList
->SignatureListSize
;
3396 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+ CertList
->SignatureListSize
);
3398 } else if (AuthVarType
== AuthVarTypePriv
) {
3401 // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
3402 // Get signer's certificates from SignedData.
3404 VerifyStatus
= Pkcs7GetSigners (
3412 if (!VerifyStatus
) {
3417 // Get previously stored signer's certificates from certdb or certdbv for existing
3418 // variable. Check whether they are identical with signer's certificates
3419 // in SignedData. If not, return error immediately.
3421 if (OrgTimeStamp
!= NULL
) {
3422 VerifyStatus
= FALSE
;
3424 Status
= GetCertsFromDb (VariableName
, VendorGuid
, Attributes
, &CertsInCertDb
, &CertsSizeinDb
);
3425 if (EFI_ERROR (Status
)) {
3429 if ((CertStackSize
!= CertsSizeinDb
) ||
3430 (CompareMem (SignerCerts
, CertsInCertDb
, CertsSizeinDb
) != 0)) {
3435 VerifyStatus
= Pkcs7Verify (
3443 if (!VerifyStatus
) {
3447 if ((OrgTimeStamp
== NULL
) && (PayloadSize
!= 0)) {
3449 // Insert signer's certificates when adding a new common authenticated variable.
3451 Status
= InsertCertsToDb (VariableName
, VendorGuid
, Attributes
, SignerCerts
, CertStackSize
);
3452 if (EFI_ERROR (Status
)) {
3453 VerifyStatus
= FALSE
;
3457 } else if (AuthVarType
== AuthVarTypePayload
) {
3458 CertList
= (EFI_SIGNATURE_LIST
*) PayloadPtr
;
3459 Cert
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) CertList
+ sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
3460 RootCert
= Cert
->SignatureData
;
3461 RootCertSize
= CertList
->SignatureSize
- (sizeof (EFI_SIGNATURE_DATA
) - 1);
3463 // Verify Pkcs7 SignedData via Pkcs7Verify library.
3465 VerifyStatus
= Pkcs7Verify (
3474 return EFI_SECURITY_VIOLATION
;
3479 if (AuthVarType
== AuthVarTypePk
|| AuthVarType
== AuthVarTypePriv
) {
3480 Pkcs7FreeSigners (RootCert
);
3481 Pkcs7FreeSigners (SignerCerts
);
3484 if (!VerifyStatus
) {
3485 return EFI_SECURITY_VIOLATION
;
3488 Status
= CheckSignatureListFormat(VariableName
, VendorGuid
, PayloadPtr
, PayloadSize
);
3489 if (EFI_ERROR (Status
)) {
3493 *VarPayloadPtr
= PayloadPtr
;
3494 *VarPayloadSize
= PayloadSize
;
3500 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
3502 Caution: This function may receive untrusted input.
3503 This function may be invoked in SMM mode, and datasize and data are external input.
3504 This function will do basic validation, before parse the data.
3505 This function will parse the authentication carefully to avoid security issues, like
3506 buffer overflow, integer overflow.
3508 @param[in] VariableName Name of Variable to be found.
3509 @param[in] VendorGuid Variable vendor GUID.
3510 @param[in] Data Data pointer.
3511 @param[in] DataSize Size of Data found. If size is less than the
3512 data, this value contains the required size.
3513 @param[in] Attributes Attribute value of the variable.
3514 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
3515 @param[out] VarDel Delete the variable or not.
3517 @retval EFI_INVALID_PARAMETER Invalid parameter.
3518 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
3519 check carried out by the firmware.
3520 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
3522 @retval EFI_SUCCESS Variable pass validation successfully.
3526 VerifyTimeBasedPayloadAndUpdate (
3527 IN CHAR16
*VariableName
,
3528 IN EFI_GUID
*VendorGuid
,
3531 IN UINT32 Attributes
,
3532 IN AUTHVAR_TYPE AuthVarType
,
3537 EFI_STATUS FindStatus
;
3540 EFI_VARIABLE_AUTHENTICATION_2
*CertData
;
3541 AUTH_VARIABLE_INFO OrgVariableInfo
;
3544 ZeroMem (&OrgVariableInfo
, sizeof (OrgVariableInfo
));
3545 FindStatus
= mAuthVarLibContextIn
->FindVariable (
3551 Status
= VerifyTimeBasedPayload (
3558 (!EFI_ERROR (FindStatus
)) ? OrgVariableInfo
.TimeStamp
: NULL
,
3562 if (EFI_ERROR (Status
)) {
3566 if (!EFI_ERROR(FindStatus
)
3567 && (PayloadSize
== 0)
3568 && ((Attributes
& EFI_VARIABLE_APPEND_WRITE
) == 0)) {
3574 CertData
= (EFI_VARIABLE_AUTHENTICATION_2
*) Data
;
3577 // Final step: Update/Append Variable if it pass Pkcs7Verify
3579 Status
= AuthServiceInternalUpdateVariableWithTimeStamp (
3585 &CertData
->TimeStamp
3589 // Delete signer's certificates when delete the common authenticated variable.
3591 if (IsDel
&& AuthVarType
== AuthVarTypePriv
&& !EFI_ERROR(Status
) ) {
3592 Status
= DeleteCertsFromDb (VariableName
, VendorGuid
, Attributes
);
3595 if (VarDel
!= NULL
) {
3596 if (IsDel
&& !EFI_ERROR(Status
)) {