1 /** @file
2   HII Config Access protocol implementation of SecureBoot configuration module.
3 
4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "SecureBootConfigImpl.h"
16 
17 CHAR16              mSecureBootStorageName[] = L"SECUREBOOT_CONFIGURATION";
18 
19 SECUREBOOT_CONFIG_PRIVATE_DATA         mSecureBootConfigPrivateDateTemplate = {
20   SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE,
21   {
22     SecureBootExtractConfig,
23     SecureBootRouteConfig,
24     SecureBootCallback
25   }
26 };
27 
28 HII_VENDOR_DEVICE_PATH          mSecureBootHiiVendorDevicePath = {
29   {
30     {
31       HARDWARE_DEVICE_PATH,
32       HW_VENDOR_DP,
33       {
34         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
35         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
36       }
37     },
38     SECUREBOOT_CONFIG_FORM_SET_GUID
39   },
40   {
41     END_DEVICE_PATH_TYPE,
42     END_ENTIRE_DEVICE_PATH_SUBTYPE,
43     {
44       (UINT8) (END_DEVICE_PATH_LENGTH),
45       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
46     }
47   }
48 };
49 
50 
51 BOOLEAN mIsEnterSecureBootForm = FALSE;
52 BOOLEAN mIsSelectedSecureBootModeForm = FALSE;
53 BOOLEAN mIsSecureBootModeChanged = FALSE;
54 
55 //
56 // OID ASN.1 Value for Hash Algorithms
57 //
58 UINT8 mHashOidValue[] = {
59   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,         // OBJ_md5
60   0x2B, 0x0E, 0x03, 0x02, 0x1A,                           // OBJ_sha1
61   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,   // OBJ_sha224
62   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,   // OBJ_sha256
63   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,   // OBJ_sha384
64   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,   // OBJ_sha512
65   };
66 
67 HASH_TABLE mHash[] = {
68   { L"SHA1",   20, &mHashOidValue[8],  5, Sha1GetContextSize,   Sha1Init,   Sha1Update,   Sha1Final  },
69   { L"SHA224", 28, &mHashOidValue[13], 9, NULL,                 NULL,       NULL,         NULL       },
70   { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},
71   { L"SHA384", 48, &mHashOidValue[31], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},
72   { L"SHA512", 64, &mHashOidValue[40], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}
73 };
74 
75 //
76 // Variable Definitions
77 //
78 UINT32            mPeCoffHeaderOffset = 0;
79 WIN_CERTIFICATE   *mCertificate = NULL;
80 IMAGE_TYPE        mImageType;
81 UINT8             *mImageBase = NULL;
82 UINTN             mImageSize = 0;
83 UINT8             mImageDigest[MAX_DIGEST_SIZE];
84 UINTN             mImageDigestSize;
85 EFI_GUID          mCertType;
86 EFI_IMAGE_SECURITY_DATA_DIRECTORY    *mSecDataDir = NULL;
87 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  mNtHeader;
88 
89 //
90 // Possible DER-encoded certificate file suffixes, end with NULL pointer.
91 //
92 CHAR16* mDerEncodedSuffix[] = {
93   L".cer",
94   L".der",
95   L".crt",
96   NULL
97 };
98 CHAR16* mSupportX509Suffix = L"*.cer/der/crt";
99 
100 /**
101   This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.
102 
103   @param[in] FileSuffix            The suffix of the input certificate file
104 
105   @retval    TRUE           It's a DER-encoded certificate.
106   @retval    FALSE          It's NOT a DER-encoded certificate.
107 
108 **/
109 BOOLEAN
IsDerEncodeCertificate(IN CONST CHAR16 * FileSuffix)110 IsDerEncodeCertificate (
111   IN CONST CHAR16         *FileSuffix
112 )
113 {
114   UINTN     Index;
115   for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {
116     if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {
117       return TRUE;
118     }
119   }
120   return FALSE;
121 }
122 
123 /**
124   Set Secure Boot option into variable space.
125 
126   @param[in] VarValue              The option of Secure Boot.
127 
128   @retval    EFI_SUCCESS           The operation is finished successfully.
129   @retval    Others                Other errors as indicated.
130 
131 **/
132 EFI_STATUS
SaveSecureBootVariable(IN UINT8 VarValue)133 SaveSecureBootVariable (
134   IN UINT8                         VarValue
135   )
136 {
137   EFI_STATUS                       Status;
138 
139   Status = gRT->SetVariable (
140              EFI_SECURE_BOOT_ENABLE_NAME,
141              &gEfiSecureBootEnableDisableGuid,
142              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
143              sizeof (UINT8),
144              &VarValue
145              );
146   return Status;
147 }
148 
149 /**
150   Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
151   descriptor with the input data. NO authentication is required in this function.
152 
153   @param[in, out]   DataSize       On input, the size of Data buffer in bytes.
154                                    On output, the size of data returned in Data
155                                    buffer in bytes.
156   @param[in, out]   Data           On input, Pointer to data buffer to be wrapped or
157                                    pointer to NULL to wrap an empty payload.
158                                    On output, Pointer to the new payload date buffer allocated from pool,
159                                    it's caller's responsibility to free the memory when finish using it.
160 
161   @retval EFI_SUCCESS              Create time based payload successfully.
162   @retval EFI_OUT_OF_RESOURCES     There are not enough memory resourses to create time based payload.
163   @retval EFI_INVALID_PARAMETER    The parameter is invalid.
164   @retval Others                   Unexpected error happens.
165 
166 **/
167 EFI_STATUS
CreateTimeBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)168 CreateTimeBasedPayload (
169   IN OUT UINTN            *DataSize,
170   IN OUT UINT8            **Data
171   )
172 {
173   EFI_STATUS                       Status;
174   UINT8                            *NewData;
175   UINT8                            *Payload;
176   UINTN                            PayloadSize;
177   EFI_VARIABLE_AUTHENTICATION_2    *DescriptorData;
178   UINTN                            DescriptorSize;
179   EFI_TIME                         Time;
180 
181   if (Data == NULL || DataSize == NULL) {
182     return EFI_INVALID_PARAMETER;
183   }
184 
185   //
186   // In Setup mode or Custom mode, the variable does not need to be signed but the
187   // parameters to the SetVariable() call still need to be prepared as authenticated
188   // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
189   // data in it.
190   //
191   Payload     = *Data;
192   PayloadSize = *DataSize;
193 
194   DescriptorSize    = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
195   NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
196   if (NewData == NULL) {
197     return EFI_OUT_OF_RESOURCES;
198   }
199 
200   if ((Payload != NULL) && (PayloadSize != 0)) {
201     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
202   }
203 
204   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
205 
206   ZeroMem (&Time, sizeof (EFI_TIME));
207   Status = gRT->GetTime (&Time, NULL);
208   if (EFI_ERROR (Status)) {
209     FreePool(NewData);
210     return Status;
211   }
212   Time.Pad1       = 0;
213   Time.Nanosecond = 0;
214   Time.TimeZone   = 0;
215   Time.Daylight   = 0;
216   Time.Pad2       = 0;
217   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
218 
219   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
220   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
221   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
222   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
223 
224   if (Payload != NULL) {
225     FreePool(Payload);
226   }
227 
228   *DataSize = DescriptorSize + PayloadSize;
229   *Data     = NewData;
230   return EFI_SUCCESS;
231 }
232 
233 /**
234   Internal helper function to delete a Variable given its name and GUID, NO authentication
235   required.
236 
237   @param[in]      VariableName            Name of the Variable.
238   @param[in]      VendorGuid              GUID of the Variable.
239 
240   @retval EFI_SUCCESS              Variable deleted successfully.
241   @retval Others                   The driver failed to start the device.
242 
243 **/
244 EFI_STATUS
DeleteVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid)245 DeleteVariable (
246   IN  CHAR16                    *VariableName,
247   IN  EFI_GUID                  *VendorGuid
248   )
249 {
250   EFI_STATUS              Status;
251   VOID*                   Variable;
252   UINT8                   *Data;
253   UINTN                   DataSize;
254   UINT32                  Attr;
255 
256   GetVariable2 (VariableName, VendorGuid, &Variable, NULL);
257   if (Variable == NULL) {
258     return EFI_SUCCESS;
259   }
260   FreePool (Variable);
261 
262   Data     = NULL;
263   DataSize = 0;
264   Attr     = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
265              | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
266 
267   Status = CreateTimeBasedPayload (&DataSize, &Data);
268   if (EFI_ERROR (Status)) {
269     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
270     return Status;
271   }
272 
273   Status = gRT->SetVariable (
274                   VariableName,
275                   VendorGuid,
276                   Attr,
277                   DataSize,
278                   Data
279                   );
280   if (Data != NULL) {
281     FreePool (Data);
282   }
283   return Status;
284 }
285 
286 /**
287 
288   Set the platform secure boot mode into "Custom" or "Standard" mode.
289 
290   @param[in]   SecureBootMode        New secure boot mode: STANDARD_SECURE_BOOT_MODE or
291                                      CUSTOM_SECURE_BOOT_MODE.
292 
293   @return EFI_SUCCESS                The platform has switched to the special mode successfully.
294   @return other                      Fail to operate the secure boot mode.
295 
296 **/
297 EFI_STATUS
SetSecureBootMode(IN UINT8 SecureBootMode)298 SetSecureBootMode (
299   IN     UINT8         SecureBootMode
300   )
301 {
302   return gRT->SetVariable (
303                 EFI_CUSTOM_MODE_NAME,
304                 &gEfiCustomModeEnableGuid,
305                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
306                 sizeof (UINT8),
307                 &SecureBootMode
308                 );
309 }
310 
311 /**
312   Generate the PK signature list from the X509 Certificate storing file (.cer)
313 
314   @param[in]   X509File              FileHandle of X509 Certificate storing file.
315   @param[out]  PkCert                Point to the data buffer to store the signature list.
316 
317   @return EFI_UNSUPPORTED            Unsupported Key Length.
318   @return EFI_OUT_OF_RESOURCES       There are not enough memory resourses to form the signature list.
319 
320 **/
321 EFI_STATUS
CreatePkX509SignatureList(IN EFI_FILE_HANDLE X509File,OUT EFI_SIGNATURE_LIST ** PkCert)322 CreatePkX509SignatureList (
323   IN    EFI_FILE_HANDLE             X509File,
324   OUT   EFI_SIGNATURE_LIST          **PkCert
325   )
326 {
327   EFI_STATUS              Status;
328   UINT8                   *X509Data;
329   UINTN                   X509DataSize;
330   EFI_SIGNATURE_DATA      *PkCertData;
331 
332   X509Data = NULL;
333   PkCertData = NULL;
334   X509DataSize = 0;
335 
336   Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);
337   if (EFI_ERROR (Status)) {
338     goto ON_EXIT;
339   }
340   ASSERT (X509Data != NULL);
341 
342   //
343   // Allocate space for PK certificate list and initialize it.
344   // Create PK database entry with SignatureHeaderSize equals 0.
345   //
346   *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool (
347               sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
348               + X509DataSize
349               );
350   if (*PkCert == NULL) {
351     Status = EFI_OUT_OF_RESOURCES;
352     goto ON_EXIT;
353   }
354 
355   (*PkCert)->SignatureListSize   = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
356                                     + sizeof(EFI_SIGNATURE_DATA) - 1
357                                     + X509DataSize);
358   (*PkCert)->SignatureSize       = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
359   (*PkCert)->SignatureHeaderSize = 0;
360   CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid);
361   PkCertData                     = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert)
362                                                           + sizeof(EFI_SIGNATURE_LIST)
363                                                           + (*PkCert)->SignatureHeaderSize);
364   CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);
365   //
366   // Fill the PK database with PKpub data from X509 certificate file.
367   //
368   CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize);
369 
370 ON_EXIT:
371 
372   if (X509Data != NULL) {
373     FreePool (X509Data);
374   }
375 
376   if (EFI_ERROR(Status) && *PkCert != NULL) {
377     FreePool (*PkCert);
378     *PkCert = NULL;
379   }
380 
381   return Status;
382 }
383 
384 /**
385   Enroll new PK into the System without original PK's authentication.
386 
387   The SignatureOwner GUID will be the same with PK's vendorguid.
388 
389   @param[in] PrivateData     The module's private data.
390 
391   @retval   EFI_SUCCESS            New PK enrolled successfully.
392   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
393   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
394 
395 **/
396 EFI_STATUS
EnrollPlatformKey(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)397 EnrollPlatformKey (
398    IN  SECUREBOOT_CONFIG_PRIVATE_DATA*   Private
399   )
400 {
401   EFI_STATUS                      Status;
402   UINT32                          Attr;
403   UINTN                           DataSize;
404   EFI_SIGNATURE_LIST              *PkCert;
405   UINT16*                         FilePostFix;
406   UINTN                           NameLength;
407 
408   if (Private->FileContext->FileName == NULL) {
409     return EFI_INVALID_PARAMETER;
410   }
411 
412   PkCert = NULL;
413 
414   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
415   if (EFI_ERROR (Status)) {
416     return Status;
417   }
418 
419   //
420   // Parse the file's postfix. Only support DER encoded X.509 certificate files.
421   //
422   NameLength = StrLen (Private->FileContext->FileName);
423   if (NameLength <= 4) {
424     return EFI_INVALID_PARAMETER;
425   }
426   FilePostFix = Private->FileContext->FileName + NameLength - 4;
427   if (!IsDerEncodeCertificate(FilePostFix)) {
428     DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix));
429     return EFI_INVALID_PARAMETER;
430   }
431   DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName));
432   DEBUG ((EFI_D_INFO, "FilePostFix = %s\n", FilePostFix));
433 
434   //
435   // Prase the selected PK file and generature PK certificate list.
436   //
437   Status = CreatePkX509SignatureList (
438             Private->FileContext->FHandle,
439             &PkCert
440             );
441   if (EFI_ERROR (Status)) {
442     goto ON_EXIT;
443   }
444   ASSERT (PkCert != NULL);
445 
446   //
447   // Set Platform Key variable.
448   //
449   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
450           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
451   DataSize = PkCert->SignatureListSize;
452   Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);
453   if (EFI_ERROR (Status)) {
454     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
455     goto ON_EXIT;
456   }
457 
458   Status = gRT->SetVariable(
459                   EFI_PLATFORM_KEY_NAME,
460                   &gEfiGlobalVariableGuid,
461                   Attr,
462                   DataSize,
463                   PkCert
464                   );
465   if (EFI_ERROR (Status)) {
466     if (Status == EFI_OUT_OF_RESOURCES) {
467       DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n"));
468     }
469     goto ON_EXIT;
470   }
471 
472 ON_EXIT:
473 
474   if (PkCert != NULL) {
475     FreePool(PkCert);
476   }
477 
478   if (Private->FileContext->FHandle != NULL) {
479     CloseFile (Private->FileContext->FHandle);
480     Private->FileContext->FHandle = NULL;
481   }
482 
483   return Status;
484 }
485 
486 /**
487   Remove the PK variable.
488 
489   @retval EFI_SUCCESS    Delete PK successfully.
490   @retval Others         Could not allow to delete PK.
491 
492 **/
493 EFI_STATUS
DeletePlatformKey(VOID)494 DeletePlatformKey (
495   VOID
496 )
497 {
498   EFI_STATUS Status;
499 
500   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
501   if (EFI_ERROR (Status)) {
502     return Status;
503   }
504 
505   Status = DeleteVariable (
506              EFI_PLATFORM_KEY_NAME,
507              &gEfiGlobalVariableGuid
508              );
509   return Status;
510 }
511 
512 /**
513   Enroll a new KEK item from public key storing file (*.pbk).
514 
515   @param[in] PrivateData           The module's private data.
516 
517   @retval   EFI_SUCCESS            New KEK enrolled successfully.
518   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
519   @retval   EFI_UNSUPPORTED        Unsupported command.
520   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
521 
522 **/
523 EFI_STATUS
EnrollRsa2048ToKek(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)524 EnrollRsa2048ToKek (
525   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
526   )
527 {
528   EFI_STATUS                      Status;
529   UINT32                          Attr;
530   UINTN                           DataSize;
531   EFI_SIGNATURE_LIST              *KekSigList;
532   UINTN                           KeyBlobSize;
533   UINT8                           *KeyBlob;
534   CPL_KEY_INFO                    *KeyInfo;
535   EFI_SIGNATURE_DATA              *KEKSigData;
536   UINTN                           KekSigListSize;
537   UINT8                           *KeyBuffer;
538   UINTN                           KeyLenInBytes;
539 
540   Attr        = 0;
541   DataSize    = 0;
542   KeyBuffer   = NULL;
543   KeyBlobSize = 0;
544   KeyBlob     = NULL;
545   KeyInfo     = NULL;
546   KEKSigData  = NULL;
547   KekSigList  = NULL;
548   KekSigListSize = 0;
549 
550   //
551   // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type.
552   // First, We have to parse out public key data from the pbk key file.
553   //
554   Status = ReadFileContent (
555              Private->FileContext->FHandle,
556              (VOID**) &KeyBlob,
557              &KeyBlobSize,
558              0
559              );
560   if (EFI_ERROR (Status)) {
561     goto ON_EXIT;
562   }
563   ASSERT (KeyBlob != NULL);
564   KeyInfo = (CPL_KEY_INFO *) KeyBlob;
565   if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {
566     DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));
567     Status = EFI_UNSUPPORTED;
568     goto ON_EXIT;
569   }
570 
571   //
572   // Convert the Public key to fix octet string format represented in RSA PKCS#1.
573   //
574   KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;
575   KeyBuffer = AllocateZeroPool (KeyLenInBytes);
576   if (KeyBuffer == NULL) {
577     Status = EFI_OUT_OF_RESOURCES;
578     goto ON_EXIT;
579   }
580   Int2OctStr (
581     (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)),
582     KeyLenInBytes / sizeof (UINTN),
583     KeyBuffer,
584     KeyLenInBytes
585     );
586   CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes);
587 
588   //
589   // Form an new EFI_SIGNATURE_LIST.
590   //
591   KekSigListSize = sizeof(EFI_SIGNATURE_LIST)
592                      + sizeof(EFI_SIGNATURE_DATA) - 1
593                      + WIN_CERT_UEFI_RSA2048_SIZE;
594 
595   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
596   if (KekSigList == NULL) {
597     Status = EFI_OUT_OF_RESOURCES;
598     goto ON_EXIT;
599   }
600 
601   KekSigList->SignatureListSize   = sizeof(EFI_SIGNATURE_LIST)
602                                   + sizeof(EFI_SIGNATURE_DATA) - 1
603                                   + WIN_CERT_UEFI_RSA2048_SIZE;
604   KekSigList->SignatureHeaderSize = 0;
605   KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;
606   CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid);
607 
608   KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST));
609   CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
610   CopyMem (
611     KEKSigData->SignatureData,
612     KeyBlob + sizeof(CPL_KEY_INFO),
613     WIN_CERT_UEFI_RSA2048_SIZE
614     );
615 
616   //
617   // Check if KEK entry has been already existed.
618   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
619   // new KEK to original variable.
620   //
621   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
622          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
623   Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
624   if (EFI_ERROR (Status)) {
625     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
626     goto ON_EXIT;
627   }
628 
629   Status = gRT->GetVariable(
630                   EFI_KEY_EXCHANGE_KEY_NAME,
631                   &gEfiGlobalVariableGuid,
632                   NULL,
633                   &DataSize,
634                   NULL
635                   );
636   if (Status == EFI_BUFFER_TOO_SMALL) {
637     Attr |= EFI_VARIABLE_APPEND_WRITE;
638   } else if (Status != EFI_NOT_FOUND) {
639     goto ON_EXIT;
640   }
641 
642   //
643   // Done. Now we have formed the correct KEKpub database item, just set it into variable storage,
644   //
645   Status = gRT->SetVariable(
646                   EFI_KEY_EXCHANGE_KEY_NAME,
647                   &gEfiGlobalVariableGuid,
648                   Attr,
649                   KekSigListSize,
650                   KekSigList
651                   );
652   if (EFI_ERROR (Status)) {
653     goto ON_EXIT;
654   }
655 
656 ON_EXIT:
657 
658   CloseFile (Private->FileContext->FHandle);
659   Private->FileContext->FHandle = NULL;
660   Private->FileContext->FileName = NULL;
661 
662   if (Private->SignatureGUID != NULL) {
663     FreePool (Private->SignatureGUID);
664     Private->SignatureGUID = NULL;
665   }
666 
667   if (KeyBlob != NULL) {
668     FreePool (KeyBlob);
669   }
670   if (KeyBuffer != NULL) {
671     FreePool (KeyBuffer);
672   }
673   if (KekSigList != NULL) {
674     FreePool (KekSigList);
675   }
676 
677   return Status;
678 }
679 
680 /**
681   Enroll a new KEK item from X509 certificate file.
682 
683   @param[in] PrivateData           The module's private data.
684 
685   @retval   EFI_SUCCESS            New X509 is enrolled successfully.
686   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
687   @retval   EFI_UNSUPPORTED        Unsupported command.
688   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
689 
690 **/
691 EFI_STATUS
EnrollX509ToKek(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)692 EnrollX509ToKek (
693   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
694   )
695 {
696   EFI_STATUS                        Status;
697   UINTN                             X509DataSize;
698   VOID                              *X509Data;
699   EFI_SIGNATURE_DATA                *KEKSigData;
700   EFI_SIGNATURE_LIST                *KekSigList;
701   UINTN                             DataSize;
702   UINTN                             KekSigListSize;
703   UINT32                            Attr;
704 
705   X509Data       = NULL;
706   X509DataSize   = 0;
707   KekSigList     = NULL;
708   KekSigListSize = 0;
709   DataSize       = 0;
710   KEKSigData     = NULL;
711 
712   Status = ReadFileContent (
713              Private->FileContext->FHandle,
714              &X509Data,
715              &X509DataSize,
716              0
717              );
718   if (EFI_ERROR (Status)) {
719     goto ON_EXIT;
720   }
721   ASSERT (X509Data != NULL);
722 
723   KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
724   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
725   if (KekSigList == NULL) {
726     Status = EFI_OUT_OF_RESOURCES;
727     goto ON_EXIT;
728   }
729 
730   //
731   // Fill Certificate Database parameters.
732   //
733   KekSigList->SignatureListSize   = (UINT32) KekSigListSize;
734   KekSigList->SignatureHeaderSize = 0;
735   KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
736   CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid);
737 
738   KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST));
739   CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
740   CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize);
741 
742   //
743   // Check if KEK been already existed.
744   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
745   // new kek to original variable
746   //
747   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
748           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
749   Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
750   if (EFI_ERROR (Status)) {
751     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
752     goto ON_EXIT;
753   }
754 
755   Status = gRT->GetVariable(
756                   EFI_KEY_EXCHANGE_KEY_NAME,
757                   &gEfiGlobalVariableGuid,
758                   NULL,
759                   &DataSize,
760                   NULL
761                   );
762   if (Status == EFI_BUFFER_TOO_SMALL) {
763     Attr |= EFI_VARIABLE_APPEND_WRITE;
764   } else if (Status != EFI_NOT_FOUND) {
765     goto ON_EXIT;
766   }
767 
768   Status = gRT->SetVariable(
769                   EFI_KEY_EXCHANGE_KEY_NAME,
770                   &gEfiGlobalVariableGuid,
771                   Attr,
772                   KekSigListSize,
773                   KekSigList
774                   );
775   if (EFI_ERROR (Status)) {
776     goto ON_EXIT;
777   }
778 
779 ON_EXIT:
780 
781   CloseFile (Private->FileContext->FHandle);
782   Private->FileContext->FileName = NULL;
783   Private->FileContext->FHandle = NULL;
784 
785   if (Private->SignatureGUID != NULL) {
786     FreePool (Private->SignatureGUID);
787     Private->SignatureGUID = NULL;
788   }
789 
790   if (KekSigList != NULL) {
791     FreePool (KekSigList);
792   }
793 
794   return Status;
795 }
796 
797 /**
798   Enroll new KEK into the System without PK's authentication.
799   The SignatureOwner GUID will be Private->SignatureGUID.
800 
801   @param[in] PrivateData     The module's private data.
802 
803   @retval   EFI_SUCCESS            New KEK enrolled successful.
804   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
805   @retval   others                 Fail to enroll KEK data.
806 
807 **/
808 EFI_STATUS
EnrollKeyExchangeKey(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)809 EnrollKeyExchangeKey (
810   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
811   )
812 {
813   UINT16*     FilePostFix;
814   EFI_STATUS  Status;
815   UINTN       NameLength;
816 
817   if ((Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {
818     return EFI_INVALID_PARAMETER;
819   }
820 
821   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
822   if (EFI_ERROR (Status)) {
823     return Status;
824   }
825 
826   //
827   // Parse the file's postfix. Supports DER-encoded X509 certificate,
828   // and .pbk as RSA public key file.
829   //
830   NameLength = StrLen (Private->FileContext->FileName);
831   if (NameLength <= 4) {
832     return EFI_INVALID_PARAMETER;
833   }
834   FilePostFix = Private->FileContext->FileName + NameLength - 4;
835   if (IsDerEncodeCertificate(FilePostFix)) {
836     return EnrollX509ToKek (Private);
837   } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {
838     return EnrollRsa2048ToKek (Private);
839   } else {
840     return EFI_INVALID_PARAMETER;
841   }
842 }
843 
844 /**
845   Enroll a new X509 certificate into Signature Database (DB or DBX or DBT) without
846   KEK's authentication.
847 
848   @param[in] PrivateData     The module's private data.
849   @param[in] VariableName    Variable name of signature database, must be
850                              EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
851 
852   @retval   EFI_SUCCESS            New X509 is enrolled successfully.
853   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
854 
855 **/
856 EFI_STATUS
EnrollX509toSigDB(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)857 EnrollX509toSigDB (
858   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
859   IN CHAR16                         *VariableName
860   )
861 {
862   EFI_STATUS                        Status;
863   UINTN                             X509DataSize;
864   VOID                              *X509Data;
865   EFI_SIGNATURE_LIST                *SigDBCert;
866   EFI_SIGNATURE_DATA                *SigDBCertData;
867   VOID                              *Data;
868   UINTN                             DataSize;
869   UINTN                             SigDBSize;
870   UINT32                            Attr;
871 
872   X509DataSize  = 0;
873   SigDBSize     = 0;
874   DataSize      = 0;
875   X509Data      = NULL;
876   SigDBCert     = NULL;
877   SigDBCertData = NULL;
878   Data          = NULL;
879 
880   Status = ReadFileContent (
881              Private->FileContext->FHandle,
882              &X509Data,
883              &X509DataSize,
884              0
885              );
886   if (EFI_ERROR (Status)) {
887     goto ON_EXIT;
888   }
889   ASSERT (X509Data != NULL);
890 
891   SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
892 
893   Data = AllocateZeroPool (SigDBSize);
894   if (Data == NULL) {
895     Status = EFI_OUT_OF_RESOURCES;
896     goto ON_EXIT;
897   }
898 
899   //
900   // Fill Certificate Database parameters.
901   //
902   SigDBCert = (EFI_SIGNATURE_LIST*) Data;
903   SigDBCert->SignatureListSize   = (UINT32) SigDBSize;
904   SigDBCert->SignatureHeaderSize = 0;
905   SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
906   CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid);
907 
908   SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST));
909   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
910   CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize);
911 
912   //
913   // Check if signature database entry has been already existed.
914   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
915   // new signature data to original variable
916   //
917   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
918           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
919   Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
920   if (EFI_ERROR (Status)) {
921     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
922     goto ON_EXIT;
923   }
924 
925   Status = gRT->GetVariable(
926                   VariableName,
927                   &gEfiImageSecurityDatabaseGuid,
928                   NULL,
929                   &DataSize,
930                   NULL
931                   );
932   if (Status == EFI_BUFFER_TOO_SMALL) {
933     Attr |= EFI_VARIABLE_APPEND_WRITE;
934   } else if (Status != EFI_NOT_FOUND) {
935     goto ON_EXIT;
936   }
937 
938   Status = gRT->SetVariable(
939                   VariableName,
940                   &gEfiImageSecurityDatabaseGuid,
941                   Attr,
942                   SigDBSize,
943                   Data
944                   );
945   if (EFI_ERROR (Status)) {
946     goto ON_EXIT;
947   }
948 
949 ON_EXIT:
950 
951   CloseFile (Private->FileContext->FHandle);
952   Private->FileContext->FileName = NULL;
953   Private->FileContext->FHandle = NULL;
954 
955   if (Private->SignatureGUID != NULL) {
956     FreePool (Private->SignatureGUID);
957     Private->SignatureGUID = NULL;
958   }
959 
960   if (Data != NULL) {
961     FreePool (Data);
962   }
963 
964   if (X509Data != NULL) {
965     FreePool (X509Data);
966   }
967 
968   return Status;
969 }
970 
971 /**
972   Check whether signature is in specified database.
973 
974   @param[in]  VariableName        Name of database variable that is searched in.
975   @param[in]  Signature           Pointer to signature that is searched for.
976   @param[in]  SignatureSize       Size of Signature.
977 
978   @return TRUE                    Found the signature in the variable database.
979   @return FALSE                   Not found the signature in the variable database.
980 
981 **/
982 BOOLEAN
IsSignatureFoundInDatabase(IN CHAR16 * VariableName,IN UINT8 * Signature,IN UINTN SignatureSize)983 IsSignatureFoundInDatabase (
984   IN CHAR16             *VariableName,
985   IN UINT8              *Signature,
986   IN UINTN              SignatureSize
987   )
988 {
989   EFI_STATUS          Status;
990   EFI_SIGNATURE_LIST  *CertList;
991   EFI_SIGNATURE_DATA  *Cert;
992   UINTN               DataSize;
993   UINT8               *Data;
994   UINTN               Index;
995   UINTN               CertCount;
996   BOOLEAN             IsFound;
997 
998   //
999   // Read signature database variable.
1000   //
1001   IsFound   = FALSE;
1002   Data      = NULL;
1003   DataSize  = 0;
1004   Status    = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1005   if (Status != EFI_BUFFER_TOO_SMALL) {
1006     return FALSE;
1007   }
1008 
1009   Data = (UINT8 *) AllocateZeroPool (DataSize);
1010   if (Data == NULL) {
1011     return FALSE;
1012   }
1013 
1014   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1015   if (EFI_ERROR (Status)) {
1016     goto Done;
1017   }
1018 
1019   //
1020   // Enumerate all signature data in SigDB to check if executable's signature exists.
1021   //
1022   CertList = (EFI_SIGNATURE_LIST *) Data;
1023   while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1024     CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1025     Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1026     if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &gEfiCertX509Guid))) {
1027       for (Index = 0; Index < CertCount; Index++) {
1028         if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {
1029           //
1030           // Find the signature in database.
1031           //
1032           IsFound = TRUE;
1033           break;
1034         }
1035         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1036       }
1037 
1038       if (IsFound) {
1039         break;
1040       }
1041     }
1042 
1043     DataSize -= CertList->SignatureListSize;
1044     CertList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1045   }
1046 
1047 Done:
1048   if (Data != NULL) {
1049     FreePool (Data);
1050   }
1051 
1052   return IsFound;
1053 }
1054 
1055 /**
1056   Calculate the hash of a certificate data with the specified hash algorithm.
1057 
1058   @param[in]    CertData  The certificate data to be hashed.
1059   @param[in]    CertSize  The certificate size in bytes.
1060   @param[in]    HashAlg   The specified hash algorithm.
1061   @param[out]   CertHash  The output digest of the certificate
1062 
1063   @retval TRUE            Successfully got the hash of the CertData.
1064   @retval FALSE           Failed to get the hash of CertData.
1065 
1066 **/
1067 BOOLEAN
CalculateCertHash(IN UINT8 * CertData,IN UINTN CertSize,IN UINT32 HashAlg,OUT UINT8 * CertHash)1068 CalculateCertHash (
1069   IN  UINT8                 *CertData,
1070   IN  UINTN                 CertSize,
1071   IN  UINT32                HashAlg,
1072   OUT UINT8                 *CertHash
1073   )
1074 {
1075   BOOLEAN                   Status;
1076   VOID                      *HashCtx;
1077   UINTN                     CtxSize;
1078   UINT8                     *TBSCert;
1079   UINTN                     TBSCertSize;
1080 
1081   HashCtx = NULL;
1082   Status  = FALSE;
1083 
1084   if (HashAlg >= HASHALG_MAX) {
1085     return FALSE;
1086   }
1087 
1088   //
1089   // Retrieve the TBSCertificate for Hash Calculation.
1090   //
1091   if (!X509GetTBSCert (CertData, CertSize, &TBSCert, &TBSCertSize)) {
1092     return FALSE;
1093   }
1094 
1095   //
1096   // 1. Initialize context of hash.
1097   //
1098   CtxSize = mHash[HashAlg].GetContextSize ();
1099   HashCtx = AllocatePool (CtxSize);
1100   ASSERT (HashCtx != NULL);
1101 
1102   //
1103   // 2. Initialize a hash context.
1104   //
1105   Status = mHash[HashAlg].HashInit (HashCtx);
1106   if (!Status) {
1107     goto Done;
1108   }
1109 
1110   //
1111   // 3. Calculate the hash.
1112   //
1113   Status  = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
1114   if (!Status) {
1115     goto Done;
1116   }
1117 
1118   //
1119   // 4. Get the hash result.
1120   //
1121   ZeroMem (CertHash, mHash[HashAlg].DigestLength);
1122   Status  = mHash[HashAlg].HashFinal (HashCtx, CertHash);
1123 
1124 Done:
1125   if (HashCtx != NULL) {
1126     FreePool (HashCtx);
1127   }
1128 
1129   return Status;
1130 }
1131 
1132 /**
1133   Check whether the hash of an X.509 certificate is in forbidden database (DBX).
1134 
1135   @param[in]  Certificate       Pointer to X.509 Certificate that is searched for.
1136   @param[in]  CertSize          Size of X.509 Certificate.
1137 
1138   @return TRUE               Found the certificate hash in the forbidden database.
1139   @return FALSE              Certificate hash is Not found in the forbidden database.
1140 
1141 **/
1142 BOOLEAN
IsCertHashFoundInDbx(IN UINT8 * Certificate,IN UINTN CertSize)1143 IsCertHashFoundInDbx (
1144   IN  UINT8               *Certificate,
1145   IN  UINTN               CertSize
1146   )
1147 {
1148   BOOLEAN                 IsFound;
1149   EFI_STATUS              Status;
1150   EFI_SIGNATURE_LIST      *DbxList;
1151   EFI_SIGNATURE_DATA      *CertHash;
1152   UINTN                   CertHashCount;
1153   UINTN                   Index;
1154   UINT32                  HashAlg;
1155   UINT8                   CertDigest[MAX_DIGEST_SIZE];
1156   UINT8                   *DbxCertHash;
1157   UINTN                   SiglistHeaderSize;
1158   UINT8                   *Data;
1159   UINTN                   DataSize;
1160 
1161   IsFound  = FALSE;
1162   HashAlg  = HASHALG_MAX;
1163   Data     = NULL;
1164 
1165   //
1166   // Read signature database variable.
1167   //
1168   DataSize  = 0;
1169   Status    = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1170   if (Status != EFI_BUFFER_TOO_SMALL) {
1171     return FALSE;
1172   }
1173 
1174   Data = (UINT8 *) AllocateZeroPool (DataSize);
1175   if (Data == NULL) {
1176     return FALSE;
1177   }
1178 
1179   Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1180   if (EFI_ERROR (Status)) {
1181     goto Done;
1182   }
1183 
1184   //
1185   // Check whether the certificate hash exists in the forbidden database.
1186   //
1187   DbxList = (EFI_SIGNATURE_LIST *) Data;
1188   while ((DataSize > 0) && (DataSize >= DbxList->SignatureListSize)) {
1189     //
1190     // Determine Hash Algorithm of Certificate in the forbidden database.
1191     //
1192     if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
1193       HashAlg = HASHALG_SHA256;
1194     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
1195       HashAlg = HASHALG_SHA384;
1196     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
1197       HashAlg = HASHALG_SHA512;
1198     } else {
1199       DataSize -= DbxList->SignatureListSize;
1200       DbxList   = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1201       continue;
1202     }
1203 
1204     //
1205     // Calculate the hash value of current db certificate for comparision.
1206     //
1207     if (!CalculateCertHash (Certificate, CertSize, HashAlg, CertDigest)) {
1208       goto Done;
1209     }
1210 
1211     SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
1212     CertHash          = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
1213     CertHashCount     = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
1214     for (Index = 0; Index < CertHashCount; Index++) {
1215       //
1216       // Iterate each Signature Data Node within this CertList for verify.
1217       //
1218       DbxCertHash = CertHash->SignatureData;
1219       if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
1220         //
1221         // Hash of Certificate is found in forbidden database.
1222         //
1223         IsFound = TRUE;
1224         goto Done;
1225       }
1226       CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
1227     }
1228 
1229     DataSize -= DbxList->SignatureListSize;
1230     DbxList   = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1231   }
1232 
1233 Done:
1234   if (Data != NULL) {
1235     FreePool (Data);
1236   }
1237 
1238   return IsFound;
1239 }
1240 
1241 /**
1242   Check whether the signature list exists in given variable data.
1243 
1244   It searches the signature list for the ceritificate hash by CertType.
1245   If the signature list is found, get the offset of Database for the
1246   next hash of a certificate.
1247 
1248   @param[in]  Database      Variable data to save signature list.
1249   @param[in]  DatabaseSize  Variable size.
1250   @param[in]  SignatureType The type of the signature.
1251   @param[out] Offset        The offset to save a new hash of certificate.
1252 
1253   @return TRUE       The signature list is found in the forbidden database.
1254   @return FALSE      The signature list is not found in the forbidden database.
1255 **/
1256 BOOLEAN
GetSignaturelistOffset(IN EFI_SIGNATURE_LIST * Database,IN UINTN DatabaseSize,IN EFI_GUID * SignatureType,OUT UINTN * Offset)1257 GetSignaturelistOffset (
1258   IN  EFI_SIGNATURE_LIST  *Database,
1259   IN  UINTN               DatabaseSize,
1260   IN  EFI_GUID            *SignatureType,
1261   OUT UINTN               *Offset
1262   )
1263 {
1264   EFI_SIGNATURE_LIST      *SigList;
1265   UINTN                   SiglistSize;
1266 
1267   if ((Database == NULL) || (DatabaseSize == 0)) {
1268     *Offset = 0;
1269     return FALSE;
1270   }
1271 
1272   SigList     = Database;
1273   SiglistSize = DatabaseSize;
1274   while ((SiglistSize > 0) && (SiglistSize >= SigList->SignatureListSize)) {
1275     if (CompareGuid (&SigList->SignatureType, SignatureType)) {
1276       *Offset = DatabaseSize - SiglistSize;
1277       return TRUE;
1278     }
1279     SiglistSize -= SigList->SignatureListSize;
1280     SigList      = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
1281   }
1282   *Offset = 0;
1283   return FALSE;
1284 }
1285 
1286 /**
1287   Enroll a new X509 certificate hash into Signature Database (dbx) without
1288   KEK's authentication.
1289 
1290   @param[in] PrivateData      The module's private data.
1291   @param[in] HashAlg          The hash algorithm to enroll the certificate.
1292   @param[in] RevocationDate   The revocation date of the certificate.
1293   @param[in] RevocationTime   The revocation time of the certificate.
1294   @param[in] AlwaysRevocation Indicate whether the certificate is always revoked.
1295 
1296   @retval   EFI_SUCCESS            New X509 is enrolled successfully.
1297   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
1298   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
1299 
1300 **/
1301 EFI_STATUS
EnrollX509HashtoSigDB(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN UINT32 HashAlg,IN EFI_HII_DATE * RevocationDate,IN EFI_HII_TIME * RevocationTime,IN BOOLEAN AlwaysRevocation)1302 EnrollX509HashtoSigDB (
1303   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1304   IN UINT32                         HashAlg,
1305   IN EFI_HII_DATE                   *RevocationDate,
1306   IN EFI_HII_TIME                   *RevocationTime,
1307   IN BOOLEAN                        AlwaysRevocation
1308   )
1309 {
1310   EFI_STATUS          Status;
1311   UINTN               X509DataSize;
1312   VOID                *X509Data;
1313   EFI_SIGNATURE_LIST  *SignatureList;
1314   UINTN               SignatureListSize;
1315   UINT8               *Data;
1316   UINT8               *NewData;
1317   UINTN               DataSize;
1318   UINTN               DbSize;
1319   UINT32              Attr;
1320   EFI_SIGNATURE_DATA  *SignatureData;
1321   UINTN               SignatureSize;
1322   EFI_GUID            SignatureType;
1323   UINTN               Offset;
1324   UINT8               CertHash[MAX_DIGEST_SIZE];
1325   UINT16*             FilePostFix;
1326   UINTN               NameLength;
1327   EFI_TIME            *Time;
1328 
1329   X509DataSize  = 0;
1330   DbSize        = 0;
1331   X509Data      = NULL;
1332   SignatureData = NULL;
1333   SignatureList = NULL;
1334   Data          = NULL;
1335   NewData       = NULL;
1336 
1337   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
1338     return EFI_INVALID_PARAMETER;
1339   }
1340 
1341   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
1342   if (EFI_ERROR (Status)) {
1343     return Status;
1344   }
1345 
1346   //
1347   // Parse the file's postfix.
1348   //
1349   NameLength = StrLen (Private->FileContext->FileName);
1350   if (NameLength <= 4) {
1351     return EFI_INVALID_PARAMETER;
1352   }
1353   FilePostFix = Private->FileContext->FileName + NameLength - 4;
1354   if (!IsDerEncodeCertificate(FilePostFix)) {
1355     //
1356     // Only supports DER-encoded X509 certificate.
1357     //
1358     return EFI_INVALID_PARAMETER;
1359   }
1360 
1361   //
1362   // Get the certificate from file and calculate its hash.
1363   //
1364   Status = ReadFileContent (
1365              Private->FileContext->FHandle,
1366              &X509Data,
1367              &X509DataSize,
1368              0
1369              );
1370   if (EFI_ERROR (Status)) {
1371     goto ON_EXIT;
1372   }
1373   ASSERT (X509Data != NULL);
1374 
1375   if (!CalculateCertHash (X509Data, X509DataSize, HashAlg, CertHash)) {
1376     goto ON_EXIT;
1377   }
1378 
1379   //
1380   // Get the variable for enrollment.
1381   //
1382   DataSize = 0;
1383   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1384   if (Status == EFI_BUFFER_TOO_SMALL) {
1385     Data = (UINT8 *) AllocateZeroPool (DataSize);
1386     if (Data == NULL) {
1387       return EFI_OUT_OF_RESOURCES;
1388     }
1389 
1390     Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1391     if (EFI_ERROR (Status)) {
1392       goto ON_EXIT;
1393     }
1394   }
1395 
1396   //
1397   // Allocate memory for Signature and fill the Signature
1398   //
1399   SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + sizeof (EFI_TIME) + mHash[HashAlg].DigestLength;
1400   SignatureData = (EFI_SIGNATURE_DATA *) AllocateZeroPool (SignatureSize);
1401   if (SignatureData == NULL) {
1402     return EFI_OUT_OF_RESOURCES;
1403   }
1404   CopyGuid (&SignatureData->SignatureOwner, Private->SignatureGUID);
1405   CopyMem (SignatureData->SignatureData, CertHash, mHash[HashAlg].DigestLength);
1406 
1407   //
1408   // Fill the time.
1409   //
1410   if (!AlwaysRevocation) {
1411     Time = (EFI_TIME *)(&SignatureData->SignatureData + mHash[HashAlg].DigestLength);
1412     Time->Year   = RevocationDate->Year;
1413     Time->Month  = RevocationDate->Month;
1414     Time->Day    = RevocationDate->Day;
1415     Time->Hour   = RevocationTime->Hour;
1416     Time->Minute = RevocationTime->Minute;
1417     Time->Second = RevocationTime->Second;
1418   }
1419 
1420   //
1421   // Determine the GUID for certificate hash.
1422   //
1423   switch (HashAlg) {
1424   case HASHALG_SHA256:
1425     SignatureType = gEfiCertX509Sha256Guid;
1426     break;
1427   case HASHALG_SHA384:
1428     SignatureType = gEfiCertX509Sha384Guid;
1429     break;
1430   case HASHALG_SHA512:
1431     SignatureType = gEfiCertX509Sha512Guid;
1432     break;
1433   default:
1434     return FALSE;
1435   }
1436 
1437   //
1438   // Add signature into the new variable data buffer
1439   //
1440   if (GetSignaturelistOffset((EFI_SIGNATURE_LIST *)Data, DataSize, &SignatureType, &Offset)) {
1441     //
1442     // Add the signature to the found signaturelist.
1443     //
1444     DbSize  = DataSize + SignatureSize;
1445     NewData = AllocateZeroPool (DbSize);
1446     if (NewData == NULL) {
1447       Status = EFI_OUT_OF_RESOURCES;
1448       goto ON_EXIT;
1449     }
1450 
1451     SignatureList     = (EFI_SIGNATURE_LIST *)(Data + Offset);
1452     SignatureListSize = (UINTN) ReadUnaligned32 ((UINT32 *)&SignatureList->SignatureListSize);
1453     CopyMem (NewData, Data, Offset + SignatureListSize);
1454 
1455     SignatureList = (EFI_SIGNATURE_LIST *)(NewData + Offset);
1456     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32)(SignatureListSize + SignatureSize));
1457 
1458     Offset += SignatureListSize;
1459     CopyMem (NewData + Offset, SignatureData, SignatureSize);
1460     CopyMem (NewData + Offset + SignatureSize, Data + Offset, DataSize - Offset);
1461 
1462     FreePool (Data);
1463     Data     = NewData;
1464     DataSize = DbSize;
1465   } else {
1466     //
1467     // Create a new signaturelist, and add the signature into the signaturelist.
1468     //
1469     DbSize  = DataSize + sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
1470     NewData = AllocateZeroPool (DbSize);
1471     if (NewData == NULL) {
1472       Status = EFI_OUT_OF_RESOURCES;
1473       goto ON_EXIT;
1474     }
1475     //
1476     // Fill Certificate Database parameters.
1477     //
1478     SignatureList     = (EFI_SIGNATURE_LIST*) (NewData + DataSize);
1479     SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
1480     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32) SignatureListSize);
1481     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureSize, (UINT32) SignatureSize);
1482     CopyGuid (&SignatureList->SignatureType, &SignatureType);
1483     CopyMem ((UINT8* ) SignatureList + sizeof (EFI_SIGNATURE_LIST), SignatureData, SignatureSize);
1484     if ((DataSize != 0) && (Data != NULL)) {
1485       CopyMem (NewData, Data, DataSize);
1486       FreePool (Data);
1487     }
1488     Data     = NewData;
1489     DataSize = DbSize;
1490   }
1491 
1492   Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &Data);
1493   if (EFI_ERROR (Status)) {
1494     goto ON_EXIT;
1495   }
1496 
1497   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
1498           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1499   Status = gRT->SetVariable(
1500                   EFI_IMAGE_SECURITY_DATABASE1,
1501                   &gEfiImageSecurityDatabaseGuid,
1502                   Attr,
1503                   DataSize,
1504                   Data
1505                   );
1506   if (EFI_ERROR (Status)) {
1507     goto ON_EXIT;
1508   }
1509 
1510 ON_EXIT:
1511   CloseFile (Private->FileContext->FHandle);
1512   Private->FileContext->FileName = NULL;
1513   Private->FileContext->FHandle = NULL;
1514 
1515   if (Private->SignatureGUID != NULL) {
1516     FreePool (Private->SignatureGUID);
1517     Private->SignatureGUID = NULL;
1518   }
1519 
1520   if (Data != NULL) {
1521     FreePool (Data);
1522   }
1523 
1524   if (SignatureData != NULL) {
1525     FreePool (SignatureData);
1526   }
1527 
1528   if (X509Data != NULL) {
1529     FreePool (X509Data);
1530   }
1531 
1532   return Status;
1533 }
1534 
1535 /**
1536   Check whether a certificate from a file exists in dbx.
1537 
1538   @param[in] PrivateData     The module's private data.
1539   @param[in] VariableName    Variable name of signature database, must be
1540                              EFI_IMAGE_SECURITY_DATABASE1.
1541 
1542   @retval   TRUE             The X509 certificate is found in dbx successfully.
1543   @retval   FALSE            The X509 certificate is not found in dbx.
1544 **/
1545 BOOLEAN
IsX509CertInDbx(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)1546 IsX509CertInDbx (
1547   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1548   IN CHAR16                         *VariableName
1549   )
1550 {
1551   EFI_STATUS          Status;
1552   UINTN               X509DataSize;
1553   VOID                *X509Data;
1554   BOOLEAN             IsFound;
1555 
1556   //
1557   //  Read the certificate from file
1558   //
1559   X509DataSize  = 0;
1560   X509Data      = NULL;
1561   Status = ReadFileContent (
1562              Private->FileContext->FHandle,
1563              &X509Data,
1564              &X509DataSize,
1565              0
1566              );
1567   if (EFI_ERROR (Status)) {
1568     return FALSE;
1569   }
1570 
1571   //
1572   // Check the raw certificate.
1573   //
1574   IsFound = FALSE;
1575   if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, X509Data, X509DataSize)) {
1576     IsFound = TRUE;
1577     goto ON_EXIT;
1578   }
1579 
1580   //
1581   // Check the hash of certificate.
1582   //
1583   if (IsCertHashFoundInDbx (X509Data, X509DataSize)) {
1584     IsFound = TRUE;
1585     goto ON_EXIT;
1586   }
1587 
1588 ON_EXIT:
1589   if (X509Data != NULL) {
1590     FreePool (X509Data);
1591   }
1592 
1593   return IsFound;
1594 }
1595 
1596 /**
1597   Load PE/COFF image information into internal buffer and check its validity.
1598 
1599   @retval   EFI_SUCCESS         Successful
1600   @retval   EFI_UNSUPPORTED     Invalid PE/COFF file
1601   @retval   EFI_ABORTED         Serious error occurs, like file I/O error etc.
1602 
1603 **/
1604 EFI_STATUS
LoadPeImage(VOID)1605 LoadPeImage (
1606   VOID
1607   )
1608 {
1609   EFI_IMAGE_DOS_HEADER                  *DosHdr;
1610   EFI_IMAGE_NT_HEADERS32                *NtHeader32;
1611   EFI_IMAGE_NT_HEADERS64                *NtHeader64;
1612 
1613   NtHeader32 = NULL;
1614   NtHeader64 = NULL;
1615   //
1616   // Read the Dos header
1617   //
1618   DosHdr = (EFI_IMAGE_DOS_HEADER*)(mImageBase);
1619   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
1620   {
1621     //
1622     // DOS image header is present,
1623     // So read the PE header after the DOS image header
1624     //
1625     mPeCoffHeaderOffset = DosHdr->e_lfanew;
1626   }
1627   else
1628   {
1629     mPeCoffHeaderOffset = 0;
1630   }
1631 
1632   //
1633   // Read PE header and check the signature validity and machine compatibility
1634   //
1635   NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset);
1636   if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE)
1637   {
1638     return EFI_UNSUPPORTED;
1639   }
1640 
1641   mNtHeader.Pe32 = NtHeader32;
1642 
1643   //
1644   // Check the architecture field of PE header and get the Certificate Data Directory data
1645   // Note the size of FileHeader field is constant for both IA32 and X64 arch
1646   //
1647   if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32)
1648       || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)
1649       || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {
1650     //
1651     // 32-bits Architecture
1652     //
1653     mImageType = ImageType_IA32;
1654     mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
1655   }
1656   else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)
1657           || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)
1658           || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
1659     //
1660     // 64-bits Architecture
1661     //
1662     mImageType = ImageType_X64;
1663     NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);
1664     mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
1665   } else {
1666     return EFI_UNSUPPORTED;
1667   }
1668 
1669   return EFI_SUCCESS;
1670 }
1671 
1672 /**
1673   Calculate hash of Pe/Coff image based on the authenticode image hashing in
1674   PE/COFF Specification 8.0 Appendix A
1675 
1676   @param[in]    HashAlg   Hash algorithm type.
1677 
1678   @retval TRUE            Successfully hash image.
1679   @retval FALSE           Fail in hash image.
1680 
1681 **/
1682 BOOLEAN
HashPeImage(IN UINT32 HashAlg)1683 HashPeImage (
1684   IN  UINT32                HashAlg
1685   )
1686 {
1687   BOOLEAN                   Status;
1688   UINT16                    Magic;
1689   EFI_IMAGE_SECTION_HEADER  *Section;
1690   VOID                      *HashCtx;
1691   UINTN                     CtxSize;
1692   UINT8                     *HashBase;
1693   UINTN                     HashSize;
1694   UINTN                     SumOfBytesHashed;
1695   EFI_IMAGE_SECTION_HEADER  *SectionHeader;
1696   UINTN                     Index;
1697   UINTN                     Pos;
1698 
1699   HashCtx       = NULL;
1700   SectionHeader = NULL;
1701   Status        = FALSE;
1702 
1703   if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {
1704     return FALSE;
1705   }
1706 
1707   //
1708   // Initialize context of hash.
1709   //
1710   ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
1711 
1712   if (HashAlg == HASHALG_SHA1) {
1713     mImageDigestSize  = SHA1_DIGEST_SIZE;
1714     mCertType         = gEfiCertSha1Guid;
1715   } else if (HashAlg == HASHALG_SHA256) {
1716     mImageDigestSize  = SHA256_DIGEST_SIZE;
1717     mCertType         = gEfiCertSha256Guid;
1718   }
1719 
1720   CtxSize   = mHash[HashAlg].GetContextSize();
1721 
1722   HashCtx = AllocatePool (CtxSize);
1723   ASSERT (HashCtx != NULL);
1724 
1725   // 1.  Load the image header into memory.
1726 
1727   // 2.  Initialize a SHA hash context.
1728   Status = mHash[HashAlg].HashInit(HashCtx);
1729   if (!Status) {
1730     goto Done;
1731   }
1732   //
1733   // Measuring PE/COFF Image Header;
1734   // But CheckSum field and SECURITY data directory (certificate) are excluded
1735   //
1736   if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1737     //
1738     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
1739     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
1740     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
1741     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
1742     //
1743     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1744   } else {
1745     //
1746     // Get the magic value from the PE/COFF Optional Header
1747     //
1748     Magic = mNtHeader.Pe32->OptionalHeader.Magic;
1749   }
1750 
1751   //
1752   // 3.  Calculate the distance from the base of the image header to the image checksum address.
1753   // 4.  Hash the image header from its base to beginning of the image checksum.
1754   //
1755   HashBase = mImageBase;
1756   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1757     //
1758     // Use PE32 offset.
1759     //
1760     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);
1761   } else {
1762     //
1763     // Use PE32+ offset.
1764     //
1765     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
1766   }
1767 
1768   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1769   if (!Status) {
1770     goto Done;
1771   }
1772   //
1773   // 5.  Skip over the image checksum (it occupies a single ULONG).
1774   // 6.  Get the address of the beginning of the Cert Directory.
1775   // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
1776   //
1777   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1778     //
1779     // Use PE32 offset.
1780     //
1781     HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
1782     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
1783   } else {
1784     //
1785     // Use PE32+ offset.
1786     //
1787     HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
1788     HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
1789   }
1790 
1791   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1792   if (!Status) {
1793     goto Done;
1794   }
1795   //
1796   // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
1797   // 9.  Hash everything from the end of the Cert Directory to the end of image header.
1798   //
1799   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1800     //
1801     // Use PE32 offset
1802     //
1803     HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
1804     HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);
1805   } else {
1806     //
1807     // Use PE32+ offset.
1808     //
1809     HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
1810     HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);
1811   }
1812 
1813   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1814   if (!Status) {
1815     goto Done;
1816   }
1817   //
1818   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
1819   //
1820   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1821     //
1822     // Use PE32 offset.
1823     //
1824     SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
1825   } else {
1826     //
1827     // Use PE32+ offset
1828     //
1829     SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
1830   }
1831 
1832   //
1833   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
1834   //     structures in the image. The 'NumberOfSections' field of the image
1835   //     header indicates how big the table should be. Do not include any
1836   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
1837   //
1838   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
1839   ASSERT (SectionHeader != NULL);
1840   //
1841   // 12.  Using the 'PointerToRawData' in the referenced section headers as
1842   //      a key, arrange the elements in the table in ascending order. In other
1843   //      words, sort the section headers according to the disk-file offset of
1844   //      the section.
1845   //
1846   Section = (EFI_IMAGE_SECTION_HEADER *) (
1847                mImageBase +
1848                mPeCoffHeaderOffset +
1849                sizeof (UINT32) +
1850                sizeof (EFI_IMAGE_FILE_HEADER) +
1851                mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
1852                );
1853   for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
1854     Pos = Index;
1855     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
1856       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
1857       Pos--;
1858     }
1859     CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
1860     Section += 1;
1861   }
1862 
1863   //
1864   // 13.  Walk through the sorted table, bring the corresponding section
1865   //      into memory, and hash the entire section (using the 'SizeOfRawData'
1866   //      field in the section header to determine the amount of data to hash).
1867   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
1868   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
1869   //
1870   for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
1871     Section = &SectionHeader[Index];
1872     if (Section->SizeOfRawData == 0) {
1873       continue;
1874     }
1875     HashBase  = mImageBase + Section->PointerToRawData;
1876     HashSize  = (UINTN) Section->SizeOfRawData;
1877 
1878     Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1879     if (!Status) {
1880       goto Done;
1881     }
1882 
1883     SumOfBytesHashed += HashSize;
1884   }
1885 
1886   //
1887   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
1888   //      data in the file that needs to be added to the hash. This data begins
1889   //      at file offset SUM_OF_BYTES_HASHED and its length is:
1890   //             FileSize  -  (CertDirectory->Size)
1891   //
1892   if (mImageSize > SumOfBytesHashed) {
1893     HashBase = mImageBase + SumOfBytesHashed;
1894     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1895       //
1896       // Use PE32 offset.
1897       //
1898       HashSize = (UINTN)(
1899                  mImageSize -
1900                  mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
1901                  SumOfBytesHashed);
1902     } else {
1903       //
1904       // Use PE32+ offset.
1905       //
1906       HashSize = (UINTN)(
1907                  mImageSize -
1908                  mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
1909                  SumOfBytesHashed);
1910     }
1911 
1912     Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1913     if (!Status) {
1914       goto Done;
1915     }
1916   }
1917 
1918   Status  = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
1919 
1920 Done:
1921   if (HashCtx != NULL) {
1922     FreePool (HashCtx);
1923   }
1924   if (SectionHeader != NULL) {
1925     FreePool (SectionHeader);
1926   }
1927   return Status;
1928 }
1929 
1930 /**
1931   Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of
1932   Pe/Coff image based on the authenticated image hashing in PE/COFF Specification
1933   8.0 Appendix A
1934 
1935   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.
1936   @retval EFI_SUCCESS                 Hash successfully.
1937 
1938 **/
1939 EFI_STATUS
HashPeImageByType(VOID)1940 HashPeImageByType (
1941   VOID
1942   )
1943 {
1944   UINT8                     Index;
1945   WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;
1946 
1947   PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset);
1948 
1949   for (Index = 0; Index < HASHALG_MAX; Index++) {
1950     //
1951     // Check the Hash algorithm in PE/COFF Authenticode.
1952     //    According to PKCS#7 Definition:
1953     //        SignedData ::= SEQUENCE {
1954     //            version Version,
1955     //            digestAlgorithms DigestAlgorithmIdentifiers,
1956     //            contentInfo ContentInfo,
1957     //            .... }
1958     //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
1959     //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.
1960     //    Fixed offset (+32) is calculated based on two bytes of length encoding.
1961      //
1962     if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
1963       //
1964       // Only support two bytes of Long Form of Length Encoding.
1965       //
1966       continue;
1967     }
1968 
1969     //
1970     if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
1971       break;
1972     }
1973   }
1974 
1975   if (Index == HASHALG_MAX) {
1976     return EFI_UNSUPPORTED;
1977   }
1978 
1979   //
1980   // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
1981   //
1982   if (!HashPeImage(Index)) {
1983     return EFI_UNSUPPORTED;
1984   }
1985 
1986   return EFI_SUCCESS;
1987 }
1988 
1989 /**
1990   Enroll a new executable's signature into Signature Database.
1991 
1992   @param[in] PrivateData     The module's private data.
1993   @param[in] VariableName    Variable name of signature database, must be
1994                              EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
1995                              or EFI_IMAGE_SECURITY_DATABASE2.
1996 
1997   @retval   EFI_SUCCESS            New signature is enrolled successfully.
1998   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
1999   @retval   EFI_UNSUPPORTED        Unsupported command.
2000   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
2001 
2002 **/
2003 EFI_STATUS
EnrollImageSignatureToSigDB(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)2004 EnrollImageSignatureToSigDB (
2005   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
2006   IN CHAR16                         *VariableName
2007   )
2008 {
2009   EFI_STATUS                        Status;
2010   EFI_SIGNATURE_LIST                *SigDBCert;
2011   EFI_SIGNATURE_DATA                *SigDBCertData;
2012   VOID                              *Data;
2013   UINTN                             DataSize;
2014   UINTN                             SigDBSize;
2015   UINT32                            Attr;
2016   WIN_CERTIFICATE_UEFI_GUID         *GuidCertData;
2017 
2018   Data = NULL;
2019   GuidCertData = NULL;
2020 
2021   if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
2022     return EFI_UNSUPPORTED;
2023   }
2024 
2025   //
2026   // Form the SigDB certificate list.
2027   // Format the data item into EFI_SIGNATURE_LIST type.
2028   //
2029   // We need to parse executable's signature data from specified signed executable file.
2030   // In current implementation, we simply trust the pass-in signed executable file.
2031   // In reality, it's OS's responsibility to verify the signed executable file.
2032   //
2033 
2034   //
2035   // Read the whole file content
2036   //
2037   Status = ReadFileContent(
2038              Private->FileContext->FHandle,
2039              (VOID **) &mImageBase,
2040              &mImageSize,
2041              0
2042              );
2043   if (EFI_ERROR (Status)) {
2044     goto ON_EXIT;
2045   }
2046   ASSERT (mImageBase != NULL);
2047 
2048   Status = LoadPeImage ();
2049   if (EFI_ERROR (Status)) {
2050     goto ON_EXIT;
2051   }
2052 
2053   if (mSecDataDir->SizeOfCert == 0) {
2054     if (!HashPeImage (HASHALG_SHA256)) {
2055       Status =  EFI_SECURITY_VIOLATION;
2056       goto ON_EXIT;
2057     }
2058   } else {
2059 
2060     //
2061     // Read the certificate data
2062     //
2063     mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);
2064 
2065     if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
2066       GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;
2067       if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {
2068         Status = EFI_ABORTED;
2069         goto ON_EXIT;
2070       }
2071 
2072       if (!HashPeImage (HASHALG_SHA256)) {
2073         Status = EFI_ABORTED;
2074         goto ON_EXIT;;
2075       }
2076 
2077     } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
2078 
2079       Status = HashPeImageByType ();
2080       if (EFI_ERROR (Status)) {
2081         goto ON_EXIT;;
2082       }
2083     } else {
2084       Status = EFI_ABORTED;
2085       goto ON_EXIT;
2086     }
2087   }
2088 
2089   //
2090   // Create a new SigDB entry.
2091   //
2092   SigDBSize = sizeof(EFI_SIGNATURE_LIST)
2093               + sizeof(EFI_SIGNATURE_DATA) - 1
2094               + (UINT32) mImageDigestSize;
2095 
2096   Data = (UINT8*) AllocateZeroPool (SigDBSize);
2097   if (Data == NULL) {
2098     Status = EFI_OUT_OF_RESOURCES;
2099     goto ON_EXIT;
2100   }
2101 
2102   //
2103   // Adjust the Certificate Database parameters.
2104   //
2105   SigDBCert = (EFI_SIGNATURE_LIST*) Data;
2106   SigDBCert->SignatureListSize   = (UINT32) SigDBSize;
2107   SigDBCert->SignatureHeaderSize = 0;
2108   SigDBCert->SignatureSize       = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;
2109   CopyGuid (&SigDBCert->SignatureType, &mCertType);
2110 
2111   SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));
2112   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
2113   CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);
2114 
2115   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
2116           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2117   Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
2118   if (EFI_ERROR (Status)) {
2119     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2120     goto ON_EXIT;
2121   }
2122 
2123   //
2124   // Check if SigDB variable has been already existed.
2125   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
2126   // new signature data to original variable
2127   //
2128   DataSize = 0;
2129   Status = gRT->GetVariable(
2130                   VariableName,
2131                   &gEfiImageSecurityDatabaseGuid,
2132                   NULL,
2133                   &DataSize,
2134                   NULL
2135                   );
2136   if (Status == EFI_BUFFER_TOO_SMALL) {
2137     Attr |= EFI_VARIABLE_APPEND_WRITE;
2138   } else if (Status != EFI_NOT_FOUND) {
2139     goto ON_EXIT;
2140   }
2141 
2142   //
2143   // Enroll the variable.
2144   //
2145   Status = gRT->SetVariable(
2146                   VariableName,
2147                   &gEfiImageSecurityDatabaseGuid,
2148                   Attr,
2149                   SigDBSize,
2150                   Data
2151                   );
2152   if (EFI_ERROR (Status)) {
2153     goto ON_EXIT;
2154   }
2155 
2156 ON_EXIT:
2157 
2158   CloseFile (Private->FileContext->FHandle);
2159   Private->FileContext->FHandle = NULL;
2160   Private->FileContext->FileName = NULL;
2161 
2162   if (Private->SignatureGUID != NULL) {
2163     FreePool (Private->SignatureGUID);
2164     Private->SignatureGUID = NULL;
2165   }
2166 
2167   if (Data != NULL) {
2168     FreePool (Data);
2169   }
2170 
2171   if (mImageBase != NULL) {
2172     FreePool (mImageBase);
2173     mImageBase = NULL;
2174   }
2175 
2176   return Status;
2177 }
2178 
2179 /**
2180   Enroll signature into DB/DBX/DBT without KEK's authentication.
2181   The SignatureOwner GUID will be Private->SignatureGUID.
2182 
2183   @param[in] PrivateData     The module's private data.
2184   @param[in] VariableName    Variable name of signature database, must be
2185                              EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
2186 
2187   @retval   EFI_SUCCESS            New signature enrolled successfully.
2188   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
2189   @retval   others                 Fail to enroll signature data.
2190 
2191 **/
2192 EFI_STATUS
EnrollSignatureDatabase(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)2193 EnrollSignatureDatabase (
2194   IN SECUREBOOT_CONFIG_PRIVATE_DATA     *Private,
2195   IN CHAR16                             *VariableName
2196   )
2197 {
2198   UINT16*      FilePostFix;
2199   EFI_STATUS   Status;
2200   UINTN        NameLength;
2201 
2202   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
2203     return EFI_INVALID_PARAMETER;
2204   }
2205 
2206   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
2207   if (EFI_ERROR (Status)) {
2208     return Status;
2209   }
2210 
2211   //
2212   // Parse the file's postfix.
2213   //
2214   NameLength = StrLen (Private->FileContext->FileName);
2215   if (NameLength <= 4) {
2216     return EFI_INVALID_PARAMETER;
2217   }
2218   FilePostFix = Private->FileContext->FileName + NameLength - 4;
2219   if (IsDerEncodeCertificate (FilePostFix)) {
2220     //
2221     // Supports DER-encoded X509 certificate.
2222     //
2223     return EnrollX509toSigDB (Private, VariableName);
2224   }
2225 
2226   return EnrollImageSignatureToSigDB (Private, VariableName);
2227 }
2228 
2229 /**
2230   List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)
2231   by GUID in the page for user to select and delete as needed.
2232 
2233   @param[in]    PrivateData         Module's private data.
2234   @param[in]    VariableName        The variable name of the vendor's signature database.
2235   @param[in]    VendorGuid          A unique identifier for the vendor.
2236   @param[in]    LabelNumber         Label number to insert opcodes.
2237   @param[in]    FormId              Form ID of current page.
2238   @param[in]    QuestionIdBase      Base question id of the signature list.
2239 
2240   @retval   EFI_SUCCESS             Success to update the signature list page
2241   @retval   EFI_OUT_OF_RESOURCES    Unable to allocate required resources.
2242 
2243 **/
2244 EFI_STATUS
UpdateDeletePage(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT16 LabelNumber,IN EFI_FORM_ID FormId,IN EFI_QUESTION_ID QuestionIdBase)2245 UpdateDeletePage (
2246   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
2247   IN CHAR16                           *VariableName,
2248   IN EFI_GUID                         *VendorGuid,
2249   IN UINT16                           LabelNumber,
2250   IN EFI_FORM_ID                      FormId,
2251   IN EFI_QUESTION_ID                  QuestionIdBase
2252   )
2253 {
2254   EFI_STATUS                  Status;
2255   UINT32                      Index;
2256   UINTN                       CertCount;
2257   UINTN                       GuidIndex;
2258   VOID                        *StartOpCodeHandle;
2259   VOID                        *EndOpCodeHandle;
2260   EFI_IFR_GUID_LABEL          *StartLabel;
2261   EFI_IFR_GUID_LABEL          *EndLabel;
2262   UINTN                       DataSize;
2263   UINT8                       *Data;
2264   EFI_SIGNATURE_LIST          *CertList;
2265   EFI_SIGNATURE_DATA          *Cert;
2266   UINT32                      ItemDataSize;
2267   CHAR16                      *GuidStr;
2268   EFI_STRING_ID               GuidID;
2269   EFI_STRING_ID               Help;
2270 
2271   Data     = NULL;
2272   CertList = NULL;
2273   Cert     = NULL;
2274   GuidStr  = NULL;
2275   StartOpCodeHandle = NULL;
2276   EndOpCodeHandle   = NULL;
2277 
2278   //
2279   // Initialize the container for dynamic opcodes.
2280   //
2281   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
2282   if (StartOpCodeHandle == NULL) {
2283     Status = EFI_OUT_OF_RESOURCES;
2284     goto ON_EXIT;
2285   }
2286 
2287   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
2288   if (EndOpCodeHandle == NULL) {
2289     Status = EFI_OUT_OF_RESOURCES;
2290     goto ON_EXIT;
2291   }
2292 
2293   //
2294   // Create Hii Extend Label OpCode.
2295   //
2296   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
2297                                         StartOpCodeHandle,
2298                                         &gEfiIfrTianoGuid,
2299                                         NULL,
2300                                         sizeof (EFI_IFR_GUID_LABEL)
2301                                         );
2302   StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
2303   StartLabel->Number        = LabelNumber;
2304 
2305   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
2306                                       EndOpCodeHandle,
2307                                       &gEfiIfrTianoGuid,
2308                                       NULL,
2309                                       sizeof (EFI_IFR_GUID_LABEL)
2310                                       );
2311   EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
2312   EndLabel->Number        = LABEL_END;
2313 
2314   //
2315   // Read Variable.
2316   //
2317   DataSize = 0;
2318   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
2319   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
2320     goto ON_EXIT;
2321   }
2322 
2323   Data = (UINT8 *) AllocateZeroPool (DataSize);
2324   if (Data == NULL) {
2325     Status = EFI_OUT_OF_RESOURCES;
2326     goto ON_EXIT;
2327   }
2328 
2329   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
2330   if (EFI_ERROR (Status)) {
2331     goto ON_EXIT;
2332   }
2333 
2334   GuidStr = AllocateZeroPool (100);
2335   if (GuidStr == NULL) {
2336     Status = EFI_OUT_OF_RESOURCES;
2337     goto ON_EXIT;
2338   }
2339 
2340   //
2341   // Enumerate all KEK pub data.
2342   //
2343   ItemDataSize = (UINT32) DataSize;
2344   CertList = (EFI_SIGNATURE_LIST *) Data;
2345   GuidIndex = 0;
2346 
2347   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2348 
2349     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {
2350       Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);
2351     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2352       Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);
2353     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {
2354       Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);
2355     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {
2356       Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);
2357     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {
2358       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);
2359     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {
2360       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);
2361     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {
2362       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);
2363     } else {
2364       //
2365       // The signature type is not supported in current implementation.
2366       //
2367       ItemDataSize -= CertList->SignatureListSize;
2368       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2369       continue;
2370     }
2371 
2372     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2373     for (Index = 0; Index < CertCount; Index++) {
2374       Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList
2375                                               + sizeof (EFI_SIGNATURE_LIST)
2376                                               + CertList->SignatureHeaderSize
2377                                               + Index * CertList->SignatureSize);
2378       //
2379       // Display GUID and help
2380       //
2381       GuidToString (&Cert->SignatureOwner, GuidStr, 100);
2382       GuidID  = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);
2383       HiiCreateCheckBoxOpCode (
2384         StartOpCodeHandle,
2385         (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),
2386         0,
2387         0,
2388         GuidID,
2389         Help,
2390         EFI_IFR_FLAG_CALLBACK,
2391         0,
2392         NULL
2393         );
2394     }
2395 
2396     ItemDataSize -= CertList->SignatureListSize;
2397     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2398   }
2399 
2400 ON_EXIT:
2401   HiiUpdateForm (
2402     PrivateData->HiiHandle,
2403     &gSecureBootConfigFormSetGuid,
2404     FormId,
2405     StartOpCodeHandle,
2406     EndOpCodeHandle
2407     );
2408 
2409   if (StartOpCodeHandle != NULL) {
2410     HiiFreeOpCodeHandle (StartOpCodeHandle);
2411   }
2412 
2413   if (EndOpCodeHandle != NULL) {
2414     HiiFreeOpCodeHandle (EndOpCodeHandle);
2415   }
2416 
2417   if (Data != NULL) {
2418     FreePool (Data);
2419   }
2420 
2421   if (GuidStr != NULL) {
2422     FreePool (GuidStr);
2423   }
2424 
2425   return EFI_SUCCESS;
2426 }
2427 
2428 /**
2429   Delete a KEK entry from KEK database.
2430 
2431   @param[in]    PrivateData         Module's private data.
2432   @param[in]    QuestionId          Question id of the KEK item to delete.
2433 
2434   @retval   EFI_SUCCESS            Delete kek item successfully.
2435   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
2436 
2437 **/
2438 EFI_STATUS
DeleteKeyExchangeKey(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN EFI_QUESTION_ID QuestionId)2439 DeleteKeyExchangeKey (
2440   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
2441   IN EFI_QUESTION_ID                  QuestionId
2442   )
2443 {
2444   EFI_STATUS                  Status;
2445   UINTN                       DataSize;
2446   UINT8                       *Data;
2447   UINT8                       *OldData;
2448   UINT32                      Attr;
2449   UINT32                      Index;
2450   EFI_SIGNATURE_LIST          *CertList;
2451   EFI_SIGNATURE_LIST          *NewCertList;
2452   EFI_SIGNATURE_DATA          *Cert;
2453   UINTN                       CertCount;
2454   UINT32                      Offset;
2455   BOOLEAN                     IsKEKItemFound;
2456   UINT32                      KekDataSize;
2457   UINTN                       DeleteKekIndex;
2458   UINTN                       GuidIndex;
2459 
2460   Data            = NULL;
2461   OldData         = NULL;
2462   CertList        = NULL;
2463   Cert            = NULL;
2464   Attr            = 0;
2465   DeleteKekIndex  = QuestionId - OPTION_DEL_KEK_QUESTION_ID;
2466 
2467   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2468   if (EFI_ERROR (Status)) {
2469     return Status;
2470   }
2471 
2472   //
2473   // Get original KEK variable.
2474   //
2475   DataSize = 0;
2476   Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);
2477   if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
2478     goto ON_EXIT;
2479   }
2480 
2481   OldData = (UINT8*)AllocateZeroPool(DataSize);
2482   if (OldData == NULL) {
2483     Status = EFI_OUT_OF_RESOURCES;
2484     goto ON_EXIT;
2485   }
2486 
2487   Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);
2488   if (EFI_ERROR(Status)) {
2489     goto ON_EXIT;
2490   }
2491 
2492   //
2493   // Allocate space for new variable.
2494   //
2495   Data = (UINT8*) AllocateZeroPool (DataSize);
2496   if (Data == NULL) {
2497     Status  =  EFI_OUT_OF_RESOURCES;
2498     goto ON_EXIT;
2499   }
2500 
2501   //
2502   // Enumerate all KEK pub data and erasing the target item.
2503   //
2504   IsKEKItemFound = FALSE;
2505   KekDataSize = (UINT32) DataSize;
2506   CertList = (EFI_SIGNATURE_LIST *) OldData;
2507   Offset = 0;
2508   GuidIndex = 0;
2509   while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2510     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
2511         CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2512       CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
2513       NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);
2514       Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2515       Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2516       CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2517       for (Index = 0; Index < CertCount; Index++) {
2518         if (GuidIndex == DeleteKekIndex ) {
2519           //
2520           // Find it! Skip it!
2521           //
2522           NewCertList->SignatureListSize -= CertList->SignatureSize;
2523           IsKEKItemFound = TRUE;
2524         } else {
2525           //
2526           // This item doesn't match. Copy it to the Data buffer.
2527           //
2528           CopyMem (Data + Offset, Cert, CertList->SignatureSize);
2529           Offset += CertList->SignatureSize;
2530         }
2531         GuidIndex++;
2532         Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);
2533       }
2534     } else {
2535       //
2536       // This List doesn't match. Copy it to the Data buffer.
2537       //
2538       CopyMem (Data + Offset, CertList, CertList->SignatureListSize);
2539       Offset += CertList->SignatureListSize;
2540     }
2541 
2542     KekDataSize -= CertList->SignatureListSize;
2543     CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);
2544   }
2545 
2546   if (!IsKEKItemFound) {
2547     //
2548     // Doesn't find the Kek Item!
2549     //
2550     Status = EFI_NOT_FOUND;
2551     goto ON_EXIT;
2552   }
2553 
2554   //
2555   // Delete the Signature header if there is no signature in the list.
2556   //
2557   KekDataSize = Offset;
2558   CertList = (EFI_SIGNATURE_LIST*) Data;
2559   Offset = 0;
2560   ZeroMem (OldData, KekDataSize);
2561   while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2562     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2563     DEBUG ((DEBUG_INFO, "       CertCount = %x\n", CertCount));
2564     if (CertCount != 0) {
2565       CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);
2566       Offset += CertList->SignatureListSize;
2567     }
2568     KekDataSize -= CertList->SignatureListSize;
2569     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2570   }
2571 
2572   DataSize = Offset;
2573   if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2574     Status = CreateTimeBasedPayload (&DataSize, &OldData);
2575     if (EFI_ERROR (Status)) {
2576       DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2577       goto ON_EXIT;
2578     }
2579   }
2580 
2581   Status = gRT->SetVariable(
2582                   EFI_KEY_EXCHANGE_KEY_NAME,
2583                   &gEfiGlobalVariableGuid,
2584                   Attr,
2585                   DataSize,
2586                   OldData
2587                   );
2588   if (EFI_ERROR (Status)) {
2589     DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
2590     goto ON_EXIT;
2591   }
2592 
2593 ON_EXIT:
2594   if (Data != NULL) {
2595     FreePool(Data);
2596   }
2597 
2598   if (OldData != NULL) {
2599     FreePool(OldData);
2600   }
2601 
2602   return UpdateDeletePage (
2603            PrivateData,
2604            EFI_KEY_EXCHANGE_KEY_NAME,
2605            &gEfiGlobalVariableGuid,
2606            LABEL_KEK_DELETE,
2607            FORMID_DELETE_KEK_FORM,
2608            OPTION_DEL_KEK_QUESTION_ID
2609            );
2610 }
2611 
2612 /**
2613   Delete a signature entry from siganture database.
2614 
2615   @param[in]    PrivateData         Module's private data.
2616   @param[in]    VariableName        The variable name of the vendor's signature database.
2617   @param[in]    VendorGuid          A unique identifier for the vendor.
2618   @param[in]    LabelNumber         Label number to insert opcodes.
2619   @param[in]    FormId              Form ID of current page.
2620   @param[in]    QuestionIdBase      Base question id of the signature list.
2621   @param[in]    DeleteIndex         Signature index to delete.
2622 
2623   @retval   EFI_SUCCESS             Delete siganture successfully.
2624   @retval   EFI_NOT_FOUND           Can't find the signature item,
2625   @retval   EFI_OUT_OF_RESOURCES    Could not allocate needed resources.
2626 **/
2627 EFI_STATUS
DeleteSignature(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT16 LabelNumber,IN EFI_FORM_ID FormId,IN EFI_QUESTION_ID QuestionIdBase,IN UINTN DeleteIndex)2628 DeleteSignature (
2629   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
2630   IN CHAR16                           *VariableName,
2631   IN EFI_GUID                         *VendorGuid,
2632   IN UINT16                           LabelNumber,
2633   IN EFI_FORM_ID                      FormId,
2634   IN EFI_QUESTION_ID                  QuestionIdBase,
2635   IN UINTN                            DeleteIndex
2636   )
2637 {
2638   EFI_STATUS                  Status;
2639   UINTN                       DataSize;
2640   UINT8                       *Data;
2641   UINT8                       *OldData;
2642   UINT32                      Attr;
2643   UINT32                      Index;
2644   EFI_SIGNATURE_LIST          *CertList;
2645   EFI_SIGNATURE_LIST          *NewCertList;
2646   EFI_SIGNATURE_DATA          *Cert;
2647   UINTN                       CertCount;
2648   UINT32                      Offset;
2649   BOOLEAN                     IsItemFound;
2650   UINT32                      ItemDataSize;
2651   UINTN                       GuidIndex;
2652 
2653   Data            = NULL;
2654   OldData         = NULL;
2655   CertList        = NULL;
2656   Cert            = NULL;
2657   Attr            = 0;
2658 
2659   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2660   if (EFI_ERROR (Status)) {
2661     return Status;
2662   }
2663 
2664   //
2665   // Get original signature list data.
2666   //
2667   DataSize = 0;
2668   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);
2669   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
2670     goto ON_EXIT;
2671   }
2672 
2673   OldData = (UINT8 *) AllocateZeroPool (DataSize);
2674   if (OldData == NULL) {
2675     Status = EFI_OUT_OF_RESOURCES;
2676     goto ON_EXIT;
2677   }
2678 
2679   Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData);
2680   if (EFI_ERROR(Status)) {
2681     goto ON_EXIT;
2682   }
2683 
2684   //
2685   // Allocate space for new variable.
2686   //
2687   Data = (UINT8*) AllocateZeroPool (DataSize);
2688   if (Data == NULL) {
2689     Status  =  EFI_OUT_OF_RESOURCES;
2690     goto ON_EXIT;
2691   }
2692 
2693   //
2694   // Enumerate all signature data and erasing the target item.
2695   //
2696   IsItemFound = FALSE;
2697   ItemDataSize = (UINT32) DataSize;
2698   CertList = (EFI_SIGNATURE_LIST *) OldData;
2699   Offset = 0;
2700   GuidIndex = 0;
2701   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2702     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
2703         CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid) ||
2704         CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid) ||
2705         CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid) ||
2706         CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid) ||
2707         CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid) ||
2708         CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)
2709         ) {
2710       //
2711       // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list.
2712       //
2713       CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
2714       NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset);
2715       Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2716       Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2717       CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2718       for (Index = 0; Index < CertCount; Index++) {
2719         if (GuidIndex == DeleteIndex) {
2720           //
2721           // Find it! Skip it!
2722           //
2723           NewCertList->SignatureListSize -= CertList->SignatureSize;
2724           IsItemFound = TRUE;
2725         } else {
2726           //
2727           // This item doesn't match. Copy it to the Data buffer.
2728           //
2729           CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize);
2730           Offset += CertList->SignatureSize;
2731         }
2732         GuidIndex++;
2733         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
2734       }
2735     } else {
2736       //
2737       // This List doesn't match. Just copy it to the Data buffer.
2738       //
2739       CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
2740       Offset += CertList->SignatureListSize;
2741     }
2742 
2743     ItemDataSize -= CertList->SignatureListSize;
2744     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2745   }
2746 
2747   if (!IsItemFound) {
2748     //
2749     // Doesn't find the signature Item!
2750     //
2751     Status = EFI_NOT_FOUND;
2752     goto ON_EXIT;
2753   }
2754 
2755   //
2756   // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list.
2757   //
2758   ItemDataSize = Offset;
2759   CertList = (EFI_SIGNATURE_LIST *) Data;
2760   Offset = 0;
2761   ZeroMem (OldData, ItemDataSize);
2762   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2763     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2764     DEBUG ((DEBUG_INFO, "       CertCount = %x\n", CertCount));
2765     if (CertCount != 0) {
2766       CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
2767       Offset += CertList->SignatureListSize;
2768     }
2769     ItemDataSize -= CertList->SignatureListSize;
2770     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2771   }
2772 
2773   DataSize = Offset;
2774   if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2775     Status = CreateTimeBasedPayload (&DataSize, &OldData);
2776     if (EFI_ERROR (Status)) {
2777       DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2778       goto ON_EXIT;
2779     }
2780   }
2781 
2782   Status = gRT->SetVariable(
2783                   VariableName,
2784                   VendorGuid,
2785                   Attr,
2786                   DataSize,
2787                   OldData
2788                   );
2789   if (EFI_ERROR (Status)) {
2790     DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
2791     goto ON_EXIT;
2792   }
2793 
2794 ON_EXIT:
2795   if (Data != NULL) {
2796     FreePool(Data);
2797   }
2798 
2799   if (OldData != NULL) {
2800     FreePool(OldData);
2801   }
2802 
2803   return UpdateDeletePage (
2804            PrivateData,
2805            VariableName,
2806            VendorGuid,
2807            LabelNumber,
2808            FormId,
2809            QuestionIdBase
2810            );
2811 }
2812 
2813 /**
2814   Perform secure boot mode transition from User Mode by setting AuditMode
2815   or DeployedMode variable.
2816 
2817   @param[in]  NewMode          New secure boot mode.
2818 
2819   @retval   EFI_SUCCESS        Secure Boot mode transition is successful.
2820 **/
2821 EFI_STATUS
TransitionFromUserMode(IN UINT8 NewMode)2822 TransitionFromUserMode(
2823   IN  UINT8 NewMode
2824   )
2825 {
2826   UINT8      Data;
2827   EFI_STATUS Status;
2828 
2829   if (NewMode == SECURE_BOOT_MODE_AUDIT_MODE) {
2830     Data = 1;
2831     Status = gRT->SetVariable(
2832                     EFI_AUDIT_MODE_NAME,
2833                     &gEfiGlobalVariableGuid,
2834                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2835                     sizeof(UINT8),
2836                     &Data
2837                     );
2838     return Status;
2839   } else if (NewMode == SECURE_BOOT_MODE_DEPLOYED_MODE) {
2840     Data = 1;
2841     Status = gRT->SetVariable(
2842                     EFI_DEPLOYED_MODE_NAME,
2843                     &gEfiGlobalVariableGuid,
2844                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2845                     sizeof(UINT8),
2846                     &Data
2847                     );
2848     return Status;
2849   }
2850 
2851   //
2852   // Other case do nothing here. May Goto enroll PK page.
2853   //
2854   return EFI_SUCCESS;
2855 }
2856 
2857 /**
2858   Perform secure boot mode transition from Setup Mode by setting AuditMode
2859   variable.
2860 
2861   @param[in]  NewMode          New secure boot mode.
2862 
2863   @retval   EFI_SUCCESS        Secure Boot mode transition is successful.
2864 **/
2865 EFI_STATUS
TransitionFromSetupMode(IN UINT8 NewMode)2866 TransitionFromSetupMode(
2867   IN UINT8 NewMode
2868   )
2869 {
2870   UINT8      Data;
2871   EFI_STATUS Status;
2872 
2873   Status = EFI_INVALID_PARAMETER;
2874 
2875   if (NewMode == SECURE_BOOT_MODE_AUDIT_MODE) {
2876     Data = 1;
2877     Status = gRT->SetVariable(
2878                     EFI_AUDIT_MODE_NAME,
2879                     &gEfiGlobalVariableGuid,
2880                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2881                     sizeof(UINT8),
2882                     &Data
2883                     );
2884     return Status;
2885   }
2886 
2887   //
2888   // Other case do nothing here. May Goto enroll PK page.
2889   //
2890   return EFI_SUCCESS;
2891 }
2892 
2893 /**
2894   Perform secure boot mode transition from Audit Mode. Nothing is done here,
2895   should goto enroll PK page.
2896 
2897   @param[in]  NewMode          New secure boot mode.
2898 
2899   @retval   EFI_SUCCESS        Secure Boot mode transition is successful.
2900 **/
2901 EFI_STATUS
TransitionFromAuditMode(IN UINT8 NewMode)2902 TransitionFromAuditMode(
2903   IN UINT8 NewMode
2904   )
2905 {
2906   //
2907   // Other case do nothing here. Should Goto enroll PK page.
2908   //
2909   return EFI_SUCCESS;
2910 }
2911 
2912 /**
2913    Perform secure boot mode transition from Deployed Mode by setting Deployed Mode
2914    variable to 0.
2915 
2916   @param[in]  NewMode          New secure boot mode.
2917 
2918   @retval   EFI_SUCCESS        Secure Boot mode transition is successful.
2919 **/
2920 EFI_STATUS
TransitionFromDeployedMode(IN UINT8 NewMode)2921 TransitionFromDeployedMode(
2922   IN UINT8 NewMode
2923   )
2924 {
2925   UINT8      Data;
2926   EFI_STATUS Status;
2927 
2928   //
2929   // Platform specific logic. when physical presence,  Allow to set DeployedMode =:0
2930   // to switch back to UserMode
2931   //
2932   if (NewMode == SECURE_BOOT_MODE_USER_MODE) {
2933     Data = 0;
2934     Status = gRT->SetVariable(
2935                     EFI_DEPLOYED_MODE_NAME,
2936                     &gEfiGlobalVariableGuid,
2937                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
2938                     sizeof(UINT8),
2939                     &Data
2940                     );
2941     DEBUG((EFI_D_INFO, "DeployedMode Status %x\n", Status));
2942     return Status;
2943   }
2944   return EFI_SUCCESS;
2945 }
2946 
2947 /**
2948    Perform main secure boot mode transition.
2949 
2950   @param[in]  CurMode          New secure boot mode.
2951   @param[in]  NewMode          New secure boot mode.
2952 
2953   @retval   EFI_SUCCESS        Secure Boot mode transition is successful.
2954 **/
2955 EFI_STATUS
SecureBootModeTransition(IN UINT8 CurMode,IN UINT8 NewMode)2956 SecureBootModeTransition(
2957   IN  UINT8  CurMode,
2958   IN  UINT8  NewMode
2959   )
2960 {
2961   EFI_STATUS                         Status;
2962 
2963   //
2964   // Set platform to be customized mode to ensure platform specific mode switch sucess
2965   //
2966   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2967   if (EFI_ERROR (Status)) {
2968     return Status;
2969   }
2970 
2971   //
2972   // SecureBootMode transition
2973   //
2974   switch (CurMode) {
2975     case SECURE_BOOT_MODE_USER_MODE:
2976       Status = TransitionFromUserMode(NewMode);
2977       break;
2978 
2979     case SECURE_BOOT_MODE_SETUP_MODE:
2980       Status = TransitionFromSetupMode(NewMode);
2981       break;
2982 
2983     case SECURE_BOOT_MODE_AUDIT_MODE:
2984       Status = TransitionFromAuditMode(NewMode);
2985       break;
2986 
2987     case SECURE_BOOT_MODE_DEPLOYED_MODE:
2988       Status = TransitionFromDeployedMode(NewMode);
2989       break;
2990 
2991     default:
2992       Status = EFI_INVALID_PARAMETER;
2993       ASSERT(FALSE);
2994   }
2995 
2996   return Status;
2997 }
2998 
2999 /**
3000    Get current secure boot mode by retrieve data from SetupMode/AuditMode/DeployedMode.
3001 
3002   @param[out]  SecureBootMode                Current secure boot mode.
3003 
3004 **/
3005 VOID
ExtractSecureBootModeFromVariable(OUT UINT8 * SecureBootMode)3006 ExtractSecureBootModeFromVariable(
3007   OUT UINT8      *SecureBootMode
3008   )
3009 {
3010   UINT8     *SetupMode;
3011   UINT8     *AuditMode;
3012   UINT8     *DeployedMode;
3013 
3014   SetupMode        = NULL;
3015   AuditMode        = NULL;
3016   DeployedMode     = NULL;
3017 
3018   //
3019   // Get AuditMode/DeployedMode from variable
3020   //
3021   GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
3022   GetVariable2 (EFI_AUDIT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&AuditMode, NULL);
3023   GetVariable2 (EFI_DEPLOYED_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&DeployedMode, NULL);
3024   if (SetupMode != NULL && AuditMode != NULL && DeployedMode != NULL) {
3025     if (*SetupMode == 0 && *AuditMode == 0 && *DeployedMode == 0) {
3026       //
3027       // User Mode
3028       //
3029       *SecureBootMode = SECURE_BOOT_MODE_USER_MODE;
3030     } else if (*SetupMode == 1 && *AuditMode == 0 && *DeployedMode == 0) {
3031       //
3032       // Setup Mode
3033       //
3034       *SecureBootMode = SECURE_BOOT_MODE_SETUP_MODE;
3035     } else if (*SetupMode == 1 && *AuditMode == 1 && *DeployedMode == 0) {
3036       //
3037       // Audit Mode
3038       //
3039       *SecureBootMode = SECURE_BOOT_MODE_AUDIT_MODE;
3040     } else if (*SetupMode == 0 && *AuditMode == 0 && *DeployedMode == 1) {
3041       //
3042       // Deployed Mode
3043       //
3044       *SecureBootMode = SECURE_BOOT_MODE_DEPLOYED_MODE;
3045     } else {
3046       ASSERT(FALSE);
3047     }
3048   }else {
3049     ASSERT(FALSE);
3050   }
3051 
3052   if (SetupMode != NULL) {
3053     FreePool (SetupMode);
3054   }
3055   if (DeployedMode != NULL) {
3056     FreePool (DeployedMode);
3057   }
3058   if (AuditMode != NULL) {
3059     FreePool (AuditMode);
3060   }
3061 }
3062 
3063 /**
3064   This function extracts configuration from variable.
3065 
3066   @param[in, out]  ConfigData   Point to SecureBoot configuration private data.
3067 
3068 **/
3069 VOID
SecureBootExtractConfigFromVariable(IN OUT SECUREBOOT_CONFIGURATION * ConfigData)3070 SecureBootExtractConfigFromVariable (
3071   IN OUT SECUREBOOT_CONFIGURATION    *ConfigData
3072   )
3073 {
3074   UINT8     *SecureBootEnable;
3075   UINT8     *SecureBootMode;
3076   EFI_TIME  CurrTime;
3077 
3078   SecureBootEnable = NULL;
3079   SecureBootMode   = NULL;
3080 
3081   //
3082   // Initilize the Date and Time using system time.
3083   //
3084   ConfigData->CertificateFormat = HASHALG_RAW;
3085   ConfigData->AlwaysRevocation = TRUE;
3086   gRT->GetTime (&CurrTime, NULL);
3087   ConfigData->RevocationDate.Year   = CurrTime.Year;
3088   ConfigData->RevocationDate.Month  = CurrTime.Month;
3089   ConfigData->RevocationDate.Day    = CurrTime.Day;
3090   ConfigData->RevocationTime.Hour   = CurrTime.Hour;
3091   ConfigData->RevocationTime.Minute = CurrTime.Minute;
3092   ConfigData->RevocationTime.Second = 0;
3093 
3094   //
3095   // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable
3096   // Checkbox.
3097   //
3098   ConfigData->AttemptSecureBoot = FALSE;
3099   GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
3100   if (SecureBootEnable == NULL) {
3101     ConfigData->HideSecureBoot = TRUE;
3102   } else {
3103     ConfigData->HideSecureBoot = FALSE;
3104     if ((*SecureBootEnable) == SECURE_BOOT_ENABLE) {
3105       ConfigData->AttemptSecureBoot = TRUE;
3106     }
3107   }
3108 
3109   //
3110   // If it is Physical Presence User, set the PhysicalPresent to true.
3111   //
3112   if (UserPhysicalPresent()) {
3113     ConfigData->PhysicalPresent = TRUE;
3114   } else {
3115     ConfigData->PhysicalPresent = FALSE;
3116   }
3117 
3118   //
3119   // Get the SecureBootMode from CustomMode variable.
3120   //
3121   GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
3122   if (SecureBootMode == NULL) {
3123     ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
3124   } else {
3125     ConfigData->SecureBootMode = *(SecureBootMode);
3126   }
3127 
3128   //
3129   // Extact current Secure Boot Mode
3130   //
3131   ExtractSecureBootModeFromVariable(&ConfigData->CurSecureBootMode);
3132 
3133   //
3134   // If there is no PK then the Delete Pk button will be gray.
3135   //
3136   if (ConfigData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE || ConfigData->CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE) {
3137     ConfigData->HasPk = FALSE;
3138   } else  {
3139     ConfigData->HasPk = TRUE;
3140   }
3141 
3142   if (SecureBootEnable != NULL) {
3143     FreePool (SecureBootEnable);
3144   }
3145 
3146   if (SecureBootMode != NULL) {
3147     FreePool (SecureBootMode);
3148   }
3149 }
3150 
3151 /**
3152   This function allows a caller to extract the current configuration for one
3153   or more named elements from the target driver.
3154 
3155   @param[in]   This              Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3156   @param[in]   Request           A null-terminated Unicode string in
3157                                  <ConfigRequest> format.
3158   @param[out]  Progress          On return, points to a character in the Request
3159                                  string. Points to the string's null terminator if
3160                                  request was successful. Points to the most recent
3161                                  '&' before the first failing name/value pair (or
3162                                  the beginning of the string if the failure is in
3163                                  the first name/value pair) if the request was not
3164                                  successful.
3165   @param[out]  Results           A null-terminated Unicode string in
3166                                  <ConfigAltResp> format which has all values filled
3167                                  in for the names in the Request string. String to
3168                                  be allocated by the called function.
3169 
3170   @retval EFI_SUCCESS            The Results is filled with the requested values.
3171   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
3172   @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
3173   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
3174                                  driver.
3175 
3176 **/
3177 EFI_STATUS
3178 EFIAPI
SecureBootExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)3179 SecureBootExtractConfig (
3180   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL        *This,
3181   IN CONST EFI_STRING                            Request,
3182        OUT EFI_STRING                            *Progress,
3183        OUT EFI_STRING                            *Results
3184   )
3185 {
3186   EFI_STATUS                        Status;
3187   UINTN                             BufferSize;
3188   UINTN                             Size;
3189   SECUREBOOT_CONFIGURATION          Configuration;
3190   EFI_STRING                        ConfigRequest;
3191   EFI_STRING                        ConfigRequestHdr;
3192   SECUREBOOT_CONFIG_PRIVATE_DATA    *PrivateData;
3193   BOOLEAN                           AllocatedRequest;
3194   UINT8                             *SecureBoot;
3195 
3196   if (Progress == NULL || Results == NULL) {
3197     return EFI_INVALID_PARAMETER;
3198   }
3199 
3200   AllocatedRequest = FALSE;
3201   ConfigRequestHdr = NULL;
3202   ConfigRequest    = NULL;
3203   Size             = 0;
3204   SecureBoot       = NULL;
3205 
3206   ZeroMem (&Configuration, sizeof (Configuration));
3207   PrivateData      = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
3208   *Progress        = Request;
3209 
3210   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
3211     return EFI_NOT_FOUND;
3212   }
3213 
3214   //
3215   // Get Configuration from Variable.
3216   //
3217   SecureBootExtractConfigFromVariable (&Configuration);
3218 
3219   //
3220   // Get current secure boot state.
3221   //
3222   GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);
3223 
3224   if (SecureBoot != NULL && *SecureBoot == SECURE_BOOT_MODE_ENABLE) {
3225     HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);
3226   } else {
3227     HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);
3228   }
3229 
3230   //
3231   // Get current secure boot mode
3232   //
3233   DEBUG((EFI_D_INFO, "Configuration.CurSecureBootMode %d\n", Configuration.CurSecureBootMode));
3234   if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE) {
3235     HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"UserMode", NULL);
3236   } else if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE) {
3237     HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"SetupMode", NULL);
3238   } else if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE) {
3239     HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"AuditMode", NULL);
3240   } else if (Configuration.CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE) {
3241     HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"DeployedMode", NULL);
3242   }
3243 
3244   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3245   ConfigRequest = Request;
3246   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
3247     //
3248     // Request is set to NULL or OFFSET is NULL, construct full request string.
3249     //
3250     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
3251     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
3252     //
3253     ConfigRequestHdr = HiiConstructConfigHdr (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, PrivateData->DriverHandle);
3254     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
3255     ConfigRequest = AllocateZeroPool (Size);
3256     ASSERT (ConfigRequest != NULL);
3257     AllocatedRequest = TRUE;
3258     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
3259     FreePool (ConfigRequestHdr);
3260     ConfigRequestHdr = NULL;
3261   }
3262 
3263   Status = gHiiConfigRouting->BlockToConfig (
3264                                 gHiiConfigRouting,
3265                                 ConfigRequest,
3266                                 (UINT8 *) &Configuration,
3267                                 BufferSize,
3268                                 Results,
3269                                 Progress
3270                                 );
3271 
3272   //
3273   // Free the allocated config request string.
3274   //
3275   if (AllocatedRequest) {
3276     FreePool (ConfigRequest);
3277   }
3278 
3279   //
3280   // Set Progress string to the original request string.
3281   //
3282   if (Request == NULL) {
3283     *Progress = NULL;
3284   } else if (StrStr (Request, L"OFFSET") == NULL) {
3285     *Progress = Request + StrLen (Request);
3286   }
3287 
3288   if (SecureBoot != NULL) {
3289     FreePool (SecureBoot);
3290   }
3291 
3292   return Status;
3293 }
3294 
3295 /**
3296   This function processes the results of changes in configuration.
3297 
3298   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3299   @param[in]  Configuration      A null-terminated Unicode string in <ConfigResp>
3300                                  format.
3301   @param[out] Progress           A pointer to a string filled in with the offset of
3302                                  the most recent '&' before the first failing
3303                                  name/value pair (or the beginning of the string if
3304                                  the failure is in the first name/value pair) or
3305                                  the terminating NULL if all was successful.
3306 
3307   @retval EFI_SUCCESS            The Results is processed successfully.
3308   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
3309   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
3310                                  driver.
3311 
3312 **/
3313 EFI_STATUS
3314 EFIAPI
SecureBootRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)3315 SecureBootRouteConfig (
3316   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
3317   IN CONST EFI_STRING                          Configuration,
3318        OUT EFI_STRING                          *Progress
3319   )
3320 {
3321   UINT8                      *SecureBootEnable;
3322   SECUREBOOT_CONFIGURATION   IfrNvData;
3323   UINTN                      BufferSize;
3324   EFI_STATUS                 Status;
3325 
3326   if (Configuration == NULL || Progress == NULL) {
3327     return EFI_INVALID_PARAMETER;
3328   }
3329 
3330   *Progress = Configuration;
3331   if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
3332     return EFI_NOT_FOUND;
3333   }
3334 
3335   //
3336   // Get Configuration from Variable.
3337   //
3338   SecureBootExtractConfigFromVariable (&IfrNvData);
3339 
3340   //
3341   // Map the Configuration to the configuration block.
3342   //
3343   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3344   Status = gHiiConfigRouting->ConfigToBlock (
3345                                 gHiiConfigRouting,
3346                                 Configuration,
3347                                 (UINT8 *)&IfrNvData,
3348                                 &BufferSize,
3349                                 Progress
3350                                 );
3351   if (EFI_ERROR (Status)) {
3352     return Status;
3353   }
3354 
3355   //
3356   // Store Buffer Storage back to EFI variable if needed
3357   //
3358   SecureBootEnable = NULL;
3359   GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
3360   if (NULL != SecureBootEnable) {
3361     FreePool (SecureBootEnable);
3362     Status = SaveSecureBootVariable (IfrNvData.AttemptSecureBoot);
3363     if (EFI_ERROR (Status)) {
3364       return Status;
3365     }
3366   }
3367 
3368   *Progress = Configuration + StrLen (Configuration);
3369   return EFI_SUCCESS;
3370 }
3371 
3372 /**
3373   This function is called to provide results data to the driver.
3374 
3375   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3376   @param[in]  Action             Specifies the type of action taken by the browser.
3377   @param[in]  QuestionId         A unique value which is sent to the original
3378                                  exporting driver so that it can identify the type
3379                                  of data to expect.
3380   @param[in]  Type               The type of value for the question.
3381   @param[in]  Value              A pointer to the data being sent to the original
3382                                  exporting driver.
3383   @param[out] ActionRequest      On return, points to the action requested by the
3384                                  callback function.
3385 
3386   @retval EFI_SUCCESS            The callback successfully handled the action.
3387   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
3388                                  variable and its data.
3389   @retval EFI_DEVICE_ERROR       The variable could not be saved.
3390   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
3391                                  callback.
3392 
3393 **/
3394 EFI_STATUS
3395 EFIAPI
SecureBootCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)3396 SecureBootCallback (
3397   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
3398   IN     EFI_BROWSER_ACTION                    Action,
3399   IN     EFI_QUESTION_ID                       QuestionId,
3400   IN     UINT8                                 Type,
3401   IN     EFI_IFR_TYPE_VALUE                    *Value,
3402      OUT EFI_BROWSER_ACTION_REQUEST            *ActionRequest
3403   )
3404 {
3405   EFI_INPUT_KEY                   Key;
3406   EFI_STATUS                      Status;
3407   SECUREBOOT_CONFIG_PRIVATE_DATA  *Private;
3408   UINTN                           BufferSize;
3409   SECUREBOOT_CONFIGURATION        *IfrNvData;
3410   UINT16                          LabelId;
3411   UINT8                           *SecureBootEnable;
3412   UINT8                           *SecureBootMode;
3413   CHAR16                          PromptString[100];
3414   UINT8                           CurSecureBootMode;
3415 
3416   Status           = EFI_SUCCESS;
3417   SecureBootEnable = NULL;
3418   SecureBootMode   = NULL;
3419 
3420   if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
3421     return EFI_INVALID_PARAMETER;
3422   }
3423   Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
3424 
3425   //
3426   // Retrieve uncommitted data from Browser
3427   //
3428   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3429   IfrNvData = AllocateZeroPool (BufferSize);
3430   if (IfrNvData == NULL) {
3431     return EFI_OUT_OF_RESOURCES;
3432   }
3433 
3434   HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData);
3435 
3436   if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
3437     if (QuestionId == KEY_SECURE_BOOT_MODE) {
3438       mIsEnterSecureBootForm = TRUE;
3439     } else if (QuestionId == KEY_TRANS_SECURE_BOOT_MODE){
3440       //
3441       // Secure Boot Policy variable changes after tranistion. Re-sync CurSecureBootMode
3442       //
3443       ExtractSecureBootModeFromVariable(&IfrNvData->CurSecureBootMode);
3444       mIsSelectedSecureBootModeForm = TRUE;
3445       mIsSecureBootModeChanged = FALSE;
3446     }
3447     goto EXIT;
3448   }
3449 
3450   if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
3451     Status = EFI_UNSUPPORTED;
3452     if (QuestionId == KEY_SECURE_BOOT_MODE) {
3453       if (mIsEnterSecureBootForm) {
3454         Value->u8 = SECURE_BOOT_MODE_STANDARD;
3455         Status = EFI_SUCCESS;
3456       }
3457     } else if (QuestionId == KEY_TRANS_SECURE_BOOT_MODE) {
3458       if (mIsSelectedSecureBootModeForm) {
3459         Value->u8 = IfrNvData->CurSecureBootMode;
3460         Status = EFI_SUCCESS;
3461       }
3462     }
3463     goto EXIT;
3464   }
3465 
3466   if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
3467       (Action != EFI_BROWSER_ACTION_CHANGING) &&
3468       (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&
3469       (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {
3470     Status = EFI_UNSUPPORTED;
3471     goto EXIT;
3472   }
3473 
3474   if (Action == EFI_BROWSER_ACTION_CHANGING) {
3475 
3476     switch (QuestionId) {
3477     case KEY_SECURE_BOOT_ENABLE:
3478       GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
3479       if (NULL != SecureBootEnable) {
3480         FreePool (SecureBootEnable);
3481         if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) {
3482           CreatePopUp (
3483             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3484             &Key,
3485             L"Only Physical Presence User could disable secure boot!",
3486             NULL
3487             );
3488           Status = EFI_UNSUPPORTED;
3489         } else {
3490           CreatePopUp (
3491             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3492             &Key,
3493             L"Configuration changed, please reset the platform to take effect!",
3494             NULL
3495             );
3496         }
3497       }
3498       break;
3499 
3500     case KEY_SECURE_BOOT_OPTION:
3501       FreeMenu (&DirectoryMenu);
3502       FreeMenu (&FsOptionMenu);
3503       break;
3504 
3505     case KEY_SECURE_BOOT_KEK_OPTION:
3506     case KEY_SECURE_BOOT_DB_OPTION:
3507     case KEY_SECURE_BOOT_DBX_OPTION:
3508     case KEY_SECURE_BOOT_DBT_OPTION:
3509       //
3510       // Clear Signature GUID.
3511       //
3512       ZeroMem (IfrNvData->SignatureGuid, sizeof (IfrNvData->SignatureGuid));
3513       if (Private->SignatureGUID == NULL) {
3514         Private->SignatureGUID = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID));
3515         if (Private->SignatureGUID == NULL) {
3516           return EFI_OUT_OF_RESOURCES;
3517         }
3518       }
3519 
3520       if (QuestionId == KEY_SECURE_BOOT_DB_OPTION) {
3521         LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
3522       } else if (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) {
3523         LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
3524       } else if (QuestionId == KEY_SECURE_BOOT_DBT_OPTION) {
3525         LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
3526       } else {
3527         LabelId = FORMID_ENROLL_KEK_FORM;
3528       }
3529 
3530       //
3531       // Refresh selected file.
3532       //
3533       CleanUpPage (LabelId, Private);
3534       break;
3535 
3536     case SECUREBOOT_ADD_PK_FILE_FORM_ID:
3537     case FORMID_ENROLL_KEK_FORM:
3538     case SECUREBOOT_ENROLL_SIGNATURE_TO_DB:
3539     case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX:
3540     case SECUREBOOT_ENROLL_SIGNATURE_TO_DBT:
3541       if (QuestionId == SECUREBOOT_ADD_PK_FILE_FORM_ID) {
3542         Private->FeCurrentState = FileExplorerStateEnrollPkFile;
3543       } else if (QuestionId == FORMID_ENROLL_KEK_FORM) {
3544         Private->FeCurrentState = FileExplorerStateEnrollKekFile;
3545       } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DB) {
3546         Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDb;
3547       } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DBX) {
3548         Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbx;
3549         IfrNvData->CertificateFormat = HASHALG_SHA256;
3550       } else {
3551         Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbt;
3552       }
3553 
3554       Private->FeDisplayContext = FileExplorerDisplayUnknown;
3555       CleanUpPage (FORM_FILE_EXPLORER_ID, Private);
3556       UpdateFileExplorer (Private, 0);
3557       break;
3558 
3559     case KEY_SECURE_BOOT_DELETE_PK:
3560       if (Value->u8) {
3561         CreatePopUp (
3562           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3563           &Key,
3564           L"Are you sure you want to delete PK? Secure boot will be disabled!",
3565           L"Press 'Y' to delete PK and exit, 'N' to discard change and return",
3566           NULL
3567           );
3568         if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
3569           Status = DeletePlatformKey ();
3570           if (EFI_ERROR (Status)) {
3571             CreatePopUp (
3572               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3573               &Key,
3574               L"Only Physical Presence User could delete PK in custom mode!",
3575               NULL
3576               );
3577           }
3578         }
3579       }
3580       break;
3581 
3582     case KEY_DELETE_KEK:
3583       UpdateDeletePage (
3584         Private,
3585         EFI_KEY_EXCHANGE_KEY_NAME,
3586         &gEfiGlobalVariableGuid,
3587         LABEL_KEK_DELETE,
3588         FORMID_DELETE_KEK_FORM,
3589         OPTION_DEL_KEK_QUESTION_ID
3590         );
3591       break;
3592 
3593     case SECUREBOOT_DELETE_SIGNATURE_FROM_DB:
3594       UpdateDeletePage (
3595         Private,
3596         EFI_IMAGE_SECURITY_DATABASE,
3597         &gEfiImageSecurityDatabaseGuid,
3598         LABEL_DB_DELETE,
3599         SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
3600         OPTION_DEL_DB_QUESTION_ID
3601         );
3602        break;
3603 
3604     case SECUREBOOT_DELETE_SIGNATURE_FROM_DBX:
3605       UpdateDeletePage (
3606         Private,
3607         EFI_IMAGE_SECURITY_DATABASE1,
3608         &gEfiImageSecurityDatabaseGuid,
3609         LABEL_DBX_DELETE,
3610         SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,
3611         OPTION_DEL_DBX_QUESTION_ID
3612         );
3613 
3614       break;
3615 
3616     case SECUREBOOT_DELETE_SIGNATURE_FROM_DBT:
3617       UpdateDeletePage (
3618         Private,
3619         EFI_IMAGE_SECURITY_DATABASE2,
3620         &gEfiImageSecurityDatabaseGuid,
3621         LABEL_DBT_DELETE,
3622         SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
3623         OPTION_DEL_DBT_QUESTION_ID
3624         );
3625 
3626       break;
3627 
3628     case KEY_VALUE_SAVE_AND_EXIT_KEK:
3629       Status = EnrollKeyExchangeKey (Private);
3630       if (EFI_ERROR (Status)) {
3631         CreatePopUp (
3632           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3633           &Key,
3634           L"ERROR: Unsupported file type!",
3635           L"Only supports DER-encoded X509 certificate",
3636           NULL
3637           );
3638       }
3639       break;
3640 
3641     case KEY_VALUE_SAVE_AND_EXIT_DB:
3642       Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE);
3643       if (EFI_ERROR (Status)) {
3644         CreatePopUp (
3645           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3646           &Key,
3647           L"ERROR: Unsupported file type!",
3648           L"Only supports DER-encoded X509 certificate and executable EFI image",
3649           NULL
3650           );
3651       }
3652       break;
3653 
3654     case KEY_VALUE_SAVE_AND_EXIT_DBX:
3655       if (IsX509CertInDbx (Private, EFI_IMAGE_SECURITY_DATABASE1)) {
3656         CreatePopUp (
3657           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3658           &Key,
3659           L"Enrollment failed! Same certificate had already been in the dbx!",
3660           NULL
3661           );
3662           break;
3663       }
3664 
3665       if ((IfrNvData != NULL) && (IfrNvData->CertificateFormat < HASHALG_MAX)) {
3666         Status = EnrollX509HashtoSigDB (
3667                    Private,
3668                    IfrNvData->CertificateFormat,
3669                    &IfrNvData->RevocationDate,
3670                    &IfrNvData->RevocationTime,
3671                    IfrNvData->AlwaysRevocation
3672                    );
3673       } else {
3674         Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE1);
3675       }
3676       if (EFI_ERROR (Status)) {
3677         CreatePopUp (
3678           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3679           &Key,
3680           L"ERROR: Unsupported file type!",
3681           L"Only supports DER-encoded X509 certificate and executable EFI image",
3682           NULL
3683           );
3684       }
3685       break;
3686 
3687     case KEY_VALUE_SAVE_AND_EXIT_DBT:
3688       Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE2);
3689       if (EFI_ERROR (Status)) {
3690         CreatePopUp (
3691           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3692           &Key,
3693           L"ERROR: Unsupported file type!",
3694           L"Only supports DER-encoded X509 certificate.",
3695           NULL
3696           );
3697       }
3698       break;
3699     case KEY_TRANS_SECURE_BOOT_MODE:
3700       //
3701       // Pop up to alert user want to change secure boot mode
3702       //
3703       if ((IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE &&
3704            (Value->u8 == SECURE_BOOT_MODE_AUDIT_MODE || Value->u8 == SECURE_BOOT_MODE_DEPLOYED_MODE))
3705         ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE &&
3706            Value->u8 == SECURE_BOOT_MODE_AUDIT_MODE)
3707         ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE &&
3708           Value->u8 == SECURE_BOOT_MODE_USER_MODE && IfrNvData->PhysicalPresent == 1)){
3709         CreatePopUp (
3710           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3711           &Key,
3712           L"Are you sure you want to switch secure boot mode?",
3713           L"Press 'Y' to switch secure boot mode, 'N' to discard change and return",
3714           NULL
3715           );
3716         if (Key.UnicodeChar != 'y' && Key.UnicodeChar != 'Y') {
3717           //
3718           // If not 'Y'/''y' restore to defualt secure boot mode
3719           //
3720           Value->u8 = IfrNvData->CurSecureBootMode;
3721           goto EXIT;
3722         }
3723       } else if ((IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE && Value->u8 == SECURE_BOOT_MODE_USER_MODE)
3724                ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE && Value->u8 == SECURE_BOOT_MODE_SETUP_MODE)
3725                ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE && Value->u8 == SECURE_BOOT_MODE_DEPLOYED_MODE)
3726                ||(IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE && Value->u8 == SECURE_BOOT_MODE_SETUP_MODE)) {
3727         CreatePopUp (
3728           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3729           &Key,
3730           L"Secure boot mode tranistion requires PK change",
3731           L"Please go to link below to update PK",
3732           NULL
3733           );
3734       } else {
3735         Status = EFI_INVALID_PARAMETER;
3736         goto EXIT;
3737       }
3738 
3739       Status = SecureBootModeTransition(IfrNvData->CurSecureBootMode, Value->u8);
3740       //
3741       // Secure Boot Policy variable may change after tranistion. Re-sync CurSecureBootMode
3742       //
3743       ExtractSecureBootModeFromVariable(&CurSecureBootMode);
3744       if (IfrNvData->CurSecureBootMode != CurSecureBootMode) {
3745         IfrNvData->CurSecureBootMode = CurSecureBootMode;
3746         mIsSecureBootModeChanged = TRUE;
3747 
3748         if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE) {
3749           HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"UserMode", NULL);
3750         } else if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_SETUP_MODE) {
3751           HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"SetupMode", NULL);
3752         } else if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_AUDIT_MODE) {
3753           HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"AuditMode", NULL);
3754         } else if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE) {
3755           HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_CUR_SECURE_BOOT_MODE_CONTENT), L"DeployedMode", NULL);
3756         }
3757       }
3758       break;
3759 
3760     default:
3761       if (QuestionId >= FILE_OPTION_GOTO_OFFSET) {
3762         UpdateFileExplorer (Private, QuestionId);
3763       } else if ((QuestionId >= OPTION_DEL_KEK_QUESTION_ID) &&
3764                  (QuestionId < (OPTION_DEL_KEK_QUESTION_ID + OPTION_CONFIG_RANGE))) {
3765         DeleteKeyExchangeKey (Private, QuestionId);
3766       } else if ((QuestionId >= OPTION_DEL_DB_QUESTION_ID) &&
3767                  (QuestionId < (OPTION_DEL_DB_QUESTION_ID + OPTION_CONFIG_RANGE))) {
3768         DeleteSignature (
3769           Private,
3770           EFI_IMAGE_SECURITY_DATABASE,
3771           &gEfiImageSecurityDatabaseGuid,
3772           LABEL_DB_DELETE,
3773           SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
3774           OPTION_DEL_DB_QUESTION_ID,
3775           QuestionId - OPTION_DEL_DB_QUESTION_ID
3776           );
3777       } else if ((QuestionId >= OPTION_DEL_DBX_QUESTION_ID) &&
3778                  (QuestionId < (OPTION_DEL_DBX_QUESTION_ID + OPTION_CONFIG_RANGE))) {
3779         DeleteSignature (
3780           Private,
3781           EFI_IMAGE_SECURITY_DATABASE1,
3782           &gEfiImageSecurityDatabaseGuid,
3783           LABEL_DBX_DELETE,
3784           SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,
3785           OPTION_DEL_DBX_QUESTION_ID,
3786           QuestionId - OPTION_DEL_DBX_QUESTION_ID
3787           );
3788       } else if ((QuestionId >= OPTION_DEL_DBT_QUESTION_ID) &&
3789                  (QuestionId < (OPTION_DEL_DBT_QUESTION_ID + OPTION_CONFIG_RANGE))) {
3790         DeleteSignature (
3791           Private,
3792           EFI_IMAGE_SECURITY_DATABASE2,
3793           &gEfiImageSecurityDatabaseGuid,
3794           LABEL_DBT_DELETE,
3795           SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
3796           OPTION_DEL_DBT_QUESTION_ID,
3797           QuestionId - OPTION_DEL_DBT_QUESTION_ID
3798           );
3799       }
3800       break;
3801     }
3802   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
3803     switch (QuestionId) {
3804     case KEY_SECURE_BOOT_ENABLE:
3805       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
3806       break;
3807     case KEY_VALUE_SAVE_AND_EXIT_PK:
3808       Status = EnrollPlatformKey (Private);
3809       if (EFI_ERROR (Status)) {
3810         UnicodeSPrint (
3811           PromptString,
3812           sizeof (PromptString),
3813           L"Only DER encoded certificate file (%s) is supported.",
3814           mSupportX509Suffix
3815           );
3816         CreatePopUp (
3817           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
3818           &Key,
3819           L"ERROR: Unsupported file type!",
3820           PromptString,
3821           NULL
3822           );
3823       } else {
3824         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
3825       }
3826       break;
3827 
3828     case KEY_VALUE_NO_SAVE_AND_EXIT_PK:
3829     case KEY_VALUE_NO_SAVE_AND_EXIT_KEK:
3830     case KEY_VALUE_NO_SAVE_AND_EXIT_DB:
3831     case KEY_VALUE_NO_SAVE_AND_EXIT_DBX:
3832     case KEY_VALUE_NO_SAVE_AND_EXIT_DBT:
3833       if (Private->FileContext->FHandle != NULL) {
3834         CloseFile (Private->FileContext->FHandle);
3835         Private->FileContext->FHandle = NULL;
3836         Private->FileContext->FileName = NULL;
3837       }
3838 
3839       if (Private->SignatureGUID != NULL) {
3840         FreePool (Private->SignatureGUID);
3841         Private->SignatureGUID = NULL;
3842       }
3843       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
3844       break;
3845 
3846     case KEY_SECURE_BOOT_MODE:
3847       mIsEnterSecureBootForm = FALSE;
3848       break;
3849     case KEY_TRANS_SECURE_BOOT_MODE:
3850       mIsSelectedSecureBootModeForm = FALSE;
3851       if (mIsSecureBootModeChanged) {
3852         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
3853       }
3854       mIsSecureBootModeChanged = FALSE;
3855       break;
3856     case KEY_SECURE_BOOT_KEK_GUID:
3857     case KEY_SECURE_BOOT_SIGNATURE_GUID_DB:
3858     case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX:
3859     case KEY_SECURE_BOOT_SIGNATURE_GUID_DBT:
3860       ASSERT (Private->SignatureGUID != NULL);
3861       Status = StringToGuid (
3862                  IfrNvData->SignatureGuid,
3863                  StrLen (IfrNvData->SignatureGuid),
3864                  Private->SignatureGUID
3865                  );
3866       if (EFI_ERROR (Status)) {
3867         break;
3868       }
3869 
3870       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
3871       break;
3872 
3873     case KEY_SECURE_BOOT_DELETE_PK:
3874       if (IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_USER_MODE || IfrNvData->CurSecureBootMode == SECURE_BOOT_MODE_DEPLOYED_MODE) {
3875         IfrNvData->DeletePk = TRUE;
3876         IfrNvData->HasPk    = FALSE;
3877         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
3878       } else  {
3879         IfrNvData->DeletePk = FALSE;
3880         IfrNvData->HasPk    = TRUE;
3881         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
3882       }
3883       break;
3884     default:
3885       if (QuestionId >= FILE_OPTION_OFFSET && QuestionId < FILE_OPTION_GOTO_OFFSET) {
3886         if (UpdateFileExplorer (Private, QuestionId)) {
3887           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
3888         }
3889       }
3890       break;
3891     }
3892   } else if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
3893     if (QuestionId == KEY_HIDE_SECURE_BOOT) {
3894       GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
3895       if (SecureBootEnable == NULL) {
3896         IfrNvData->HideSecureBoot = TRUE;
3897       } else {
3898         FreePool (SecureBootEnable);
3899         IfrNvData->HideSecureBoot = FALSE;
3900       }
3901       Value->b = IfrNvData->HideSecureBoot;
3902     }
3903   } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
3904     //
3905     // Force the platform back to Standard Mode once user leave the setup screen.
3906     //
3907     GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
3908     if (NULL != SecureBootMode && *SecureBootMode == CUSTOM_SECURE_BOOT_MODE) {
3909       IfrNvData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
3910       SetSecureBootMode(STANDARD_SECURE_BOOT_MODE);
3911     }
3912     if (SecureBootMode != NULL) {
3913       FreePool (SecureBootMode);
3914     }
3915   }
3916 
3917 EXIT:
3918 
3919   if (!EFI_ERROR (Status)) {
3920     BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3921     HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL);
3922   }
3923 
3924   FreePool (IfrNvData);
3925 
3926   return EFI_SUCCESS;
3927 }
3928 
3929 /**
3930   This function publish the SecureBoot configuration Form.
3931 
3932   @param[in, out]  PrivateData   Points to SecureBoot configuration private data.
3933 
3934   @retval EFI_SUCCESS            HII Form is installed successfully.
3935   @retval EFI_OUT_OF_RESOURCES   Not enough resource for HII Form installation.
3936   @retval Others                 Other errors as indicated.
3937 
3938 **/
3939 EFI_STATUS
InstallSecureBootConfigForm(IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData)3940 InstallSecureBootConfigForm (
3941   IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA  *PrivateData
3942   )
3943 {
3944   EFI_STATUS                      Status;
3945   EFI_HII_HANDLE                  HiiHandle;
3946   EFI_HANDLE                      DriverHandle;
3947   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
3948 
3949   DriverHandle = NULL;
3950   ConfigAccess = &PrivateData->ConfigAccess;
3951   Status = gBS->InstallMultipleProtocolInterfaces (
3952                   &DriverHandle,
3953                   &gEfiDevicePathProtocolGuid,
3954                   &mSecureBootHiiVendorDevicePath,
3955                   &gEfiHiiConfigAccessProtocolGuid,
3956                   ConfigAccess,
3957                   NULL
3958                   );
3959   if (EFI_ERROR (Status)) {
3960     return Status;
3961   }
3962 
3963   PrivateData->DriverHandle = DriverHandle;
3964 
3965   //
3966   // Publish the HII package list
3967   //
3968   HiiHandle = HiiAddPackages (
3969                 &gSecureBootConfigFormSetGuid,
3970                 DriverHandle,
3971                 SecureBootConfigDxeStrings,
3972                 SecureBootConfigBin,
3973                 NULL
3974                 );
3975   if (HiiHandle == NULL) {
3976     gBS->UninstallMultipleProtocolInterfaces (
3977            DriverHandle,
3978            &gEfiDevicePathProtocolGuid,
3979            &mSecureBootHiiVendorDevicePath,
3980            &gEfiHiiConfigAccessProtocolGuid,
3981            ConfigAccess,
3982            NULL
3983            );
3984     return EFI_OUT_OF_RESOURCES;
3985   }
3986 
3987   PrivateData->HiiHandle = HiiHandle;
3988 
3989   PrivateData->FileContext = AllocateZeroPool (sizeof (SECUREBOOT_FILE_CONTEXT));
3990   PrivateData->MenuEntry   = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));
3991 
3992   if (PrivateData->FileContext == NULL || PrivateData->MenuEntry == NULL) {
3993     UninstallSecureBootConfigForm (PrivateData);
3994     return EFI_OUT_OF_RESOURCES;
3995   }
3996 
3997   PrivateData->FeCurrentState = FileExplorerStateInActive;
3998   PrivateData->FeDisplayContext = FileExplorerDisplayUnknown;
3999 
4000   InitializeListHead (&FsOptionMenu.Head);
4001   InitializeListHead (&DirectoryMenu.Head);
4002 
4003   //
4004   // Init OpCode Handle and Allocate space for creation of Buffer
4005   //
4006   mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
4007   if (mStartOpCodeHandle == NULL) {
4008     UninstallSecureBootConfigForm (PrivateData);
4009     return EFI_OUT_OF_RESOURCES;
4010   }
4011 
4012   mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
4013   if (mEndOpCodeHandle == NULL) {
4014     UninstallSecureBootConfigForm (PrivateData);
4015     return EFI_OUT_OF_RESOURCES;
4016   }
4017 
4018   //
4019   // Create Hii Extend Label OpCode as the start opcode
4020   //
4021   mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
4022                                          mStartOpCodeHandle,
4023                                          &gEfiIfrTianoGuid,
4024                                          NULL,
4025                                          sizeof (EFI_IFR_GUID_LABEL)
4026                                          );
4027   mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
4028 
4029   //
4030   // Create Hii Extend Label OpCode as the end opcode
4031   //
4032   mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
4033                                        mEndOpCodeHandle,
4034                                        &gEfiIfrTianoGuid,
4035                                        NULL,
4036                                        sizeof (EFI_IFR_GUID_LABEL)
4037                                        );
4038   mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
4039   mEndLabel->Number       = LABEL_END;
4040 
4041   return EFI_SUCCESS;
4042 }
4043 
4044 /**
4045   This function removes SecureBoot configuration Form.
4046 
4047   @param[in, out]  PrivateData   Points to SecureBoot configuration private data.
4048 
4049 **/
4050 VOID
UninstallSecureBootConfigForm(IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData)4051 UninstallSecureBootConfigForm (
4052   IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA    *PrivateData
4053   )
4054 {
4055   //
4056   // Uninstall HII package list
4057   //
4058   if (PrivateData->HiiHandle != NULL) {
4059     HiiRemovePackages (PrivateData->HiiHandle);
4060     PrivateData->HiiHandle = NULL;
4061   }
4062 
4063   //
4064   // Uninstall HII Config Access Protocol
4065   //
4066   if (PrivateData->DriverHandle != NULL) {
4067     gBS->UninstallMultipleProtocolInterfaces (
4068            PrivateData->DriverHandle,
4069            &gEfiDevicePathProtocolGuid,
4070            &mSecureBootHiiVendorDevicePath,
4071            &gEfiHiiConfigAccessProtocolGuid,
4072            &PrivateData->ConfigAccess,
4073            NULL
4074            );
4075     PrivateData->DriverHandle = NULL;
4076   }
4077 
4078   if (PrivateData->SignatureGUID != NULL) {
4079     FreePool (PrivateData->SignatureGUID);
4080   }
4081 
4082   if (PrivateData->MenuEntry != NULL) {
4083     FreePool (PrivateData->MenuEntry);
4084   }
4085 
4086   if (PrivateData->FileContext != NULL) {
4087     FreePool (PrivateData->FileContext);
4088   }
4089 
4090   FreePool (PrivateData);
4091 
4092   FreeMenu (&DirectoryMenu);
4093   FreeMenu (&FsOptionMenu);
4094 
4095   if (mStartOpCodeHandle != NULL) {
4096     HiiFreeOpCodeHandle (mStartOpCodeHandle);
4097   }
4098 
4099   if (mEndOpCodeHandle != NULL) {
4100     HiiFreeOpCodeHandle (mEndOpCodeHandle);
4101   }
4102 }
4103