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