SecurityPkg: SecureBootConfigDxe: Update CloseEnrolledFile comment
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / SecureBootConfigDxe / SecureBootConfigImpl.c
1 /** @file\r
2   HII Config Access protocol implementation of SecureBoot configuration module.\r
3 \r
4 Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "SecureBootConfigImpl.h"\r
16 \r
17 CHAR16              mSecureBootStorageName[] = L"SECUREBOOT_CONFIGURATION";\r
18 \r
19 SECUREBOOT_CONFIG_PRIVATE_DATA         mSecureBootConfigPrivateDateTemplate = {\r
20   SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE,\r
21   {\r
22     SecureBootExtractConfig,\r
23     SecureBootRouteConfig,\r
24     SecureBootCallback\r
25   }\r
26 };\r
27 \r
28 HII_VENDOR_DEVICE_PATH          mSecureBootHiiVendorDevicePath = {\r
29   {\r
30     {\r
31       HARDWARE_DEVICE_PATH,\r
32       HW_VENDOR_DP,\r
33       {\r
34         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
35         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
36       }\r
37     },\r
38     SECUREBOOT_CONFIG_FORM_SET_GUID\r
39   },\r
40   {\r
41     END_DEVICE_PATH_TYPE,\r
42     END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
43     {\r
44       (UINT8) (END_DEVICE_PATH_LENGTH),\r
45       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
46     }\r
47   }\r
48 };\r
49 \r
50 \r
51 BOOLEAN mIsEnterSecureBootForm = FALSE;\r
52 \r
53 //\r
54 // OID ASN.1 Value for Hash Algorithms\r
55 //\r
56 UINT8 mHashOidValue[] = {\r
57   0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,         // OBJ_md5\r
58   0x2B, 0x0E, 0x03, 0x02, 0x1A,                           // OBJ_sha1\r
59   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,   // OBJ_sha224\r
60   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,   // OBJ_sha256\r
61   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,   // OBJ_sha384\r
62   0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,   // OBJ_sha512\r
63   };\r
64 \r
65 HASH_TABLE mHash[] = {\r
66   { L"SHA224", 28, &mHashOidValue[13], 9, NULL,                 NULL,       NULL,         NULL       },\r
67   { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},\r
68   { L"SHA384", 48, &mHashOidValue[31], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},\r
69   { L"SHA512", 64, &mHashOidValue[40], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}\r
70 };\r
71 \r
72 //\r
73 // Variable Definitions\r
74 //\r
75 UINT32            mPeCoffHeaderOffset = 0;\r
76 WIN_CERTIFICATE   *mCertificate = NULL;\r
77 IMAGE_TYPE        mImageType;\r
78 UINT8             *mImageBase = NULL;\r
79 UINTN             mImageSize = 0;\r
80 UINT8             mImageDigest[MAX_DIGEST_SIZE];\r
81 UINTN             mImageDigestSize;\r
82 EFI_GUID          mCertType;\r
83 EFI_IMAGE_SECURITY_DATA_DIRECTORY    *mSecDataDir = NULL;\r
84 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  mNtHeader;\r
85 \r
86 //\r
87 // Possible DER-encoded certificate file suffixes, end with NULL pointer.\r
88 //\r
89 CHAR16* mDerEncodedSuffix[] = {\r
90   L".cer",\r
91   L".der",\r
92   L".crt",\r
93   NULL\r
94 };\r
95 CHAR16* mSupportX509Suffix = L"*.cer/der/crt";\r
96 \r
97 SECUREBOOT_CONFIG_PRIVATE_DATA  *gSecureBootPrivateData = NULL;\r
98 \r
99 /**\r
100   This code cleans up enrolled file by closing file & free related resources attached to\r
101   enrolled file.\r
102 \r
103   @param[in] FileContext            FileContext cached in SecureBootConfig driver\r
104 \r
105 **/\r
106 VOID\r
107 CloseEnrolledFile(\r
108   IN SECUREBOOT_FILE_CONTEXT *FileContext\r
109 )\r
110 {\r
111   if (FileContext->FHandle != NULL) {\r
112     CloseFile (FileContext->FHandle);\r
113     FileContext->FHandle = NULL;\r
114   }\r
115 \r
116   if (FileContext->FileName != NULL){\r
117     FreePool(FileContext->FileName);\r
118     FileContext->FileName = NULL;\r
119   }\r
120   FileContext->FileType = UNKNOWN_FILE_TYPE;\r
121 \r
122 }\r
123 \r
124 /**\r
125   This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.\r
126 \r
127   @param[in] FileSuffix            The suffix of the input certificate file\r
128 \r
129   @retval    TRUE           It's a DER-encoded certificate.\r
130   @retval    FALSE          It's NOT a DER-encoded certificate.\r
131 \r
132 **/\r
133 BOOLEAN\r
134 IsDerEncodeCertificate (\r
135   IN CONST CHAR16         *FileSuffix\r
136 )\r
137 {\r
138   UINTN     Index;\r
139   for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {\r
140     if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {\r
141       return TRUE;\r
142     }\r
143   }\r
144   return FALSE;\r
145 }\r
146 \r
147 /**\r
148   This code checks if the file content complies with EFI_VARIABLE_AUTHENTICATION_2 format\r
149 The function reads file content but won't open/close given FileHandle.\r
150 \r
151   @param[in] FileHandle            The FileHandle to be checked\r
152 \r
153   @retval    TRUE            The content is EFI_VARIABLE_AUTHENTICATION_2 format.\r
154   @retval    FALSE          The content is NOT a EFI_VARIABLE_AUTHENTICATION_2 format.\r
155 \r
156 **/\r
157 BOOLEAN\r
158 IsAuthentication2Format (\r
159   IN   EFI_FILE_HANDLE    FileHandle\r
160 )\r
161 {\r
162   EFI_STATUS                     Status;\r
163   EFI_VARIABLE_AUTHENTICATION_2  *Auth2;\r
164   BOOLEAN                        IsAuth2Format;\r
165 \r
166   IsAuth2Format = FALSE;\r
167 \r
168   //\r
169   // Read the whole file content\r
170   //\r
171   Status = ReadFileContent(\r
172              FileHandle,\r
173              (VOID **) &mImageBase,\r
174              &mImageSize,\r
175              0\r
176              );\r
177   if (EFI_ERROR (Status)) {\r
178     goto ON_EXIT;\r
179   }\r
180 \r
181   Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)mImageBase;\r
182   if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {\r
183     goto ON_EXIT;\r
184   }\r
185 \r
186   if (CompareGuid(&gEfiCertPkcs7Guid, &Auth2->AuthInfo.CertType)) {\r
187     IsAuth2Format = TRUE;\r
188   }\r
189 \r
190 ON_EXIT:\r
191   //\r
192   // Do not close File. simply check file content\r
193   //\r
194   if (mImageBase != NULL) {\r
195     FreePool (mImageBase);\r
196     mImageBase = NULL;\r
197   }\r
198 \r
199   return IsAuth2Format;\r
200 }\r
201 \r
202 /**\r
203   Set Secure Boot option into variable space.\r
204 \r
205   @param[in] VarValue              The option of Secure Boot.\r
206 \r
207   @retval    EFI_SUCCESS           The operation is finished successfully.\r
208   @retval    Others                Other errors as indicated.\r
209 \r
210 **/\r
211 EFI_STATUS\r
212 SaveSecureBootVariable (\r
213   IN UINT8                         VarValue\r
214   )\r
215 {\r
216   EFI_STATUS                       Status;\r
217 \r
218   Status = gRT->SetVariable (\r
219              EFI_SECURE_BOOT_ENABLE_NAME,\r
220              &gEfiSecureBootEnableDisableGuid,\r
221              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
222              sizeof (UINT8),\r
223              &VarValue\r
224              );\r
225   return Status;\r
226 }\r
227 \r
228 /**\r
229   Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2\r
230   descriptor with the input data. NO authentication is required in this function.\r
231 \r
232   @param[in, out]   DataSize       On input, the size of Data buffer in bytes.\r
233                                    On output, the size of data returned in Data\r
234                                    buffer in bytes.\r
235   @param[in, out]   Data           On input, Pointer to data buffer to be wrapped or\r
236                                    pointer to NULL to wrap an empty payload.\r
237                                    On output, Pointer to the new payload date buffer allocated from pool,\r
238                                    it's caller's responsibility to free the memory when finish using it.\r
239 \r
240   @retval EFI_SUCCESS              Create time based payload successfully.\r
241   @retval EFI_OUT_OF_RESOURCES     There are not enough memory resourses to create time based payload.\r
242   @retval EFI_INVALID_PARAMETER    The parameter is invalid.\r
243   @retval Others                   Unexpected error happens.\r
244 \r
245 **/\r
246 EFI_STATUS\r
247 CreateTimeBasedPayload (\r
248   IN OUT UINTN            *DataSize,\r
249   IN OUT UINT8            **Data\r
250   )\r
251 {\r
252   EFI_STATUS                       Status;\r
253   UINT8                            *NewData;\r
254   UINT8                            *Payload;\r
255   UINTN                            PayloadSize;\r
256   EFI_VARIABLE_AUTHENTICATION_2    *DescriptorData;\r
257   UINTN                            DescriptorSize;\r
258   EFI_TIME                         Time;\r
259 \r
260   if (Data == NULL || DataSize == NULL) {\r
261     return EFI_INVALID_PARAMETER;\r
262   }\r
263 \r
264   //\r
265   // In Setup mode or Custom mode, the variable does not need to be signed but the\r
266   // parameters to the SetVariable() call still need to be prepared as authenticated\r
267   // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate\r
268   // data in it.\r
269   //\r
270   Payload     = *Data;\r
271   PayloadSize = *DataSize;\r
272 \r
273   DescriptorSize    = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
274   NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);\r
275   if (NewData == NULL) {\r
276     return EFI_OUT_OF_RESOURCES;\r
277   }\r
278 \r
279   if ((Payload != NULL) && (PayloadSize != 0)) {\r
280     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
281   }\r
282 \r
283   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);\r
284 \r
285   ZeroMem (&Time, sizeof (EFI_TIME));\r
286   Status = gRT->GetTime (&Time, NULL);\r
287   if (EFI_ERROR (Status)) {\r
288     FreePool(NewData);\r
289     return Status;\r
290   }\r
291   Time.Pad1       = 0;\r
292   Time.Nanosecond = 0;\r
293   Time.TimeZone   = 0;\r
294   Time.Daylight   = 0;\r
295   Time.Pad2       = 0;\r
296   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));\r
297 \r
298   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
299   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;\r
300   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
301   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);\r
302 \r
303   if (Payload != NULL) {\r
304     FreePool(Payload);\r
305   }\r
306 \r
307   *DataSize = DescriptorSize + PayloadSize;\r
308   *Data     = NewData;\r
309   return EFI_SUCCESS;\r
310 }\r
311 \r
312 /**\r
313   Internal helper function to delete a Variable given its name and GUID, NO authentication\r
314   required.\r
315 \r
316   @param[in]      VariableName            Name of the Variable.\r
317   @param[in]      VendorGuid              GUID of the Variable.\r
318 \r
319   @retval EFI_SUCCESS              Variable deleted successfully.\r
320   @retval Others                   The driver failed to start the device.\r
321 \r
322 **/\r
323 EFI_STATUS\r
324 DeleteVariable (\r
325   IN  CHAR16                    *VariableName,\r
326   IN  EFI_GUID                  *VendorGuid\r
327   )\r
328 {\r
329   EFI_STATUS              Status;\r
330   VOID*                   Variable;\r
331   UINT8                   *Data;\r
332   UINTN                   DataSize;\r
333   UINT32                  Attr;\r
334 \r
335   GetVariable2 (VariableName, VendorGuid, &Variable, NULL);\r
336   if (Variable == NULL) {\r
337     return EFI_SUCCESS;\r
338   }\r
339   FreePool (Variable);\r
340 \r
341   Data     = NULL;\r
342   DataSize = 0;\r
343   Attr     = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
344              | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
345 \r
346   Status = CreateTimeBasedPayload (&DataSize, &Data);\r
347   if (EFI_ERROR (Status)) {\r
348     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
349     return Status;\r
350   }\r
351 \r
352   Status = gRT->SetVariable (\r
353                   VariableName,\r
354                   VendorGuid,\r
355                   Attr,\r
356                   DataSize,\r
357                   Data\r
358                   );\r
359   if (Data != NULL) {\r
360     FreePool (Data);\r
361   }\r
362   return Status;\r
363 }\r
364 \r
365 /**\r
366 \r
367   Set the platform secure boot mode into "Custom" or "Standard" mode.\r
368 \r
369   @param[in]   SecureBootMode        New secure boot mode: STANDARD_SECURE_BOOT_MODE or\r
370                                      CUSTOM_SECURE_BOOT_MODE.\r
371 \r
372   @return EFI_SUCCESS                The platform has switched to the special mode successfully.\r
373   @return other                      Fail to operate the secure boot mode.\r
374 \r
375 **/\r
376 EFI_STATUS\r
377 SetSecureBootMode (\r
378   IN     UINT8         SecureBootMode\r
379   )\r
380 {\r
381   return gRT->SetVariable (\r
382                 EFI_CUSTOM_MODE_NAME,\r
383                 &gEfiCustomModeEnableGuid,\r
384                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
385                 sizeof (UINT8),\r
386                 &SecureBootMode\r
387                 );\r
388 }\r
389 \r
390 /**\r
391   Generate the PK signature list from the X509 Certificate storing file (.cer)\r
392 \r
393   @param[in]   X509File              FileHandle of X509 Certificate storing file.\r
394   @param[out]  PkCert                Point to the data buffer to store the signature list.\r
395 \r
396   @return EFI_UNSUPPORTED            Unsupported Key Length.\r
397   @return EFI_OUT_OF_RESOURCES       There are not enough memory resourses to form the signature list.\r
398 \r
399 **/\r
400 EFI_STATUS\r
401 CreatePkX509SignatureList (\r
402   IN    EFI_FILE_HANDLE             X509File,\r
403   OUT   EFI_SIGNATURE_LIST          **PkCert\r
404   )\r
405 {\r
406   EFI_STATUS              Status;\r
407   UINT8                   *X509Data;\r
408   UINTN                   X509DataSize;\r
409   EFI_SIGNATURE_DATA      *PkCertData;\r
410 \r
411   X509Data = NULL;\r
412   PkCertData = NULL;\r
413   X509DataSize = 0;\r
414 \r
415   Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);\r
416   if (EFI_ERROR (Status)) {\r
417     goto ON_EXIT;\r
418   }\r
419   ASSERT (X509Data != NULL);\r
420 \r
421   //\r
422   // Allocate space for PK certificate list and initialize it.\r
423   // Create PK database entry with SignatureHeaderSize equals 0.\r
424   //\r
425   *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool (\r
426               sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1\r
427               + X509DataSize\r
428               );\r
429   if (*PkCert == NULL) {\r
430     Status = EFI_OUT_OF_RESOURCES;\r
431     goto ON_EXIT;\r
432   }\r
433 \r
434   (*PkCert)->SignatureListSize   = (UINT32) (sizeof(EFI_SIGNATURE_LIST)\r
435                                     + sizeof(EFI_SIGNATURE_DATA) - 1\r
436                                     + X509DataSize);\r
437   (*PkCert)->SignatureSize       = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);\r
438   (*PkCert)->SignatureHeaderSize = 0;\r
439   CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid);\r
440   PkCertData                     = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert)\r
441                                                           + sizeof(EFI_SIGNATURE_LIST)\r
442                                                           + (*PkCert)->SignatureHeaderSize);\r
443   CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);\r
444   //\r
445   // Fill the PK database with PKpub data from X509 certificate file.\r
446   //\r
447   CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize);\r
448 \r
449 ON_EXIT:\r
450 \r
451   if (X509Data != NULL) {\r
452     FreePool (X509Data);\r
453   }\r
454 \r
455   if (EFI_ERROR(Status) && *PkCert != NULL) {\r
456     FreePool (*PkCert);\r
457     *PkCert = NULL;\r
458   }\r
459 \r
460   return Status;\r
461 }\r
462 \r
463 /**\r
464   Enroll new PK into the System without original PK's authentication.\r
465 \r
466   The SignatureOwner GUID will be the same with PK's vendorguid.\r
467 \r
468   @param[in] PrivateData     The module's private data.\r
469 \r
470   @retval   EFI_SUCCESS            New PK enrolled successfully.\r
471   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
472   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
473 \r
474 **/\r
475 EFI_STATUS\r
476 EnrollPlatformKey (\r
477    IN  SECUREBOOT_CONFIG_PRIVATE_DATA*   Private\r
478   )\r
479 {\r
480   EFI_STATUS                      Status;\r
481   UINT32                          Attr;\r
482   UINTN                           DataSize;\r
483   EFI_SIGNATURE_LIST              *PkCert;\r
484   UINT16*                         FilePostFix;\r
485   UINTN                           NameLength;\r
486 \r
487   if (Private->FileContext->FileName == NULL) {\r
488     return EFI_INVALID_PARAMETER;\r
489   }\r
490 \r
491   PkCert = NULL;\r
492 \r
493   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
494   if (EFI_ERROR (Status)) {\r
495     return Status;\r
496   }\r
497 \r
498   //\r
499   // Parse the file's postfix. Only support DER encoded X.509 certificate files.\r
500   //\r
501   NameLength = StrLen (Private->FileContext->FileName);\r
502   if (NameLength <= 4) {\r
503     return EFI_INVALID_PARAMETER;\r
504   }\r
505   FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
506   if (!IsDerEncodeCertificate(FilePostFix)) {\r
507     DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix));\r
508     return EFI_INVALID_PARAMETER;\r
509   }\r
510   DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName));\r
511   DEBUG ((EFI_D_INFO, "FilePostFix = %s\n", FilePostFix));\r
512 \r
513   //\r
514   // Prase the selected PK file and generature PK certificate list.\r
515   //\r
516   Status = CreatePkX509SignatureList (\r
517             Private->FileContext->FHandle,\r
518             &PkCert\r
519             );\r
520   if (EFI_ERROR (Status)) {\r
521     goto ON_EXIT;\r
522   }\r
523   ASSERT (PkCert != NULL);\r
524 \r
525   //\r
526   // Set Platform Key variable.\r
527   //\r
528   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
529           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
530   DataSize = PkCert->SignatureListSize;\r
531   Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);\r
532   if (EFI_ERROR (Status)) {\r
533     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
534     goto ON_EXIT;\r
535   }\r
536 \r
537   Status = gRT->SetVariable(\r
538                   EFI_PLATFORM_KEY_NAME,\r
539                   &gEfiGlobalVariableGuid,\r
540                   Attr,\r
541                   DataSize,\r
542                   PkCert\r
543                   );\r
544   if (EFI_ERROR (Status)) {\r
545     if (Status == EFI_OUT_OF_RESOURCES) {\r
546       DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n"));\r
547     }\r
548     goto ON_EXIT;\r
549   }\r
550 \r
551 ON_EXIT:\r
552 \r
553   if (PkCert != NULL) {\r
554     FreePool(PkCert);\r
555   }\r
556 \r
557   CloseEnrolledFile(Private->FileContext);\r
558 \r
559   return Status;\r
560 }\r
561 \r
562 /**\r
563   Remove the PK variable.\r
564 \r
565   @retval EFI_SUCCESS    Delete PK successfully.\r
566   @retval Others         Could not allow to delete PK.\r
567 \r
568 **/\r
569 EFI_STATUS\r
570 DeletePlatformKey (\r
571   VOID\r
572 )\r
573 {\r
574   EFI_STATUS Status;\r
575 \r
576   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
577   if (EFI_ERROR (Status)) {\r
578     return Status;\r
579   }\r
580 \r
581   Status = DeleteVariable (\r
582              EFI_PLATFORM_KEY_NAME,\r
583              &gEfiGlobalVariableGuid\r
584              );\r
585   return Status;\r
586 }\r
587 \r
588 /**\r
589   Enroll a new KEK item from public key storing file (*.pbk).\r
590 \r
591   @param[in] PrivateData           The module's private data.\r
592 \r
593   @retval   EFI_SUCCESS            New KEK enrolled successfully.\r
594   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
595   @retval   EFI_UNSUPPORTED        Unsupported command.\r
596   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
597 \r
598 **/\r
599 EFI_STATUS\r
600 EnrollRsa2048ToKek (\r
601   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private\r
602   )\r
603 {\r
604   EFI_STATUS                      Status;\r
605   UINT32                          Attr;\r
606   UINTN                           DataSize;\r
607   EFI_SIGNATURE_LIST              *KekSigList;\r
608   UINTN                           KeyBlobSize;\r
609   UINT8                           *KeyBlob;\r
610   CPL_KEY_INFO                    *KeyInfo;\r
611   EFI_SIGNATURE_DATA              *KEKSigData;\r
612   UINTN                           KekSigListSize;\r
613   UINT8                           *KeyBuffer;\r
614   UINTN                           KeyLenInBytes;\r
615 \r
616   Attr        = 0;\r
617   DataSize    = 0;\r
618   KeyBuffer   = NULL;\r
619   KeyBlobSize = 0;\r
620   KeyBlob     = NULL;\r
621   KeyInfo     = NULL;\r
622   KEKSigData  = NULL;\r
623   KekSigList  = NULL;\r
624   KekSigListSize = 0;\r
625 \r
626   //\r
627   // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type.\r
628   // First, We have to parse out public key data from the pbk key file.\r
629   //\r
630   Status = ReadFileContent (\r
631              Private->FileContext->FHandle,\r
632              (VOID**) &KeyBlob,\r
633              &KeyBlobSize,\r
634              0\r
635              );\r
636   if (EFI_ERROR (Status)) {\r
637     goto ON_EXIT;\r
638   }\r
639   ASSERT (KeyBlob != NULL);\r
640   KeyInfo = (CPL_KEY_INFO *) KeyBlob;\r
641   if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {\r
642     DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));\r
643     Status = EFI_UNSUPPORTED;\r
644     goto ON_EXIT;\r
645   }\r
646 \r
647   //\r
648   // Convert the Public key to fix octet string format represented in RSA PKCS#1.\r
649   //\r
650   KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;\r
651   KeyBuffer = AllocateZeroPool (KeyLenInBytes);\r
652   if (KeyBuffer == NULL) {\r
653     Status = EFI_OUT_OF_RESOURCES;\r
654     goto ON_EXIT;\r
655   }\r
656   Int2OctStr (\r
657     (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)),\r
658     KeyLenInBytes / sizeof (UINTN),\r
659     KeyBuffer,\r
660     KeyLenInBytes\r
661     );\r
662   CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes);\r
663 \r
664   //\r
665   // Form an new EFI_SIGNATURE_LIST.\r
666   //\r
667   KekSigListSize = sizeof(EFI_SIGNATURE_LIST)\r
668                      + sizeof(EFI_SIGNATURE_DATA) - 1\r
669                      + WIN_CERT_UEFI_RSA2048_SIZE;\r
670 \r
671   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);\r
672   if (KekSigList == NULL) {\r
673     Status = EFI_OUT_OF_RESOURCES;\r
674     goto ON_EXIT;\r
675   }\r
676 \r
677   KekSigList->SignatureListSize   = sizeof(EFI_SIGNATURE_LIST)\r
678                                   + sizeof(EFI_SIGNATURE_DATA) - 1\r
679                                   + WIN_CERT_UEFI_RSA2048_SIZE;\r
680   KekSigList->SignatureHeaderSize = 0;\r
681   KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;\r
682   CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid);\r
683 \r
684   KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST));\r
685   CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);\r
686   CopyMem (\r
687     KEKSigData->SignatureData,\r
688     KeyBlob + sizeof(CPL_KEY_INFO),\r
689     WIN_CERT_UEFI_RSA2048_SIZE\r
690     );\r
691 \r
692   //\r
693   // Check if KEK entry has been already existed.\r
694   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
695   // new KEK to original variable.\r
696   //\r
697   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
698          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
699   Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);\r
700   if (EFI_ERROR (Status)) {\r
701     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
702     goto ON_EXIT;\r
703   }\r
704 \r
705   Status = gRT->GetVariable(\r
706                   EFI_KEY_EXCHANGE_KEY_NAME,\r
707                   &gEfiGlobalVariableGuid,\r
708                   NULL,\r
709                   &DataSize,\r
710                   NULL\r
711                   );\r
712   if (Status == EFI_BUFFER_TOO_SMALL) {\r
713     Attr |= EFI_VARIABLE_APPEND_WRITE;\r
714   } else if (Status != EFI_NOT_FOUND) {\r
715     goto ON_EXIT;\r
716   }\r
717 \r
718   //\r
719   // Done. Now we have formed the correct KEKpub database item, just set it into variable storage,\r
720   //\r
721   Status = gRT->SetVariable(\r
722                   EFI_KEY_EXCHANGE_KEY_NAME,\r
723                   &gEfiGlobalVariableGuid,\r
724                   Attr,\r
725                   KekSigListSize,\r
726                   KekSigList\r
727                   );\r
728   if (EFI_ERROR (Status)) {\r
729     goto ON_EXIT;\r
730   }\r
731 \r
732 ON_EXIT:\r
733 \r
734   CloseEnrolledFile(Private->FileContext);\r
735 \r
736   if (Private->SignatureGUID != NULL) {\r
737     FreePool (Private->SignatureGUID);\r
738     Private->SignatureGUID = NULL;\r
739   }\r
740 \r
741   if (KeyBlob != NULL) {\r
742     FreePool (KeyBlob);\r
743   }\r
744   if (KeyBuffer != NULL) {\r
745     FreePool (KeyBuffer);\r
746   }\r
747   if (KekSigList != NULL) {\r
748     FreePool (KekSigList);\r
749   }\r
750 \r
751   return Status;\r
752 }\r
753 \r
754 /**\r
755   Enroll a new KEK item from X509 certificate file.\r
756 \r
757   @param[in] PrivateData           The module's private data.\r
758 \r
759   @retval   EFI_SUCCESS            New X509 is enrolled successfully.\r
760   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
761   @retval   EFI_UNSUPPORTED        Unsupported command.\r
762   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
763 \r
764 **/\r
765 EFI_STATUS\r
766 EnrollX509ToKek (\r
767   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private\r
768   )\r
769 {\r
770   EFI_STATUS                        Status;\r
771   UINTN                             X509DataSize;\r
772   VOID                              *X509Data;\r
773   EFI_SIGNATURE_DATA                *KEKSigData;\r
774   EFI_SIGNATURE_LIST                *KekSigList;\r
775   UINTN                             DataSize;\r
776   UINTN                             KekSigListSize;\r
777   UINT32                            Attr;\r
778 \r
779   X509Data       = NULL;\r
780   X509DataSize   = 0;\r
781   KekSigList     = NULL;\r
782   KekSigListSize = 0;\r
783   DataSize       = 0;\r
784   KEKSigData     = NULL;\r
785 \r
786   Status = ReadFileContent (\r
787              Private->FileContext->FHandle,\r
788              &X509Data,\r
789              &X509DataSize,\r
790              0\r
791              );\r
792   if (EFI_ERROR (Status)) {\r
793     goto ON_EXIT;\r
794   }\r
795   ASSERT (X509Data != NULL);\r
796 \r
797   KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;\r
798   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);\r
799   if (KekSigList == NULL) {\r
800     Status = EFI_OUT_OF_RESOURCES;\r
801     goto ON_EXIT;\r
802   }\r
803 \r
804   //\r
805   // Fill Certificate Database parameters.\r
806   //\r
807   KekSigList->SignatureListSize   = (UINT32) KekSigListSize;\r
808   KekSigList->SignatureHeaderSize = 0;\r
809   KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);\r
810   CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid);\r
811 \r
812   KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST));\r
813   CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);\r
814   CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize);\r
815 \r
816   //\r
817   // Check if KEK been already existed.\r
818   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
819   // new kek to original variable\r
820   //\r
821   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
822           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
823   Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);\r
824   if (EFI_ERROR (Status)) {\r
825     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
826     goto ON_EXIT;\r
827   }\r
828 \r
829   Status = gRT->GetVariable(\r
830                   EFI_KEY_EXCHANGE_KEY_NAME,\r
831                   &gEfiGlobalVariableGuid,\r
832                   NULL,\r
833                   &DataSize,\r
834                   NULL\r
835                   );\r
836   if (Status == EFI_BUFFER_TOO_SMALL) {\r
837     Attr |= EFI_VARIABLE_APPEND_WRITE;\r
838   } else if (Status != EFI_NOT_FOUND) {\r
839     goto ON_EXIT;\r
840   }\r
841 \r
842   Status = gRT->SetVariable(\r
843                   EFI_KEY_EXCHANGE_KEY_NAME,\r
844                   &gEfiGlobalVariableGuid,\r
845                   Attr,\r
846                   KekSigListSize,\r
847                   KekSigList\r
848                   );\r
849   if (EFI_ERROR (Status)) {\r
850     goto ON_EXIT;\r
851   }\r
852 \r
853 ON_EXIT:\r
854 \r
855   CloseEnrolledFile(Private->FileContext);\r
856 \r
857   if (Private->SignatureGUID != NULL) {\r
858     FreePool (Private->SignatureGUID);\r
859     Private->SignatureGUID = NULL;\r
860   }\r
861 \r
862   if (KekSigList != NULL) {\r
863     FreePool (KekSigList);\r
864   }\r
865 \r
866   return Status;\r
867 }\r
868 \r
869 /**\r
870   Enroll new KEK into the System without PK's authentication.\r
871   The SignatureOwner GUID will be Private->SignatureGUID.\r
872 \r
873   @param[in] PrivateData     The module's private data.\r
874 \r
875   @retval   EFI_SUCCESS            New KEK enrolled successful.\r
876   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
877   @retval   others                 Fail to enroll KEK data.\r
878 \r
879 **/\r
880 EFI_STATUS\r
881 EnrollKeyExchangeKey (\r
882   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private\r
883   )\r
884 {\r
885   UINT16*     FilePostFix;\r
886   EFI_STATUS  Status;\r
887   UINTN       NameLength;\r
888 \r
889   if ((Private->FileContext->FHandle == NULL) || (Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {\r
890     return EFI_INVALID_PARAMETER;\r
891   }\r
892 \r
893   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
894   if (EFI_ERROR (Status)) {\r
895     return Status;\r
896   }\r
897 \r
898   //\r
899   // Parse the file's postfix. Supports DER-encoded X509 certificate,\r
900   // and .pbk as RSA public key file.\r
901   //\r
902   NameLength = StrLen (Private->FileContext->FileName);\r
903   if (NameLength <= 4) {\r
904     return EFI_INVALID_PARAMETER;\r
905   }\r
906   FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
907   if (IsDerEncodeCertificate(FilePostFix)) {\r
908     return EnrollX509ToKek (Private);\r
909   } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {\r
910     return EnrollRsa2048ToKek (Private);\r
911   } else {\r
912     //\r
913     // File type is wrong, simply close it\r
914     //\r
915     CloseEnrolledFile(Private->FileContext);\r
916 \r
917     return EFI_INVALID_PARAMETER;\r
918   }\r
919 }\r
920 \r
921 /**\r
922   Enroll a new X509 certificate into Signature Database (DB or DBX or DBT) without\r
923   KEK's authentication.\r
924 \r
925   @param[in] PrivateData     The module's private data.\r
926   @param[in] VariableName    Variable name of signature database, must be\r
927                              EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.\r
928 \r
929   @retval   EFI_SUCCESS            New X509 is enrolled successfully.\r
930   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
931 \r
932 **/\r
933 EFI_STATUS\r
934 EnrollX509toSigDB (\r
935   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
936   IN CHAR16                         *VariableName\r
937   )\r
938 {\r
939   EFI_STATUS                        Status;\r
940   UINTN                             X509DataSize;\r
941   VOID                              *X509Data;\r
942   EFI_SIGNATURE_LIST                *SigDBCert;\r
943   EFI_SIGNATURE_DATA                *SigDBCertData;\r
944   VOID                              *Data;\r
945   UINTN                             DataSize;\r
946   UINTN                             SigDBSize;\r
947   UINT32                            Attr;\r
948 \r
949   X509DataSize  = 0;\r
950   SigDBSize     = 0;\r
951   DataSize      = 0;\r
952   X509Data      = NULL;\r
953   SigDBCert     = NULL;\r
954   SigDBCertData = NULL;\r
955   Data          = NULL;\r
956 \r
957   Status = ReadFileContent (\r
958              Private->FileContext->FHandle,\r
959              &X509Data,\r
960              &X509DataSize,\r
961              0\r
962              );\r
963   if (EFI_ERROR (Status)) {\r
964     goto ON_EXIT;\r
965   }\r
966   ASSERT (X509Data != NULL);\r
967 \r
968   SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;\r
969 \r
970   Data = AllocateZeroPool (SigDBSize);\r
971   if (Data == NULL) {\r
972     Status = EFI_OUT_OF_RESOURCES;\r
973     goto ON_EXIT;\r
974   }\r
975 \r
976   //\r
977   // Fill Certificate Database parameters.\r
978   //\r
979   SigDBCert = (EFI_SIGNATURE_LIST*) Data;\r
980   SigDBCert->SignatureListSize   = (UINT32) SigDBSize;\r
981   SigDBCert->SignatureHeaderSize = 0;\r
982   SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);\r
983   CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid);\r
984 \r
985   SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST));\r
986   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);\r
987   CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize);\r
988 \r
989   //\r
990   // Check if signature database entry has been already existed.\r
991   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
992   // new signature data to original variable\r
993   //\r
994   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
995           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
996   Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
997   if (EFI_ERROR (Status)) {\r
998     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
999     goto ON_EXIT;\r
1000   }\r
1001 \r
1002   Status = gRT->GetVariable(\r
1003                   VariableName,\r
1004                   &gEfiImageSecurityDatabaseGuid,\r
1005                   NULL,\r
1006                   &DataSize,\r
1007                   NULL\r
1008                   );\r
1009   if (Status == EFI_BUFFER_TOO_SMALL) {\r
1010     Attr |= EFI_VARIABLE_APPEND_WRITE;\r
1011   } else if (Status != EFI_NOT_FOUND) {\r
1012     goto ON_EXIT;\r
1013   }\r
1014 \r
1015   Status = gRT->SetVariable(\r
1016                   VariableName,\r
1017                   &gEfiImageSecurityDatabaseGuid,\r
1018                   Attr,\r
1019                   SigDBSize,\r
1020                   Data\r
1021                   );\r
1022   if (EFI_ERROR (Status)) {\r
1023     goto ON_EXIT;\r
1024   }\r
1025 \r
1026 ON_EXIT:\r
1027 \r
1028   CloseEnrolledFile(Private->FileContext);\r
1029 \r
1030   if (Private->SignatureGUID != NULL) {\r
1031     FreePool (Private->SignatureGUID);\r
1032     Private->SignatureGUID = NULL;\r
1033   }\r
1034 \r
1035   if (Data != NULL) {\r
1036     FreePool (Data);\r
1037   }\r
1038 \r
1039   if (X509Data != NULL) {\r
1040     FreePool (X509Data);\r
1041   }\r
1042 \r
1043   return Status;\r
1044 }\r
1045 \r
1046 /**\r
1047   Check whether signature is in specified database.\r
1048 \r
1049   @param[in]  VariableName        Name of database variable that is searched in.\r
1050   @param[in]  Signature           Pointer to signature that is searched for.\r
1051   @param[in]  SignatureSize       Size of Signature.\r
1052 \r
1053   @return TRUE                    Found the signature in the variable database.\r
1054   @return FALSE                   Not found the signature in the variable database.\r
1055 \r
1056 **/\r
1057 BOOLEAN\r
1058 IsSignatureFoundInDatabase (\r
1059   IN CHAR16             *VariableName,\r
1060   IN UINT8              *Signature,\r
1061   IN UINTN              SignatureSize\r
1062   )\r
1063 {\r
1064   EFI_STATUS          Status;\r
1065   EFI_SIGNATURE_LIST  *CertList;\r
1066   EFI_SIGNATURE_DATA  *Cert;\r
1067   UINTN               DataSize;\r
1068   UINT8               *Data;\r
1069   UINTN               Index;\r
1070   UINTN               CertCount;\r
1071   BOOLEAN             IsFound;\r
1072 \r
1073   //\r
1074   // Read signature database variable.\r
1075   //\r
1076   IsFound   = FALSE;\r
1077   Data      = NULL;\r
1078   DataSize  = 0;\r
1079   Status    = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
1080   if (Status != EFI_BUFFER_TOO_SMALL) {\r
1081     return FALSE;\r
1082   }\r
1083 \r
1084   Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1085   if (Data == NULL) {\r
1086     return FALSE;\r
1087   }\r
1088 \r
1089   Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
1090   if (EFI_ERROR (Status)) {\r
1091     goto Done;\r
1092   }\r
1093 \r
1094   //\r
1095   // Enumerate all signature data in SigDB to check if executable's signature exists.\r
1096   //\r
1097   CertList = (EFI_SIGNATURE_LIST *) Data;\r
1098   while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
1099     CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1100     Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1101     if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &gEfiCertX509Guid))) {\r
1102       for (Index = 0; Index < CertCount; Index++) {\r
1103         if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r
1104           //\r
1105           // Find the signature in database.\r
1106           //\r
1107           IsFound = TRUE;\r
1108           break;\r
1109         }\r
1110         Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1111       }\r
1112 \r
1113       if (IsFound) {\r
1114         break;\r
1115       }\r
1116     }\r
1117 \r
1118     DataSize -= CertList->SignatureListSize;\r
1119     CertList  = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1120   }\r
1121 \r
1122 Done:\r
1123   if (Data != NULL) {\r
1124     FreePool (Data);\r
1125   }\r
1126 \r
1127   return IsFound;\r
1128 }\r
1129 \r
1130 /**\r
1131   Calculate the hash of a certificate data with the specified hash algorithm.\r
1132 \r
1133   @param[in]    CertData  The certificate data to be hashed.\r
1134   @param[in]    CertSize  The certificate size in bytes.\r
1135   @param[in]    HashAlg   The specified hash algorithm.\r
1136   @param[out]   CertHash  The output digest of the certificate\r
1137 \r
1138   @retval TRUE            Successfully got the hash of the CertData.\r
1139   @retval FALSE           Failed to get the hash of CertData.\r
1140 \r
1141 **/\r
1142 BOOLEAN\r
1143 CalculateCertHash (\r
1144   IN  UINT8                 *CertData,\r
1145   IN  UINTN                 CertSize,\r
1146   IN  UINT32                HashAlg,\r
1147   OUT UINT8                 *CertHash\r
1148   )\r
1149 {\r
1150   BOOLEAN                   Status;\r
1151   VOID                      *HashCtx;\r
1152   UINTN                     CtxSize;\r
1153   UINT8                     *TBSCert;\r
1154   UINTN                     TBSCertSize;\r
1155 \r
1156   HashCtx = NULL;\r
1157   Status  = FALSE;\r
1158 \r
1159   if (HashAlg >= HASHALG_MAX) {\r
1160     return FALSE;\r
1161   }\r
1162 \r
1163   //\r
1164   // Retrieve the TBSCertificate for Hash Calculation.\r
1165   //\r
1166   if (!X509GetTBSCert (CertData, CertSize, &TBSCert, &TBSCertSize)) {\r
1167     return FALSE;\r
1168   }\r
1169 \r
1170   //\r
1171   // 1. Initialize context of hash.\r
1172   //\r
1173   CtxSize = mHash[HashAlg].GetContextSize ();\r
1174   HashCtx = AllocatePool (CtxSize);\r
1175   ASSERT (HashCtx != NULL);\r
1176 \r
1177   //\r
1178   // 2. Initialize a hash context.\r
1179   //\r
1180   Status = mHash[HashAlg].HashInit (HashCtx);\r
1181   if (!Status) {\r
1182     goto Done;\r
1183   }\r
1184 \r
1185   //\r
1186   // 3. Calculate the hash.\r
1187   //\r
1188   Status  = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);\r
1189   if (!Status) {\r
1190     goto Done;\r
1191   }\r
1192 \r
1193   //\r
1194   // 4. Get the hash result.\r
1195   //\r
1196   ZeroMem (CertHash, mHash[HashAlg].DigestLength);\r
1197   Status  = mHash[HashAlg].HashFinal (HashCtx, CertHash);\r
1198 \r
1199 Done:\r
1200   if (HashCtx != NULL) {\r
1201     FreePool (HashCtx);\r
1202   }\r
1203 \r
1204   return Status;\r
1205 }\r
1206 \r
1207 /**\r
1208   Check whether the hash of an X.509 certificate is in forbidden database (DBX).\r
1209 \r
1210   @param[in]  Certificate       Pointer to X.509 Certificate that is searched for.\r
1211   @param[in]  CertSize          Size of X.509 Certificate.\r
1212 \r
1213   @return TRUE               Found the certificate hash in the forbidden database.\r
1214   @return FALSE              Certificate hash is Not found in the forbidden database.\r
1215 \r
1216 **/\r
1217 BOOLEAN\r
1218 IsCertHashFoundInDbx (\r
1219   IN  UINT8               *Certificate,\r
1220   IN  UINTN               CertSize\r
1221   )\r
1222 {\r
1223   BOOLEAN                 IsFound;\r
1224   EFI_STATUS              Status;\r
1225   EFI_SIGNATURE_LIST      *DbxList;\r
1226   EFI_SIGNATURE_DATA      *CertHash;\r
1227   UINTN                   CertHashCount;\r
1228   UINTN                   Index;\r
1229   UINT32                  HashAlg;\r
1230   UINT8                   CertDigest[MAX_DIGEST_SIZE];\r
1231   UINT8                   *DbxCertHash;\r
1232   UINTN                   SiglistHeaderSize;\r
1233   UINT8                   *Data;\r
1234   UINTN                   DataSize;\r
1235 \r
1236   IsFound  = FALSE;\r
1237   HashAlg  = HASHALG_MAX;\r
1238   Data     = NULL;\r
1239 \r
1240   //\r
1241   // Read signature database variable.\r
1242   //\r
1243   DataSize  = 0;\r
1244   Status    = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
1245   if (Status != EFI_BUFFER_TOO_SMALL) {\r
1246     return FALSE;\r
1247   }\r
1248 \r
1249   Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1250   if (Data == NULL) {\r
1251     return FALSE;\r
1252   }\r
1253 \r
1254   Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
1255   if (EFI_ERROR (Status)) {\r
1256     goto Done;\r
1257   }\r
1258 \r
1259   //\r
1260   // Check whether the certificate hash exists in the forbidden database.\r
1261   //\r
1262   DbxList = (EFI_SIGNATURE_LIST *) Data;\r
1263   while ((DataSize > 0) && (DataSize >= DbxList->SignatureListSize)) {\r
1264     //\r
1265     // Determine Hash Algorithm of Certificate in the forbidden database.\r
1266     //\r
1267     if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
1268       HashAlg = HASHALG_SHA256;\r
1269     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
1270       HashAlg = HASHALG_SHA384;\r
1271     } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
1272       HashAlg = HASHALG_SHA512;\r
1273     } else {\r
1274       DataSize -= DbxList->SignatureListSize;\r
1275       DbxList   = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
1276       continue;\r
1277     }\r
1278 \r
1279     //\r
1280     // Calculate the hash value of current db certificate for comparision.\r
1281     //\r
1282     if (!CalculateCertHash (Certificate, CertSize, HashAlg, CertDigest)) {\r
1283       goto Done;\r
1284     }\r
1285 \r
1286     SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;\r
1287     CertHash          = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);\r
1288     CertHashCount     = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;\r
1289     for (Index = 0; Index < CertHashCount; Index++) {\r
1290       //\r
1291       // Iterate each Signature Data Node within this CertList for verify.\r
1292       //\r
1293       DbxCertHash = CertHash->SignatureData;\r
1294       if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {\r
1295         //\r
1296         // Hash of Certificate is found in forbidden database.\r
1297         //\r
1298         IsFound = TRUE;\r
1299         goto Done;\r
1300       }\r
1301       CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);\r
1302     }\r
1303 \r
1304     DataSize -= DbxList->SignatureListSize;\r
1305     DbxList   = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
1306   }\r
1307 \r
1308 Done:\r
1309   if (Data != NULL) {\r
1310     FreePool (Data);\r
1311   }\r
1312 \r
1313   return IsFound;\r
1314 }\r
1315 \r
1316 /**\r
1317   Check whether the signature list exists in given variable data.\r
1318 \r
1319   It searches the signature list for the ceritificate hash by CertType.\r
1320   If the signature list is found, get the offset of Database for the\r
1321   next hash of a certificate.\r
1322 \r
1323   @param[in]  Database      Variable data to save signature list.\r
1324   @param[in]  DatabaseSize  Variable size.\r
1325   @param[in]  SignatureType The type of the signature.\r
1326   @param[out] Offset        The offset to save a new hash of certificate.\r
1327 \r
1328   @return TRUE       The signature list is found in the forbidden database.\r
1329   @return FALSE      The signature list is not found in the forbidden database.\r
1330 **/\r
1331 BOOLEAN\r
1332 GetSignaturelistOffset (\r
1333   IN  EFI_SIGNATURE_LIST  *Database,\r
1334   IN  UINTN               DatabaseSize,\r
1335   IN  EFI_GUID            *SignatureType,\r
1336   OUT UINTN               *Offset\r
1337   )\r
1338 {\r
1339   EFI_SIGNATURE_LIST      *SigList;\r
1340   UINTN                   SiglistSize;\r
1341 \r
1342   if ((Database == NULL) || (DatabaseSize == 0)) {\r
1343     *Offset = 0;\r
1344     return FALSE;\r
1345   }\r
1346 \r
1347   SigList     = Database;\r
1348   SiglistSize = DatabaseSize;\r
1349   while ((SiglistSize > 0) && (SiglistSize >= SigList->SignatureListSize)) {\r
1350     if (CompareGuid (&SigList->SignatureType, SignatureType)) {\r
1351       *Offset = DatabaseSize - SiglistSize;\r
1352       return TRUE;\r
1353     }\r
1354     SiglistSize -= SigList->SignatureListSize;\r
1355     SigList      = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
1356   }\r
1357   *Offset = 0;\r
1358   return FALSE;\r
1359 }\r
1360 \r
1361 /**\r
1362   Enroll a new X509 certificate hash into Signature Database (dbx) without\r
1363   KEK's authentication.\r
1364 \r
1365   @param[in] PrivateData      The module's private data.\r
1366   @param[in] HashAlg          The hash algorithm to enroll the certificate.\r
1367   @param[in] RevocationDate   The revocation date of the certificate.\r
1368   @param[in] RevocationTime   The revocation time of the certificate.\r
1369   @param[in] AlwaysRevocation Indicate whether the certificate is always revoked.\r
1370 \r
1371   @retval   EFI_SUCCESS            New X509 is enrolled successfully.\r
1372   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
1373   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
1374 \r
1375 **/\r
1376 EFI_STATUS\r
1377 EnrollX509HashtoSigDB (\r
1378   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
1379   IN UINT32                         HashAlg,\r
1380   IN EFI_HII_DATE                   *RevocationDate,\r
1381   IN EFI_HII_TIME                   *RevocationTime,\r
1382   IN BOOLEAN                        AlwaysRevocation\r
1383   )\r
1384 {\r
1385   EFI_STATUS          Status;\r
1386   UINTN               X509DataSize;\r
1387   VOID                *X509Data;\r
1388   EFI_SIGNATURE_LIST  *SignatureList;\r
1389   UINTN               SignatureListSize;\r
1390   UINT8               *Data;\r
1391   UINT8               *NewData;\r
1392   UINTN               DataSize;\r
1393   UINTN               DbSize;\r
1394   UINT32              Attr;\r
1395   EFI_SIGNATURE_DATA  *SignatureData;\r
1396   UINTN               SignatureSize;\r
1397   EFI_GUID            SignatureType;\r
1398   UINTN               Offset;\r
1399   UINT8               CertHash[MAX_DIGEST_SIZE];\r
1400   UINT16*             FilePostFix;\r
1401   UINTN               NameLength;\r
1402   EFI_TIME            *Time;\r
1403 \r
1404   X509DataSize  = 0;\r
1405   DbSize        = 0;\r
1406   X509Data      = NULL;\r
1407   SignatureData = NULL;\r
1408   SignatureList = NULL;\r
1409   Data          = NULL;\r
1410   NewData       = NULL;\r
1411 \r
1412   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {\r
1413     return EFI_INVALID_PARAMETER;\r
1414   }\r
1415 \r
1416   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
1417   if (EFI_ERROR (Status)) {\r
1418     return Status;\r
1419   }\r
1420 \r
1421   //\r
1422   // Parse the file's postfix.\r
1423   //\r
1424   NameLength = StrLen (Private->FileContext->FileName);\r
1425   if (NameLength <= 4) {\r
1426     return EFI_INVALID_PARAMETER;\r
1427   }\r
1428   FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
1429   if (!IsDerEncodeCertificate(FilePostFix)) {\r
1430     //\r
1431     // Only supports DER-encoded X509 certificate.\r
1432     //\r
1433     return EFI_INVALID_PARAMETER;\r
1434   }\r
1435 \r
1436   //\r
1437   // Get the certificate from file and calculate its hash.\r
1438   //\r
1439   Status = ReadFileContent (\r
1440              Private->FileContext->FHandle,\r
1441              &X509Data,\r
1442              &X509DataSize,\r
1443              0\r
1444              );\r
1445   if (EFI_ERROR (Status)) {\r
1446     goto ON_EXIT;\r
1447   }\r
1448   ASSERT (X509Data != NULL);\r
1449 \r
1450   if (!CalculateCertHash (X509Data, X509DataSize, HashAlg, CertHash)) {\r
1451     goto ON_EXIT;\r
1452   }\r
1453 \r
1454   //\r
1455   // Get the variable for enrollment.\r
1456   //\r
1457   DataSize = 0;\r
1458   Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
1459   if (Status == EFI_BUFFER_TOO_SMALL) {\r
1460     Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1461     if (Data == NULL) {\r
1462       return EFI_OUT_OF_RESOURCES;\r
1463     }\r
1464 \r
1465     Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
1466     if (EFI_ERROR (Status)) {\r
1467       goto ON_EXIT;\r
1468     }\r
1469   }\r
1470 \r
1471   //\r
1472   // Allocate memory for Signature and fill the Signature\r
1473   //\r
1474   SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + sizeof (EFI_TIME) + mHash[HashAlg].DigestLength;\r
1475   SignatureData = (EFI_SIGNATURE_DATA *) AllocateZeroPool (SignatureSize);\r
1476   if (SignatureData == NULL) {\r
1477     return EFI_OUT_OF_RESOURCES;\r
1478   }\r
1479   CopyGuid (&SignatureData->SignatureOwner, Private->SignatureGUID);\r
1480   CopyMem (SignatureData->SignatureData, CertHash, mHash[HashAlg].DigestLength);\r
1481 \r
1482   //\r
1483   // Fill the time.\r
1484   //\r
1485   if (!AlwaysRevocation) {\r
1486     Time = (EFI_TIME *)(&SignatureData->SignatureData + mHash[HashAlg].DigestLength);\r
1487     Time->Year   = RevocationDate->Year;\r
1488     Time->Month  = RevocationDate->Month;\r
1489     Time->Day    = RevocationDate->Day;\r
1490     Time->Hour   = RevocationTime->Hour;\r
1491     Time->Minute = RevocationTime->Minute;\r
1492     Time->Second = RevocationTime->Second;\r
1493   }\r
1494 \r
1495   //\r
1496   // Determine the GUID for certificate hash.\r
1497   //\r
1498   switch (HashAlg) {\r
1499   case HASHALG_SHA256:\r
1500     SignatureType = gEfiCertX509Sha256Guid;\r
1501     break;\r
1502   case HASHALG_SHA384:\r
1503     SignatureType = gEfiCertX509Sha384Guid;\r
1504     break;\r
1505   case HASHALG_SHA512:\r
1506     SignatureType = gEfiCertX509Sha512Guid;\r
1507     break;\r
1508   default:\r
1509     return FALSE;\r
1510   }\r
1511 \r
1512   //\r
1513   // Add signature into the new variable data buffer\r
1514   //\r
1515   if (GetSignaturelistOffset((EFI_SIGNATURE_LIST *)Data, DataSize, &SignatureType, &Offset)) {\r
1516     //\r
1517     // Add the signature to the found signaturelist.\r
1518     //\r
1519     DbSize  = DataSize + SignatureSize;\r
1520     NewData = AllocateZeroPool (DbSize);\r
1521     if (NewData == NULL) {\r
1522       Status = EFI_OUT_OF_RESOURCES;\r
1523       goto ON_EXIT;\r
1524     }\r
1525 \r
1526     SignatureList     = (EFI_SIGNATURE_LIST *)(Data + Offset);\r
1527     SignatureListSize = (UINTN) ReadUnaligned32 ((UINT32 *)&SignatureList->SignatureListSize);\r
1528     CopyMem (NewData, Data, Offset + SignatureListSize);\r
1529 \r
1530     SignatureList = (EFI_SIGNATURE_LIST *)(NewData + Offset);\r
1531     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32)(SignatureListSize + SignatureSize));\r
1532 \r
1533     Offset += SignatureListSize;\r
1534     CopyMem (NewData + Offset, SignatureData, SignatureSize);\r
1535     CopyMem (NewData + Offset + SignatureSize, Data + Offset, DataSize - Offset);\r
1536 \r
1537     FreePool (Data);\r
1538     Data     = NewData;\r
1539     DataSize = DbSize;\r
1540   } else {\r
1541     //\r
1542     // Create a new signaturelist, and add the signature into the signaturelist.\r
1543     //\r
1544     DbSize  = DataSize + sizeof(EFI_SIGNATURE_LIST) + SignatureSize;\r
1545     NewData = AllocateZeroPool (DbSize);\r
1546     if (NewData == NULL) {\r
1547       Status = EFI_OUT_OF_RESOURCES;\r
1548       goto ON_EXIT;\r
1549     }\r
1550     //\r
1551     // Fill Certificate Database parameters.\r
1552     //\r
1553     SignatureList     = (EFI_SIGNATURE_LIST*) (NewData + DataSize);\r
1554     SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + SignatureSize;\r
1555     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32) SignatureListSize);\r
1556     WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureSize, (UINT32) SignatureSize);\r
1557     CopyGuid (&SignatureList->SignatureType, &SignatureType);\r
1558     CopyMem ((UINT8* ) SignatureList + sizeof (EFI_SIGNATURE_LIST), SignatureData, SignatureSize);\r
1559     if ((DataSize != 0) && (Data != NULL)) {\r
1560       CopyMem (NewData, Data, DataSize);\r
1561       FreePool (Data);\r
1562     }\r
1563     Data     = NewData;\r
1564     DataSize = DbSize;\r
1565   }\r
1566 \r
1567   Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &Data);\r
1568   if (EFI_ERROR (Status)) {\r
1569     goto ON_EXIT;\r
1570   }\r
1571 \r
1572   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
1573           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
1574   Status = gRT->SetVariable(\r
1575                   EFI_IMAGE_SECURITY_DATABASE1,\r
1576                   &gEfiImageSecurityDatabaseGuid,\r
1577                   Attr,\r
1578                   DataSize,\r
1579                   Data\r
1580                   );\r
1581   if (EFI_ERROR (Status)) {\r
1582     goto ON_EXIT;\r
1583   }\r
1584 \r
1585 ON_EXIT:\r
1586 \r
1587   CloseEnrolledFile(Private->FileContext);\r
1588 \r
1589   if (Private->SignatureGUID != NULL) {\r
1590     FreePool (Private->SignatureGUID);\r
1591     Private->SignatureGUID = NULL;\r
1592   }\r
1593 \r
1594   if (Data != NULL) {\r
1595     FreePool (Data);\r
1596   }\r
1597 \r
1598   if (SignatureData != NULL) {\r
1599     FreePool (SignatureData);\r
1600   }\r
1601 \r
1602   if (X509Data != NULL) {\r
1603     FreePool (X509Data);\r
1604   }\r
1605 \r
1606   return Status;\r
1607 }\r
1608 \r
1609 /**\r
1610   Check whether a certificate from a file exists in dbx.\r
1611 \r
1612   @param[in] PrivateData     The module's private data.\r
1613   @param[in] VariableName    Variable name of signature database, must be\r
1614                              EFI_IMAGE_SECURITY_DATABASE1.\r
1615 \r
1616   @retval   TRUE             The X509 certificate is found in dbx successfully.\r
1617   @retval   FALSE            The X509 certificate is not found in dbx.\r
1618 **/\r
1619 BOOLEAN\r
1620 IsX509CertInDbx (\r
1621   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
1622   IN CHAR16                         *VariableName\r
1623   )\r
1624 {\r
1625   EFI_STATUS          Status;\r
1626   UINTN               X509DataSize;\r
1627   VOID                *X509Data;\r
1628   BOOLEAN             IsFound;\r
1629 \r
1630   //\r
1631   //  Read the certificate from file\r
1632   //\r
1633   X509DataSize  = 0;\r
1634   X509Data      = NULL;\r
1635   Status = ReadFileContent (\r
1636              Private->FileContext->FHandle,\r
1637              &X509Data,\r
1638              &X509DataSize,\r
1639              0\r
1640              );\r
1641   if (EFI_ERROR (Status)) {\r
1642     return FALSE;\r
1643   }\r
1644 \r
1645   //\r
1646   // Check the raw certificate.\r
1647   //\r
1648   IsFound = FALSE;\r
1649   if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, X509Data, X509DataSize)) {\r
1650     IsFound = TRUE;\r
1651     goto ON_EXIT;\r
1652   }\r
1653 \r
1654   //\r
1655   // Check the hash of certificate.\r
1656   //\r
1657   if (IsCertHashFoundInDbx (X509Data, X509DataSize)) {\r
1658     IsFound = TRUE;\r
1659     goto ON_EXIT;\r
1660   }\r
1661 \r
1662 ON_EXIT:\r
1663   if (X509Data != NULL) {\r
1664     FreePool (X509Data);\r
1665   }\r
1666 \r
1667   return IsFound;\r
1668 }\r
1669 \r
1670 /**\r
1671   Reads contents of a PE/COFF image in memory buffer.\r
1672 \r
1673   Caution: This function may receive untrusted input.\r
1674   PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
1675   read is within the image buffer.\r
1676 \r
1677   @param  FileHandle      Pointer to the file handle to read the PE/COFF image.\r
1678   @param  FileOffset      Offset into the PE/COFF image to begin the read operation.\r
1679   @param  ReadSize        On input, the size in bytes of the requested read operation.\r
1680                           On output, the number of bytes actually read.\r
1681   @param  Buffer          Output buffer that contains the data read from the PE/COFF image.\r
1682 \r
1683   @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size\r
1684 **/\r
1685 EFI_STATUS\r
1686 EFIAPI\r
1687 SecureBootConfigImageRead (\r
1688   IN     VOID    *FileHandle,\r
1689   IN     UINTN   FileOffset,\r
1690   IN OUT UINTN   *ReadSize,\r
1691   OUT    VOID    *Buffer\r
1692   )\r
1693 {\r
1694   UINTN               EndPosition;\r
1695 \r
1696   if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
1697     return EFI_INVALID_PARAMETER;\r
1698   }\r
1699 \r
1700   if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
1701     return EFI_INVALID_PARAMETER;\r
1702   }\r
1703 \r
1704   EndPosition = FileOffset + *ReadSize;\r
1705   if (EndPosition > mImageSize) {\r
1706     *ReadSize = (UINT32)(mImageSize - FileOffset);\r
1707   }\r
1708 \r
1709   if (FileOffset >= mImageSize) {\r
1710     *ReadSize = 0;\r
1711   }\r
1712 \r
1713   CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
1714 \r
1715   return EFI_SUCCESS;\r
1716 }\r
1717 \r
1718 /**\r
1719   Load PE/COFF image information into internal buffer and check its validity.\r
1720 \r
1721   @retval   EFI_SUCCESS         Successful\r
1722   @retval   EFI_UNSUPPORTED     Invalid PE/COFF file\r
1723   @retval   EFI_ABORTED         Serious error occurs, like file I/O error etc.\r
1724 \r
1725 **/\r
1726 EFI_STATUS\r
1727 LoadPeImage (\r
1728   VOID\r
1729   )\r
1730 {\r
1731   EFI_IMAGE_DOS_HEADER                  *DosHdr;\r
1732   EFI_IMAGE_NT_HEADERS32                *NtHeader32;\r
1733   EFI_IMAGE_NT_HEADERS64                *NtHeader64;\r
1734   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
1735   EFI_STATUS                            Status;\r
1736 \r
1737   NtHeader32 = NULL;\r
1738   NtHeader64 = NULL;\r
1739 \r
1740   ZeroMem (&ImageContext, sizeof (ImageContext));\r
1741   ImageContext.Handle    = (VOID *) mImageBase;\r
1742   ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecureBootConfigImageRead;\r
1743 \r
1744   //\r
1745   // Get information about the image being loaded\r
1746   //\r
1747   Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
1748   if (EFI_ERROR (Status)) {\r
1749     //\r
1750     // The information can't be got from the invalid PeImage\r
1751     //\r
1752     DEBUG ((DEBUG_INFO, "SecureBootConfigDxe: PeImage invalid. \n"));\r
1753     return Status;\r
1754   }\r
1755 \r
1756   //\r
1757   // Read the Dos header\r
1758   //\r
1759   DosHdr = (EFI_IMAGE_DOS_HEADER*)(mImageBase);\r
1760   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)\r
1761   {\r
1762     //\r
1763     // DOS image header is present,\r
1764     // So read the PE header after the DOS image header\r
1765     //\r
1766     mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
1767   }\r
1768   else\r
1769   {\r
1770     mPeCoffHeaderOffset = 0;\r
1771   }\r
1772 \r
1773   //\r
1774   // Read PE header and check the signature validity and machine compatibility\r
1775   //\r
1776   NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset);\r
1777   if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE)\r
1778   {\r
1779     return EFI_UNSUPPORTED;\r
1780   }\r
1781 \r
1782   mNtHeader.Pe32 = NtHeader32;\r
1783 \r
1784   //\r
1785   // Check the architecture field of PE header and get the Certificate Data Directory data\r
1786   // Note the size of FileHeader field is constant for both IA32 and X64 arch\r
1787   //\r
1788   if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32)\r
1789       || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)\r
1790       || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {\r
1791     //\r
1792     // 32-bits Architecture\r
1793     //\r
1794     mImageType = ImageType_IA32;\r
1795     mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);\r
1796   }\r
1797   else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)\r
1798           || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)\r
1799           || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {\r
1800     //\r
1801     // 64-bits Architecture\r
1802     //\r
1803     mImageType = ImageType_X64;\r
1804     NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);\r
1805     mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);\r
1806   } else {\r
1807     return EFI_UNSUPPORTED;\r
1808   }\r
1809 \r
1810   return EFI_SUCCESS;\r
1811 }\r
1812 \r
1813 /**\r
1814   Calculate hash of Pe/Coff image based on the authenticode image hashing in\r
1815   PE/COFF Specification 8.0 Appendix A\r
1816 \r
1817   Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in \r
1818   the function LoadPeImage ().\r
1819 \r
1820   @param[in]    HashAlg   Hash algorithm type.\r
1821 \r
1822   @retval TRUE            Successfully hash image.\r
1823   @retval FALSE           Fail in hash image.\r
1824 \r
1825 **/\r
1826 BOOLEAN\r
1827 HashPeImage (\r
1828   IN  UINT32                HashAlg\r
1829   )\r
1830 {\r
1831   BOOLEAN                   Status;\r
1832   UINT16                    Magic;\r
1833   EFI_IMAGE_SECTION_HEADER  *Section;\r
1834   VOID                      *HashCtx;\r
1835   UINTN                     CtxSize;\r
1836   UINT8                     *HashBase;\r
1837   UINTN                     HashSize;\r
1838   UINTN                     SumOfBytesHashed;\r
1839   EFI_IMAGE_SECTION_HEADER  *SectionHeader;\r
1840   UINTN                     Index;\r
1841   UINTN                     Pos;\r
1842 \r
1843   HashCtx       = NULL;\r
1844   SectionHeader = NULL;\r
1845   Status        = FALSE;\r
1846 \r
1847   if (HashAlg != HASHALG_SHA256) {\r
1848     return FALSE;\r
1849   }\r
1850 \r
1851   //\r
1852   // Initialize context of hash.\r
1853   //\r
1854   ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
1855 \r
1856   mImageDigestSize  = SHA256_DIGEST_SIZE;\r
1857   mCertType         = gEfiCertSha256Guid;\r
1858 \r
1859   CtxSize   = mHash[HashAlg].GetContextSize();\r
1860 \r
1861   HashCtx = AllocatePool (CtxSize);\r
1862   ASSERT (HashCtx != NULL);\r
1863 \r
1864   // 1.  Load the image header into memory.\r
1865 \r
1866   // 2.  Initialize a SHA hash context.\r
1867   Status = mHash[HashAlg].HashInit(HashCtx);\r
1868   if (!Status) {\r
1869     goto Done;\r
1870   }\r
1871   //\r
1872   // Measuring PE/COFF Image Header;\r
1873   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
1874   //\r
1875   if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1876     //\r
1877     // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
1878     //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
1879     //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
1880     //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
1881     //\r
1882     Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1883   } else {\r
1884     //\r
1885     // Get the magic value from the PE/COFF Optional Header\r
1886     //\r
1887     Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
1888   }\r
1889 \r
1890   //\r
1891   // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
1892   // 4.  Hash the image header from its base to beginning of the image checksum.\r
1893   //\r
1894   HashBase = mImageBase;\r
1895   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1896     //\r
1897     // Use PE32 offset.\r
1898     //\r
1899     HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
1900   } else {\r
1901     //\r
1902     // Use PE32+ offset.\r
1903     //\r
1904     HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
1905   }\r
1906 \r
1907   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1908   if (!Status) {\r
1909     goto Done;\r
1910   }\r
1911   //\r
1912   // 5.  Skip over the image checksum (it occupies a single ULONG).\r
1913   // 6.  Get the address of the beginning of the Cert Directory.\r
1914   // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
1915   //\r
1916   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1917     //\r
1918     // Use PE32 offset.\r
1919     //\r
1920     HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
1921     HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
1922   } else {\r
1923     //\r
1924     // Use PE32+ offset.\r
1925     //\r
1926     HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
1927     HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
1928   }\r
1929 \r
1930   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1931   if (!Status) {\r
1932     goto Done;\r
1933   }\r
1934   //\r
1935   // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
1936   // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
1937   //\r
1938   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1939     //\r
1940     // Use PE32 offset\r
1941     //\r
1942     HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
1943     HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);\r
1944   } else {\r
1945     //\r
1946     // Use PE32+ offset.\r
1947     //\r
1948     HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
1949     HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);\r
1950   }\r
1951 \r
1952   Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1953   if (!Status) {\r
1954     goto Done;\r
1955   }\r
1956   //\r
1957   // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
1958   //\r
1959   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1960     //\r
1961     // Use PE32 offset.\r
1962     //\r
1963     SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r
1964   } else {\r
1965     //\r
1966     // Use PE32+ offset\r
1967     //\r
1968     SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
1969   }\r
1970 \r
1971   //\r
1972   // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
1973   //     structures in the image. The 'NumberOfSections' field of the image\r
1974   //     header indicates how big the table should be. Do not include any\r
1975   //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
1976   //\r
1977   SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r
1978   ASSERT (SectionHeader != NULL);\r
1979   //\r
1980   // 12.  Using the 'PointerToRawData' in the referenced section headers as\r
1981   //      a key, arrange the elements in the table in ascending order. In other\r
1982   //      words, sort the section headers according to the disk-file offset of\r
1983   //      the section.\r
1984   //\r
1985   Section = (EFI_IMAGE_SECTION_HEADER *) (\r
1986                mImageBase +\r
1987                mPeCoffHeaderOffset +\r
1988                sizeof (UINT32) +\r
1989                sizeof (EFI_IMAGE_FILE_HEADER) +\r
1990                mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
1991                );\r
1992   for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
1993     Pos = Index;\r
1994     while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
1995       CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r
1996       Pos--;\r
1997     }\r
1998     CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r
1999     Section += 1;\r
2000   }\r
2001 \r
2002   //\r
2003   // 13.  Walk through the sorted table, bring the corresponding section\r
2004   //      into memory, and hash the entire section (using the 'SizeOfRawData'\r
2005   //      field in the section header to determine the amount of data to hash).\r
2006   // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
2007   // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.\r
2008   //\r
2009   for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
2010     Section = &SectionHeader[Index];\r
2011     if (Section->SizeOfRawData == 0) {\r
2012       continue;\r
2013     }\r
2014     HashBase  = mImageBase + Section->PointerToRawData;\r
2015     HashSize  = (UINTN) Section->SizeOfRawData;\r
2016 \r
2017     Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
2018     if (!Status) {\r
2019       goto Done;\r
2020     }\r
2021 \r
2022     SumOfBytesHashed += HashSize;\r
2023   }\r
2024 \r
2025   //\r
2026   // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
2027   //      data in the file that needs to be added to the hash. This data begins\r
2028   //      at file offset SUM_OF_BYTES_HASHED and its length is:\r
2029   //             FileSize  -  (CertDirectory->Size)\r
2030   //\r
2031   if (mImageSize > SumOfBytesHashed) {\r
2032     HashBase = mImageBase + SumOfBytesHashed;\r
2033     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
2034       //\r
2035       // Use PE32 offset.\r
2036       //\r
2037       HashSize = (UINTN)(\r
2038                  mImageSize -\r
2039                  mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
2040                  SumOfBytesHashed);\r
2041     } else {\r
2042       //\r
2043       // Use PE32+ offset.\r
2044       //\r
2045       HashSize = (UINTN)(\r
2046                  mImageSize -\r
2047                  mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
2048                  SumOfBytesHashed);\r
2049     }\r
2050 \r
2051     Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
2052     if (!Status) {\r
2053       goto Done;\r
2054     }\r
2055   }\r
2056 \r
2057   Status  = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
2058 \r
2059 Done:\r
2060   if (HashCtx != NULL) {\r
2061     FreePool (HashCtx);\r
2062   }\r
2063   if (SectionHeader != NULL) {\r
2064     FreePool (SectionHeader);\r
2065   }\r
2066   return Status;\r
2067 }\r
2068 \r
2069 /**\r
2070   Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of\r
2071   Pe/Coff image based on the authenticated image hashing in PE/COFF Specification\r
2072   8.0 Appendix A\r
2073 \r
2074   @retval EFI_UNSUPPORTED             Hash algorithm is not supported.\r
2075   @retval EFI_SUCCESS                 Hash successfully.\r
2076 \r
2077 **/\r
2078 EFI_STATUS\r
2079 HashPeImageByType (\r
2080   VOID\r
2081   )\r
2082 {\r
2083   UINT8                     Index;\r
2084   WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;\r
2085 \r
2086   PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset);\r
2087 \r
2088   for (Index = 0; Index < HASHALG_MAX; Index++) {\r
2089     //\r
2090     // Check the Hash algorithm in PE/COFF Authenticode.\r
2091     //    According to PKCS#7 Definition:\r
2092     //        SignedData ::= SEQUENCE {\r
2093     //            version Version,\r
2094     //            digestAlgorithms DigestAlgorithmIdentifiers,\r
2095     //            contentInfo ContentInfo,\r
2096     //            .... }\r
2097     //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
2098     //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
2099     //    Fixed offset (+32) is calculated based on two bytes of length encoding.\r
2100      //\r
2101     if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
2102       //\r
2103       // Only support two bytes of Long Form of Length Encoding.\r
2104       //\r
2105       continue;\r
2106     }\r
2107 \r
2108     //\r
2109     if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
2110       break;\r
2111     }\r
2112   }\r
2113 \r
2114   if (Index == HASHALG_MAX) {\r
2115     return EFI_UNSUPPORTED;\r
2116   }\r
2117 \r
2118   //\r
2119   // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
2120   //\r
2121   if (!HashPeImage(Index)) {\r
2122     return EFI_UNSUPPORTED;\r
2123   }\r
2124 \r
2125   return EFI_SUCCESS;\r
2126 }\r
2127 \r
2128 /**\r
2129   Enroll a new executable's signature into Signature Database.\r
2130 \r
2131   @param[in] PrivateData     The module's private data.\r
2132   @param[in] VariableName    Variable name of signature database, must be\r
2133                              EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1\r
2134                              or EFI_IMAGE_SECURITY_DATABASE2.\r
2135 \r
2136   @retval   EFI_SUCCESS            New signature is enrolled successfully.\r
2137   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
2138   @retval   EFI_UNSUPPORTED        Unsupported command.\r
2139   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
2140 \r
2141 **/\r
2142 EFI_STATUS\r
2143 EnrollAuthentication2Descriptor (\r
2144   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2145   IN CHAR16                         *VariableName\r
2146   )\r
2147 {\r
2148   EFI_STATUS                        Status;\r
2149   VOID                              *Data;\r
2150   UINTN                             DataSize;\r
2151   UINT32                            Attr;\r
2152 \r
2153   Data = NULL;\r
2154 \r
2155   //\r
2156   // DBT only support DER-X509 Cert Enrollment\r
2157   //\r
2158   if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {\r
2159     return EFI_UNSUPPORTED;\r
2160   }\r
2161 \r
2162   //\r
2163   // Read the whole file content\r
2164   //\r
2165   Status = ReadFileContent(\r
2166              Private->FileContext->FHandle,\r
2167              (VOID **) &mImageBase,\r
2168              &mImageSize,\r
2169              0\r
2170              );\r
2171   if (EFI_ERROR (Status)) {\r
2172     goto ON_EXIT;\r
2173   }\r
2174   ASSERT (mImageBase != NULL);\r
2175 \r
2176   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
2177          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2178 \r
2179   //\r
2180   // Check if SigDB variable has been already existed.\r
2181   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
2182   // new signature data to original variable\r
2183   //\r
2184   DataSize = 0;\r
2185   Status = gRT->GetVariable(\r
2186                   VariableName,\r
2187                   &gEfiImageSecurityDatabaseGuid,\r
2188                   NULL,\r
2189                   &DataSize,\r
2190                   NULL\r
2191                   );\r
2192   if (Status == EFI_BUFFER_TOO_SMALL) {\r
2193     Attr |= EFI_VARIABLE_APPEND_WRITE;\r
2194   } else if (Status != EFI_NOT_FOUND) {\r
2195     goto ON_EXIT;\r
2196   }\r
2197 \r
2198   //\r
2199   // Diretly set AUTHENTICATION_2 data to SetVariable\r
2200   //\r
2201   Status = gRT->SetVariable(\r
2202                   VariableName,\r
2203                   &gEfiImageSecurityDatabaseGuid,\r
2204                   Attr,\r
2205                   mImageSize,\r
2206                   mImageBase\r
2207                   );\r
2208 \r
2209   DEBUG((DEBUG_INFO, "Enroll AUTH_2 data to Var:%s Status: %x\n", VariableName, Status));\r
2210 \r
2211 ON_EXIT:\r
2212 \r
2213   CloseEnrolledFile(Private->FileContext);\r
2214 \r
2215   if (Data != NULL) {\r
2216     FreePool (Data);\r
2217   }\r
2218 \r
2219   if (mImageBase != NULL) {\r
2220     FreePool (mImageBase);\r
2221     mImageBase = NULL;\r
2222   }\r
2223 \r
2224   return Status;\r
2225 \r
2226 }\r
2227 \r
2228 \r
2229 /**\r
2230   Enroll a new executable's signature into Signature Database.\r
2231 \r
2232   @param[in] PrivateData     The module's private data.\r
2233   @param[in] VariableName    Variable name of signature database, must be\r
2234                              EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1\r
2235                              or EFI_IMAGE_SECURITY_DATABASE2.\r
2236 \r
2237   @retval   EFI_SUCCESS            New signature is enrolled successfully.\r
2238   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
2239   @retval   EFI_UNSUPPORTED        Unsupported command.\r
2240   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
2241 \r
2242 **/\r
2243 EFI_STATUS\r
2244 EnrollImageSignatureToSigDB (\r
2245   IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2246   IN CHAR16                         *VariableName\r
2247   )\r
2248 {\r
2249   EFI_STATUS                        Status;\r
2250   EFI_SIGNATURE_LIST                *SigDBCert;\r
2251   EFI_SIGNATURE_DATA                *SigDBCertData;\r
2252   VOID                              *Data;\r
2253   UINTN                             DataSize;\r
2254   UINTN                             SigDBSize;\r
2255   UINT32                            Attr;\r
2256   WIN_CERTIFICATE_UEFI_GUID         *GuidCertData;\r
2257 \r
2258   Data = NULL;\r
2259   GuidCertData = NULL;\r
2260 \r
2261   if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {\r
2262     return EFI_UNSUPPORTED;\r
2263   }\r
2264 \r
2265   //\r
2266   // Form the SigDB certificate list.\r
2267   // Format the data item into EFI_SIGNATURE_LIST type.\r
2268   //\r
2269   // We need to parse executable's signature data from specified signed executable file.\r
2270   // In current implementation, we simply trust the pass-in signed executable file.\r
2271   // In reality, it's OS's responsibility to verify the signed executable file.\r
2272   //\r
2273 \r
2274   //\r
2275   // Read the whole file content\r
2276   //\r
2277   Status = ReadFileContent(\r
2278              Private->FileContext->FHandle,\r
2279              (VOID **) &mImageBase,\r
2280              &mImageSize,\r
2281              0\r
2282              );\r
2283   if (EFI_ERROR (Status)) {\r
2284     goto ON_EXIT;\r
2285   }\r
2286   ASSERT (mImageBase != NULL);\r
2287 \r
2288   Status = LoadPeImage ();\r
2289   if (EFI_ERROR (Status)) {\r
2290     goto ON_EXIT;\r
2291   }\r
2292 \r
2293   if (mSecDataDir->SizeOfCert == 0) {\r
2294     if (!HashPeImage (HASHALG_SHA256)) {\r
2295       Status =  EFI_SECURITY_VIOLATION;\r
2296       goto ON_EXIT;\r
2297     }\r
2298   } else {\r
2299 \r
2300     //\r
2301     // Read the certificate data\r
2302     //\r
2303     mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);\r
2304 \r
2305     if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
2306       GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;\r
2307       if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {\r
2308         Status = EFI_ABORTED;\r
2309         goto ON_EXIT;\r
2310       }\r
2311 \r
2312       if (!HashPeImage (HASHALG_SHA256)) {\r
2313         Status = EFI_ABORTED;\r
2314         goto ON_EXIT;;\r
2315       }\r
2316 \r
2317     } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
2318 \r
2319       Status = HashPeImageByType ();\r
2320       if (EFI_ERROR (Status)) {\r
2321         goto ON_EXIT;;\r
2322       }\r
2323     } else {\r
2324       Status = EFI_ABORTED;\r
2325       goto ON_EXIT;\r
2326     }\r
2327   }\r
2328 \r
2329   //\r
2330   // Create a new SigDB entry.\r
2331   //\r
2332   SigDBSize = sizeof(EFI_SIGNATURE_LIST)\r
2333               + sizeof(EFI_SIGNATURE_DATA) - 1\r
2334               + (UINT32) mImageDigestSize;\r
2335 \r
2336   Data = (UINT8*) AllocateZeroPool (SigDBSize);\r
2337   if (Data == NULL) {\r
2338     Status = EFI_OUT_OF_RESOURCES;\r
2339     goto ON_EXIT;\r
2340   }\r
2341 \r
2342   //\r
2343   // Adjust the Certificate Database parameters.\r
2344   //\r
2345   SigDBCert = (EFI_SIGNATURE_LIST*) Data;\r
2346   SigDBCert->SignatureListSize   = (UINT32) SigDBSize;\r
2347   SigDBCert->SignatureHeaderSize = 0;\r
2348   SigDBCert->SignatureSize       = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;\r
2349   CopyGuid (&SigDBCert->SignatureType, &mCertType);\r
2350 \r
2351   SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));\r
2352   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);\r
2353   CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);\r
2354 \r
2355   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
2356           | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2357   Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
2358   if (EFI_ERROR (Status)) {\r
2359     DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2360     goto ON_EXIT;\r
2361   }\r
2362 \r
2363   //\r
2364   // Check if SigDB variable has been already existed.\r
2365   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
2366   // new signature data to original variable\r
2367   //\r
2368   DataSize = 0;\r
2369   Status = gRT->GetVariable(\r
2370                   VariableName,\r
2371                   &gEfiImageSecurityDatabaseGuid,\r
2372                   NULL,\r
2373                   &DataSize,\r
2374                   NULL\r
2375                   );\r
2376   if (Status == EFI_BUFFER_TOO_SMALL) {\r
2377     Attr |= EFI_VARIABLE_APPEND_WRITE;\r
2378   } else if (Status != EFI_NOT_FOUND) {\r
2379     goto ON_EXIT;\r
2380   }\r
2381 \r
2382   //\r
2383   // Enroll the variable.\r
2384   //\r
2385   Status = gRT->SetVariable(\r
2386                   VariableName,\r
2387                   &gEfiImageSecurityDatabaseGuid,\r
2388                   Attr,\r
2389                   SigDBSize,\r
2390                   Data\r
2391                   );\r
2392   if (EFI_ERROR (Status)) {\r
2393     goto ON_EXIT;\r
2394   }\r
2395 \r
2396 ON_EXIT:\r
2397 \r
2398   CloseEnrolledFile(Private->FileContext);\r
2399 \r
2400   if (Private->SignatureGUID != NULL) {\r
2401     FreePool (Private->SignatureGUID);\r
2402     Private->SignatureGUID = NULL;\r
2403   }\r
2404 \r
2405   if (Data != NULL) {\r
2406     FreePool (Data);\r
2407   }\r
2408 \r
2409   if (mImageBase != NULL) {\r
2410     FreePool (mImageBase);\r
2411     mImageBase = NULL;\r
2412   }\r
2413 \r
2414   return Status;\r
2415 }\r
2416 \r
2417 /**\r
2418   Enroll signature into DB/DBX/DBT without KEK's authentication.\r
2419   The SignatureOwner GUID will be Private->SignatureGUID.\r
2420 \r
2421   @param[in] PrivateData     The module's private data.\r
2422   @param[in] VariableName    Variable name of signature database, must be\r
2423                              EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.\r
2424 \r
2425   @retval   EFI_SUCCESS            New signature enrolled successfully.\r
2426   @retval   EFI_INVALID_PARAMETER  The parameter is invalid.\r
2427   @retval   others                 Fail to enroll signature data.\r
2428 \r
2429 **/\r
2430 EFI_STATUS\r
2431 EnrollSignatureDatabase (\r
2432   IN SECUREBOOT_CONFIG_PRIVATE_DATA     *Private,\r
2433   IN CHAR16                             *VariableName\r
2434   )\r
2435 {\r
2436   UINT16*      FilePostFix;\r
2437   EFI_STATUS   Status;\r
2438   UINTN        NameLength;\r
2439 \r
2440   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {\r
2441     return EFI_INVALID_PARAMETER;\r
2442   }\r
2443 \r
2444   Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
2445   if (EFI_ERROR (Status)) {\r
2446     return Status;\r
2447   }\r
2448 \r
2449   //\r
2450   // Parse the file's postfix.\r
2451   //\r
2452   NameLength = StrLen (Private->FileContext->FileName);\r
2453   if (NameLength <= 4) {\r
2454     return EFI_INVALID_PARAMETER;\r
2455   }\r
2456   FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
2457   if (IsDerEncodeCertificate (FilePostFix)) {\r
2458     //\r
2459     // Supports DER-encoded X509 certificate.\r
2460     //\r
2461     return EnrollX509toSigDB (Private, VariableName);\r
2462   } else if (IsAuthentication2Format(Private->FileContext->FHandle)){\r
2463     return EnrollAuthentication2Descriptor(Private, VariableName);\r
2464   } else {\r
2465     return EnrollImageSignatureToSigDB (Private, VariableName);\r
2466   }\r
2467 }\r
2468 \r
2469 /**\r
2470   List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)\r
2471   by GUID in the page for user to select and delete as needed.\r
2472 \r
2473   @param[in]    PrivateData         Module's private data.\r
2474   @param[in]    VariableName        The variable name of the vendor's signature database.\r
2475   @param[in]    VendorGuid          A unique identifier for the vendor.\r
2476   @param[in]    LabelNumber         Label number to insert opcodes.\r
2477   @param[in]    FormId              Form ID of current page.\r
2478   @param[in]    QuestionIdBase      Base question id of the signature list.\r
2479 \r
2480   @retval   EFI_SUCCESS             Success to update the signature list page\r
2481   @retval   EFI_OUT_OF_RESOURCES    Unable to allocate required resources.\r
2482 \r
2483 **/\r
2484 EFI_STATUS\r
2485 UpdateDeletePage (\r
2486   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,\r
2487   IN CHAR16                           *VariableName,\r
2488   IN EFI_GUID                         *VendorGuid,\r
2489   IN UINT16                           LabelNumber,\r
2490   IN EFI_FORM_ID                      FormId,\r
2491   IN EFI_QUESTION_ID                  QuestionIdBase\r
2492   )\r
2493 {\r
2494   EFI_STATUS                  Status;\r
2495   UINT32                      Index;\r
2496   UINTN                       CertCount;\r
2497   UINTN                       GuidIndex;\r
2498   VOID                        *StartOpCodeHandle;\r
2499   VOID                        *EndOpCodeHandle;\r
2500   EFI_IFR_GUID_LABEL          *StartLabel;\r
2501   EFI_IFR_GUID_LABEL          *EndLabel;\r
2502   UINTN                       DataSize;\r
2503   UINT8                       *Data;\r
2504   EFI_SIGNATURE_LIST          *CertList;\r
2505   EFI_SIGNATURE_DATA          *Cert;\r
2506   UINT32                      ItemDataSize;\r
2507   CHAR16                      *GuidStr;\r
2508   EFI_STRING_ID               GuidID;\r
2509   EFI_STRING_ID               Help;\r
2510 \r
2511   Data     = NULL;\r
2512   CertList = NULL;\r
2513   Cert     = NULL;\r
2514   GuidStr  = NULL;\r
2515   StartOpCodeHandle = NULL;\r
2516   EndOpCodeHandle   = NULL;\r
2517 \r
2518   //\r
2519   // Initialize the container for dynamic opcodes.\r
2520   //\r
2521   StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2522   if (StartOpCodeHandle == NULL) {\r
2523     Status = EFI_OUT_OF_RESOURCES;\r
2524     goto ON_EXIT;\r
2525   }\r
2526 \r
2527   EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2528   if (EndOpCodeHandle == NULL) {\r
2529     Status = EFI_OUT_OF_RESOURCES;\r
2530     goto ON_EXIT;\r
2531   }\r
2532 \r
2533   //\r
2534   // Create Hii Extend Label OpCode.\r
2535   //\r
2536   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2537                                         StartOpCodeHandle,\r
2538                                         &gEfiIfrTianoGuid,\r
2539                                         NULL,\r
2540                                         sizeof (EFI_IFR_GUID_LABEL)\r
2541                                         );\r
2542   StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
2543   StartLabel->Number        = LabelNumber;\r
2544 \r
2545   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2546                                       EndOpCodeHandle,\r
2547                                       &gEfiIfrTianoGuid,\r
2548                                       NULL,\r
2549                                       sizeof (EFI_IFR_GUID_LABEL)\r
2550                                       );\r
2551   EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
2552   EndLabel->Number        = LABEL_END;\r
2553 \r
2554   //\r
2555   // Read Variable.\r
2556   //\r
2557   DataSize = 0;\r
2558   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);\r
2559   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2560     goto ON_EXIT;\r
2561   }\r
2562 \r
2563   Data = (UINT8 *) AllocateZeroPool (DataSize);\r
2564   if (Data == NULL) {\r
2565     Status = EFI_OUT_OF_RESOURCES;\r
2566     goto ON_EXIT;\r
2567   }\r
2568 \r
2569   Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);\r
2570   if (EFI_ERROR (Status)) {\r
2571     goto ON_EXIT;\r
2572   }\r
2573 \r
2574   GuidStr = AllocateZeroPool (100);\r
2575   if (GuidStr == NULL) {\r
2576     Status = EFI_OUT_OF_RESOURCES;\r
2577     goto ON_EXIT;\r
2578   }\r
2579 \r
2580   //\r
2581   // Enumerate all KEK pub data.\r
2582   //\r
2583   ItemDataSize = (UINT32) DataSize;\r
2584   CertList = (EFI_SIGNATURE_LIST *) Data;\r
2585   GuidIndex = 0;\r
2586 \r
2587   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {\r
2588 \r
2589     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {\r
2590       Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);\r
2591     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2592       Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);\r
2593     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {\r
2594       Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);\r
2595     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {\r
2596       Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);\r
2597     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
2598       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);\r
2599     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
2600       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);\r
2601     } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
2602       Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);\r
2603     } else {\r
2604       //\r
2605       // The signature type is not supported in current implementation.\r
2606       //\r
2607       ItemDataSize -= CertList->SignatureListSize;\r
2608       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2609       continue;\r
2610     }\r
2611 \r
2612     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2613     for (Index = 0; Index < CertCount; Index++) {\r
2614       Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList\r
2615                                               + sizeof (EFI_SIGNATURE_LIST)\r
2616                                               + CertList->SignatureHeaderSize\r
2617                                               + Index * CertList->SignatureSize);\r
2618       //\r
2619       // Display GUID and help\r
2620       //\r
2621       GuidToString (&Cert->SignatureOwner, GuidStr, 100);\r
2622       GuidID  = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);\r
2623       HiiCreateCheckBoxOpCode (\r
2624         StartOpCodeHandle,\r
2625         (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),\r
2626         0,\r
2627         0,\r
2628         GuidID,\r
2629         Help,\r
2630         EFI_IFR_FLAG_CALLBACK,\r
2631         0,\r
2632         NULL\r
2633         );\r
2634     }\r
2635 \r
2636     ItemDataSize -= CertList->SignatureListSize;\r
2637     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2638   }\r
2639 \r
2640 ON_EXIT:\r
2641   HiiUpdateForm (\r
2642     PrivateData->HiiHandle,\r
2643     &gSecureBootConfigFormSetGuid,\r
2644     FormId,\r
2645     StartOpCodeHandle,\r
2646     EndOpCodeHandle\r
2647     );\r
2648 \r
2649   if (StartOpCodeHandle != NULL) {\r
2650     HiiFreeOpCodeHandle (StartOpCodeHandle);\r
2651   }\r
2652 \r
2653   if (EndOpCodeHandle != NULL) {\r
2654     HiiFreeOpCodeHandle (EndOpCodeHandle);\r
2655   }\r
2656 \r
2657   if (Data != NULL) {\r
2658     FreePool (Data);\r
2659   }\r
2660 \r
2661   if (GuidStr != NULL) {\r
2662     FreePool (GuidStr);\r
2663   }\r
2664 \r
2665   return EFI_SUCCESS;\r
2666 }\r
2667 \r
2668 /**\r
2669   Delete a KEK entry from KEK database.\r
2670 \r
2671   @param[in]    PrivateData         Module's private data.\r
2672   @param[in]    QuestionId          Question id of the KEK item to delete.\r
2673 \r
2674   @retval   EFI_SUCCESS            Delete kek item successfully.\r
2675   @retval   EFI_OUT_OF_RESOURCES   Could not allocate needed resources.\r
2676 \r
2677 **/\r
2678 EFI_STATUS\r
2679 DeleteKeyExchangeKey (\r
2680   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,\r
2681   IN EFI_QUESTION_ID                  QuestionId\r
2682   )\r
2683 {\r
2684   EFI_STATUS                  Status;\r
2685   UINTN                       DataSize;\r
2686   UINT8                       *Data;\r
2687   UINT8                       *OldData;\r
2688   UINT32                      Attr;\r
2689   UINT32                      Index;\r
2690   EFI_SIGNATURE_LIST          *CertList;\r
2691   EFI_SIGNATURE_LIST          *NewCertList;\r
2692   EFI_SIGNATURE_DATA          *Cert;\r
2693   UINTN                       CertCount;\r
2694   UINT32                      Offset;\r
2695   BOOLEAN                     IsKEKItemFound;\r
2696   UINT32                      KekDataSize;\r
2697   UINTN                       DeleteKekIndex;\r
2698   UINTN                       GuidIndex;\r
2699 \r
2700   Data            = NULL;\r
2701   OldData         = NULL;\r
2702   CertList        = NULL;\r
2703   Cert            = NULL;\r
2704   Attr            = 0;\r
2705   DeleteKekIndex  = QuestionId - OPTION_DEL_KEK_QUESTION_ID;\r
2706 \r
2707   Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
2708   if (EFI_ERROR (Status)) {\r
2709     return Status;\r
2710   }\r
2711 \r
2712   //\r
2713   // Get original KEK variable.\r
2714   //\r
2715   DataSize = 0;\r
2716   Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);\r
2717   if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2718     goto ON_EXIT;\r
2719   }\r
2720 \r
2721   OldData = (UINT8*)AllocateZeroPool(DataSize);\r
2722   if (OldData == NULL) {\r
2723     Status = EFI_OUT_OF_RESOURCES;\r
2724     goto ON_EXIT;\r
2725   }\r
2726 \r
2727   Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);\r
2728   if (EFI_ERROR(Status)) {\r
2729     goto ON_EXIT;\r
2730   }\r
2731 \r
2732   //\r
2733   // Allocate space for new variable.\r
2734   //\r
2735   Data = (UINT8*) AllocateZeroPool (DataSize);\r
2736   if (Data == NULL) {\r
2737     Status  =  EFI_OUT_OF_RESOURCES;\r
2738     goto ON_EXIT;\r
2739   }\r
2740 \r
2741   //\r
2742   // Enumerate all KEK pub data and erasing the target item.\r
2743   //\r
2744   IsKEKItemFound = FALSE;\r
2745   KekDataSize = (UINT32) DataSize;\r
2746   CertList = (EFI_SIGNATURE_LIST *) OldData;\r
2747   Offset = 0;\r
2748   GuidIndex = 0;\r
2749   while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2750     if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||\r
2751         CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2752       CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));\r
2753       NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);\r
2754       Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2755       Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2756       CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2757       for (Index = 0; Index < CertCount; Index++) {\r
2758         if (GuidIndex == DeleteKekIndex ) {\r
2759           //\r
2760           // Find it! Skip it!\r
2761           //\r
2762           NewCertList->SignatureListSize -= CertList->SignatureSize;\r
2763           IsKEKItemFound = TRUE;\r
2764         } else {\r
2765           //\r
2766           // This item doesn't match. Copy it to the Data buffer.\r
2767           //\r
2768           CopyMem (Data + Offset, Cert, CertList->SignatureSize);\r
2769           Offset += CertList->SignatureSize;\r
2770         }\r
2771         GuidIndex++;\r
2772         Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);\r
2773       }\r
2774     } else {\r
2775       //\r
2776       // This List doesn't match. Copy it to the Data buffer.\r
2777       //\r
2778       CopyMem (Data + Offset, CertList, CertList->SignatureListSize);\r
2779       Offset += CertList->SignatureListSize;\r
2780     }\r
2781 \r
2782     KekDataSize -= CertList->SignatureListSize;\r
2783     CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);\r
2784   }\r
2785 \r
2786   if (!IsKEKItemFound) {\r
2787     //\r
2788     // Doesn't find the Kek Item!\r
2789     //\r
2790     Status = EFI_NOT_FOUND;\r
2791     goto ON_EXIT;\r
2792   }\r
2793 \r
2794   //\r
2795   // Delete the Signature header if there is no signature in the list.\r
2796   //\r
2797   KekDataSize = Offset;\r
2798   CertList = (EFI_SIGNATURE_LIST*) Data;\r
2799   Offset = 0;\r
2800   ZeroMem (OldData, KekDataSize);\r
2801   while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2802     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2803     DEBUG ((DEBUG_INFO, "       CertCount = %x\n", CertCount));\r
2804     if (CertCount != 0) {\r
2805       CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);\r
2806       Offset += CertList->SignatureListSize;\r
2807     }\r
2808     KekDataSize -= CertList->SignatureListSize;\r
2809     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2810   }\r
2811 \r
2812   DataSize = Offset;\r
2813   if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2814     Status = CreateTimeBasedPayload (&DataSize, &OldData);\r
2815     if (EFI_ERROR (Status)) {\r
2816       DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2817       goto ON_EXIT;\r
2818     }\r
2819   }\r
2820 \r
2821   Status = gRT->SetVariable(\r
2822                   EFI_KEY_EXCHANGE_KEY_NAME,\r
2823                   &gEfiGlobalVariableGuid,\r
2824                   Attr,\r
2825                   DataSize,\r
2826                   OldData\r
2827                   );\r
2828   if (EFI_ERROR (Status)) {\r
2829     DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));\r
2830     goto ON_EXIT;\r
2831   }\r
2832 \r
2833 ON_EXIT:\r
2834   if (Data != NULL) {\r
2835     FreePool(Data);\r
2836   }\r
2837 \r
2838   if (OldData != NULL) {\r
2839     FreePool(OldData);\r
2840   }\r
2841 \r
2842   return UpdateDeletePage (\r
2843            PrivateData,\r
2844            EFI_KEY_EXCHANGE_KEY_NAME,\r
2845            &gEfiGlobalVariableGuid,\r
2846            LABEL_KEK_DELETE,\r
2847            FORMID_DELETE_KEK_FORM,\r
2848            OPTION_DEL_KEK_QUESTION_ID\r
2849            );\r
2850 }\r
2851 \r
2852 /**\r
2853   Delete a signature entry from siganture database.\r
2854 \r
2855   @param[in]    PrivateData         Module's private data.\r
2856   @param[in]    VariableName        The variable name of the vendor's signature database.\r
2857   @param[in]    VendorGuid          A unique identifier for the vendor.\r
2858   @param[in]    LabelNumber         Label number to insert opcodes.\r
2859   @param[in]    FormId              Form ID of current page.\r
2860   @param[in]    QuestionIdBase      Base question id of the signature list.\r
2861   @param[in]    DeleteIndex         Signature index to delete.\r
2862 \r
2863   @retval   EFI_SUCCESS             Delete siganture successfully.\r
2864   @retval   EFI_NOT_FOUND           Can't find the signature item,\r
2865   @retval   EFI_OUT_OF_RESOURCES    Could not allocate needed resources.\r
2866 **/\r
2867 EFI_STATUS\r
2868 DeleteSignature (\r
2869   IN SECUREBOOT_CONFIG_PRIVATE_DATA   *PrivateData,\r