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