2 Implement authentication services for the authenticated variable
5 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "AuthService.h"
20 /// Global database array for scratch
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 mVariableModuleGlobal
->AuthenticatedVariableGuid
[Physical
] = &gEfiAuthenticatedVariableGuid
;
52 mVariableModuleGlobal
->CertRsa2048Sha256Guid
[Physical
] = &gEfiCertRsa2048Sha256Guid
;
53 mVariableModuleGlobal
->ImageSecurityDatabaseGuid
[Physical
] = &gEfiImageSecurityDatabaseGuid
;
56 // Initialize hash context.
58 CtxSize
= Sha256GetContextSize ();
59 mVariableModuleGlobal
->HashContext
[Physical
] = AllocateRuntimePool (CtxSize
);
60 ASSERT (mVariableModuleGlobal
->HashContext
[Physical
] != NULL
);
62 // Check "AuthVarKeyDatabase" variable's existence.
63 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
65 Status
= FindVariable (
66 mVariableModuleGlobal
->VariableName
[Physical
][VAR_AUTH_KEY_DB
],
67 &gEfiAuthenticatedVariableGuid
,
69 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
70 mVariableModuleGlobal
->FvbInstance
73 if (Variable
.CurrPtr
== 0x0) {
74 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
77 Status
= UpdateVariable (
78 mVariableModuleGlobal
->VariableName
[Physical
][VAR_AUTH_KEY_DB
],
79 &gEfiAuthenticatedVariableGuid
,
86 mVariableModuleGlobal
,
89 if (EFI_ERROR (Status
)) {
94 // Load database in global variable for cache.
96 Valid
= IsValidVariableHeader (
99 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
100 mVariableModuleGlobal
->FvbInstance
,
105 DataSize
= DataSizeOfVariable (&VariableHeader
);
106 ASSERT (DataSize
<= MAX_KEYDB_SIZE
);
110 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
111 mVariableModuleGlobal
->FvbInstance
,
112 (CHAR16
*) mVariableModuleGlobal
->PubKeyStore
115 mPubKeyNumber
= (UINT32
) (DataSize
/ EFI_CERT_TYPE_RSA2048_SIZE
);
118 // Check "SetupMode" variable's existence.
119 // If it doesn't exist, check PK database's existence to determine the value.
120 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
122 Status
= FindVariable (
123 mVariableModuleGlobal
->VariableName
[Physical
][VAR_SETUP_MODE
],
124 &gEfiGlobalVariableGuid
,
126 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
127 mVariableModuleGlobal
->FvbInstance
130 if (Variable
.CurrPtr
== 0x0) {
131 Status
= FindVariable (
132 mVariableModuleGlobal
->VariableName
[Physical
][VAR_PLATFORM_KEY
],
133 &gEfiGlobalVariableGuid
,
135 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
136 mVariableModuleGlobal
->FvbInstance
138 if (Variable
.CurrPtr
== 0x0) {
139 mPlatformMode
= SETUP_MODE
;
141 mPlatformMode
= USER_MODE
;
144 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
145 Status
= UpdateVariable (
146 mVariableModuleGlobal
->VariableName
[Physical
][VAR_SETUP_MODE
],
147 &gEfiGlobalVariableGuid
,
154 mVariableModuleGlobal
,
157 if (EFI_ERROR (Status
)) {
164 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
165 mVariableModuleGlobal
->FvbInstance
,
166 (CHAR16
*) &mPlatformMode
170 // Check "SignatureSupport" variable's existence.
171 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
173 Status
= FindVariable (
174 EFI_SIGNATURE_SUPPORT_NAME
,
175 &gEfiGlobalVariableGuid
,
177 &mVariableModuleGlobal
->VariableGlobal
[Physical
],
178 mVariableModuleGlobal
->FvbInstance
181 if (Variable
.CurrPtr
== 0x0) {
182 VarAttr
= EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
183 Status
= UpdateVariable (
184 EFI_SIGNATURE_SUPPORT_NAME
,
185 &gEfiGlobalVariableGuid
,
187 SIGSUPPORT_NUM
* sizeof(EFI_GUID
),
192 mVariableModuleGlobal
,
201 Add public key in store and return its index.
203 @param[in] VirtualMode The current calling mode for this function.
204 @param[in] Global The context of this Extended SAL Variable Services Class call.
205 @param[in] PubKey The input pointer to Public Key data.
207 @return The index of new added item.
212 IN BOOLEAN VirtualMode
,
213 IN ESAL_VARIABLE_GLOBAL
*Global
,
220 VARIABLE_POINTER_TRACK Variable
;
223 if (PubKey
== NULL
) {
227 Status
= FindVariable (
228 Global
->VariableName
[VirtualMode
][VAR_AUTH_KEY_DB
],
229 Global
->AuthenticatedVariableGuid
[VirtualMode
],
231 &Global
->VariableGlobal
[VirtualMode
],
234 ASSERT_EFI_ERROR (Status
);
236 // Check whether the public key entry does exist.
239 for (Ptr
= Global
->PubKeyStore
, Index
= 1; Index
<= mPubKeyNumber
; Index
++) {
240 if (CompareMem (Ptr
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
244 Ptr
+= EFI_CERT_TYPE_RSA2048_SIZE
;
249 // Add public key in database.
251 if (mPubKeyNumber
== MAX_KEY_NUM
) {
253 // Notes: Database is full, need enhancement here, currently just return 0.
258 CopyMem (Global
->PubKeyStore
+ mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
259 Index
= ++mPubKeyNumber
;
261 // Update public key database variable.
263 Status
= UpdateVariable (
264 Global
->VariableName
[VirtualMode
][VAR_AUTH_KEY_DB
],
265 Global
->AuthenticatedVariableGuid
[VirtualMode
],
267 mPubKeyNumber
* EFI_CERT_TYPE_RSA2048_SIZE
,
268 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
,
275 ASSERT_EFI_ERROR (Status
);
282 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
283 Follow the steps in UEFI2.2.
285 @param[in] VirtualMode The current calling mode for this function.
286 @param[in] Global The context of this Extended SAL Variable Services Class call.
287 @param[in] Data The pointer to data with AuthInfo.
288 @param[in] DataSize The size of Data.
289 @param[in] PubKey The public key used for verification.
291 @retval EFI_INVALID_PARAMETER Invalid parameter.
292 @retval EFI_SECURITY_VIOLATION Authentication failed.
293 @retval EFI_SUCCESS Authentication successful.
298 IN BOOLEAN VirtualMode
,
299 IN ESAL_VARIABLE_GLOBAL
*Global
,
306 EFI_VARIABLE_AUTHENTICATION
*CertData
;
307 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
308 UINT8 Digest
[SHA256_DIGEST_SIZE
];
316 if (Data
== NULL
|| PubKey
== NULL
) {
317 return EFI_INVALID_PARAMETER
;
320 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
321 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
324 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
325 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
327 if ((CertData
->AuthInfo
.Hdr
.wCertificateType
!= WIN_CERT_TYPE_EFI_GUID
) ||
328 !CompareGuid (&CertData
->AuthInfo
.CertType
, Global
->CertRsa2048Sha256Guid
[VirtualMode
])
331 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
333 return EFI_SECURITY_VIOLATION
;
337 // Hash data payload with SHA256.
339 ZeroMem (Digest
, SHA256_DIGEST_SIZE
);
340 HashContext
= Global
->HashContext
[VirtualMode
];
341 Status
= Sha256Init (HashContext
);
345 Status
= Sha256Update (HashContext
, Data
+ AUTHINFO_SIZE
, (UINTN
) (DataSize
- AUTHINFO_SIZE
));
350 // Hash Monotonic Count.
352 Status
= Sha256Update (HashContext
, &CertData
->MonotonicCount
, sizeof (UINT64
));
356 Status
= Sha256Final (HashContext
, Digest
);
361 // Generate & Initialize RSA Context.
364 ASSERT (Rsa
!= NULL
);
366 // Set RSA Key Components.
367 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
369 Status
= RsaSetKey (Rsa
, RsaKeyN
, PubKey
, EFI_CERT_TYPE_RSA2048_SIZE
);
373 Status
= RsaSetKey (Rsa
, RsaKeyE
, mRsaE
, sizeof (mRsaE
));
378 // Verify the signature.
380 Status
= RsaPkcs1Verify (
384 CertBlock
->Signature
,
385 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
395 return EFI_SECURITY_VIOLATION
;
401 Update platform mode.
403 @param[in] VirtualMode The current calling mode for this function.
404 @param[in] Global The context of this Extended SAL Variable Services Class call.
405 @param[in] Mode SETUP_MODE or USER_MODE.
410 IN BOOLEAN VirtualMode
,
411 IN ESAL_VARIABLE_GLOBAL
*Global
,
416 VARIABLE_POINTER_TRACK Variable
;
419 Status
= FindVariable (
420 Global
->VariableName
[VirtualMode
][VAR_SETUP_MODE
],
421 Global
->GlobalVariableGuid
[VirtualMode
],
423 &Global
->VariableGlobal
[VirtualMode
],
426 ASSERT_EFI_ERROR (Status
);
428 mPlatformMode
= Mode
;
429 VarAttr
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
;
430 Status
= UpdateVariable (
431 Global
->VariableName
[VirtualMode
][VAR_SETUP_MODE
],
432 Global
->GlobalVariableGuid
[VirtualMode
],
442 ASSERT_EFI_ERROR (Status
);
446 Process variable with platform key for verification.
448 @param[in] VariableName The name of Variable to be found.
449 @param[in] VendorGuid The variable vendor GUID.
450 @param[in] Data The data pointer.
451 @param[in] DataSize The size of Data found. If size is less than the
452 data, this value contains the required size.
453 @param[in] VirtualMode The current calling mode for this function.
454 @param[in] Global The context of this Extended SAL Variable Services Class call.
455 @param[in] Variable The variable information which is used to keep track of variable usage.
456 @param[in] Attributes The attribute value of the variable.
457 @param[in] IsPk Indicates whether to process pk.
459 @retval EFI_INVALID_PARAMETER Invalid parameter.
460 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
461 check carried out by the firmware.
462 @retval EFI_SUCCESS The variable passed validation successfully.
467 IN CHAR16
*VariableName
,
468 IN EFI_GUID
*VendorGuid
,
471 IN BOOLEAN VirtualMode
,
472 IN ESAL_VARIABLE_GLOBAL
*Global
,
473 IN VARIABLE_POINTER_TRACK
*Variable
,
474 IN UINT32 Attributes OPTIONAL
,
479 VARIABLE_POINTER_TRACK PkVariable
;
480 EFI_SIGNATURE_LIST
*OldPkList
;
481 EFI_SIGNATURE_DATA
*OldPkData
;
482 EFI_VARIABLE_AUTHENTICATION
*CertData
;
483 VARIABLE_HEADER VariableHeader
;
488 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
490 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
492 return EFI_INVALID_PARAMETER
;
495 if (mPlatformMode
== USER_MODE
) {
496 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
498 // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
500 return EFI_INVALID_PARAMETER
;
503 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
505 if (Variable
->CurrPtr
!= 0x0) {
506 Valid
= IsValidVariableHeader (
509 &Global
->VariableGlobal
[VirtualMode
],
515 if (CertData
->MonotonicCount
<= VariableHeader
.MonotonicCount
) {
517 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
519 return EFI_SECURITY_VIOLATION
;
523 // Get platform key from variable.
525 Status
= FindVariable (
526 Global
->VariableName
[VirtualMode
][VAR_PLATFORM_KEY
],
527 Global
->GlobalVariableGuid
[VirtualMode
],
529 &Global
->VariableGlobal
[VirtualMode
],
532 ASSERT_EFI_ERROR (Status
);
534 ZeroMem (Global
->KeyList
, MAX_KEYDB_SIZE
);
538 &Global
->VariableGlobal
[VirtualMode
],
540 (CHAR16
*) Global
->KeyList
543 OldPkList
= (EFI_SIGNATURE_LIST
*) Global
->KeyList
;
544 OldPkData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) OldPkList
+ sizeof (EFI_SIGNATURE_LIST
) + OldPkList
->SignatureHeaderSize
);
545 Status
= VerifyDataPayload (VirtualMode
, Global
, Data
, DataSize
, OldPkData
->SignatureData
);
546 if (!EFI_ERROR (Status
)) {
547 Status
= UpdateVariable (
550 (UINT8
*)Data
+ AUTHINFO_SIZE
,
551 DataSize
- AUTHINFO_SIZE
,
554 CertData
->MonotonicCount
,
560 if (!EFI_ERROR (Status
)) {
562 // If delete PK in user mode, need change to setup mode.
564 if ((DataSize
== AUTHINFO_SIZE
) && IsPk
) {
565 UpdatePlatformMode (VirtualMode
, Global
, SETUP_MODE
);
570 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, 0, 0, VirtualMode
, Global
, Variable
);
572 // If enroll PK in setup mode, need change to user mode.
574 if ((DataSize
!= 0) && IsPk
) {
575 UpdatePlatformMode (VirtualMode
, Global
, USER_MODE
);
583 Process variable with key exchange key for verification.
585 @param[in] VariableName The name of Variable to be found.
586 @param[in] VendorGuid The variable vendor GUID.
587 @param[in] Data The data pointer.
588 @param[in] DataSize The size of Data found. If size is less than the
589 data, this value contains the required size.
590 @param[in] VirtualMode The current calling mode for this function.
591 @param[in] Global The context of this Extended SAL Variable Services Class call.
592 @param[in] Variable The variable information which is used to keep track of variable usage.
593 @param[in] Attributes The attribute value of the variable.
595 @retval EFI_INVALID_PARAMETER Invalid parameter.
596 @retval EFI_SECURITY_VIOLATION The variable did NOT pass the validation
597 check carried out by the firmware.
598 @retval EFI_SUCCESS The variable passed validation successfully.
603 IN CHAR16
*VariableName
,
604 IN EFI_GUID
*VendorGuid
,
607 IN BOOLEAN VirtualMode
,
608 IN ESAL_VARIABLE_GLOBAL
*Global
,
609 IN VARIABLE_POINTER_TRACK
*Variable
,
610 IN UINT32 Attributes OPTIONAL
614 VARIABLE_POINTER_TRACK KekVariable
;
615 EFI_SIGNATURE_LIST
*KekList
;
616 EFI_SIGNATURE_DATA
*KekItem
;
618 EFI_VARIABLE_AUTHENTICATION
*CertData
;
619 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
622 VARIABLE_HEADER VariableHeader
;
627 if (mPlatformMode
== USER_MODE
) {
628 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
630 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
632 return EFI_INVALID_PARAMETER
;
635 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
636 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
637 if (Variable
->CurrPtr
!= 0x0) {
638 Valid
= IsValidVariableHeader (
641 &Global
->VariableGlobal
[VirtualMode
],
647 if (CertData
->MonotonicCount
<= VariableHeader
.MonotonicCount
) {
649 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
651 return EFI_SECURITY_VIOLATION
;
655 // Get KEK database from variable.
657 Status
= FindVariable (
658 Global
->VariableName
[VirtualMode
][VAR_KEY_EXCHANGE_KEY
],
659 Global
->GlobalVariableGuid
[VirtualMode
],
661 &Global
->VariableGlobal
[VirtualMode
],
664 ASSERT_EFI_ERROR (Status
);
666 ZeroMem (Global
->KeyList
, MAX_KEYDB_SIZE
);
669 KekVariable
.Volatile
,
670 &Global
->VariableGlobal
[VirtualMode
],
672 (CHAR16
*) Global
->KeyList
675 // Enumerate all Kek items in this list to verify the variable certificate data.
676 // If anyone is authenticated successfully, it means the variable is correct!
678 KekList
= (EFI_SIGNATURE_LIST
*) Global
->KeyList
;
680 KekCount
= (KekList
->SignatureListSize
- sizeof (EFI_SIGNATURE_LIST
) - KekList
->SignatureHeaderSize
) / KekList
->SignatureSize
;
681 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekList
+ sizeof (EFI_SIGNATURE_LIST
) + KekList
->SignatureHeaderSize
);
682 for (Index
= 0; Index
< KekCount
; Index
++) {
683 if (CompareMem (KekItem
->SignatureData
, CertBlock
->PublicKey
, EFI_CERT_TYPE_RSA2048_SIZE
) == 0) {
687 KekItem
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) KekItem
+ KekList
->SignatureSize
);
691 return EFI_SECURITY_VIOLATION
;
694 Status
= VerifyDataPayload (VirtualMode
, Global
, Data
, DataSize
, CertBlock
->PublicKey
);
695 if (!EFI_ERROR (Status
)) {
696 Status
= UpdateVariable (
699 (UINT8
*)Data
+ AUTHINFO_SIZE
,
700 DataSize
- AUTHINFO_SIZE
,
703 CertData
->MonotonicCount
,
711 // If in setup mode, no authentication needed.
713 Status
= UpdateVariable (
731 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
733 @param[in] Data The data pointer.
734 @param[in] DataSize The size of Data found. If size is less than the
735 data, this value contains the required size.
736 @param[in] VirtualMode The current calling mode for this function.
737 @param[in] Global The context of this Extended SAL Variable Services Class call.
738 @param[in] Variable The variable information which is used to keep track of variable usage.
739 @param[in] Attributes The attribute value of the variable.
740 @param[out] KeyIndex The output index of corresponding public key in database.
741 @param[out] MonotonicCount The output value of corresponding Monotonic Count.
743 @retval EFI_INVALID_PARAMETER Invalid parameter.
744 @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with
745 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
746 @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
747 set, but the AuthInfo does NOT pass the validation
748 check carried out by the firmware.
749 @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully.
756 IN BOOLEAN VirtualMode
,
757 IN ESAL_VARIABLE_GLOBAL
*Global
,
758 IN VARIABLE_POINTER_TRACK
*Variable
,
759 IN UINT32 Attributes OPTIONAL
,
760 OUT UINT32
*KeyIndex OPTIONAL
,
761 OUT UINT64
*MonotonicCount OPTIONAL
768 EFI_VARIABLE_AUTHENTICATION
*CertData
;
769 EFI_CERT_BLOCK_RSA_2048_SHA256
*CertBlock
;
770 VARIABLE_HEADER VariableHeader
;
779 if (KeyIndex
!= NULL
) {
783 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
785 ZeroMem (&VariableHeader
, sizeof (VARIABLE_HEADER
));
786 if (Variable
->CurrPtr
!= 0x0) {
787 Valid
= IsValidVariableHeader (
790 &Global
->VariableGlobal
[VirtualMode
],
797 if ((Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
798 if (KeyIndex
== NULL
) {
799 return EFI_INVALID_PARAMETER
;
803 // Determine current operation type.
805 if (DataSize
== AUTHINFO_SIZE
) {
809 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
811 if (Variable
->CurrPtr
== 0x0) {
813 } else if (Valid
&&(VariableHeader
.Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) == 0) {
816 *KeyIndex
= VariableHeader
.PubKeyIndex
;
819 } else if (Valid
&& (VariableHeader
.Attributes
& EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
) != 0) {
821 // If the variable is already write-protected, it always needs authentication before update.
823 return EFI_WRITE_PROTECTED
;
826 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
827 // That means it is not authenticated variable, just return EFI_SUCCESS.
833 // Get PubKey and check Monotonic Count value corresponding to the variable.
835 CertData
= (EFI_VARIABLE_AUTHENTICATION
*) Data
;
836 CertBlock
= (EFI_CERT_BLOCK_RSA_2048_SHA256
*) (CertData
->AuthInfo
.CertData
);
837 PubKey
= CertBlock
->PublicKey
;
839 if (MonotonicCount
!= NULL
) {
841 // Update Monotonic Count value.
843 *MonotonicCount
= CertData
->MonotonicCount
;
848 // Check input PubKey.
850 if (CompareMem (PubKey
, Global
->PubKeyStore
+ (*KeyIndex
- 1) * EFI_CERT_TYPE_RSA2048_SIZE
, EFI_CERT_TYPE_RSA2048_SIZE
) != 0) {
851 return EFI_SECURITY_VIOLATION
;
854 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
855 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
857 if (CertData
->MonotonicCount
<= VariableHeader
.MonotonicCount
) {
859 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
861 return EFI_SECURITY_VIOLATION
;
865 // Verify the certificate in Data payload.
867 Status
= VerifyDataPayload (VirtualMode
, Global
, Data
, DataSize
, PubKey
);
868 if (!EFI_ERROR (Status
)) {
870 // Now, the signature has been verified!
872 if (IsFirstTime
&& !IsDeletion
) {
874 // Update public key database variable if need and return the index.
876 *KeyIndex
= AddPubKeyInStore (VirtualMode
, Global
, PubKey
);