2 Implement authentication services for the authenticated variable
5 Copyright (c) 2009 - 2014, 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
24 EFI_GUID mSignatureSupport
[SIGSUPPORT_NUM
] = {EFI_CERT_RSA2048_SHA256_GUID
, EFI_CERT_RSA2048_SHA1_GUID
};
26 // Public Exponent of RSA Key.
28 CONST UINT8 mRsaE
[] = { 0x01, 0x00, 0x01 };
31 Initializes for authenticated varibale service.
33 @retval EFI_SUCCESS The function successfully executed.
34 @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources.
38 AutenticatedVariableServiceInitialize (
43 VARIABLE_POINTER_TRACK Variable
;
48 VARIABLE_HEADER VariableHeader
;
51 ZeroMem (&VariableHeader
, sizeof (VARIABLE_HEADER
));
53 mVariableModuleGlobal
->AuthenticatedVariableGuid
[Physical
] = &gEfiAuthenticatedVariableGuid
;
54 mVariableModuleGlobal
->CertRsa2048Sha256Guid
[Physical
] = &gEfiCertRsa2048Sha256Guid
;
55 mVariableModuleGlobal
->ImageSecurityDatabaseGuid
[Physical
] = &gEfiImageSecurityDatabaseGuid
;
58 // Initialize hash context.
60 CtxSize
= Sha256GetContextSize ();
61 mVariableModuleGlobal
->HashContext
[Physical
] = AllocateRuntimePool (CtxSize
);
62 ASSERT (mVariableModuleGlobal
->HashContext
[Physical
] != NULL
);
64 // Check "AuthVarKeyDatabase" variable's existence.
65 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
67 Status
= FindVariable (
68 mVariableModuleGlobal
->VariableName
[Physical
][VAR_AUTH_KEY_DB
],
69 &gEfiAuthenticatedVariableGuid
,
71 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
72 mVariableModuleGlobal
->FvbInstance
75 if (Variable
.CurrPtr
== 0x0) {
76 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
79 Status
= UpdateVariable (
80 mVariableModuleGlobal
->VariableName
[Physical
][VAR_AUTH_KEY_DB
],
81 &gEfiAuthenticatedVariableGuid
,
88 mVariableModuleGlobal
,
91 if (EFI_ERROR (Status
)) {
96 // Load database in global variable for cache.
98 Valid
= IsValidVariableHeader (
101 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
102 mVariableModuleGlobal
->FvbInstance
,
107 DataSize
= DataSizeOfVariable (&VariableHeader
);
108 ASSERT (DataSize
<= MAX_KEYDB_SIZE
);
112 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
113 mVariableModuleGlobal
->FvbInstance
,
114 (CHAR16
*) mVariableModuleGlobal
->PubKeyStore
117 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
120 // Check "SetupMode" variable's existence.
121 // If it doesn't exist, check PK database's existence to determine the value.
122 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
124 Status
= FindVariable (
125 mVariableModuleGlobal
->VariableName
[Physical
][VAR_SETUP_MODE
],
126 &gEfiGlobalVariableGuid
,
128 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
129 mVariableModuleGlobal
->FvbInstance
132 if (Variable
.CurrPtr
== 0x0) {
133 Status
= FindVariable (
134 mVariableModuleGlobal
->VariableName
[Physical
][VAR_PLATFORM_KEY
],
135 &gEfiGlobalVariableGuid
,
137 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
138 mVariableModuleGlobal
->FvbInstance
140 if (Variable
.CurrPtr
== 0x0) {
141 mPlatformMode
= SETUP_MODE
;
143 mPlatformMode
= USER_MODE
;
146 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
147 Status
= UpdateVariable (
148 mVariableModuleGlobal
->VariableName
[Physical
][VAR_SETUP_MODE
],
149 &gEfiGlobalVariableGuid
,
156 mVariableModuleGlobal
,
159 if (EFI_ERROR (Status
)) {
166 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
167 mVariableModuleGlobal
->FvbInstance
,
168 (CHAR16
*) &mPlatformMode
172 // Check "SignatureSupport" variable's existence.
173 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
175 Status
= FindVariable (
176 EFI_SIGNATURE_SUPPORT_NAME
,
177 &gEfiGlobalVariableGuid
,
179 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
180 mVariableModuleGlobal
->FvbInstance
183 if (Variable
.CurrPtr
== 0x0) {
184 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
185 Status
= UpdateVariable (
186 EFI_SIGNATURE_SUPPORT_NAME
,
187 &gEfiGlobalVariableGuid
,
189 SIGSUPPORT_NUM
* sizeof(EFI_GUID
),
194 mVariableModuleGlobal
,
203 Add public key in store and return its index.
205 @param[in] VirtualMode The current calling mode for this function.
206 @param[in] Global The context of this Extended SAL Variable Services Class call.
207 @param[in] PubKey The input pointer to Public Key data.
209 @return The index of new added item.
214 IN BOOLEAN VirtualMode
,
215 IN ESAL_VARIABLE_GLOBAL
*Global
,
222 VARIABLE_POINTER_TRACK Variable
;
225 if (PubKey
== NULL
) {
229 Status
= FindVariable (
230 Global
->VariableName
[VirtualMode
][VAR_AUTH_KEY_DB
],
231 Global
->AuthenticatedVariableGuid
[VirtualMode
],
233 &Global
->VariableGlobal
[VirtualMode
],
236 ASSERT_EFI_ERROR (Status
);
238 // Check whether the public key entry does exist.
241 for (Ptr
= Global
->PubKeyStore
, Index
= 1; Index
<= mPubKeyNumber
; Index
++) {
242 if (CompareMem (Ptr
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
246 Ptr
+= EFI_CERT_TYPE_RSA2048_SIZE
;
251 // Add public key in database.
253 if (mPubKeyNumber
== MAX_KEY_NUM
) {
255 // Notes: Database is full, need enhancement here, currently just return 0.
260 CopyMem (Global
->PubKeyStore
+ mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
261 Index
= ++mPubKeyNumber
;
263 // Update public key database variable.
265 Status
= UpdateVariable (
266 Global
->VariableName
[VirtualMode
][VAR_AUTH_KEY_DB
],
267 Global
->AuthenticatedVariableGuid
[VirtualMode
],
269 mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
,
270 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
277 ASSERT_EFI_ERROR (Status
);
284 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
285 Follow the steps in UEFI2.2.
287 @param[in] VirtualMode The current calling mode for this function.
288 @param[in] Global The context of this Extended SAL Variable Services Class call.
289 @param[in] Data The pointer to data with AuthInfo.
290 @param[in] DataSize The size of Data.
291 @param[in] PubKey The public key used for verification.
293 @retval EFI_INVALID_PARAMETER Invalid parameter.
294 @retval EFI_SECURITY_VIOLATION Authentication failed.
295 @retval EFI_SUCCESS Authentication successful.
300 IN BOOLEAN VirtualMode
,
301 IN ESAL_VARIABLE_GLOBAL
*Global
,
308 EFI_VARIABLE_AUTHENTICATION
*CertData
;
309 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
310 UINT8 Digest
[SHA256_DIGEST_SIZE
];
318 if (Data
== NULL
|| PubKey
== NULL
) {
319 return EFI_INVALID_PARAMETER
;
322 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
323 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
326 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
327 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
329 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
330 !CompareGuid (&CertData
->AuthInfo
.CertType
, Global
->CertRsa2048Sha256Guid
[VirtualMode
])
333 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
335 return EFI_SECURITY_VIOLATION
;
339 // Hash data payload with SHA256.
341 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
342 HashContext
= Global
->HashContext
[VirtualMode
];
343 Status
= Sha256Init (HashContext
);
347 Status
= Sha256Update (HashContext
, Data
+ AUTHINFO_SIZE
, (UINTN
) (DataSize
- AUTHINFO_SIZE
));
352 // Hash Monotonic Count.
354 Status
= Sha256Update (HashContext
, &CertData
->MonotonicCount
, sizeof (UINT64
));
358 Status
= Sha256Final (HashContext
, Digest
);
363 // Generate & Initialize RSA Context.
366 ASSERT (Rsa
!= NULL
);
368 // Set RSA Key Components.
369 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
371 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
375 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
380 // Verify the signature.
382 Status
= RsaPkcs1Verify (
386 CertBlock
->Signature
,
387 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
397 return EFI_SECURITY_VIOLATION
;
403 Update platform mode.
405 @param[in] VirtualMode The current calling mode for this function.
406 @param[in] Global The context of this Extended SAL Variable Services Class call.
407 @param[in] Mode SETUP_MODE or USER_MODE.
412 IN BOOLEAN VirtualMode
,
413 IN ESAL_VARIABLE_GLOBAL
*Global
,
418 VARIABLE_POINTER_TRACK Variable
;
421 Status
= FindVariable (
422 Global
->VariableName
[VirtualMode
][VAR_SETUP_MODE
],
423 Global
->GlobalVariableGuid
[VirtualMode
],
425 &Global
->VariableGlobal
[VirtualMode
],
428 ASSERT_EFI_ERROR (Status
);
430 mPlatformMode
= Mode
;
431 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
432 Status
= UpdateVariable (
433 Global
->VariableName
[VirtualMode
][VAR_SETUP_MODE
],
434 Global
->GlobalVariableGuid
[VirtualMode
],
444 ASSERT_EFI_ERROR (Status
);
448 Process variable with platform key for verification.
450 @param[in] VariableName The name of Variable to be found.
451 @param[in] VendorGuid The variable vendor GUID.
452 @param[in] Data The data pointer.
453 @param[in] DataSize The size of Data found. If size is less than the
454 data, this value contains the required size.
455 @param[in] VirtualMode The current calling mode for this function.
456 @param[in] Global The context of this Extended SAL Variable Services Class call.
457 @param[in] Variable The variable information which is used to keep track of variable usage.
458 @param[in] Attributes The attribute value of the variable.
459 @param[in] IsPk Indicates whether to process pk.
461 @retval EFI_INVALID_PARAMETER Invalid parameter.
462 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
463 check carried out by the firmware.
464 @retval EFI_SUCCESS The variable passed validation successfully.
469 IN CHAR16
*VariableName
,
470 IN EFI_GUID
*VendorGuid
,
473 IN BOOLEAN VirtualMode
,
474 IN ESAL_VARIABLE_GLOBAL
*Global
,
475 IN VARIABLE_POINTER_TRACK
*Variable
,
476 IN UINT32 Attributes OPTIONAL
,
481 VARIABLE_POINTER_TRACK PkVariable
;
482 EFI_SIGNATURE_LIST
*OldPkList
;
483 EFI_SIGNATURE_DATA
*OldPkData
;
484 EFI_VARIABLE_AUTHENTICATION
*CertData
;
485 VARIABLE_HEADER VariableHeader
;
489 ZeroMem (&VariableHeader
, sizeof (VARIABLE_HEADER
));
491 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
493 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
495 return EFI_INVALID_PARAMETER
;
498 if (mPlatformMode
== USER_MODE
) {
499 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
501 // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
503 return EFI_INVALID_PARAMETER
;
506 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
508 if (Variable
->CurrPtr
!= 0x0) {
509 Valid
= IsValidVariableHeader (
512 &Global
->VariableGlobal
[VirtualMode
],
518 if (CertData
->MonotonicCount
<= VariableHeader
.MonotonicCount
) {
520 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
522 return EFI_SECURITY_VIOLATION
;
526 // Get platform key from variable.
528 Status
= FindVariable (
529 Global
->VariableName
[VirtualMode
][VAR_PLATFORM_KEY
],
530 Global
->GlobalVariableGuid
[VirtualMode
],
532 &Global
->VariableGlobal
[VirtualMode
],
535 ASSERT_EFI_ERROR (Status
);
537 ZeroMem (Global
->KeyList
, MAX_KEYDB_SIZE
);
541 &Global
->VariableGlobal
[VirtualMode
],
543 (CHAR16
*) Global
->KeyList
546 OldPkList
= (EFI_SIGNATURE_LIST
*) Global
->KeyList
;
547 OldPkData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) OldPkList
+ sizeof (EFI_SIGNATURE_LIST
) + OldPkList
->SignatureHeaderSize
);
548 Status
= VerifyDataPayload (VirtualMode
, Global
, Data
, DataSize
, OldPkData
->SignatureData
);
549 if (!EFI_ERROR (Status
)) {
550 Status
= UpdateVariable (
553 (UINT8
*)Data
+ AUTHINFO_SIZE
,
554 DataSize
- AUTHINFO_SIZE
,
557 CertData
->MonotonicCount
,
563 if (!EFI_ERROR (Status
)) {
565 // If delete PK in user mode, need change to setup mode.
567 if ((DataSize
== AUTHINFO_SIZE
) && IsPk
) {
568 UpdatePlatformMode (VirtualMode
, Global
, SETUP_MODE
);
573 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, VirtualMode
, Global
, Variable
);
575 // If enroll PK in setup mode, need change to user mode.
577 if ((DataSize
!= 0) && IsPk
) {
578 UpdatePlatformMode (VirtualMode
, Global
, USER_MODE
);
586 Process variable with key exchange key for verification.
588 @param[in] VariableName The name of Variable to be found.
589 @param[in] VendorGuid The variable vendor GUID.
590 @param[in] Data The data pointer.
591 @param[in] DataSize The size of Data found. If size is less than the
592 data, this value contains the required size.
593 @param[in] VirtualMode The current calling mode for this function.
594 @param[in] Global The context of this Extended SAL Variable Services Class call.
595 @param[in] Variable The variable information which is used to keep track of variable usage.
596 @param[in] Attributes The attribute value of the variable.
598 @retval EFI_INVALID_PARAMETER Invalid parameter.
599 @retval EFI_SECURITY_VIOLATION The variable did NOT pass the validation
600 check carried out by the firmware.
601 @retval EFI_SUCCESS The variable passed validation successfully.
606 IN CHAR16
*VariableName
,
607 IN EFI_GUID
*VendorGuid
,
610 IN BOOLEAN VirtualMode
,
611 IN ESAL_VARIABLE_GLOBAL
*Global
,
612 IN VARIABLE_POINTER_TRACK
*Variable
,
613 IN UINT32 Attributes OPTIONAL
617 VARIABLE_POINTER_TRACK KekVariable
;
618 EFI_SIGNATURE_LIST
*KekList
;
619 EFI_SIGNATURE_DATA
*KekItem
;
621 EFI_VARIABLE_AUTHENTICATION
*CertData
;
622 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
625 VARIABLE_HEADER VariableHeader
;
629 ZeroMem (&VariableHeader
, sizeof (VARIABLE_HEADER
));
631 if (mPlatformMode
== USER_MODE
) {
632 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
634 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
636 return EFI_INVALID_PARAMETER
;
639 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
640 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
641 if (Variable
->CurrPtr
!= 0x0) {
642 Valid
= IsValidVariableHeader (
645 &Global
->VariableGlobal
[VirtualMode
],
651 if (CertData
->MonotonicCount
<= VariableHeader
.MonotonicCount
) {
653 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
655 return EFI_SECURITY_VIOLATION
;
659 // Get KEK database from variable.
661 Status
= FindVariable (
662 Global
->VariableName
[VirtualMode
][VAR_KEY_EXCHANGE_KEY
],
663 Global
->GlobalVariableGuid
[VirtualMode
],
665 &Global
->VariableGlobal
[VirtualMode
],
668 ASSERT_EFI_ERROR (Status
);
670 ZeroMem (Global
->KeyList
, MAX_KEYDB_SIZE
);
673 KekVariable
.Volatile
,
674 &Global
->VariableGlobal
[VirtualMode
],
676 (CHAR16
*) Global
->KeyList
679 // Enumerate all Kek items in this list to verify the variable certificate data.
680 // If anyone is authenticated successfully, it means the variable is correct!
682 KekList
= (EFI_SIGNATURE_LIST
*) Global
->KeyList
;
684 KekCount
= (KekList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - KekList
->SignatureHeaderSize
) / KekList
->SignatureSize
;
685 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekList
+ sizeof (EFI_SIGNATURE_LIST
) + KekList
->SignatureHeaderSize
);
686 for (Index
= 0; Index
< KekCount
; Index
++) {
687 if (CompareMem (KekItem
->SignatureData
, CertBlock
->PublicKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
691 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekItem
+ KekList
->SignatureSize
);
695 return EFI_SECURITY_VIOLATION
;
698 Status
= VerifyDataPayload (VirtualMode
, Global
, Data
, DataSize
, CertBlock
->PublicKey
);
699 if (!EFI_ERROR (Status
)) {
700 Status
= UpdateVariable (
703 (UINT8
*)Data
+ AUTHINFO_SIZE
,
704 DataSize
- AUTHINFO_SIZE
,
707 CertData
->MonotonicCount
,
715 // If in setup mode, no authentication needed.
717 Status
= UpdateVariable (
735 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
737 @param[in] Data The data pointer.
738 @param[in] DataSize The size of Data found. If size is less than the
739 data, this value contains the required size.
740 @param[in] VirtualMode The current calling mode for this function.
741 @param[in] Global The context of this Extended SAL Variable Services Class call.
742 @param[in] Variable The variable information which is used to keep track of variable usage.
743 @param[in] Attributes The attribute value of the variable.
744 @param[out] KeyIndex The output index of corresponding public key in database.
745 @param[out] MonotonicCount The output value of corresponding Monotonic Count.
747 @retval EFI_INVALID_PARAMETER Invalid parameter.
748 @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with
749 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
750 @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
751 set, but the AuthInfo does NOT pass the validation
752 check carried out by the firmware.
753 @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully.
760 IN BOOLEAN VirtualMode
,
761 IN ESAL_VARIABLE_GLOBAL
*Global
,
762 IN VARIABLE_POINTER_TRACK
*Variable
,
763 IN UINT32 Attributes OPTIONAL
,
764 OUT UINT32
*KeyIndex OPTIONAL
,
765 OUT UINT64
*MonotonicCount OPTIONAL
772 EFI_VARIABLE_AUTHENTICATION
*CertData
;
773 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
774 VARIABLE_HEADER VariableHeader
;
783 if (KeyIndex
!= NULL
) {
787 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
789 ZeroMem (&VariableHeader
, sizeof (VARIABLE_HEADER
));
790 if (Variable
->CurrPtr
!= 0x0) {
791 Valid
= IsValidVariableHeader (
794 &Global
->VariableGlobal
[VirtualMode
],
801 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
802 if (KeyIndex
== NULL
) {
803 return EFI_INVALID_PARAMETER
;
807 // Determine current operation type.
809 if (DataSize
== AUTHINFO_SIZE
) {
813 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
815 if (Variable
->CurrPtr
== 0x0) {
817 } else if (Valid
&&(VariableHeader
.Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
820 *KeyIndex
= VariableHeader
.PubKeyIndex
;
823 } else if (Valid
&& (VariableHeader
.Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
825 // If the variable is already write-protected, it always needs authentication before update.
827 return EFI_WRITE_PROTECTED
;
830 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
831 // That means it is not authenticated variable, just return EFI_SUCCESS.
837 // Get PubKey and check Monotonic Count value corresponding to the variable.
839 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
840 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
841 PubKey
= CertBlock
->PublicKey
;
843 if (MonotonicCount
!= NULL
) {
845 // Update Monotonic Count value.
847 *MonotonicCount
= CertData
->MonotonicCount
;
852 // Check input PubKey.
854 if (CompareMem (PubKey
, Global
->PubKeyStore
+ (*KeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
, EFI_CERT_TYPE_RSA2048_SIZE
) != 0) {
855 return EFI_SECURITY_VIOLATION
;
858 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
859 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
861 if (CertData
->MonotonicCount
<= VariableHeader
.MonotonicCount
) {
863 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
865 return EFI_SECURITY_VIOLATION
;
869 // Verify the certificate in Data payload.
871 Status
= VerifyDataPayload (VirtualMode
, Global
, Data
, DataSize
, PubKey
);
872 if (!EFI_ERROR (Status
)) {
874 // Now, the signature has been verified!
876 if (IsFirstTime
&& !IsDeletion
) {
878 // Update public key database variable if need and return the index.
880 *KeyIndex
= AddPubKeyInStore (VirtualMode
, Global
, PubKey
);