]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Fix always reboot issue for an invalid physical presence operation request.
[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 - 2012, 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 Determine whether this operation needs a physical present user.
70
71 @param[in] VariableName Name of the Variable.
72 @param[in] VendorGuid GUID of the Variable.
73
74 @retval TRUE This variable is protected, only a physical present user could set this variable.
75 @retval FALSE This variable is not protected.
76
77 **/
78 BOOLEAN
79 NeedPhysicallyPresent(
80 IN CHAR16 *VariableName,
81 IN EFI_GUID *VendorGuid
82 )
83 {
84 if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
85 || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
86 return TRUE;
87 }
88
89 return FALSE;
90 }
91
92 /**
93 Determine whether the platform is operating in Custom Secure Boot mode.
94
95 @retval TRUE The platform is operating in Custom mode.
96 @retval FALSE The platform is operating in Standard mode.
97
98 **/
99 BOOLEAN
100 InCustomMode (
101 VOID
102 )
103 {
104 VARIABLE_POINTER_TRACK Variable;
105
106 FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
107 if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {
108 return TRUE;
109 }
110
111 return FALSE;
112 }
113
114
115 /**
116 Internal function to delete a Variable given its name and GUID, no authentication
117 required.
118
119 @param[in] VariableName Name of the Variable.
120 @param[in] VendorGuid GUID of the Variable.
121
122 @retval EFI_SUCCESS Variable deleted successfully.
123 @retval Others The driver failded to start the device.
124
125 **/
126 EFI_STATUS
127 DeleteVariable (
128 IN CHAR16 *VariableName,
129 IN EFI_GUID *VendorGuid
130 )
131 {
132 EFI_STATUS Status;
133 VARIABLE_POINTER_TRACK Variable;
134
135 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
136 if (EFI_ERROR (Status)) {
137 return EFI_SUCCESS;
138 }
139
140 ASSERT (Variable.CurrPtr != NULL);
141 return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);
142 }
143
144 /**
145 Initializes for authenticated varibale service.
146
147 @retval EFI_SUCCESS Function successfully executed.
148 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
149
150 **/
151 EFI_STATUS
152 AutenticatedVariableServiceInitialize (
153 VOID
154 )
155 {
156 EFI_STATUS Status;
157 VARIABLE_POINTER_TRACK Variable;
158 VARIABLE_POINTER_TRACK PkVariable;
159 UINT8 VarValue;
160 UINT32 VarAttr;
161 UINT8 *Data;
162 UINTN DataSize;
163 UINTN CtxSize;
164 UINT8 SecureBootMode;
165 UINT8 SecureBootEnable;
166 UINT8 CustomMode;
167 UINT32 ListSize;
168
169 //
170 // Initialize hash context.
171 //
172 CtxSize = Sha256GetContextSize ();
173 mHashCtx = AllocateRuntimePool (CtxSize);
174 if (mHashCtx == NULL) {
175 return EFI_OUT_OF_RESOURCES;
176 }
177
178 //
179 // Reserved runtime buffer for "Append" operation in virtual mode.
180 //
181 mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize));
182 if (mStorageArea == NULL) {
183 return EFI_OUT_OF_RESOURCES;
184 }
185
186 //
187 // Prepare runtime buffer for serialized data of time-based authenticated
188 // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).
189 //
190 mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));
191 if (mSerializationRuntimeBuffer == NULL) {
192 return EFI_OUT_OF_RESOURCES;
193 }
194
195 //
196 // Check "AuthVarKeyDatabase" variable's existence.
197 // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
198 //
199 Status = FindVariable (
200 AUTHVAR_KEYDB_NAME,
201 &gEfiAuthenticatedVariableGuid,
202 &Variable,
203 &mVariableModuleGlobal->VariableGlobal,
204 FALSE
205 );
206
207 if (Variable.CurrPtr == NULL) {
208 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
209 VarValue = 0;
210 mPubKeyNumber = 0;
211 Status = UpdateVariable (
212 AUTHVAR_KEYDB_NAME,
213 &gEfiAuthenticatedVariableGuid,
214 &VarValue,
215 sizeof(UINT8),
216 VarAttr,
217 0,
218 0,
219 &Variable,
220 NULL
221 );
222 if (EFI_ERROR (Status)) {
223 return Status;
224 }
225 } else {
226 //
227 // Load database in global variable for cache.
228 //
229 DataSize = DataSizeOfVariable (Variable.CurrPtr);
230 Data = GetVariableDataPtr (Variable.CurrPtr);
231 ASSERT ((DataSize != 0) && (Data != NULL));
232 CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
233 mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
234 }
235
236 FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);
237 if (PkVariable.CurrPtr == NULL) {
238 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
239 } else {
240 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
241 }
242
243 //
244 // Check "SetupMode" variable's existence.
245 // If it doesn't exist, check PK database's existence to determine the value.
246 // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
247 //
248 Status = FindVariable (
249 EFI_SETUP_MODE_NAME,
250 &gEfiGlobalVariableGuid,
251 &Variable,
252 &mVariableModuleGlobal->VariableGlobal,
253 FALSE
254 );
255
256 if (Variable.CurrPtr == NULL) {
257 if (PkVariable.CurrPtr == NULL) {
258 mPlatformMode = SETUP_MODE;
259 } else {
260 mPlatformMode = USER_MODE;
261 }
262
263 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
264 Status = UpdateVariable (
265 EFI_SETUP_MODE_NAME,
266 &gEfiGlobalVariableGuid,
267 &mPlatformMode,
268 sizeof(UINT8),
269 VarAttr,
270 0,
271 0,
272 &Variable,
273 NULL
274 );
275 if (EFI_ERROR (Status)) {
276 return Status;
277 }
278 } else {
279 mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));
280 }
281 //
282 // Check "SignatureSupport" variable's existence.
283 // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
284 //
285 Status = FindVariable (
286 EFI_SIGNATURE_SUPPORT_NAME,
287 &gEfiGlobalVariableGuid,
288 &Variable,
289 &mVariableModuleGlobal->VariableGlobal,
290 FALSE
291 );
292
293 if (Variable.CurrPtr == NULL) {
294 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
295 Status = UpdateVariable (
296 EFI_SIGNATURE_SUPPORT_NAME,
297 &gEfiGlobalVariableGuid,
298 mSignatureSupport,
299 sizeof(mSignatureSupport),
300 VarAttr,
301 0,
302 0,
303 &Variable,
304 NULL
305 );
306 }
307
308 //
309 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
310 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
311 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
312 //
313 SecureBootEnable = SECURE_BOOT_MODE_DISABLE;
314 FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
315 if (Variable.CurrPtr != NULL) {
316 SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));
317 } else if (mPlatformMode == USER_MODE) {
318 //
319 // "SecureBootEnable" not exist, initialize it in USER_MODE.
320 //
321 SecureBootEnable = SECURE_BOOT_MODE_ENABLE;
322 Status = UpdateVariable (
323 EFI_SECURE_BOOT_ENABLE_NAME,
324 &gEfiSecureBootEnableDisableGuid,
325 &SecureBootEnable,
326 sizeof (UINT8),
327 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
328 0,
329 0,
330 &Variable,
331 NULL
332 );
333 if (EFI_ERROR (Status)) {
334 return Status;
335 }
336 }
337
338 if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
339 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
340 } else {
341 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
342 }
343 FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
344 Status = UpdateVariable (
345 EFI_SECURE_BOOT_MODE_NAME,
346 &gEfiGlobalVariableGuid,
347 &SecureBootMode,
348 sizeof (UINT8),
349 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
350 0,
351 0,
352 &Variable,
353 NULL
354 );
355 if (EFI_ERROR (Status)) {
356 return Status;
357 }
358
359 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));
360 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));
361 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
362
363 //
364 // Check "CustomMode" variable's existence.
365 //
366 FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
367 if (Variable.CurrPtr != NULL) {
368 CustomMode = *(GetVariableDataPtr (Variable.CurrPtr));
369 } else {
370 //
371 // "CustomMode" not exist, initialize it in STANDARD_SECURE_BOOT_MODE.
372 //
373 CustomMode = STANDARD_SECURE_BOOT_MODE;
374 Status = UpdateVariable (
375 EFI_CUSTOM_MODE_NAME,
376 &gEfiCustomModeEnableGuid,
377 &CustomMode,
378 sizeof (UINT8),
379 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
380 0,
381 0,
382 &Variable,
383 NULL
384 );
385 if (EFI_ERROR (Status)) {
386 return Status;
387 }
388 }
389
390 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
391
392 //
393 // Check "certdb" variable's existence.
394 // If it doesn't exist, then create a new one with
395 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
396 //
397 Status = FindVariable (
398 EFI_CERT_DB_NAME,
399 &gEfiCertDbGuid,
400 &Variable,
401 &mVariableModuleGlobal->VariableGlobal,
402 FALSE
403 );
404
405 if (Variable.CurrPtr == NULL) {
406 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
407 ListSize = 0;
408 Status = UpdateVariable (
409 EFI_CERT_DB_NAME,
410 &gEfiCertDbGuid,
411 &ListSize,
412 sizeof (UINT32),
413 VarAttr,
414 0,
415 0,
416 &Variable,
417 NULL
418 );
419
420 }
421
422 return Status;
423 }
424
425 /**
426 Add public key in store and return its index.
427
428 @param[in] PubKey Input pointer to Public Key data
429
430 @return Index of new added item
431
432 **/
433 UINT32
434 AddPubKeyInStore (
435 IN UINT8 *PubKey
436 )
437 {
438 EFI_STATUS Status;
439 BOOLEAN IsFound;
440 UINT32 Index;
441 VARIABLE_POINTER_TRACK Variable;
442 UINT8 *Ptr;
443
444 if (PubKey == NULL) {
445 return 0;
446 }
447
448 Status = FindVariable (
449 AUTHVAR_KEYDB_NAME,
450 &gEfiAuthenticatedVariableGuid,
451 &Variable,
452 &mVariableModuleGlobal->VariableGlobal,
453 FALSE
454 );
455 ASSERT_EFI_ERROR (Status);
456 //
457 // Check whether the public key entry does exist.
458 //
459 IsFound = FALSE;
460 for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
461 if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
462 IsFound = TRUE;
463 break;
464 }
465 Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
466 }
467
468 if (!IsFound) {
469 //
470 // Add public key in database.
471 //
472 if (mPubKeyNumber == MAX_KEY_NUM) {
473 //
474 // Notes: Database is full, need enhancement here, currently just return 0.
475 //
476 return 0;
477 }
478
479 CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
480 Index = ++mPubKeyNumber;
481 //
482 // Update public key database variable.
483 //
484 Status = UpdateVariable (
485 AUTHVAR_KEYDB_NAME,
486 &gEfiAuthenticatedVariableGuid,
487 mPubKeyStore,
488 mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
489 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
490 0,
491 0,
492 &Variable,
493 NULL
494 );
495 ASSERT_EFI_ERROR (Status);
496 }
497
498 return Index;
499 }
500
501 /**
502 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
503 Follow the steps in UEFI2.2.
504
505 @param[in] Data Pointer to data with AuthInfo.
506 @param[in] DataSize Size of Data.
507 @param[in] PubKey Public key used for verification.
508
509 @retval EFI_INVALID_PARAMETER Invalid parameter.
510 @retval EFI_SECURITY_VIOLATION If authentication failed.
511 @retval EFI_SUCCESS Authentication successful.
512
513 **/
514 EFI_STATUS
515 VerifyCounterBasedPayload (
516 IN UINT8 *Data,
517 IN UINTN DataSize,
518 IN UINT8 *PubKey
519 )
520 {
521 BOOLEAN Status;
522 EFI_VARIABLE_AUTHENTICATION *CertData;
523 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
524 UINT8 Digest[SHA256_DIGEST_SIZE];
525 VOID *Rsa;
526
527 Rsa = NULL;
528 CertData = NULL;
529 CertBlock = NULL;
530
531 if (Data == NULL || PubKey == NULL) {
532 return EFI_INVALID_PARAMETER;
533 }
534
535 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
536 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
537
538 //
539 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
540 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
541 //
542 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
543 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)
544 ) {
545 //
546 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
547 //
548 return EFI_SECURITY_VIOLATION;
549 }
550 //
551 // Hash data payload with SHA256.
552 //
553 ZeroMem (Digest, SHA256_DIGEST_SIZE);
554 Status = Sha256Init (mHashCtx);
555 if (!Status) {
556 goto Done;
557 }
558 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
559 if (!Status) {
560 goto Done;
561 }
562 //
563 // Hash Monotonic Count.
564 //
565 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
566 if (!Status) {
567 goto Done;
568 }
569 Status = Sha256Final (mHashCtx, Digest);
570 if (!Status) {
571 goto Done;
572 }
573 //
574 // Generate & Initialize RSA Context.
575 //
576 Rsa = RsaNew ();
577 ASSERT (Rsa != NULL);
578 //
579 // Set RSA Key Components.
580 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
581 //
582 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
583 if (!Status) {
584 goto Done;
585 }
586 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
587 if (!Status) {
588 goto Done;
589 }
590 //
591 // Verify the signature.
592 //
593 Status = RsaPkcs1Verify (
594 Rsa,
595 Digest,
596 SHA256_DIGEST_SIZE,
597 CertBlock->Signature,
598 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
599 );
600
601 Done:
602 if (Rsa != NULL) {
603 RsaFree (Rsa);
604 }
605 if (Status) {
606 return EFI_SUCCESS;
607 } else {
608 return EFI_SECURITY_VIOLATION;
609 }
610 }
611
612 /**
613 Update platform mode.
614
615 @param[in] Mode SETUP_MODE or USER_MODE.
616
617 @return EFI_INVALID_PARAMETER Invalid parameter.
618 @return EFI_SUCCESS Update platform mode successfully.
619
620 **/
621 EFI_STATUS
622 UpdatePlatformMode (
623 IN UINT32 Mode
624 )
625 {
626 EFI_STATUS Status;
627 VARIABLE_POINTER_TRACK Variable;
628 UINT32 VarAttr;
629 UINT8 SecureBootMode;
630 UINT8 SecureBootEnable;
631 UINTN VariableDataSize;
632
633 Status = FindVariable (
634 EFI_SETUP_MODE_NAME,
635 &gEfiGlobalVariableGuid,
636 &Variable,
637 &mVariableModuleGlobal->VariableGlobal,
638 FALSE
639 );
640 if (EFI_ERROR (Status)) {
641 return Status;
642 }
643
644 mPlatformMode = Mode;
645 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
646 Status = UpdateVariable (
647 EFI_SETUP_MODE_NAME,
648 &gEfiGlobalVariableGuid,
649 &mPlatformMode,
650 sizeof(UINT8),
651 VarAttr,
652 0,
653 0,
654 &Variable,
655 NULL
656 );
657 if (EFI_ERROR (Status)) {
658 return Status;
659 }
660
661 if (AtRuntime ()) {
662 //
663 // SecureBoot Variable indicates whether the platform firmware is operating
664 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
665 // Variable in runtime.
666 //
667 return Status;
668 }
669
670 //
671 // Check "SecureBoot" variable's existence.
672 // If it doesn't exist, firmware has no capability to perform driver signing verification,
673 // then set "SecureBoot" to 0.
674 //
675 Status = FindVariable (
676 EFI_SECURE_BOOT_MODE_NAME,
677 &gEfiGlobalVariableGuid,
678 &Variable,
679 &mVariableModuleGlobal->VariableGlobal,
680 FALSE
681 );
682 //
683 // If "SecureBoot" variable exists, then check "SetupMode" variable update.
684 // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
685 // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
686 //
687 if (Variable.CurrPtr == NULL) {
688 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
689 } else {
690 if (mPlatformMode == USER_MODE) {
691 SecureBootMode = SECURE_BOOT_MODE_ENABLE;
692 } else if (mPlatformMode == SETUP_MODE) {
693 SecureBootMode = SECURE_BOOT_MODE_DISABLE;
694 } else {
695 return EFI_NOT_FOUND;
696 }
697 }
698
699 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
700 Status = UpdateVariable (
701 EFI_SECURE_BOOT_MODE_NAME,
702 &gEfiGlobalVariableGuid,
703 &SecureBootMode,
704 sizeof(UINT8),
705 VarAttr,
706 0,
707 0,
708 &Variable,
709 NULL
710 );
711 if (EFI_ERROR (Status)) {
712 return Status;
713 }
714
715 //
716 // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
717 //
718 Status = FindVariable (
719 EFI_SECURE_BOOT_ENABLE_NAME,
720 &gEfiSecureBootEnableDisableGuid,
721 &Variable,
722 &mVariableModuleGlobal->VariableGlobal,
723 FALSE
724 );
725
726 if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
727 //
728 // Create the "SecureBootEnable" variable as secure boot is enabled.
729 //
730 SecureBootEnable = SECURE_BOOT_ENABLE;
731 VariableDataSize = sizeof (SecureBootEnable);
732 } else {
733 //
734 // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
735 // variable is not in secure boot state.
736 //
737 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
738 return EFI_SUCCESS;
739 }
740 SecureBootEnable = SECURE_BOOT_DISABLE;
741 VariableDataSize = 0;
742 }
743
744 Status = UpdateVariable (
745 EFI_SECURE_BOOT_ENABLE_NAME,
746 &gEfiSecureBootEnableDisableGuid,
747 &SecureBootEnable,
748 VariableDataSize,
749 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
750 0,
751 0,
752 &Variable,
753 NULL
754 );
755 return Status;
756 }
757
758 /**
759 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.
760
761 @param[in] VariableName Name of Variable to be check.
762 @param[in] VendorGuid Variable vendor GUID.
763 @param[in] Data Point to the variable data to be checked.
764 @param[in] DataSize Size of Data.
765
766 @return EFI_INVALID_PARAMETER Invalid signature list format.
767 @return EFI_SUCCESS Passed signature list format check successfully.
768
769 **/
770 EFI_STATUS
771 CheckSignatureListFormat(
772 IN CHAR16 *VariableName,
773 IN EFI_GUID *VendorGuid,
774 IN VOID *Data,
775 IN UINTN DataSize
776 )
777 {
778 EFI_SIGNATURE_LIST *SigList;
779 UINTN SigDataSize;
780 UINT32 Index;
781 UINT32 SigCount;
782 BOOLEAN IsPk;
783
784 if (DataSize == 0) {
785 return EFI_SUCCESS;
786 }
787
788 ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
789
790 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
791 IsPk = TRUE;
792 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
793 IsPk = FALSE;
794 } else {
795 return EFI_SUCCESS;
796 }
797
798 SigCount = 0;
799 SigList = (EFI_SIGNATURE_LIST *) Data;
800 SigDataSize = DataSize;
801
802 //
803 // Walk throuth the input signature list and check the data format.
804 // If any signature is incorrectly formed, the whole check will fail.
805 //
806 while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
807 for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
808 if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
809 //
810 // The value of SignatureSize should always be 16 (size of SignatureOwner
811 // component) add the data length according to signature type.
812 //
813 if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
814 (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
815 return EFI_INVALID_PARAMETER;
816 }
817 if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&
818 SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
819 return EFI_INVALID_PARAMETER;
820 }
821 break;
822 }
823 }
824
825 if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
826 //
827 // Undefined signature type.
828 //
829 return EFI_INVALID_PARAMETER;
830 }
831
832 if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
833 return EFI_INVALID_PARAMETER;
834 }
835 SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
836
837 SigDataSize -= SigList->SignatureListSize;
838 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
839 }
840
841 if (((UINTN) SigList - (UINTN) Data) != DataSize) {
842 return EFI_INVALID_PARAMETER;
843 }
844
845 if (IsPk && SigCount > 1) {
846 return EFI_INVALID_PARAMETER;
847 }
848
849 return EFI_SUCCESS;
850 }
851
852 /**
853 Process variable with platform key for verification.
854
855 @param[in] VariableName Name of Variable to be found.
856 @param[in] VendorGuid Variable vendor GUID.
857 @param[in] Data Data pointer.
858 @param[in] DataSize Size of Data found. If size is less than the
859 data, this value contains the required size.
860 @param[in] Variable The variable information which is used to keep track of variable usage.
861 @param[in] Attributes Attribute value of the variable
862 @param[in] IsPk Indicate whether it is to process pk.
863
864 @return EFI_INVALID_PARAMETER Invalid parameter.
865 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
866 check carried out by the firmware.
867 @return EFI_SUCCESS Variable passed validation successfully.
868
869 **/
870 EFI_STATUS
871 ProcessVarWithPk (
872 IN CHAR16 *VariableName,
873 IN EFI_GUID *VendorGuid,
874 IN VOID *Data,
875 IN UINTN DataSize,
876 IN VARIABLE_POINTER_TRACK *Variable,
877 IN UINT32 Attributes OPTIONAL,
878 IN BOOLEAN IsPk
879 )
880 {
881 EFI_STATUS Status;
882 VARIABLE_POINTER_TRACK PkVariable;
883 EFI_SIGNATURE_LIST *OldPkList;
884 EFI_SIGNATURE_DATA *OldPkData;
885 EFI_VARIABLE_AUTHENTICATION *CertData;
886 BOOLEAN TimeBase;
887 BOOLEAN Del;
888 UINT8 *Payload;
889 UINTN PayloadSize;
890 UINT64 MonotonicCount;
891 EFI_TIME *TimeStamp;
892
893 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
894 //
895 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
896 //
897 return EFI_INVALID_PARAMETER;
898 }
899
900 if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
901
902 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
903 //
904 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.
905 //
906 TimeBase = TRUE;
907 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
908 //
909 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.
910 //
911 TimeBase = FALSE;
912 } else {
913 return EFI_INVALID_PARAMETER;
914 }
915
916 if (TimeBase) {
917 //
918 // Verify against X509 Cert PK.
919 //
920 Del = FALSE;
921 Status = VerifyTimeBasedPayload (
922 VariableName,
923 VendorGuid,
924 Data,
925 DataSize,
926 Variable,
927 Attributes,
928 AuthVarTypePk,
929 &Del
930 );
931 if (!EFI_ERROR (Status)) {
932 //
933 // If delete PK in user mode, need change to setup mode.
934 //
935 if (Del && IsPk) {
936 Status = UpdatePlatformMode (SETUP_MODE);
937 }
938 }
939 return Status;
940 } else {
941 //
942 // Verify against RSA2048 Cert PK.
943 //
944 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
945 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
946 //
947 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
948 //
949 return EFI_SECURITY_VIOLATION;
950 }
951 //
952 // Get platform key from variable.
953 //
954 Status = FindVariable (
955 EFI_PLATFORM_KEY_NAME,
956 &gEfiGlobalVariableGuid,
957 &PkVariable,
958 &mVariableModuleGlobal->VariableGlobal,
959 FALSE
960 );
961 ASSERT_EFI_ERROR (Status);
962
963 OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
964 OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
965 Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);
966 if (!EFI_ERROR (Status)) {
967 Status = CheckSignatureListFormat(
968 VariableName,
969 VendorGuid,
970 (UINT8*)Data + AUTHINFO_SIZE,
971 DataSize - AUTHINFO_SIZE);
972 if (EFI_ERROR (Status)) {
973 return Status;
974 }
975
976 Status = UpdateVariable (
977 VariableName,
978 VendorGuid,
979 (UINT8*)Data + AUTHINFO_SIZE,
980 DataSize - AUTHINFO_SIZE,
981 Attributes,
982 0,
983 CertData->MonotonicCount,
984 Variable,
985 NULL
986 );
987
988 if (!EFI_ERROR (Status)) {
989 //
990 // If delete PK in user mode, need change to setup mode.
991 //
992 if ((DataSize == AUTHINFO_SIZE) && IsPk) {
993 Status = UpdatePlatformMode (SETUP_MODE);
994 }
995 }
996 }
997 }
998 } else {
999 //
1000 // Process PK or KEK in Setup mode or Custom Secure Boot mode.
1001 //
1002 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1003 //
1004 // Time-based Authentication descriptor.
1005 //
1006 MonotonicCount = 0;
1007 TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;
1008 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
1009 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
1010 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1011 //
1012 // Counter-based Authentication descriptor.
1013 //
1014 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;
1015 TimeStamp = NULL;
1016 Payload = (UINT8*) Data + AUTHINFO_SIZE;
1017 PayloadSize = DataSize - AUTHINFO_SIZE;
1018 } else {
1019 //
1020 // No Authentication descriptor.
1021 //
1022 MonotonicCount = 0;
1023 TimeStamp = NULL;
1024 Payload = Data;
1025 PayloadSize = DataSize;
1026 }
1027
1028 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
1029 if (EFI_ERROR (Status)) {
1030 return Status;
1031 }
1032
1033 Status = UpdateVariable (
1034 VariableName,
1035 VendorGuid,
1036 Payload,
1037 PayloadSize,
1038 Attributes,
1039 0,
1040 MonotonicCount,
1041 Variable,
1042 TimeStamp
1043 );
1044
1045 if (IsPk) {
1046 if (PayloadSize != 0) {
1047 //
1048 // If enroll PK in setup mode, need change to user mode.
1049 //
1050 Status = UpdatePlatformMode (USER_MODE);
1051 } else {
1052 //
1053 // If delete PK in custom mode, need change to setup mode.
1054 //
1055 UpdatePlatformMode (SETUP_MODE);
1056 }
1057 }
1058 }
1059
1060 return Status;
1061 }
1062
1063 /**
1064 Process variable with key exchange key for verification.
1065
1066 @param[in] VariableName Name of Variable to be found.
1067 @param[in] VendorGuid Variable vendor GUID.
1068 @param[in] Data Data pointer.
1069 @param[in] DataSize Size of Data found. If size is less than the
1070 data, this value contains the required size.
1071 @param[in] Variable The variable information which is used to keep track of variable usage.
1072 @param[in] Attributes Attribute value of the variable.
1073
1074 @return EFI_INVALID_PARAMETER Invalid parameter.
1075 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1076 check carried out by the firmware.
1077 @return EFI_SUCCESS Variable pass validation successfully.
1078
1079 **/
1080 EFI_STATUS
1081 ProcessVarWithKek (
1082 IN CHAR16 *VariableName,
1083 IN EFI_GUID *VendorGuid,
1084 IN VOID *Data,
1085 IN UINTN DataSize,
1086 IN VARIABLE_POINTER_TRACK *Variable,
1087 IN UINT32 Attributes OPTIONAL
1088 )
1089 {
1090 EFI_STATUS Status;
1091 VARIABLE_POINTER_TRACK KekVariable;
1092 EFI_SIGNATURE_LIST *KekList;
1093 EFI_SIGNATURE_DATA *KekItem;
1094 UINT32 KekCount;
1095 EFI_VARIABLE_AUTHENTICATION *CertData;
1096 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
1097 BOOLEAN IsFound;
1098 UINT32 Index;
1099 UINT32 KekDataSize;
1100 UINT8 *Payload;
1101 UINTN PayloadSize;
1102 UINT64 MonotonicCount;
1103 EFI_TIME *TimeStamp;
1104
1105 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1106 //
1107 // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute.
1108 //
1109 return EFI_INVALID_PARAMETER;
1110 }
1111
1112 Status = EFI_SUCCESS;
1113 if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
1114 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) &&
1115 ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)){
1116 //
1117 // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or
1118 // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute.
1119 //
1120 return EFI_INVALID_PARAMETER;
1121 }
1122
1123 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1124 //
1125 // Time-based, verify against X509 Cert KEK.
1126 //
1127 return VerifyTimeBasedPayload (
1128 VariableName,
1129 VendorGuid,
1130 Data,
1131 DataSize,
1132 Variable,
1133 Attributes,
1134 AuthVarTypeKek,
1135 NULL
1136 );
1137 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1138 //
1139 // Counter-based, verify against RSA2048 Cert KEK.
1140 //
1141 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
1142 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
1143 if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {
1144 //
1145 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1146 //
1147 return EFI_SECURITY_VIOLATION;
1148 }
1149 //
1150 // Get KEK database from variable.
1151 //
1152 Status = FindVariable (
1153 EFI_KEY_EXCHANGE_KEY_NAME,
1154 &gEfiGlobalVariableGuid,
1155 &KekVariable,
1156 &mVariableModuleGlobal->VariableGlobal,
1157 FALSE
1158 );
1159 ASSERT_EFI_ERROR (Status);
1160
1161 KekDataSize = KekVariable.CurrPtr->DataSize;
1162 KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
1163
1164 //
1165 // Enumerate all Kek items in this list to verify the variable certificate data.
1166 // If anyone is authenticated successfully, it means the variable is correct!
1167 //
1168 IsFound = FALSE;
1169 while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {
1170 if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {
1171 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
1172 KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
1173 for (Index = 0; Index < KekCount; Index++) {
1174 if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
1175 IsFound = TRUE;
1176 break;
1177 }
1178 KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
1179 }
1180 }
1181 KekDataSize -= KekList->SignatureListSize;
1182 KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
1183 }
1184
1185 if (!IsFound) {
1186 return EFI_SECURITY_VIOLATION;
1187 }
1188
1189 Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);
1190 if (!EFI_ERROR (Status)) {
1191 Status = UpdateVariable (
1192 VariableName,
1193 VendorGuid,
1194 (UINT8*)Data + AUTHINFO_SIZE,
1195 DataSize - AUTHINFO_SIZE,
1196 Attributes,
1197 0,
1198 CertData->MonotonicCount,
1199 Variable,
1200 NULL
1201 );
1202 }
1203 }
1204 } else {
1205 //
1206 // If in setup mode or custom secure boot mode, no authentication needed.
1207 //
1208 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1209 //
1210 // Time-based Authentication descriptor.
1211 //
1212 MonotonicCount = 0;
1213 TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;
1214 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
1215 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
1216 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1217 //
1218 // Counter-based Authentication descriptor.
1219 //
1220 MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;
1221 TimeStamp = NULL;
1222 Payload = (UINT8*) Data + AUTHINFO_SIZE;
1223 PayloadSize = DataSize - AUTHINFO_SIZE;
1224 } else {
1225 //
1226 // No Authentication descriptor.
1227 //
1228 MonotonicCount = 0;
1229 TimeStamp = NULL;
1230 Payload = Data;
1231 PayloadSize = DataSize;
1232 }
1233
1234 Status = UpdateVariable (
1235 VariableName,
1236 VendorGuid,
1237 Payload,
1238 PayloadSize,
1239 Attributes,
1240 0,
1241 MonotonicCount,
1242 Variable,
1243 TimeStamp
1244 );
1245 }
1246
1247 return Status;
1248 }
1249
1250 /**
1251 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1252
1253 @param[in] VariableName Name of Variable to be found.
1254 @param[in] VendorGuid Variable vendor GUID.
1255
1256 @param[in] Data Data pointer.
1257 @param[in] DataSize Size of Data found. If size is less than the
1258 data, this value contains the required size.
1259 @param[in] Variable The variable information which is used to keep track of variable usage.
1260 @param[in] Attributes Attribute value of the variable.
1261
1262 @return EFI_INVALID_PARAMETER Invalid parameter.
1263 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
1264 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1265 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1266 set, but the AuthInfo does NOT pass the validation
1267 check carried out by the firmware.
1268 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
1269
1270 **/
1271 EFI_STATUS
1272 ProcessVariable (
1273 IN CHAR16 *VariableName,
1274 IN EFI_GUID *VendorGuid,
1275 IN VOID *Data,
1276 IN UINTN DataSize,
1277 IN VARIABLE_POINTER_TRACK *Variable,
1278 IN UINT32 Attributes
1279 )
1280 {
1281 EFI_STATUS Status;
1282 BOOLEAN IsDeletion;
1283 BOOLEAN IsFirstTime;
1284 UINT8 *PubKey;
1285 EFI_VARIABLE_AUTHENTICATION *CertData;
1286 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
1287 UINT32 KeyIndex;
1288 UINT64 MonotonicCount;
1289
1290 KeyIndex = 0;
1291 CertData = NULL;
1292 CertBlock = NULL;
1293 PubKey = NULL;
1294 IsDeletion = FALSE;
1295
1296 if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {
1297 //
1298 // This variable is protected, only physical present user could modify its value.
1299 //
1300 return EFI_SECURITY_VIOLATION;
1301 }
1302
1303 //
1304 // Process Time-based Authenticated variable.
1305 //
1306 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1307 return VerifyTimeBasedPayload (
1308 VariableName,
1309 VendorGuid,
1310 Data,
1311 DataSize,
1312 Variable,
1313 Attributes,
1314 AuthVarTypePriv,
1315 NULL
1316 );
1317 }
1318
1319 //
1320 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
1321 //
1322 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1323 //
1324 // Determine current operation type.
1325 //
1326 if (DataSize == AUTHINFO_SIZE) {
1327 IsDeletion = TRUE;
1328 }
1329 //
1330 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1331 //
1332 if (Variable->CurrPtr == NULL) {
1333 IsFirstTime = TRUE;
1334 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
1335 IsFirstTime = TRUE;
1336 } else {
1337 KeyIndex = Variable->CurrPtr->PubKeyIndex;
1338 IsFirstTime = FALSE;
1339 }
1340 } else if ((Variable->CurrPtr != NULL) &&
1341 ((Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
1342 ) {
1343 //
1344 // If the variable is already write-protected, it always needs authentication before update.
1345 //
1346 return EFI_WRITE_PROTECTED;
1347 } else {
1348 //
1349 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
1350 // That means it is not authenticated variable, just update variable as usual.
1351 //
1352 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
1353 return Status;
1354 }
1355
1356 //
1357 // Get PubKey and check Monotonic Count value corresponding to the variable.
1358 //
1359 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
1360 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
1361 PubKey = CertBlock->PublicKey;
1362
1363 //
1364 // Update Monotonic Count value.
1365 //
1366 MonotonicCount = CertData->MonotonicCount;
1367
1368 if (!IsFirstTime) {
1369 //
1370 // Check input PubKey.
1371 //
1372 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
1373 return EFI_SECURITY_VIOLATION;
1374 }
1375 //
1376 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
1377 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
1378 //
1379 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {
1380 //
1381 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1382 //
1383 return EFI_SECURITY_VIOLATION;
1384 }
1385 }
1386 //
1387 // Verify the certificate in Data payload.
1388 //
1389 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
1390 if (EFI_ERROR (Status)) {
1391 return Status;
1392 }
1393
1394 //
1395 // Now, the signature has been verified!
1396 //
1397 if (IsFirstTime && !IsDeletion) {
1398 //
1399 // Update public key database variable if need.
1400 //
1401 KeyIndex = AddPubKeyInStore (PubKey);
1402 }
1403
1404 //
1405 // Verification pass.
1406 //
1407 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
1408 }
1409
1410 /**
1411 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
1412 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
1413 will be ignored.
1414
1415 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
1416 @param[in] DataSize Size of Data buffer.
1417 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
1418 @param[in] NewDataSize Size of NewData buffer.
1419
1420 @return Size of the merged buffer.
1421
1422 **/
1423 UINTN
1424 AppendSignatureList (
1425 IN OUT VOID *Data,
1426 IN UINTN DataSize,
1427 IN VOID *NewData,
1428 IN UINTN NewDataSize
1429 )
1430 {
1431 EFI_SIGNATURE_LIST *CertList;
1432 EFI_SIGNATURE_DATA *Cert;
1433 UINTN CertCount;
1434 EFI_SIGNATURE_LIST *NewCertList;
1435 EFI_SIGNATURE_DATA *NewCert;
1436 UINTN NewCertCount;
1437 UINTN Index;
1438 UINTN Index2;
1439 UINTN Size;
1440 UINT8 *Tail;
1441 UINTN CopiedCount;
1442 UINTN SignatureListSize;
1443 BOOLEAN IsNewCert;
1444
1445 Tail = (UINT8 *) Data + DataSize;
1446
1447 NewCertList = (EFI_SIGNATURE_LIST *) NewData;
1448 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {
1449 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1450 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
1451
1452 CopiedCount = 0;
1453 for (Index = 0; Index < NewCertCount; Index++) {
1454 IsNewCert = TRUE;
1455
1456 Size = DataSize;
1457 CertList = (EFI_SIGNATURE_LIST *) Data;
1458 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
1459 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
1460 (CertList->SignatureSize == NewCertList->SignatureSize)) {
1461 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1462 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1463 for (Index2 = 0; Index2 < CertCount; Index2++) {
1464 //
1465 // Iterate each Signature Data in this Signature List.
1466 //
1467 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
1468 IsNewCert = FALSE;
1469 break;
1470 }
1471 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1472 }
1473 }
1474
1475 if (!IsNewCert) {
1476 break;
1477 }
1478 Size -= CertList->SignatureListSize;
1479 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1480 }
1481
1482 if (IsNewCert) {
1483 //
1484 // New EFI_SIGNATURE_DATA, append it.
1485 //
1486 if (CopiedCount == 0) {
1487 //
1488 // Copy EFI_SIGNATURE_LIST header for only once.
1489 //
1490 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1491 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
1492 }
1493
1494 CopyMem (Tail, NewCert, NewCertList->SignatureSize);
1495 Tail += NewCertList->SignatureSize;
1496 CopiedCount++;
1497 }
1498
1499 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
1500 }
1501
1502 //
1503 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
1504 //
1505 if (CopiedCount != 0) {
1506 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
1507 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
1508 CertList->SignatureListSize = (UINT32) SignatureListSize;
1509 }
1510
1511 NewDataSize -= NewCertList->SignatureListSize;
1512 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
1513 }
1514
1515 return (Tail - (UINT8 *) Data);
1516 }
1517
1518 /**
1519 Compare two EFI_TIME data.
1520
1521
1522 @param FirstTime A pointer to the first EFI_TIME data.
1523 @param SecondTime A pointer to the second EFI_TIME data.
1524
1525 @retval TRUE The FirstTime is not later than the SecondTime.
1526 @retval FALSE The FirstTime is later than the SecondTime.
1527
1528 **/
1529 BOOLEAN
1530 CompareTimeStamp (
1531 IN EFI_TIME *FirstTime,
1532 IN EFI_TIME *SecondTime
1533 )
1534 {
1535 if (FirstTime->Year != SecondTime->Year) {
1536 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
1537 } else if (FirstTime->Month != SecondTime->Month) {
1538 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
1539 } else if (FirstTime->Day != SecondTime->Day) {
1540 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
1541 } else if (FirstTime->Hour != SecondTime->Hour) {
1542 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
1543 } else if (FirstTime->Minute != SecondTime->Minute) {
1544 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
1545 }
1546
1547 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
1548 }
1549
1550 /**
1551 Find matching signer's certificates for common authenticated variable
1552 by corresponding VariableName and VendorGuid from "certdb".
1553
1554 The data format of "certdb":
1555 //
1556 // UINT32 CertDbListSize;
1557 // /// AUTH_CERT_DB_DATA Certs1[];
1558 // /// AUTH_CERT_DB_DATA Certs2[];
1559 // /// ...
1560 // /// AUTH_CERT_DB_DATA Certsn[];
1561 //
1562
1563 @param[in] VariableName Name of authenticated Variable.
1564 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1565 @param[in] Data Pointer to variable "certdb".
1566 @param[in] DataSize Size of variable "certdb".
1567 @param[out] CertOffset Offset of matching CertData, from starting of Data.
1568 @param[out] CertDataSize Length of CertData in bytes.
1569 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
1570 starting of Data.
1571 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
1572
1573 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1574 @retval EFI_NOT_FOUND Fail to find matching certs.
1575 @retval EFI_SUCCESS Find matching certs and output parameters.
1576
1577 **/
1578 EFI_STATUS
1579 FindCertsFromDb (
1580 IN CHAR16 *VariableName,
1581 IN EFI_GUID *VendorGuid,
1582 IN UINT8 *Data,
1583 IN UINTN DataSize,
1584 OUT UINT32 *CertOffset, OPTIONAL
1585 OUT UINT32 *CertDataSize, OPTIONAL
1586 OUT UINT32 *CertNodeOffset,OPTIONAL
1587 OUT UINT32 *CertNodeSize OPTIONAL
1588 )
1589 {
1590 UINT32 Offset;
1591 AUTH_CERT_DB_DATA *Ptr;
1592 UINT32 CertSize;
1593 UINT32 NameSize;
1594 UINT32 NodeSize;
1595 UINT32 CertDbListSize;
1596
1597 if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
1598 return EFI_INVALID_PARAMETER;
1599 }
1600
1601 //
1602 // Check whether DataSize matches recorded CertDbListSize.
1603 //
1604 if (DataSize < sizeof (UINT32)) {
1605 return EFI_INVALID_PARAMETER;
1606 }
1607
1608 CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
1609
1610 if (CertDbListSize != (UINT32) DataSize) {
1611 return EFI_INVALID_PARAMETER;
1612 }
1613
1614 Offset = sizeof (UINT32);
1615
1616 //
1617 // Get corresponding certificates by VendorGuid and VariableName.
1618 //
1619 while (Offset < (UINT32) DataSize) {
1620 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
1621 //
1622 // Check whether VendorGuid matches.
1623 //
1624 if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
1625 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
1626 NameSize = ReadUnaligned32 (&Ptr->NameSize);
1627 CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
1628
1629 if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
1630 sizeof (CHAR16) * NameSize) {
1631 return EFI_INVALID_PARAMETER;
1632 }
1633
1634 Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
1635 //
1636 // Check whether VariableName matches.
1637 //
1638 if ((NameSize == StrLen (VariableName)) &&
1639 (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
1640 Offset = Offset + NameSize * sizeof (CHAR16);
1641
1642 if (CertOffset != NULL) {
1643 *CertOffset = Offset;
1644 }
1645
1646 if (CertDataSize != NULL) {
1647 *CertDataSize = CertSize;
1648 }
1649
1650 if (CertNodeOffset != NULL) {
1651 *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
1652 }
1653
1654 if (CertNodeSize != NULL) {
1655 *CertNodeSize = NodeSize;
1656 }
1657
1658 return EFI_SUCCESS;
1659 } else {
1660 Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
1661 }
1662 } else {
1663 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
1664 Offset = Offset + NodeSize;
1665 }
1666 }
1667
1668 return EFI_NOT_FOUND;
1669 }
1670
1671 /**
1672 Retrieve signer's certificates for common authenticated variable
1673 by corresponding VariableName and VendorGuid from "certdb".
1674
1675 @param[in] VariableName Name of authenticated Variable.
1676 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1677 @param[out] CertData Pointer to signer's certificates.
1678 @param[out] CertDataSize Length of CertData in bytes.
1679
1680 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1681 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1682 @retval EFI_SUCCESS Get signer's certificates successfully.
1683
1684 **/
1685 EFI_STATUS
1686 GetCertsFromDb (
1687 IN CHAR16 *VariableName,
1688 IN EFI_GUID *VendorGuid,
1689 OUT UINT8 **CertData,
1690 OUT UINT32 *CertDataSize
1691 )
1692 {
1693 VARIABLE_POINTER_TRACK CertDbVariable;
1694 EFI_STATUS Status;
1695 UINT8 *Data;
1696 UINTN DataSize;
1697 UINT32 CertOffset;
1698
1699 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
1700 return EFI_INVALID_PARAMETER;
1701 }
1702
1703 //
1704 // Get variable "certdb".
1705 //
1706 Status = FindVariable (
1707 EFI_CERT_DB_NAME,
1708 &gEfiCertDbGuid,
1709 &CertDbVariable,
1710 &mVariableModuleGlobal->VariableGlobal,
1711 FALSE
1712 );
1713 if (EFI_ERROR (Status)) {
1714 return Status;
1715 }
1716
1717 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1718 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1719 if ((DataSize == 0) || (Data == NULL)) {
1720 ASSERT (FALSE);
1721 return EFI_NOT_FOUND;
1722 }
1723
1724 Status = FindCertsFromDb (
1725 VariableName,
1726 VendorGuid,
1727 Data,
1728 DataSize,
1729 &CertOffset,
1730 CertDataSize,
1731 NULL,
1732 NULL
1733 );
1734
1735 if (EFI_ERROR (Status)) {
1736 return Status;
1737 }
1738
1739 *CertData = Data + CertOffset;
1740 return EFI_SUCCESS;
1741 }
1742
1743 /**
1744 Delete matching signer's certificates when deleting common authenticated
1745 variable by corresponding VariableName and VendorGuid from "certdb".
1746
1747 @param[in] VariableName Name of authenticated Variable.
1748 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1749
1750 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1751 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1752 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1753 @retval EFI_SUCCESS The operation is completed successfully.
1754
1755 **/
1756 EFI_STATUS
1757 DeleteCertsFromDb (
1758 IN CHAR16 *VariableName,
1759 IN EFI_GUID *VendorGuid
1760 )
1761 {
1762 VARIABLE_POINTER_TRACK CertDbVariable;
1763 EFI_STATUS Status;
1764 UINT8 *Data;
1765 UINTN DataSize;
1766 UINT32 VarAttr;
1767 UINT32 CertNodeOffset;
1768 UINT32 CertNodeSize;
1769 UINT8 *NewCertDb;
1770 UINT32 NewCertDbSize;
1771
1772 if ((VariableName == NULL) || (VendorGuid == NULL)) {
1773 return EFI_INVALID_PARAMETER;
1774 }
1775
1776 //
1777 // Get variable "certdb".
1778 //
1779 Status = FindVariable (
1780 EFI_CERT_DB_NAME,
1781 &gEfiCertDbGuid,
1782 &CertDbVariable,
1783 &mVariableModuleGlobal->VariableGlobal,
1784 FALSE
1785 );
1786 if (EFI_ERROR (Status)) {
1787 return Status;
1788 }
1789
1790 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1791 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1792 if ((DataSize == 0) || (Data == NULL)) {
1793 ASSERT (FALSE);
1794 return EFI_NOT_FOUND;
1795 }
1796
1797 if (DataSize == sizeof (UINT32)) {
1798 //
1799 // There is no certs in certdb.
1800 //
1801 return EFI_SUCCESS;
1802 }
1803
1804 //
1805 // Get corresponding cert node from certdb.
1806 //
1807 Status = FindCertsFromDb (
1808 VariableName,
1809 VendorGuid,
1810 Data,
1811 DataSize,
1812 NULL,
1813 NULL,
1814 &CertNodeOffset,
1815 &CertNodeSize
1816 );
1817
1818 if (EFI_ERROR (Status)) {
1819 return Status;
1820 }
1821
1822 if (DataSize < (CertNodeOffset + CertNodeSize)) {
1823 return EFI_NOT_FOUND;
1824 }
1825
1826 //
1827 // Construct new data content of variable "certdb".
1828 //
1829 NewCertDbSize = (UINT32) DataSize - CertNodeSize;
1830 NewCertDb = AllocateZeroPool (NewCertDbSize);
1831 if (NewCertDb == NULL) {
1832 return EFI_OUT_OF_RESOURCES;
1833 }
1834
1835 //
1836 // Copy the DB entries before deleting node.
1837 //
1838 CopyMem (NewCertDb, Data, CertNodeOffset);
1839 //
1840 // Update CertDbListSize.
1841 //
1842 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
1843 //
1844 // Copy the DB entries after deleting node.
1845 //
1846 if (DataSize > (CertNodeOffset + CertNodeSize)) {
1847 CopyMem (
1848 NewCertDb + CertNodeOffset,
1849 Data + CertNodeOffset + CertNodeSize,
1850 DataSize - CertNodeOffset - CertNodeSize
1851 );
1852 }
1853
1854 //
1855 // Set "certdb".
1856 //
1857 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1858 Status = UpdateVariable (
1859 EFI_CERT_DB_NAME,
1860 &gEfiCertDbGuid,
1861 NewCertDb,
1862 NewCertDbSize,
1863 VarAttr,
1864 0,
1865 0,
1866 &CertDbVariable,
1867 NULL
1868 );
1869
1870 FreePool (NewCertDb);
1871 return Status;
1872 }
1873
1874 /**
1875 Insert signer's certificates for common authenticated variable with VariableName
1876 and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
1877
1878 @param[in] VariableName Name of authenticated Variable.
1879 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1880 @param[in] CertData Pointer to signer's certificates.
1881 @param[in] CertDataSize Length of CertData in bytes.
1882
1883 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1884 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
1885 and VendorGuid already exists.
1886 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1887 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"
1888
1889 **/
1890 EFI_STATUS
1891 InsertCertsToDb (
1892 IN CHAR16 *VariableName,
1893 IN EFI_GUID *VendorGuid,
1894 IN UINT8 *CertData,
1895 IN UINTN CertDataSize
1896 )
1897 {
1898 VARIABLE_POINTER_TRACK CertDbVariable;
1899 EFI_STATUS Status;
1900 UINT8 *Data;
1901 UINTN DataSize;
1902 UINT32 VarAttr;
1903 UINT8 *NewCertDb;
1904 UINT32 NewCertDbSize;
1905 UINT32 CertNodeSize;
1906 UINT32 NameSize;
1907 AUTH_CERT_DB_DATA *Ptr;
1908
1909 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
1910 return EFI_INVALID_PARAMETER;
1911 }
1912
1913 //
1914 // Get variable "certdb".
1915 //
1916 Status = FindVariable (
1917 EFI_CERT_DB_NAME,
1918 &gEfiCertDbGuid,
1919 &CertDbVariable,
1920 &mVariableModuleGlobal->VariableGlobal,
1921 FALSE
1922 );
1923 if (EFI_ERROR (Status)) {
1924 return Status;
1925 }
1926
1927 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1928 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1929 if ((DataSize == 0) || (Data == NULL)) {
1930 ASSERT (FALSE);
1931 return EFI_NOT_FOUND;
1932 }
1933
1934 //
1935 // Find whether matching cert node already exists in "certdb".
1936 // If yes return error.
1937 //
1938 Status = FindCertsFromDb (
1939 VariableName,
1940 VendorGuid,
1941 Data,
1942 DataSize,
1943 NULL,
1944 NULL,
1945 NULL,
1946 NULL
1947 );
1948
1949 if (!EFI_ERROR (Status)) {
1950 ASSERT (FALSE);
1951 return EFI_ACCESS_DENIED;
1952 }
1953
1954 //
1955 // Construct new data content of variable "certdb".
1956 //
1957 NameSize = (UINT32) StrLen (VariableName);
1958 CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
1959 NewCertDbSize = (UINT32) DataSize + CertNodeSize;
1960 NewCertDb = AllocateZeroPool (NewCertDbSize);
1961 if (NewCertDb == NULL) {
1962 return EFI_OUT_OF_RESOURCES;
1963 }
1964
1965 //
1966 // Copy the DB entries before deleting node.
1967 //
1968 CopyMem (NewCertDb, Data, DataSize);
1969 //
1970 // Update CertDbListSize.
1971 //
1972 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
1973 //
1974 // Construct new cert node.
1975 //
1976 Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
1977 CopyGuid (&Ptr->VendorGuid, VendorGuid);
1978 CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
1979 CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
1980 CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
1981
1982 CopyMem (
1983 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
1984 VariableName,
1985 NameSize * sizeof (CHAR16)
1986 );
1987
1988 CopyMem (
1989 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
1990 CertData,
1991 CertDataSize
1992 );
1993
1994 //
1995 // Set "certdb".
1996 //
1997 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1998 Status = UpdateVariable (
1999 EFI_CERT_DB_NAME,
2000 &gEfiCertDbGuid,
2001 NewCertDb,
2002 NewCertDbSize,
2003 VarAttr,
2004 0,
2005 0,
2006 &CertDbVariable,
2007 NULL
2008 );
2009
2010 FreePool (NewCertDb);
2011 return Status;
2012 }
2013
2014 /**
2015 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
2016
2017 @param[in] VariableName Name of Variable to be found.
2018 @param[in] VendorGuid Variable vendor GUID.
2019 @param[in] Data Data pointer.
2020 @param[in] DataSize Size of Data found. If size is less than the
2021 data, this value contains the required size.
2022 @param[in] Variable The variable information which is used to keep track of variable usage.
2023 @param[in] Attributes Attribute value of the variable.
2024 @param[in] AuthVarType Verify against PK or KEK database or private database.
2025 @param[out] VarDel Delete the variable or not.
2026
2027 @retval EFI_INVALID_PARAMETER Invalid parameter.
2028 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
2029 check carried out by the firmware.
2030 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
2031 of resources.
2032 @retval EFI_SUCCESS Variable pass validation successfully.
2033
2034 **/
2035 EFI_STATUS
2036 VerifyTimeBasedPayload (
2037 IN CHAR16 *VariableName,
2038 IN EFI_GUID *VendorGuid,
2039 IN VOID *Data,
2040 IN UINTN DataSize,
2041 IN VARIABLE_POINTER_TRACK *Variable,
2042 IN UINT32 Attributes,
2043 IN AUTHVAR_TYPE AuthVarType,
2044 OUT BOOLEAN *VarDel
2045 )
2046 {
2047 UINT8 *RootCert;
2048 UINT8 *SigData;
2049 UINT8 *PayloadPtr;
2050 UINTN RootCertSize;
2051 UINTN Index;
2052 UINTN CertCount;
2053 UINTN PayloadSize;
2054 UINT32 Attr;
2055 UINT32 SigDataSize;
2056 UINT32 KekDataSize;
2057 BOOLEAN VerifyStatus;
2058 EFI_STATUS Status;
2059 EFI_SIGNATURE_LIST *CertList;
2060 EFI_SIGNATURE_DATA *Cert;
2061 VARIABLE_POINTER_TRACK KekVariable;
2062 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
2063 UINT8 *NewData;
2064 UINTN NewDataSize;
2065 VARIABLE_POINTER_TRACK PkVariable;
2066 UINT8 *Buffer;
2067 UINTN Length;
2068 UINT8 *SignerCerts;
2069 UINT8 *WrapSigData;
2070 UINTN CertStackSize;
2071 UINT8 *CertsInCertDb;
2072 UINT32 CertsSizeinDb;
2073
2074 VerifyStatus = FALSE;
2075 CertData = NULL;
2076 NewData = NULL;
2077 Attr = Attributes;
2078 WrapSigData = NULL;
2079 SignerCerts = NULL;
2080 RootCert = NULL;
2081
2082 //
2083 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
2084 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
2085 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
2086 // variable value and DataSize shall reflect the combined size of the descriptor and the new
2087 // variable value. The authentication descriptor is not part of the variable data and is not
2088 // returned by subsequent calls to GetVariable().
2089 //
2090 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
2091
2092 //
2093 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
2094 // TimeStamp value are set to zero.
2095 //
2096 if ((CertData->TimeStamp.Pad1 != 0) ||
2097 (CertData->TimeStamp.Nanosecond != 0) ||
2098 (CertData->TimeStamp.TimeZone != 0) ||
2099 (CertData->TimeStamp.Daylight != 0) ||
2100 (CertData->TimeStamp.Pad2 != 0)) {
2101 return EFI_SECURITY_VIOLATION;
2102 }
2103
2104 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
2105 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
2106 //
2107 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
2108 //
2109 return EFI_SECURITY_VIOLATION;
2110 }
2111 }
2112
2113 //
2114 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
2115 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
2116 //
2117 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
2118 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
2119 //
2120 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
2121 //
2122 return EFI_SECURITY_VIOLATION;
2123 }
2124
2125 //
2126 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2127 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
2128 //
2129 SigData = CertData->AuthInfo.CertData;
2130 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
2131
2132 //
2133 // Find out the new data payload which follows Pkcs7 SignedData directly.
2134 //
2135 PayloadPtr = SigData + SigDataSize;
2136 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
2137
2138 //
2139 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
2140 //
2141 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
2142 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
2143 NewData = mSerializationRuntimeBuffer;
2144
2145 Buffer = NewData;
2146 Length = StrLen (VariableName) * sizeof (CHAR16);
2147 CopyMem (Buffer, VariableName, Length);
2148 Buffer += Length;
2149
2150 Length = sizeof (EFI_GUID);
2151 CopyMem (Buffer, VendorGuid, Length);
2152 Buffer += Length;
2153
2154 Length = sizeof (UINT32);
2155 CopyMem (Buffer, &Attr, Length);
2156 Buffer += Length;
2157
2158 Length = sizeof (EFI_TIME);
2159 CopyMem (Buffer, &CertData->TimeStamp, Length);
2160 Buffer += Length;
2161
2162 CopyMem (Buffer, PayloadPtr, PayloadSize);
2163
2164 if (AuthVarType == AuthVarTypePk) {
2165 //
2166 // Get platform key from variable.
2167 //
2168 Status = FindVariable (
2169 EFI_PLATFORM_KEY_NAME,
2170 &gEfiGlobalVariableGuid,
2171 &PkVariable,
2172 &mVariableModuleGlobal->VariableGlobal,
2173 FALSE
2174 );
2175 if (EFI_ERROR (Status)) {
2176 return Status;
2177 }
2178
2179 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
2180 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2181 RootCert = Cert->SignatureData;
2182 RootCertSize = CertList->SignatureSize;
2183
2184
2185 //
2186 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2187 //
2188 VerifyStatus = Pkcs7Verify (
2189 SigData,
2190 SigDataSize,
2191 RootCert,
2192 RootCertSize,
2193 NewData,
2194 NewDataSize
2195 );
2196
2197 } else if (AuthVarType == AuthVarTypeKek) {
2198
2199 //
2200 // Get KEK database from variable.
2201 //
2202 Status = FindVariable (
2203 EFI_KEY_EXCHANGE_KEY_NAME,
2204 &gEfiGlobalVariableGuid,
2205 &KekVariable,
2206 &mVariableModuleGlobal->VariableGlobal,
2207 FALSE
2208 );
2209 if (EFI_ERROR (Status)) {
2210 return Status;
2211 }
2212
2213 //
2214 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
2215 //
2216 KekDataSize = KekVariable.CurrPtr->DataSize;
2217 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
2218 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2219 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2220 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2221 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2222 for (Index = 0; Index < CertCount; Index++) {
2223 //
2224 // Iterate each Signature Data Node within this CertList for a verify
2225 //
2226 RootCert = Cert->SignatureData;
2227 RootCertSize = CertList->SignatureSize;
2228
2229 //
2230 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2231 //
2232 VerifyStatus = Pkcs7Verify (
2233 SigData,
2234 SigDataSize,
2235 RootCert,
2236 RootCertSize,
2237 NewData,
2238 NewDataSize
2239 );
2240 if (VerifyStatus) {
2241 goto Exit;
2242 }
2243 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
2244 }
2245 }
2246 KekDataSize -= CertList->SignatureListSize;
2247 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2248 }
2249 } else if (AuthVarType == AuthVarTypePriv) {
2250
2251 //
2252 // Process common authenticated variable except PK/KEK/DB/DBX.
2253 // Get signer's certificates from SignedData.
2254 //
2255 VerifyStatus = Pkcs7GetSigners (
2256 SigData,
2257 SigDataSize,
2258 &SignerCerts,
2259 &CertStackSize,
2260 &RootCert,
2261 &RootCertSize
2262 );
2263 if (!VerifyStatus) {
2264 goto Exit;
2265 }
2266
2267 //
2268 // Get previously stored signer's certificates from certdb for existing
2269 // variable. Check whether they are identical with signer's certificates
2270 // in SignedData. If not, return error immediately.
2271 //
2272 if ((Variable->CurrPtr != NULL)) {
2273 VerifyStatus = FALSE;
2274
2275 Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);
2276 if (EFI_ERROR (Status)) {
2277 goto Exit;
2278 }
2279
2280 if ((CertStackSize != CertsSizeinDb) ||
2281 (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
2282 goto Exit;
2283 }
2284 }
2285
2286 VerifyStatus = Pkcs7Verify (
2287 SigData,
2288 SigDataSize,
2289 RootCert,
2290 RootCertSize,
2291 NewData,
2292 NewDataSize
2293 );
2294 if (!VerifyStatus) {
2295 goto Exit;
2296 }
2297
2298 //
2299 // Delete signer's certificates when delete the common authenticated variable.
2300 //
2301 if ((PayloadSize == 0) && (Variable->CurrPtr != NULL)) {
2302 Status = DeleteCertsFromDb (VariableName, VendorGuid);
2303 if (EFI_ERROR (Status)) {
2304 VerifyStatus = FALSE;
2305 goto Exit;
2306 }
2307 } else if (Variable->CurrPtr == NULL) {
2308 //
2309 // Insert signer's certificates when adding a new common authenticated variable.
2310 //
2311 Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);
2312 if (EFI_ERROR (Status)) {
2313 VerifyStatus = FALSE;
2314 goto Exit;
2315 }
2316 }
2317 } else {
2318 return EFI_SECURITY_VIOLATION;
2319 }
2320
2321 Exit:
2322
2323 if (AuthVarType == AuthVarTypePriv) {
2324 Pkcs7FreeSigners (RootCert);
2325 Pkcs7FreeSigners (SignerCerts);
2326 }
2327
2328 if (!VerifyStatus) {
2329 return EFI_SECURITY_VIOLATION;
2330 }
2331
2332 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
2333 if (EFI_ERROR (Status)) {
2334 return Status;
2335 }
2336
2337 if ((PayloadSize == 0) && (VarDel != NULL)) {
2338 *VarDel = TRUE;
2339 }
2340
2341 //
2342 // Final step: Update/Append Variable if it pass Pkcs7Verify
2343 //
2344 return UpdateVariable (
2345 VariableName,
2346 VendorGuid,
2347 PayloadPtr,
2348 PayloadSize,
2349 Attributes,
2350 0,
2351 0,
2352 Variable,
2353 &CertData->TimeStamp
2354 );
2355 }
2356