]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Add debug information for secure boot test convenient.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / 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 UINT8 mPubKeyStore[MAX_KEYDB_SIZE];
23 UINT32 mPubKeyNumber;
24 UINT32 mPlatformMode;
25 EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
26 //
27 // Public Exponent of RSA Key.
28 //
29 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
30 //
31 // Hash context pointer
32 //
33 VOID *mHashCtx = NULL;
34
35 //
36 // Pointer to runtime buffer.
37 // For "Append" operation to an existing variable, a read/modify/write operation
38 // is supported by firmware internally. Reserve runtime buffer to cache previous
39 // variable data in runtime phase because memory allocation is forbidden in virtual mode.
40 //
41 VOID *mStorageArea = NULL;
42
43 //
44 // The serialization of the values of the VariableName, VendorGuid and Attributes
45 // parameters of the SetVariable() call and the TimeStamp component of the
46 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
47 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
48 //
49 UINT8 *mSerializationRuntimeBuffer = NULL;
50
51 /**
52 Internal function to delete a Variable given its name and GUID, no authentication
53 required.
54
55 @param[in] VariableName Name of the Variable.
56 @param[in] VendorGuid GUID of the Variable.
57
58 @retval EFI_SUCCESS Variable deleted successfully.
59 @retval Others The driver failded to start the device.
60
61 **/
62 EFI_STATUS
63 DeleteVariable (
64 IN CHAR16 *VariableName,
65 IN EFI_GUID *VendorGuid
66 )
67 {
68 EFI_STATUS Status;
69 VARIABLE_POINTER_TRACK Variable;
70
71 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
72 if (EFI_ERROR (Status)) {
73 return EFI_SUCCESS;
74 }
75
76 ASSERT (Variable.CurrPtr != NULL);
77 return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);
78 }
79
80 /**
81 Initializes for authenticated varibale service.
82
83 @retval EFI_SUCCESS Function successfully executed.
84 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
85
86 **/
87 EFI_STATUS
88 AutenticatedVariableServiceInitialize (
89 VOID
90 )
91 {
92 EFI_STATUS Status;
93 VARIABLE_POINTER_TRACK Variable;
94 VARIABLE_POINTER_TRACK PkVariable;
95 UINT8 VarValue;
96 UINT32 VarAttr;
97 UINT8 *Data;
98 UINTN DataSize;
99 UINTN CtxSize;
100 UINT8 SecureBootMode;
101 UINT8 SecureBootEnable;
102
103 //
104 // Initialize hash context.
105 //
106 CtxSize = Sha256GetContextSize ();
107 mHashCtx = AllocateRuntimePool (CtxSize);
108 if (mHashCtx == NULL) {
109 return EFI_OUT_OF_RESOURCES;
110 }
111
112 //
113 // Reserved runtime buffer for "Append" operation in virtual mode.
114 //
115 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));
116 if (mStorageArea == NULL) {
117 return EFI_OUT_OF_RESOURCES;
118 }
119
120 //
121 // Prepare runtime buffer for serialized data of time-based authenticated
122 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).
123 //
124 mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));
125 if (mSerializationRuntimeBuffer == NULL) {
126 return EFI_OUT_OF_RESOURCES;
127 }
128
129 //
130 // Check "AuthVarKeyDatabase" variable's existence.
131 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
132 //
133 Status = FindVariable (
134 AUTHVAR_KEYDB_NAME,
135 &gEfiAuthenticatedVariableGuid,
136 &Variable,
137 &mVariableModuleGlobal->VariableGlobal
138 );
139
140 if (Variable.CurrPtr == NULL) {
141 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
142 VarValue = 0;
143 mPubKeyNumber = 0;
144 Status = UpdateVariable (
145 AUTHVAR_KEYDB_NAME,
146 &gEfiAuthenticatedVariableGuid,
147 &VarValue,
148 sizeof(UINT8),
149 VarAttr,
150 0,
151 0,
152 &Variable,
153 NULL
154 );
155 if (EFI_ERROR (Status)) {
156 return Status;
157 }
158 } else {
159 //
160 // Load database in global variable for cache.
161 //
162 DataSize = DataSizeOfVariable (Variable.CurrPtr);
163 Data = GetVariableDataPtr (Variable.CurrPtr);
164 ASSERT ((DataSize != 0) && (Data != NULL));
165 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
166 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
167 }
168
169 FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal);
170 if (PkVariable.CurrPtr == NULL) {
171 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
172 } else {
173 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
174 }
175
176 //
177 // Check "SetupMode" variable's existence.
178 // If it doesn't exist, check PK database's existence to determine the value.
179 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
180 //
181 Status = FindVariable (
182 EFI_SETUP_MODE_NAME,
183 &gEfiGlobalVariableGuid,
184 &Variable,
185 &mVariableModuleGlobal->VariableGlobal
186 );
187
188 if (Variable.CurrPtr == NULL) {
189 if (PkVariable.CurrPtr == NULL) {
190 mPlatformMode = SETUP_MODE;
191 } else {
192 mPlatformMode = USER_MODE;
193 }
194
195 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
196 Status = UpdateVariable (
197 EFI_SETUP_MODE_NAME,
198 &gEfiGlobalVariableGuid,
199 &mPlatformMode,
200 sizeof(UINT8),
201 VarAttr,
202 0,
203 0,
204 &Variable,
205 NULL
206 );
207 if (EFI_ERROR (Status)) {
208 return Status;
209 }
210 } else {
211 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));
212 }
213 //
214 // Check "SignatureSupport" variable's existence.
215 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
216 //
217 Status = FindVariable (
218 EFI_SIGNATURE_SUPPORT_NAME,
219 &gEfiGlobalVariableGuid,
220 &Variable,
221 &mVariableModuleGlobal->VariableGlobal
222 );
223
224 if (Variable.CurrPtr == NULL) {
225 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
226 Status = UpdateVariable (
227 EFI_SIGNATURE_SUPPORT_NAME,
228 &gEfiGlobalVariableGuid,
229 mSignatureSupport,
230 SIGSUPPORT_NUM * sizeof(EFI_GUID),
231 VarAttr,
232 0,
233 0,
234 &Variable,
235 NULL
236 );
237 }
238
239 //
240 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
241 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
242 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
243 //
244 SecureBootEnable = SECURE_BOOT_MODE_DISABLE;
245 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
246 if (Variable.CurrPtr != NULL) {
247 SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));
248 } else if (mPlatformMode == USER_MODE) {
249 //
250 // "SecureBootEnable" not exist, initialize it in USER_MODE.
251 //
252 SecureBootEnable = SECURE_BOOT_MODE_ENABLE;
253 Status = UpdateVariable (
254 EFI_SECURE_BOOT_ENABLE_NAME,
255 &gEfiSecureBootEnableDisableGuid,
256 &SecureBootEnable,
257 sizeof (UINT8),
258 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
259 0,
260 0,
261 &Variable,
262 NULL
263 );
264 if (EFI_ERROR (Status)) {
265 return Status;
266 }
267 }
268
269 if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
270 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
271 } else {
272 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
273 }
274 FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
275 Status = UpdateVariable (
276 EFI_SECURE_BOOT_MODE_NAME,
277 &gEfiGlobalVariableGuid,
278 &SecureBootMode,
279 sizeof (UINT8),
280 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
281 0,
282 0,
283 &Variable,
284 NULL
285 );
286 if (EFI_ERROR (Status)) {
287 return Status;
288 }
289
290 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));
291 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));
292 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
293
294 //
295 // Detect whether a secure platform-specific method to clear PK(Platform Key)
296 // is configured by platform owner. This method is provided for users force to clear PK
297 // in case incorrect enrollment mis-haps.
298 //
299 if (ForceClearPK ()) {
300 DEBUG ((EFI_D_INFO, "Variable PK/KEK/DB/DBX will be cleared in clear PK mode.\n"));
301
302 //
303 // 1. Clear PK.
304 //
305 Status = DeleteVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid);
306 if (EFI_ERROR (Status)) {
307 return Status;
308 }
309
310 //
311 // 2. Update "SetupMode" variable to SETUP_MODE.
312 //
313 UpdatePlatformMode (SETUP_MODE);
314
315 //
316 // 3. Clear KEK, DB and DBX.
317 //
318 DeleteVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid);
319 DeleteVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid);
320 DeleteVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid);
321 }
322
323 return Status;
324 }
325
326 /**
327 Add public key in store and return its index.
328
329 @param[in] PubKey Input pointer to Public Key data
330
331 @return Index of new added item
332
333 **/
334 UINT32
335 AddPubKeyInStore (
336 IN UINT8 *PubKey
337 )
338 {
339 EFI_STATUS Status;
340 BOOLEAN IsFound;
341 UINT32 Index;
342 VARIABLE_POINTER_TRACK Variable;
343 UINT8 *Ptr;
344
345 if (PubKey == NULL) {
346 return 0;
347 }
348
349 Status = FindVariable (
350 AUTHVAR_KEYDB_NAME,
351 &gEfiAuthenticatedVariableGuid,
352 &Variable,
353 &mVariableModuleGlobal->VariableGlobal
354 );
355 ASSERT_EFI_ERROR (Status);
356 //
357 // Check whether the public key entry does exist.
358 //
359 IsFound = FALSE;
360 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
361 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
362 IsFound = TRUE;
363 break;
364 }
365 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
366 }
367
368 if (!IsFound) {
369 //
370 // Add public key in database.
371 //
372 if (mPubKeyNumber == MAX_KEY_NUM) {
373 //
374 // Notes: Database is full, need enhancement here, currently just return 0.
375 //
376 return 0;
377 }
378
379 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
380 Index = ++mPubKeyNumber;
381 //
382 // Update public key database variable.
383 //
384 Status = UpdateVariable (
385 AUTHVAR_KEYDB_NAME,
386 &gEfiAuthenticatedVariableGuid,
387 mPubKeyStore,
388 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
389 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
390 0,
391 0,
392 &Variable,
393 NULL
394 );
395 ASSERT_EFI_ERROR (Status);
396 }
397
398 return Index;
399 }
400
401 /**
402 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
403 Follow the steps in UEFI2.2.
404
405 @param[in] Data Pointer to data with AuthInfo.
406 @param[in] DataSize Size of Data.
407 @param[in] PubKey Public key used for verification.
408
409 @retval EFI_INVALID_PARAMETER Invalid parameter.
410 @retval EFI_SECURITY_VIOLATION If authentication failed.
411 @retval EFI_SUCCESS Authentication successful.
412
413 **/
414 EFI_STATUS
415 VerifyCounterBasedPayload (
416 IN UINT8 *Data,
417 IN UINTN DataSize,
418 IN UINT8 *PubKey
419 )
420 {
421 BOOLEAN Status;
422 EFI_VARIABLE_AUTHENTICATION *CertData;
423 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
424 UINT8 Digest[SHA256_DIGEST_SIZE];
425 VOID *Rsa;
426
427 Rsa = NULL;
428 CertData = NULL;
429 CertBlock = NULL;
430
431 if (Data == NULL || PubKey == NULL) {
432 return EFI_INVALID_PARAMETER;
433 }
434
435 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
436 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
437
438 //
439 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
440 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
441 //
442 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
443 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)
444 ) {
445 //
446 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
447 //
448 return EFI_SECURITY_VIOLATION;
449 }
450 //
451 // Hash data payload with SHA256.
452 //
453 ZeroMem (Digest, SHA256_DIGEST_SIZE);
454 Status = Sha256Init (mHashCtx);
455 if (!Status) {
456 goto Done;
457 }
458 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
459 if (!Status) {
460 goto Done;
461 }
462 //
463 // Hash Monotonic Count.
464 //
465 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
466 if (!Status) {
467 goto Done;
468 }
469 Status = Sha256Final (mHashCtx, Digest);
470 if (!Status) {
471 goto Done;
472 }
473 //
474 // Generate & Initialize RSA Context.
475 //
476 Rsa = RsaNew ();
477 ASSERT (Rsa != NULL);
478 //
479 // Set RSA Key Components.
480 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
481 //
482 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
483 if (!Status) {
484 goto Done;
485 }
486 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
487 if (!Status) {
488 goto Done;
489 }
490 //
491 // Verify the signature.
492 //
493 Status = RsaPkcs1Verify (
494 Rsa,
495 Digest,
496 SHA256_DIGEST_SIZE,
497 CertBlock->Signature,
498 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
499 );
500
501 Done:
502 if (Rsa != NULL) {
503 RsaFree (Rsa);
504 }
505 if (Status) {
506 return EFI_SUCCESS;
507 } else {
508 return EFI_SECURITY_VIOLATION;
509 }
510 }
511
512 /**
513 Update platform mode.
514
515 @param[in] Mode SETUP_MODE or USER_MODE.
516
517 @return EFI_INVALID_PARAMETER Invalid parameter.
518 @return EFI_SUCCESS Update platform mode successfully.
519
520 **/
521 EFI_STATUS
522 UpdatePlatformMode (
523 IN UINT32 Mode
524 )
525 {
526 EFI_STATUS Status;
527 VARIABLE_POINTER_TRACK Variable;
528 UINT32 VarAttr;
529 UINT8 SecureBootMode;
530 UINT8 SecureBootEnable;
531 UINTN VariableDataSize;
532
533 Status = FindVariable (
534 EFI_SETUP_MODE_NAME,
535 &gEfiGlobalVariableGuid,
536 &Variable,
537 &mVariableModuleGlobal->VariableGlobal
538 );
539 if (EFI_ERROR (Status)) {
540 return Status;
541 }
542
543 mPlatformMode = Mode;
544 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
545 Status = UpdateVariable (
546 EFI_SETUP_MODE_NAME,
547 &gEfiGlobalVariableGuid,
548 &mPlatformMode,
549 sizeof(UINT8),
550 VarAttr,
551 0,
552 0,
553 &Variable,
554 NULL
555 );
556 if (EFI_ERROR (Status)) {
557 return Status;
558 }
559
560 if (AtRuntime ()) {
561 //
562 // SecureBoot Variable indicates whether the platform firmware is operating
563 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
564 // Variable in runtime.
565 //
566 return Status;
567 }
568
569 //
570 // Check "SecureBoot" variable's existence.
571 // If it doesn't exist, firmware has no capability to perform driver signing verification,
572 // then set "SecureBoot" to 0.
573 //
574 Status = FindVariable (
575 EFI_SECURE_BOOT_MODE_NAME,
576 &gEfiGlobalVariableGuid,
577 &Variable,
578 &mVariableModuleGlobal->VariableGlobal
579 );
580 //
581 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
582 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
583 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
584 //
585 if (Variable.CurrPtr == NULL) {
586 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
587 } else {
588 if (mPlatformMode == USER_MODE) {
589 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
590 } else if (mPlatformMode == SETUP_MODE) {
591 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
592 } else {
593 return EFI_NOT_FOUND;
594 }
595 }
596
597 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
598 Status = UpdateVariable (
599 EFI_SECURE_BOOT_MODE_NAME,
600 &gEfiGlobalVariableGuid,
601 &SecureBootMode,
602 sizeof(UINT8),
603 VarAttr,
604 0,
605 0,
606 &Variable,
607 NULL
608 );
609 if (EFI_ERROR (Status)) {
610 return Status;
611 }
612
613 //
614 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
615 //
616 Status = FindVariable (
617 EFI_SECURE_BOOT_ENABLE_NAME,
618 &gEfiSecureBootEnableDisableGuid,
619 &Variable,
620 &mVariableModuleGlobal->VariableGlobal
621 );
622
623 if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
624 //
625 // Create the "SecureBootEnable" variable as secure boot is enabled.
626 //
627 SecureBootEnable = SECURE_BOOT_ENABLE;
628 VariableDataSize = sizeof (SecureBootEnable);
629 } else {
630 //
631 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
632 // variable is not in secure boot state.
633 //
634 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
635 return EFI_SUCCESS;
636 }
637 SecureBootEnable = SECURE_BOOT_DISABLE;
638 VariableDataSize = 0;
639 }
640
641 Status = UpdateVariable (
642 EFI_SECURE_BOOT_ENABLE_NAME,
643 &gEfiSecureBootEnableDisableGuid,
644 &SecureBootEnable,
645 VariableDataSize,
646 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
647 0,
648 0,
649 &Variable,
650 NULL
651 );
652 return Status;
653 }
654
655 /**
656 Process variable with platform key for verification.
657
658 @param[in] VariableName Name of Variable to be found.
659 @param[in] VendorGuid Variable vendor GUID.
660 @param[in] Data Data pointer.
661 @param[in] DataSize Size of Data found. If size is less than the
662 data, this value contains the required size.
663 @param[in] Variable The variable information which is used to keep track of variable usage.
664 @param[in] Attributes Attribute value of the variable
665 @param[in] IsPk Indicate whether it is to process pk.
666
667 @return EFI_INVALID_PARAMETER Invalid parameter.
668 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
669 check carried out by the firmware.
670 @return EFI_SUCCESS Variable passed validation successfully.
671
672 **/
673 EFI_STATUS
674 ProcessVarWithPk (
675 IN CHAR16 *VariableName,
676 IN EFI_GUID *VendorGuid,
677 IN VOID *Data,
678 IN UINTN DataSize,
679 IN VARIABLE_POINTER_TRACK *Variable,
680 IN UINT32 Attributes OPTIONAL,
681 IN BOOLEAN IsPk
682 )
683 {
684 EFI_STATUS Status;
685 VARIABLE_POINTER_TRACK PkVariable;
686 EFI_SIGNATURE_LIST *OldPkList;
687 EFI_SIGNATURE_DATA *OldPkData;
688 EFI_VARIABLE_AUTHENTICATION *CertData;
689 BOOLEAN TimeBase;
690 BOOLEAN Del;
691 UINT8 *Payload;
692 UINTN PayloadSize;
693 UINT64 MonotonicCount;
694 EFI_TIME *TimeStamp;
695
696 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
697 //
698 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
699 //
700 return EFI_INVALID_PARAMETER;
701 }
702
703 if (mPlatformMode == USER_MODE) {
704
705 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
706 //
707 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.
708 //
709 TimeBase = TRUE;
710 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
711 //
712 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.
713 //
714 TimeBase = FALSE;
715 } else {
716 return EFI_INVALID_PARAMETER;
717 }
718
719 if (TimeBase) {
720 //
721 // Verify against X509 Cert PK.
722 //
723 Del = FALSE;
724 Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);
725 if (!EFI_ERROR (Status)) {
726 //
727 // If delete PK in user mode, need change to setup mode.
728 //
729 if (Del && IsPk) {
730 Status = UpdatePlatformMode (SETUP_MODE);
731 }
732 }
733 return Status;
734 } else {
735 //
736 // Verify against RSA2048 Cert PK.
737 //
738 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
739 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
740 //
741 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
742 //
743 return EFI_SECURITY_VIOLATION;
744 }
745 //
746 // Get platform key from variable.
747 //
748 Status = FindVariable (
749 EFI_PLATFORM_KEY_NAME,
750 &gEfiGlobalVariableGuid,
751 &PkVariable,
752 &mVariableModuleGlobal->VariableGlobal
753 );
754 ASSERT_EFI_ERROR (Status);
755
756 OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
757 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
758 Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);
759 if (!EFI_ERROR (Status)) {
760 Status = UpdateVariable (
761 VariableName,
762 VendorGuid,
763 (UINT8*)Data + AUTHINFO_SIZE,
764 DataSize - AUTHINFO_SIZE,
765 Attributes,
766 0,
767 CertData->MonotonicCount,
768 Variable,
769 NULL
770 );
771
772 if (!EFI_ERROR (Status)) {
773 //
774 // If delete PK in user mode, need change to setup mode.
775 //
776 if ((DataSize == AUTHINFO_SIZE) && IsPk) {
777 Status = UpdatePlatformMode (SETUP_MODE);
778 }
779 }
780 }
781 }
782 } else {
783 //
784 // Process PK or KEK in Setup mode.
785 //
786 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
787 //
788 // Time-based Authentication descriptor.
789 //
790 MonotonicCount = 0;
791 TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;
792 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
793 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
794 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
795 //
796 // Counter-based Authentication descriptor.
797 //
798 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;
799 TimeStamp = NULL;
800 Payload = (UINT8*) Data + AUTHINFO_SIZE;
801 PayloadSize = DataSize - AUTHINFO_SIZE;
802 } else {
803 //
804 // No Authentication descriptor.
805 //
806 MonotonicCount = 0;
807 TimeStamp = NULL;
808 Payload = Data;
809 PayloadSize = DataSize;
810 }
811
812 Status = UpdateVariable (
813 VariableName,
814 VendorGuid,
815 Payload,
816 PayloadSize,
817 Attributes,
818 0,
819 MonotonicCount,
820 Variable,
821 TimeStamp
822 );
823 //
824 // If enroll PK in setup mode, need change to user mode.
825 //
826 if ((DataSize != 0) && IsPk) {
827 Status = UpdatePlatformMode (USER_MODE);
828 }
829 }
830
831 return Status;
832 }
833
834 /**
835 Process variable with key exchange key for verification.
836
837 @param[in] VariableName Name of Variable to be found.
838 @param[in] VendorGuid Variable vendor GUID.
839 @param[in] Data Data pointer.
840 @param[in] DataSize Size of Data found. If size is less than the
841 data, this value contains the required size.
842 @param[in] Variable The variable information which is used to keep track of variable usage.
843 @param[in] Attributes Attribute value of the variable.
844
845 @return EFI_INVALID_PARAMETER Invalid parameter.
846 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
847 check carried out by the firmware.
848 @return EFI_SUCCESS Variable pass validation successfully.
849
850 **/
851 EFI_STATUS
852 ProcessVarWithKek (
853 IN CHAR16 *VariableName,
854 IN EFI_GUID *VendorGuid,
855 IN VOID *Data,
856 IN UINTN DataSize,
857 IN VARIABLE_POINTER_TRACK *Variable,
858 IN UINT32 Attributes OPTIONAL
859 )
860 {
861 EFI_STATUS Status;
862 VARIABLE_POINTER_TRACK KekVariable;
863 EFI_SIGNATURE_LIST *KekList;
864 EFI_SIGNATURE_DATA *KekItem;
865 UINT32 KekCount;
866 EFI_VARIABLE_AUTHENTICATION *CertData;
867 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
868 BOOLEAN IsFound;
869 UINT32 Index;
870 UINT32 KekDataSize;
871 UINT8 *Payload;
872 UINTN PayloadSize;
873 UINT64 MonotonicCount;
874
875 if (mPlatformMode == USER_MODE) {
876 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
877 //
878 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
879 //
880 return EFI_INVALID_PARAMETER;
881 }
882
883 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
884 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
885 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
886 //
887 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
888 //
889 return EFI_SECURITY_VIOLATION;
890 }
891 //
892 // Get KEK database from variable.
893 //
894 Status = FindVariable (
895 EFI_KEY_EXCHANGE_KEY_NAME,
896 &gEfiGlobalVariableGuid,
897 &KekVariable,
898 &mVariableModuleGlobal->VariableGlobal
899 );
900 ASSERT_EFI_ERROR (Status);
901
902 KekDataSize = KekVariable.CurrPtr->DataSize;
903 KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
904
905 //
906 // Enumerate all Kek items in this list to verify the variable certificate data.
907 // If anyone is authenticated successfully, it means the variable is correct!
908 //
909 IsFound = FALSE;
910 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {
911 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {
912 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
913 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
914 for (Index = 0; Index < KekCount; Index++) {
915 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
916 IsFound = TRUE;
917 break;
918 }
919 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
920 }
921 }
922 KekDataSize -= KekList->SignatureListSize;
923 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
924 }
925
926 if (!IsFound) {
927 return EFI_SECURITY_VIOLATION;
928 }
929
930 Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);
931 if (!EFI_ERROR (Status)) {
932 Status = UpdateVariable (
933 VariableName,
934 VendorGuid,
935 (UINT8*)Data + AUTHINFO_SIZE,
936 DataSize - AUTHINFO_SIZE,
937 Attributes,
938 0,
939 CertData->MonotonicCount,
940 Variable,
941 NULL
942 );
943 }
944 } else {
945 //
946 // If in setup mode, no authentication needed.
947 //
948 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
949 //
950 // Counter-based Authentication descriptor.
951 //
952 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;
953 Payload = (UINT8*) Data + AUTHINFO_SIZE;
954 PayloadSize = DataSize - AUTHINFO_SIZE;
955 } else {
956 //
957 // No Authentication descriptor.
958 //
959 MonotonicCount = 0;
960 Payload = Data;
961 PayloadSize = DataSize;
962 }
963
964 Status = UpdateVariable (
965 VariableName,
966 VendorGuid,
967 Payload,
968 PayloadSize,
969 Attributes,
970 0,
971 MonotonicCount,
972 Variable,
973 NULL
974 );
975 }
976
977 return Status;
978 }
979
980 /**
981 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
982
983 @param[in] VariableName Name of Variable to be found.
984 @param[in] VendorGuid Variable vendor GUID.
985
986 @param[in] Data Data pointer.
987 @param[in] DataSize Size of Data found. If size is less than the
988 data, this value contains the required size.
989 @param[in] Variable The variable information which is used to keep track of variable usage.
990 @param[in] Attributes Attribute value of the variable.
991
992 @return EFI_INVALID_PARAMETER Invalid parameter.
993 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
994 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
995 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
996 set, but the AuthInfo does NOT pass the validation
997 check carried out by the firmware.
998 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
999
1000 **/
1001 EFI_STATUS
1002 ProcessVariable (
1003 IN CHAR16 *VariableName,
1004 IN EFI_GUID *VendorGuid,
1005 IN VOID *Data,
1006 IN UINTN DataSize,
1007 IN VARIABLE_POINTER_TRACK *Variable,
1008 IN UINT32 Attributes
1009 )
1010 {
1011 EFI_STATUS Status;
1012 BOOLEAN IsDeletion;
1013 BOOLEAN IsFirstTime;
1014 UINT8 *PubKey;
1015 EFI_VARIABLE_AUTHENTICATION *CertData;
1016 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
1017 UINT32 KeyIndex;
1018 UINT64 MonotonicCount;
1019
1020 KeyIndex = 0;
1021 CertData = NULL;
1022 CertBlock = NULL;
1023 PubKey = NULL;
1024 IsDeletion = FALSE;
1025
1026 //
1027 // Process Time-based Authenticated variable.
1028 //
1029 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1030 return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);
1031 }
1032
1033 //
1034 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
1035 //
1036 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1037 //
1038 // Determine current operation type.
1039 //
1040 if (DataSize == AUTHINFO_SIZE) {
1041 IsDeletion = TRUE;
1042 }
1043 //
1044 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1045 //
1046 if (Variable->CurrPtr == NULL) {
1047 IsFirstTime = TRUE;
1048 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
1049 IsFirstTime = TRUE;
1050 } else {
1051 KeyIndex = Variable->CurrPtr->PubKeyIndex;
1052 IsFirstTime = FALSE;
1053 }
1054 } else if ((Variable->CurrPtr != NULL) &&
1055 (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0
1056 ) {
1057 //
1058 // If the variable is already write-protected, it always needs authentication before update.
1059 //
1060 return EFI_WRITE_PROTECTED;
1061 } else {
1062 //
1063 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
1064 // That means it is not authenticated variable, just update variable as usual.
1065 //
1066 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
1067 return Status;
1068 }
1069
1070 //
1071 // Get PubKey and check Monotonic Count value corresponding to the variable.
1072 //
1073 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
1074 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
1075 PubKey = CertBlock->PublicKey;
1076
1077 //
1078 // Update Monotonic Count value.
1079 //
1080 MonotonicCount = CertData->MonotonicCount;
1081
1082 if (!IsFirstTime) {
1083 //
1084 // Check input PubKey.
1085 //
1086 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
1087 return EFI_SECURITY_VIOLATION;
1088 }
1089 //
1090 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
1091 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
1092 //
1093 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {
1094 //
1095 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1096 //
1097 return EFI_SECURITY_VIOLATION;
1098 }
1099 }
1100 //
1101 // Verify the certificate in Data payload.
1102 //
1103 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
1104 if (EFI_ERROR (Status)) {
1105 return Status;
1106 }
1107
1108 //
1109 // Now, the signature has been verified!
1110 //
1111 if (IsFirstTime && !IsDeletion) {
1112 //
1113 // Update public key database variable if need.
1114 //
1115 KeyIndex = AddPubKeyInStore (PubKey);
1116 }
1117
1118 //
1119 // Verification pass.
1120 //
1121 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
1122 }
1123
1124 /**
1125 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
1126 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
1127 will be ignored.
1128
1129 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
1130 @param[in] DataSize Size of Data buffer.
1131 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
1132 @param[in] NewDataSize Size of NewData buffer.
1133
1134 @return Size of the merged buffer.
1135
1136 **/
1137 UINTN
1138 AppendSignatureList (
1139 IN OUT VOID *Data,
1140 IN UINTN DataSize,
1141 IN VOID *NewData,
1142 IN UINTN NewDataSize
1143 )
1144 {
1145 EFI_SIGNATURE_LIST *CertList;
1146 EFI_SIGNATURE_DATA *Cert;
1147 UINTN CertCount;
1148 EFI_SIGNATURE_LIST *NewCertList;
1149 EFI_SIGNATURE_DATA *NewCert;
1150 UINTN NewCertCount;
1151 UINTN Index;
1152 UINTN Index2;
1153 UINTN Size;
1154 UINT8 *Tail;
1155 UINTN CopiedCount;
1156 UINTN SignatureListSize;
1157 BOOLEAN IsNewCert;
1158
1159 Tail = (UINT8 *) Data + DataSize;
1160
1161 NewCertList = (EFI_SIGNATURE_LIST *) NewData;
1162 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {
1163 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1164 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
1165
1166 CopiedCount = 0;
1167 for (Index = 0; Index < NewCertCount; Index++) {
1168 IsNewCert = TRUE;
1169
1170 Size = DataSize;
1171 CertList = (EFI_SIGNATURE_LIST *) Data;
1172 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
1173 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
1174 (CertList->SignatureSize == NewCertList->SignatureSize)) {
1175 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1176 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1177 for (Index2 = 0; Index2 < CertCount; Index2++) {
1178 //
1179 // Iterate each Signature Data in this Signature List.
1180 //
1181 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
1182 IsNewCert = FALSE;
1183 break;
1184 }
1185 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1186 }
1187 }
1188
1189 if (!IsNewCert) {
1190 break;
1191 }
1192 Size -= CertList->SignatureListSize;
1193 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1194 }
1195
1196 if (IsNewCert) {
1197 //
1198 // New EFI_SIGNATURE_DATA, append it.
1199 //
1200 if (CopiedCount == 0) {
1201 //
1202 // Copy EFI_SIGNATURE_LIST header for only once.
1203 //
1204 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1205 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
1206 }
1207
1208 CopyMem (Tail, NewCert, NewCertList->SignatureSize);
1209 Tail += NewCertList->SignatureSize;
1210 CopiedCount++;
1211 }
1212
1213 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
1214 }
1215
1216 //
1217 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
1218 //
1219 if (CopiedCount != 0) {
1220 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
1221 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
1222 CertList->SignatureListSize = (UINT32) SignatureListSize;
1223 }
1224
1225 NewDataSize -= NewCertList->SignatureListSize;
1226 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
1227 }
1228
1229 return (Tail - (UINT8 *) Data);
1230 }
1231
1232 /**
1233 Compare two EFI_TIME data.
1234
1235
1236 @param FirstTime A pointer to the first EFI_TIME data.
1237 @param SecondTime A pointer to the second EFI_TIME data.
1238
1239 @retval TRUE The FirstTime is not later than the SecondTime.
1240 @retval FALSE The FirstTime is later than the SecondTime.
1241
1242 **/
1243 BOOLEAN
1244 CompareTimeStamp (
1245 IN EFI_TIME *FirstTime,
1246 IN EFI_TIME *SecondTime
1247 )
1248 {
1249 if (FirstTime->Year != SecondTime->Year) {
1250 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
1251 } else if (FirstTime->Month != SecondTime->Month) {
1252 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
1253 } else if (FirstTime->Day != SecondTime->Day) {
1254 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
1255 } else if (FirstTime->Hour != SecondTime->Hour) {
1256 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
1257 } else if (FirstTime->Minute != SecondTime->Minute) {
1258 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
1259 }
1260
1261 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
1262 }
1263
1264 /**
1265 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1266
1267 @param[in] VariableName Name of Variable to be found.
1268 @param[in] VendorGuid Variable vendor GUID.
1269 @param[in] Data Data pointer.
1270 @param[in] DataSize Size of Data found. If size is less than the
1271 data, this value contains the required size.
1272 @param[in] Variable The variable information which is used to keep track of variable usage.
1273 @param[in] Attributes Attribute value of the variable.
1274 @param[in] Pk Verify against PK or KEK database.
1275 @param[out] VarDel Delete the variable or not.
1276
1277 @retval EFI_INVALID_PARAMETER Invalid parameter.
1278 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1279 check carried out by the firmware.
1280 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
1281 of resources.
1282 @retval EFI_SUCCESS Variable pass validation successfully.
1283
1284 **/
1285 EFI_STATUS
1286 VerifyTimeBasedPayload (
1287 IN CHAR16 *VariableName,
1288 IN EFI_GUID *VendorGuid,
1289 IN VOID *Data,
1290 IN UINTN DataSize,
1291 IN VARIABLE_POINTER_TRACK *Variable,
1292 IN UINT32 Attributes,
1293 IN BOOLEAN Pk,
1294 OUT BOOLEAN *VarDel
1295 )
1296 {
1297 UINT8 *RootCert;
1298 UINT8 *SigData;
1299 UINT8 *PayloadPtr;
1300 UINTN RootCertSize;
1301 UINTN Index;
1302 UINTN CertCount;
1303 UINTN PayloadSize;
1304 UINT32 Attr;
1305 UINT32 SigDataSize;
1306 UINT32 KekDataSize;
1307 BOOLEAN Result;
1308 BOOLEAN VerifyStatus;
1309 EFI_STATUS Status;
1310 EFI_SIGNATURE_LIST *CertList;
1311 EFI_SIGNATURE_DATA *Cert;
1312 VARIABLE_POINTER_TRACK KekVariable;
1313 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
1314 UINT8 *NewData;
1315 UINTN NewDataSize;
1316 VARIABLE_POINTER_TRACK PkVariable;
1317 UINT8 *Buffer;
1318 UINTN Length;
1319
1320 Result = FALSE;
1321 VerifyStatus = FALSE;
1322 CertData = NULL;
1323 NewData = NULL;
1324 Attr = Attributes;
1325
1326 //
1327 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1328 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1329 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1330 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1331 // variable value. The authentication descriptor is not part of the variable data and is not
1332 // returned by subsequent calls to GetVariable().
1333 //
1334 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
1335
1336 //
1337 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
1338 // TimeStamp value are set to zero.
1339 //
1340 if ((CertData->TimeStamp.Pad1 != 0) ||
1341 (CertData->TimeStamp.Nanosecond != 0) ||
1342 (CertData->TimeStamp.TimeZone != 0) ||
1343 (CertData->TimeStamp.Daylight != 0) ||
1344 (CertData->TimeStamp.Pad2 != 0)) {
1345 return EFI_INVALID_PARAMETER;
1346 }
1347
1348 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
1349 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
1350 //
1351 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1352 //
1353 return EFI_SECURITY_VIOLATION;
1354 }
1355 }
1356
1357 //
1358 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1359 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1360 //
1361 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
1362 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
1363 //
1364 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1365 //
1366 return EFI_SECURITY_VIOLATION;
1367 }
1368
1369 //
1370 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1371 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1372 //
1373 SigData = CertData->AuthInfo.CertData;
1374 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
1375
1376 //
1377 // Find out the new data payload which follows Pkcs7 SignedData directly.
1378 //
1379 PayloadPtr = SigData + SigDataSize;
1380 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
1381
1382 //
1383 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
1384 //
1385 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
1386 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
1387 NewData = mSerializationRuntimeBuffer;
1388
1389 Buffer = NewData;
1390 Length = StrLen (VariableName) * sizeof (CHAR16);
1391 CopyMem (Buffer, VariableName, Length);
1392 Buffer += Length;
1393
1394 Length = sizeof (EFI_GUID);
1395 CopyMem (Buffer, VendorGuid, Length);
1396 Buffer += Length;
1397
1398 Length = sizeof (UINT32);
1399 CopyMem (Buffer, &Attr, Length);
1400 Buffer += Length;
1401
1402 Length = sizeof (EFI_TIME);
1403 CopyMem (Buffer, &CertData->TimeStamp, Length);
1404 Buffer += Length;
1405
1406 CopyMem (Buffer, PayloadPtr, PayloadSize);
1407
1408 if (Pk) {
1409 //
1410 // Get platform key from variable.
1411 //
1412 Status = FindVariable (
1413 EFI_PLATFORM_KEY_NAME,
1414 &gEfiGlobalVariableGuid,
1415 &PkVariable,
1416 &mVariableModuleGlobal->VariableGlobal
1417 );
1418 if (EFI_ERROR (Status)) {
1419 return Status;
1420 }
1421
1422 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
1423 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1424 RootCert = Cert->SignatureData;
1425 RootCertSize = CertList->SignatureSize;
1426
1427
1428 //
1429 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1430 //
1431 VerifyStatus = Pkcs7Verify (
1432 SigData,
1433 SigDataSize,
1434 RootCert,
1435 RootCertSize,
1436 NewData,
1437 NewDataSize
1438 );
1439
1440 } else {
1441
1442 //
1443 // Get KEK database from variable.
1444 //
1445 Status = FindVariable (
1446 EFI_KEY_EXCHANGE_KEY_NAME,
1447 &gEfiGlobalVariableGuid,
1448 &KekVariable,
1449 &mVariableModuleGlobal->VariableGlobal
1450 );
1451 if (EFI_ERROR (Status)) {
1452 return Status;
1453 }
1454
1455 //
1456 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
1457 //
1458 KekDataSize = KekVariable.CurrPtr->DataSize;
1459 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
1460 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
1461 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
1462 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1463 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1464 for (Index = 0; Index < CertCount; Index++) {
1465 //
1466 // Iterate each Signature Data Node within this CertList for a verify
1467 //
1468 RootCert = Cert->SignatureData;
1469 RootCertSize = CertList->SignatureSize;
1470
1471 //
1472 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1473 //
1474 VerifyStatus = Pkcs7Verify (
1475 SigData,
1476 SigDataSize,
1477 RootCert,
1478 RootCertSize,
1479 NewData,
1480 NewDataSize
1481 );
1482 if (VerifyStatus) {
1483 goto Exit;
1484 }
1485 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1486 }
1487 }
1488 KekDataSize -= CertList->SignatureListSize;
1489 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1490 }
1491 }
1492
1493 Exit:
1494
1495 if (!VerifyStatus) {
1496 return EFI_SECURITY_VIOLATION;
1497 }
1498
1499 if ((PayloadSize == 0) && (VarDel != NULL)) {
1500 *VarDel = TRUE;
1501 }
1502
1503 //
1504 // Final step: Update/Append Variable if it pass Pkcs7Verify
1505 //
1506 return UpdateVariable (
1507 VariableName,
1508 VendorGuid,
1509 PayloadPtr,
1510 PayloadSize,
1511 Attributes,
1512 0,
1513 0,
1514 Variable,
1515 &CertData->TimeStamp
1516 );
1517 }