]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/Library/AuthVariableLib/AuthService.c
4649e50e5e083584532d047a9ec7c002f3d22eab
[mirror_edk2.git] / SecurityPkg / Library / AuthVariableLib / AuthService.c
1 /** @file
2 Implement authentication services for the authenticated variables.
3
4 Caution: This module requires additional review when modified.
5 This driver will have external input - variable data. It may be input in SMM mode.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8 Variable attribute should also be checked to avoid authentication bypass.
9 The whole SMM authentication variable design relies on the integrity of flash part and SMM.
10 which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
11 may not be modified without authorization. If platform fails to protect these resources,
12 the authentication service provided in this driver will be broken, and the behavior is undefined.
13
14 ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
15 variable authentication.
16
17 VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.
18 They will do basic validation for authentication data structure, then call crypto library
19 to verify the signature.
20
21 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
22 This program and the accompanying materials
23 are licensed and made available under the terms and conditions of the BSD License
24 which accompanies this distribution. The full text of the license may be found at
25 http://opensource.org/licenses/bsd-license.php
26
27 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
28 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
29
30 **/
31
32 #include "AuthServiceInternal.h"
33
34 //
35 // Public Exponent of RSA Key.
36 //
37 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
38
39 //
40 // Requirement for different signature type which have been defined in UEFI spec.
41 // These data are used to perform SignatureList format check while setting PK/KEK variable.
42 //
43 EFI_SIGNATURE_ITEM mSupportSigItem[] = {
44 //{SigType, SigHeaderSize, SigDataSize }
45 {EFI_CERT_SHA256_GUID, 0, 32 },
46 {EFI_CERT_RSA2048_GUID, 0, 256 },
47 {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },
48 {EFI_CERT_SHA1_GUID, 0, 20 },
49 {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },
50 {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},
51 {EFI_CERT_SHA224_GUID, 0, 28 },
52 {EFI_CERT_SHA384_GUID, 0, 48 },
53 {EFI_CERT_SHA512_GUID, 0, 64 },
54 {EFI_CERT_X509_SHA256_GUID, 0, 48 },
55 {EFI_CERT_X509_SHA384_GUID, 0, 64 },
56 {EFI_CERT_X509_SHA512_GUID, 0, 80 }
57 };
58
59 //
60 // Secure Boot Mode state machine
61 //
62 SECURE_BOOT_MODE mSecureBootState[SecureBootModeTypeMax] = {
63 // USER MODE
64 {
65 AUDIT_MODE_DISABLE, // AuditMode
66 FALSE, // IsAuditModeRO, AuditMode is RW
67 DEPLOYED_MODE_DISABLE, // DeployedMode
68 FALSE, // IsDeployedModeRO, DeployedMode is RW
69 SETUP_MODE_DISABLE, // SetupMode
70 // SetupMode is always RO
71 SECURE_BOOT_MODE_ENABLE // SecureBoot
72 },
73 // SETUP MODE
74 {
75 AUDIT_MODE_DISABLE, // AuditMode
76 FALSE, // IsAuditModeRO, AuditMode is RW
77 DEPLOYED_MODE_DISABLE, // DeployedMode
78 TRUE, // IsDeployedModeRO, DeployedMode is RO
79 SETUP_MODE_ENABLE, // SetupMode
80 // SetupMode is always RO
81 SECURE_BOOT_MODE_DISABLE // SecureBoot
82 },
83 // AUDIT MODE
84 {
85 AUDIT_MODE_ENABLE, // AuditMode
86 TRUE, // AuditModeValAttr RO, AuditMode is RO
87 DEPLOYED_MODE_DISABLE, // DeployedMode
88 TRUE, // DeployedModeValAttr RO, DeployedMode is RO
89 SETUP_MODE_ENABLE, // SetupMode
90 // SetupMode is always RO
91 SECURE_BOOT_MODE_DISABLE // SecureBoot
92 },
93 // DEPLOYED MODE
94 {
95 AUDIT_MODE_DISABLE, // AuditMode, AuditMode is RO
96 TRUE, // AuditModeValAttr RO
97 DEPLOYED_MODE_ENABLE, // DeployedMode
98 TRUE, // DeployedModeValAttr RO, DeployedMode is RO
99 SETUP_MODE_DISABLE, // SetupMode
100 // SetupMode is always RO
101 SECURE_BOOT_MODE_ENABLE // SecureBoot
102 }
103 };
104
105 SECURE_BOOT_MODE_TYPE mSecureBootMode;
106
107 /**
108 Finds variable in storage blocks of volatile and non-volatile storage areas.
109
110 This code finds variable in storage blocks of volatile and non-volatile storage areas.
111 If VariableName is an empty string, then we just return the first
112 qualified variable without comparing VariableName and VendorGuid.
113
114 @param[in] VariableName Name of the variable to be found.
115 @param[in] VendorGuid Variable vendor GUID to be found.
116 @param[out] Data Pointer to data address.
117 @param[out] DataSize Pointer to data size.
118
119 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
120 while VendorGuid is NULL.
121 @retval EFI_SUCCESS Variable successfully found.
122 @retval EFI_NOT_FOUND Variable not found
123
124 **/
125 EFI_STATUS
126 AuthServiceInternalFindVariable (
127 IN CHAR16 *VariableName,
128 IN EFI_GUID *VendorGuid,
129 OUT VOID **Data,
130 OUT UINTN *DataSize
131 )
132 {
133 EFI_STATUS Status;
134 AUTH_VARIABLE_INFO AuthVariableInfo;
135
136 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
137 Status = mAuthVarLibContextIn->FindVariable (
138 VariableName,
139 VendorGuid,
140 &AuthVariableInfo
141 );
142 *Data = AuthVariableInfo.Data;
143 *DataSize = AuthVariableInfo.DataSize;
144 return Status;
145 }
146
147 /**
148 Update the variable region with Variable information.
149
150 @param[in] VariableName Name of variable.
151 @param[in] VendorGuid Guid of variable.
152 @param[in] Data Data pointer.
153 @param[in] DataSize Size of Data.
154 @param[in] Attributes Attribute value of the variable.
155
156 @retval EFI_SUCCESS The update operation is success.
157 @retval EFI_INVALID_PARAMETER Invalid parameter.
158 @retval EFI_WRITE_PROTECTED Variable is write-protected.
159 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
160
161 **/
162 EFI_STATUS
163 AuthServiceInternalUpdateVariable (
164 IN CHAR16 *VariableName,
165 IN EFI_GUID *VendorGuid,
166 IN VOID *Data,
167 IN UINTN DataSize,
168 IN UINT32 Attributes
169 )
170 {
171 AUTH_VARIABLE_INFO AuthVariableInfo;
172
173 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
174 AuthVariableInfo.VariableName = VariableName;
175 AuthVariableInfo.VendorGuid = VendorGuid;
176 AuthVariableInfo.Data = Data;
177 AuthVariableInfo.DataSize = DataSize;
178 AuthVariableInfo.Attributes = Attributes;
179
180 return mAuthVarLibContextIn->UpdateVariable (
181 &AuthVariableInfo
182 );
183 }
184
185 /**
186 Update the variable region with Variable information.
187
188 @param[in] VariableName Name of variable.
189 @param[in] VendorGuid Guid of variable.
190 @param[in] Data Data pointer.
191 @param[in] DataSize Size of Data.
192 @param[in] Attributes Attribute value of the variable.
193 @param[in] KeyIndex Index of associated public key.
194 @param[in] MonotonicCount Value of associated monotonic count.
195
196 @retval EFI_SUCCESS The update operation is success.
197 @retval EFI_INVALID_PARAMETER Invalid parameter.
198 @retval EFI_WRITE_PROTECTED Variable is write-protected.
199 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
200
201 **/
202 EFI_STATUS
203 AuthServiceInternalUpdateVariableWithMonotonicCount (
204 IN CHAR16 *VariableName,
205 IN EFI_GUID *VendorGuid,
206 IN VOID *Data,
207 IN UINTN DataSize,
208 IN UINT32 Attributes,
209 IN UINT32 KeyIndex,
210 IN UINT64 MonotonicCount
211 )
212 {
213 AUTH_VARIABLE_INFO AuthVariableInfo;
214
215 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
216 AuthVariableInfo.VariableName = VariableName;
217 AuthVariableInfo.VendorGuid = VendorGuid;
218 AuthVariableInfo.Data = Data;
219 AuthVariableInfo.DataSize = DataSize;
220 AuthVariableInfo.Attributes = Attributes;
221 AuthVariableInfo.PubKeyIndex = KeyIndex;
222 AuthVariableInfo.MonotonicCount = MonotonicCount;
223
224 return mAuthVarLibContextIn->UpdateVariable (
225 &AuthVariableInfo
226 );
227 }
228
229 /**
230 Update the variable region with Variable information.
231
232 @param[in] VariableName Name of variable.
233 @param[in] VendorGuid Guid of variable.
234 @param[in] Data Data pointer.
235 @param[in] DataSize Size of Data.
236 @param[in] Attributes Attribute value of the variable.
237 @param[in] TimeStamp Value of associated TimeStamp.
238
239 @retval EFI_SUCCESS The update operation is success.
240 @retval EFI_INVALID_PARAMETER Invalid parameter.
241 @retval EFI_WRITE_PROTECTED Variable is write-protected.
242 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
243
244 **/
245 EFI_STATUS
246 AuthServiceInternalUpdateVariableWithTimeStamp (
247 IN CHAR16 *VariableName,
248 IN EFI_GUID *VendorGuid,
249 IN VOID *Data,
250 IN UINTN DataSize,
251 IN UINT32 Attributes,
252 IN EFI_TIME *TimeStamp
253 )
254 {
255 EFI_STATUS FindStatus;
256 VOID *OrgData;
257 UINTN OrgDataSize;
258 AUTH_VARIABLE_INFO AuthVariableInfo;
259
260 FindStatus = AuthServiceInternalFindVariable (
261 VariableName,
262 VendorGuid,
263 &OrgData,
264 &OrgDataSize
265 );
266
267 //
268 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
269 //
270 if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
271 if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
272 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
273 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
274 (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
275 //
276 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
277 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
278 //
279 FilterSignatureList (
280 OrgData,
281 OrgDataSize,
282 Data,
283 &DataSize
284 );
285 }
286 }
287
288 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
289 AuthVariableInfo.VariableName = VariableName;
290 AuthVariableInfo.VendorGuid = VendorGuid;
291 AuthVariableInfo.Data = Data;
292 AuthVariableInfo.DataSize = DataSize;
293 AuthVariableInfo.Attributes = Attributes;
294 AuthVariableInfo.TimeStamp = TimeStamp;
295 return mAuthVarLibContextIn->UpdateVariable (
296 &AuthVariableInfo
297 );
298 }
299
300 /**
301 Initialize Secure Boot variables.
302
303 @retval EFI_SUCCESS The initialization operation is successful.
304 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
305
306 **/
307 EFI_STATUS
308 InitSecureBootVariables (
309 VOID
310 )
311 {
312 EFI_STATUS Status;
313 UINT8 *Data;
314 UINTN DataSize;
315 UINT32 SecureBoot;
316 UINT8 SecureBootEnable;
317 SECURE_BOOT_MODE_TYPE SecureBootMode;
318 BOOLEAN IsPkPresent;
319
320 //
321 // Find "PK" variable
322 //
323 Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);
324 if (EFI_ERROR (Status)) {
325 IsPkPresent = FALSE;
326 DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
327 } else {
328 IsPkPresent = TRUE;
329 DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
330 }
331
332 //
333 // Init "SecureBootMode" variable.
334 // Initial case
335 // SecureBootMode doesn't exist. Init it with PK state
336 // 3 inconsistency cases need to sync
337 // 1.1 Add PK -> system break -> update SecureBootMode Var
338 // 1.2 Delete PK -> system break -> update SecureBootMode Var
339 // 1.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var
340 //
341 Status = AuthServiceInternalFindVariable (EDKII_SECURE_BOOT_MODE_NAME, &gEdkiiSecureBootModeGuid, (VOID **)&Data, &DataSize);
342 if (EFI_ERROR(Status)) {
343 //
344 // Variable driver Initial Case
345 //
346 if (IsPkPresent) {
347 SecureBootMode = SecureBootModeTypeUserMode;
348 } else {
349 SecureBootMode = SecureBootModeTypeSetupMode;
350 }
351 } else {
352 //
353 // 3 inconsistency cases need to sync
354 //
355 SecureBootMode = (SECURE_BOOT_MODE_TYPE)*Data;
356 ASSERT(SecureBootMode < SecureBootModeTypeMax);
357
358 if (IsPkPresent) {
359 //
360 // 3.1 Add PK -> system break -> update SecureBootMode Var
361 //
362 if (SecureBootMode == SecureBootModeTypeSetupMode) {
363 SecureBootMode = SecureBootModeTypeUserMode;
364 } else if (SecureBootMode == SecureBootModeTypeAuditMode) {
365 SecureBootMode = SecureBootModeTypeDeployedMode;
366 }
367 } else {
368 //
369 // 3.2 Delete PK -> system break -> update SecureBootMode Var
370 // 3.3 Set AuditMode ->Delete PK -> system break -> Update SecureBootMode Var. Reinit to be SetupMode
371 //
372 if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {
373 SecureBootMode = SecureBootModeTypeSetupMode;
374 }
375 }
376 }
377
378 if (EFI_ERROR(Status) || (SecureBootMode != (SECURE_BOOT_MODE_TYPE)*Data)) {
379 //
380 // Update SecureBootMode Var
381 //
382 Status = AuthServiceInternalUpdateVariable (
383 EDKII_SECURE_BOOT_MODE_NAME,
384 &gEdkiiSecureBootModeGuid,
385 &SecureBootMode,
386 sizeof (UINT8),
387 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
388 );
389 if (EFI_ERROR(Status)) {
390 return Status;
391 }
392 }
393
394 //
395 // Init "AuditMode"
396 //
397 Status = AuthServiceInternalUpdateVariable (
398 EFI_AUDIT_MODE_NAME,
399 &gEfiGlobalVariableGuid,
400 &mSecureBootState[SecureBootMode].AuditMode,
401 sizeof(UINT8),
402 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
403 );
404 if (EFI_ERROR(Status)) {
405 return Status;
406 }
407
408 //
409 // Init "DeployedMode"
410 //
411 Status = AuthServiceInternalUpdateVariable (
412 EFI_DEPLOYED_MODE_NAME,
413 &gEfiGlobalVariableGuid,
414 &mSecureBootState[SecureBootMode].DeployedMode,
415 sizeof(UINT8),
416 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
417 );
418 if (EFI_ERROR(Status)) {
419 return Status;
420 }
421
422 //
423 // Init "SetupMode"
424 //
425 Status = AuthServiceInternalUpdateVariable (
426 EFI_SETUP_MODE_NAME,
427 &gEfiGlobalVariableGuid,
428 &mSecureBootState[SecureBootMode].SetupMode,
429 sizeof(UINT8),
430 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
431 );
432 if (EFI_ERROR(Status)) {
433 return Status;
434 }
435
436 //
437 // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
438 // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
439 // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
440 //
441 SecureBootEnable = SECURE_BOOT_DISABLE;
442 Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **)&Data, &DataSize);
443 if (!EFI_ERROR(Status)) {
444 if (IsPkPresent) {
445 SecureBootEnable = *Data;
446 }
447 } else if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {
448 //
449 // "SecureBootEnable" not exist, initialize it in User Mode or Deployed Mode.
450 //
451 SecureBootEnable = SECURE_BOOT_ENABLE;
452 Status = AuthServiceInternalUpdateVariable (
453 EFI_SECURE_BOOT_ENABLE_NAME,
454 &gEfiSecureBootEnableDisableGuid,
455 &SecureBootEnable,
456 sizeof (UINT8),
457 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
458 );
459 if (EFI_ERROR (Status)) {
460 return Status;
461 }
462 }
463
464 //
465 // Create "SecureBoot" variable with BS+RT attribute set.
466 //
467 if ((SecureBootEnable == SECURE_BOOT_ENABLE)
468 && ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode))) {
469 SecureBoot = SECURE_BOOT_MODE_ENABLE;
470 } else {
471 SecureBoot = SECURE_BOOT_MODE_DISABLE;
472 }
473 Status = AuthServiceInternalUpdateVariable (
474 EFI_SECURE_BOOT_MODE_NAME,
475 &gEfiGlobalVariableGuid,
476 &SecureBoot,
477 sizeof (UINT8),
478 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
479 );
480
481 DEBUG ((EFI_D_INFO, "SecureBootMode is %x\n", SecureBootMode));
482 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBoot));
483 DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
484
485 //
486 // Save SecureBootMode in global space
487 //
488 mSecureBootMode = SecureBootMode;
489
490 return Status;
491 }
492
493 /**
494 Update SecureBootMode variable.
495
496 @param[in] NewMode New Secure Boot Mode.
497
498 @retval EFI_SUCCESS The initialization operation is successful.
499 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
500
501 **/
502 EFI_STATUS
503 UpdateSecureBootMode(
504 IN SECURE_BOOT_MODE_TYPE NewMode
505 )
506 {
507 EFI_STATUS Status;
508
509 //
510 // Update "SecureBootMode" variable to new Secure Boot Mode
511 //
512 Status = AuthServiceInternalUpdateVariable (
513 EDKII_SECURE_BOOT_MODE_NAME,
514 &gEdkiiSecureBootModeGuid,
515 &NewMode,
516 sizeof (UINT8),
517 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
518 );
519
520 if (!EFI_ERROR(Status)) {
521 DEBUG((EFI_D_INFO, "SecureBootMode Update to %x\n", NewMode));
522 mSecureBootMode = NewMode;
523 } else {
524 DEBUG((EFI_D_ERROR, "SecureBootMode Update failure %x\n", Status));
525 }
526
527 return Status;
528 }
529
530 /**
531 Current secure boot mode is AuditMode. This function performs secure boot mode transition
532 to a new mode.
533
534 @param[in] NewMode New Secure Boot Mode.
535
536 @retval EFI_SUCCESS The initialization operation is successful.
537 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
538
539 **/
540 EFI_STATUS
541 TransitionFromAuditMode(
542 IN SECURE_BOOT_MODE_TYPE NewMode
543 )
544 {
545 EFI_STATUS Status;
546 VOID *AuditVarData;
547 VOID *DeployedVarData;
548 VOID *SetupVarData;
549 VOID *SecureBootVarData;
550 UINT8 SecureBootEnable;
551 UINTN DataSize;
552
553 //
554 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
555 // they can be RW. but can't be deleted. so they can always be found.
556 //
557 Status = AuthServiceInternalFindVariable (
558 EFI_AUDIT_MODE_NAME,
559 &gEfiGlobalVariableGuid,
560 &AuditVarData,
561 &DataSize
562 );
563 if (EFI_ERROR (Status)) {
564 ASSERT(FALSE);
565 }
566
567 Status = AuthServiceInternalFindVariable (
568 EFI_DEPLOYED_MODE_NAME,
569 &gEfiGlobalVariableGuid,
570 &DeployedVarData,
571 &DataSize
572 );
573 if (EFI_ERROR (Status)) {
574 ASSERT(FALSE);
575 }
576
577 Status = AuthServiceInternalFindVariable (
578 EFI_SETUP_MODE_NAME,
579 &gEfiGlobalVariableGuid,
580 &SetupVarData,
581 &DataSize
582 );
583 if (EFI_ERROR (Status)) {
584 ASSERT(FALSE);
585 }
586
587 Status = AuthServiceInternalFindVariable (
588 EFI_SECURE_BOOT_MODE_NAME,
589 &gEfiGlobalVariableGuid,
590 &SecureBootVarData,
591 &DataSize
592 );
593 if (EFI_ERROR (Status)) {
594 ASSERT(FALSE);
595 }
596
597 //
598 // Make Secure Boot Mode transition ATOMIC
599 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
600 // other tranisition logic are all memory operations.
601 //
602 Status = UpdateSecureBootMode(NewMode);
603 if (EFI_ERROR(Status)) {
604 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
605 }
606
607 if (NewMode == SecureBootModeTypeDeployedMode) {
608 //
609 // Since PK is enrolled, can't rollback, always update SecureBootMode in memory
610 //
611 mSecureBootMode = NewMode;
612 Status = EFI_SUCCESS;
613
614 //
615 // AuditMode ----> DeployedMode
616 // Side Effects
617 // AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0
618 //
619 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
620 // variable storage reclaim at runtime.
621 //
622 CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));
623 //
624 // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible
625 // variable storage reclaim at runtime.
626 //
627 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
628 //
629 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
630 // variable storage reclaim at runtime.
631 //
632 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
633
634 if (mAuthVarLibContextIn->AtRuntime ()) {
635 //
636 // SecureBoot Variable indicates whether the platform firmware is operating
637 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
638 // Variable in runtime.
639 //
640 return Status;
641 }
642
643 //
644 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
645 // variable storage reclaim at runtime.
646 //
647 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
648
649 //
650 // Create "SecureBootEnable" variable as secure boot is enabled.
651 //
652 SecureBootEnable = SECURE_BOOT_ENABLE;
653 AuthServiceInternalUpdateVariable (
654 EFI_SECURE_BOOT_ENABLE_NAME,
655 &gEfiSecureBootEnableDisableGuid,
656 &SecureBootEnable,
657 sizeof (SecureBootEnable),
658 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
659 );
660 } else {
661 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeAuditMode, NewMode));
662 ASSERT(FALSE);
663 }
664
665 return Status;
666 }
667
668 /**
669 Current secure boot mode is DeployedMode. This function performs secure boot mode transition
670 to a new mode.
671
672 @param[in] NewMode New Secure Boot Mode.
673
674 @retval EFI_SUCCESS The initialization operation is successful.
675 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
676
677 **/
678 EFI_STATUS
679 TransitionFromDeployedMode(
680 IN SECURE_BOOT_MODE_TYPE NewMode
681 )
682 {
683 EFI_STATUS Status;
684 VOID *DeployedVarData;
685 VOID *SetupVarData;
686 VOID *SecureBootVarData;
687 UINT8 SecureBootEnable;
688 UINTN DataSize;
689
690 //
691 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
692 // they can be RW. but can't be deleted. so they can always be found.
693 //
694 Status = AuthServiceInternalFindVariable (
695 EFI_DEPLOYED_MODE_NAME,
696 &gEfiGlobalVariableGuid,
697 &DeployedVarData,
698 &DataSize
699 );
700 if (EFI_ERROR (Status)) {
701 ASSERT(FALSE);
702 }
703
704 Status = AuthServiceInternalFindVariable (
705 EFI_SETUP_MODE_NAME,
706 &gEfiGlobalVariableGuid,
707 &SetupVarData,
708 &DataSize
709 );
710 if (EFI_ERROR (Status)) {
711 ASSERT(FALSE);
712 }
713
714 Status = AuthServiceInternalFindVariable (
715 EFI_SECURE_BOOT_MODE_NAME,
716 &gEfiGlobalVariableGuid,
717 &SecureBootVarData,
718 &DataSize
719 );
720 if (EFI_ERROR (Status)) {
721 ASSERT(FALSE);
722 }
723
724 //
725 // Make Secure Boot Mode transition ATOMIC
726 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
727 // other tranisition logic are all memory operations.
728 //
729 Status = UpdateSecureBootMode(NewMode);
730 if (EFI_ERROR(Status)) {
731 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
732 }
733
734 switch(NewMode) {
735 case SecureBootModeTypeUserMode:
736 //
737 // DeployedMode ----> UserMode
738 // Side Effects
739 // DeployedMode := 0
740 //
741 // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
742 //
743 if (EFI_ERROR(Status)) {
744 return Status;
745 }
746 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
747
748 break;
749
750 case SecureBootModeTypeSetupMode:
751 //
752 // Since PK is processed before, can't rollback, still update SecureBootMode in memory
753 //
754 mSecureBootMode = NewMode;
755 Status = EFI_SUCCESS;
756
757 //
758 // DeployedMode ----> SetupMode
759 //
760 // Platform Specific PKpub clear or Delete Pkpub
761 // Side Effects
762 // DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0
763 //
764 // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible
765 // variable storage reclaim at runtime.
766 //
767 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
768 //
769 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
770 // variable storage reclaim at runtime.
771 //
772 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
773
774 if (mAuthVarLibContextIn->AtRuntime ()) {
775 //
776 // SecureBoot Variable indicates whether the platform firmware is operating
777 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
778 // Variable in runtime.
779 //
780 return Status;
781 }
782
783 //
784 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
785 // variable storage reclaim at runtime.
786 //
787 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
788
789 //
790 // Delete the "SecureBootEnable" variable as secure boot is Disabled.
791 //
792 SecureBootEnable = SECURE_BOOT_DISABLE;
793 AuthServiceInternalUpdateVariable (
794 EFI_SECURE_BOOT_ENABLE_NAME,
795 &gEfiSecureBootEnableDisableGuid,
796 &SecureBootEnable,
797 0,
798 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
799 );
800 break;
801
802 default:
803 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeDeployedMode, NewMode));
804 ASSERT(FALSE);
805 }
806
807 return Status;
808 }
809
810 /**
811 Current secure boot mode is UserMode. This function performs secure boot mode transition
812 to a new mode.
813
814 @param[in] NewMode New Secure Boot Mode.
815
816 @retval EFI_SUCCESS The initialization operation is successful.
817 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
818
819 **/
820 EFI_STATUS
821 TransitionFromUserMode(
822 IN SECURE_BOOT_MODE_TYPE NewMode
823 )
824 {
825 EFI_STATUS Status;
826 VOID *AuditVarData;
827 VOID *DeployedVarData;
828 VOID *SetupVarData;
829 VOID *PkVarData;
830 VOID *SecureBootVarData;
831 UINT8 SecureBootEnable;
832 UINTN DataSize;
833 VARIABLE_ENTRY_CONSISTENCY VariableEntry;
834
835 //
836 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
837 // they can be RW. but can't be deleted. so they can always be found.
838 //
839 Status = AuthServiceInternalFindVariable (
840 EFI_AUDIT_MODE_NAME,
841 &gEfiGlobalVariableGuid,
842 &AuditVarData,
843 &DataSize
844 );
845 if (EFI_ERROR (Status)) {
846 ASSERT(FALSE);
847 }
848
849 Status = AuthServiceInternalFindVariable (
850 EFI_DEPLOYED_MODE_NAME,
851 &gEfiGlobalVariableGuid,
852 &DeployedVarData,
853 &DataSize
854 );
855 if (EFI_ERROR (Status)) {
856 ASSERT(FALSE);
857 }
858
859 Status = AuthServiceInternalFindVariable (
860 EFI_SETUP_MODE_NAME,
861 &gEfiGlobalVariableGuid,
862 &SetupVarData,
863 &DataSize
864 );
865 if (EFI_ERROR (Status)) {
866 ASSERT(FALSE);
867 }
868
869 Status = AuthServiceInternalFindVariable (
870 EFI_SECURE_BOOT_MODE_NAME,
871 &gEfiGlobalVariableGuid,
872 &SecureBootVarData,
873 &DataSize
874 );
875 if (EFI_ERROR (Status)) {
876 ASSERT(FALSE);
877 }
878
879 //
880 // Make Secure Boot Mode transition ATOMIC
881 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
882 // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.
883 //
884 if (NewMode != SecureBootModeTypeAuditMode) {
885 Status = UpdateSecureBootMode(NewMode);
886 if (EFI_ERROR(Status)) {
887 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
888 }
889 } else {
890 //
891 // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var first.
892 // Will update SecureBootMode after DeletePK logic
893 //
894 VariableEntry.VariableSize = sizeof(UINT8);
895 VariableEntry.Guid = &gEdkiiSecureBootModeGuid;
896 VariableEntry.Name = EDKII_SECURE_BOOT_MODE_NAME;
897 if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry, NULL)) {
898 return EFI_OUT_OF_RESOURCES;
899 }
900 }
901
902 switch(NewMode) {
903 case SecureBootModeTypeDeployedMode:
904 //
905 // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
906 //
907 if (EFI_ERROR(Status)) {
908 return Status;
909 }
910
911 //
912 // UserMode ----> DeployedMode
913 // Side Effects
914 // DeployedMode := 1
915 //
916 CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
917 break;
918
919 case SecureBootModeTypeAuditMode:
920 //
921 // UserMode ----> AuditMode
922 // Side Effects
923 // Delete PKpub / SetupMode := 1 / SecureBoot := 0
924 //
925 // Delete PKpub without verification. Should always succeed.
926 //
927 PkVarData = NULL;
928 Status = AuthServiceInternalUpdateVariable (
929 EFI_PLATFORM_KEY_NAME,
930 &gEfiGlobalVariableGuid,
931 PkVarData,
932 0,
933 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
934 );
935 if (EFI_ERROR(Status)) {
936 DEBUG((EFI_D_ERROR, "UserMode -> AuditMode. Delete PK fail %x\n", Status));
937 ASSERT(FALSE);
938 }
939
940 //
941 // Update Private NV SecureBootMode Variable
942 //
943 Status = UpdateSecureBootMode(NewMode);
944 if (EFI_ERROR(Status)) {
945 //
946 // Since PK is deleted successfully, Doesn't break, continue to update other variable.
947 //
948 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
949 }
950 CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));
951
952 //
953 // Fall into SetupMode logic
954 //
955 case SecureBootModeTypeSetupMode:
956 //
957 // Since PK is deleted before , can't rollback, still update SecureBootMode in memory
958 //
959 mSecureBootMode = NewMode;
960 Status = EFI_SUCCESS;
961
962 //
963 // UserMode ----> SetupMode
964 // Side Effects
965 // DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0
966 //
967 // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
968 // variable storage reclaim at runtime.
969 //
970 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
971
972 if (mAuthVarLibContextIn->AtRuntime ()) {
973 //
974 // SecureBoot Variable indicates whether the platform firmware is operating
975 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
976 // Variable in runtime.
977 //
978 return Status;
979 }
980
981 //
982 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
983 // variable storage reclaim at runtime.
984 //
985 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
986
987 //
988 // Delete the "SecureBootEnable" variable as secure boot is Disabled.
989 //
990 SecureBootEnable = SECURE_BOOT_DISABLE;
991 AuthServiceInternalUpdateVariable (
992 EFI_SECURE_BOOT_ENABLE_NAME,
993 &gEfiSecureBootEnableDisableGuid,
994 &SecureBootEnable,
995 0,
996 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
997 );
998
999 break;
1000
1001 default:
1002 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeUserMode, NewMode));
1003 ASSERT(FALSE);
1004 }
1005
1006 return Status;
1007 }
1008
1009 /**
1010 Current secure boot mode is SetupMode. This function performs secure boot mode transition
1011 to a new mode.
1012
1013 @param[in] NewMode New Secure Boot Mode.
1014
1015 @retval EFI_SUCCESS The initialization operation is successful.
1016 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
1017
1018 **/
1019 EFI_STATUS
1020 TransitionFromSetupMode(
1021 IN SECURE_BOOT_MODE_TYPE NewMode
1022 )
1023 {
1024 EFI_STATUS Status;
1025 VOID *AuditVarData;
1026 VOID *SetupVarData;
1027 VOID *SecureBootVarData;
1028 UINT8 SecureBootEnable;
1029 UINTN DataSize;
1030
1031 //
1032 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
1033 // they can be RW. but can't be deleted. so they can always be found.
1034 //
1035 Status = AuthServiceInternalFindVariable (
1036 EFI_AUDIT_MODE_NAME,
1037 &gEfiGlobalVariableGuid,
1038 &AuditVarData,
1039 &DataSize
1040 );
1041 if (EFI_ERROR (Status)) {
1042 ASSERT(FALSE);
1043 }
1044
1045 Status = AuthServiceInternalFindVariable (
1046 EFI_SETUP_MODE_NAME,
1047 &gEfiGlobalVariableGuid,
1048 &SetupVarData,
1049 &DataSize
1050 );
1051 if (EFI_ERROR (Status)) {
1052 ASSERT(FALSE);
1053 }
1054
1055 Status = AuthServiceInternalFindVariable (
1056 EFI_SECURE_BOOT_MODE_NAME,
1057 &gEfiGlobalVariableGuid,
1058 &SecureBootVarData,
1059 &DataSize
1060 );
1061 if (EFI_ERROR (Status)) {
1062 ASSERT(FALSE);
1063 }
1064
1065 //
1066 // Make Secure Boot Mode transition ATOMIC
1067 // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
1068 // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.
1069 //
1070 Status = UpdateSecureBootMode(NewMode);
1071 if (EFI_ERROR(Status)) {
1072 DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
1073 }
1074
1075 switch(NewMode) {
1076 case SecureBootModeTypeAuditMode:
1077 //
1078 // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
1079 //
1080 if (EFI_ERROR(Status)) {
1081 return Status;
1082 }
1083
1084 //
1085 // SetupMode ----> AuditMode
1086 // Side Effects
1087 // AuditMode := 1
1088 //
1089 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
1090 // variable storage reclaim at runtime.
1091 //
1092 CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));
1093 break;
1094
1095 case SecureBootModeTypeUserMode:
1096 //
1097 // Since PK is enrolled before, can't rollback, still update SecureBootMode in memory
1098 //
1099 mSecureBootMode = NewMode;
1100 Status = EFI_SUCCESS;
1101
1102 //
1103 // SetupMode ----> UserMode
1104 // Side Effects
1105 // SetupMode := 0 / SecureBoot := 1
1106 //
1107 // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
1108 // variable storage reclaim at runtime.
1109 //
1110 CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
1111
1112 if (mAuthVarLibContextIn->AtRuntime ()) {
1113 //
1114 // SecureBoot Variable indicates whether the platform firmware is operating
1115 // in Secure boot mode (1) or not (0), so we should not change SecureBoot
1116 // Variable in runtime.
1117 //
1118 return Status;
1119 }
1120
1121 //
1122 // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
1123 // variable storage reclaim at runtime.
1124 //
1125 CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
1126
1127 //
1128 // Create the "SecureBootEnable" variable as secure boot is enabled.
1129 //
1130 SecureBootEnable = SECURE_BOOT_ENABLE;
1131 AuthServiceInternalUpdateVariable (
1132 EFI_SECURE_BOOT_ENABLE_NAME,
1133 &gEfiSecureBootEnableDisableGuid,
1134 &SecureBootEnable,
1135 sizeof (SecureBootEnable),
1136 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
1137 );
1138 break;
1139
1140 default:
1141 DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeSetupMode, NewMode));
1142 ASSERT(FALSE);
1143 }
1144
1145 return Status;
1146 }
1147
1148 /**
1149 This function performs main secure boot mode transition logic.
1150
1151 @param[in] CurMode Current Secure Boot Mode.
1152 @param[in] NewMode New Secure Boot Mode.
1153
1154 @retval EFI_SUCCESS The initialization operation is successful.
1155 @retval EFI_OUT_OF_RESOURCES There is not enough resource.
1156 @retval EFI_INVALID_PARAMETER The Current Secure Boot Mode is wrong.
1157
1158 **/
1159 EFI_STATUS
1160 SecureBootModeTransition(
1161 IN SECURE_BOOT_MODE_TYPE CurMode,
1162 IN SECURE_BOOT_MODE_TYPE NewMode
1163 )
1164 {
1165 EFI_STATUS Status;
1166
1167 //
1168 // SecureBootMode transition
1169 //
1170 switch (CurMode) {
1171 case SecureBootModeTypeUserMode:
1172 Status = TransitionFromUserMode(NewMode);
1173 break;
1174
1175 case SecureBootModeTypeSetupMode:
1176 Status = TransitionFromSetupMode(NewMode);
1177 break;
1178
1179 case SecureBootModeTypeAuditMode:
1180 Status = TransitionFromAuditMode(NewMode);
1181 break;
1182
1183 case SecureBootModeTypeDeployedMode:
1184 Status = TransitionFromDeployedMode(NewMode);
1185 break;
1186
1187 default:
1188 Status = EFI_INVALID_PARAMETER;
1189 ASSERT(FALSE);
1190 }
1191
1192 return Status;
1193
1194 }
1195
1196 /**
1197 Determine whether this operation needs a physical present user.
1198
1199 @param[in] VariableName Name of the Variable.
1200 @param[in] VendorGuid GUID of the Variable.
1201
1202 @retval TRUE This variable is protected, only a physical present user could set this variable.
1203 @retval FALSE This variable is not protected.
1204
1205 **/
1206 BOOLEAN
1207 NeedPhysicallyPresent(
1208 IN CHAR16 *VariableName,
1209 IN EFI_GUID *VendorGuid
1210 )
1211 {
1212 if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
1213 || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
1214 return TRUE;
1215 }
1216
1217 return FALSE;
1218 }
1219
1220 /**
1221 Determine whether the platform is operating in Custom Secure Boot mode.
1222
1223 @retval TRUE The platform is operating in Custom mode.
1224 @retval FALSE The platform is operating in Standard mode.
1225
1226 **/
1227 BOOLEAN
1228 InCustomMode (
1229 VOID
1230 )
1231 {
1232 EFI_STATUS Status;
1233 VOID *Data;
1234 UINTN DataSize;
1235
1236 Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);
1237 if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {
1238 return TRUE;
1239 }
1240
1241 return FALSE;
1242 }
1243
1244 /**
1245 Get available public key index.
1246
1247 @param[in] PubKey Pointer to Public Key data.
1248
1249 @return Public key index, 0 if no any public key index available.
1250
1251 **/
1252 UINT32
1253 GetAvailableKeyIndex (
1254 IN UINT8 *PubKey
1255 )
1256 {
1257 EFI_STATUS Status;
1258 UINT8 *Data;
1259 UINTN DataSize;
1260 UINT8 *Ptr;
1261 UINT32 Index;
1262 BOOLEAN IsFound;
1263 EFI_GUID VendorGuid;
1264 CHAR16 Name[1];
1265 AUTH_VARIABLE_INFO AuthVariableInfo;
1266 UINT32 KeyIndex;
1267
1268 Status = AuthServiceInternalFindVariable (
1269 AUTHVAR_KEYDB_NAME,
1270 &gEfiAuthenticatedVariableGuid,
1271 (VOID **) &Data,
1272 &DataSize
1273 );
1274 if (EFI_ERROR (Status)) {
1275 DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
1276 return 0;
1277 }
1278
1279 if (mPubKeyNumber == mMaxKeyNumber) {
1280 Name[0] = 0;
1281 AuthVariableInfo.VariableName = Name;
1282 ZeroMem (&VendorGuid, sizeof (VendorGuid));
1283 AuthVariableInfo.VendorGuid = &VendorGuid;
1284 mPubKeyNumber = 0;
1285 //
1286 // Collect valid key data.
1287 //
1288 do {
1289 Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);
1290 if (!EFI_ERROR (Status)) {
1291 if (AuthVariableInfo.PubKeyIndex != 0) {
1292 for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
1293 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
1294 //
1295 // Check if the key data has been collected.
1296 //
1297 for (Index = 0; Index < mPubKeyNumber; Index++) {
1298 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
1299 break;
1300 }
1301 }
1302 if (Index == mPubKeyNumber) {
1303 //
1304 // New key data.
1305 //
1306 CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));
1307 mPubKeyNumber++;
1308 }
1309 break;
1310 }
1311 }
1312 }
1313 }
1314 } while (Status != EFI_NOT_FOUND);
1315
1316 //
1317 // No available space to add new public key.
1318 //
1319 if (mPubKeyNumber == mMaxKeyNumber) {
1320 return 0;
1321 }
1322 }
1323
1324 //
1325 // Find available public key index.
1326 //
1327 for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {
1328 IsFound = FALSE;
1329 for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
1330 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {
1331 IsFound = TRUE;
1332 break;
1333 }
1334 }
1335 if (!IsFound) {
1336 break;
1337 }
1338 }
1339
1340 return KeyIndex;
1341 }
1342
1343 /**
1344 Add public key in store and return its index.
1345
1346 @param[in] PubKey Input pointer to Public Key data.
1347 @param[in] VariableDataEntry The variable data entry.
1348
1349 @return Index of new added public key.
1350
1351 **/
1352 UINT32
1353 AddPubKeyInStore (
1354 IN UINT8 *PubKey,
1355 IN VARIABLE_ENTRY_CONSISTENCY *VariableDataEntry
1356 )
1357 {
1358 EFI_STATUS Status;
1359 UINT32 Index;
1360 VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry;
1361 UINT32 Attributes;
1362 UINT32 KeyIndex;
1363
1364 if (PubKey == NULL) {
1365 return 0;
1366 }
1367
1368 //
1369 // Check whether the public key entry does exist.
1370 //
1371 for (Index = 0; Index < mPubKeyNumber; Index++) {
1372 if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
1373 return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));
1374 }
1375 }
1376
1377 KeyIndex = GetAvailableKeyIndex (PubKey);
1378 if (KeyIndex == 0) {
1379 return 0;
1380 }
1381
1382 //
1383 // Check the variable space for both public key and variable data.
1384 //
1385 PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);
1386 PublicKeyEntry.Guid = &gEfiAuthenticatedVariableGuid;
1387 PublicKeyEntry.Name = AUTHVAR_KEYDB_NAME;
1388 Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
1389
1390 if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {
1391 //
1392 // No enough variable space.
1393 //
1394 return 0;
1395 }
1396
1397 WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);
1398 CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
1399 mPubKeyNumber++;
1400
1401 //
1402 // Update public key database variable.
1403 //
1404 Status = AuthServiceInternalUpdateVariable (
1405 AUTHVAR_KEYDB_NAME,
1406 &gEfiAuthenticatedVariableGuid,
1407 mPubKeyStore,
1408 mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),
1409 Attributes
1410 );
1411 if (EFI_ERROR (Status)) {
1412 DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));
1413 return 0;
1414 }
1415
1416 return KeyIndex;
1417 }
1418
1419 /**
1420 Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
1421 Follow the steps in UEFI2.2.
1422
1423 Caution: This function may receive untrusted input.
1424 This function may be invoked in SMM mode, and datasize and data are external input.
1425 This function will do basic validation, before parse the data.
1426 This function will parse the authentication carefully to avoid security issues, like
1427 buffer overflow, integer overflow.
1428
1429 @param[in] Data Pointer to data with AuthInfo.
1430 @param[in] DataSize Size of Data.
1431 @param[in] PubKey Public key used for verification.
1432
1433 @retval EFI_INVALID_PARAMETER Invalid parameter.
1434 @retval EFI_SECURITY_VIOLATION If authentication failed.
1435 @retval EFI_SUCCESS Authentication successful.
1436
1437 **/
1438 EFI_STATUS
1439 VerifyCounterBasedPayload (
1440 IN UINT8 *Data,
1441 IN UINTN DataSize,
1442 IN UINT8 *PubKey
1443 )
1444 {
1445 BOOLEAN Status;
1446 EFI_VARIABLE_AUTHENTICATION *CertData;
1447 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
1448 UINT8 Digest[SHA256_DIGEST_SIZE];
1449 VOID *Rsa;
1450 UINTN PayloadSize;
1451
1452 PayloadSize = DataSize - AUTHINFO_SIZE;
1453 Rsa = NULL;
1454 CertData = NULL;
1455 CertBlock = NULL;
1456
1457 if (Data == NULL || PubKey == NULL) {
1458 return EFI_INVALID_PARAMETER;
1459 }
1460
1461 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
1462 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
1463
1464 //
1465 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
1466 // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
1467 //
1468 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
1469 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {
1470 //
1471 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
1472 //
1473 return EFI_SECURITY_VIOLATION;
1474 }
1475 //
1476 // Hash data payload with SHA256.
1477 //
1478 ZeroMem (Digest, SHA256_DIGEST_SIZE);
1479 Status = Sha256Init (mHashCtx);
1480 if (!Status) {
1481 goto Done;
1482 }
1483 Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
1484 if (!Status) {
1485 goto Done;
1486 }
1487 //
1488 // Hash Size.
1489 //
1490 Status = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
1491 if (!Status) {
1492 goto Done;
1493 }
1494 //
1495 // Hash Monotonic Count.
1496 //
1497 Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
1498 if (!Status) {
1499 goto Done;
1500 }
1501 Status = Sha256Final (mHashCtx, Digest);
1502 if (!Status) {
1503 goto Done;
1504 }
1505 //
1506 // Generate & Initialize RSA Context.
1507 //
1508 Rsa = RsaNew ();
1509 ASSERT (Rsa != NULL);
1510 //
1511 // Set RSA Key Components.
1512 // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
1513 //
1514 Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
1515 if (!Status) {
1516 goto Done;
1517 }
1518 Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
1519 if (!Status) {
1520 goto Done;
1521 }
1522 //
1523 // Verify the signature.
1524 //
1525 Status = RsaPkcs1Verify (
1526 Rsa,
1527 Digest,
1528 SHA256_DIGEST_SIZE,
1529 CertBlock->Signature,
1530 EFI_CERT_TYPE_RSA2048_SHA256_SIZE
1531 );
1532
1533 Done:
1534 if (Rsa != NULL) {
1535 RsaFree (Rsa);
1536 }
1537 if (Status) {
1538 return EFI_SUCCESS;
1539 } else {
1540 return EFI_SECURITY_VIOLATION;
1541 }
1542 }
1543
1544
1545 /**
1546 Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
1547
1548 @param[in] VariableName Name of Variable to be check.
1549 @param[in] VendorGuid Variable vendor GUID.
1550 @param[in] Data Point to the variable data to be checked.
1551 @param[in] DataSize Size of Data.
1552
1553 @return EFI_INVALID_PARAMETER Invalid signature list format.
1554 @return EFI_SUCCESS Passed signature list format check successfully.
1555
1556 **/
1557 EFI_STATUS
1558 CheckSignatureListFormat(
1559 IN CHAR16 *VariableName,
1560 IN EFI_GUID *VendorGuid,
1561 IN VOID *Data,
1562 IN UINTN DataSize
1563 )
1564 {
1565 EFI_SIGNATURE_LIST *SigList;
1566 UINTN SigDataSize;
1567 UINT32 Index;
1568 UINT32 SigCount;
1569 BOOLEAN IsPk;
1570 VOID *RsaContext;
1571 EFI_SIGNATURE_DATA *CertData;
1572 UINTN CertLen;
1573
1574 if (DataSize == 0) {
1575 return EFI_SUCCESS;
1576 }
1577
1578 ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
1579
1580 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
1581 IsPk = TRUE;
1582 } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||
1583 (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
1584 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
1585 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {
1586 IsPk = FALSE;
1587 } else {
1588 return EFI_SUCCESS;
1589 }
1590
1591 SigCount = 0;
1592 SigList = (EFI_SIGNATURE_LIST *) Data;
1593 SigDataSize = DataSize;
1594 RsaContext = NULL;
1595
1596 //
1597 // Walk throuth the input signature list and check the data format.
1598 // If any signature is incorrectly formed, the whole check will fail.
1599 //
1600 while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
1601 for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
1602 if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
1603 //
1604 // The value of SignatureSize should always be 16 (size of SignatureOwner
1605 // component) add the data length according to signature type.
1606 //
1607 if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
1608 (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
1609 return EFI_INVALID_PARAMETER;
1610 }
1611 if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) &&
1612 SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
1613 return EFI_INVALID_PARAMETER;
1614 }
1615 break;
1616 }
1617 }
1618
1619 if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
1620 //
1621 // Undefined signature type.
1622 //
1623 return EFI_INVALID_PARAMETER;
1624 }
1625
1626 if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
1627 //
1628 // Try to retrieve the RSA public key from the X.509 certificate.
1629 // If this operation fails, it's not a valid certificate.
1630 //
1631 RsaContext = RsaNew ();
1632 if (RsaContext == NULL) {
1633 return EFI_INVALID_PARAMETER;
1634 }
1635 CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
1636 CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
1637 if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
1638 RsaFree (RsaContext);
1639 return EFI_INVALID_PARAMETER;
1640 }
1641 RsaFree (RsaContext);
1642 }
1643
1644 if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
1645 return EFI_INVALID_PARAMETER;
1646 }
1647 SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
1648
1649 SigDataSize -= SigList->SignatureListSize;
1650 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
1651 }
1652
1653 if (((UINTN) SigList - (UINTN) Data) != DataSize) {
1654 return EFI_INVALID_PARAMETER;
1655 }
1656
1657 if (IsPk && SigCount > 1) {
1658 return EFI_INVALID_PARAMETER;
1659 }
1660
1661 return EFI_SUCCESS;
1662 }
1663
1664 /**
1665 Update "VendorKeys" variable to record the out of band secure boot key modification.
1666
1667 @return EFI_SUCCESS Variable is updated successfully.
1668 @return Others Failed to update variable.
1669
1670 **/
1671 EFI_STATUS
1672 VendorKeyIsModified (
1673 VOID
1674 )
1675 {
1676 EFI_STATUS Status;
1677
1678 if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
1679 return EFI_SUCCESS;
1680 }
1681 mVendorKeyState = VENDOR_KEYS_MODIFIED;
1682
1683 Status = AuthServiceInternalUpdateVariable (
1684 EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
1685 &gEfiVendorKeysNvGuid,
1686 &mVendorKeyState,
1687 sizeof (UINT8),
1688 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
1689 );
1690 if (EFI_ERROR (Status)) {
1691 return Status;
1692 }
1693
1694 return AuthServiceInternalUpdateVariable (
1695 EFI_VENDOR_KEYS_VARIABLE_NAME,
1696 &gEfiGlobalVariableGuid,
1697 &mVendorKeyState,
1698 sizeof (UINT8),
1699 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
1700 );
1701 }
1702
1703 /**
1704 Process Secure Boot Mode variable.
1705
1706 Caution: This function may receive untrusted input.
1707 This function may be invoked in SMM mode, and datasize and data are external input.
1708 This function will do basic validation, before parse the data.
1709 This function will parse the authentication carefully to avoid security issues, like
1710 buffer overflow, integer overflow.
1711 This function will check attribute carefully to avoid authentication bypass.
1712
1713 @param[in] VariableName Name of Variable to be found.
1714 @param[in] VendorGuid Variable vendor GUID.
1715 @param[in] Data Data pointer.
1716 @param[in] DataSize Size of Data found. If size is less than the
1717 data, this value contains the required size.
1718 @param[in] Attributes Attribute value of the variable
1719
1720 @return EFI_INVALID_PARAMETER Invalid parameter
1721 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
1722 check carried out by the firmware.
1723 @return EFI_WRITE_PROTECTED Variable is Read-Only.
1724 @return EFI_SUCCESS Variable passed validation successfully.
1725
1726 **/
1727 EFI_STATUS
1728 ProcessSecureBootModeVar (
1729 IN CHAR16 *VariableName,
1730 IN EFI_GUID *VendorGuid,
1731 IN VOID *Data,
1732 IN UINTN DataSize,
1733 IN UINT32 Attributes OPTIONAL
1734 )
1735 {
1736 EFI_STATUS Status;
1737 VOID *VarData;
1738 UINTN VarDataSize;
1739
1740 //
1741 // Check "AuditMode", "DeployedMode" Variable ReadWrite Attributes
1742 // if in Runtime, Always RO
1743 // if in Boottime, Depends on current Secure Boot Mode
1744 //
1745 if (mAuthVarLibContextIn->AtRuntime()) {
1746 return EFI_WRITE_PROTECTED;
1747 }
1748
1749 //
1750 // Delete not OK
1751 //
1752 if ((DataSize != sizeof(UINT8)) || (Attributes == 0)) {
1753 return EFI_INVALID_PARAMETER;
1754 }
1755
1756 if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {
1757 if(mSecureBootState[mSecureBootMode].IsAuditModeRO) {
1758 return EFI_WRITE_PROTECTED;
1759 }
1760 } else {
1761 //
1762 // Platform specific deployedMode clear. Set DeployedMode = RW
1763 //
1764 if (!InCustomMode() || !UserPhysicalPresent() || mSecureBootMode != SecureBootModeTypeDeployedMode) {
1765 if(mSecureBootState[mSecureBootMode].IsDeployedModeRO) {
1766 return EFI_WRITE_PROTECTED;
1767 }
1768 }
1769 }
1770
1771 if (*(UINT8 *)Data != 0 && *(UINT8 *)Data != 1) {
1772 return EFI_INVALID_PARAMETER;
1773 }
1774
1775 //
1776 // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
1777 // they can be RW. but can't be deleted. so they can always be found.
1778 //
1779 Status = AuthServiceInternalFindVariable (
1780 VariableName,
1781 VendorGuid,
1782 &VarData,
1783 &VarDataSize
1784 );
1785 if (EFI_ERROR(Status)) {
1786 ASSERT(FALSE);
1787 }
1788
1789 //
1790 // If AuditMode/DeployedMode is assigned same value. Simply return EFI_SUCCESS
1791 //
1792 if (*(UINT8 *)VarData == *(UINT8 *)Data) {
1793 return EFI_SUCCESS;
1794 }
1795
1796 //
1797 // Perform SecureBootMode transition
1798 //
1799 if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {
1800 DEBUG((EFI_D_INFO, "Current SecureBootMode %x Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeAuditMode));
1801 return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeAuditMode);
1802 } else if (StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0) {
1803 if (mSecureBootMode == SecureBootModeTypeDeployedMode) {
1804 //
1805 // Platform specific DeployedMode clear. InCustomMode() && UserPhysicalPresent() is checked before
1806 //
1807 DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeUserMode));
1808 return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeUserMode);
1809 } else {
1810 DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeDeployedMode));
1811 return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeDeployedMode);
1812 }
1813 }
1814
1815 return EFI_INVALID_PARAMETER;
1816 }
1817
1818 /**
1819 Process variable with platform key for verification.
1820
1821 Caution: This function may receive untrusted input.
1822 This function may be invoked in SMM mode, and datasize and data are external input.
1823 This function will do basic validation, before parse the data.
1824 This function will parse the authentication carefully to avoid security issues, like
1825 buffer overflow, integer overflow.
1826 This function will check attribute carefully to avoid authentication bypass.
1827
1828 @param[in] VariableName Name of Variable to be found.
1829 @param[in] VendorGuid Variable vendor GUID.
1830 @param[in] Data Data pointer.
1831 @param[in] DataSize Size of Data found. If size is less than the
1832 data, this value contains the required size.
1833 @param[in] Attributes Attribute value of the variable
1834 @param[in] IsPk Indicate whether it is to process pk.
1835
1836 @return EFI_INVALID_PARAMETER Invalid parameter.
1837 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
1838 check carried out by the firmware.
1839 @return EFI_SUCCESS Variable passed validation successfully.
1840
1841 **/
1842 EFI_STATUS
1843 ProcessVarWithPk (
1844 IN CHAR16 *VariableName,
1845 IN EFI_GUID *VendorGuid,
1846 IN VOID *Data,
1847 IN UINTN DataSize,
1848 IN UINT32 Attributes OPTIONAL,
1849 IN BOOLEAN IsPk
1850 )
1851 {
1852 EFI_STATUS Status;
1853 BOOLEAN Del;
1854 UINT8 *Payload;
1855 UINTN PayloadSize;
1856 VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];
1857
1858 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
1859 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
1860 //
1861 // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
1862 // authenticated variable.
1863 //
1864 return EFI_INVALID_PARAMETER;
1865 }
1866
1867 //
1868 // Init state of Del. State may change due to secure check
1869 //
1870 Del = FALSE;
1871 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
1872 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
1873 if (PayloadSize == 0) {
1874 Del = TRUE;
1875 }
1876
1877 //
1878 // Check the variable space for both PKpub and SecureBootMode variable.
1879 //
1880 VariableEntry[0].VariableSize = PayloadSize;
1881 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
1882 VariableEntry[0].Name = EFI_PLATFORM_KEY_NAME;
1883
1884 VariableEntry[1].VariableSize = sizeof(UINT8);
1885 VariableEntry[1].Guid = &gEdkiiSecureBootModeGuid;
1886 VariableEntry[1].Name = EDKII_SECURE_BOOT_MODE_NAME;
1887
1888 if ((InCustomMode() && UserPhysicalPresent()) ||
1889 (((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode)) && !IsPk)) {
1890
1891 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
1892 if (EFI_ERROR (Status)) {
1893 return Status;
1894 }
1895
1896 //
1897 // If delete PKpub, only check for "SecureBootMode" only
1898 // if update / add PKpub, check both NewPKpub & "SecureBootMode"
1899 //
1900 if (IsPk) {
1901 //
1902 // Delete PKpub
1903 //
1904 if (Del && ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode))
1905 && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){
1906 return EFI_OUT_OF_RESOURCES;
1907 //
1908 // Add PKpub
1909 //
1910 } else if (!Del && ((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode))
1911 && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
1912 return EFI_OUT_OF_RESOURCES;
1913 }
1914 }
1915
1916 Status = AuthServiceInternalUpdateVariableWithTimeStamp (
1917 VariableName,
1918 VendorGuid,
1919 Payload,
1920 PayloadSize,
1921 Attributes,
1922 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
1923 );
1924 if (EFI_ERROR(Status)) {
1925 return Status;
1926 }
1927
1928 if (((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) || IsPk) {
1929 Status = VendorKeyIsModified ();
1930 }
1931 } else if (mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode) {
1932 //
1933 // If delete PKpub, check "SecureBootMode" only
1934 //
1935 if (IsPk && Del && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){
1936 return EFI_OUT_OF_RESOURCES;
1937 }
1938
1939 //
1940 // Verify against X509 Cert in PK database.
1941 //
1942 Status = VerifyTimeBasedPayloadAndUpdate (
1943 VariableName,
1944 VendorGuid,
1945 Data,
1946 DataSize,
1947 Attributes,
1948 AuthVarTypePk,
1949 &Del
1950 );
1951 } else {
1952 //
1953 // SetupMode or AuditMode to add PK
1954 // Verify against the certificate in data payload.
1955 //
1956 //
1957 // Check PKpub & SecureBootMode variable space consistency
1958 //
1959 if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
1960 //
1961 // No enough variable space to set PK successfully.
1962 //
1963 return EFI_OUT_OF_RESOURCES;
1964 }
1965
1966 Status = VerifyTimeBasedPayloadAndUpdate (
1967 VariableName,
1968 VendorGuid,
1969 Data,
1970 DataSize,
1971 Attributes,
1972 AuthVarTypePayload,
1973 &Del
1974 );
1975 }
1976
1977 if (!EFI_ERROR(Status) && IsPk) {
1978 //
1979 // Delete or Enroll PK causes SecureBootMode change
1980 //
1981 if (!Del) {
1982 if (mSecureBootMode == SecureBootModeTypeSetupMode) {
1983 //
1984 // If enroll PK in setup mode, change to user mode.
1985 //
1986 Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeUserMode);
1987 } else if (mSecureBootMode == SecureBootModeTypeAuditMode) {
1988 //
1989 // If enroll PK in Audit mode, change to Deployed mode.
1990 //
1991 Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeDeployedMode);
1992 } else {
1993 DEBUG((EFI_D_INFO, "PK is updated in %x mode. No SecureBootMode change.\n", mSecureBootMode));
1994 }
1995 } else {
1996 if ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode)) {
1997 //
1998 // If delete PK in User Mode or DeployedMode, change to Setup Mode.
1999 //
2000 Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeSetupMode);
2001 }
2002 }
2003 }
2004
2005 return Status;
2006 }
2007
2008 /**
2009 Process variable with key exchange key for verification.
2010
2011 Caution: This function may receive untrusted input.
2012 This function may be invoked in SMM mode, and datasize and data are external input.
2013 This function will do basic validation, before parse the data.
2014 This function will parse the authentication carefully to avoid security issues, like
2015 buffer overflow, integer overflow.
2016 This function will check attribute carefully to avoid authentication bypass.
2017
2018 @param[in] VariableName Name of Variable to be found.
2019 @param[in] VendorGuid Variable vendor GUID.
2020 @param[in] Data Data pointer.
2021 @param[in] DataSize Size of Data found. If size is less than the
2022 data, this value contains the required size.
2023 @param[in] Attributes Attribute value of the variable.
2024
2025 @return EFI_INVALID_PARAMETER Invalid parameter.
2026 @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
2027 check carried out by the firmware.
2028 @return EFI_SUCCESS Variable pass validation successfully.
2029
2030 **/
2031 EFI_STATUS
2032 ProcessVarWithKek (
2033 IN CHAR16 *VariableName,
2034 IN EFI_GUID *VendorGuid,
2035 IN VOID *Data,
2036 IN UINTN DataSize,
2037 IN UINT32 Attributes OPTIONAL
2038 )
2039 {
2040 EFI_STATUS Status;
2041 UINT8 *Payload;
2042 UINTN PayloadSize;
2043
2044 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
2045 (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
2046 //
2047 // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
2048 // authenticated variable.
2049 //
2050 return EFI_INVALID_PARAMETER;
2051 }
2052
2053 Status = EFI_SUCCESS;
2054 if ((mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode)
2055 && !(InCustomMode() && UserPhysicalPresent())) {
2056 //
2057 // Time-based, verify against X509 Cert KEK.
2058 //
2059 return VerifyTimeBasedPayloadAndUpdate (
2060 VariableName,
2061 VendorGuid,
2062 Data,
2063 DataSize,
2064 Attributes,
2065 AuthVarTypeKek,
2066 NULL
2067 );
2068 } else {
2069 //
2070 // If in setup mode or custom secure boot mode, no authentication needed.
2071 //
2072 Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
2073 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
2074
2075 Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
2076 if (EFI_ERROR (Status)) {
2077 return Status;
2078 }
2079
2080 Status = AuthServiceInternalUpdateVariableWithTimeStamp (
2081 VariableName,
2082 VendorGuid,
2083 Payload,
2084 PayloadSize,
2085 Attributes,
2086 &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
2087 );
2088 if (EFI_ERROR (Status)) {
2089 return Status;
2090 }
2091
2092 if ((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) {
2093 Status = VendorKeyIsModified ();
2094 }
2095 }
2096
2097 return Status;
2098 }
2099
2100 /**
2101 Check if it is to delete auth variable.
2102
2103 @param[in] OrgAttributes Original attribute value of the variable.
2104 @param[in] Data Data pointer.
2105 @param[in] DataSize Size of Data.
2106 @param[in] Attributes Attribute value of the variable.
2107
2108 @retval TRUE It is to delete auth variable.
2109 @retval FALSE It is not to delete auth variable.
2110
2111 **/
2112 BOOLEAN
2113 IsDeleteAuthVariable (
2114 IN UINT32 OrgAttributes,
2115 IN VOID *Data,
2116 IN UINTN DataSize,
2117 IN UINT32 Attributes
2118 )
2119 {
2120 BOOLEAN Del;
2121 UINTN PayloadSize;
2122
2123 Del = FALSE;
2124
2125 //
2126 // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
2127 // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
2128 // SetVariable must be used with attributes matching the existing variable
2129 // and the DataSize set to the size of the AuthInfo descriptor.
2130 //
2131 if ((Attributes == OrgAttributes) &&
2132 ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {
2133 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2134 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
2135 if (PayloadSize == 0) {
2136 Del = TRUE;
2137 }
2138 } else {
2139 PayloadSize = DataSize - AUTHINFO_SIZE;
2140 if (PayloadSize == 0) {
2141 Del = TRUE;
2142 }
2143 }
2144 }
2145
2146 return Del;
2147 }
2148
2149 /**
2150 Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
2151
2152 Caution: This function may receive untrusted input.
2153 This function may be invoked in SMM mode, and datasize and data are external input.
2154 This function will do basic validation, before parse the data.
2155 This function will parse the authentication carefully to avoid security issues, like
2156 buffer overflow, integer overflow.
2157 This function will check attribute carefully to avoid authentication bypass.
2158
2159 @param[in] VariableName Name of the variable.
2160 @param[in] VendorGuid Variable vendor GUID.
2161 @param[in] Data Data pointer.
2162 @param[in] DataSize Size of Data.
2163 @param[in] Attributes Attribute value of the variable.
2164
2165 @return EFI_INVALID_PARAMETER Invalid parameter.
2166 @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
2167 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
2168 @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
2169 @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
2170 set, but the AuthInfo does NOT pass the validation
2171 check carried out by the firmware.
2172 @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
2173
2174 **/
2175 EFI_STATUS
2176 ProcessVariable (
2177 IN CHAR16 *VariableName,
2178 IN EFI_GUID *VendorGuid,
2179 IN VOID *Data,
2180 IN UINTN DataSize,
2181 IN UINT32 Attributes
2182 )
2183 {
2184 EFI_STATUS Status;
2185 BOOLEAN IsDeletion;
2186 BOOLEAN IsFirstTime;
2187 UINT8 *PubKey;
2188 EFI_VARIABLE_AUTHENTICATION *CertData;
2189 EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
2190 UINT32 KeyIndex;
2191 UINT64 MonotonicCount;
2192 VARIABLE_ENTRY_CONSISTENCY VariableDataEntry;
2193 UINT32 Index;
2194 AUTH_VARIABLE_INFO OrgVariableInfo;
2195
2196 KeyIndex = 0;
2197 CertData = NULL;
2198 CertBlock = NULL;
2199 PubKey = NULL;
2200 IsDeletion = FALSE;
2201 Status = EFI_SUCCESS;
2202
2203 ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
2204 Status = mAuthVarLibContextIn->FindVariable (
2205 VariableName,
2206 VendorGuid,
2207 &OrgVariableInfo
2208 );
2209
2210 if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {
2211 //
2212 // Allow the delete operation of common authenticated variable at user physical presence.
2213 //
2214 Status = AuthServiceInternalUpdateVariable (
2215 VariableName,
2216 VendorGuid,
2217 NULL,
2218 0,
2219 0
2220 );
2221 if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
2222 Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
2223 }
2224
2225 return Status;
2226 }
2227
2228 if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {
2229 //
2230 // This variable is protected, only physical present user could modify its value.
2231 //
2232 return EFI_SECURITY_VIOLATION;
2233 }
2234
2235 //
2236 // A time-based authenticated variable and a count-based authenticated variable
2237 // can't be updated by each other.
2238 //
2239 if (OrgVariableInfo.Data != NULL) {
2240 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
2241 ((OrgVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
2242 return EFI_SECURITY_VIOLATION;
2243 }
2244
2245 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
2246 ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
2247 return EFI_SECURITY_VIOLATION;
2248 }
2249 }
2250
2251 //
2252 // Process Time-based Authenticated variable.
2253 //
2254 if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2255 return VerifyTimeBasedPayloadAndUpdate (
2256 VariableName,
2257 VendorGuid,
2258 Data,
2259 DataSize,
2260 Attributes,
2261 AuthVarTypePriv,
2262 NULL
2263 );
2264 }
2265
2266 //
2267 // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
2268 //
2269 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
2270 //
2271 // Determine current operation type.
2272 //
2273 if (DataSize == AUTHINFO_SIZE) {
2274 IsDeletion = TRUE;
2275 }
2276 //
2277 // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
2278 //
2279 if (OrgVariableInfo.Data == NULL) {
2280 IsFirstTime = TRUE;
2281 } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
2282 IsFirstTime = TRUE;
2283 } else {
2284 KeyIndex = OrgVariableInfo.PubKeyIndex;
2285 IsFirstTime = FALSE;
2286 }
2287 } else if ((OrgVariableInfo.Data != NULL) &&
2288 ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
2289 ) {
2290 //
2291 // If the variable is already write-protected, it always needs authentication before update.
2292 //
2293 return EFI_WRITE_PROTECTED;
2294 } else {
2295 //
2296 // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
2297 // That means it is not authenticated variable, just update variable as usual.
2298 //
2299 Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
2300 return Status;
2301 }
2302
2303 //
2304 // Get PubKey and check Monotonic Count value corresponding to the variable.
2305 //
2306 CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
2307 CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
2308 PubKey = CertBlock->PublicKey;
2309
2310 //
2311 // Update Monotonic Count value.
2312 //
2313 MonotonicCount = CertData->MonotonicCount;
2314
2315 if (!IsFirstTime) {
2316 //
2317 // 2 cases need to check here
2318 // 1. Internal PubKey variable. PubKeyIndex is always 0
2319 // 2. Other counter-based AuthVariable. Check input PubKey.
2320 //
2321 if (KeyIndex == 0) {
2322 return EFI_SECURITY_VIOLATION;
2323 }
2324 for (Index = 0; Index < mPubKeyNumber; Index++) {
2325 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {
2326 if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
2327 break;
2328 } else {
2329 return EFI_SECURITY_VIOLATION;
2330 }
2331 }
2332 }
2333 if (Index == mPubKeyNumber) {
2334 return EFI_SECURITY_VIOLATION;
2335 }
2336
2337 //
2338 // Compare the current monotonic count and ensure that it is greater than the last SetVariable
2339 // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
2340 //
2341 if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {
2342 //
2343 // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
2344 //
2345 return EFI_SECURITY_VIOLATION;
2346 }
2347 }
2348 //
2349 // Verify the certificate in Data payload.
2350 //
2351 Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
2352 if (EFI_ERROR (Status)) {
2353 return Status;
2354 }
2355
2356 //
2357 // Now, the signature has been verified!
2358 //
2359 if (IsFirstTime && !IsDeletion) {
2360 VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;
2361 VariableDataEntry.Guid = VendorGuid;
2362 VariableDataEntry.Name = VariableName;
2363
2364 //
2365 // Update public key database variable if need.
2366 //
2367 KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);
2368 if (KeyIndex == 0) {
2369 return EFI_OUT_OF_RESOURCES;
2370 }
2371 }
2372
2373 //
2374 // Verification pass.
2375 //
2376 return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);
2377 }
2378
2379 /**
2380 Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
2381
2382 @param[in] Data Pointer to original EFI_SIGNATURE_LIST.
2383 @param[in] DataSize Size of Data buffer.
2384 @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.
2385 @param[in, out] NewDataSize Size of NewData buffer.
2386
2387 **/
2388 EFI_STATUS
2389 FilterSignatureList (
2390 IN VOID *Data,
2391 IN UINTN DataSize,
2392 IN OUT VOID *NewData,
2393 IN OUT UINTN *NewDataSize
2394 )
2395 {
2396 EFI_SIGNATURE_LIST *CertList;
2397 EFI_SIGNATURE_DATA *Cert;
2398 UINTN CertCount;
2399 EFI_SIGNATURE_LIST *NewCertList;
2400 EFI_SIGNATURE_DATA *NewCert;
2401 UINTN NewCertCount;
2402 UINTN Index;
2403 UINTN Index2;
2404 UINTN Size;
2405 UINT8 *Tail;
2406 UINTN CopiedCount;
2407 UINTN SignatureListSize;
2408 BOOLEAN IsNewCert;
2409 UINT8 *TempData;
2410 UINTN TempDataSize;
2411 EFI_STATUS Status;
2412
2413 if (*NewDataSize == 0) {
2414 return EFI_SUCCESS;
2415 }
2416
2417 TempDataSize = *NewDataSize;
2418 Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);
2419 if (EFI_ERROR (Status)) {
2420 return EFI_OUT_OF_RESOURCES;
2421 }
2422
2423 Tail = TempData;
2424
2425 NewCertList = (EFI_SIGNATURE_LIST *) NewData;
2426 while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {
2427 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
2428 NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
2429
2430 CopiedCount = 0;
2431 for (Index = 0; Index < NewCertCount; Index++) {
2432 IsNewCert = TRUE;
2433
2434 Size = DataSize;
2435 CertList = (EFI_SIGNATURE_LIST *) Data;
2436 while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
2437 if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
2438 (CertList->SignatureSize == NewCertList->SignatureSize)) {
2439 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2440 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2441 for (Index2 = 0; Index2 < CertCount; Index2++) {
2442 //
2443 // Iterate each Signature Data in this Signature List.
2444 //
2445 if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
2446 IsNewCert = FALSE;
2447 break;
2448 }
2449 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
2450 }
2451 }
2452
2453 if (!IsNewCert) {
2454 break;
2455 }
2456 Size -= CertList->SignatureListSize;
2457 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2458 }
2459
2460 if (IsNewCert) {
2461 //
2462 // New EFI_SIGNATURE_DATA, keep it.
2463 //
2464 if (CopiedCount == 0) {
2465 //
2466 // Copy EFI_SIGNATURE_LIST header for only once.
2467 //
2468 CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
2469 Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
2470 }
2471
2472 CopyMem (Tail, NewCert, NewCertList->SignatureSize);
2473 Tail += NewCertList->SignatureSize;
2474 CopiedCount++;
2475 }
2476
2477 NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
2478 }
2479
2480 //
2481 // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
2482 //
2483 if (CopiedCount != 0) {
2484 SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
2485 CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
2486 CertList->SignatureListSize = (UINT32) SignatureListSize;
2487 }
2488
2489 *NewDataSize -= NewCertList->SignatureListSize;
2490 NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
2491 }
2492
2493 TempDataSize = (Tail - (UINT8 *) TempData);
2494
2495 CopyMem (NewData, TempData, TempDataSize);
2496 *NewDataSize = TempDataSize;
2497
2498 return EFI_SUCCESS;
2499 }
2500
2501 /**
2502 Compare two EFI_TIME data.
2503
2504
2505 @param FirstTime A pointer to the first EFI_TIME data.
2506 @param SecondTime A pointer to the second EFI_TIME data.
2507
2508 @retval TRUE The FirstTime is not later than the SecondTime.
2509 @retval FALSE The FirstTime is later than the SecondTime.
2510
2511 **/
2512 BOOLEAN
2513 AuthServiceInternalCompareTimeStamp (
2514 IN EFI_TIME *FirstTime,
2515 IN EFI_TIME *SecondTime
2516 )
2517 {
2518 if (FirstTime->Year != SecondTime->Year) {
2519 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
2520 } else if (FirstTime->Month != SecondTime->Month) {
2521 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
2522 } else if (FirstTime->Day != SecondTime->Day) {
2523 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
2524 } else if (FirstTime->Hour != SecondTime->Hour) {
2525 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
2526 } else if (FirstTime->Minute != SecondTime->Minute) {
2527 return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
2528 }
2529
2530 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
2531 }
2532
2533 /**
2534 Find matching signer's certificates for common authenticated variable
2535 by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
2536
2537 The data format of "certdb" or "certdbv":
2538 //
2539 // UINT32 CertDbListSize;
2540 // /// AUTH_CERT_DB_DATA Certs1[];
2541 // /// AUTH_CERT_DB_DATA Certs2[];
2542 // /// ...
2543 // /// AUTH_CERT_DB_DATA Certsn[];
2544 //
2545
2546 @param[in] VariableName Name of authenticated Variable.
2547 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2548 @param[in] Data Pointer to variable "certdb" or "certdbv".
2549 @param[in] DataSize Size of variable "certdb" or "certdbv".
2550 @param[out] CertOffset Offset of matching CertData, from starting of Data.
2551 @param[out] CertDataSize Length of CertData in bytes.
2552 @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
2553 starting of Data.
2554 @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
2555
2556 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2557 @retval EFI_NOT_FOUND Fail to find matching certs.
2558 @retval EFI_SUCCESS Find matching certs and output parameters.
2559
2560 **/
2561 EFI_STATUS
2562 FindCertsFromDb (
2563 IN CHAR16 *VariableName,
2564 IN EFI_GUID *VendorGuid,
2565 IN UINT8 *Data,
2566 IN UINTN DataSize,
2567 OUT UINT32 *CertOffset, OPTIONAL
2568 OUT UINT32 *CertDataSize, OPTIONAL
2569 OUT UINT32 *CertNodeOffset,OPTIONAL
2570 OUT UINT32 *CertNodeSize OPTIONAL
2571 )
2572 {
2573 UINT32 Offset;
2574 AUTH_CERT_DB_DATA *Ptr;
2575 UINT32 CertSize;
2576 UINT32 NameSize;
2577 UINT32 NodeSize;
2578 UINT32 CertDbListSize;
2579
2580 if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
2581 return EFI_INVALID_PARAMETER;
2582 }
2583
2584 //
2585 // Check whether DataSize matches recorded CertDbListSize.
2586 //
2587 if (DataSize < sizeof (UINT32)) {
2588 return EFI_INVALID_PARAMETER;
2589 }
2590
2591 CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
2592
2593 if (CertDbListSize != (UINT32) DataSize) {
2594 return EFI_INVALID_PARAMETER;
2595 }
2596
2597 Offset = sizeof (UINT32);
2598
2599 //
2600 // Get corresponding certificates by VendorGuid and VariableName.
2601 //
2602 while (Offset < (UINT32) DataSize) {
2603 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
2604 //
2605 // Check whether VendorGuid matches.
2606 //
2607 if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
2608 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
2609 NameSize = ReadUnaligned32 (&Ptr->NameSize);
2610 CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
2611
2612 if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
2613 sizeof (CHAR16) * NameSize) {
2614 return EFI_INVALID_PARAMETER;
2615 }
2616
2617 Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
2618 //
2619 // Check whether VariableName matches.
2620 //
2621 if ((NameSize == StrLen (VariableName)) &&
2622 (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
2623 Offset = Offset + NameSize * sizeof (CHAR16);
2624
2625 if (CertOffset != NULL) {
2626 *CertOffset = Offset;
2627 }
2628
2629 if (CertDataSize != NULL) {
2630 *CertDataSize = CertSize;
2631 }
2632
2633 if (CertNodeOffset != NULL) {
2634 *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
2635 }
2636
2637 if (CertNodeSize != NULL) {
2638 *CertNodeSize = NodeSize;
2639 }
2640
2641 return EFI_SUCCESS;
2642 } else {
2643 Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
2644 }
2645 } else {
2646 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
2647 Offset = Offset + NodeSize;
2648 }
2649 }
2650
2651 return EFI_NOT_FOUND;
2652 }
2653
2654 /**
2655 Retrieve signer's certificates for common authenticated variable
2656 by corresponding VariableName and VendorGuid from "certdb"
2657 or "certdbv" according to authenticated variable attributes.
2658
2659 @param[in] VariableName Name of authenticated Variable.
2660 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2661 @param[in] Attributes Attributes of authenticated variable.
2662 @param[out] CertData Pointer to signer's certificates.
2663 @param[out] CertDataSize Length of CertData in bytes.
2664
2665 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2666 @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
2667 @retval EFI_SUCCESS Get signer's certificates successfully.
2668
2669 **/
2670 EFI_STATUS
2671 GetCertsFromDb (
2672 IN CHAR16 *VariableName,
2673 IN EFI_GUID *VendorGuid,
2674 IN UINT32 Attributes,
2675 OUT UINT8 **CertData,
2676 OUT UINT32 *CertDataSize
2677 )
2678 {
2679 EFI_STATUS Status;
2680 UINT8 *Data;
2681 UINTN DataSize;
2682 UINT32 CertOffset;
2683 CHAR16 *DbName;
2684
2685 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
2686 return EFI_INVALID_PARAMETER;
2687 }
2688
2689
2690 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2691 //
2692 // Get variable "certdb".
2693 //
2694 DbName = EFI_CERT_DB_NAME;
2695 } else {
2696 //
2697 // Get variable "certdbv".
2698 //
2699 DbName = EFI_CERT_DB_VOLATILE_NAME;
2700 }
2701
2702 //
2703 // Get variable "certdb" or "certdbv".
2704 //
2705 Status = AuthServiceInternalFindVariable (
2706 DbName,
2707 &gEfiCertDbGuid,
2708 (VOID **) &Data,
2709 &DataSize
2710 );
2711 if (EFI_ERROR (Status)) {
2712 return Status;
2713 }
2714
2715 if ((DataSize == 0) || (Data == NULL)) {
2716 ASSERT (FALSE);
2717 return EFI_NOT_FOUND;
2718 }
2719
2720 Status = FindCertsFromDb (
2721 VariableName,
2722 VendorGuid,
2723 Data,
2724 DataSize,
2725 &CertOffset,
2726 CertDataSize,
2727 NULL,
2728 NULL
2729 );
2730
2731 if (EFI_ERROR (Status)) {
2732 return Status;
2733 }
2734
2735 *CertData = Data + CertOffset;
2736 return EFI_SUCCESS;
2737 }
2738
2739 /**
2740 Delete matching signer's certificates when deleting common authenticated
2741 variable by corresponding VariableName and VendorGuid from "certdb" or
2742 "certdbv" according to authenticated variable attributes.
2743
2744 @param[in] VariableName Name of authenticated Variable.
2745 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2746 @param[in] Attributes Attributes of authenticated variable.
2747
2748 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2749 @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
2750 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
2751 @retval EFI_SUCCESS The operation is completed successfully.
2752
2753 **/
2754 EFI_STATUS
2755 DeleteCertsFromDb (
2756 IN CHAR16 *VariableName,
2757 IN EFI_GUID *VendorGuid,
2758 IN UINT32 Attributes
2759 )
2760 {
2761 EFI_STATUS Status;
2762 UINT8 *Data;
2763 UINTN DataSize;
2764 UINT32 VarAttr;
2765 UINT32 CertNodeOffset;
2766 UINT32 CertNodeSize;
2767 UINT8 *NewCertDb;
2768 UINT32 NewCertDbSize;
2769 CHAR16 *DbName;
2770
2771 if ((VariableName == NULL) || (VendorGuid == NULL)) {
2772 return EFI_INVALID_PARAMETER;
2773 }
2774
2775 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2776 //
2777 // Get variable "certdb".
2778 //
2779 DbName = EFI_CERT_DB_NAME;
2780 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2781 } else {
2782 //
2783 // Get variable "certdbv".
2784 //
2785 DbName = EFI_CERT_DB_VOLATILE_NAME;
2786 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2787 }
2788
2789 Status = AuthServiceInternalFindVariable (
2790 DbName,
2791 &gEfiCertDbGuid,
2792 (VOID **) &Data,
2793 &DataSize
2794 );
2795
2796 if (EFI_ERROR (Status)) {
2797 return Status;
2798 }
2799
2800 if ((DataSize == 0) || (Data == NULL)) {
2801 ASSERT (FALSE);
2802 return EFI_NOT_FOUND;
2803 }
2804
2805 if (DataSize == sizeof (UINT32)) {
2806 //
2807 // There is no certs in "certdb" or "certdbv".
2808 //
2809 return EFI_SUCCESS;
2810 }
2811
2812 //
2813 // Get corresponding cert node from "certdb" or "certdbv".
2814 //
2815 Status = FindCertsFromDb (
2816 VariableName,
2817 VendorGuid,
2818 Data,
2819 DataSize,
2820 NULL,
2821 NULL,
2822 &CertNodeOffset,
2823 &CertNodeSize
2824 );
2825
2826 if (EFI_ERROR (Status)) {
2827 return Status;
2828 }
2829
2830 if (DataSize < (CertNodeOffset + CertNodeSize)) {
2831 return EFI_NOT_FOUND;
2832 }
2833
2834 //
2835 // Construct new data content of variable "certdb" or "certdbv".
2836 //
2837 NewCertDbSize = (UINT32) DataSize - CertNodeSize;
2838 NewCertDb = (UINT8*) mCertDbStore;
2839
2840 //
2841 // Copy the DB entries before deleting node.
2842 //
2843 CopyMem (NewCertDb, Data, CertNodeOffset);
2844 //
2845 // Update CertDbListSize.
2846 //
2847 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
2848 //
2849 // Copy the DB entries after deleting node.
2850 //
2851 if (DataSize > (CertNodeOffset + CertNodeSize)) {
2852 CopyMem (
2853 NewCertDb + CertNodeOffset,
2854 Data + CertNodeOffset + CertNodeSize,
2855 DataSize - CertNodeOffset - CertNodeSize
2856 );
2857 }
2858
2859 //
2860 // Set "certdb" or "certdbv".
2861 //
2862 Status = AuthServiceInternalUpdateVariable (
2863 DbName,
2864 &gEfiCertDbGuid,
2865 NewCertDb,
2866 NewCertDbSize,
2867 VarAttr
2868 );
2869
2870 return Status;
2871 }
2872
2873 /**
2874 Insert signer's certificates for common authenticated variable with VariableName
2875 and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
2876 time based authenticated variable attributes.
2877
2878 @param[in] VariableName Name of authenticated Variable.
2879 @param[in] VendorGuid Vendor GUID of authenticated Variable.
2880 @param[in] Attributes Attributes of authenticated variable.
2881 @param[in] CertData Pointer to signer's certificates.
2882 @param[in] CertDataSize Length of CertData in bytes.
2883
2884 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
2885 @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
2886 and VendorGuid already exists.
2887 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
2888 @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
2889
2890 **/
2891 EFI_STATUS
2892 InsertCertsToDb (
2893 IN CHAR16 *VariableName,
2894 IN EFI_GUID *VendorGuid,
2895 IN UINT32 Attributes,
2896 IN UINT8 *CertData,
2897 IN UINTN CertDataSize
2898 )
2899 {
2900 EFI_STATUS Status;
2901 UINT8 *Data;
2902 UINTN DataSize;
2903 UINT32 VarAttr;
2904 UINT8 *NewCertDb;
2905 UINT32 NewCertDbSize;
2906 UINT32 CertNodeSize;
2907 UINT32 NameSize;
2908 AUTH_CERT_DB_DATA *Ptr;
2909 CHAR16 *DbName;
2910
2911 if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
2912 return EFI_INVALID_PARAMETER;
2913 }
2914
2915 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2916 //
2917 // Get variable "certdb".
2918 //
2919 DbName = EFI_CERT_DB_NAME;
2920 VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2921 } else {
2922 //
2923 // Get variable "certdbv".
2924 //
2925 DbName = EFI_CERT_DB_VOLATILE_NAME;
2926 VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2927 }
2928
2929 //
2930 // Get variable "certdb" or "certdbv".
2931 //
2932 Status = AuthServiceInternalFindVariable (
2933 DbName,
2934 &gEfiCertDbGuid,
2935 (VOID **) &Data,
2936 &DataSize
2937 );
2938 if (EFI_ERROR (Status)) {
2939 return Status;
2940 }
2941
2942 if ((DataSize == 0) || (Data == NULL)) {
2943 ASSERT (FALSE);
2944 return EFI_NOT_FOUND;
2945 }
2946
2947 //
2948 // Find whether matching cert node already exists in "certdb" or "certdbv".
2949 // If yes return error.
2950 //
2951 Status = FindCertsFromDb (
2952 VariableName,
2953 VendorGuid,
2954 Data,
2955 DataSize,
2956 NULL,
2957 NULL,
2958 NULL,
2959 NULL
2960 );
2961
2962 if (!EFI_ERROR (Status)) {
2963 ASSERT (FALSE);
2964 return EFI_ACCESS_DENIED;
2965 }
2966
2967 //
2968 // Construct new data content of variable "certdb" or "certdbv".
2969 //
2970 NameSize = (UINT32) StrLen (VariableName);
2971 CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
2972 NewCertDbSize = (UINT32) DataSize + CertNodeSize;
2973 if (NewCertDbSize > mMaxCertDbSize) {
2974 return EFI_OUT_OF_RESOURCES;
2975 }
2976 NewCertDb = (UINT8*) mCertDbStore;
2977
2978 //
2979 // Copy the DB entries before inserting node.
2980 //
2981 CopyMem (NewCertDb, Data, DataSize);
2982 //
2983 // Update CertDbListSize.
2984 //
2985 CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
2986 //
2987 // Construct new cert node.
2988 //
2989 Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
2990 CopyGuid (&Ptr->VendorGuid, VendorGuid);
2991 CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
2992 CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
2993 CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
2994
2995 CopyMem (
2996 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
2997 VariableName,
2998 NameSize * sizeof (CHAR16)
2999 );
3000
3001 CopyMem (
3002 (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
3003 CertData,
3004 CertDataSize
3005 );
3006
3007 //
3008 // Set "certdb" or "certdbv".
3009 //
3010 Status = AuthServiceInternalUpdateVariable (
3011 DbName,
3012 &gEfiCertDbGuid,
3013 NewCertDb,
3014 NewCertDbSize,
3015 VarAttr
3016 );
3017
3018 return Status;
3019 }
3020
3021 /**
3022 Clean up signer's certificates for common authenticated variable
3023 by corresponding VariableName and VendorGuid from "certdb".
3024 System may break down during Timebased Variable update & certdb update,
3025 make them inconsistent, this function is called in AuthVariable Init
3026 to ensure consistency.
3027
3028 @retval EFI_NOT_FOUND Fail to find variable "certdb".
3029 @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
3030 @retval EFI_SUCCESS The operation is completed successfully.
3031
3032 **/
3033 EFI_STATUS
3034 CleanCertsFromDb (
3035 VOID
3036 )
3037 {
3038 UINT32 Offset;
3039 AUTH_CERT_DB_DATA *Ptr;
3040 UINT32 NameSize;
3041 UINT32 NodeSize;
3042 CHAR16 *VariableName;
3043 EFI_STATUS Status;
3044 BOOLEAN CertCleaned;
3045 UINT8 *Data;
3046 UINTN DataSize;
3047 EFI_GUID AuthVarGuid;
3048 AUTH_VARIABLE_INFO AuthVariableInfo;
3049
3050 Status = EFI_SUCCESS;
3051
3052 //
3053 // Get corresponding certificates by VendorGuid and VariableName.
3054 //
3055 do {
3056 CertCleaned = FALSE;
3057
3058 //
3059 // Get latest variable "certdb"
3060 //
3061 Status = AuthServiceInternalFindVariable (
3062 EFI_CERT_DB_NAME,
3063 &gEfiCertDbGuid,
3064 (VOID **) &Data,
3065 &DataSize
3066 );
3067 if (EFI_ERROR (Status)) {
3068 return Status;
3069 }
3070
3071 if ((DataSize == 0) || (Data == NULL)) {
3072 ASSERT (FALSE);
3073 return EFI_NOT_FOUND;
3074 }
3075
3076 Offset = sizeof (UINT32);
3077
3078 while (Offset < (UINT32) DataSize) {
3079 Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
3080 NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
3081 NameSize = ReadUnaligned32 (&Ptr->NameSize);
3082
3083 //
3084 // Get VarName tailed with '\0'
3085 //
3086 VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));
3087 if (VariableName == NULL) {
3088 return EFI_OUT_OF_RESOURCES;
3089 }
3090 CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));
3091 //
3092 // Keep VarGuid aligned
3093 //
3094 CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));
3095
3096 //
3097 // Find corresponding time auth variable
3098 //
3099 ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
3100 Status = mAuthVarLibContextIn->FindVariable (
3101 VariableName,
3102 &AuthVarGuid,
3103 &AuthVariableInfo
3104 );
3105
3106 if (EFI_ERROR(Status)) {
3107 Status = DeleteCertsFromDb(
3108 VariableName,
3109 &AuthVarGuid,
3110 AuthVariableInfo.Attributes
3111 );
3112 CertCleaned = TRUE;
3113 DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
3114 FreePool(VariableName);
3115 break;
3116 }
3117
3118 FreePool(VariableName);
3119 Offset = Offset + NodeSize;
3120 }
3121 } while (CertCleaned);
3122
3123 return Status;
3124 }
3125
3126 /**
3127 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
3128
3129 Caution: This function may receive untrusted input.
3130 This function may be invoked in SMM mode, and datasize and data are external input.
3131 This function will do basic validation, before parse the data.
3132 This function will parse the authentication carefully to avoid security issues, like
3133 buffer overflow, integer overflow.
3134
3135 @param[in] VariableName Name of Variable to be found.
3136 @param[in] VendorGuid Variable vendor GUID.
3137 @param[in] Data Data pointer.
3138 @param[in] DataSize Size of Data found. If size is less than the
3139 data, this value contains the required size.
3140 @param[in] Attributes Attribute value of the variable.
3141 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
3142 @param[in] OrgTimeStamp Pointer to original time stamp,
3143 original variable is not found if NULL.
3144 @param[out] VarPayloadPtr Pointer to variable payload address.
3145 @param[out] VarPayloadSize Pointer to variable payload size.
3146
3147 @retval EFI_INVALID_PARAMETER Invalid parameter.
3148 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
3149 check carried out by the firmware.
3150 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
3151 of resources.
3152 @retval EFI_SUCCESS Variable pass validation successfully.
3153
3154 **/
3155 EFI_STATUS
3156 VerifyTimeBasedPayload (
3157 IN CHAR16 *VariableName,
3158 IN EFI_GUID *VendorGuid,
3159 IN VOID *Data,
3160 IN UINTN DataSize,
3161 IN UINT32 Attributes,
3162 IN AUTHVAR_TYPE AuthVarType,
3163 IN EFI_TIME *OrgTimeStamp,
3164 OUT UINT8 **VarPayloadPtr,
3165 OUT UINTN *VarPayloadSize
3166 )
3167 {
3168 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
3169 UINT8 *SigData;
3170 UINT32 SigDataSize;
3171 UINT8 *PayloadPtr;
3172 UINTN PayloadSize;
3173 UINT32 Attr;
3174 BOOLEAN VerifyStatus;
3175 EFI_STATUS Status;
3176 EFI_SIGNATURE_LIST *CertList;
3177 EFI_SIGNATURE_DATA *Cert;
3178 UINTN Index;
3179 UINTN CertCount;
3180 UINT32 KekDataSize;
3181 UINT8 *NewData;
3182 UINTN NewDataSize;
3183 UINT8 *Buffer;
3184 UINTN Length;
3185 UINT8 *RootCert;
3186 UINTN RootCertSize;
3187 UINT8 *SignerCerts;
3188 UINTN CertStackSize;
3189 UINT8 *CertsInCertDb;
3190 UINT32 CertsSizeinDb;
3191
3192 VerifyStatus = FALSE;
3193 CertData = NULL;
3194 NewData = NULL;
3195 Attr = Attributes;
3196 SignerCerts = NULL;
3197 RootCert = NULL;
3198 CertsInCertDb = NULL;
3199
3200 //
3201 // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
3202 // set, then the Data buffer shall begin with an instance of a complete (and serialized)
3203 // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
3204 // variable value and DataSize shall reflect the combined size of the descriptor and the new
3205 // variable value. The authentication descriptor is not part of the variable data and is not
3206 // returned by subsequent calls to GetVariable().
3207 //
3208 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
3209
3210 //
3211 // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
3212 // TimeStamp value are set to zero.
3213 //
3214 if ((CertData->TimeStamp.Pad1 != 0) ||
3215 (CertData->TimeStamp.Nanosecond != 0) ||
3216 (CertData->TimeStamp.TimeZone != 0) ||
3217 (CertData->TimeStamp.Daylight != 0) ||
3218 (CertData->TimeStamp.Pad2 != 0)) {
3219 return EFI_SECURITY_VIOLATION;
3220 }
3221
3222 if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
3223 if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {
3224 //
3225 // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
3226 //
3227 return EFI_SECURITY_VIOLATION;
3228 }
3229 }
3230
3231 //
3232 // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
3233 // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
3234 //
3235 if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
3236 !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
3237 //
3238 // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
3239 //
3240 return EFI_SECURITY_VIOLATION;
3241 }
3242
3243 //
3244 // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3245 // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
3246 //
3247 SigData = CertData->AuthInfo.CertData;
3248 SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
3249
3250 //
3251 // Find out the new data payload which follows Pkcs7 SignedData directly.
3252 //
3253 PayloadPtr = SigData + SigDataSize;
3254 PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
3255
3256 //
3257 // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
3258 // parameters of the SetVariable() call and the TimeStamp component of the
3259 // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
3260 // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
3261 //
3262 NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
3263 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
3264
3265 //
3266 // Here is to reuse scratch data area(at the end of volatile variable store)
3267 // to reduce SMRAM consumption for SMM variable driver.
3268 // The scratch buffer is enough to hold the serialized data and safe to use,
3269 // because it is only used at here to do verification temporarily first
3270 // and then used in UpdateVariable() for a time based auth variable set.
3271 //
3272 Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);
3273 if (EFI_ERROR (Status)) {
3274 return EFI_OUT_OF_RESOURCES;
3275 }
3276
3277 Buffer = NewData;
3278 Length = StrLen (VariableName) * sizeof (CHAR16);
3279 CopyMem (Buffer, VariableName, Length);
3280 Buffer += Length;
3281
3282 Length = sizeof (EFI_GUID);
3283 CopyMem (Buffer, VendorGuid, Length);
3284 Buffer += Length;
3285
3286 Length = sizeof (UINT32);
3287 CopyMem (Buffer, &Attr, Length);
3288 Buffer += Length;
3289
3290 Length = sizeof (EFI_TIME);
3291 CopyMem (Buffer, &CertData->TimeStamp, Length);
3292 Buffer += Length;
3293
3294 CopyMem (Buffer, PayloadPtr, PayloadSize);
3295
3296 if (AuthVarType == AuthVarTypePk) {
3297 //
3298 // Verify that the signature has been made with the current Platform Key (no chaining for PK).
3299 // First, get signer's certificates from SignedData.
3300 //
3301 VerifyStatus = Pkcs7GetSigners (
3302 SigData,
3303 SigDataSize,
3304 &SignerCerts,
3305 &CertStackSize,
3306 &RootCert,
3307 &RootCertSize
3308 );
3309 if (!VerifyStatus) {
3310 goto Exit;
3311 }
3312
3313 //
3314 // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
3315 // in SignedData. If not, return error immediately.
3316 //
3317 Status = AuthServiceInternalFindVariable (
3318 EFI_PLATFORM_KEY_NAME,
3319 &gEfiGlobalVariableGuid,
3320 &Data,
3321 &DataSize
3322 );
3323 if (EFI_ERROR (Status)) {
3324 VerifyStatus = FALSE;
3325 goto Exit;
3326 }
3327 CertList = (EFI_SIGNATURE_LIST *) Data;
3328 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
3329 if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
3330 (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {
3331 VerifyStatus = FALSE;
3332 goto Exit;
3333 }
3334
3335 //
3336 // Verify Pkcs7 SignedData via Pkcs7Verify library.
3337 //
3338 VerifyStatus = Pkcs7Verify (
3339 SigData,
3340 SigDataSize,
3341 RootCert,
3342 RootCertSize,
3343 NewData,
3344 NewDataSize
3345 );
3346
3347 } else if (AuthVarType == AuthVarTypeKek) {
3348
3349 //
3350 // Get KEK database from variable.
3351 //
3352 Status = AuthServiceInternalFindVariable (
3353 EFI_KEY_EXCHANGE_KEY_NAME,
3354 &gEfiGlobalVariableGuid,
3355 &Data,
3356 &DataSize
3357 );
3358 if (EFI_ERROR (Status)) {
3359 return Status;
3360 }
3361
3362 //
3363 // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
3364 //
3365 KekDataSize = (UINT32) DataSize;
3366 CertList = (EFI_SIGNATURE_LIST *) Data;
3367 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
3368 if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
3369 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
3370 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
3371 for (Index = 0; Index < CertCount; Index++) {
3372 //
3373 // Iterate each Signature Data Node within this CertList for a verify
3374 //
3375 RootCert = Cert->SignatureData;
3376 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
3377
3378 //
3379 // Verify Pkcs7 SignedData via Pkcs7Verify library.
3380 //
3381 VerifyStatus = Pkcs7Verify (
3382 SigData,
3383 SigDataSize,
3384 RootCert,
3385 RootCertSize,
3386 NewData,
3387 NewDataSize
3388 );
3389 if (VerifyStatus) {
3390 goto Exit;
3391 }
3392 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
3393 }
3394 }
3395 KekDataSize -= CertList->SignatureListSize;
3396 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
3397 }
3398 } else if (AuthVarType == AuthVarTypePriv) {
3399
3400 //
3401 // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
3402 // Get signer's certificates from SignedData.
3403 //
3404 VerifyStatus = Pkcs7GetSigners (
3405 SigData,
3406 SigDataSize,
3407 &SignerCerts,
3408 &CertStackSize,
3409 &RootCert,
3410 &RootCertSize
3411 );
3412 if (!VerifyStatus) {
3413 goto Exit;
3414 }
3415
3416 //
3417 // Get previously stored signer's certificates from certdb or certdbv for existing
3418 // variable. Check whether they are identical with signer's certificates
3419 // in SignedData. If not, return error immediately.
3420 //
3421 if (OrgTimeStamp != NULL) {
3422 VerifyStatus = FALSE;
3423
3424 Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);
3425 if (EFI_ERROR (Status)) {
3426 goto Exit;
3427 }
3428
3429 if ((CertStackSize != CertsSizeinDb) ||
3430 (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
3431 goto Exit;
3432 }
3433 }
3434
3435 VerifyStatus = Pkcs7Verify (
3436 SigData,
3437 SigDataSize,
3438 RootCert,
3439 RootCertSize,
3440 NewData,
3441 NewDataSize
3442 );
3443 if (!VerifyStatus) {
3444 goto Exit;
3445 }
3446
3447 if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
3448 //
3449 // Insert signer's certificates when adding a new common authenticated variable.
3450 //
3451 Status = InsertCertsToDb (VariableName, VendorGuid, Attributes, SignerCerts, CertStackSize);
3452 if (EFI_ERROR (Status)) {
3453 VerifyStatus = FALSE;
3454 goto Exit;
3455 }
3456 }
3457 } else if (AuthVarType == AuthVarTypePayload) {
3458 CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;
3459 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
3460 RootCert = Cert->SignatureData;
3461 RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
3462 //
3463 // Verify Pkcs7 SignedData via Pkcs7Verify library.
3464 //
3465 VerifyStatus = Pkcs7Verify (
3466 SigData,
3467 SigDataSize,
3468 RootCert,
3469 RootCertSize,
3470 NewData,
3471 NewDataSize
3472 );
3473 } else {
3474 return EFI_SECURITY_VIOLATION;
3475 }
3476
3477 Exit:
3478
3479 if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {
3480 Pkcs7FreeSigners (RootCert);
3481 Pkcs7FreeSigners (SignerCerts);
3482 }
3483
3484 if (!VerifyStatus) {
3485 return EFI_SECURITY_VIOLATION;
3486 }
3487
3488 Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
3489 if (EFI_ERROR (Status)) {
3490 return Status;
3491 }
3492
3493 *VarPayloadPtr = PayloadPtr;
3494 *VarPayloadSize = PayloadSize;
3495
3496 return EFI_SUCCESS;
3497 }
3498
3499 /**
3500 Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
3501
3502 Caution: This function may receive untrusted input.
3503 This function may be invoked in SMM mode, and datasize and data are external input.
3504 This function will do basic validation, before parse the data.
3505 This function will parse the authentication carefully to avoid security issues, like
3506 buffer overflow, integer overflow.
3507
3508 @param[in] VariableName Name of Variable to be found.
3509 @param[in] VendorGuid Variable vendor GUID.
3510 @param[in] Data Data pointer.
3511 @param[in] DataSize Size of Data found. If size is less than the
3512 data, this value contains the required size.
3513 @param[in] Attributes Attribute value of the variable.
3514 @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
3515 @param[out] VarDel Delete the variable or not.
3516
3517 @retval EFI_INVALID_PARAMETER Invalid parameter.
3518 @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
3519 check carried out by the firmware.
3520 @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
3521 of resources.
3522 @retval EFI_SUCCESS Variable pass validation successfully.
3523
3524 **/
3525 EFI_STATUS
3526 VerifyTimeBasedPayloadAndUpdate (
3527 IN CHAR16 *VariableName,
3528 IN EFI_GUID *VendorGuid,
3529 IN VOID *Data,
3530 IN UINTN DataSize,
3531 IN UINT32 Attributes,
3532 IN AUTHVAR_TYPE AuthVarType,
3533 OUT BOOLEAN *VarDel
3534 )
3535 {
3536 EFI_STATUS Status;
3537 EFI_STATUS FindStatus;
3538 UINT8 *PayloadPtr;
3539 UINTN PayloadSize;
3540 EFI_VARIABLE_AUTHENTICATION_2 *CertData;
3541 AUTH_VARIABLE_INFO OrgVariableInfo;
3542 BOOLEAN IsDel;
3543
3544 ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
3545 FindStatus = mAuthVarLibContextIn->FindVariable (
3546 VariableName,
3547 VendorGuid,
3548 &OrgVariableInfo
3549 );
3550
3551 Status = VerifyTimeBasedPayload (
3552 VariableName,
3553 VendorGuid,
3554 Data,
3555 DataSize,
3556 Attributes,
3557 AuthVarType,
3558 (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,
3559 &PayloadPtr,
3560 &PayloadSize
3561 );
3562 if (EFI_ERROR (Status)) {
3563 return Status;
3564 }
3565
3566 if (!EFI_ERROR(FindStatus)
3567 && (PayloadSize == 0)
3568 && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
3569 IsDel = TRUE;
3570 } else {
3571 IsDel = FALSE;
3572 }
3573
3574 CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
3575
3576 //
3577 // Final step: Update/Append Variable if it pass Pkcs7Verify
3578 //
3579 Status = AuthServiceInternalUpdateVariableWithTimeStamp (
3580 VariableName,
3581 VendorGuid,
3582 PayloadPtr,
3583 PayloadSize,
3584 Attributes,
3585 &CertData->TimeStamp
3586 );
3587
3588 //
3589 // Delete signer's certificates when delete the common authenticated variable.
3590 //
3591 if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {
3592 Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
3593 }
3594
3595 if (VarDel != NULL) {
3596 if (IsDel && !EFI_ERROR(Status)) {
3597 *VarDel = TRUE;
3598 } else {
3599 *VarDel = FALSE;
3600 }
3601 }
3602
3603 return Status;
3604 }