1 /** @file
2   Implement authentication services for the authenticated variable
3   service in UEFI2.2.
4 
5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "Variable.h"
17 #include "AuthService.h"
18 
19 ///
20 /// Global database array for scratch
21 ///
22 UINT32   mPubKeyNumber;
23 UINT32   mPlatformMode;
24 EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
25 //
26 // Public Exponent of RSA Key.
27 //
28 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
29 
30 /**
31   Initializes for authenticated varibale service.
32 
33   @retval EFI_SUCCESS           The function successfully executed.
34   @retval EFI_OUT_OF_RESOURCES  Failed to allocate enough memory resources.
35 
36 **/
37 EFI_STATUS
AutenticatedVariableServiceInitialize(VOID)38 AutenticatedVariableServiceInitialize (
39   VOID
40   )
41 {
42   EFI_STATUS                        Status;
43   VARIABLE_POINTER_TRACK            Variable;
44   UINT8                             VarValue;
45   UINT32                            VarAttr;
46   UINTN                             DataSize;
47   UINTN                             CtxSize;
48   AUTHENTICATED_VARIABLE_HEADER     VariableHeader;
49   BOOLEAN                           Valid;
50 
51   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
52 
53   mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;
54   mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical]     = &gEfiCertRsa2048Sha256Guid;
55   mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;
56 
57   //
58   // Initialize hash context.
59   //
60   CtxSize   = Sha256GetContextSize ();
61   mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);
62   ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);
63   //
64   // Check "AuthVarKeyDatabase" variable's existence.
65   // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
66   //
67   Status = FindVariable (
68              mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
69              &gEfiAuthenticatedVariableGuid,
70              &Variable,
71              &mVariableModuleGlobal->VariableGlobal[Physical],
72              mVariableModuleGlobal->FvbInstance
73              );
74 
75   if (Variable.CurrPtr == 0x0) {
76     VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
77     VarValue      = 0;
78     mPubKeyNumber = 0;
79     Status        = UpdateVariable (
80                       mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
81                       &gEfiAuthenticatedVariableGuid,
82                       &VarValue,
83                       sizeof(UINT8),
84                       VarAttr,
85                       0,
86                       0,
87                       FALSE,
88                       mVariableModuleGlobal,
89                       &Variable
90                       );
91     if (EFI_ERROR (Status)) {
92       return Status;
93     }
94   } else {
95     //
96     // Load database in global variable for cache.
97     //
98     Valid = IsValidVariableHeader (
99               Variable.CurrPtr,
100               Variable.Volatile,
101               &mVariableModuleGlobal->VariableGlobal[Physical],
102               mVariableModuleGlobal->FvbInstance,
103               &VariableHeader
104               );
105     ASSERT (Valid);
106 
107     DataSize  = DataSizeOfVariable (&VariableHeader);
108     ASSERT (DataSize <= MAX_KEYDB_SIZE);
109     GetVariableDataPtr (
110       Variable.CurrPtr,
111       Variable.Volatile,
112       &mVariableModuleGlobal->VariableGlobal[Physical],
113       mVariableModuleGlobal->FvbInstance,
114       (CHAR16 *) mVariableModuleGlobal->PubKeyStore
115       );
116 
117     mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
118   }
119   //
120   // Check "SetupMode" variable's existence.
121   // If it doesn't exist, check PK database's existence to determine the value.
122   // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
123   //
124   Status = FindVariable (
125              mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
126              &gEfiGlobalVariableGuid,
127              &Variable,
128              &mVariableModuleGlobal->VariableGlobal[Physical],
129              mVariableModuleGlobal->FvbInstance
130              );
131 
132   if (Variable.CurrPtr == 0x0) {
133     Status = FindVariable (
134                mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY],
135                &gEfiGlobalVariableGuid,
136                &Variable,
137                &mVariableModuleGlobal->VariableGlobal[Physical],
138                mVariableModuleGlobal->FvbInstance
139                );
140     if (Variable.CurrPtr == 0x0) {
141       mPlatformMode = SETUP_MODE;
142     } else {
143       mPlatformMode = USER_MODE;
144     }
145 
146     VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
147     Status  = UpdateVariable (
148                 mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
149                 &gEfiGlobalVariableGuid,
150                 &mPlatformMode,
151                 sizeof(UINT8),
152                 VarAttr,
153                 0,
154                 0,
155                 FALSE,
156                 mVariableModuleGlobal,
157                 &Variable
158                 );
159     if (EFI_ERROR (Status)) {
160       return Status;
161     }
162   } else {
163     GetVariableDataPtr (
164       Variable.CurrPtr,
165       Variable.Volatile,
166       &mVariableModuleGlobal->VariableGlobal[Physical],
167       mVariableModuleGlobal->FvbInstance,
168       (CHAR16 *) &mPlatformMode
169       );
170   }
171   //
172   // Check "SignatureSupport" variable's existence.
173   // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
174   //
175   Status = FindVariable (
176              EFI_SIGNATURE_SUPPORT_NAME,
177              &gEfiGlobalVariableGuid,
178              &Variable,
179              &mVariableModuleGlobal->VariableGlobal[Physical],
180              mVariableModuleGlobal->FvbInstance
181              );
182 
183   if (Variable.CurrPtr == 0x0) {
184     VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
185     Status  = UpdateVariable (
186                 EFI_SIGNATURE_SUPPORT_NAME,
187                 &gEfiGlobalVariableGuid,
188                 mSignatureSupport,
189                 SIGSUPPORT_NUM * sizeof(EFI_GUID),
190                 VarAttr,
191                 0,
192                 0,
193                 FALSE,
194                 mVariableModuleGlobal,
195                 &Variable
196                 );
197   }
198 
199   return Status;
200 }
201 
202 /**
203   Add public key in store and return its index.
204 
205   @param[in]  VirtualMode             The current calling mode for this function.
206   @param[in]  Global                  The context of this Extended SAL Variable Services Class call.
207   @param[in]  PubKey                  The input pointer to Public Key data.
208 
209   @return                             The index of new added item.
210 
211 **/
212 UINT32
AddPubKeyInStore(IN BOOLEAN VirtualMode,IN ESAL_VARIABLE_GLOBAL * Global,IN UINT8 * PubKey)213 AddPubKeyInStore (
214   IN  BOOLEAN                   VirtualMode,
215   IN  ESAL_VARIABLE_GLOBAL      *Global,
216   IN  UINT8                     *PubKey
217   )
218 {
219   EFI_STATUS              Status;
220   BOOLEAN                 IsFound;
221   UINT32                  Index;
222   VARIABLE_POINTER_TRACK  Variable;
223   UINT8                   *Ptr;
224 
225   if (PubKey == NULL) {
226     return 0;
227   }
228 
229   Status = FindVariable (
230              Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
231              Global->AuthenticatedVariableGuid[VirtualMode],
232              &Variable,
233              &Global->VariableGlobal[VirtualMode],
234              Global->FvbInstance
235              );
236   ASSERT_EFI_ERROR (Status);
237   //
238   // Check whether the public key entry does exist.
239   //
240   IsFound = FALSE;
241   for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
242     if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
243       IsFound = TRUE;
244       break;
245     }
246     Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
247   }
248 
249   if (!IsFound) {
250     //
251     // Add public key in database.
252     //
253     if (mPubKeyNumber == MAX_KEY_NUM) {
254       //
255       // Notes: Database is full, need enhancement here, currently just return 0.
256       //
257       return 0;
258     }
259 
260     CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
261     Index = ++mPubKeyNumber;
262     //
263     // Update public key database variable.
264     //
265     Status = UpdateVariable (
266                Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
267                Global->AuthenticatedVariableGuid[VirtualMode],
268                Global->PubKeyStore,
269                mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
270                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
271                0,
272                0,
273                VirtualMode,
274                Global,
275                &Variable
276                );
277     ASSERT_EFI_ERROR (Status);
278   }
279 
280   return Index;
281 }
282 
283 /**
284   Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
285   Follow the steps in UEFI2.2.
286 
287   @param[in]  VirtualMode             The current calling mode for this function.
288   @param[in]  Global                  The context of this Extended SAL Variable Services Class call.
289   @param[in]  Data                    The pointer to data with AuthInfo.
290   @param[in]  DataSize                The size of Data.
291   @param[in]  PubKey                  The public key used for verification.
292 
293   @retval EFI_INVALID_PARAMETER       Invalid parameter.
294   @retval EFI_SECURITY_VIOLATION      Authentication failed.
295   @retval EFI_SUCCESS                 Authentication successful.
296 
297 **/
298 EFI_STATUS
VerifyDataPayload(IN BOOLEAN VirtualMode,IN ESAL_VARIABLE_GLOBAL * Global,IN UINT8 * Data,IN UINTN DataSize,IN UINT8 * PubKey)299 VerifyDataPayload (
300   IN  BOOLEAN                   VirtualMode,
301   IN  ESAL_VARIABLE_GLOBAL      *Global,
302   IN  UINT8                     *Data,
303   IN  UINTN                     DataSize,
304   IN  UINT8                     *PubKey
305   )
306 {
307   BOOLEAN                         Status;
308   EFI_VARIABLE_AUTHENTICATION     *CertData;
309   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
310   UINT8                           Digest[SHA256_DIGEST_SIZE];
311   VOID                            *Rsa;
312   VOID                            *HashContext;
313 
314   Rsa         = NULL;
315   CertData    = NULL;
316   CertBlock   = NULL;
317 
318   if (Data == NULL || PubKey == NULL) {
319     return EFI_INVALID_PARAMETER;
320   }
321 
322   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
323   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
324 
325   //
326   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
327   // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
328   //
329   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
330       !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])
331         ) {
332     //
333     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
334     //
335     return EFI_SECURITY_VIOLATION;
336   }
337 
338   //
339   // Hash data payload with SHA256.
340   //
341   ZeroMem (Digest, SHA256_DIGEST_SIZE);
342   HashContext = Global->HashContext[VirtualMode];
343   Status  = Sha256Init (HashContext);
344   if (!Status) {
345     goto Done;
346   }
347   Status  = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
348   if (!Status) {
349     goto Done;
350   }
351   //
352   // Hash Monotonic Count.
353   //
354   Status  = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));
355   if (!Status) {
356     goto Done;
357   }
358   Status  = Sha256Final (HashContext, Digest);
359   if (!Status) {
360     goto Done;
361   }
362   //
363   // Generate & Initialize RSA Context.
364   //
365   Rsa = RsaNew ();
366   ASSERT (Rsa != NULL);
367   //
368   // Set RSA Key Components.
369   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
370   //
371   Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
372   if (!Status) {
373     goto Done;
374   }
375   Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
376   if (!Status) {
377     goto Done;
378   }
379   //
380   // Verify the signature.
381   //
382   Status = RsaPkcs1Verify (
383              Rsa,
384              Digest,
385              SHA256_DIGEST_SIZE,
386              CertBlock->Signature,
387              EFI_CERT_TYPE_RSA2048_SHA256_SIZE
388              );
389 
390 Done:
391   if (Rsa != NULL) {
392     RsaFree (Rsa);
393   }
394   if (Status) {
395     return EFI_SUCCESS;
396   } else {
397     return EFI_SECURITY_VIOLATION;
398   }
399 }
400 
401 
402 /**
403   Update platform mode.
404 
405   @param[in]  VirtualMode             The current calling mode for this function.
406   @param[in]  Global                  The context of this Extended SAL Variable Services Class call.
407   @param[in]  Mode                    SETUP_MODE or USER_MODE.
408 
409 **/
410 VOID
UpdatePlatformMode(IN BOOLEAN VirtualMode,IN ESAL_VARIABLE_GLOBAL * Global,IN UINT32 Mode)411 UpdatePlatformMode (
412   IN  BOOLEAN                   VirtualMode,
413   IN  ESAL_VARIABLE_GLOBAL      *Global,
414   IN  UINT32                    Mode
415   )
416 {
417   EFI_STATUS              Status;
418   VARIABLE_POINTER_TRACK  Variable;
419   UINT32                  VarAttr;
420 
421   Status = FindVariable (
422              Global->VariableName[VirtualMode][VAR_SETUP_MODE],
423              Global->GlobalVariableGuid[VirtualMode],
424              &Variable,
425              &Global->VariableGlobal[VirtualMode],
426              Global->FvbInstance
427              );
428   ASSERT_EFI_ERROR (Status);
429 
430   mPlatformMode  = Mode;
431   VarAttr        = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
432   Status         = UpdateVariable (
433                      Global->VariableName[VirtualMode][VAR_SETUP_MODE],
434                      Global->GlobalVariableGuid[VirtualMode],
435                      &mPlatformMode,
436                      sizeof(UINT8),
437                      VarAttr,
438                      0,
439                      0,
440                      VirtualMode,
441                      Global,
442                      &Variable
443                      );
444   ASSERT_EFI_ERROR (Status);
445 }
446 
447 /**
448   Process variable with platform key for verification.
449 
450   @param[in]  VariableName                The name of Variable to be found.
451   @param[in]  VendorGuid                  The variable vendor GUID.
452   @param[in]  Data                        The data pointer.
453   @param[in]  DataSize                    The size of Data found. If size is less than the
454                                           data, this value contains the required size.
455   @param[in]  VirtualMode                 The current calling mode for this function.
456   @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
457   @param[in]  Variable                    The variable information which is used to keep track of variable usage.
458   @param[in]  Attributes                  The attribute value of the variable.
459   @param[in]  IsPk                        Indicates whether to process pk.
460 
461   @retval EFI_INVALID_PARAMETER           Invalid parameter.
462   @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
463                                           check carried out by the firmware.
464   @retval EFI_SUCCESS                     The variable passed validation successfully.
465 
466 **/
467 EFI_STATUS
ProcessVarWithPk(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN VOID * Data,IN UINTN DataSize,IN BOOLEAN VirtualMode,IN ESAL_VARIABLE_GLOBAL * Global,IN VARIABLE_POINTER_TRACK * Variable,IN UINT32 Attributes OPTIONAL,IN BOOLEAN IsPk)468 ProcessVarWithPk (
469   IN  CHAR16                    *VariableName,
470   IN  EFI_GUID                  *VendorGuid,
471   IN  VOID                      *Data,
472   IN  UINTN                     DataSize,
473   IN  BOOLEAN                   VirtualMode,
474   IN  ESAL_VARIABLE_GLOBAL      *Global,
475   IN  VARIABLE_POINTER_TRACK    *Variable,
476   IN  UINT32                    Attributes OPTIONAL,
477   IN  BOOLEAN                   IsPk
478   )
479 {
480   EFI_STATUS                    Status;
481   VARIABLE_POINTER_TRACK        PkVariable;
482   EFI_SIGNATURE_LIST            *OldPkList;
483   EFI_SIGNATURE_DATA            *OldPkData;
484   EFI_VARIABLE_AUTHENTICATION   *CertData;
485   AUTHENTICATED_VARIABLE_HEADER VariableHeader;
486   BOOLEAN                       Valid;
487 
488   OldPkList = NULL;
489   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
490 
491   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
492     //
493     // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
494     //
495     return EFI_INVALID_PARAMETER;
496   }
497 
498   if (mPlatformMode == USER_MODE) {
499     if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
500       //
501       // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
502       //
503       return EFI_INVALID_PARAMETER;
504     }
505 
506     CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
507 
508     if (Variable->CurrPtr != 0x0) {
509       Valid = IsValidVariableHeader (
510                 Variable->CurrPtr,
511                 Variable->Volatile,
512                 &Global->VariableGlobal[VirtualMode],
513                 Global->FvbInstance,
514                 &VariableHeader
515                 );
516       ASSERT (Valid);
517 
518       if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
519         //
520         // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
521         //
522         return EFI_SECURITY_VIOLATION;
523       }
524     }
525     //
526     // Get platform key from variable.
527     //
528     Status = FindVariable (
529                Global->VariableName[VirtualMode][VAR_PLATFORM_KEY],
530                Global->GlobalVariableGuid[VirtualMode],
531                &PkVariable,
532                &Global->VariableGlobal[VirtualMode],
533                Global->FvbInstance
534                );
535     ASSERT_EFI_ERROR (Status);
536 
537     ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
538     GetVariableDataPtr (
539       PkVariable.CurrPtr,
540       PkVariable.Volatile,
541       &Global->VariableGlobal[VirtualMode],
542       Global->FvbInstance,
543       (CHAR16 *) Global->KeyList
544       );
545 
546     OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;
547     OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
548     Status    = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);
549     if (!EFI_ERROR (Status)) {
550       Status = UpdateVariable (
551                  VariableName,
552                  VendorGuid,
553                  (UINT8*)Data + AUTHINFO_SIZE,
554                  DataSize - AUTHINFO_SIZE,
555                  Attributes,
556                  0,
557                  CertData->MonotonicCount,
558                  VirtualMode,
559                  Global,
560                  Variable
561                  );
562 
563       if (!EFI_ERROR (Status)) {
564         //
565         // If delete PK in user mode, need change to setup mode.
566         //
567         if ((DataSize == AUTHINFO_SIZE) && IsPk) {
568           UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);
569         }
570       }
571     }
572   } else {
573     Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);
574     //
575     // If enroll PK in setup mode, need change to user mode.
576     //
577     if ((DataSize != 0) && IsPk) {
578       UpdatePlatformMode (VirtualMode, Global, USER_MODE);
579     }
580   }
581 
582   return Status;
583 }
584 
585 /**
586   Process variable with key exchange key for verification.
587 
588   @param[in]  VariableName                The name of Variable to be found.
589   @param[in]  VendorGuid                  The variable vendor GUID.
590   @param[in]  Data                        The data pointer.
591   @param[in]  DataSize                    The size of Data found. If size is less than the
592                                           data, this value contains the required size.
593   @param[in]  VirtualMode                 The current calling mode for this function.
594   @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
595   @param[in]  Variable                    The variable information which is used to keep track of variable usage.
596   @param[in]  Attributes                  The attribute value of the variable.
597 
598   @retval EFI_INVALID_PARAMETER           Invalid parameter.
599   @retval EFI_SECURITY_VIOLATION          The variable did NOT pass the validation
600                                           check carried out by the firmware.
601   @retval EFI_SUCCESS                     The variable passed validation successfully.
602 
603 **/
604 EFI_STATUS
ProcessVarWithKek(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN VOID * Data,IN UINTN DataSize,IN BOOLEAN VirtualMode,IN ESAL_VARIABLE_GLOBAL * Global,IN VARIABLE_POINTER_TRACK * Variable,IN UINT32 Attributes OPTIONAL)605 ProcessVarWithKek (
606   IN  CHAR16                               *VariableName,
607   IN  EFI_GUID                             *VendorGuid,
608   IN  VOID                                 *Data,
609   IN  UINTN                                DataSize,
610   IN  BOOLEAN                              VirtualMode,
611   IN  ESAL_VARIABLE_GLOBAL                 *Global,
612   IN  VARIABLE_POINTER_TRACK               *Variable,
613   IN  UINT32                               Attributes OPTIONAL
614   )
615 {
616   EFI_STATUS                      Status;
617   VARIABLE_POINTER_TRACK          KekVariable;
618   EFI_SIGNATURE_LIST              *KekList;
619   EFI_SIGNATURE_DATA              *KekItem;
620   UINT32                          KekCount;
621   EFI_VARIABLE_AUTHENTICATION     *CertData;
622   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
623   BOOLEAN                         IsFound;
624   UINT32                          Index;
625   AUTHENTICATED_VARIABLE_HEADER   VariableHeader;
626   BOOLEAN                         Valid;
627 
628   KekList = NULL;
629   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
630 
631   if (mPlatformMode == USER_MODE) {
632     if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
633       //
634       // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
635       //
636       return EFI_INVALID_PARAMETER;
637     }
638 
639     CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
640     CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
641     if (Variable->CurrPtr != 0x0) {
642       Valid = IsValidVariableHeader (
643                 Variable->CurrPtr,
644                 Variable->Volatile,
645                 &Global->VariableGlobal[VirtualMode],
646                 Global->FvbInstance,
647                 &VariableHeader
648                 );
649       ASSERT (Valid);
650 
651       if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
652         //
653         // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
654         //
655         return EFI_SECURITY_VIOLATION;
656       }
657     }
658     //
659     // Get KEK database from variable.
660     //
661     Status = FindVariable (
662                Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY],
663                Global->GlobalVariableGuid[VirtualMode],
664                &KekVariable,
665                &Global->VariableGlobal[VirtualMode],
666                Global->FvbInstance
667                );
668     ASSERT_EFI_ERROR (Status);
669 
670     ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
671     GetVariableDataPtr (
672       KekVariable.CurrPtr,
673       KekVariable.Volatile,
674       &Global->VariableGlobal[VirtualMode],
675       Global->FvbInstance,
676       (CHAR16 *) Global->KeyList
677       );
678     //
679     // Enumerate all Kek items in this list to verify the variable certificate data.
680     // If anyone is authenticated successfully, it means the variable is correct!
681     //
682     KekList   = (EFI_SIGNATURE_LIST *) Global->KeyList;
683     IsFound   = FALSE;
684     KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
685     KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
686     for (Index = 0; Index < KekCount; Index++) {
687       if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
688         IsFound = TRUE;
689         break;
690       }
691       KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
692     }
693 
694     if (!IsFound) {
695       return EFI_SECURITY_VIOLATION;
696     }
697 
698     Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);
699     if (!EFI_ERROR (Status)) {
700       Status = UpdateVariable (
701                  VariableName,
702                  VendorGuid,
703                  (UINT8*)Data + AUTHINFO_SIZE,
704                  DataSize - AUTHINFO_SIZE,
705                  Attributes,
706                  0,
707                  CertData->MonotonicCount,
708                  VirtualMode,
709                  Global,
710                  Variable
711                  );
712     }
713   } else {
714     //
715     // If in setup mode, no authentication needed.
716     //
717     Status = UpdateVariable (
718                VariableName,
719                VendorGuid,
720                Data,
721                DataSize,
722                Attributes,
723                0,
724                0,
725                VirtualMode,
726                Global,
727                Variable
728                );
729   }
730 
731   return Status;
732 }
733 
734 /**
735   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
736 
737   @param[in]  Data                        The data pointer.
738   @param[in]  DataSize                    The size of Data found. If size is less than the
739                                           data, this value contains the required size.
740   @param[in]  VirtualMode                 The current calling mode for this function.
741   @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
742   @param[in]  Variable                    The variable information which is used to keep track of variable usage.
743   @param[in]  Attributes                  The attribute value of the variable.
744   @param[out] KeyIndex                    The output index of corresponding public key in database.
745   @param[out] MonotonicCount              The output value of corresponding Monotonic Count.
746 
747   @retval EFI_INVALID_PARAMETER           Invalid parameter.
748   @retval EFI_WRITE_PROTECTED             The variable is write-protected and needs authentication with
749                                           EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
750   @retval EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
751                                           set, but the AuthInfo does NOT pass the validation
752                                           check carried out by the firmware.
753   @retval EFI_SUCCESS                     The variable is not write-protected, or passed validation successfully.
754 
755 **/
756 EFI_STATUS
VerifyVariable(IN VOID * Data,IN UINTN DataSize,IN BOOLEAN VirtualMode,IN ESAL_VARIABLE_GLOBAL * Global,IN VARIABLE_POINTER_TRACK * Variable,IN UINT32 Attributes OPTIONAL,OUT UINT32 * KeyIndex OPTIONAL,OUT UINT64 * MonotonicCount OPTIONAL)757 VerifyVariable (
758   IN  VOID                      *Data,
759   IN  UINTN                     DataSize,
760   IN  BOOLEAN                   VirtualMode,
761   IN  ESAL_VARIABLE_GLOBAL      *Global,
762   IN  VARIABLE_POINTER_TRACK    *Variable,
763   IN  UINT32                    Attributes OPTIONAL,
764   OUT UINT32                    *KeyIndex OPTIONAL,
765   OUT UINT64                    *MonotonicCount OPTIONAL
766   )
767 {
768   EFI_STATUS                      Status;
769   BOOLEAN                         IsDeletion;
770   BOOLEAN                         IsFirstTime;
771   UINT8                           *PubKey;
772   EFI_VARIABLE_AUTHENTICATION     *CertData;
773   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
774   AUTHENTICATED_VARIABLE_HEADER   VariableHeader;
775   BOOLEAN                         Valid;
776 
777   CertData    = NULL;
778   CertBlock   = NULL;
779   PubKey      = NULL;
780   IsDeletion  = FALSE;
781   Valid       = FALSE;
782 
783   if (KeyIndex != NULL) {
784     *KeyIndex = 0;
785   }
786   //
787   // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
788   //
789   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
790   if (Variable->CurrPtr != 0x0) {
791     Valid = IsValidVariableHeader (
792               Variable->CurrPtr,
793               Variable->Volatile,
794               &Global->VariableGlobal[VirtualMode],
795               Global->FvbInstance,
796               &VariableHeader
797               );
798     ASSERT (Valid);
799   }
800 
801   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
802     if (KeyIndex == NULL) {
803       return EFI_INVALID_PARAMETER;
804     }
805 
806     //
807     // Determine current operation type.
808     //
809     if (DataSize == AUTHINFO_SIZE) {
810       IsDeletion = TRUE;
811     }
812     //
813     // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
814     //
815     if (Variable->CurrPtr == 0x0) {
816       IsFirstTime = TRUE;
817     } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
818       IsFirstTime = TRUE;
819     } else {
820       *KeyIndex   = VariableHeader.PubKeyIndex;
821       IsFirstTime = FALSE;
822     }
823   } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
824       //
825       // If the variable is already write-protected, it always needs authentication before update.
826       //
827       return EFI_WRITE_PROTECTED;
828   } else {
829     //
830     // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
831     // That means it is not authenticated variable, just return EFI_SUCCESS.
832     //
833     return EFI_SUCCESS;
834   }
835 
836   //
837   // Get PubKey and check Monotonic Count value corresponding to the variable.
838   //
839   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
840   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
841   PubKey    = CertBlock->PublicKey;
842 
843   if (MonotonicCount != NULL) {
844     //
845     // Update Monotonic Count value.
846     //
847     *MonotonicCount = CertData->MonotonicCount;
848   }
849 
850   if (!IsFirstTime) {
851     //
852     // Check input PubKey.
853     //
854     if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
855       return EFI_SECURITY_VIOLATION;
856     }
857     //
858     // Compare the current monotonic count and ensure that it is greater than the last SetVariable
859     // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
860     //
861     if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
862       //
863       // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
864       //
865       return EFI_SECURITY_VIOLATION;
866     }
867   }
868   //
869   // Verify the certificate in Data payload.
870   //
871   Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);
872   if (!EFI_ERROR (Status)) {
873     //
874     // Now, the signature has been verified!
875     //
876     if (IsFirstTime && !IsDeletion) {
877       //
878       // Update public key database variable if need and return the index.
879       //
880       *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);
881     }
882   }
883 
884   return Status;
885 }
886 
887