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