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