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