]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c
Add security package to repository.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / EsalVariableDxeSal / AuthService.c
1 /** @file
2 Implement authentication services for the authenticated variable
3 service in UEFI2.2.
4
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
10
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.
13
14 **/
15
16 #include "Variable.h"
17 #include "AuthService.h"
18
19 ///
20 /// Global database array for scratch
21 ///
22 UINT32 mPubKeyNumber;
23 UINT32 mPlatformMode;
24 EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
25 //
26 // Public Exponent of RSA Key.
27 //
28 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
29
30 /**
31 Initializes for authenticated varibale service.
32
33 @retval EFI_SUCCESS The function successfully executed.
34 @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources.
35
36 **/
37 EFI_STATUS
38 AutenticatedVariableServiceInitialize (
39 VOID
40 )
41 {
42 EFI_STATUS Status;
43 VARIABLE_POINTER_TRACK Variable;
44 UINT8 VarValue;
45 UINT32 VarAttr;
46 UINTN DataSize;
47 UINTN CtxSize;
48 VARIABLE_HEADER VariableHeader;
49 BOOLEAN Valid;
50
51 mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;
52 mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical] = &gEfiCertRsa2048Sha256Guid;
53 mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;
54
55 //
56 // Initialize hash context.
57 //
58 CtxSize = Sha256GetContextSize ();
59 mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);
60 ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);
61 //
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.
64 //
65 Status = FindVariable (
66 mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
67 &gEfiAuthenticatedVariableGuid,
68 &Variable,
69 &mVariableModuleGlobal->VariableGlobal[Physical],
70 mVariableModuleGlobal->FvbInstance
71 );
72
73 if (Variable.CurrPtr == 0x0) {
74 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
75 VarValue = 0;
76 mPubKeyNumber = 0;
77 Status = UpdateVariable (
78 mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
79 &gEfiAuthenticatedVariableGuid,
80 &VarValue,
81 sizeof(UINT8),
82 VarAttr,
83 0,
84 0,
85 FALSE,
86 mVariableModuleGlobal,
87 &Variable
88 );
89 if (EFI_ERROR (Status)) {
90 return Status;
91 }
92 } else {
93 //
94 // Load database in global variable for cache.
95 //
96 Valid = IsValidVariableHeader (
97 Variable.CurrPtr,
98 Variable.Volatile,
99 &mVariableModuleGlobal->VariableGlobal[Physical],
100 mVariableModuleGlobal->FvbInstance,
101 &VariableHeader
102 );
103 ASSERT (Valid);
104
105 DataSize = DataSizeOfVariable (&VariableHeader);
106 ASSERT (DataSize <= MAX_KEYDB_SIZE);
107 GetVariableDataPtr (
108 Variable.CurrPtr,
109 Variable.Volatile,
110 &mVariableModuleGlobal->VariableGlobal[Physical],
111 mVariableModuleGlobal->FvbInstance,
112 (CHAR16 *) mVariableModuleGlobal->PubKeyStore
113 );
114
115 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
116 }
117 //
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.
121 //
122 Status = FindVariable (
123 mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
124 &gEfiGlobalVariableGuid,
125 &Variable,
126 &mVariableModuleGlobal->VariableGlobal[Physical],
127 mVariableModuleGlobal->FvbInstance
128 );
129
130 if (Variable.CurrPtr == 0x0) {
131 Status = FindVariable (
132 mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY],
133 &gEfiGlobalVariableGuid,
134 &Variable,
135 &mVariableModuleGlobal->VariableGlobal[Physical],
136 mVariableModuleGlobal->FvbInstance
137 );
138 if (Variable.CurrPtr == 0x0) {
139 mPlatformMode = SETUP_MODE;
140 } else {
141 mPlatformMode = USER_MODE;
142 }
143
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,
148 &mPlatformMode,
149 sizeof(UINT8),
150 VarAttr,
151 0,
152 0,
153 FALSE,
154 mVariableModuleGlobal,
155 &Variable
156 );
157 if (EFI_ERROR (Status)) {
158 return Status;
159 }
160 } else {
161 GetVariableDataPtr (
162 Variable.CurrPtr,
163 Variable.Volatile,
164 &mVariableModuleGlobal->VariableGlobal[Physical],
165 mVariableModuleGlobal->FvbInstance,
166 (CHAR16 *) &mPlatformMode
167 );
168 }
169 //
170 // Check "SignatureSupport" variable's existence.
171 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
172 //
173 Status = FindVariable (
174 EFI_SIGNATURE_SUPPORT_NAME,
175 &gEfiGlobalVariableGuid,
176 &Variable,
177 &mVariableModuleGlobal->VariableGlobal[Physical],
178 mVariableModuleGlobal->FvbInstance
179 );
180
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,
186 mSignatureSupport,
187 SIGSUPPORT_NUM * sizeof(EFI_GUID),
188 VarAttr,
189 0,
190 0,
191 FALSE,
192 mVariableModuleGlobal,
193 &Variable
194 );
195 }
196
197 return Status;
198 }
199
200 /**
201 Add public key in store and return its index.
202
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.
206
207 @return The index of new added item.
208
209 **/
210 UINT32
211 AddPubKeyInStore (
212 IN BOOLEAN VirtualMode,
213 IN ESAL_VARIABLE_GLOBAL *Global,
214 IN UINT8 *PubKey
215 )
216 {
217 EFI_STATUS Status;
218 BOOLEAN IsFound;
219 UINT32 Index;
220 VARIABLE_POINTER_TRACK Variable;
221 UINT8 *Ptr;
222
223 if (PubKey == NULL) {
224 return 0;
225 }
226
227 Status = FindVariable (
228 Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
229 Global->AuthenticatedVariableGuid[VirtualMode],
230 &Variable,
231 &Global->VariableGlobal[VirtualMode],
232 Global->FvbInstance
233 );
234 ASSERT_EFI_ERROR (Status);
235 //
236 // Check whether the public key entry does exist.
237 //
238 IsFound = FALSE;
239 for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
240 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
241 IsFound = TRUE;
242 break;
243 }
244 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
245 }
246
247 if (!IsFound) {
248 //
249 // Add public key in database.
250 //
251 if (mPubKeyNumber == MAX_KEY_NUM) {
252 //
253 // Notes: Database is full, need enhancement here, currently just return 0.
254 //
255 return 0;
256 }
257
258 CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
259 Index = ++mPubKeyNumber;
260 //
261 // Update public key database variable.
262 //
263 Status = UpdateVariable (
264 Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
265 Global->AuthenticatedVariableGuid[VirtualMode],
266 Global->PubKeyStore,
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,
269 0,
270 0,
271 VirtualMode,
272 Global,
273 &Variable
274 );
275 ASSERT_EFI_ERROR (Status);
276 }
277
278 return Index;
279 }
280
281 /**
282 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
283 Follow the steps in UEFI2.2.
284
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.
290
291 @retval EFI_INVALID_PARAMETER Invalid parameter.
292 @retval EFI_SECURITY_VIOLATION Authentication failed.
293 @retval EFI_SUCCESS Authentication successful.
294
295 **/
296 EFI_STATUS
297 VerifyDataPayload (
298 IN BOOLEAN VirtualMode,
299 IN ESAL_VARIABLE_GLOBAL *Global,
300 IN UINT8 *Data,
301 IN UINTN DataSize,
302 IN UINT8 *PubKey
303 )
304 {
305 BOOLEAN Status;
306 EFI_VARIABLE_AUTHENTICATION *CertData;
307 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
308 UINT8 Digest[SHA256_DIGEST_SIZE];
309 VOID *Rsa;
310 VOID *HashContext;
311
312 Rsa = NULL;
313 CertData = NULL;
314 CertBlock = NULL;
315
316 if (Data == NULL || PubKey == NULL) {
317 return EFI_INVALID_PARAMETER;
318 }
319
320 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
321 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
322
323 //
324 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
325 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
326 //
327 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
328 !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])
329 ) {
330 //
331 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
332 //
333 return EFI_SECURITY_VIOLATION;
334 }
335
336 //
337 // Hash data payload with SHA256.
338 //
339 ZeroMem (Digest, SHA256_DIGEST_SIZE);
340 HashContext = Global->HashContext[VirtualMode];
341 Status = Sha256Init (HashContext);
342 if (!Status) {
343 goto Done;
344 }
345 Status = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
346 if (!Status) {
347 goto Done;
348 }
349 //
350 // Hash Monotonic Count.
351 //
352 Status = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));
353 if (!Status) {
354 goto Done;
355 }
356 Status = Sha256Final (HashContext, Digest);
357 if (!Status) {
358 goto Done;
359 }
360 //
361 // Generate & Initialize RSA Context.
362 //
363 Rsa = RsaNew ();
364 ASSERT (Rsa != NULL);
365 //
366 // Set RSA Key Components.
367 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
368 //
369 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
370 if (!Status) {
371 goto Done;
372 }
373 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
374 if (!Status) {
375 goto Done;
376 }
377 //
378 // Verify the signature.
379 //
380 Status = RsaPkcs1Verify (
381 Rsa,
382 Digest,
383 SHA256_DIGEST_SIZE,
384 CertBlock->Signature,
385 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
386 );
387
388 Done:
389 if (Rsa != NULL) {
390 RsaFree (Rsa);
391 }
392 if (Status) {
393 return EFI_SUCCESS;
394 } else {
395 return EFI_SECURITY_VIOLATION;
396 }
397 }
398
399
400 /**
401 Update platform mode.
402
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.
406
407 **/
408 VOID
409 UpdatePlatformMode (
410 IN BOOLEAN VirtualMode,
411 IN ESAL_VARIABLE_GLOBAL *Global,
412 IN UINT32 Mode
413 )
414 {
415 EFI_STATUS Status;
416 VARIABLE_POINTER_TRACK Variable;
417 UINT32 VarAttr;
418
419 Status = FindVariable (
420 Global->VariableName[VirtualMode][VAR_SETUP_MODE],
421 Global->GlobalVariableGuid[VirtualMode],
422 &Variable,
423 &Global->VariableGlobal[VirtualMode],
424 Global->FvbInstance
425 );
426 ASSERT_EFI_ERROR (Status);
427
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],
433 &mPlatformMode,
434 sizeof(UINT8),
435 VarAttr,
436 0,
437 0,
438 VirtualMode,
439 Global,
440 &Variable
441 );
442 ASSERT_EFI_ERROR (Status);
443 }
444
445 /**
446 Process variable with platform key for verification.
447
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.
458
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.
463
464 **/
465 EFI_STATUS
466 ProcessVarWithPk (
467 IN CHAR16 *VariableName,
468 IN EFI_GUID *VendorGuid,
469 IN VOID *Data,
470 IN UINTN DataSize,
471 IN BOOLEAN VirtualMode,
472 IN ESAL_VARIABLE_GLOBAL *Global,
473 IN VARIABLE_POINTER_TRACK *Variable,
474 IN UINT32 Attributes OPTIONAL,
475 IN BOOLEAN IsPk
476 )
477 {
478 EFI_STATUS Status;
479 VARIABLE_POINTER_TRACK PkVariable;
480 EFI_SIGNATURE_LIST *OldPkList;
481 EFI_SIGNATURE_DATA *OldPkData;
482 EFI_VARIABLE_AUTHENTICATION *CertData;
483 VARIABLE_HEADER VariableHeader;
484 BOOLEAN Valid;
485
486 OldPkList = NULL;
487
488 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
489 //
490 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
491 //
492 return EFI_INVALID_PARAMETER;
493 }
494
495 if (mPlatformMode == USER_MODE) {
496 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
497 //
498 // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
499 //
500 return EFI_INVALID_PARAMETER;
501 }
502
503 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
504
505 if (Variable->CurrPtr != 0x0) {
506 Valid = IsValidVariableHeader (
507 Variable->CurrPtr,
508 Variable->Volatile,
509 &Global->VariableGlobal[VirtualMode],
510 Global->FvbInstance,
511 &VariableHeader
512 );
513 ASSERT (Valid);
514
515 if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
516 //
517 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
518 //
519 return EFI_SECURITY_VIOLATION;
520 }
521 }
522 //
523 // Get platform key from variable.
524 //
525 Status = FindVariable (
526 Global->VariableName[VirtualMode][VAR_PLATFORM_KEY],
527 Global->GlobalVariableGuid[VirtualMode],
528 &PkVariable,
529 &Global->VariableGlobal[VirtualMode],
530 Global->FvbInstance
531 );
532 ASSERT_EFI_ERROR (Status);
533
534 ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
535 GetVariableDataPtr (
536 PkVariable.CurrPtr,
537 PkVariable.Volatile,
538 &Global->VariableGlobal[VirtualMode],
539 Global->FvbInstance,
540 (CHAR16 *) Global->KeyList
541 );
542
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 (
548 VariableName,
549 VendorGuid,
550 (UINT8*)Data + AUTHINFO_SIZE,
551 DataSize - AUTHINFO_SIZE,
552 Attributes,
553 0,
554 CertData->MonotonicCount,
555 VirtualMode,
556 Global,
557 Variable
558 );
559
560 if (!EFI_ERROR (Status)) {
561 //
562 // If delete PK in user mode, need change to setup mode.
563 //
564 if ((DataSize == AUTHINFO_SIZE) && IsPk) {
565 UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);
566 }
567 }
568 }
569 } else {
570 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);
571 //
572 // If enroll PK in setup mode, need change to user mode.
573 //
574 if ((DataSize != 0) && IsPk) {
575 UpdatePlatformMode (VirtualMode, Global, USER_MODE);
576 }
577 }
578
579 return Status;
580 }
581
582 /**
583 Process variable with key exchange key for verification.
584
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.
594
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.
599
600 **/
601 EFI_STATUS
602 ProcessVarWithKek (
603 IN CHAR16 *VariableName,
604 IN EFI_GUID *VendorGuid,
605 IN VOID *Data,
606 IN UINTN DataSize,
607 IN BOOLEAN VirtualMode,
608 IN ESAL_VARIABLE_GLOBAL *Global,
609 IN VARIABLE_POINTER_TRACK *Variable,
610 IN UINT32 Attributes OPTIONAL
611 )
612 {
613 EFI_STATUS Status;
614 VARIABLE_POINTER_TRACK KekVariable;
615 EFI_SIGNATURE_LIST *KekList;
616 EFI_SIGNATURE_DATA *KekItem;
617 UINT32 KekCount;
618 EFI_VARIABLE_AUTHENTICATION *CertData;
619 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
620 BOOLEAN IsFound;
621 UINT32 Index;
622 VARIABLE_HEADER VariableHeader;
623 BOOLEAN Valid;
624
625 KekList = NULL;
626
627 if (mPlatformMode == USER_MODE) {
628 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
629 //
630 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
631 //
632 return EFI_INVALID_PARAMETER;
633 }
634
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 (
639 Variable->CurrPtr,
640 Variable->Volatile,
641 &Global->VariableGlobal[VirtualMode],
642 Global->FvbInstance,
643 &VariableHeader
644 );
645 ASSERT (Valid);
646
647 if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
648 //
649 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
650 //
651 return EFI_SECURITY_VIOLATION;
652 }
653 }
654 //
655 // Get KEK database from variable.
656 //
657 Status = FindVariable (
658 Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY],
659 Global->GlobalVariableGuid[VirtualMode],
660 &KekVariable,
661 &Global->VariableGlobal[VirtualMode],
662 Global->FvbInstance
663 );
664 ASSERT_EFI_ERROR (Status);
665
666 ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
667 GetVariableDataPtr (
668 KekVariable.CurrPtr,
669 KekVariable.Volatile,
670 &Global->VariableGlobal[VirtualMode],
671 Global->FvbInstance,
672 (CHAR16 *) Global->KeyList
673 );
674 //
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!
677 //
678 KekList = (EFI_SIGNATURE_LIST *) Global->KeyList;
679 IsFound = FALSE;
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) {
684 IsFound = TRUE;
685 break;
686 }
687 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
688 }
689
690 if (!IsFound) {
691 return EFI_SECURITY_VIOLATION;
692 }
693
694 Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);
695 if (!EFI_ERROR (Status)) {
696 Status = UpdateVariable (
697 VariableName,
698 VendorGuid,
699 (UINT8*)Data + AUTHINFO_SIZE,
700 DataSize - AUTHINFO_SIZE,
701 Attributes,
702 0,
703 CertData->MonotonicCount,
704 VirtualMode,
705 Global,
706 Variable
707 );
708 }
709 } else {
710 //
711 // If in setup mode, no authentication needed.
712 //
713 Status = UpdateVariable (
714 VariableName,
715 VendorGuid,
716 Data,
717 DataSize,
718 Attributes,
719 0,
720 0,
721 VirtualMode,
722 Global,
723 Variable
724 );
725 }
726
727 return Status;
728 }
729
730 /**
731 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
732
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.
742
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.
750
751 **/
752 EFI_STATUS
753 VerifyVariable (
754 IN VOID *Data,
755 IN UINTN DataSize,
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
762 )
763 {
764 EFI_STATUS Status;
765 BOOLEAN IsDeletion;
766 BOOLEAN IsFirstTime;
767 UINT8 *PubKey;
768 EFI_VARIABLE_AUTHENTICATION *CertData;
769 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
770 VARIABLE_HEADER VariableHeader;
771 BOOLEAN Valid;
772
773 CertData = NULL;
774 CertBlock = NULL;
775 PubKey = NULL;
776 IsDeletion = FALSE;
777 Valid = FALSE;
778
779 if (KeyIndex != NULL) {
780 *KeyIndex = 0;
781 }
782 //
783 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
784 //
785 ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER));
786 if (Variable->CurrPtr != 0x0) {
787 Valid = IsValidVariableHeader (
788 Variable->CurrPtr,
789 Variable->Volatile,
790 &Global->VariableGlobal[VirtualMode],
791 Global->FvbInstance,
792 &VariableHeader
793 );
794 ASSERT (Valid);
795 }
796
797 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
798 if (KeyIndex == NULL) {
799 return EFI_INVALID_PARAMETER;
800 }
801
802 //
803 // Determine current operation type.
804 //
805 if (DataSize == AUTHINFO_SIZE) {
806 IsDeletion = TRUE;
807 }
808 //
809 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
810 //
811 if (Variable->CurrPtr == 0x0) {
812 IsFirstTime = TRUE;
813 } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
814 IsFirstTime = TRUE;
815 } else {
816 *KeyIndex = VariableHeader.PubKeyIndex;
817 IsFirstTime = FALSE;
818 }
819 } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
820 //
821 // If the variable is already write-protected, it always needs authentication before update.
822 //
823 return EFI_WRITE_PROTECTED;
824 } else {
825 //
826 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
827 // That means it is not authenticated variable, just return EFI_SUCCESS.
828 //
829 return EFI_SUCCESS;
830 }
831
832 //
833 // Get PubKey and check Monotonic Count value corresponding to the variable.
834 //
835 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
836 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
837 PubKey = CertBlock->PublicKey;
838
839 if (MonotonicCount != NULL) {
840 //
841 // Update Monotonic Count value.
842 //
843 *MonotonicCount = CertData->MonotonicCount;
844 }
845
846 if (!IsFirstTime) {
847 //
848 // Check input PubKey.
849 //
850 if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
851 return EFI_SECURITY_VIOLATION;
852 }
853 //
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.
856 //
857 if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
858 //
859 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
860 //
861 return EFI_SECURITY_VIOLATION;
862 }
863 }
864 //
865 // Verify the certificate in Data payload.
866 //
867 Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);
868 if (!EFI_ERROR (Status)) {
869 //
870 // Now, the signature has been verified!
871 //
872 if (IsFirstTime && !IsDeletion) {
873 //
874 // Update public key database variable if need and return the index.
875 //
876 *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);
877 }
878 }
879
880 return Status;
881 }
882