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