]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Update auth-variable and secure boot UI driver to support only time-based PK, KEK...
[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 BOOLEAN Del;
883 UINT8 *Payload;
884 UINTN PayloadSize;
885
886 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
887 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
888 //
889 // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
890 // authenticated variable.
891 //
892 return EFI_INVALID_PARAMETER;
893 }
894
895 if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
896 //
897 // Verify against X509 Cert PK.
898 //
899 Del = FALSE;
900 Status = VerifyTimeBasedPayload (
901 VariableName,
902 VendorGuid,
903 Data,
904 DataSize,
905 Variable,
906 Attributes,
907 AuthVarTypePk,
908 &Del
909 );
910 if (!EFI_ERROR (Status)) {
911 //
912 // If delete PK in user mode, need change to setup mode.
913 //
914 if (Del && IsPk) {
915 Status = UpdatePlatformMode (SETUP_MODE);
916 }
917 }
918 return Status;
919 } else {
920 //
921 // Process PK or KEK in Setup mode or Custom Secure Boot mode.
922 //
923 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
924 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
925
926 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
927 if (EFI_ERROR (Status)) {
928 return Status;
929 }
930
931 Status = UpdateVariable (
932 VariableName,
933 VendorGuid,
934 Payload,
935 PayloadSize,
936 Attributes,
937 0,
938 0,
939 Variable,
940 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
941 );
942
943 if (IsPk) {
944 if (PayloadSize != 0) {
945 //
946 // If enroll PK in setup mode, need change to user mode.
947 //
948 Status = UpdatePlatformMode (USER_MODE);
949 } else {
950 //
951 // If delete PK in custom mode, need change to setup mode.
952 //
953 UpdatePlatformMode (SETUP_MODE);
954 }
955 }
956 }
957
958 return Status;
959 }
960
961 /**
962 Process variable with key exchange key for verification.
963
964 @param[in] VariableName Name of Variable to be found.
965 @param[in] VendorGuid Variable vendor GUID.
966 @param[in] Data Data pointer.
967 @param[in] DataSize Size of Data found. If size is less than the
968 data, this value contains the required size.
969 @param[in] Variable The variable information which is used to keep track of variable usage.
970 @param[in] Attributes Attribute value of the variable.
971
972 @return EFI_INVALID_PARAMETER Invalid parameter.
973 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
974 check carried out by the firmware.
975 @return EFI_SUCCESS Variable pass validation successfully.
976
977 **/
978 EFI_STATUS
979 ProcessVarWithKek (
980 IN CHAR16 *VariableName,
981 IN EFI_GUID *VendorGuid,
982 IN VOID *Data,
983 IN UINTN DataSize,
984 IN VARIABLE_POINTER_TRACK *Variable,
985 IN UINT32 Attributes OPTIONAL
986 )
987 {
988 EFI_STATUS Status;
989 UINT8 *Payload;
990 UINTN PayloadSize;
991
992 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
993 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
994 //
995 // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
996 // authenticated variable.
997 //
998 return EFI_INVALID_PARAMETER;
999 }
1000
1001 Status = EFI_SUCCESS;
1002 if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
1003 //
1004 // Time-based, verify against X509 Cert KEK.
1005 //
1006 return VerifyTimeBasedPayload (
1007 VariableName,
1008 VendorGuid,
1009 Data,
1010 DataSize,
1011 Variable,
1012 Attributes,
1013 AuthVarTypeKek,
1014 NULL
1015 );
1016 } else {
1017 //
1018 // If in setup mode or custom secure boot mode, no authentication needed.
1019 //
1020 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
1021 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
1022
1023 Status = UpdateVariable (
1024 VariableName,
1025 VendorGuid,
1026 Payload,
1027 PayloadSize,
1028 Attributes,
1029 0,
1030 0,
1031 Variable,
1032 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
1033 );
1034 }
1035
1036 return Status;
1037 }
1038
1039 /**
1040 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1041
1042 @param[in] VariableName Name of Variable to be found.
1043 @param[in] VendorGuid Variable vendor GUID.
1044
1045 @param[in] Data Data pointer.
1046 @param[in] DataSize Size of Data found. If size is less than the
1047 data, this value contains the required size.
1048 @param[in] Variable The variable information which is used to keep track of variable usage.
1049 @param[in] Attributes Attribute value of the variable.
1050
1051 @return EFI_INVALID_PARAMETER Invalid parameter.
1052 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
1053 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1054 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
1055 set, but the AuthInfo does NOT pass the validation
1056 check carried out by the firmware.
1057 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
1058
1059 **/
1060 EFI_STATUS
1061 ProcessVariable (
1062 IN CHAR16 *VariableName,
1063 IN EFI_GUID *VendorGuid,
1064 IN VOID *Data,
1065 IN UINTN DataSize,
1066 IN VARIABLE_POINTER_TRACK *Variable,
1067 IN UINT32 Attributes
1068 )
1069 {
1070 EFI_STATUS Status;
1071 BOOLEAN IsDeletion;
1072 BOOLEAN IsFirstTime;
1073 UINT8 *PubKey;
1074 EFI_VARIABLE_AUTHENTICATION *CertData;
1075 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
1076 UINT32 KeyIndex;
1077 UINT64 MonotonicCount;
1078
1079 KeyIndex = 0;
1080 CertData = NULL;
1081 CertBlock = NULL;
1082 PubKey = NULL;
1083 IsDeletion = FALSE;
1084
1085 if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {
1086 //
1087 // This variable is protected, only physical present user could modify its value.
1088 //
1089 return EFI_SECURITY_VIOLATION;
1090 }
1091
1092 //
1093 // Process Time-based Authenticated variable.
1094 //
1095 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
1096 return VerifyTimeBasedPayload (
1097 VariableName,
1098 VendorGuid,
1099 Data,
1100 DataSize,
1101 Variable,
1102 Attributes,
1103 AuthVarTypePriv,
1104 NULL
1105 );
1106 }
1107
1108 //
1109 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
1110 //
1111 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1112 //
1113 // Determine current operation type.
1114 //
1115 if (DataSize == AUTHINFO_SIZE) {
1116 IsDeletion = TRUE;
1117 }
1118 //
1119 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
1120 //
1121 if (Variable->CurrPtr == NULL) {
1122 IsFirstTime = TRUE;
1123 } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
1124 IsFirstTime = TRUE;
1125 } else {
1126 KeyIndex = Variable->CurrPtr->PubKeyIndex;
1127 IsFirstTime = FALSE;
1128 }
1129 } else if ((Variable->CurrPtr != NULL) &&
1130 ((Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
1131 ) {
1132 //
1133 // If the variable is already write-protected, it always needs authentication before update.
1134 //
1135 return EFI_WRITE_PROTECTED;
1136 } else {
1137 //
1138 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
1139 // That means it is not authenticated variable, just update variable as usual.
1140 //
1141 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
1142 return Status;
1143 }
1144
1145 //
1146 // Get PubKey and check Monotonic Count value corresponding to the variable.
1147 //
1148 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
1149 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
1150 PubKey = CertBlock->PublicKey;
1151
1152 //
1153 // Update Monotonic Count value.
1154 //
1155 MonotonicCount = CertData->MonotonicCount;
1156
1157 if (!IsFirstTime) {
1158 //
1159 // Check input PubKey.
1160 //
1161 if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
1162 return EFI_SECURITY_VIOLATION;
1163 }
1164 //
1165 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
1166 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
1167 //
1168 if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {
1169 //
1170 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1171 //
1172 return EFI_SECURITY_VIOLATION;
1173 }
1174 }
1175 //
1176 // Verify the certificate in Data payload.
1177 //
1178 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
1179 if (EFI_ERROR (Status)) {
1180 return Status;
1181 }
1182
1183 //
1184 // Now, the signature has been verified!
1185 //
1186 if (IsFirstTime && !IsDeletion) {
1187 //
1188 // Update public key database variable if need.
1189 //
1190 KeyIndex = AddPubKeyInStore (PubKey);
1191 if (KeyIndex == 0) {
1192 return EFI_SECURITY_VIOLATION;
1193 }
1194 }
1195
1196 //
1197 // Verification pass.
1198 //
1199 return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
1200 }
1201
1202 /**
1203 Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
1204 will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
1205 will be ignored.
1206
1207 @param[in, out] Data Pointer to original EFI_SIGNATURE_LIST.
1208 @param[in] DataSize Size of Data buffer.
1209 @param[in] NewData Pointer to new EFI_SIGNATURE_LIST to be appended.
1210 @param[in] NewDataSize Size of NewData buffer.
1211
1212 @return Size of the merged buffer.
1213
1214 **/
1215 UINTN
1216 AppendSignatureList (
1217 IN OUT VOID *Data,
1218 IN UINTN DataSize,
1219 IN VOID *NewData,
1220 IN UINTN NewDataSize
1221 )
1222 {
1223 EFI_SIGNATURE_LIST *CertList;
1224 EFI_SIGNATURE_DATA *Cert;
1225 UINTN CertCount;
1226 EFI_SIGNATURE_LIST *NewCertList;
1227 EFI_SIGNATURE_DATA *NewCert;
1228 UINTN NewCertCount;
1229 UINTN Index;
1230 UINTN Index2;
1231 UINTN Size;
1232 UINT8 *Tail;
1233 UINTN CopiedCount;
1234 UINTN SignatureListSize;
1235 BOOLEAN IsNewCert;
1236
1237 Tail = (UINT8 *) Data + DataSize;
1238
1239 NewCertList = (EFI_SIGNATURE_LIST *) NewData;
1240 while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {
1241 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1242 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
1243
1244 CopiedCount = 0;
1245 for (Index = 0; Index < NewCertCount; Index++) {
1246 IsNewCert = TRUE;
1247
1248 Size = DataSize;
1249 CertList = (EFI_SIGNATURE_LIST *) Data;
1250 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
1251 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
1252 (CertList->SignatureSize == NewCertList->SignatureSize)) {
1253 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1254 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1255 for (Index2 = 0; Index2 < CertCount; Index2++) {
1256 //
1257 // Iterate each Signature Data in this Signature List.
1258 //
1259 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
1260 IsNewCert = FALSE;
1261 break;
1262 }
1263 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1264 }
1265 }
1266
1267 if (!IsNewCert) {
1268 break;
1269 }
1270 Size -= CertList->SignatureListSize;
1271 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1272 }
1273
1274 if (IsNewCert) {
1275 //
1276 // New EFI_SIGNATURE_DATA, append it.
1277 //
1278 if (CopiedCount == 0) {
1279 //
1280 // Copy EFI_SIGNATURE_LIST header for only once.
1281 //
1282 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
1283 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
1284 }
1285
1286 CopyMem (Tail, NewCert, NewCertList->SignatureSize);
1287 Tail += NewCertList->SignatureSize;
1288 CopiedCount++;
1289 }
1290
1291 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
1292 }
1293
1294 //
1295 // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.
1296 //
1297 if (CopiedCount != 0) {
1298 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
1299 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
1300 CertList->SignatureListSize = (UINT32) SignatureListSize;
1301 }
1302
1303 NewDataSize -= NewCertList->SignatureListSize;
1304 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
1305 }
1306
1307 return (Tail - (UINT8 *) Data);
1308 }
1309
1310 /**
1311 Compare two EFI_TIME data.
1312
1313
1314 @param FirstTime A pointer to the first EFI_TIME data.
1315 @param SecondTime A pointer to the second EFI_TIME data.
1316
1317 @retval TRUE The FirstTime is not later than the SecondTime.
1318 @retval FALSE The FirstTime is later than the SecondTime.
1319
1320 **/
1321 BOOLEAN
1322 CompareTimeStamp (
1323 IN EFI_TIME *FirstTime,
1324 IN EFI_TIME *SecondTime
1325 )
1326 {
1327 if (FirstTime->Year != SecondTime->Year) {
1328 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
1329 } else if (FirstTime->Month != SecondTime->Month) {
1330 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
1331 } else if (FirstTime->Day != SecondTime->Day) {
1332 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
1333 } else if (FirstTime->Hour != SecondTime->Hour) {
1334 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
1335 } else if (FirstTime->Minute != SecondTime->Minute) {
1336 return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);
1337 }
1338
1339 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
1340 }
1341
1342 /**
1343 Find matching signer's certificates for common authenticated variable
1344 by corresponding VariableName and VendorGuid from "certdb".
1345
1346 The data format of "certdb":
1347 //
1348 // UINT32 CertDbListSize;
1349 // /// AUTH_CERT_DB_DATA Certs1[];
1350 // /// AUTH_CERT_DB_DATA Certs2[];
1351 // /// ...
1352 // /// AUTH_CERT_DB_DATA Certsn[];
1353 //
1354
1355 @param[in] VariableName Name of authenticated Variable.
1356 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1357 @param[in] Data Pointer to variable "certdb".
1358 @param[in] DataSize Size of variable "certdb".
1359 @param[out] CertOffset Offset of matching CertData, from starting of Data.
1360 @param[out] CertDataSize Length of CertData in bytes.
1361 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
1362 starting of Data.
1363 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
1364
1365 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1366 @retval EFI_NOT_FOUND Fail to find matching certs.
1367 @retval EFI_SUCCESS Find matching certs and output parameters.
1368
1369 **/
1370 EFI_STATUS
1371 FindCertsFromDb (
1372 IN CHAR16 *VariableName,
1373 IN EFI_GUID *VendorGuid,
1374 IN UINT8 *Data,
1375 IN UINTN DataSize,
1376 OUT UINT32 *CertOffset, OPTIONAL
1377 OUT UINT32 *CertDataSize, OPTIONAL
1378 OUT UINT32 *CertNodeOffset,OPTIONAL
1379 OUT UINT32 *CertNodeSize OPTIONAL
1380 )
1381 {
1382 UINT32 Offset;
1383 AUTH_CERT_DB_DATA *Ptr;
1384 UINT32 CertSize;
1385 UINT32 NameSize;
1386 UINT32 NodeSize;
1387 UINT32 CertDbListSize;
1388
1389 if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
1390 return EFI_INVALID_PARAMETER;
1391 }
1392
1393 //
1394 // Check whether DataSize matches recorded CertDbListSize.
1395 //
1396 if (DataSize < sizeof (UINT32)) {
1397 return EFI_INVALID_PARAMETER;
1398 }
1399
1400 CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
1401
1402 if (CertDbListSize != (UINT32) DataSize) {
1403 return EFI_INVALID_PARAMETER;
1404 }
1405
1406 Offset = sizeof (UINT32);
1407
1408 //
1409 // Get corresponding certificates by VendorGuid and VariableName.
1410 //
1411 while (Offset < (UINT32) DataSize) {
1412 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
1413 //
1414 // Check whether VendorGuid matches.
1415 //
1416 if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
1417 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
1418 NameSize = ReadUnaligned32 (&Ptr->NameSize);
1419 CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
1420
1421 if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
1422 sizeof (CHAR16) * NameSize) {
1423 return EFI_INVALID_PARAMETER;
1424 }
1425
1426 Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
1427 //
1428 // Check whether VariableName matches.
1429 //
1430 if ((NameSize == StrLen (VariableName)) &&
1431 (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
1432 Offset = Offset + NameSize * sizeof (CHAR16);
1433
1434 if (CertOffset != NULL) {
1435 *CertOffset = Offset;
1436 }
1437
1438 if (CertDataSize != NULL) {
1439 *CertDataSize = CertSize;
1440 }
1441
1442 if (CertNodeOffset != NULL) {
1443 *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
1444 }
1445
1446 if (CertNodeSize != NULL) {
1447 *CertNodeSize = NodeSize;
1448 }
1449
1450 return EFI_SUCCESS;
1451 } else {
1452 Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
1453 }
1454 } else {
1455 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
1456 Offset = Offset + NodeSize;
1457 }
1458 }
1459
1460 return EFI_NOT_FOUND;
1461 }
1462
1463 /**
1464 Retrieve signer's certificates for common authenticated variable
1465 by corresponding VariableName and VendorGuid from "certdb".
1466
1467 @param[in] VariableName Name of authenticated Variable.
1468 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1469 @param[out] CertData Pointer to signer's certificates.
1470 @param[out] CertDataSize Length of CertData in bytes.
1471
1472 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1473 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1474 @retval EFI_SUCCESS Get signer's certificates successfully.
1475
1476 **/
1477 EFI_STATUS
1478 GetCertsFromDb (
1479 IN CHAR16 *VariableName,
1480 IN EFI_GUID *VendorGuid,
1481 OUT UINT8 **CertData,
1482 OUT UINT32 *CertDataSize
1483 )
1484 {
1485 VARIABLE_POINTER_TRACK CertDbVariable;
1486 EFI_STATUS Status;
1487 UINT8 *Data;
1488 UINTN DataSize;
1489 UINT32 CertOffset;
1490
1491 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
1492 return EFI_INVALID_PARAMETER;
1493 }
1494
1495 //
1496 // Get variable "certdb".
1497 //
1498 Status = FindVariable (
1499 EFI_CERT_DB_NAME,
1500 &gEfiCertDbGuid,
1501 &CertDbVariable,
1502 &mVariableModuleGlobal->VariableGlobal,
1503 FALSE
1504 );
1505 if (EFI_ERROR (Status)) {
1506 return Status;
1507 }
1508
1509 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1510 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1511 if ((DataSize == 0) || (Data == NULL)) {
1512 ASSERT (FALSE);
1513 return EFI_NOT_FOUND;
1514 }
1515
1516 Status = FindCertsFromDb (
1517 VariableName,
1518 VendorGuid,
1519 Data,
1520 DataSize,
1521 &CertOffset,
1522 CertDataSize,
1523 NULL,
1524 NULL
1525 );
1526
1527 if (EFI_ERROR (Status)) {
1528 return Status;
1529 }
1530
1531 *CertData = Data + CertOffset;
1532 return EFI_SUCCESS;
1533 }
1534
1535 /**
1536 Delete matching signer's certificates when deleting common authenticated
1537 variable by corresponding VariableName and VendorGuid from "certdb".
1538
1539 @param[in] VariableName Name of authenticated Variable.
1540 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1541
1542 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1543 @retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
1544 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1545 @retval EFI_SUCCESS The operation is completed successfully.
1546
1547 **/
1548 EFI_STATUS
1549 DeleteCertsFromDb (
1550 IN CHAR16 *VariableName,
1551 IN EFI_GUID *VendorGuid
1552 )
1553 {
1554 VARIABLE_POINTER_TRACK CertDbVariable;
1555 EFI_STATUS Status;
1556 UINT8 *Data;
1557 UINTN DataSize;
1558 UINT32 VarAttr;
1559 UINT32 CertNodeOffset;
1560 UINT32 CertNodeSize;
1561 UINT8 *NewCertDb;
1562 UINT32 NewCertDbSize;
1563
1564 if ((VariableName == NULL) || (VendorGuid == NULL)) {
1565 return EFI_INVALID_PARAMETER;
1566 }
1567
1568 //
1569 // Get variable "certdb".
1570 //
1571 Status = FindVariable (
1572 EFI_CERT_DB_NAME,
1573 &gEfiCertDbGuid,
1574 &CertDbVariable,
1575 &mVariableModuleGlobal->VariableGlobal,
1576 FALSE
1577 );
1578 if (EFI_ERROR (Status)) {
1579 return Status;
1580 }
1581
1582 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1583 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1584 if ((DataSize == 0) || (Data == NULL)) {
1585 ASSERT (FALSE);
1586 return EFI_NOT_FOUND;
1587 }
1588
1589 if (DataSize == sizeof (UINT32)) {
1590 //
1591 // There is no certs in certdb.
1592 //
1593 return EFI_SUCCESS;
1594 }
1595
1596 //
1597 // Get corresponding cert node from certdb.
1598 //
1599 Status = FindCertsFromDb (
1600 VariableName,
1601 VendorGuid,
1602 Data,
1603 DataSize,
1604 NULL,
1605 NULL,
1606 &CertNodeOffset,
1607 &CertNodeSize
1608 );
1609
1610 if (EFI_ERROR (Status)) {
1611 return Status;
1612 }
1613
1614 if (DataSize < (CertNodeOffset + CertNodeSize)) {
1615 return EFI_NOT_FOUND;
1616 }
1617
1618 //
1619 // Construct new data content of variable "certdb".
1620 //
1621 NewCertDbSize = (UINT32) DataSize - CertNodeSize;
1622 NewCertDb = AllocateZeroPool (NewCertDbSize);
1623 if (NewCertDb == NULL) {
1624 return EFI_OUT_OF_RESOURCES;
1625 }
1626
1627 //
1628 // Copy the DB entries before deleting node.
1629 //
1630 CopyMem (NewCertDb, Data, CertNodeOffset);
1631 //
1632 // Update CertDbListSize.
1633 //
1634 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
1635 //
1636 // Copy the DB entries after deleting node.
1637 //
1638 if (DataSize > (CertNodeOffset + CertNodeSize)) {
1639 CopyMem (
1640 NewCertDb + CertNodeOffset,
1641 Data + CertNodeOffset + CertNodeSize,
1642 DataSize - CertNodeOffset - CertNodeSize
1643 );
1644 }
1645
1646 //
1647 // Set "certdb".
1648 //
1649 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1650 Status = UpdateVariable (
1651 EFI_CERT_DB_NAME,
1652 &gEfiCertDbGuid,
1653 NewCertDb,
1654 NewCertDbSize,
1655 VarAttr,
1656 0,
1657 0,
1658 &CertDbVariable,
1659 NULL
1660 );
1661
1662 FreePool (NewCertDb);
1663 return Status;
1664 }
1665
1666 /**
1667 Insert signer's certificates for common authenticated variable with VariableName
1668 and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
1669
1670 @param[in] VariableName Name of authenticated Variable.
1671 @param[in] VendorGuid Vendor GUID of authenticated Variable.
1672 @param[in] CertData Pointer to signer's certificates.
1673 @param[in] CertDataSize Length of CertData in bytes.
1674
1675 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1676 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
1677 and VendorGuid already exists.
1678 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
1679 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb"
1680
1681 **/
1682 EFI_STATUS
1683 InsertCertsToDb (
1684 IN CHAR16 *VariableName,
1685 IN EFI_GUID *VendorGuid,
1686 IN UINT8 *CertData,
1687 IN UINTN CertDataSize
1688 )
1689 {
1690 VARIABLE_POINTER_TRACK CertDbVariable;
1691 EFI_STATUS Status;
1692 UINT8 *Data;
1693 UINTN DataSize;
1694 UINT32 VarAttr;
1695 UINT8 *NewCertDb;
1696 UINT32 NewCertDbSize;
1697 UINT32 CertNodeSize;
1698 UINT32 NameSize;
1699 AUTH_CERT_DB_DATA *Ptr;
1700
1701 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
1702 return EFI_INVALID_PARAMETER;
1703 }
1704
1705 //
1706 // Get variable "certdb".
1707 //
1708 Status = FindVariable (
1709 EFI_CERT_DB_NAME,
1710 &gEfiCertDbGuid,
1711 &CertDbVariable,
1712 &mVariableModuleGlobal->VariableGlobal,
1713 FALSE
1714 );
1715 if (EFI_ERROR (Status)) {
1716 return Status;
1717 }
1718
1719 DataSize = DataSizeOfVariable (CertDbVariable.CurrPtr);
1720 Data = GetVariableDataPtr (CertDbVariable.CurrPtr);
1721 if ((DataSize == 0) || (Data == NULL)) {
1722 ASSERT (FALSE);
1723 return EFI_NOT_FOUND;
1724 }
1725
1726 //
1727 // Find whether matching cert node already exists in "certdb".
1728 // If yes return error.
1729 //
1730 Status = FindCertsFromDb (
1731 VariableName,
1732 VendorGuid,
1733 Data,
1734 DataSize,
1735 NULL,
1736 NULL,
1737 NULL,
1738 NULL
1739 );
1740
1741 if (!EFI_ERROR (Status)) {
1742 ASSERT (FALSE);
1743 return EFI_ACCESS_DENIED;
1744 }
1745
1746 //
1747 // Construct new data content of variable "certdb".
1748 //
1749 NameSize = (UINT32) StrLen (VariableName);
1750 CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
1751 NewCertDbSize = (UINT32) DataSize + CertNodeSize;
1752 NewCertDb = AllocateZeroPool (NewCertDbSize);
1753 if (NewCertDb == NULL) {
1754 return EFI_OUT_OF_RESOURCES;
1755 }
1756
1757 //
1758 // Copy the DB entries before deleting node.
1759 //
1760 CopyMem (NewCertDb, Data, DataSize);
1761 //
1762 // Update CertDbListSize.
1763 //
1764 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
1765 //
1766 // Construct new cert node.
1767 //
1768 Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
1769 CopyGuid (&Ptr->VendorGuid, VendorGuid);
1770 CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
1771 CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
1772 CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
1773
1774 CopyMem (
1775 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
1776 VariableName,
1777 NameSize * sizeof (CHAR16)
1778 );
1779
1780 CopyMem (
1781 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
1782 CertData,
1783 CertDataSize
1784 );
1785
1786 //
1787 // Set "certdb".
1788 //
1789 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1790 Status = UpdateVariable (
1791 EFI_CERT_DB_NAME,
1792 &gEfiCertDbGuid,
1793 NewCertDb,
1794 NewCertDbSize,
1795 VarAttr,
1796 0,
1797 0,
1798 &CertDbVariable,
1799 NULL
1800 );
1801
1802 FreePool (NewCertDb);
1803 return Status;
1804 }
1805
1806 /**
1807 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
1808
1809 @param[in] VariableName Name of Variable to be found.
1810 @param[in] VendorGuid Variable vendor GUID.
1811 @param[in] Data Data pointer.
1812 @param[in] DataSize Size of Data found. If size is less than the
1813 data, this value contains the required size.
1814 @param[in] Variable The variable information which is used to keep track of variable usage.
1815 @param[in] Attributes Attribute value of the variable.
1816 @param[in] AuthVarType Verify against PK or KEK database or private database.
1817 @param[out] VarDel Delete the variable or not.
1818
1819 @retval EFI_INVALID_PARAMETER Invalid parameter.
1820 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1821 check carried out by the firmware.
1822 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
1823 of resources.
1824 @retval EFI_SUCCESS Variable pass validation successfully.
1825
1826 **/
1827 EFI_STATUS
1828 VerifyTimeBasedPayload (
1829 IN CHAR16 *VariableName,
1830 IN EFI_GUID *VendorGuid,
1831 IN VOID *Data,
1832 IN UINTN DataSize,
1833 IN VARIABLE_POINTER_TRACK *Variable,
1834 IN UINT32 Attributes,
1835 IN AUTHVAR_TYPE AuthVarType,
1836 OUT BOOLEAN *VarDel
1837 )
1838 {
1839 UINT8 *RootCert;
1840 UINT8 *SigData;
1841 UINT8 *PayloadPtr;
1842 UINTN RootCertSize;
1843 UINTN Index;
1844 UINTN CertCount;
1845 UINTN PayloadSize;
1846 UINT32 Attr;
1847 UINT32 SigDataSize;
1848 UINT32 KekDataSize;
1849 BOOLEAN VerifyStatus;
1850 EFI_STATUS Status;
1851 EFI_SIGNATURE_LIST *CertList;
1852 EFI_SIGNATURE_DATA *Cert;
1853 VARIABLE_POINTER_TRACK KekVariable;
1854 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
1855 UINT8 *NewData;
1856 UINTN NewDataSize;
1857 VARIABLE_POINTER_TRACK PkVariable;
1858 UINT8 *Buffer;
1859 UINTN Length;
1860 UINT8 *SignerCerts;
1861 UINT8 *WrapSigData;
1862 UINTN CertStackSize;
1863 UINT8 *CertsInCertDb;
1864 UINT32 CertsSizeinDb;
1865
1866 VerifyStatus = FALSE;
1867 CertData = NULL;
1868 NewData = NULL;
1869 Attr = Attributes;
1870 WrapSigData = NULL;
1871 SignerCerts = NULL;
1872 RootCert = NULL;
1873
1874 //
1875 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
1876 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
1877 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
1878 // variable value and DataSize shall reflect the combined size of the descriptor and the new
1879 // variable value. The authentication descriptor is not part of the variable data and is not
1880 // returned by subsequent calls to GetVariable().
1881 //
1882 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
1883
1884 //
1885 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
1886 // TimeStamp value are set to zero.
1887 //
1888 if ((CertData->TimeStamp.Pad1 != 0) ||
1889 (CertData->TimeStamp.Nanosecond != 0) ||
1890 (CertData->TimeStamp.TimeZone != 0) ||
1891 (CertData->TimeStamp.Daylight != 0) ||
1892 (CertData->TimeStamp.Pad2 != 0)) {
1893 return EFI_SECURITY_VIOLATION;
1894 }
1895
1896 if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
1897 if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
1898 //
1899 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
1900 //
1901 return EFI_SECURITY_VIOLATION;
1902 }
1903 }
1904
1905 //
1906 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1907 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
1908 //
1909 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
1910 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
1911 //
1912 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1913 //
1914 return EFI_SECURITY_VIOLATION;
1915 }
1916
1917 //
1918 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
1919 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
1920 //
1921 SigData = CertData->AuthInfo.CertData;
1922 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
1923
1924 //
1925 // Find out the new data payload which follows Pkcs7 SignedData directly.
1926 //
1927 PayloadPtr = SigData + SigDataSize;
1928 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
1929
1930 //
1931 // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
1932 //
1933 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
1934 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
1935 NewData = mSerializationRuntimeBuffer;
1936
1937 Buffer = NewData;
1938 Length = StrLen (VariableName) * sizeof (CHAR16);
1939 CopyMem (Buffer, VariableName, Length);
1940 Buffer += Length;
1941
1942 Length = sizeof (EFI_GUID);
1943 CopyMem (Buffer, VendorGuid, Length);
1944 Buffer += Length;
1945
1946 Length = sizeof (UINT32);
1947 CopyMem (Buffer, &Attr, Length);
1948 Buffer += Length;
1949
1950 Length = sizeof (EFI_TIME);
1951 CopyMem (Buffer, &CertData->TimeStamp, Length);
1952 Buffer += Length;
1953
1954 CopyMem (Buffer, PayloadPtr, PayloadSize);
1955
1956 if (AuthVarType == AuthVarTypePk) {
1957 //
1958 // Get platform key from variable.
1959 //
1960 Status = FindVariable (
1961 EFI_PLATFORM_KEY_NAME,
1962 &gEfiGlobalVariableGuid,
1963 &PkVariable,
1964 &mVariableModuleGlobal->VariableGlobal,
1965 FALSE
1966 );
1967 if (EFI_ERROR (Status)) {
1968 return Status;
1969 }
1970
1971 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
1972 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1973 RootCert = Cert->SignatureData;
1974 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
1975
1976
1977 //
1978 // Verify Pkcs7 SignedData via Pkcs7Verify library.
1979 //
1980 VerifyStatus = Pkcs7Verify (
1981 SigData,
1982 SigDataSize,
1983 RootCert,
1984 RootCertSize,
1985 NewData,
1986 NewDataSize
1987 );
1988
1989 } else if (AuthVarType == AuthVarTypeKek) {
1990
1991 //
1992 // Get KEK database from variable.
1993 //
1994 Status = FindVariable (
1995 EFI_KEY_EXCHANGE_KEY_NAME,
1996 &gEfiGlobalVariableGuid,
1997 &KekVariable,
1998 &mVariableModuleGlobal->VariableGlobal,
1999 FALSE
2000 );
2001 if (EFI_ERROR (Status)) {
2002 return Status;
2003 }
2004
2005 //
2006 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
2007 //
2008 KekDataSize = KekVariable.CurrPtr->DataSize;
2009 CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
2010 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2011 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2012 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2013 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2014 for (Index = 0; Index < CertCount; Index++) {
2015 //
2016 // Iterate each Signature Data Node within this CertList for a verify
2017 //
2018 RootCert = Cert->SignatureData;
2019 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
2020
2021 //
2022 // Verify Pkcs7 SignedData via Pkcs7Verify library.
2023 //
2024 VerifyStatus = Pkcs7Verify (
2025 SigData,
2026 SigDataSize,
2027 RootCert,
2028 RootCertSize,
2029 NewData,
2030 NewDataSize
2031 );
2032 if (VerifyStatus) {
2033 goto Exit;
2034 }
2035 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
2036 }
2037 }
2038 KekDataSize -= CertList->SignatureListSize;
2039 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2040 }
2041 } else if (AuthVarType == AuthVarTypePriv) {
2042
2043 //
2044 // Process common authenticated variable except PK/KEK/DB/DBX.
2045 // Get signer's certificates from SignedData.
2046 //
2047 VerifyStatus = Pkcs7GetSigners (
2048 SigData,
2049 SigDataSize,
2050 &SignerCerts,
2051 &CertStackSize,
2052 &RootCert,
2053 &RootCertSize
2054 );
2055 if (!VerifyStatus) {
2056 goto Exit;
2057 }
2058
2059 //
2060 // Get previously stored signer's certificates from certdb for existing
2061 // variable. Check whether they are identical with signer's certificates
2062 // in SignedData. If not, return error immediately.
2063 //
2064 if ((Variable->CurrPtr != NULL)) {
2065 VerifyStatus = FALSE;
2066
2067 Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);
2068 if (EFI_ERROR (Status)) {
2069 goto Exit;
2070 }
2071
2072 if ((CertStackSize != CertsSizeinDb) ||
2073 (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
2074 goto Exit;
2075 }
2076 }
2077
2078 VerifyStatus = Pkcs7Verify (
2079 SigData,
2080 SigDataSize,
2081 RootCert,
2082 RootCertSize,
2083 NewData,
2084 NewDataSize
2085 );
2086 if (!VerifyStatus) {
2087 goto Exit;
2088 }
2089
2090 //
2091 // Delete signer's certificates when delete the common authenticated variable.
2092 //
2093 if ((PayloadSize == 0) && (Variable->CurrPtr != NULL)) {
2094 Status = DeleteCertsFromDb (VariableName, VendorGuid);
2095 if (EFI_ERROR (Status)) {
2096 VerifyStatus = FALSE;
2097 goto Exit;
2098 }
2099 } else if (Variable->CurrPtr == NULL) {
2100 //
2101 // Insert signer's certificates when adding a new common authenticated variable.
2102 //
2103 Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);
2104 if (EFI_ERROR (Status)) {
2105 VerifyStatus = FALSE;
2106 goto Exit;
2107 }
2108 }
2109 } else {
2110 return EFI_SECURITY_VIOLATION;
2111 }
2112
2113 Exit:
2114
2115 if (AuthVarType == AuthVarTypePriv) {
2116 Pkcs7FreeSigners (RootCert);
2117 Pkcs7FreeSigners (SignerCerts);
2118 }
2119
2120 if (!VerifyStatus) {
2121 return EFI_SECURITY_VIOLATION;
2122 }
2123
2124 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
2125 if (EFI_ERROR (Status)) {
2126 return Status;
2127 }
2128
2129 if ((PayloadSize == 0) && (VarDel != NULL)) {
2130 *VarDel = TRUE;
2131 }
2132
2133 //
2134 // Final step: Update/Append Variable if it pass Pkcs7Verify
2135 //
2136 return UpdateVariable (
2137 VariableName,
2138 VendorGuid,
2139 PayloadPtr,
2140 PayloadSize,
2141 Attributes,
2142 0,
2143 0,
2144 Variable,
2145 &CertData->TimeStamp
2146 );
2147 }
2148