1 /** @file
2   HII Config Access protocol implementation of SecureBoot configuration module.
3 
4 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "SecureBootConfigImpl.h"
11 #include <Library/BaseCryptLib.h>
12 
13 CHAR16              mSecureBootStorageName[] = L"SECUREBOOT_CONFIGURATION";
14 
15 SECUREBOOT_CONFIG_PRIVATE_DATA         mSecureBootConfigPrivateDateTemplate = {
16   SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE,
17   {
18     SecureBootExtractConfig,
19     SecureBootRouteConfig,
20     SecureBootCallback
21   }
22 };
23 
24 HII_VENDOR_DEVICE_PATH          mSecureBootHiiVendorDevicePath = {
25   {
26     {
27       HARDWARE_DEVICE_PATH,
28       HW_VENDOR_DP,
29       {
30         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
31         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
32       }
33     },
34     SECUREBOOT_CONFIG_FORM_SET_GUID
35   },
36   {
37     END_DEVICE_PATH_TYPE,
38     END_ENTIRE_DEVICE_PATH_SUBTYPE,
39     {
40       (UINT8) (END_DEVICE_PATH_LENGTH),
41       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
42     }
43   }
44 };
45 
46 
47 BOOLEAN mIsEnterSecureBootForm = FALSE;
48 
49 //
50 // OID ASN.1 Value for Hash Algorithms
51 //
52 UINT8 mHashOidValue[] = {
53   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,         // OBJ_md5
54   0x2B, 0x0E, 0x03, 0x02, 0x1A,                           // OBJ_sha1
55   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,   // OBJ_sha224
56   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,   // OBJ_sha256
57   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,   // OBJ_sha384
58   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,   // OBJ_sha512
59   };
60 
61 HASH_TABLE mHash[] = {
62   { L"SHA224", 28, &mHashOidValue[13], 9, NULL,                 NULL,       NULL,         NULL       },
63   { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},
64   { L"SHA384", 48, &mHashOidValue[31], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},
65   { L"SHA512", 64, &mHashOidValue[40], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}
66 };
67 
68 //
69 // Variable Definitions
70 //
71 UINT32            mPeCoffHeaderOffset = 0;
72 WIN_CERTIFICATE   *mCertificate = NULL;
73 IMAGE_TYPE        mImageType;
74 UINT8             *mImageBase = NULL;
75 UINTN             mImageSize = 0;
76 UINT8             mImageDigest[MAX_DIGEST_SIZE];
77 UINTN             mImageDigestSize;
78 EFI_GUID          mCertType;
79 EFI_IMAGE_SECURITY_DATA_DIRECTORY    *mSecDataDir = NULL;
80 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  mNtHeader;
81 
82 //
83 // Possible DER-encoded certificate file suffixes, end with NULL pointer.
84 //
85 CHAR16* mDerEncodedSuffix[] = {
86   L".cer",
87   L".der",
88   L".crt",
89   NULL
90 };
91 CHAR16* mSupportX509Suffix = L"*.cer/der/crt";
92 
93 SECUREBOOT_CONFIG_PRIVATE_DATA  *gSecureBootPrivateData = NULL;
94 
95 /**
96   This code cleans up enrolled file by closing file & free related resources attached to
97   enrolled file.
98 
99   @param[in] FileContext            FileContext cached in SecureBootConfig driver
100 
101 **/
102 VOID
CloseEnrolledFile(IN SECUREBOOT_FILE_CONTEXT * FileContext)103 CloseEnrolledFile(
104   IN SECUREBOOT_FILE_CONTEXT *FileContext
105 )
106 {
107   if (FileContext->FHandle != NULL) {
108     CloseFile (FileContext->FHandle);
109     FileContext->FHandle = NULL;
110   }
111 
112   if (FileContext->FileName != NULL){
113     FreePool(FileContext->FileName);
114     FileContext->FileName = NULL;
115   }
116   FileContext->FileType = UNKNOWN_FILE_TYPE;
117 
118 }
119 
120 /**
121   This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.
122 
123   @param[in] FileSuffix            The suffix of the input certificate file
124 
125   @retval    TRUE           It's a DER-encoded certificate.
126   @retval    FALSE          It's NOT a DER-encoded certificate.
127 
128 **/
129 BOOLEAN
IsDerEncodeCertificate(IN CONST CHAR16 * FileSuffix)130 IsDerEncodeCertificate (
131   IN CONST CHAR16         *FileSuffix
132 )
133 {
134   UINTN     Index;
135   for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {
136     if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {
137       return TRUE;
138     }
139   }
140   return FALSE;
141 }
142 
143 /**
144   This code checks if the file content complies with EFI_VARIABLE_AUTHENTICATION_2 format
145 The function reads file content but won't open/close given FileHandle.
146 
147   @param[in] FileHandle            The FileHandle to be checked
148 
149   @retval    TRUE            The content is EFI_VARIABLE_AUTHENTICATION_2 format.
150   @retval    FALSE          The content is NOT a EFI_VARIABLE_AUTHENTICATION_2 format.
151 
152 **/
153 BOOLEAN
IsAuthentication2Format(IN EFI_FILE_HANDLE FileHandle)154 IsAuthentication2Format (
155   IN   EFI_FILE_HANDLE    FileHandle
156 )
157 {
158   EFI_STATUS                     Status;
159   EFI_VARIABLE_AUTHENTICATION_2  *Auth2;
160   BOOLEAN                        IsAuth2Format;
161 
162   IsAuth2Format = FALSE;
163 
164   //
165   // Read the whole file content
166   //
167   Status = ReadFileContent(
168              FileHandle,
169              (VOID **) &mImageBase,
170              &mImageSize,
171              0
172              );
173   if (EFI_ERROR (Status)) {
174     goto ON_EXIT;
175   }
176 
177   Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)mImageBase;
178   if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {
179     goto ON_EXIT;
180   }
181 
182   if (CompareGuid(&gEfiCertPkcs7Guid, &Auth2->AuthInfo.CertType)) {
183     IsAuth2Format = TRUE;
184   }
185 
186 ON_EXIT:
187   //
188   // Do not close File. simply check file content
189   //
190   if (mImageBase != NULL) {
191     FreePool (mImageBase);
192     mImageBase = NULL;
193   }
194 
195   return IsAuth2Format;
196 }
197 
198 /**
199   Set Secure Boot option into variable space.
200 
201   @param[in] VarValue              The option of Secure Boot.
202 
203   @retval    EFI_SUCCESS           The operation is finished successfully.
204   @retval    Others                Other errors as indicated.
205 
206 **/
207 EFI_STATUS
SaveSecureBootVariable(IN UINT8 VarValue)208 SaveSecureBootVariable (
209   IN UINT8                         VarValue
210   )
211 {
212   EFI_STATUS                       Status;
213 
214   Status = gRT->SetVariable (
215              EFI_SECURE_BOOT_ENABLE_NAME,
216              &gEfiSecureBootEnableDisableGuid,
217              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
218              sizeof (UINT8),
219              &VarValue
220              );
221   return Status;
222 }
223 
224 /**
225   Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
226   descriptor with the input data. NO authentication is required in this function.
227 
228   @param[in, out]   DataSize       On input, the size of Data buffer in bytes.
229                                    On output, the size of data returned in Data
230                                    buffer in bytes.
231   @param[in, out]   Data           On input, Pointer to data buffer to be wrapped or
232                                    pointer to NULL to wrap an empty payload.
233                                    On output, Pointer to the new payload date buffer allocated from pool,
234                                    it's caller's responsibility to free the memory when finish using it.
235 
236   @retval EFI_SUCCESS              Create time based payload successfully.
237   @retval EFI_OUT_OF_RESOURCES     There are not enough memory resourses to create time based payload.
238   @retval EFI_INVALID_PARAMETER    The parameter is invalid.
239   @retval Others                   Unexpected error happens.
240 
241 **/
242 EFI_STATUS
CreateTimeBasedPayload(IN OUT UINTN * DataSize,IN OUT UINT8 ** Data)243 CreateTimeBasedPayload (
244   IN OUT UINTN            *DataSize,
245   IN OUT UINT8            **Data
246   )
247 {
248   EFI_STATUS                       Status;
249   UINT8                            *NewData;
250   UINT8                            *Payload;
251   UINTN                            PayloadSize;
252   EFI_VARIABLE_AUTHENTICATION_2    *DescriptorData;
253   UINTN                            DescriptorSize;
254   EFI_TIME                         Time;
255 
256   if (Data == NULL || DataSize == NULL) {
257     return EFI_INVALID_PARAMETER;
258   }
259 
260   //
261   // In Setup mode or Custom mode, the variable does not need to be signed but the
262   // parameters to the SetVariable() call still need to be prepared as authenticated
263   // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
264   // data in it.
265   //
266   Payload     = *Data;
267   PayloadSize = *DataSize;
268 
269   DescriptorSize    = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
270   NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
271   if (NewData == NULL) {
272     return EFI_OUT_OF_RESOURCES;
273   }
274 
275   if ((Payload != NULL) && (PayloadSize != 0)) {
276     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
277   }
278 
279   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
280 
281   ZeroMem (&Time, sizeof (EFI_TIME));
282   Status = gRT->GetTime (&Time, NULL);
283   if (EFI_ERROR (Status)) {
284     FreePool(NewData);
285     return Status;
286   }
287   Time.Pad1       = 0;
288   Time.Nanosecond = 0;
289   Time.TimeZone   = 0;
290   Time.Daylight   = 0;
291   Time.Pad2       = 0;
292   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
293 
294   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
295   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
296   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
297   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
298 
299   if (Payload != NULL) {
300     FreePool(Payload);
301   }
302 
303   *DataSize = DescriptorSize + PayloadSize;
304   *Data     = NewData;
305   return EFI_SUCCESS;
306 }
307 
308 /**
309   Internal helper function to delete a Variable given its name and GUID, NO authentication
310   required.
311 
312   @param[in]      VariableName            Name of the Variable.
313   @param[in]      VendorGuid              GUID of the Variable.
314 
315   @retval EFI_SUCCESS              Variable deleted successfully.
316   @retval Others                   The driver failed to start the device.
317 
318 **/
319 EFI_STATUS
DeleteVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid)320 DeleteVariable (
321   IN  CHAR16                    *VariableName,
322   IN  EFI_GUID                  *VendorGuid
323   )
324 {
325   EFI_STATUS              Status;
326   VOID*                   Variable;
327   UINT8                   *Data;
328   UINTN                   DataSize;
329   UINT32                  Attr;
330 
331   GetVariable2 (VariableName, VendorGuid, &Variable, NULL);
332   if (Variable == NULL) {
333     return EFI_SUCCESS;
334   }
335   FreePool (Variable);
336 
337   Data     = NULL;
338   DataSize = 0;
339   Attr     = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
340              | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
341 
342   Status = CreateTimeBasedPayload (&DataSize, &Data);
343   if (EFI_ERROR (Status)) {
344     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
345     return Status;
346   }
347 
348   Status = gRT->SetVariable (
349                   VariableName,
350                   VendorGuid,
351                   Attr,
352                   DataSize,
353                   Data
354                   );
355   if (Data != NULL) {
356     FreePool (Data);
357   }
358   return Status;
359 }
360 
361 /**
362 
363   Set the platform secure boot mode into "Custom" or "Standard" mode.
364 
365   @param[in]   SecureBootMode        New secure boot mode: STANDARD_SECURE_BOOT_MODE or
366                                      CUSTOM_SECURE_BOOT_MODE.
367 
368   @return EFI_SUCCESS                The platform has switched to the special mode successfully.
369   @return other                      Fail to operate the secure boot mode.
370 
371 **/
372 EFI_STATUS
SetSecureBootMode(IN UINT8 SecureBootMode)373 SetSecureBootMode (
374   IN     UINT8         SecureBootMode
375   )
376 {
377   return gRT->SetVariable (
378                 EFI_CUSTOM_MODE_NAME,
379                 &gEfiCustomModeEnableGuid,
380                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
381                 sizeof (UINT8),
382                 &SecureBootMode
383                 );
384 }
385 
386 /**
387   Generate the PK signature list from the X509 Certificate storing file (.cer)
388 
389   @param[in]   X509File              FileHandle of X509 Certificate storing file.
390   @param[out]  PkCert                Point to the data buffer to store the signature list.
391 
392   @return EFI_UNSUPPORTED            Unsupported Key Length.
393   @return EFI_OUT_OF_RESOURCES       There are not enough memory resourses to form the signature list.
394 
395 **/
396 EFI_STATUS
CreatePkX509SignatureList(IN EFI_FILE_HANDLE X509File,OUT EFI_SIGNATURE_LIST ** PkCert)397 CreatePkX509SignatureList (
398   IN    EFI_FILE_HANDLE             X509File,
399   OUT   EFI_SIGNATURE_LIST          **PkCert
400   )
401 {
402   EFI_STATUS              Status;
403   UINT8                   *X509Data;
404   UINTN                   X509DataSize;
405   EFI_SIGNATURE_DATA      *PkCertData;
406 
407   X509Data = NULL;
408   PkCertData = NULL;
409   X509DataSize = 0;
410 
411   Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);
412   if (EFI_ERROR (Status)) {
413     goto ON_EXIT;
414   }
415   ASSERT (X509Data != NULL);
416 
417   //
418   // Allocate space for PK certificate list and initialize it.
419   // Create PK database entry with SignatureHeaderSize equals 0.
420   //
421   *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool (
422               sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
423               + X509DataSize
424               );
425   if (*PkCert == NULL) {
426     Status = EFI_OUT_OF_RESOURCES;
427     goto ON_EXIT;
428   }
429 
430   (*PkCert)->SignatureListSize   = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
431                                     + sizeof(EFI_SIGNATURE_DATA) - 1
432                                     + X509DataSize);
433   (*PkCert)->SignatureSize       = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
434   (*PkCert)->SignatureHeaderSize = 0;
435   CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid);
436   PkCertData                     = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert)
437                                                           + sizeof(EFI_SIGNATURE_LIST)
438                                                           + (*PkCert)->SignatureHeaderSize);
439   CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);
440   //
441   // Fill the PK database with PKpub data from X509 certificate file.
442   //
443   CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize);
444 
445 ON_EXIT:
446 
447   if (X509Data != NULL) {
448     FreePool (X509Data);
449   }
450 
451   if (EFI_ERROR(Status) && *PkCert != NULL) {
452     FreePool (*PkCert);
453     *PkCert = NULL;
454   }
455 
456   return Status;
457 }
458 
459 /**
460   Enroll new PK into the System without original PK's authentication.
461 
462   The SignatureOwner GUID will be the same with PK's vendorguid.
463 
464   @param[in] PrivateData     The module's private data.
465 
466   @retval   EFI_SUCCESS            New PK enrolled successfully.
467   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
468   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
469 
470 **/
471 EFI_STATUS
EnrollPlatformKey(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)472 EnrollPlatformKey (
473    IN  SECUREBOOT_CONFIG_PRIVATE_DATA*   Private
474   )
475 {
476   EFI_STATUS                      Status;
477   UINT32                          Attr;
478   UINTN                           DataSize;
479   EFI_SIGNATURE_LIST              *PkCert;
480   UINT16*                         FilePostFix;
481   UINTN                           NameLength;
482 
483   if (Private->FileContext->FileName == NULL) {
484     return EFI_INVALID_PARAMETER;
485   }
486 
487   PkCert = NULL;
488 
489   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
490   if (EFI_ERROR (Status)) {
491     return Status;
492   }
493 
494   //
495   // Parse the file's postfix. Only support DER encoded X.509 certificate files.
496   //
497   NameLength = StrLen (Private->FileContext->FileName);
498   if (NameLength <= 4) {
499     return EFI_INVALID_PARAMETER;
500   }
501   FilePostFix = Private->FileContext->FileName + NameLength - 4;
502   if (!IsDerEncodeCertificate(FilePostFix)) {
503     DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix));
504     return EFI_INVALID_PARAMETER;
505   }
506   DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName));
507   DEBUG ((EFI_D_INFO, "FilePostFix = %s\n", FilePostFix));
508 
509   //
510   // Prase the selected PK file and generature PK certificate list.
511   //
512   Status = CreatePkX509SignatureList (
513             Private->FileContext->FHandle,
514             &PkCert
515             );
516   if (EFI_ERROR (Status)) {
517     goto ON_EXIT;
518   }
519   ASSERT (PkCert != NULL);
520 
521   //
522   // Set Platform Key variable.
523   //
524   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
525           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
526   DataSize = PkCert->SignatureListSize;
527   Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);
528   if (EFI_ERROR (Status)) {
529     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
530     goto ON_EXIT;
531   }
532 
533   Status = gRT->SetVariable(
534                   EFI_PLATFORM_KEY_NAME,
535                   &gEfiGlobalVariableGuid,
536                   Attr,
537                   DataSize,
538                   PkCert
539                   );
540   if (EFI_ERROR (Status)) {
541     if (Status == EFI_OUT_OF_RESOURCES) {
542       DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n"));
543     }
544     goto ON_EXIT;
545   }
546 
547 ON_EXIT:
548 
549   if (PkCert != NULL) {
550     FreePool(PkCert);
551   }
552 
553   CloseEnrolledFile(Private->FileContext);
554 
555   return Status;
556 }
557 
558 /**
559   Remove the PK variable.
560 
561   @retval EFI_SUCCESS    Delete PK successfully.
562   @retval Others         Could not allow to delete PK.
563 
564 **/
565 EFI_STATUS
DeletePlatformKey(VOID)566 DeletePlatformKey (
567   VOID
568 )
569 {
570   EFI_STATUS Status;
571 
572   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
573   if (EFI_ERROR (Status)) {
574     return Status;
575   }
576 
577   Status = DeleteVariable (
578              EFI_PLATFORM_KEY_NAME,
579              &gEfiGlobalVariableGuid
580              );
581   return Status;
582 }
583 
584 /**
585   Enroll a new KEK item from public key storing file (*.pbk).
586 
587   @param[in] PrivateData           The module's private data.
588 
589   @retval   EFI_SUCCESS            New KEK enrolled successfully.
590   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
591   @retval   EFI_UNSUPPORTED        Unsupported command.
592   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
593 
594 **/
595 EFI_STATUS
EnrollRsa2048ToKek(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)596 EnrollRsa2048ToKek (
597   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
598   )
599 {
600   EFI_STATUS                      Status;
601   UINT32                          Attr;
602   UINTN                           DataSize;
603   EFI_SIGNATURE_LIST              *KekSigList;
604   UINTN                           KeyBlobSize;
605   UINT8                           *KeyBlob;
606   CPL_KEY_INFO                    *KeyInfo;
607   EFI_SIGNATURE_DATA              *KEKSigData;
608   UINTN                           KekSigListSize;
609   UINT8                           *KeyBuffer;
610   UINTN                           KeyLenInBytes;
611 
612   Attr        = 0;
613   DataSize    = 0;
614   KeyBuffer   = NULL;
615   KeyBlobSize = 0;
616   KeyBlob     = NULL;
617   KeyInfo     = NULL;
618   KEKSigData  = NULL;
619   KekSigList  = NULL;
620   KekSigListSize = 0;
621 
622   //
623   // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type.
624   // First, We have to parse out public key data from the pbk key file.
625   //
626   Status = ReadFileContent (
627              Private->FileContext->FHandle,
628              (VOID**) &KeyBlob,
629              &KeyBlobSize,
630              0
631              );
632   if (EFI_ERROR (Status)) {
633     goto ON_EXIT;
634   }
635   ASSERT (KeyBlob != NULL);
636   KeyInfo = (CPL_KEY_INFO *) KeyBlob;
637   if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {
638     DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));
639     Status = EFI_UNSUPPORTED;
640     goto ON_EXIT;
641   }
642 
643   //
644   // Convert the Public key to fix octet string format represented in RSA PKCS#1.
645   //
646   KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;
647   KeyBuffer = AllocateZeroPool (KeyLenInBytes);
648   if (KeyBuffer == NULL) {
649     Status = EFI_OUT_OF_RESOURCES;
650     goto ON_EXIT;
651   }
652   Int2OctStr (
653     (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)),
654     KeyLenInBytes / sizeof (UINTN),
655     KeyBuffer,
656     KeyLenInBytes
657     );
658   CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes);
659 
660   //
661   // Form an new EFI_SIGNATURE_LIST.
662   //
663   KekSigListSize = sizeof(EFI_SIGNATURE_LIST)
664                      + sizeof(EFI_SIGNATURE_DATA) - 1
665                      + WIN_CERT_UEFI_RSA2048_SIZE;
666 
667   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
668   if (KekSigList == NULL) {
669     Status = EFI_OUT_OF_RESOURCES;
670     goto ON_EXIT;
671   }
672 
673   KekSigList->SignatureListSize   = sizeof(EFI_SIGNATURE_LIST)
674                                   + sizeof(EFI_SIGNATURE_DATA) - 1
675                                   + WIN_CERT_UEFI_RSA2048_SIZE;
676   KekSigList->SignatureHeaderSize = 0;
677   KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;
678   CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid);
679 
680   KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST));
681   CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
682   CopyMem (
683     KEKSigData->SignatureData,
684     KeyBlob + sizeof(CPL_KEY_INFO),
685     WIN_CERT_UEFI_RSA2048_SIZE
686     );
687 
688   //
689   // Check if KEK entry has been already existed.
690   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
691   // new KEK to original variable.
692   //
693   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
694          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
695   Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
696   if (EFI_ERROR (Status)) {
697     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
698     goto ON_EXIT;
699   }
700 
701   Status = gRT->GetVariable(
702                   EFI_KEY_EXCHANGE_KEY_NAME,
703                   &gEfiGlobalVariableGuid,
704                   NULL,
705                   &DataSize,
706                   NULL
707                   );
708   if (Status == EFI_BUFFER_TOO_SMALL) {
709     Attr |= EFI_VARIABLE_APPEND_WRITE;
710   } else if (Status != EFI_NOT_FOUND) {
711     goto ON_EXIT;
712   }
713 
714   //
715   // Done. Now we have formed the correct KEKpub database item, just set it into variable storage,
716   //
717   Status = gRT->SetVariable(
718                   EFI_KEY_EXCHANGE_KEY_NAME,
719                   &gEfiGlobalVariableGuid,
720                   Attr,
721                   KekSigListSize,
722                   KekSigList
723                   );
724   if (EFI_ERROR (Status)) {
725     goto ON_EXIT;
726   }
727 
728 ON_EXIT:
729 
730   CloseEnrolledFile(Private->FileContext);
731 
732   if (Private->SignatureGUID != NULL) {
733     FreePool (Private->SignatureGUID);
734     Private->SignatureGUID = NULL;
735   }
736 
737   if (KeyBlob != NULL) {
738     FreePool (KeyBlob);
739   }
740   if (KeyBuffer != NULL) {
741     FreePool (KeyBuffer);
742   }
743   if (KekSigList != NULL) {
744     FreePool (KekSigList);
745   }
746 
747   return Status;
748 }
749 
750 /**
751   Enroll a new KEK item from X509 certificate file.
752 
753   @param[in] PrivateData           The module's private data.
754 
755   @retval   EFI_SUCCESS            New X509 is enrolled successfully.
756   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
757   @retval   EFI_UNSUPPORTED        Unsupported command.
758   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
759 
760 **/
761 EFI_STATUS
EnrollX509ToKek(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)762 EnrollX509ToKek (
763   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
764   )
765 {
766   EFI_STATUS                        Status;
767   UINTN                             X509DataSize;
768   VOID                              *X509Data;
769   EFI_SIGNATURE_DATA                *KEKSigData;
770   EFI_SIGNATURE_LIST                *KekSigList;
771   UINTN                             DataSize;
772   UINTN                             KekSigListSize;
773   UINT32                            Attr;
774 
775   X509Data       = NULL;
776   X509DataSize   = 0;
777   KekSigList     = NULL;
778   KekSigListSize = 0;
779   DataSize       = 0;
780   KEKSigData     = NULL;
781 
782   Status = ReadFileContent (
783              Private->FileContext->FHandle,
784              &X509Data,
785              &X509DataSize,
786              0
787              );
788   if (EFI_ERROR (Status)) {
789     goto ON_EXIT;
790   }
791   ASSERT (X509Data != NULL);
792 
793   KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
794   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
795   if (KekSigList == NULL) {
796     Status = EFI_OUT_OF_RESOURCES;
797     goto ON_EXIT;
798   }
799 
800   //
801   // Fill Certificate Database parameters.
802   //
803   KekSigList->SignatureListSize   = (UINT32) KekSigListSize;
804   KekSigList->SignatureHeaderSize = 0;
805   KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
806   CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid);
807 
808   KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST));
809   CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
810   CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize);
811 
812   //
813   // Check if KEK been already existed.
814   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
815   // new kek to original variable
816   //
817   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
818           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
819   Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
820   if (EFI_ERROR (Status)) {
821     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
822     goto ON_EXIT;
823   }
824 
825   Status = gRT->GetVariable(
826                   EFI_KEY_EXCHANGE_KEY_NAME,
827                   &gEfiGlobalVariableGuid,
828                   NULL,
829                   &DataSize,
830                   NULL
831                   );
832   if (Status == EFI_BUFFER_TOO_SMALL) {
833     Attr |= EFI_VARIABLE_APPEND_WRITE;
834   } else if (Status != EFI_NOT_FOUND) {
835     goto ON_EXIT;
836   }
837 
838   Status = gRT->SetVariable(
839                   EFI_KEY_EXCHANGE_KEY_NAME,
840                   &gEfiGlobalVariableGuid,
841                   Attr,
842                   KekSigListSize,
843                   KekSigList
844                   );
845   if (EFI_ERROR (Status)) {
846     goto ON_EXIT;
847   }
848 
849 ON_EXIT:
850 
851   CloseEnrolledFile(Private->FileContext);
852 
853   if (Private->SignatureGUID != NULL) {
854     FreePool (Private->SignatureGUID);
855     Private->SignatureGUID = NULL;
856   }
857 
858   if (KekSigList != NULL) {
859     FreePool (KekSigList);
860   }
861 
862   return Status;
863 }
864 
865 /**
866   Enroll new KEK into the System without PK's authentication.
867   The SignatureOwner GUID will be Private->SignatureGUID.
868 
869   @param[in] PrivateData     The module's private data.
870 
871   @retval   EFI_SUCCESS            New KEK enrolled successful.
872   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
873   @retval   others                 Fail to enroll KEK data.
874 
875 **/
876 EFI_STATUS
EnrollKeyExchangeKey(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)877 EnrollKeyExchangeKey (
878   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
879   )
880 {
881   UINT16*     FilePostFix;
882   EFI_STATUS  Status;
883   UINTN       NameLength;
884 
885   if ((Private->FileContext->FHandle == NULL) || (Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {
886     return EFI_INVALID_PARAMETER;
887   }
888 
889   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
890   if (EFI_ERROR (Status)) {
891     return Status;
892   }
893 
894   //
895   // Parse the file's postfix. Supports DER-encoded X509 certificate,
896   // and .pbk as RSA public key file.
897   //
898   NameLength = StrLen (Private->FileContext->FileName);
899   if (NameLength <= 4) {
900     return EFI_INVALID_PARAMETER;
901   }
902   FilePostFix = Private->FileContext->FileName + NameLength - 4;
903   if (IsDerEncodeCertificate(FilePostFix)) {
904     return EnrollX509ToKek (Private);
905   } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {
906     return EnrollRsa2048ToKek (Private);
907   } else {
908     //
909     // File type is wrong, simply close it
910     //
911     CloseEnrolledFile(Private->FileContext);
912 
913     return EFI_INVALID_PARAMETER;
914   }
915 }
916 
917 /**
918   Enroll a new X509 certificate into Signature Database (DB or DBX or DBT) without
919   KEK's authentication.
920 
921   @param[in] PrivateData     The module's private data.
922   @param[in] VariableName    Variable name of signature database, must be
923                              EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
924 
925   @retval   EFI_SUCCESS            New X509 is enrolled successfully.
926   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
927 
928 **/
929 EFI_STATUS
EnrollX509toSigDB(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)930 EnrollX509toSigDB (
931   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
932   IN CHAR16                         *VariableName
933   )
934 {
935   EFI_STATUS                        Status;
936   UINTN                             X509DataSize;
937   VOID                              *X509Data;
938   EFI_SIGNATURE_LIST                *SigDBCert;
939   EFI_SIGNATURE_DATA                *SigDBCertData;
940   VOID                              *Data;
941   UINTN                             DataSize;
942   UINTN                             SigDBSize;
943   UINT32                            Attr;
944 
945   X509DataSize  = 0;
946   SigDBSize     = 0;
947   DataSize      = 0;
948   X509Data      = NULL;
949   SigDBCert     = NULL;
950   SigDBCertData = NULL;
951   Data          = NULL;
952 
953   Status = ReadFileContent (
954              Private->FileContext->FHandle,
955              &X509Data,
956              &X509DataSize,
957              0
958              );
959   if (EFI_ERROR (Status)) {
960     goto ON_EXIT;
961   }
962   ASSERT (X509Data != NULL);
963 
964   SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
965 
966   Data = AllocateZeroPool (SigDBSize);
967   if (Data == NULL) {
968     Status = EFI_OUT_OF_RESOURCES;
969     goto ON_EXIT;
970   }
971 
972   //
973   // Fill Certificate Database parameters.
974   //
975   SigDBCert = (EFI_SIGNATURE_LIST*) Data;
976   SigDBCert->SignatureListSize   = (UINT32) SigDBSize;
977   SigDBCert->SignatureHeaderSize = 0;
978   SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
979   CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid);
980 
981   SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST));
982   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
983   CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize);
984 
985   //
986   // Check if signature database entry has been already existed.
987   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
988   // new signature data to original variable
989   //
990   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
991           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
992   Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
993   if (EFI_ERROR (Status)) {
994     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
995     goto ON_EXIT;
996   }
997 
998   Status = gRT->GetVariable(
999                   VariableName,
1000                   &gEfiImageSecurityDatabaseGuid,
1001                   NULL,
1002                   &DataSize,
1003                   NULL
1004                   );
1005   if (Status == EFI_BUFFER_TOO_SMALL) {
1006     Attr |= EFI_VARIABLE_APPEND_WRITE;
1007   } else if (Status != EFI_NOT_FOUND) {
1008     goto ON_EXIT;
1009   }
1010 
1011   Status = gRT->SetVariable(
1012                   VariableName,
1013                   &gEfiImageSecurityDatabaseGuid,
1014                   Attr,
1015                   SigDBSize,
1016                   Data
1017                   );
1018   if (EFI_ERROR (Status)) {
1019     goto ON_EXIT;
1020   }
1021 
1022 ON_EXIT:
1023 
1024   CloseEnrolledFile(Private->FileContext);
1025 
1026   if (Private->SignatureGUID != NULL) {
1027     FreePool (Private->SignatureGUID);
1028     Private->SignatureGUID = NULL;
1029   }
1030 
1031   if (Data != NULL) {
1032     FreePool (Data);
1033   }
1034 
1035   if (X509Data != NULL) {
1036     FreePool (X509Data);
1037   }
1038 
1039   return Status;
1040 }
1041 
1042 /**
1043   Check whether signature is in specified database.
1044 
1045   @param[in]  VariableName        Name of database variable that is searched in.
1046   @param[in]  Signature           Pointer to signature that is searched for.
1047   @param[in]  SignatureSize       Size of Signature.
1048 
1049   @return TRUE                    Found the signature in the variable database.
1050   @return FALSE                   Not found the signature in the variable database.
1051 
1052 **/
1053 BOOLEAN
IsSignatureFoundInDatabase(IN CHAR16 * VariableName,IN UINT8 * Signature,IN UINTN SignatureSize)1054 IsSignatureFoundInDatabase (
1055   IN CHAR16             *VariableName,
1056   IN UINT8              *Signature,
1057   IN UINTN              SignatureSize
1058   )
1059 {
1060   EFI_STATUS          Status;
1061   EFI_SIGNATURE_LIST  *CertList;
1062   EFI_SIGNATURE_DATA  *Cert;
1063   UINTN               DataSize;
1064   UINT8               *Data;
1065   UINTN               Index;
1066   UINTN               CertCount;
1067   BOOLEAN             IsFound;
1068 
1069   //
1070   // Read signature database variable.
1071   //
1072   IsFound   = FALSE;
1073   Data      = NULL;
1074   DataSize  = 0;
1075   Status    = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1076   if (Status != EFI_BUFFER_TOO_SMALL) {
1077     return FALSE;
1078   }
1079 
1080   Data = (UINT8 *) AllocateZeroPool (DataSize);
1081   if (Data == NULL) {
1082     return FALSE;
1083   }
1084 
1085   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1086   if (EFI_ERROR (Status)) {
1087     goto Done;
1088   }
1089 
1090   //
1091   // Enumerate all signature data in SigDB to check if executable's signature exists.
1092   //
1093   CertList = (EFI_SIGNATURE_LIST *) Data;
1094   while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1095     CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1096     Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1097     if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &gEfiCertX509Guid))) {
1098       for (Index = 0; Index < CertCount; Index++) {
1099         if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {
1100           //
1101           // Find the signature in database.
1102           //
1103           IsFound = TRUE;
1104           break;
1105         }
1106         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1107       }
1108 
1109       if (IsFound) {
1110         break;
1111       }
1112     }
1113 
1114     DataSize -= CertList->SignatureListSize;
1115     CertList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1116   }
1117 
1118 Done:
1119   if (Data != NULL) {
1120     FreePool (Data);
1121   }
1122 
1123   return IsFound;
1124 }
1125 
1126 /**
1127   Calculate the hash of a certificate data with the specified hash algorithm.
1128 
1129   @param[in]    CertData  The certificate data to be hashed.
1130   @param[in]    CertSize  The certificate size in bytes.
1131   @param[in]    HashAlg   The specified hash algorithm.
1132   @param[out]   CertHash  The output digest of the certificate
1133 
1134   @retval TRUE            Successfully got the hash of the CertData.
1135   @retval FALSE           Failed to get the hash of CertData.
1136 
1137 **/
1138 BOOLEAN
CalculateCertHash(IN UINT8 * CertData,IN UINTN CertSize,IN UINT32 HashAlg,OUT UINT8 * CertHash)1139 CalculateCertHash (
1140   IN  UINT8                 *CertData,
1141   IN  UINTN                 CertSize,
1142   IN  UINT32                HashAlg,
1143   OUT UINT8                 *CertHash
1144   )
1145 {
1146   BOOLEAN                   Status;
1147   VOID                      *HashCtx;
1148   UINTN                     CtxSize;
1149   UINT8                     *TBSCert;
1150   UINTN                     TBSCertSize;
1151 
1152   HashCtx = NULL;
1153   Status  = FALSE;
1154 
1155   if (HashAlg >= HASHALG_MAX) {
1156     return FALSE;
1157   }
1158 
1159   //
1160   // Retrieve the TBSCertificate for Hash Calculation.
1161   //
1162   if (!X509GetTBSCert (CertData, CertSize, &TBSCert, &TBSCertSize)) {
1163     return FALSE;
1164   }
1165 
1166   //
1167   // 1. Initialize context of hash.
1168   //
1169   CtxSize = mHash[HashAlg].GetContextSize ();
1170   HashCtx = AllocatePool (CtxSize);
1171   ASSERT (HashCtx != NULL);
1172 
1173   //
1174   // 2. Initialize a hash context.
1175   //
1176   Status = mHash[HashAlg].HashInit (HashCtx);
1177   if (!Status) {
1178     goto Done;
1179   }
1180 
1181   //
1182   // 3. Calculate the hash.
1183   //
1184   Status  = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
1185   if (!Status) {
1186     goto Done;
1187   }
1188 
1189   //
1190   // 4. Get the hash result.
1191   //
1192   ZeroMem (CertHash, mHash[HashAlg].DigestLength);
1193   Status  = mHash[HashAlg].HashFinal (HashCtx, CertHash);
1194 
1195 Done:
1196   if (HashCtx != NULL) {
1197     FreePool (HashCtx);
1198   }
1199 
1200   return Status;
1201 }
1202 
1203 /**
1204   Check whether the hash of an X.509 certificate is in forbidden database (DBX).
1205 
1206   @param[in]  Certificate       Pointer to X.509 Certificate that is searched for.
1207   @param[in]  CertSize          Size of X.509 Certificate.
1208 
1209   @return TRUE               Found the certificate hash in the forbidden database.
1210   @return FALSE              Certificate hash is Not found in the forbidden database.
1211 
1212 **/
1213 BOOLEAN
IsCertHashFoundInDbx(IN UINT8 * Certificate,IN UINTN CertSize)1214 IsCertHashFoundInDbx (
1215   IN  UINT8               *Certificate,
1216   IN  UINTN               CertSize
1217   )
1218 {
1219   BOOLEAN                 IsFound;
1220   EFI_STATUS              Status;
1221   EFI_SIGNATURE_LIST      *DbxList;
1222   EFI_SIGNATURE_DATA      *CertHash;
1223   UINTN                   CertHashCount;
1224   UINTN                   Index;
1225   UINT32                  HashAlg;
1226   UINT8                   CertDigest[MAX_DIGEST_SIZE];
1227   UINT8                   *DbxCertHash;
1228   UINTN                   SiglistHeaderSize;
1229   UINT8                   *Data;
1230   UINTN                   DataSize;
1231 
1232   IsFound  = FALSE;
1233   HashAlg  = HASHALG_MAX;
1234   Data     = NULL;
1235 
1236   //
1237   // Read signature database variable.
1238   //
1239   DataSize  = 0;
1240   Status    = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1241   if (Status != EFI_BUFFER_TOO_SMALL) {
1242     return FALSE;
1243   }
1244 
1245   Data = (UINT8 *) AllocateZeroPool (DataSize);
1246   if (Data == NULL) {
1247     return FALSE;
1248   }
1249 
1250   Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1251   if (EFI_ERROR (Status)) {
1252     goto Done;
1253   }
1254 
1255   //
1256   // Check whether the certificate hash exists in the forbidden database.
1257   //
1258   DbxList = (EFI_SIGNATURE_LIST *) Data;
1259   while ((DataSize > 0) && (DataSize >= DbxList->SignatureListSize)) {
1260     //
1261     // Determine Hash Algorithm of Certificate in the forbidden database.
1262     //
1263     if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
1264       HashAlg = HASHALG_SHA256;
1265     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
1266       HashAlg = HASHALG_SHA384;
1267     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
1268       HashAlg = HASHALG_SHA512;
1269     } else {
1270       DataSize -= DbxList->SignatureListSize;
1271       DbxList   = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1272       continue;
1273     }
1274 
1275     //
1276     // Calculate the hash value of current db certificate for comparision.
1277     //
1278     if (!CalculateCertHash (Certificate, CertSize, HashAlg, CertDigest)) {
1279       goto Done;
1280     }
1281 
1282     SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
1283     CertHash          = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
1284     CertHashCount     = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
1285     for (Index = 0; Index < CertHashCount; Index++) {
1286       //
1287       // Iterate each Signature Data Node within this CertList for verify.
1288       //
1289       DbxCertHash = CertHash->SignatureData;
1290       if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
1291         //
1292         // Hash of Certificate is found in forbidden database.
1293         //
1294         IsFound = TRUE;
1295         goto Done;
1296       }
1297       CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
1298     }
1299 
1300     DataSize -= DbxList->SignatureListSize;
1301     DbxList   = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1302   }
1303 
1304 Done:
1305   if (Data != NULL) {
1306     FreePool (Data);
1307   }
1308 
1309   return IsFound;
1310 }
1311 
1312 /**
1313   Check whether the signature list exists in given variable data.
1314 
1315   It searches the signature list for the ceritificate hash by CertType.
1316   If the signature list is found, get the offset of Database for the
1317   next hash of a certificate.
1318 
1319   @param[in]  Database      Variable data to save signature list.
1320   @param[in]  DatabaseSize  Variable size.
1321   @param[in]  SignatureType The type of the signature.
1322   @param[out] Offset        The offset to save a new hash of certificate.
1323 
1324   @return TRUE       The signature list is found in the forbidden database.
1325   @return FALSE      The signature list is not found in the forbidden database.
1326 **/
1327 BOOLEAN
GetSignaturelistOffset(IN EFI_SIGNATURE_LIST * Database,IN UINTN DatabaseSize,IN EFI_GUID * SignatureType,OUT UINTN * Offset)1328 GetSignaturelistOffset (
1329   IN  EFI_SIGNATURE_LIST  *Database,
1330   IN  UINTN               DatabaseSize,
1331   IN  EFI_GUID            *SignatureType,
1332   OUT UINTN               *Offset
1333   )
1334 {
1335   EFI_SIGNATURE_LIST      *SigList;
1336   UINTN                   SiglistSize;
1337 
1338   if ((Database == NULL) || (DatabaseSize == 0)) {
1339     *Offset = 0;
1340     return FALSE;
1341   }
1342 
1343   SigList     = Database;
1344   SiglistSize = DatabaseSize;
1345   while ((SiglistSize > 0) && (SiglistSize >= SigList->SignatureListSize)) {
1346     if (CompareGuid (&SigList->SignatureType, SignatureType)) {
1347       *Offset = DatabaseSize - SiglistSize;
1348       return TRUE;
1349     }
1350     SiglistSize -= SigList->SignatureListSize;
1351     SigList      = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
1352   }
1353   *Offset = 0;
1354   return FALSE;
1355 }
1356 
1357 /**
1358   Enroll a new X509 certificate hash into Signature Database (dbx) without
1359   KEK's authentication.
1360 
1361   @param[in] PrivateData      The module's private data.
1362   @param[in] HashAlg          The hash algorithm to enroll the certificate.
1363   @param[in] RevocationDate   The revocation date of the certificate.
1364   @param[in] RevocationTime   The revocation time of the certificate.
1365   @param[in] AlwaysRevocation Indicate whether the certificate is always revoked.
1366 
1367   @retval   EFI_SUCCESS            New X509 is enrolled successfully.
1368   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
1369   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
1370 
1371 **/
1372 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)1373 EnrollX509HashtoSigDB (
1374   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1375   IN UINT32                         HashAlg,
1376   IN EFI_HII_DATE                   *RevocationDate,
1377   IN EFI_HII_TIME                   *RevocationTime,
1378   IN BOOLEAN                        AlwaysRevocation
1379   )
1380 {
1381   EFI_STATUS          Status;
1382   UINTN               X509DataSize;
1383   VOID                *X509Data;
1384   EFI_SIGNATURE_LIST  *SignatureList;
1385   UINTN               SignatureListSize;
1386   UINT8               *Data;
1387   UINT8               *NewData;
1388   UINTN               DataSize;
1389   UINTN               DbSize;
1390   UINT32              Attr;
1391   EFI_SIGNATURE_DATA  *SignatureData;
1392   UINTN               SignatureSize;
1393   EFI_GUID            SignatureType;
1394   UINTN               Offset;
1395   UINT8               CertHash[MAX_DIGEST_SIZE];
1396   UINT16*             FilePostFix;
1397   UINTN               NameLength;
1398   EFI_TIME            *Time;
1399 
1400   X509DataSize  = 0;
1401   DbSize        = 0;
1402   X509Data      = NULL;
1403   SignatureData = NULL;
1404   SignatureList = NULL;
1405   Data          = NULL;
1406   NewData       = NULL;
1407 
1408   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
1409     return EFI_INVALID_PARAMETER;
1410   }
1411 
1412   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
1413   if (EFI_ERROR (Status)) {
1414     return Status;
1415   }
1416 
1417   //
1418   // Parse the file's postfix.
1419   //
1420   NameLength = StrLen (Private->FileContext->FileName);
1421   if (NameLength <= 4) {
1422     return EFI_INVALID_PARAMETER;
1423   }
1424   FilePostFix = Private->FileContext->FileName + NameLength - 4;
1425   if (!IsDerEncodeCertificate(FilePostFix)) {
1426     //
1427     // Only supports DER-encoded X509 certificate.
1428     //
1429     return EFI_INVALID_PARAMETER;
1430   }
1431 
1432   //
1433   // Get the certificate from file and calculate its hash.
1434   //
1435   Status = ReadFileContent (
1436              Private->FileContext->FHandle,
1437              &X509Data,
1438              &X509DataSize,
1439              0
1440              );
1441   if (EFI_ERROR (Status)) {
1442     goto ON_EXIT;
1443   }
1444   ASSERT (X509Data != NULL);
1445 
1446   if (!CalculateCertHash (X509Data, X509DataSize, HashAlg, CertHash)) {
1447     goto ON_EXIT;
1448   }
1449 
1450   //
1451   // Get the variable for enrollment.
1452   //
1453   DataSize = 0;
1454   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1455   if (Status == EFI_BUFFER_TOO_SMALL) {
1456     Data = (UINT8 *) AllocateZeroPool (DataSize);
1457     if (Data == NULL) {
1458       return EFI_OUT_OF_RESOURCES;
1459     }
1460 
1461     Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1462     if (EFI_ERROR (Status)) {
1463       goto ON_EXIT;
1464     }
1465   }
1466 
1467   //
1468   // Allocate memory for Signature and fill the Signature
1469   //
1470   SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + sizeof (EFI_TIME) + mHash[HashAlg].DigestLength;
1471   SignatureData = (EFI_SIGNATURE_DATA *) AllocateZeroPool (SignatureSize);
1472   if (SignatureData == NULL) {
1473     return EFI_OUT_OF_RESOURCES;
1474   }
1475   CopyGuid (&SignatureData->SignatureOwner, Private->SignatureGUID);
1476   CopyMem (SignatureData->SignatureData, CertHash, mHash[HashAlg].DigestLength);
1477 
1478   //
1479   // Fill the time.
1480   //
1481   if (!AlwaysRevocation) {
1482     Time = (EFI_TIME *)(&SignatureData->SignatureData + mHash[HashAlg].DigestLength);
1483     Time->Year   = RevocationDate->Year;
1484     Time->Month  = RevocationDate->Month;
1485     Time->Day    = RevocationDate->Day;
1486     Time->Hour   = RevocationTime->Hour;
1487     Time->Minute = RevocationTime->Minute;
1488     Time->Second = RevocationTime->Second;
1489   }
1490 
1491   //
1492   // Determine the GUID for certificate hash.
1493   //
1494   switch (HashAlg) {
1495   case HASHALG_SHA256:
1496     SignatureType = gEfiCertX509Sha256Guid;
1497     break;
1498   case HASHALG_SHA384:
1499     SignatureType = gEfiCertX509Sha384Guid;
1500     break;
1501   case HASHALG_SHA512:
1502     SignatureType = gEfiCertX509Sha512Guid;
1503     break;
1504   default:
1505     return FALSE;
1506   }
1507 
1508   //
1509   // Add signature into the new variable data buffer
1510   //
1511   if (GetSignaturelistOffset((EFI_SIGNATURE_LIST *)Data, DataSize, &SignatureType, &Offset)) {
1512     //
1513     // Add the signature to the found signaturelist.
1514     //
1515     DbSize  = DataSize + SignatureSize;
1516     NewData = AllocateZeroPool (DbSize);
1517     if (NewData == NULL) {
1518       Status = EFI_OUT_OF_RESOURCES;
1519       goto ON_EXIT;
1520     }
1521 
1522     SignatureList     = (EFI_SIGNATURE_LIST *)(Data + Offset);
1523     SignatureListSize = (UINTN) ReadUnaligned32 ((UINT32 *)&SignatureList->SignatureListSize);
1524     CopyMem (NewData, Data, Offset + SignatureListSize);
1525 
1526     SignatureList = (EFI_SIGNATURE_LIST *)(NewData + Offset);
1527     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32)(SignatureListSize + SignatureSize));
1528 
1529     Offset += SignatureListSize;
1530     CopyMem (NewData + Offset, SignatureData, SignatureSize);
1531     CopyMem (NewData + Offset + SignatureSize, Data + Offset, DataSize - Offset);
1532 
1533     FreePool (Data);
1534     Data     = NewData;
1535     DataSize = DbSize;
1536   } else {
1537     //
1538     // Create a new signaturelist, and add the signature into the signaturelist.
1539     //
1540     DbSize  = DataSize + sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
1541     NewData = AllocateZeroPool (DbSize);
1542     if (NewData == NULL) {
1543       Status = EFI_OUT_OF_RESOURCES;
1544       goto ON_EXIT;
1545     }
1546     //
1547     // Fill Certificate Database parameters.
1548     //
1549     SignatureList     = (EFI_SIGNATURE_LIST*) (NewData + DataSize);
1550     SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
1551     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32) SignatureListSize);
1552     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureSize, (UINT32) SignatureSize);
1553     CopyGuid (&SignatureList->SignatureType, &SignatureType);
1554     CopyMem ((UINT8* ) SignatureList + sizeof (EFI_SIGNATURE_LIST), SignatureData, SignatureSize);
1555     if ((DataSize != 0) && (Data != NULL)) {
1556       CopyMem (NewData, Data, DataSize);
1557       FreePool (Data);
1558     }
1559     Data     = NewData;
1560     DataSize = DbSize;
1561   }
1562 
1563   Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &Data);
1564   if (EFI_ERROR (Status)) {
1565     goto ON_EXIT;
1566   }
1567 
1568   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
1569           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1570   Status = gRT->SetVariable(
1571                   EFI_IMAGE_SECURITY_DATABASE1,
1572                   &gEfiImageSecurityDatabaseGuid,
1573                   Attr,
1574                   DataSize,
1575                   Data
1576                   );
1577   if (EFI_ERROR (Status)) {
1578     goto ON_EXIT;
1579   }
1580 
1581 ON_EXIT:
1582 
1583   CloseEnrolledFile(Private->FileContext);
1584 
1585   if (Private->SignatureGUID != NULL) {
1586     FreePool (Private->SignatureGUID);
1587     Private->SignatureGUID = NULL;
1588   }
1589 
1590   if (Data != NULL) {
1591     FreePool (Data);
1592   }
1593 
1594   if (SignatureData != NULL) {
1595     FreePool (SignatureData);
1596   }
1597 
1598   if (X509Data != NULL) {
1599     FreePool (X509Data);
1600   }
1601 
1602   return Status;
1603 }
1604 
1605 /**
1606   Check whether a certificate from a file exists in dbx.
1607 
1608   @param[in] PrivateData     The module's private data.
1609   @param[in] VariableName    Variable name of signature database, must be
1610                              EFI_IMAGE_SECURITY_DATABASE1.
1611 
1612   @retval   TRUE             The X509 certificate is found in dbx successfully.
1613   @retval   FALSE            The X509 certificate is not found in dbx.
1614 **/
1615 BOOLEAN
IsX509CertInDbx(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)1616 IsX509CertInDbx (
1617   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1618   IN CHAR16                         *VariableName
1619   )
1620 {
1621   EFI_STATUS          Status;
1622   UINTN               X509DataSize;
1623   VOID                *X509Data;
1624   BOOLEAN             IsFound;
1625 
1626   //
1627   //  Read the certificate from file
1628   //
1629   X509DataSize  = 0;
1630   X509Data      = NULL;
1631   Status = ReadFileContent (
1632              Private->FileContext->FHandle,
1633              &X509Data,
1634              &X509DataSize,
1635              0
1636              );
1637   if (EFI_ERROR (Status)) {
1638     return FALSE;
1639   }
1640 
1641   //
1642   // Check the raw certificate.
1643   //
1644   IsFound = FALSE;
1645   if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, X509Data, X509DataSize)) {
1646     IsFound = TRUE;
1647     goto ON_EXIT;
1648   }
1649 
1650   //
1651   // Check the hash of certificate.
1652   //
1653   if (IsCertHashFoundInDbx (X509Data, X509DataSize)) {
1654     IsFound = TRUE;
1655     goto ON_EXIT;
1656   }
1657 
1658 ON_EXIT:
1659   if (X509Data != NULL) {
1660     FreePool (X509Data);
1661   }
1662 
1663   return IsFound;
1664 }
1665 
1666 /**
1667   Reads contents of a PE/COFF image in memory buffer.
1668 
1669   Caution: This function may receive untrusted input.
1670   PE/COFF image is external input, so this function will make sure the PE/COFF image content
1671   read is within the image buffer.
1672 
1673   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.
1674   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.
1675   @param  ReadSize        On input, the size in bytes of the requested read operation.
1676                           On output, the number of bytes actually read.
1677   @param  Buffer          Output buffer that contains the data read from the PE/COFF image.
1678 
1679   @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size
1680 **/
1681 EFI_STATUS
1682 EFIAPI
SecureBootConfigImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)1683 SecureBootConfigImageRead (
1684   IN     VOID    *FileHandle,
1685   IN     UINTN   FileOffset,
1686   IN OUT UINTN   *ReadSize,
1687   OUT    VOID    *Buffer
1688   )
1689 {
1690   UINTN               EndPosition;
1691 
1692   if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
1693     return EFI_INVALID_PARAMETER;
1694   }
1695 
1696   if (MAX_ADDRESS - FileOffset < *ReadSize) {
1697     return EFI_INVALID_PARAMETER;
1698   }
1699 
1700   EndPosition = FileOffset + *ReadSize;
1701   if (EndPosition > mImageSize) {
1702     *ReadSize = (UINT32)(mImageSize - FileOffset);
1703   }
1704 
1705   if (FileOffset >= mImageSize) {
1706     *ReadSize = 0;
1707   }
1708 
1709   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
1710 
1711   return EFI_SUCCESS;
1712 }
1713 
1714 /**
1715   Load PE/COFF image information into internal buffer and check its validity.
1716 
1717   @retval   EFI_SUCCESS         Successful
1718   @retval   EFI_UNSUPPORTED     Invalid PE/COFF file
1719   @retval   EFI_ABORTED         Serious error occurs, like file I/O error etc.
1720 
1721 **/
1722 EFI_STATUS
LoadPeImage(VOID)1723 LoadPeImage (
1724   VOID
1725   )
1726 {
1727   EFI_IMAGE_DOS_HEADER                  *DosHdr;
1728   EFI_IMAGE_NT_HEADERS32                *NtHeader32;
1729   EFI_IMAGE_NT_HEADERS64                *NtHeader64;
1730   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
1731   EFI_STATUS                            Status;
1732 
1733   NtHeader32 = NULL;
1734   NtHeader64 = NULL;
1735 
1736   ZeroMem (&ImageContext, sizeof (ImageContext));
1737   ImageContext.Handle    = (VOID *) mImageBase;
1738   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecureBootConfigImageRead;
1739 
1740   //
1741   // Get information about the image being loaded
1742   //
1743   Status = PeCoffLoaderGetImageInfo (&ImageContext);
1744   if (EFI_ERROR (Status)) {
1745     //
1746     // The information can't be got from the invalid PeImage
1747     //
1748     DEBUG ((DEBUG_INFO, "SecureBootConfigDxe: PeImage invalid. \n"));
1749     return Status;
1750   }
1751 
1752   //
1753   // Read the Dos header
1754   //
1755   DosHdr = (EFI_IMAGE_DOS_HEADER*)(mImageBase);
1756   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
1757   {
1758     //
1759     // DOS image header is present,
1760     // So read the PE header after the DOS image header
1761     //
1762     mPeCoffHeaderOffset = DosHdr->e_lfanew;
1763   }
1764   else
1765   {
1766     mPeCoffHeaderOffset = 0;
1767   }
1768 
1769   //
1770   // Read PE header and check the signature validity and machine compatibility
1771   //
1772   NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset);
1773   if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE)
1774   {
1775     return EFI_UNSUPPORTED;
1776   }
1777 
1778   mNtHeader.Pe32 = NtHeader32;
1779 
1780   //
1781   // Check the architecture field of PE header and get the Certificate Data Directory data
1782   // Note the size of FileHeader field is constant for both IA32 and X64 arch
1783   //
1784   if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32)
1785       || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)
1786       || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {
1787     //
1788     // 32-bits Architecture
1789     //
1790     mImageType = ImageType_IA32;
1791     mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
1792   }
1793   else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)
1794           || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)
1795           || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
1796     //
1797     // 64-bits Architecture
1798     //
1799     mImageType = ImageType_X64;
1800     NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);
1801     mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
1802   } else {
1803     return EFI_UNSUPPORTED;
1804   }
1805 
1806   return EFI_SUCCESS;
1807 }
1808 
1809 /**
1810   Calculate hash of Pe/Coff image based on the authenticode image hashing in
1811   PE/COFF Specification 8.0 Appendix A
1812 
1813   Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
1814   the function LoadPeImage ().
1815 
1816   @param[in]    HashAlg   Hash algorithm type.
1817 
1818   @retval TRUE            Successfully hash image.
1819   @retval FALSE           Fail in hash image.
1820 
1821 **/
1822 BOOLEAN
HashPeImage(IN UINT32 HashAlg)1823 HashPeImage (
1824   IN  UINT32                HashAlg
1825   )
1826 {
1827   BOOLEAN                   Status;
1828   EFI_IMAGE_SECTION_HEADER  *Section;
1829   VOID                      *HashCtx;
1830   UINTN                     CtxSize;
1831   UINT8                     *HashBase;
1832   UINTN                     HashSize;
1833   UINTN                     SumOfBytesHashed;
1834   EFI_IMAGE_SECTION_HEADER  *SectionHeader;
1835   UINTN                     Index;
1836   UINTN                     Pos;
1837 
1838   HashCtx       = NULL;
1839   SectionHeader = NULL;
1840   Status        = FALSE;
1841 
1842   if (HashAlg != HASHALG_SHA256) {
1843     return FALSE;
1844   }
1845 
1846   //
1847   // Initialize context of hash.
1848   //
1849   ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
1850 
1851   mImageDigestSize  = SHA256_DIGEST_SIZE;
1852   mCertType         = gEfiCertSha256Guid;
1853 
1854   CtxSize   = mHash[HashAlg].GetContextSize();
1855 
1856   HashCtx = AllocatePool (CtxSize);
1857   ASSERT (HashCtx != NULL);
1858 
1859   // 1.  Load the image header into memory.
1860 
1861   // 2.  Initialize a SHA hash context.
1862   Status = mHash[HashAlg].HashInit(HashCtx);
1863   if (!Status) {
1864     goto Done;
1865   }
1866   //
1867   // Measuring PE/COFF Image Header;
1868   // But CheckSum field and SECURITY data directory (certificate) are excluded
1869   //
1870 
1871   //
1872   // 3.  Calculate the distance from the base of the image header to the image checksum address.
1873   // 4.  Hash the image header from its base to beginning of the image checksum.
1874   //
1875   HashBase = mImageBase;
1876   if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1877     //
1878     // Use PE32 offset.
1879     //
1880     HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
1881   } else {
1882     //
1883     // Use PE32+ offset.
1884     //
1885     HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
1886   }
1887 
1888   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1889   if (!Status) {
1890     goto Done;
1891   }
1892   //
1893   // 5.  Skip over the image checksum (it occupies a single ULONG).
1894   // 6.  Get the address of the beginning of the Cert Directory.
1895   // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.
1896   //
1897   if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1898     //
1899     // Use PE32 offset.
1900     //
1901     HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
1902     HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
1903   } else {
1904     //
1905     // Use PE32+ offset.
1906     //
1907     HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
1908     HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
1909   }
1910 
1911   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1912   if (!Status) {
1913     goto Done;
1914   }
1915   //
1916   // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
1917   // 9.  Hash everything from the end of the Cert Directory to the end of image header.
1918   //
1919   if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1920     //
1921     // Use PE32 offset
1922     //
1923     HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
1924     HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);
1925   } else {
1926     //
1927     // Use PE32+ offset.
1928     //
1929     HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
1930     HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);
1931   }
1932 
1933   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1934   if (!Status) {
1935     goto Done;
1936   }
1937   //
1938   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
1939   //
1940   if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1941     //
1942     // Use PE32 offset.
1943     //
1944     SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
1945   } else {
1946     //
1947     // Use PE32+ offset
1948     //
1949     SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
1950   }
1951 
1952   //
1953   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
1954   //     structures in the image. The 'NumberOfSections' field of the image
1955   //     header indicates how big the table should be. Do not include any
1956   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
1957   //
1958   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
1959   ASSERT (SectionHeader != NULL);
1960   //
1961   // 12.  Using the 'PointerToRawData' in the referenced section headers as
1962   //      a key, arrange the elements in the table in ascending order. In other
1963   //      words, sort the section headers according to the disk-file offset of
1964   //      the section.
1965   //
1966   Section = (EFI_IMAGE_SECTION_HEADER *) (
1967                mImageBase +
1968                mPeCoffHeaderOffset +
1969                sizeof (UINT32) +
1970                sizeof (EFI_IMAGE_FILE_HEADER) +
1971                mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
1972                );
1973   for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
1974     Pos = Index;
1975     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
1976       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
1977       Pos--;
1978     }
1979     CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
1980     Section += 1;
1981   }
1982 
1983   //
1984   // 13.  Walk through the sorted table, bring the corresponding section
1985   //      into memory, and hash the entire section (using the 'SizeOfRawData'
1986   //      field in the section header to determine the amount of data to hash).
1987   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
1988   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.
1989   //
1990   for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
1991     Section = &SectionHeader[Index];
1992     if (Section->SizeOfRawData == 0) {
1993       continue;
1994     }
1995     HashBase  = mImageBase + Section->PointerToRawData;
1996     HashSize  = (UINTN) Section->SizeOfRawData;
1997 
1998     Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1999     if (!Status) {
2000       goto Done;
2001     }
2002 
2003     SumOfBytesHashed += HashSize;
2004   }
2005 
2006   //
2007   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
2008   //      data in the file that needs to be added to the hash. This data begins
2009   //      at file offset SUM_OF_BYTES_HASHED and its length is:
2010   //             FileSize  -  (CertDirectory->Size)
2011   //
2012   if (mImageSize > SumOfBytesHashed) {
2013     HashBase = mImageBase + SumOfBytesHashed;
2014     if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2015       //
2016       // Use PE32 offset.
2017       //
2018       HashSize = (UINTN)(
2019                  mImageSize -
2020                  mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
2021                  SumOfBytesHashed);
2022     } else {
2023       //
2024       // Use PE32+ offset.
2025       //
2026       HashSize = (UINTN)(
2027                  mImageSize -
2028                  mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
2029                  SumOfBytesHashed);
2030     }
2031 
2032     Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
2033     if (!Status) {
2034       goto Done;
2035     }
2036   }
2037 
2038   Status  = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
2039 
2040 Done:
2041   if (HashCtx != NULL) {
2042     FreePool (HashCtx);
2043   }
2044   if (SectionHeader != NULL) {
2045     FreePool (SectionHeader);
2046   }
2047   return Status;
2048 }
2049 
2050 /**
2051   Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of
2052   Pe/Coff image based on the authenticated image hashing in PE/COFF Specification
2053   8.0 Appendix A
2054 
2055   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.
2056   @retval EFI_SUCCESS                 Hash successfully.
2057 
2058 **/
2059 EFI_STATUS
HashPeImageByType(VOID)2060 HashPeImageByType (
2061   VOID
2062   )
2063 {
2064   UINT8                     Index;
2065   WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;
2066 
2067   PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset);
2068 
2069   for (Index = 0; Index < HASHALG_MAX; Index++) {
2070     //
2071     // Check the Hash algorithm in PE/COFF Authenticode.
2072     //    According to PKCS#7 Definition:
2073     //        SignedData ::= SEQUENCE {
2074     //            version Version,
2075     //            digestAlgorithms DigestAlgorithmIdentifiers,
2076     //            contentInfo ContentInfo,
2077     //            .... }
2078     //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
2079     //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.
2080     //    Fixed offset (+32) is calculated based on two bytes of length encoding.
2081      //
2082     if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
2083       //
2084       // Only support two bytes of Long Form of Length Encoding.
2085       //
2086       continue;
2087     }
2088 
2089     //
2090     if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
2091       break;
2092     }
2093   }
2094 
2095   if (Index == HASHALG_MAX) {
2096     return EFI_UNSUPPORTED;
2097   }
2098 
2099   //
2100   // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
2101   //
2102   if (!HashPeImage(Index)) {
2103     return EFI_UNSUPPORTED;
2104   }
2105 
2106   return EFI_SUCCESS;
2107 }
2108 
2109 /**
2110   Enroll a new executable's signature into Signature Database.
2111 
2112   @param[in] PrivateData     The module's private data.
2113   @param[in] VariableName    Variable name of signature database, must be
2114                              EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
2115                              or EFI_IMAGE_SECURITY_DATABASE2.
2116 
2117   @retval   EFI_SUCCESS            New signature is enrolled successfully.
2118   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
2119   @retval   EFI_UNSUPPORTED        Unsupported command.
2120   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
2121 
2122 **/
2123 EFI_STATUS
EnrollAuthentication2Descriptor(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)2124 EnrollAuthentication2Descriptor (
2125   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
2126   IN CHAR16                         *VariableName
2127   )
2128 {
2129   EFI_STATUS                        Status;
2130   VOID                              *Data;
2131   UINTN                             DataSize;
2132   UINT32                            Attr;
2133 
2134   Data = NULL;
2135 
2136   //
2137   // DBT only support DER-X509 Cert Enrollment
2138   //
2139   if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
2140     return EFI_UNSUPPORTED;
2141   }
2142 
2143   //
2144   // Read the whole file content
2145   //
2146   Status = ReadFileContent(
2147              Private->FileContext->FHandle,
2148              (VOID **) &mImageBase,
2149              &mImageSize,
2150              0
2151              );
2152   if (EFI_ERROR (Status)) {
2153     goto ON_EXIT;
2154   }
2155   ASSERT (mImageBase != NULL);
2156 
2157   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
2158          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2159 
2160   //
2161   // Check if SigDB variable has been already existed.
2162   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
2163   // new signature data to original variable
2164   //
2165   DataSize = 0;
2166   Status = gRT->GetVariable(
2167                   VariableName,
2168                   &gEfiImageSecurityDatabaseGuid,
2169                   NULL,
2170                   &DataSize,
2171                   NULL
2172                   );
2173   if (Status == EFI_BUFFER_TOO_SMALL) {
2174     Attr |= EFI_VARIABLE_APPEND_WRITE;
2175   } else if (Status != EFI_NOT_FOUND) {
2176     goto ON_EXIT;
2177   }
2178 
2179   //
2180   // Diretly set AUTHENTICATION_2 data to SetVariable
2181   //
2182   Status = gRT->SetVariable(
2183                   VariableName,
2184                   &gEfiImageSecurityDatabaseGuid,
2185                   Attr,
2186                   mImageSize,
2187                   mImageBase
2188                   );
2189 
2190   DEBUG((DEBUG_INFO, "Enroll AUTH_2 data to Var:%s Status: %x\n", VariableName, Status));
2191 
2192 ON_EXIT:
2193 
2194   CloseEnrolledFile(Private->FileContext);
2195 
2196   if (Data != NULL) {
2197     FreePool (Data);
2198   }
2199 
2200   if (mImageBase != NULL) {
2201     FreePool (mImageBase);
2202     mImageBase = NULL;
2203   }
2204 
2205   return Status;
2206 
2207 }
2208 
2209 
2210 /**
2211   Enroll a new executable's signature into Signature Database.
2212 
2213   @param[in] PrivateData     The module's private data.
2214   @param[in] VariableName    Variable name of signature database, must be
2215                              EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
2216                              or EFI_IMAGE_SECURITY_DATABASE2.
2217 
2218   @retval   EFI_SUCCESS            New signature is enrolled successfully.
2219   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
2220   @retval   EFI_UNSUPPORTED        Unsupported command.
2221   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
2222 
2223 **/
2224 EFI_STATUS
EnrollImageSignatureToSigDB(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)2225 EnrollImageSignatureToSigDB (
2226   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
2227   IN CHAR16                         *VariableName
2228   )
2229 {
2230   EFI_STATUS                        Status;
2231   EFI_SIGNATURE_LIST                *SigDBCert;
2232   EFI_SIGNATURE_DATA                *SigDBCertData;
2233   VOID                              *Data;
2234   UINTN                             DataSize;
2235   UINTN                             SigDBSize;
2236   UINT32                            Attr;
2237   WIN_CERTIFICATE_UEFI_GUID         *GuidCertData;
2238 
2239   Data = NULL;
2240   GuidCertData = NULL;
2241 
2242   if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
2243     return EFI_UNSUPPORTED;
2244   }
2245 
2246   //
2247   // Form the SigDB certificate list.
2248   // Format the data item into EFI_SIGNATURE_LIST type.
2249   //
2250   // We need to parse executable's signature data from specified signed executable file.
2251   // In current implementation, we simply trust the pass-in signed executable file.
2252   // In reality, it's OS's responsibility to verify the signed executable file.
2253   //
2254 
2255   //
2256   // Read the whole file content
2257   //
2258   Status = ReadFileContent(
2259              Private->FileContext->FHandle,
2260              (VOID **) &mImageBase,
2261              &mImageSize,
2262              0
2263              );
2264   if (EFI_ERROR (Status)) {
2265     goto ON_EXIT;
2266   }
2267   ASSERT (mImageBase != NULL);
2268 
2269   Status = LoadPeImage ();
2270   if (EFI_ERROR (Status)) {
2271     goto ON_EXIT;
2272   }
2273 
2274   if (mSecDataDir->SizeOfCert == 0) {
2275     if (!HashPeImage (HASHALG_SHA256)) {
2276       Status =  EFI_SECURITY_VIOLATION;
2277       goto ON_EXIT;
2278     }
2279   } else {
2280 
2281     //
2282     // Read the certificate data
2283     //
2284     mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);
2285 
2286     if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
2287       GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;
2288       if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {
2289         Status = EFI_ABORTED;
2290         goto ON_EXIT;
2291       }
2292 
2293       if (!HashPeImage (HASHALG_SHA256)) {
2294         Status = EFI_ABORTED;
2295         goto ON_EXIT;;
2296       }
2297 
2298     } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
2299 
2300       Status = HashPeImageByType ();
2301       if (EFI_ERROR (Status)) {
2302         goto ON_EXIT;;
2303       }
2304     } else {
2305       Status = EFI_ABORTED;
2306       goto ON_EXIT;
2307     }
2308   }
2309 
2310   //
2311   // Create a new SigDB entry.
2312   //
2313   SigDBSize = sizeof(EFI_SIGNATURE_LIST)
2314               + sizeof(EFI_SIGNATURE_DATA) - 1
2315               + (UINT32) mImageDigestSize;
2316 
2317   Data = (UINT8*) AllocateZeroPool (SigDBSize);
2318   if (Data == NULL) {
2319     Status = EFI_OUT_OF_RESOURCES;
2320     goto ON_EXIT;
2321   }
2322 
2323   //
2324   // Adjust the Certificate Database parameters.
2325   //
2326   SigDBCert = (EFI_SIGNATURE_LIST*) Data;
2327   SigDBCert->SignatureListSize   = (UINT32) SigDBSize;
2328   SigDBCert->SignatureHeaderSize = 0;
2329   SigDBCert->SignatureSize       = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;
2330   CopyGuid (&SigDBCert->SignatureType, &mCertType);
2331 
2332   SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));
2333   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
2334   CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);
2335 
2336   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
2337           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2338   Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
2339   if (EFI_ERROR (Status)) {
2340     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2341     goto ON_EXIT;
2342   }
2343 
2344   //
2345   // Check if SigDB variable has been already existed.
2346   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
2347   // new signature data to original variable
2348   //
2349   DataSize = 0;
2350   Status = gRT->GetVariable(
2351                   VariableName,
2352                   &gEfiImageSecurityDatabaseGuid,
2353                   NULL,
2354                   &DataSize,
2355                   NULL
2356                   );
2357   if (Status == EFI_BUFFER_TOO_SMALL) {
2358     Attr |= EFI_VARIABLE_APPEND_WRITE;
2359   } else if (Status != EFI_NOT_FOUND) {
2360     goto ON_EXIT;
2361   }
2362 
2363   //
2364   // Enroll the variable.
2365   //
2366   Status = gRT->SetVariable(
2367                   VariableName,
2368                   &gEfiImageSecurityDatabaseGuid,
2369                   Attr,
2370                   SigDBSize,
2371                   Data
2372                   );
2373   if (EFI_ERROR (Status)) {
2374     goto ON_EXIT;
2375   }
2376 
2377 ON_EXIT:
2378 
2379   CloseEnrolledFile(Private->FileContext);
2380 
2381   if (Private->SignatureGUID != NULL) {
2382     FreePool (Private->SignatureGUID);
2383     Private->SignatureGUID = NULL;
2384   }
2385 
2386   if (Data != NULL) {
2387     FreePool (Data);
2388   }
2389 
2390   if (mImageBase != NULL) {
2391     FreePool (mImageBase);
2392     mImageBase = NULL;
2393   }
2394 
2395   return Status;
2396 }
2397 
2398 /**
2399   Enroll signature into DB/DBX/DBT without KEK's authentication.
2400   The SignatureOwner GUID will be Private->SignatureGUID.
2401 
2402   @param[in] PrivateData     The module's private data.
2403   @param[in] VariableName    Variable name of signature database, must be
2404                              EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
2405 
2406   @retval   EFI_SUCCESS            New signature enrolled successfully.
2407   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.
2408   @retval   others                 Fail to enroll signature data.
2409 
2410 **/
2411 EFI_STATUS
EnrollSignatureDatabase(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN CHAR16 * VariableName)2412 EnrollSignatureDatabase (
2413   IN SECUREBOOT_CONFIG_PRIVATE_DATA     *Private,
2414   IN CHAR16                             *VariableName
2415   )
2416 {
2417   UINT16*      FilePostFix;
2418   EFI_STATUS   Status;
2419   UINTN        NameLength;
2420 
2421   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
2422     return EFI_INVALID_PARAMETER;
2423   }
2424 
2425   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
2426   if (EFI_ERROR (Status)) {
2427     return Status;
2428   }
2429 
2430   //
2431   // Parse the file's postfix.
2432   //
2433   NameLength = StrLen (Private->FileContext->FileName);
2434   if (NameLength <= 4) {
2435     return EFI_INVALID_PARAMETER;
2436   }
2437   FilePostFix = Private->FileContext->FileName + NameLength - 4;
2438   if (IsDerEncodeCertificate (FilePostFix)) {
2439     //
2440     // Supports DER-encoded X509 certificate.
2441     //
2442     return EnrollX509toSigDB (Private, VariableName);
2443   } else if (IsAuthentication2Format(Private->FileContext->FHandle)){
2444     return EnrollAuthentication2Descriptor(Private, VariableName);
2445   } else {
2446     return EnrollImageSignatureToSigDB (Private, VariableName);
2447   }
2448 }
2449 
2450 /**
2451   List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)
2452   by GUID in the page for user to select and delete as needed.
2453 
2454   @param[in]    PrivateData         Module's private data.
2455   @param[in]    VariableName        The variable name of the vendor's signature database.
2456   @param[in]    VendorGuid          A unique identifier for the vendor.
2457   @param[in]    LabelNumber         Label number to insert opcodes.
2458   @param[in]    FormId              Form ID of current page.
2459   @param[in]    QuestionIdBase      Base question id of the signature list.
2460 
2461   @retval   EFI_SUCCESS             Success to update the signature list page
2462   @retval   EFI_OUT_OF_RESOURCES    Unable to allocate required resources.
2463 
2464 **/
2465 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)2466 UpdateDeletePage (
2467   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
2468   IN CHAR16                           *VariableName,
2469   IN EFI_GUID                         *VendorGuid,
2470   IN UINT16                           LabelNumber,
2471   IN EFI_FORM_ID                      FormId,
2472   IN EFI_QUESTION_ID                  QuestionIdBase
2473   )
2474 {
2475   EFI_STATUS                  Status;
2476   UINT32                      Index;
2477   UINTN                       CertCount;
2478   UINTN                       GuidIndex;
2479   VOID                        *StartOpCodeHandle;
2480   VOID                        *EndOpCodeHandle;
2481   EFI_IFR_GUID_LABEL          *StartLabel;
2482   EFI_IFR_GUID_LABEL          *EndLabel;
2483   UINTN                       DataSize;
2484   UINT8                       *Data;
2485   EFI_SIGNATURE_LIST          *CertList;
2486   EFI_SIGNATURE_DATA          *Cert;
2487   UINT32                      ItemDataSize;
2488   CHAR16                      *GuidStr;
2489   EFI_STRING_ID               GuidID;
2490   EFI_STRING_ID               Help;
2491 
2492   Data     = NULL;
2493   CertList = NULL;
2494   Cert     = NULL;
2495   GuidStr  = NULL;
2496   StartOpCodeHandle = NULL;
2497   EndOpCodeHandle   = NULL;
2498 
2499   //
2500   // Initialize the container for dynamic opcodes.
2501   //
2502   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
2503   if (StartOpCodeHandle == NULL) {
2504     Status = EFI_OUT_OF_RESOURCES;
2505     goto ON_EXIT;
2506   }
2507 
2508   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
2509   if (EndOpCodeHandle == NULL) {
2510     Status = EFI_OUT_OF_RESOURCES;
2511     goto ON_EXIT;
2512   }
2513 
2514   //
2515   // Create Hii Extend Label OpCode.
2516   //
2517   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
2518                                         StartOpCodeHandle,
2519                                         &gEfiIfrTianoGuid,
2520                                         NULL,
2521                                         sizeof (EFI_IFR_GUID_LABEL)
2522                                         );
2523   StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
2524   StartLabel->Number        = LabelNumber;
2525 
2526   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
2527                                       EndOpCodeHandle,
2528                                       &gEfiIfrTianoGuid,
2529                                       NULL,
2530                                       sizeof (EFI_IFR_GUID_LABEL)
2531                                       );
2532   EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
2533   EndLabel->Number        = LABEL_END;
2534 
2535   //
2536   // Read Variable.
2537   //
2538   DataSize = 0;
2539   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
2540   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
2541     goto ON_EXIT;
2542   }
2543 
2544   Data = (UINT8 *) AllocateZeroPool (DataSize);
2545   if (Data == NULL) {
2546     Status = EFI_OUT_OF_RESOURCES;
2547     goto ON_EXIT;
2548   }
2549 
2550   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
2551   if (EFI_ERROR (Status)) {
2552     goto ON_EXIT;
2553   }
2554 
2555   GuidStr = AllocateZeroPool (100);
2556   if (GuidStr == NULL) {
2557     Status = EFI_OUT_OF_RESOURCES;
2558     goto ON_EXIT;
2559   }
2560 
2561   //
2562   // Enumerate all KEK pub data.
2563   //
2564   ItemDataSize = (UINT32) DataSize;
2565   CertList = (EFI_SIGNATURE_LIST *) Data;
2566   GuidIndex = 0;
2567 
2568   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2569 
2570     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {
2571       Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);
2572     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2573       Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);
2574     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {
2575       Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);
2576     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {
2577       Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);
2578     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {
2579       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);
2580     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {
2581       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);
2582     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {
2583       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);
2584     } else {
2585       //
2586       // The signature type is not supported in current implementation.
2587       //
2588       ItemDataSize -= CertList->SignatureListSize;
2589       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2590       continue;
2591     }
2592 
2593     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2594     for (Index = 0; Index < CertCount; Index++) {
2595       Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList
2596                                               + sizeof (EFI_SIGNATURE_LIST)
2597                                               + CertList->SignatureHeaderSize
2598                                               + Index * CertList->SignatureSize);
2599       //
2600       // Display GUID and help
2601       //
2602       GuidToString (&Cert->SignatureOwner, GuidStr, 100);
2603       GuidID  = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);
2604       HiiCreateCheckBoxOpCode (
2605         StartOpCodeHandle,
2606         (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),
2607         0,
2608         0,
2609         GuidID,
2610         Help,
2611         EFI_IFR_FLAG_CALLBACK,
2612         0,
2613         NULL
2614         );
2615     }
2616 
2617     ItemDataSize -= CertList->SignatureListSize;
2618     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2619   }
2620 
2621 ON_EXIT:
2622   HiiUpdateForm (
2623     PrivateData->HiiHandle,
2624     &gSecureBootConfigFormSetGuid,
2625     FormId,
2626     StartOpCodeHandle,
2627     EndOpCodeHandle
2628     );
2629 
2630   if (StartOpCodeHandle != NULL) {
2631     HiiFreeOpCodeHandle (StartOpCodeHandle);
2632   }
2633 
2634   if (EndOpCodeHandle != NULL) {
2635     HiiFreeOpCodeHandle (EndOpCodeHandle);
2636   }
2637 
2638   if (Data != NULL) {
2639     FreePool (Data);
2640   }
2641 
2642   if (GuidStr != NULL) {
2643     FreePool (GuidStr);
2644   }
2645 
2646   return EFI_SUCCESS;
2647 }
2648 
2649 /**
2650   Delete a KEK entry from KEK database.
2651 
2652   @param[in]    PrivateData         Module's private data.
2653   @param[in]    QuestionId          Question id of the KEK item to delete.
2654 
2655   @retval   EFI_SUCCESS            Delete kek item successfully.
2656   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.
2657 
2658 **/
2659 EFI_STATUS
DeleteKeyExchangeKey(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN EFI_QUESTION_ID QuestionId)2660 DeleteKeyExchangeKey (
2661   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
2662   IN EFI_QUESTION_ID                  QuestionId
2663   )
2664 {
2665   EFI_STATUS                  Status;
2666   UINTN                       DataSize;
2667   UINT8                       *Data;
2668   UINT8                       *OldData;
2669   UINT32                      Attr;
2670   UINT32                      Index;
2671   EFI_SIGNATURE_LIST          *CertList;
2672   EFI_SIGNATURE_LIST          *NewCertList;
2673   EFI_SIGNATURE_DATA          *Cert;
2674   UINTN                       CertCount;
2675   UINT32                      Offset;
2676   BOOLEAN                     IsKEKItemFound;
2677   UINT32                      KekDataSize;
2678   UINTN                       DeleteKekIndex;
2679   UINTN                       GuidIndex;
2680 
2681   Data            = NULL;
2682   OldData         = NULL;
2683   CertList        = NULL;
2684   Cert            = NULL;
2685   Attr            = 0;
2686   DeleteKekIndex  = QuestionId - OPTION_DEL_KEK_QUESTION_ID;
2687 
2688   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2689   if (EFI_ERROR (Status)) {
2690     return Status;
2691   }
2692 
2693   //
2694   // Get original KEK variable.
2695   //
2696   DataSize = 0;
2697   Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);
2698   if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
2699     goto ON_EXIT;
2700   }
2701 
2702   OldData = (UINT8*)AllocateZeroPool(DataSize);
2703   if (OldData == NULL) {
2704     Status = EFI_OUT_OF_RESOURCES;
2705     goto ON_EXIT;
2706   }
2707 
2708   Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);
2709   if (EFI_ERROR(Status)) {
2710     goto ON_EXIT;
2711   }
2712 
2713   //
2714   // Allocate space for new variable.
2715   //
2716   Data = (UINT8*) AllocateZeroPool (DataSize);
2717   if (Data == NULL) {
2718     Status  =  EFI_OUT_OF_RESOURCES;
2719     goto ON_EXIT;
2720   }
2721 
2722   //
2723   // Enumerate all KEK pub data and erasing the target item.
2724   //
2725   IsKEKItemFound = FALSE;
2726   KekDataSize = (UINT32) DataSize;
2727   CertList = (EFI_SIGNATURE_LIST *) OldData;
2728   Offset = 0;
2729   GuidIndex = 0;
2730   while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2731     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
2732         CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2733       CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
2734       NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);
2735       Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2736       Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2737       CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2738       for (Index = 0; Index < CertCount; Index++) {
2739         if (GuidIndex == DeleteKekIndex ) {
2740           //
2741           // Find it! Skip it!
2742           //
2743           NewCertList->SignatureListSize -= CertList->SignatureSize;
2744           IsKEKItemFound = TRUE;
2745         } else {
2746           //
2747           // This item doesn't match. Copy it to the Data buffer.
2748           //
2749           CopyMem (Data + Offset, Cert, CertList->SignatureSize);
2750           Offset += CertList->SignatureSize;
2751         }
2752         GuidIndex++;
2753         Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);
2754       }
2755     } else {
2756       //
2757       // This List doesn't match. Copy it to the Data buffer.
2758       //
2759       CopyMem (Data + Offset, CertList, CertList->SignatureListSize);
2760       Offset += CertList->SignatureListSize;
2761     }
2762 
2763     KekDataSize -= CertList->SignatureListSize;
2764     CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);
2765   }
2766 
2767   if (!IsKEKItemFound) {
2768     //
2769     // Doesn't find the Kek Item!
2770     //
2771     Status = EFI_NOT_FOUND;
2772     goto ON_EXIT;
2773   }
2774 
2775   //
2776   // Delete the Signature header if there is no signature in the list.
2777   //
2778   KekDataSize = Offset;
2779   CertList = (EFI_SIGNATURE_LIST*) Data;
2780   Offset = 0;
2781   ZeroMem (OldData, KekDataSize);
2782   while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2783     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2784     DEBUG ((DEBUG_INFO, "       CertCount = %x\n", CertCount));
2785     if (CertCount != 0) {
2786       CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);
2787       Offset += CertList->SignatureListSize;
2788     }
2789     KekDataSize -= CertList->SignatureListSize;
2790     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2791   }
2792 
2793   DataSize = Offset;
2794   if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2795     Status = CreateTimeBasedPayload (&DataSize, &OldData);
2796     if (EFI_ERROR (Status)) {
2797       DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2798       goto ON_EXIT;
2799     }
2800   }
2801 
2802   Status = gRT->SetVariable(
2803                   EFI_KEY_EXCHANGE_KEY_NAME,
2804                   &gEfiGlobalVariableGuid,
2805                   Attr,
2806                   DataSize,
2807                   OldData
2808                   );
2809   if (EFI_ERROR (Status)) {
2810     DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
2811     goto ON_EXIT;
2812   }
2813 
2814 ON_EXIT:
2815   if (Data != NULL) {
2816     FreePool(Data);
2817   }
2818 
2819   if (OldData != NULL) {
2820     FreePool(OldData);
2821   }
2822 
2823   return UpdateDeletePage (
2824            PrivateData,
2825            EFI_KEY_EXCHANGE_KEY_NAME,
2826            &gEfiGlobalVariableGuid,
2827            LABEL_KEK_DELETE,
2828            FORMID_DELETE_KEK_FORM,
2829            OPTION_DEL_KEK_QUESTION_ID
2830            );
2831 }
2832 
2833 /**
2834   Delete a signature entry from signature database.
2835 
2836   @param[in]    PrivateData         Module's private data.
2837   @param[in]    VariableName        The variable name of the vendor's signature database.
2838   @param[in]    VendorGuid          A unique identifier for the vendor.
2839   @param[in]    LabelNumber         Label number to insert opcodes.
2840   @param[in]    FormId              Form ID of current page.
2841   @param[in]    QuestionIdBase      Base question id of the signature list.
2842   @param[in]    DeleteIndex         Signature index to delete.
2843 
2844   @retval   EFI_SUCCESS             Delete signature successfully.
2845   @retval   EFI_NOT_FOUND           Can't find the signature item,
2846   @retval   EFI_OUT_OF_RESOURCES    Could not allocate needed resources.
2847 **/
2848 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)2849 DeleteSignature (
2850   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
2851   IN CHAR16                           *VariableName,
2852   IN EFI_GUID                         *VendorGuid,
2853   IN UINT16                           LabelNumber,
2854   IN EFI_FORM_ID                      FormId,
2855   IN EFI_QUESTION_ID                  QuestionIdBase,
2856   IN UINTN                            DeleteIndex
2857   )
2858 {
2859   EFI_STATUS                  Status;
2860   UINTN                       DataSize;
2861   UINT8                       *Data;
2862   UINT8                       *OldData;
2863   UINT32                      Attr;
2864   UINT32                      Index;
2865   EFI_SIGNATURE_LIST          *CertList;
2866   EFI_SIGNATURE_LIST          *NewCertList;
2867   EFI_SIGNATURE_DATA          *Cert;
2868   UINTN                       CertCount;
2869   UINT32                      Offset;
2870   BOOLEAN                     IsItemFound;
2871   UINT32                      ItemDataSize;
2872   UINTN                       GuidIndex;
2873 
2874   Data            = NULL;
2875   OldData         = NULL;
2876   CertList        = NULL;
2877   Cert            = NULL;
2878   Attr            = 0;
2879 
2880   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2881   if (EFI_ERROR (Status)) {
2882     return Status;
2883   }
2884 
2885   //
2886   // Get original signature list data.
2887   //
2888   DataSize = 0;
2889   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);
2890   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
2891     goto ON_EXIT;
2892   }
2893 
2894   OldData = (UINT8 *) AllocateZeroPool (DataSize);
2895   if (OldData == NULL) {
2896     Status = EFI_OUT_OF_RESOURCES;
2897     goto ON_EXIT;
2898   }
2899 
2900   Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData);
2901   if (EFI_ERROR(Status)) {
2902     goto ON_EXIT;
2903   }
2904 
2905   //
2906   // Allocate space for new variable.
2907   //
2908   Data = (UINT8*) AllocateZeroPool (DataSize);
2909   if (Data == NULL) {
2910     Status  =  EFI_OUT_OF_RESOURCES;
2911     goto ON_EXIT;
2912   }
2913 
2914   //
2915   // Enumerate all signature data and erasing the target item.
2916   //
2917   IsItemFound = FALSE;
2918   ItemDataSize = (UINT32) DataSize;
2919   CertList = (EFI_SIGNATURE_LIST *) OldData;
2920   Offset = 0;
2921   GuidIndex = 0;
2922   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2923     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
2924         CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid) ||
2925         CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid) ||
2926         CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid) ||
2927         CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid) ||
2928         CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid) ||
2929         CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)
2930         ) {
2931       //
2932       // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list.
2933       //
2934       CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
2935       NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset);
2936       Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2937       Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2938       CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2939       for (Index = 0; Index < CertCount; Index++) {
2940         if (GuidIndex == DeleteIndex) {
2941           //
2942           // Find it! Skip it!
2943           //
2944           NewCertList->SignatureListSize -= CertList->SignatureSize;
2945           IsItemFound = TRUE;
2946         } else {
2947           //
2948           // This item doesn't match. Copy it to the Data buffer.
2949           //
2950           CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize);
2951           Offset += CertList->SignatureSize;
2952         }
2953         GuidIndex++;
2954         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
2955       }
2956     } else {
2957       //
2958       // This List doesn't match. Just copy it to the Data buffer.
2959       //
2960       CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
2961       Offset += CertList->SignatureListSize;
2962     }
2963 
2964     ItemDataSize -= CertList->SignatureListSize;
2965     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2966   }
2967 
2968   if (!IsItemFound) {
2969     //
2970     // Doesn't find the signature Item!
2971     //
2972     Status = EFI_NOT_FOUND;
2973     goto ON_EXIT;
2974   }
2975 
2976   //
2977   // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list.
2978   //
2979   ItemDataSize = Offset;
2980   CertList = (EFI_SIGNATURE_LIST *) Data;
2981   Offset = 0;
2982   ZeroMem (OldData, ItemDataSize);
2983   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2984     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2985     DEBUG ((DEBUG_INFO, "       CertCount = %x\n", CertCount));
2986     if (CertCount != 0) {
2987       CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
2988       Offset += CertList->SignatureListSize;
2989     }
2990     ItemDataSize -= CertList->SignatureListSize;
2991     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2992   }
2993 
2994   DataSize = Offset;
2995   if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2996     Status = CreateTimeBasedPayload (&DataSize, &OldData);
2997     if (EFI_ERROR (Status)) {
2998       DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2999       goto ON_EXIT;
3000     }
3001   }
3002 
3003   Status = gRT->SetVariable(
3004                   VariableName,
3005                   VendorGuid,
3006                   Attr,
3007                   DataSize,
3008                   OldData
3009                   );
3010   if (EFI_ERROR (Status)) {
3011     DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
3012     goto ON_EXIT;
3013   }
3014 
3015 ON_EXIT:
3016   if (Data != NULL) {
3017     FreePool(Data);
3018   }
3019 
3020   if (OldData != NULL) {
3021     FreePool(OldData);
3022   }
3023 
3024   return UpdateDeletePage (
3025            PrivateData,
3026            VariableName,
3027            VendorGuid,
3028            LabelNumber,
3029            FormId,
3030            QuestionIdBase
3031            );
3032 }
3033 
3034 /**
3035   This function to delete signature list or data, according by DelType.
3036 
3037   @param[in]  PrivateData           Module's private data.
3038   @param[in]  DelType               Indicate delete signature list or data.
3039   @param[in]  CheckedCount          Indicate how many signature data have
3040                                     been checked in current signature list.
3041 
3042   @retval   EFI_SUCCESS             Success to update the signature list page
3043   @retval   EFI_OUT_OF_RESOURCES    Unable to allocate required resources.
3044 **/
3045 EFI_STATUS
DeleteSignatureEx(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN SIGNATURE_DELETE_TYPE DelType,IN UINT32 CheckedCount)3046 DeleteSignatureEx (
3047   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
3048   IN SIGNATURE_DELETE_TYPE            DelType,
3049   IN UINT32                           CheckedCount
3050   )
3051 {
3052   EFI_STATUS          Status;
3053   EFI_SIGNATURE_LIST  *ListWalker;
3054   EFI_SIGNATURE_LIST  *NewCertList;
3055   EFI_SIGNATURE_DATA  *DataWalker;
3056   CHAR16              VariableName[BUFFER_MAX_SIZE];
3057   UINT32              VariableAttr;
3058   UINTN               VariableDataSize;
3059   UINTN               RemainingSize;
3060   UINTN               ListIndex;
3061   UINTN               Index;
3062   UINTN               Offset;
3063   UINT8               *VariableData;
3064   UINT8               *NewVariableData;
3065 
3066   Status              = EFI_SUCCESS;
3067   VariableAttr        = 0;
3068   VariableDataSize    = 0;
3069   ListIndex           = 0;
3070   Offset              = 0;
3071   VariableData        = NULL;
3072   NewVariableData     = NULL;
3073 
3074   if (PrivateData->VariableName == Variable_DB) {
3075     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE);
3076   } else if (PrivateData->VariableName == Variable_DBX) {
3077     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE1);
3078   } else if (PrivateData->VariableName == Variable_DBT) {
3079     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE2);
3080   } else {
3081     goto ON_EXIT;
3082   }
3083 
3084   Status = gRT->GetVariable (
3085                   VariableName,
3086                   &gEfiImageSecurityDatabaseGuid,
3087                   &VariableAttr,
3088                   &VariableDataSize,
3089                   VariableData
3090                 );
3091   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
3092     goto ON_EXIT;
3093   }
3094 
3095   VariableData = AllocateZeroPool (VariableDataSize);
3096   if (VariableData == NULL) {
3097     Status = EFI_OUT_OF_RESOURCES;
3098     goto ON_EXIT;
3099   }
3100 
3101   Status = gRT->GetVariable (
3102                   VariableName,
3103                   &gEfiImageSecurityDatabaseGuid,
3104                   &VariableAttr,
3105                   &VariableDataSize,
3106                   VariableData
3107                 );
3108   if (EFI_ERROR (Status)) {
3109     goto ON_EXIT;
3110   }
3111 
3112   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
3113   if (EFI_ERROR (Status)) {
3114     goto ON_EXIT;
3115   }
3116 
3117   NewVariableData = AllocateZeroPool (VariableDataSize);
3118   if (NewVariableData == NULL) {
3119     Status = EFI_OUT_OF_RESOURCES;
3120     goto ON_EXIT;
3121   }
3122 
3123   RemainingSize = VariableDataSize;
3124   ListWalker = (EFI_SIGNATURE_LIST *)(VariableData);
3125   if (DelType == Delete_Signature_List_All) {
3126     VariableDataSize = 0;
3127   } else {
3128     //
3129     //  Traverse to target EFI_SIGNATURE_LIST but others will be skipped.
3130     //
3131     while ((RemainingSize > 0) && (RemainingSize >= ListWalker->SignatureListSize) && ListIndex < PrivateData->ListIndex) {
3132       CopyMem ((UINT8 *)NewVariableData + Offset, ListWalker, ListWalker->SignatureListSize);
3133       Offset += ListWalker->SignatureListSize;
3134 
3135       RemainingSize -= ListWalker->SignatureListSize;
3136       ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
3137       ListIndex++;
3138     }
3139 
3140     //
3141     //  Handle the target EFI_SIGNATURE_LIST.
3142     //  If CheckedCount == SIGNATURE_DATA_COUNTS (ListWalker) or DelType == Delete_Signature_List_One
3143     //  it means delete the whole EFI_SIGNATURE_LIST, So we just skip this EFI_SIGNATURE_LIST.
3144     //
3145     if (CheckedCount < SIGNATURE_DATA_COUNTS (ListWalker) && DelType == Delete_Signature_Data) {
3146       NewCertList = (EFI_SIGNATURE_LIST *)(NewVariableData + Offset);
3147       //
3148       // Copy header.
3149       //
3150       CopyMem ((UINT8 *)NewVariableData + Offset, ListWalker, sizeof (EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize);
3151       Offset += sizeof (EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize;
3152 
3153       DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)ListWalker + sizeof(EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize);
3154       for (Index = 0; Index < SIGNATURE_DATA_COUNTS(ListWalker); Index = Index + 1) {
3155         if (PrivateData->CheckArray[Index]) {
3156           //
3157           // Delete checked signature data, and update the size of whole signature list.
3158           //
3159           NewCertList->SignatureListSize -= NewCertList->SignatureSize;
3160         } else {
3161           //
3162           // Remain the unchecked signature data.
3163           //
3164           CopyMem ((UINT8 *)NewVariableData + Offset, DataWalker, ListWalker->SignatureSize);
3165           Offset += ListWalker->SignatureSize;
3166         }
3167         DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)DataWalker + ListWalker->SignatureSize);
3168       }
3169     }
3170 
3171     RemainingSize -= ListWalker->SignatureListSize;
3172     ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
3173 
3174     //
3175     // Copy remaining data, maybe 0.
3176     //
3177     CopyMem((UINT8 *)NewVariableData + Offset, ListWalker, RemainingSize);
3178     Offset += RemainingSize;
3179 
3180     VariableDataSize = Offset;
3181   }
3182 
3183   if ((VariableAttr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
3184     Status = CreateTimeBasedPayload (&VariableDataSize, &NewVariableData);
3185     if (EFI_ERROR (Status)) {
3186       DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status));
3187       goto ON_EXIT;
3188     }
3189   }
3190 
3191   Status = gRT->SetVariable (
3192                   VariableName,
3193                   &gEfiImageSecurityDatabaseGuid,
3194                   VariableAttr,
3195                   VariableDataSize,
3196                   NewVariableData
3197                 );
3198   if (EFI_ERROR (Status)) {
3199     DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r", Status));
3200     goto ON_EXIT;
3201   }
3202 
3203 ON_EXIT:
3204   SECUREBOOT_FREE_NON_NULL (VariableData);
3205   SECUREBOOT_FREE_NON_NULL (NewVariableData);
3206 
3207   return Status;
3208 }
3209 
3210 /**
3211 
3212   Update SecureBoot strings based on new Secure Boot Mode State. String includes STR_SECURE_BOOT_STATE_CONTENT
3213  and STR_CUR_SECURE_BOOT_MODE_CONTENT.
3214 
3215   @param[in]    PrivateData         Module's private data.
3216 
3217   @return EFI_SUCCESS              Update secure boot strings successfully.
3218   @return other                          Fail to update secure boot strings.
3219 
3220 **/
3221 EFI_STATUS
UpdateSecureBootString(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private)3222 UpdateSecureBootString(
3223   IN SECUREBOOT_CONFIG_PRIVATE_DATA  *Private
3224   )
3225 {
3226   UINT8       *SecureBoot;
3227 
3228   SecureBoot = NULL;
3229 
3230   //
3231   // Get current secure boot state.
3232   //
3233   GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);
3234   if (SecureBoot == NULL) {
3235     return EFI_NOT_FOUND;
3236   }
3237 
3238   if (*SecureBoot == SECURE_BOOT_MODE_ENABLE) {
3239     HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);
3240   } else {
3241     HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);
3242   }
3243 
3244   FreePool(SecureBoot);
3245 
3246   return EFI_SUCCESS;
3247 }
3248 
3249 /**
3250   This function extracts configuration from variable.
3251 
3252   @param[in]       Private      Point to SecureBoot configuration driver private data.
3253   @param[in, out]  ConfigData   Point to SecureBoot configuration private data.
3254 
3255 **/
3256 VOID
SecureBootExtractConfigFromVariable(IN SECUREBOOT_CONFIG_PRIVATE_DATA * Private,IN OUT SECUREBOOT_CONFIGURATION * ConfigData)3257 SecureBootExtractConfigFromVariable (
3258   IN SECUREBOOT_CONFIG_PRIVATE_DATA  *Private,
3259   IN OUT SECUREBOOT_CONFIGURATION    *ConfigData
3260   )
3261 {
3262   UINT8     *SecureBootEnable;
3263   UINT8     *SetupMode;
3264   UINT8     *SecureBootMode;
3265   EFI_TIME  CurrTime;
3266 
3267   SecureBootEnable = NULL;
3268   SetupMode        = NULL;
3269   SecureBootMode   = NULL;
3270 
3271   //
3272   // Initilize the Date and Time using system time.
3273   //
3274   ConfigData->CertificateFormat = HASHALG_RAW;
3275   ConfigData->AlwaysRevocation = TRUE;
3276   gRT->GetTime (&CurrTime, NULL);
3277   ConfigData->RevocationDate.Year   = CurrTime.Year;
3278   ConfigData->RevocationDate.Month  = CurrTime.Month;
3279   ConfigData->RevocationDate.Day    = CurrTime.Day;
3280   ConfigData->RevocationTime.Hour   = CurrTime.Hour;
3281   ConfigData->RevocationTime.Minute = CurrTime.Minute;
3282   ConfigData->RevocationTime.Second = 0;
3283   if (Private->FileContext->FHandle != NULL) {
3284     ConfigData->FileEnrollType = Private->FileContext->FileType;
3285   } else {
3286     ConfigData->FileEnrollType = UNKNOWN_FILE_TYPE;
3287   }
3288 
3289   //
3290   // If it is Physical Presence User, set the PhysicalPresent to true.
3291   //
3292   if (UserPhysicalPresent()) {
3293     ConfigData->PhysicalPresent = TRUE;
3294   } else {
3295     ConfigData->PhysicalPresent = FALSE;
3296   }
3297 
3298   //
3299   // If there is no PK then the Delete Pk button will be gray.
3300   //
3301   GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
3302   if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {
3303     ConfigData->HasPk = FALSE;
3304   } else  {
3305     ConfigData->HasPk = TRUE;
3306   }
3307 
3308   //
3309   // Check SecureBootEnable & Pk status, fix the inconsistence.
3310   // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable
3311   // Checkbox.
3312   //
3313   ConfigData->AttemptSecureBoot = FALSE;
3314   GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
3315 
3316   //
3317   // Fix Pk, SecureBootEnable inconsistence
3318   //
3319   if ((SetupMode != NULL) && (*SetupMode) == USER_MODE) {
3320     ConfigData->HideSecureBoot = FALSE;
3321     if ((SecureBootEnable != NULL) && (*SecureBootEnable == SECURE_BOOT_ENABLE)) {
3322       ConfigData->AttemptSecureBoot = TRUE;
3323     }
3324   } else {
3325     ConfigData->HideSecureBoot = TRUE;
3326   }
3327 
3328   //
3329   // Get the SecureBootMode from CustomMode variable.
3330   //
3331   GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
3332   if (SecureBootMode == NULL) {
3333     ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
3334   } else {
3335     ConfigData->SecureBootMode = *(SecureBootMode);
3336   }
3337 
3338   if (SecureBootEnable != NULL) {
3339     FreePool (SecureBootEnable);
3340   }
3341   if (SetupMode != NULL) {
3342     FreePool (SetupMode);
3343   }
3344   if (SecureBootMode != NULL) {
3345     FreePool (SecureBootMode);
3346   }
3347 }
3348 
3349 /**
3350   This function allows a caller to extract the current configuration for one
3351   or more named elements from the target driver.
3352 
3353   @param[in]   This              Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3354   @param[in]   Request           A null-terminated Unicode string in
3355                                  <ConfigRequest> format.
3356   @param[out]  Progress          On return, points to a character in the Request
3357                                  string. Points to the string's null terminator if
3358                                  request was successful. Points to the most recent
3359                                  '&' before the first failing name/value pair (or
3360                                  the beginning of the string if the failure is in
3361                                  the first name/value pair) if the request was not
3362                                  successful.
3363   @param[out]  Results           A null-terminated Unicode string in
3364                                  <ConfigAltResp> format which has all values filled
3365                                  in for the names in the Request string. String to
3366                                  be allocated by the called function.
3367 
3368   @retval EFI_SUCCESS            The Results is filled with the requested values.
3369   @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
3370   @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
3371   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
3372                                  driver.
3373 
3374 **/
3375 EFI_STATUS
3376 EFIAPI
SecureBootExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)3377 SecureBootExtractConfig (
3378   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL        *This,
3379   IN CONST EFI_STRING                            Request,
3380        OUT EFI_STRING                            *Progress,
3381        OUT EFI_STRING                            *Results
3382   )
3383 {
3384   EFI_STATUS                        Status;
3385   UINTN                             BufferSize;
3386   UINTN                             Size;
3387   SECUREBOOT_CONFIGURATION          Configuration;
3388   EFI_STRING                        ConfigRequest;
3389   EFI_STRING                        ConfigRequestHdr;
3390   SECUREBOOT_CONFIG_PRIVATE_DATA    *PrivateData;
3391   BOOLEAN                           AllocatedRequest;
3392 
3393   if (Progress == NULL || Results == NULL) {
3394     return EFI_INVALID_PARAMETER;
3395   }
3396 
3397   AllocatedRequest = FALSE;
3398   ConfigRequestHdr = NULL;
3399   ConfigRequest    = NULL;
3400   Size             = 0;
3401 
3402   ZeroMem (&Configuration, sizeof (Configuration));
3403   PrivateData      = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
3404   *Progress        = Request;
3405 
3406   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
3407     return EFI_NOT_FOUND;
3408   }
3409 
3410   ZeroMem(&Configuration, sizeof(SECUREBOOT_CONFIGURATION));
3411 
3412   //
3413   // Get Configuration from Variable.
3414   //
3415   SecureBootExtractConfigFromVariable (PrivateData, &Configuration);
3416 
3417   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3418   ConfigRequest = Request;
3419   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
3420     //
3421     // Request is set to NULL or OFFSET is NULL, construct full request string.
3422     //
3423     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
3424     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
3425     //
3426     ConfigRequestHdr = HiiConstructConfigHdr (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, PrivateData->DriverHandle);
3427     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
3428     ConfigRequest = AllocateZeroPool (Size);
3429     ASSERT (ConfigRequest != NULL);
3430     AllocatedRequest = TRUE;
3431     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
3432     FreePool (ConfigRequestHdr);
3433     ConfigRequestHdr = NULL;
3434   }
3435 
3436   Status = gHiiConfigRouting->BlockToConfig (
3437                                 gHiiConfigRouting,
3438                                 ConfigRequest,
3439                                 (UINT8 *) &Configuration,
3440                                 BufferSize,
3441                                 Results,
3442                                 Progress
3443                                 );
3444 
3445   //
3446   // Free the allocated config request string.
3447   //
3448   if (AllocatedRequest) {
3449     FreePool (ConfigRequest);
3450   }
3451 
3452   //
3453   // Set Progress string to the original request string.
3454   //
3455   if (Request == NULL) {
3456     *Progress = NULL;
3457   } else if (StrStr (Request, L"OFFSET") == NULL) {
3458     *Progress = Request + StrLen (Request);
3459   }
3460 
3461   return Status;
3462 }
3463 
3464 /**
3465   This function processes the results of changes in configuration.
3466 
3467   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3468   @param[in]  Configuration      A null-terminated Unicode string in <ConfigResp>
3469                                  format.
3470   @param[out] Progress           A pointer to a string filled in with the offset of
3471                                  the most recent '&' before the first failing
3472                                  name/value pair (or the beginning of the string if
3473                                  the failure is in the first name/value pair) or
3474                                  the terminating NULL if all was successful.
3475 
3476   @retval EFI_SUCCESS            The Results is processed successfully.
3477   @retval EFI_INVALID_PARAMETER  Configuration is NULL.
3478   @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this
3479                                  driver.
3480 
3481 **/
3482 EFI_STATUS
3483 EFIAPI
SecureBootRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)3484 SecureBootRouteConfig (
3485   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
3486   IN CONST EFI_STRING                          Configuration,
3487        OUT EFI_STRING                          *Progress
3488   )
3489 {
3490   SECUREBOOT_CONFIGURATION          IfrNvData;
3491   UINTN                             BufferSize;
3492   SECUREBOOT_CONFIG_PRIVATE_DATA    *PrivateData;
3493   EFI_STATUS                        Status;
3494 
3495   if (Configuration == NULL || Progress == NULL) {
3496     return EFI_INVALID_PARAMETER;
3497   }
3498 
3499   *Progress = Configuration;
3500   if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
3501     return EFI_NOT_FOUND;
3502   }
3503 
3504   PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
3505 
3506   //
3507   // Get Configuration from Variable.
3508   //
3509   SecureBootExtractConfigFromVariable (PrivateData, &IfrNvData);
3510 
3511   //
3512   // Map the Configuration to the configuration block.
3513   //
3514   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3515   Status = gHiiConfigRouting->ConfigToBlock (
3516                                 gHiiConfigRouting,
3517                                 Configuration,
3518                                 (UINT8 *)&IfrNvData,
3519                                 &BufferSize,
3520                                 Progress
3521                                 );
3522   if (EFI_ERROR (Status)) {
3523     return Status;
3524   }
3525 
3526   //
3527   // Store Buffer Storage back to EFI variable if needed
3528   //
3529   if (!IfrNvData.HideSecureBoot) {
3530     Status = SaveSecureBootVariable (IfrNvData.AttemptSecureBoot);
3531     if (EFI_ERROR (Status)) {
3532       return Status;
3533     }
3534   }
3535 
3536   *Progress = Configuration + StrLen (Configuration);
3537   return EFI_SUCCESS;
3538 }
3539 
3540 /**
3541   This function to load signature list, the update the menu page.
3542 
3543   @param[in]  PrivateData         Module's private data.
3544   @param[in]  LabelId             Label number to insert opcodes.
3545   @param[in]  FormId              Form ID of current page.
3546   @param[in]  QuestionIdBase      Base question id of the signature list.
3547 
3548   @retval   EFI_SUCCESS           Success to update the signature list page
3549   @retval   EFI_OUT_OF_RESOURCES  Unable to allocate required resources.
3550 **/
3551 EFI_STATUS
LoadSignatureList(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN UINT16 LabelId,IN EFI_FORM_ID FormId,IN EFI_QUESTION_ID QuestionIdBase)3552 LoadSignatureList (
3553   IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
3554   IN UINT16                         LabelId,
3555   IN EFI_FORM_ID                    FormId,
3556   IN EFI_QUESTION_ID                QuestionIdBase
3557   )
3558 {
3559   EFI_STATUS            Status;
3560   EFI_STRING_ID         ListType;
3561   EFI_STRING            FormatNameString;
3562   EFI_STRING            FormatHelpString;
3563   EFI_STRING            FormatTypeString;
3564   EFI_SIGNATURE_LIST    *ListWalker;
3565   EFI_IFR_GUID_LABEL    *StartLabel;
3566   EFI_IFR_GUID_LABEL    *EndLabel;
3567   EFI_IFR_GUID_LABEL    *StartGoto;
3568   EFI_IFR_GUID_LABEL    *EndGoto;
3569   EFI_FORM_ID           DstFormId;
3570   VOID                  *StartOpCodeHandle;
3571   VOID                  *EndOpCodeHandle;
3572   VOID                  *StartGotoHandle;
3573   VOID                  *EndGotoHandle;
3574   UINTN                 DataSize;
3575   UINTN                 RemainingSize;
3576   UINT16                Index;
3577   UINT8                 *VariableData;
3578   CHAR16                VariableName[BUFFER_MAX_SIZE];
3579   CHAR16                NameBuffer[BUFFER_MAX_SIZE];
3580   CHAR16                HelpBuffer[BUFFER_MAX_SIZE];
3581 
3582   Status                = EFI_SUCCESS;
3583   FormatNameString      = NULL;
3584   FormatHelpString      = NULL;
3585   StartOpCodeHandle     = NULL;
3586   EndOpCodeHandle       = NULL;
3587   StartGotoHandle       = NULL;
3588   EndGotoHandle         = NULL;
3589   Index                 = 0;
3590   VariableData          = NULL;
3591 
3592   //
3593   // Initialize the container for dynamic opcodes.
3594   //
3595   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
3596   if (StartOpCodeHandle == NULL) {
3597     Status = EFI_OUT_OF_RESOURCES;
3598     goto ON_EXIT;
3599   }
3600 
3601   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
3602   if (EndOpCodeHandle == NULL) {
3603     Status = EFI_OUT_OF_RESOURCES;
3604     goto ON_EXIT;
3605   }
3606 
3607   StartGotoHandle = HiiAllocateOpCodeHandle ();
3608   if (StartGotoHandle == NULL) {
3609     Status = EFI_OUT_OF_RESOURCES;
3610     goto ON_EXIT;
3611   }
3612 
3613   EndGotoHandle = HiiAllocateOpCodeHandle ();
3614   if (EndGotoHandle == NULL) {
3615     Status = EFI_OUT_OF_RESOURCES;
3616     goto ON_EXIT;
3617   }
3618 
3619   //
3620   // Create Hii Extend Label OpCode.
3621   //
3622   StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
3623                                        StartOpCodeHandle,
3624                                        &gEfiIfrTianoGuid,
3625                                        NULL,
3626                                        sizeof (EFI_IFR_GUID_LABEL)
3627                                      );
3628   StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
3629   StartLabel->Number        = LabelId;
3630 
3631   EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
3632                                      EndOpCodeHandle,
3633                                      &gEfiIfrTianoGuid,
3634                                      NULL,
3635                                      sizeof (EFI_IFR_GUID_LABEL)
3636                                    );
3637   EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
3638   EndLabel->Number        = LABEL_END;
3639 
3640   StartGoto = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode(
3641                                       StartGotoHandle,
3642                                       &gEfiIfrTianoGuid,
3643                                       NULL,
3644                                       sizeof(EFI_IFR_GUID_LABEL)
3645                                     );
3646   StartGoto->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
3647   StartGoto->Number        = LABEL_DELETE_ALL_LIST_BUTTON;
3648 
3649   EndGoto = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode(
3650                                     EndGotoHandle,
3651                                     &gEfiIfrTianoGuid,
3652                                     NULL,
3653                                     sizeof(EFI_IFR_GUID_LABEL)
3654                                   );
3655   EndGoto->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
3656   EndGoto->Number = LABEL_END;
3657 
3658   if (PrivateData->VariableName == Variable_DB) {
3659     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE);
3660     DstFormId = FORMID_SECURE_BOOT_DB_OPTION_FORM;
3661   } else if (PrivateData->VariableName == Variable_DBX) {
3662     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE1);
3663     DstFormId = FORMID_SECURE_BOOT_DBX_OPTION_FORM;
3664   } else if (PrivateData->VariableName == Variable_DBT) {
3665     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE2);
3666     DstFormId = FORMID_SECURE_BOOT_DBT_OPTION_FORM;
3667   } else {
3668     goto ON_EXIT;
3669   }
3670 
3671   HiiCreateGotoOpCode (
3672     StartGotoHandle,
3673     DstFormId,
3674     STRING_TOKEN (STR_SECURE_BOOT_DELETE_ALL_LIST),
3675     STRING_TOKEN (STR_SECURE_BOOT_DELETE_ALL_LIST),
3676     EFI_IFR_FLAG_CALLBACK,
3677     KEY_SECURE_BOOT_DELETE_ALL_LIST
3678   );
3679 
3680   //
3681   // Read Variable, the variable name save in the PrivateData->VariableName.
3682   //
3683   DataSize = 0;
3684   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
3685   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
3686     goto ON_EXIT;
3687   }
3688 
3689   VariableData = AllocateZeroPool (DataSize);
3690   if (VariableData == NULL) {
3691     Status = EFI_OUT_OF_RESOURCES;
3692     goto ON_EXIT;
3693   }
3694   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
3695   if (EFI_ERROR (Status)) {
3696     goto ON_EXIT;
3697   }
3698 
3699   FormatNameString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_LIST_NAME_FORMAT), NULL);
3700   FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_LIST_HELP_FORMAT), NULL);
3701   if (FormatNameString == NULL || FormatHelpString == NULL) {
3702     goto ON_EXIT;
3703   }
3704 
3705   RemainingSize = DataSize;
3706   ListWalker    = (EFI_SIGNATURE_LIST *)VariableData;
3707   while ((RemainingSize > 0) && (RemainingSize >= ListWalker->SignatureListSize)) {
3708     if (CompareGuid (&ListWalker->SignatureType, &gEfiCertRsa2048Guid)) {
3709       ListType = STRING_TOKEN (STR_LIST_TYPE_RSA2048_SHA256);
3710     } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Guid)) {
3711       ListType = STRING_TOKEN (STR_LIST_TYPE_X509);
3712     } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertSha1Guid)) {
3713       ListType = STRING_TOKEN (STR_LIST_TYPE_SHA1);
3714     } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertSha256Guid)) {
3715       ListType = STRING_TOKEN (STR_LIST_TYPE_SHA256);
3716     } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Sha256Guid)) {
3717       ListType = STRING_TOKEN (STR_LIST_TYPE_X509_SHA256);
3718     } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Sha384Guid)) {
3719       ListType = STRING_TOKEN (STR_LIST_TYPE_X509_SHA384);
3720     } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Sha512Guid)) {
3721       ListType = STRING_TOKEN (STR_LIST_TYPE_X509_SHA512);
3722     } else {
3723       ListType = STRING_TOKEN (STR_LIST_TYPE_UNKNOWN);
3724     }
3725     FormatTypeString = HiiGetString (PrivateData->HiiHandle, ListType, NULL);
3726     if (FormatTypeString == NULL) {
3727       goto ON_EXIT;
3728     }
3729 
3730     ZeroMem (NameBuffer, sizeof (NameBuffer));
3731     UnicodeSPrint (NameBuffer, sizeof (NameBuffer), FormatNameString, Index + 1);
3732 
3733     ZeroMem (HelpBuffer, sizeof (HelpBuffer));
3734     UnicodeSPrint (HelpBuffer,
3735       sizeof (HelpBuffer),
3736       FormatHelpString,
3737       FormatTypeString,
3738       SIGNATURE_DATA_COUNTS (ListWalker)
3739     );
3740     SECUREBOOT_FREE_NON_NULL (FormatTypeString);
3741     FormatTypeString = NULL;
3742 
3743     HiiCreateGotoOpCode (
3744       StartOpCodeHandle,
3745       SECUREBOOT_DELETE_SIGNATURE_DATA_FORM,
3746       HiiSetString (PrivateData->HiiHandle, 0, NameBuffer, NULL),
3747       HiiSetString (PrivateData->HiiHandle, 0, HelpBuffer, NULL),
3748       EFI_IFR_FLAG_CALLBACK,
3749       QuestionIdBase + Index++
3750     );
3751 
3752     RemainingSize -= ListWalker->SignatureListSize;
3753     ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
3754   }
3755 
3756 ON_EXIT:
3757   HiiUpdateForm (
3758     PrivateData->HiiHandle,
3759     &gSecureBootConfigFormSetGuid,
3760     FormId,
3761     StartOpCodeHandle,
3762     EndOpCodeHandle
3763   );
3764 
3765   HiiUpdateForm (
3766     PrivateData->HiiHandle,
3767     &gSecureBootConfigFormSetGuid,
3768     FormId,
3769     StartGotoHandle,
3770     EndGotoHandle
3771   );
3772 
3773   SECUREBOOT_FREE_NON_OPCODE (StartOpCodeHandle);
3774   SECUREBOOT_FREE_NON_OPCODE (EndOpCodeHandle);
3775   SECUREBOOT_FREE_NON_OPCODE (StartGotoHandle);
3776   SECUREBOOT_FREE_NON_OPCODE (EndGotoHandle);
3777 
3778   SECUREBOOT_FREE_NON_NULL (VariableData);
3779   SECUREBOOT_FREE_NON_NULL (FormatNameString);
3780   SECUREBOOT_FREE_NON_NULL (FormatHelpString);
3781 
3782   PrivateData->ListCount = Index;
3783 
3784   return Status;
3785 }
3786 
3787 /**
3788   Parse hash value from EFI_SIGNATURE_DATA, and save in the CHAR16 type array.
3789   The buffer is callee allocated and should be freed by the caller.
3790 
3791   @param[in]    ListEntry                 The pointer point to the signature list.
3792   @param[in]    DataEntry                 The signature data we are processing.
3793   @param[out]   BufferToReturn            Buffer to save the hash value.
3794 
3795   @retval       EFI_INVALID_PARAMETER     Invalid List or Data or Buffer.
3796   @retval       EFI_OUT_OF_RESOURCES      A memory allocation failed.
3797   @retval       EFI_SUCCESS               Operation success.
3798 **/
3799 EFI_STATUS
ParseHashValue(IN EFI_SIGNATURE_LIST * ListEntry,IN EFI_SIGNATURE_DATA * DataEntry,OUT CHAR16 ** BufferToReturn)3800 ParseHashValue (
3801   IN     EFI_SIGNATURE_LIST    *ListEntry,
3802   IN     EFI_SIGNATURE_DATA    *DataEntry,
3803      OUT CHAR16                **BufferToReturn
3804   )
3805 {
3806   UINTN       Index;
3807   UINTN       BufferIndex;
3808   UINTN       TotalSize;
3809   UINTN       DataSize;
3810   UINTN       Line;
3811   UINTN       OneLineBytes;
3812 
3813   //
3814   //  Assume that, display 8 bytes in one line.
3815   //
3816   OneLineBytes = 8;
3817 
3818   if (ListEntry == NULL || DataEntry == NULL || BufferToReturn == NULL) {
3819     return EFI_INVALID_PARAMETER;
3820   }
3821 
3822   DataSize = ListEntry->SignatureSize - sizeof(EFI_GUID);
3823   Line = (DataSize + OneLineBytes - 1) / OneLineBytes;
3824 
3825   //
3826   // Each byte will split two Hex-number, and each line need additional memory to save '\r\n'.
3827   //
3828   TotalSize = ((DataSize + Line) * 2 * sizeof(CHAR16));
3829 
3830   *BufferToReturn = AllocateZeroPool(TotalSize);
3831   if (*BufferToReturn == NULL) {
3832     return EFI_OUT_OF_RESOURCES;
3833   }
3834 
3835   for (Index = 0, BufferIndex = 0; Index < DataSize; Index = Index + 1) {
3836     if ((Index > 0) && (Index % OneLineBytes == 0)) {
3837       BufferIndex += UnicodeSPrint(&(*BufferToReturn)[BufferIndex], TotalSize - sizeof(CHAR16) * BufferIndex, L"\n");
3838     }
3839     BufferIndex += UnicodeSPrint(&(*BufferToReturn)[BufferIndex], TotalSize - sizeof(CHAR16) * BufferIndex, L"%02x", DataEntry->SignatureData[Index]);
3840   }
3841   BufferIndex += UnicodeSPrint(&(*BufferToReturn)[BufferIndex], TotalSize - sizeof(CHAR16) * BufferIndex, L"\n");
3842 
3843   return EFI_SUCCESS;
3844 }
3845 
3846 /**
3847   Function to get the common name from the X509 format certificate.
3848   The buffer is callee allocated and should be freed by the caller.
3849 
3850   @param[in]    ListEntry                 The pointer point to the signature list.
3851   @param[in]    DataEntry                 The signature data we are processing.
3852   @param[out]   BufferToReturn            Buffer to save the CN of X509 certificate.
3853 
3854   @retval       EFI_INVALID_PARAMETER     Invalid List or Data or Buffer.
3855   @retval       EFI_OUT_OF_RESOURCES      A memory allocation failed.
3856   @retval       EFI_SUCCESS               Operation success.
3857   @retval       EFI_NOT_FOUND             Not found CN field in the X509 certificate.
3858 **/
3859 EFI_STATUS
GetCommonNameFromX509(IN EFI_SIGNATURE_LIST * ListEntry,IN EFI_SIGNATURE_DATA * DataEntry,OUT CHAR16 ** BufferToReturn)3860 GetCommonNameFromX509 (
3861   IN     EFI_SIGNATURE_LIST    *ListEntry,
3862   IN     EFI_SIGNATURE_DATA    *DataEntry,
3863      OUT CHAR16                **BufferToReturn
3864   )
3865 {
3866   EFI_STATUS      Status;
3867   CHAR8           *CNBuffer;
3868   UINTN           CNBufferSize;
3869 
3870   Status        = EFI_SUCCESS;
3871   CNBuffer      = NULL;
3872 
3873   CNBuffer = AllocateZeroPool(256);
3874   if (CNBuffer == NULL) {
3875     Status = EFI_OUT_OF_RESOURCES;
3876     goto ON_EXIT;
3877   }
3878 
3879   CNBufferSize = 256;
3880   X509GetCommonName (
3881     (UINT8 *)DataEntry + sizeof(EFI_GUID),
3882     ListEntry->SignatureSize - sizeof(EFI_GUID),
3883     CNBuffer,
3884     &CNBufferSize
3885   );
3886 
3887   *BufferToReturn = AllocateZeroPool(256 * sizeof(CHAR16));
3888   if (*BufferToReturn == NULL) {
3889     Status = EFI_OUT_OF_RESOURCES;
3890     goto ON_EXIT;
3891   }
3892 
3893   AsciiStrToUnicodeStrS (CNBuffer, *BufferToReturn, 256);
3894 
3895 ON_EXIT:
3896   SECUREBOOT_FREE_NON_NULL (CNBuffer);
3897 
3898   return Status;
3899 }
3900 
3901 /**
3902   Format the help info for the signature data, each help info contain 3 parts.
3903   1. Onwer Guid.
3904   2. Content, depends on the type of the signature list.
3905   3. Revocation time.
3906 
3907   @param[in]      PrivateData             Module's private data.
3908   @param[in]      ListEntry               Point to the signature list.
3909   @param[in]      DataEntry               Point to the signature data we are processing.
3910   @param[out]     StringId                Save the string id of help info.
3911 
3912   @retval         EFI_SUCCESS             Operation success.
3913   @retval         EFI_OUT_OF_RESOURCES    Unable to allocate required resources.
3914 **/
3915 EFI_STATUS
FormatHelpInfo(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN EFI_SIGNATURE_LIST * ListEntry,IN EFI_SIGNATURE_DATA * DataEntry,OUT EFI_STRING_ID * StringId)3916 FormatHelpInfo (
3917   IN     SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,
3918   IN     EFI_SIGNATURE_LIST               *ListEntry,
3919   IN     EFI_SIGNATURE_DATA               *DataEntry,
3920      OUT EFI_STRING_ID                    *StringId
3921   )
3922 {
3923   EFI_STATUS      Status;
3924   EFI_TIME        *Time;
3925   EFI_STRING_ID   ListTypeId;
3926   EFI_STRING      FormatHelpString;
3927   EFI_STRING      FormatTypeString;
3928   UINTN           DataSize;
3929   UINTN           HelpInfoIndex;
3930   UINTN           TotalSize;
3931   CHAR16          GuidString[BUFFER_MAX_SIZE];
3932   CHAR16          TimeString[BUFFER_MAX_SIZE];
3933   CHAR16          *DataString;
3934   CHAR16          *HelpInfoString;
3935   BOOLEAN         IsCert;
3936 
3937   Status            = EFI_SUCCESS;
3938   Time              = NULL;
3939   FormatTypeString  = NULL;
3940   HelpInfoIndex     = 0;
3941   DataString        = NULL;
3942   HelpInfoString    = NULL;
3943   IsCert            = FALSE;
3944 
3945   if (CompareGuid(&ListEntry->SignatureType, &gEfiCertRsa2048Guid)) {
3946     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_RSA2048_SHA256);
3947     DataSize = ListEntry->SignatureSize - sizeof(EFI_GUID);
3948     IsCert = TRUE;
3949   } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Guid)) {
3950     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509);
3951     DataSize = ListEntry->SignatureSize - sizeof(EFI_GUID);
3952     IsCert = TRUE;
3953   } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertSha1Guid)) {
3954     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_SHA1);
3955     DataSize = 20;
3956   } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertSha256Guid)) {
3957     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_SHA256);
3958     DataSize = 32;
3959   } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Sha256Guid)) {
3960     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509_SHA256);
3961     DataSize = 32;
3962     Time = (EFI_TIME *)(DataEntry->SignatureData + DataSize);
3963   } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Sha384Guid)) {
3964     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509_SHA384);
3965     DataSize = 48;
3966     Time = (EFI_TIME *)(DataEntry->SignatureData + DataSize);
3967   } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Sha512Guid)) {
3968     ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509_SHA512);
3969     DataSize = 64;
3970     Time = (EFI_TIME *)(DataEntry->SignatureData + DataSize);
3971   } else {
3972     Status = EFI_UNSUPPORTED;
3973     goto ON_EXIT;
3974   }
3975 
3976   FormatTypeString = HiiGetString (PrivateData->HiiHandle, ListTypeId, NULL);
3977   if (FormatTypeString == NULL) {
3978     goto ON_EXIT;
3979   }
3980 
3981   TotalSize = 1024;
3982   HelpInfoString = AllocateZeroPool (TotalSize);
3983   if (HelpInfoString == NULL) {
3984     Status = EFI_OUT_OF_RESOURCES;
3985     goto ON_EXIT;
3986   }
3987 
3988   //
3989   // Format GUID part.
3990   //
3991   ZeroMem (GuidString, sizeof (GuidString));
3992   GuidToString(&DataEntry->SignatureOwner, GuidString, BUFFER_MAX_SIZE);
3993   FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_GUID), NULL);
3994   if (FormatHelpString == NULL) {
3995     goto ON_EXIT;
3996   }
3997   HelpInfoIndex += UnicodeSPrint (
3998                      &HelpInfoString[HelpInfoIndex],
3999                      TotalSize - sizeof(CHAR16) * HelpInfoIndex,
4000                      FormatHelpString,
4001                      GuidString
4002                    );
4003   SECUREBOOT_FREE_NON_NULL (FormatHelpString);
4004   FormatHelpString = NULL;
4005 
4006   //
4007   // Format content part, it depends on the type of signature list, hash value or CN.
4008   //
4009   if (IsCert) {
4010     GetCommonNameFromX509 (ListEntry, DataEntry, &DataString);
4011     FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_CN), NULL);
4012   } else {
4013     //
4014     //  Format hash value for each signature data entry.
4015     //
4016     ParseHashValue (ListEntry, DataEntry, &DataString);
4017     FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_HASH), NULL);
4018   }
4019   if (FormatHelpString == NULL) {
4020     goto ON_EXIT;
4021   }
4022   HelpInfoIndex += UnicodeSPrint (
4023                      &HelpInfoString[HelpInfoIndex],
4024                      TotalSize - sizeof (CHAR16) * HelpInfoIndex,
4025                      FormatHelpString,
4026                      FormatTypeString,
4027                      DataSize,
4028                      DataString
4029                    );
4030   SECUREBOOT_FREE_NON_NULL (FormatHelpString);
4031   FormatHelpString = NULL;
4032 
4033   //
4034   // Format revocation time part.
4035   //
4036   if (Time != NULL) {
4037     ZeroMem (TimeString, sizeof (TimeString));
4038     UnicodeSPrint (
4039       TimeString,
4040       sizeof (TimeString),
4041       L"%d-%d-%d %d:%d:%d",
4042       Time->Year,
4043       Time->Month,
4044       Time->Day,
4045       Time->Hour,
4046       Time->Minute,
4047       Time->Second
4048     );
4049     FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_TIME), NULL);
4050     if (FormatHelpString == NULL) {
4051       goto ON_EXIT;
4052     }
4053     UnicodeSPrint (
4054       &HelpInfoString[HelpInfoIndex],
4055       TotalSize - sizeof (CHAR16) * HelpInfoIndex,
4056       FormatHelpString,
4057       TimeString
4058     );
4059     SECUREBOOT_FREE_NON_NULL (FormatHelpString);
4060     FormatHelpString = NULL;
4061   }
4062 
4063   *StringId = HiiSetString (PrivateData->HiiHandle, 0, HelpInfoString, NULL);
4064 ON_EXIT:
4065   SECUREBOOT_FREE_NON_NULL (DataString);
4066   SECUREBOOT_FREE_NON_NULL (HelpInfoString);
4067 
4068   SECUREBOOT_FREE_NON_NULL (FormatTypeString);
4069 
4070   return Status;
4071 }
4072 
4073 /**
4074   This functino to load signature data under the signature list.
4075 
4076   @param[in]  PrivateData         Module's private data.
4077   @param[in]  LabelId             Label number to insert opcodes.
4078   @param[in]  FormId              Form ID of current page.
4079   @param[in]  QuestionIdBase      Base question id of the signature list.
4080   @param[in]  ListIndex           Indicate to load which signature list.
4081 
4082   @retval   EFI_SUCCESS           Success to update the signature list page
4083   @retval   EFI_OUT_OF_RESOURCES  Unable to allocate required resources.
4084 **/
4085 EFI_STATUS
LoadSignatureData(IN SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData,IN UINT16 LabelId,IN EFI_FORM_ID FormId,IN EFI_QUESTION_ID QuestionIdBase,IN UINT16 ListIndex)4086 LoadSignatureData (
4087   IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
4088   IN UINT16                         LabelId,
4089   IN EFI_FORM_ID                    FormId,
4090   IN EFI_QUESTION_ID                QuestionIdBase,
4091   IN UINT16                         ListIndex
4092   )
4093 {
4094   EFI_STATUS            Status;
4095   EFI_SIGNATURE_LIST    *ListWalker;
4096   EFI_SIGNATURE_DATA    *DataWalker;
4097   EFI_IFR_GUID_LABEL    *StartLabel;
4098   EFI_IFR_GUID_LABEL    *EndLabel;
4099   EFI_STRING_ID         HelpStringId;
4100   EFI_STRING            FormatNameString;
4101   VOID                  *StartOpCodeHandle;
4102   VOID                  *EndOpCodeHandle;
4103   UINTN                 DataSize;
4104   UINTN                 RemainingSize;
4105   UINT16                Index;
4106   UINT8                 *VariableData;
4107   CHAR16                VariableName[BUFFER_MAX_SIZE];
4108   CHAR16                NameBuffer[BUFFER_MAX_SIZE];
4109 
4110   Status              = EFI_SUCCESS;
4111   FormatNameString    = NULL;
4112   StartOpCodeHandle   = NULL;
4113   EndOpCodeHandle     = NULL;
4114   Index               = 0;
4115   VariableData        = NULL;
4116 
4117   //
4118   // Initialize the container for dynamic opcodes.
4119   //
4120   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
4121   if (StartOpCodeHandle == NULL) {
4122     Status = EFI_OUT_OF_RESOURCES;
4123     goto ON_EXIT;
4124   }
4125 
4126   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
4127   if (EndOpCodeHandle == NULL) {
4128     Status = EFI_OUT_OF_RESOURCES;
4129     goto ON_EXIT;
4130   }
4131 
4132   //
4133   // Create Hii Extend Label OpCode.
4134   //
4135   StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
4136                                        StartOpCodeHandle,
4137                                        &gEfiIfrTianoGuid,
4138                                        NULL,
4139                                        sizeof (EFI_IFR_GUID_LABEL)
4140                                      );
4141   StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
4142   StartLabel->Number        = LabelId;
4143 
4144   EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
4145                                      EndOpCodeHandle,
4146                                      &gEfiIfrTianoGuid,
4147                                      NULL,
4148                                      sizeof (EFI_IFR_GUID_LABEL)
4149                                    );
4150   EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;
4151   EndLabel->Number        = LABEL_END;
4152 
4153   if (PrivateData->VariableName == Variable_DB) {
4154     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE);
4155   } else if (PrivateData->VariableName == Variable_DBX) {
4156     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE1);
4157   } else if (PrivateData->VariableName == Variable_DBT) {
4158     UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE2);
4159   } else {
4160     goto ON_EXIT;
4161   }
4162 
4163   //
4164   // Read Variable, the variable name save in the PrivateData->VariableName.
4165   //
4166   DataSize = 0;
4167   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
4168   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
4169     goto ON_EXIT;
4170   }
4171 
4172   VariableData = AllocateZeroPool (DataSize);
4173   if (VariableData == NULL) {
4174     Status = EFI_OUT_OF_RESOURCES;
4175     goto ON_EXIT;
4176   }
4177   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
4178   if (EFI_ERROR (Status)) {
4179     goto ON_EXIT;
4180   }
4181 
4182   RemainingSize = DataSize;
4183   ListWalker = (EFI_SIGNATURE_LIST *)VariableData;
4184 
4185   //
4186   // Skip signature list.
4187   //
4188   while ((RemainingSize > 0) && (RemainingSize >= ListWalker->SignatureListSize) && ListIndex-- > 0) {
4189     RemainingSize -= ListWalker->SignatureListSize;
4190     ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
4191   }
4192 
4193   FormatNameString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_NAME_FORMAT), NULL);
4194   if (FormatNameString == NULL) {
4195     goto ON_EXIT;
4196   }
4197 
4198   DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)ListWalker + sizeof(EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize);
4199   for (Index = 0; Index < SIGNATURE_DATA_COUNTS(ListWalker); Index = Index + 1) {
4200     //
4201     // Format name buffer.
4202     //
4203     ZeroMem (NameBuffer, sizeof (NameBuffer));
4204     UnicodeSPrint (NameBuffer, sizeof (NameBuffer), FormatNameString, Index + 1);
4205 
4206     //
4207     // Format help info buffer.
4208     //
4209     Status = FormatHelpInfo (PrivateData, ListWalker, DataWalker, &HelpStringId);
4210     if (EFI_ERROR (Status)) {
4211       goto ON_EXIT;
4212     }
4213 
4214     HiiCreateCheckBoxOpCode (
4215       StartOpCodeHandle,
4216       (EFI_QUESTION_ID)(QuestionIdBase + Index),
4217       0,
4218       0,
4219       HiiSetString (PrivateData->HiiHandle, 0, NameBuffer, NULL),
4220       HelpStringId,
4221       EFI_IFR_FLAG_CALLBACK,
4222       0,
4223       NULL
4224     );
4225 
4226     ZeroMem(NameBuffer, 100);
4227     DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)DataWalker + ListWalker->SignatureSize);
4228   }
4229 
4230   //
4231   // Allocate a buffer to record which signature data will be checked.
4232   // This memory buffer will be freed when exit from the SECUREBOOT_DELETE_SIGNATURE_DATA_FORM form.
4233   //
4234   PrivateData->CheckArray = AllocateZeroPool (SIGNATURE_DATA_COUNTS (ListWalker) * sizeof (BOOLEAN));
4235 ON_EXIT:
4236   HiiUpdateForm (
4237     PrivateData->HiiHandle,
4238     &gSecureBootConfigFormSetGuid,
4239     FormId,
4240     StartOpCodeHandle,
4241     EndOpCodeHandle
4242   );
4243 
4244   SECUREBOOT_FREE_NON_OPCODE (StartOpCodeHandle);
4245   SECUREBOOT_FREE_NON_OPCODE (EndOpCodeHandle);
4246 
4247   SECUREBOOT_FREE_NON_NULL (VariableData);
4248   SECUREBOOT_FREE_NON_NULL (FormatNameString);
4249 
4250   return Status;
4251 }
4252 
4253 /**
4254   This function is called to provide results data to the driver.
4255 
4256   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
4257   @param[in]  Action             Specifies the type of action taken by the browser.
4258   @param[in]  QuestionId         A unique value which is sent to the original
4259                                  exporting driver so that it can identify the type
4260                                  of data to expect.
4261   @param[in]  Type               The type of value for the question.
4262   @param[in]  Value              A pointer to the data being sent to the original
4263                                  exporting driver.
4264   @param[out] ActionRequest      On return, points to the action requested by the
4265                                  callback function.
4266 
4267   @retval EFI_SUCCESS            The callback successfully handled the action.
4268   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
4269                                  variable and its data.
4270   @retval EFI_DEVICE_ERROR       The variable could not be saved.
4271   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
4272                                  callback.
4273 
4274 **/
4275 EFI_STATUS
4276 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)4277 SecureBootCallback (
4278   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
4279   IN     EFI_BROWSER_ACTION                    Action,
4280   IN     EFI_QUESTION_ID                       QuestionId,
4281   IN     UINT8                                 Type,
4282   IN     EFI_IFR_TYPE_VALUE                    *Value,
4283      OUT EFI_BROWSER_ACTION_REQUEST            *ActionRequest
4284   )
4285 {
4286   EFI_INPUT_KEY                   Key;
4287   EFI_STATUS                      Status;
4288   RETURN_STATUS                   RStatus;
4289   SECUREBOOT_CONFIG_PRIVATE_DATA  *Private;
4290   UINTN                           BufferSize;
4291   SECUREBOOT_CONFIGURATION        *IfrNvData;
4292   UINT16                          LabelId;
4293   UINT8                           *SecureBootEnable;
4294   UINT8                           *Pk;
4295   UINT8                           *SecureBootMode;
4296   UINT8                           *SetupMode;
4297   CHAR16                          PromptString[100];
4298   EFI_DEVICE_PATH_PROTOCOL        *File;
4299   UINTN                           NameLength;
4300   UINT16                          *FilePostFix;
4301   SECUREBOOT_CONFIG_PRIVATE_DATA  *PrivateData;
4302   BOOLEAN                         GetBrowserDataResult;
4303 
4304   Status           = EFI_SUCCESS;
4305   SecureBootEnable = NULL;
4306   SecureBootMode   = NULL;
4307   SetupMode        = NULL;
4308   File             = NULL;
4309 
4310   if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
4311     return EFI_INVALID_PARAMETER;
4312   }
4313 
4314   Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
4315 
4316   gSecureBootPrivateData = Private;
4317 
4318   //
4319   // Retrieve uncommitted data from Browser
4320   //
4321   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
4322   IfrNvData = AllocateZeroPool (BufferSize);
4323   if (IfrNvData == NULL) {
4324     return EFI_OUT_OF_RESOURCES;
4325   }
4326 
4327   GetBrowserDataResult = HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData);
4328 
4329   if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
4330     if (QuestionId == KEY_SECURE_BOOT_MODE) {
4331       //
4332       // Update secure boot strings when opening this form
4333       //
4334       Status = UpdateSecureBootString(Private);
4335       SecureBootExtractConfigFromVariable (Private, IfrNvData);
4336       mIsEnterSecureBootForm = TRUE;
4337     } else {
4338       //
4339       // When entering SecureBoot OPTION Form
4340       // always close opened file & free resource
4341       //
4342       if ((QuestionId == KEY_SECURE_BOOT_PK_OPTION) ||
4343           (QuestionId == KEY_SECURE_BOOT_KEK_OPTION) ||
4344           (QuestionId == KEY_SECURE_BOOT_DB_OPTION) ||
4345           (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) ||
4346           (QuestionId == KEY_SECURE_BOOT_DBT_OPTION)) {
4347         CloseEnrolledFile(Private->FileContext);
4348       } else if (QuestionId == KEY_SECURE_BOOT_DELETE_ALL_LIST) {
4349         //
4350         // Update ListCount field in varstore
4351         // Button "Delete All Signature List" is
4352         // enable when ListCount is greater than 0.
4353         //
4354         IfrNvData->ListCount = Private->ListCount;
4355       }
4356     }
4357     goto EXIT;
4358   }
4359 
4360   if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
4361     Status = EFI_UNSUPPORTED;
4362     if (QuestionId == KEY_SECURE_BOOT_MODE) {
4363       if (mIsEnterSecureBootForm) {
4364         Value->u8 = SECURE_BOOT_MODE_STANDARD;
4365         Status = EFI_SUCCESS;
4366       }
4367     }
4368     goto EXIT;
4369   }
4370 
4371   if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
4372       (Action != EFI_BROWSER_ACTION_CHANGING) &&
4373       (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&
4374       (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {
4375     Status = EFI_UNSUPPORTED;
4376     goto EXIT;
4377   }
4378 
4379   if (Action == EFI_BROWSER_ACTION_CHANGING) {
4380 
4381     switch (QuestionId) {
4382     case KEY_SECURE_BOOT_ENABLE:
4383       GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
4384       if (NULL != SecureBootEnable) {
4385         FreePool (SecureBootEnable);
4386         if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) {
4387           CreatePopUp (
4388             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4389             &Key,
4390             L"Only Physical Presence User could disable secure boot!",
4391             NULL
4392             );
4393           Status = EFI_UNSUPPORTED;
4394         } else {
4395           CreatePopUp (
4396             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4397             &Key,
4398             L"Configuration changed, please reset the platform to take effect!",
4399             NULL
4400             );
4401         }
4402       }
4403       break;
4404 
4405     case KEY_SECURE_BOOT_KEK_OPTION:
4406     case KEY_SECURE_BOOT_DB_OPTION:
4407     case KEY_SECURE_BOOT_DBX_OPTION:
4408     case KEY_SECURE_BOOT_DBT_OPTION:
4409       PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
4410       //
4411       // Clear Signature GUID.
4412       //
4413       ZeroMem (IfrNvData->SignatureGuid, sizeof (IfrNvData->SignatureGuid));
4414       if (Private->SignatureGUID == NULL) {
4415         Private->SignatureGUID = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID));
4416         if (Private->SignatureGUID == NULL) {
4417           return EFI_OUT_OF_RESOURCES;
4418         }
4419       }
4420 
4421       //
4422       // Cleanup VFRData once leaving PK/KEK/DB/DBX/DBT enroll/delete page
4423       //
4424       SecureBootExtractConfigFromVariable (PrivateData, IfrNvData);
4425 
4426       if (QuestionId == KEY_SECURE_BOOT_DB_OPTION) {
4427         LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
4428       } else if (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) {
4429         LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
4430       } else if (QuestionId == KEY_SECURE_BOOT_DBT_OPTION) {
4431         LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
4432       } else {
4433         LabelId = FORMID_ENROLL_KEK_FORM;
4434       }
4435 
4436       //
4437       // Refresh selected file.
4438       //
4439       CleanUpPage (LabelId, Private);
4440       break;
4441     case KEY_SECURE_BOOT_PK_OPTION:
4442       LabelId = FORMID_ENROLL_PK_FORM;
4443       //
4444       // Refresh selected file.
4445       //
4446       CleanUpPage (LabelId, Private);
4447       break;
4448 
4449     case FORMID_ENROLL_PK_FORM:
4450       ChooseFile (NULL, NULL, UpdatePKFromFile, &File);
4451       break;
4452 
4453     case FORMID_ENROLL_KEK_FORM:
4454       ChooseFile (NULL, NULL, UpdateKEKFromFile, &File);
4455       break;
4456 
4457     case SECUREBOOT_ENROLL_SIGNATURE_TO_DB:
4458       ChooseFile (NULL, NULL, UpdateDBFromFile, &File);
4459       break;
4460 
4461     case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX:
4462       ChooseFile (NULL, NULL, UpdateDBXFromFile, &File);
4463 
4464       if (Private->FileContext->FHandle != NULL) {
4465         //
4466         // Parse the file's postfix.
4467         //
4468         NameLength = StrLen (Private->FileContext->FileName);
4469         if (NameLength <= 4) {
4470           return FALSE;
4471         }
4472         FilePostFix = Private->FileContext->FileName + NameLength - 4;
4473 
4474         if (IsDerEncodeCertificate (FilePostFix)) {
4475           //
4476           // Supports DER-encoded X509 certificate.
4477           //
4478           IfrNvData->FileEnrollType = X509_CERT_FILE_TYPE;
4479         } else if (IsAuthentication2Format(Private->FileContext->FHandle)){
4480           IfrNvData->FileEnrollType = AUTHENTICATION_2_FILE_TYPE;
4481         } else {
4482           IfrNvData->FileEnrollType = PE_IMAGE_FILE_TYPE;
4483         }
4484         Private->FileContext->FileType = IfrNvData->FileEnrollType;
4485 
4486         //
4487         // Clean up Certificate Format if File type is not X509 DER
4488         //
4489         if (IfrNvData->FileEnrollType != X509_CERT_FILE_TYPE) {
4490           IfrNvData->CertificateFormat = HASHALG_RAW;
4491         }
4492         DEBUG((DEBUG_ERROR, "IfrNvData->FileEnrollType %d\n", Private->FileContext->FileType));
4493       }
4494 
4495       break;
4496 
4497     case SECUREBOOT_ENROLL_SIGNATURE_TO_DBT:
4498       ChooseFile (NULL, NULL, UpdateDBTFromFile, &File);
4499       break;
4500 
4501     case KEY_SECURE_BOOT_DELETE_PK:
4502       if (Value->u8) {
4503         CreatePopUp (
4504           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4505           &Key,
4506           L"Are you sure you want to delete PK? Secure boot will be disabled!",
4507           L"Press 'Y' to delete PK and exit, 'N' to discard change and return",
4508           NULL
4509           );
4510         if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
4511           Status = DeletePlatformKey ();
4512           if (EFI_ERROR (Status)) {
4513             CreatePopUp (
4514               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4515               &Key,
4516               L"Only Physical Presence User could delete PK in custom mode!",
4517               NULL
4518               );
4519           }
4520         }
4521       }
4522       break;
4523 
4524     case KEY_DELETE_KEK:
4525       UpdateDeletePage (
4526         Private,
4527         EFI_KEY_EXCHANGE_KEY_NAME,
4528         &gEfiGlobalVariableGuid,
4529         LABEL_KEK_DELETE,
4530         FORMID_DELETE_KEK_FORM,
4531         OPTION_DEL_KEK_QUESTION_ID
4532         );
4533       break;
4534 
4535     case SECUREBOOT_DELETE_SIGNATURE_FROM_DB:
4536       UpdateDeletePage (
4537         Private,
4538         EFI_IMAGE_SECURITY_DATABASE,
4539         &gEfiImageSecurityDatabaseGuid,
4540         LABEL_DB_DELETE,
4541         SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
4542         OPTION_DEL_DB_QUESTION_ID
4543         );
4544        break;
4545 
4546     //
4547     // From DBX option to the level-1 form, display signature list.
4548     //
4549     case KEY_VALUE_FROM_DBX_TO_LIST_FORM:
4550       Private->VariableName = Variable_DBX;
4551       LoadSignatureList (
4552         Private,
4553         LABEL_SIGNATURE_LIST_START,
4554         SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4555         OPTION_SIGNATURE_LIST_QUESTION_ID
4556       );
4557       break;
4558 
4559       //
4560       // Delete all signature list and reload.
4561       //
4562     case KEY_SECURE_BOOT_DELETE_ALL_LIST:
4563       CreatePopUp(
4564         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4565         &Key,
4566         L"Press 'Y' to delete signature list.",
4567         L"Press other key to cancel and exit.",
4568         NULL
4569       );
4570 
4571       if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
4572         DeleteSignatureEx (Private, Delete_Signature_List_All, IfrNvData->CheckedDataCount);
4573       }
4574 
4575       LoadSignatureList (
4576         Private,
4577         LABEL_SIGNATURE_LIST_START,
4578         SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4579         OPTION_SIGNATURE_LIST_QUESTION_ID
4580       );
4581       break;
4582 
4583       //
4584       // Delete one signature list and reload.
4585       //
4586     case KEY_SECURE_BOOT_DELETE_ALL_DATA:
4587       CreatePopUp(
4588         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4589         &Key,
4590         L"Press 'Y' to delete signature data.",
4591         L"Press other key to cancel and exit.",
4592         NULL
4593       );
4594 
4595       if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
4596         DeleteSignatureEx (Private, Delete_Signature_List_One, IfrNvData->CheckedDataCount);
4597       }
4598 
4599       LoadSignatureList (
4600         Private,
4601         LABEL_SIGNATURE_LIST_START,
4602         SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4603         OPTION_SIGNATURE_LIST_QUESTION_ID
4604       );
4605       break;
4606 
4607       //
4608       // Delete checked signature data and reload.
4609       //
4610     case KEY_SECURE_BOOT_DELETE_CHECK_DATA:
4611       CreatePopUp(
4612         EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4613         &Key,
4614         L"Press 'Y' to delete signature data.",
4615         L"Press other key to cancel and exit.",
4616         NULL
4617       );
4618 
4619       if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
4620         DeleteSignatureEx (Private, Delete_Signature_Data, IfrNvData->CheckedDataCount);
4621       }
4622 
4623       LoadSignatureList (
4624         Private,
4625         LABEL_SIGNATURE_LIST_START,
4626         SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4627         OPTION_SIGNATURE_LIST_QUESTION_ID
4628       );
4629       break;
4630 
4631     case SECUREBOOT_DELETE_SIGNATURE_FROM_DBT:
4632       UpdateDeletePage (
4633         Private,
4634         EFI_IMAGE_SECURITY_DATABASE2,
4635         &gEfiImageSecurityDatabaseGuid,
4636         LABEL_DBT_DELETE,
4637         SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
4638         OPTION_DEL_DBT_QUESTION_ID
4639         );
4640 
4641       break;
4642 
4643     case KEY_VALUE_SAVE_AND_EXIT_KEK:
4644       Status = EnrollKeyExchangeKey (Private);
4645       if (EFI_ERROR (Status)) {
4646         CreatePopUp (
4647           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4648           &Key,
4649           L"ERROR: Unsupported file type!",
4650           L"Only supports DER-encoded X509 certificate",
4651           NULL
4652           );
4653       }
4654       break;
4655 
4656     case KEY_VALUE_SAVE_AND_EXIT_DB:
4657       Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE);
4658       if (EFI_ERROR (Status)) {
4659         CreatePopUp (
4660           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4661           &Key,
4662           L"ERROR: Unsupported file type!",
4663           L"Only supports DER-encoded X509 certificate and executable EFI image",
4664           NULL
4665           );
4666       }
4667       break;
4668 
4669     case KEY_VALUE_SAVE_AND_EXIT_DBX:
4670       if (IsX509CertInDbx (Private, EFI_IMAGE_SECURITY_DATABASE1)) {
4671         CreatePopUp (
4672           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4673           &Key,
4674           L"Enrollment failed! Same certificate had already been in the dbx!",
4675           NULL
4676           );
4677 
4678         //
4679         // Cert already exists in DBX. Close opened file before exit.
4680         //
4681         CloseEnrolledFile(Private->FileContext);
4682         break;
4683       }
4684 
4685       if ((IfrNvData != NULL) && (IfrNvData->CertificateFormat < HASHALG_MAX)) {
4686         Status = EnrollX509HashtoSigDB (
4687                    Private,
4688                    IfrNvData->CertificateFormat,
4689                    &IfrNvData->RevocationDate,
4690                    &IfrNvData->RevocationTime,
4691                    IfrNvData->AlwaysRevocation
4692                    );
4693         IfrNvData->CertificateFormat = HASHALG_RAW;
4694       } else {
4695         Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE1);
4696       }
4697       if (EFI_ERROR (Status)) {
4698         CreatePopUp (
4699           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4700           &Key,
4701           L"ERROR: Unsupported file type!",
4702           L"Only supports DER-encoded X509 certificate, AUTH_2 format data & executable EFI image",
4703           NULL
4704           );
4705       }
4706       break;
4707 
4708     case KEY_VALUE_SAVE_AND_EXIT_DBT:
4709       Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE2);
4710       if (EFI_ERROR (Status)) {
4711         CreatePopUp (
4712           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4713           &Key,
4714           L"ERROR: Unsupported file type!",
4715           L"Only supports DER-encoded X509 certificate.",
4716           NULL
4717           );
4718       }
4719       break;
4720     case KEY_VALUE_SAVE_AND_EXIT_PK:
4721       Status = EnrollPlatformKey (Private);
4722       if (EFI_ERROR (Status)) {
4723         UnicodeSPrint (
4724           PromptString,
4725           sizeof (PromptString),
4726           L"Only DER encoded certificate file (%s) is supported.",
4727           mSupportX509Suffix
4728           );
4729         CreatePopUp (
4730           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4731           &Key,
4732           L"ERROR: Unsupported file type!",
4733           PromptString,
4734           NULL
4735           );
4736       }
4737       break;
4738     default:
4739       if ((QuestionId >= OPTION_DEL_KEK_QUESTION_ID) &&
4740                  (QuestionId < (OPTION_DEL_KEK_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4741         DeleteKeyExchangeKey (Private, QuestionId);
4742       } else if ((QuestionId >= OPTION_DEL_DB_QUESTION_ID) &&
4743                  (QuestionId < (OPTION_DEL_DB_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4744         DeleteSignature (
4745           Private,
4746           EFI_IMAGE_SECURITY_DATABASE,
4747           &gEfiImageSecurityDatabaseGuid,
4748           LABEL_DB_DELETE,
4749           SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
4750           OPTION_DEL_DB_QUESTION_ID,
4751           QuestionId - OPTION_DEL_DB_QUESTION_ID
4752           );
4753       } else if ((QuestionId >= OPTION_SIGNATURE_LIST_QUESTION_ID) &&
4754                  (QuestionId < (OPTION_SIGNATURE_LIST_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4755         LoadSignatureData (
4756           Private,
4757           LABEL_SIGNATURE_DATA_START,
4758           SECUREBOOT_DELETE_SIGNATURE_DATA_FORM,
4759           OPTION_SIGNATURE_DATA_QUESTION_ID,
4760           QuestionId - OPTION_SIGNATURE_LIST_QUESTION_ID
4761         );
4762         Private->ListIndex = QuestionId - OPTION_SIGNATURE_LIST_QUESTION_ID;
4763       } else if ((QuestionId >= OPTION_SIGNATURE_DATA_QUESTION_ID) &&
4764                  (QuestionId < (OPTION_SIGNATURE_DATA_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4765         if (Private->CheckArray[QuestionId - OPTION_SIGNATURE_DATA_QUESTION_ID]) {
4766           IfrNvData->CheckedDataCount--;
4767           Private->CheckArray[QuestionId - OPTION_SIGNATURE_DATA_QUESTION_ID] = FALSE;
4768         } else {
4769           IfrNvData->CheckedDataCount++;
4770           Private->CheckArray[QuestionId - OPTION_SIGNATURE_DATA_QUESTION_ID] = TRUE;
4771         }
4772       } else if ((QuestionId >= OPTION_DEL_DBT_QUESTION_ID) &&
4773                  (QuestionId < (OPTION_DEL_DBT_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4774         DeleteSignature (
4775           Private,
4776           EFI_IMAGE_SECURITY_DATABASE2,
4777           &gEfiImageSecurityDatabaseGuid,
4778           LABEL_DBT_DELETE,
4779           SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
4780           OPTION_DEL_DBT_QUESTION_ID,
4781           QuestionId - OPTION_DEL_DBT_QUESTION_ID
4782           );
4783       }
4784       break;
4785 
4786     case KEY_VALUE_NO_SAVE_AND_EXIT_PK:
4787     case KEY_VALUE_NO_SAVE_AND_EXIT_KEK:
4788     case KEY_VALUE_NO_SAVE_AND_EXIT_DB:
4789     case KEY_VALUE_NO_SAVE_AND_EXIT_DBX:
4790     case KEY_VALUE_NO_SAVE_AND_EXIT_DBT:
4791       CloseEnrolledFile(Private->FileContext);
4792 
4793       if (Private->SignatureGUID != NULL) {
4794         FreePool (Private->SignatureGUID);
4795         Private->SignatureGUID = NULL;
4796       }
4797       break;
4798     }
4799   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
4800     switch (QuestionId) {
4801     case KEY_SECURE_BOOT_ENABLE:
4802       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
4803       break;
4804     case KEY_SECURE_BOOT_MODE:
4805       mIsEnterSecureBootForm = FALSE;
4806       break;
4807     case KEY_SECURE_BOOT_KEK_GUID:
4808     case KEY_SECURE_BOOT_SIGNATURE_GUID_DB:
4809     case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX:
4810     case KEY_SECURE_BOOT_SIGNATURE_GUID_DBT:
4811       ASSERT (Private->SignatureGUID != NULL);
4812       RStatus = StrToGuid (IfrNvData->SignatureGuid, Private->SignatureGUID);
4813       if (RETURN_ERROR (RStatus) || (IfrNvData->SignatureGuid[GUID_STRING_LENGTH] != L'\0')) {
4814         Status = EFI_INVALID_PARAMETER;
4815         break;
4816       }
4817 
4818       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
4819       break;
4820     case KEY_SECURE_BOOT_DELETE_PK:
4821       GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
4822       if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {
4823         IfrNvData->DeletePk = TRUE;
4824         IfrNvData->HasPk    = FALSE;
4825         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
4826       } else  {
4827         IfrNvData->DeletePk = FALSE;
4828         IfrNvData->HasPk    = TRUE;
4829         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
4830       }
4831       if (SetupMode != NULL) {
4832         FreePool (SetupMode);
4833       }
4834       break;
4835     default:
4836       break;
4837     }
4838   } else if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
4839     if (QuestionId == KEY_HIDE_SECURE_BOOT) {
4840       GetVariable2 (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID**)&Pk, NULL);
4841       if (Pk == NULL) {
4842         IfrNvData->HideSecureBoot = TRUE;
4843       } else {
4844         FreePool (Pk);
4845         IfrNvData->HideSecureBoot = FALSE;
4846       }
4847       Value->b = IfrNvData->HideSecureBoot;
4848     }
4849   } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
4850     //
4851     // Force the platform back to Standard Mode once user leave the setup screen.
4852     //
4853     GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
4854     if (NULL != SecureBootMode && *SecureBootMode == CUSTOM_SECURE_BOOT_MODE) {
4855       IfrNvData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
4856       SetSecureBootMode(STANDARD_SECURE_BOOT_MODE);
4857     }
4858     if (SecureBootMode != NULL) {
4859       FreePool (SecureBootMode);
4860     }
4861 
4862     if (QuestionId == KEY_SECURE_BOOT_DELETE_ALL_DATA) {
4863       //
4864       // Free memory when exit from the SECUREBOOT_DELETE_SIGNATURE_DATA_FORM form.
4865       //
4866       SECUREBOOT_FREE_NON_NULL (Private->CheckArray);
4867       IfrNvData->CheckedDataCount = 0;
4868     }
4869   }
4870 
4871 EXIT:
4872 
4873   if (!EFI_ERROR (Status) && GetBrowserDataResult) {
4874     BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
4875     HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL);
4876   }
4877 
4878   FreePool (IfrNvData);
4879 
4880   if (File != NULL){
4881     FreePool(File);
4882     File = NULL;
4883   }
4884 
4885   return EFI_SUCCESS;
4886 }
4887 
4888 /**
4889   This function publish the SecureBoot configuration Form.
4890 
4891   @param[in, out]  PrivateData   Points to SecureBoot configuration private data.
4892 
4893   @retval EFI_SUCCESS            HII Form is installed successfully.
4894   @retval EFI_OUT_OF_RESOURCES   Not enough resource for HII Form installation.
4895   @retval Others                 Other errors as indicated.
4896 
4897 **/
4898 EFI_STATUS
InstallSecureBootConfigForm(IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData)4899 InstallSecureBootConfigForm (
4900   IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA  *PrivateData
4901   )
4902 {
4903   EFI_STATUS                      Status;
4904   EFI_HII_HANDLE                  HiiHandle;
4905   EFI_HANDLE                      DriverHandle;
4906   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;
4907 
4908   DriverHandle = NULL;
4909   ConfigAccess = &PrivateData->ConfigAccess;
4910   Status = gBS->InstallMultipleProtocolInterfaces (
4911                   &DriverHandle,
4912                   &gEfiDevicePathProtocolGuid,
4913                   &mSecureBootHiiVendorDevicePath,
4914                   &gEfiHiiConfigAccessProtocolGuid,
4915                   ConfigAccess,
4916                   NULL
4917                   );
4918   if (EFI_ERROR (Status)) {
4919     return Status;
4920   }
4921 
4922   PrivateData->DriverHandle = DriverHandle;
4923 
4924   //
4925   // Publish the HII package list
4926   //
4927   HiiHandle = HiiAddPackages (
4928                 &gSecureBootConfigFormSetGuid,
4929                 DriverHandle,
4930                 SecureBootConfigDxeStrings,
4931                 SecureBootConfigBin,
4932                 NULL
4933                 );
4934   if (HiiHandle == NULL) {
4935     gBS->UninstallMultipleProtocolInterfaces (
4936            DriverHandle,
4937            &gEfiDevicePathProtocolGuid,
4938            &mSecureBootHiiVendorDevicePath,
4939            &gEfiHiiConfigAccessProtocolGuid,
4940            ConfigAccess,
4941            NULL
4942            );
4943     return EFI_OUT_OF_RESOURCES;
4944   }
4945 
4946   PrivateData->HiiHandle = HiiHandle;
4947 
4948   PrivateData->FileContext = AllocateZeroPool (sizeof (SECUREBOOT_FILE_CONTEXT));
4949 
4950   if (PrivateData->FileContext == NULL) {
4951     UninstallSecureBootConfigForm (PrivateData);
4952     return EFI_OUT_OF_RESOURCES;
4953   }
4954 
4955   //
4956   // Init OpCode Handle and Allocate space for creation of Buffer
4957   //
4958   mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
4959   if (mStartOpCodeHandle == NULL) {
4960     UninstallSecureBootConfigForm (PrivateData);
4961     return EFI_OUT_OF_RESOURCES;
4962   }
4963 
4964   mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
4965   if (mEndOpCodeHandle == NULL) {
4966     UninstallSecureBootConfigForm (PrivateData);
4967     return EFI_OUT_OF_RESOURCES;
4968   }
4969 
4970   //
4971   // Create Hii Extend Label OpCode as the start opcode
4972   //
4973   mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
4974                                          mStartOpCodeHandle,
4975                                          &gEfiIfrTianoGuid,
4976                                          NULL,
4977                                          sizeof (EFI_IFR_GUID_LABEL)
4978                                          );
4979   mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
4980 
4981   //
4982   // Create Hii Extend Label OpCode as the end opcode
4983   //
4984   mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
4985                                        mEndOpCodeHandle,
4986                                        &gEfiIfrTianoGuid,
4987                                        NULL,
4988                                        sizeof (EFI_IFR_GUID_LABEL)
4989                                        );
4990   mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
4991   mEndLabel->Number       = LABEL_END;
4992 
4993   return EFI_SUCCESS;
4994 }
4995 
4996 /**
4997   This function removes SecureBoot configuration Form.
4998 
4999   @param[in, out]  PrivateData   Points to SecureBoot configuration private data.
5000 
5001 **/
5002 VOID
UninstallSecureBootConfigForm(IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA * PrivateData)5003 UninstallSecureBootConfigForm (
5004   IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA    *PrivateData
5005   )
5006 {
5007   //
5008   // Uninstall HII package list
5009   //
5010   if (PrivateData->HiiHandle != NULL) {
5011     HiiRemovePackages (PrivateData->HiiHandle);
5012     PrivateData->HiiHandle = NULL;
5013   }
5014 
5015   //
5016   // Uninstall HII Config Access Protocol
5017   //
5018   if (PrivateData->DriverHandle != NULL) {
5019     gBS->UninstallMultipleProtocolInterfaces (
5020            PrivateData->DriverHandle,
5021            &gEfiDevicePathProtocolGuid,
5022            &mSecureBootHiiVendorDevicePath,
5023            &gEfiHiiConfigAccessProtocolGuid,
5024            &PrivateData->ConfigAccess,
5025            NULL
5026            );
5027     PrivateData->DriverHandle = NULL;
5028   }
5029 
5030   if (PrivateData->SignatureGUID != NULL) {
5031     FreePool (PrivateData->SignatureGUID);
5032   }
5033 
5034   if (PrivateData->FileContext != NULL) {
5035     FreePool (PrivateData->FileContext);
5036   }
5037 
5038   FreePool (PrivateData);
5039 
5040   if (mStartOpCodeHandle != NULL) {
5041     HiiFreeOpCodeHandle (mStartOpCodeHandle);
5042   }
5043 
5044   if (mEndOpCodeHandle != NULL) {
5045     HiiFreeOpCodeHandle (mEndOpCodeHandle);
5046   }
5047 }
5048