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