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