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