]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
SecurityPkg: Update SecureBootConfigDxe to support ARM image
[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
a16170a1
AB
1646 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)\r
1647 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {\r
ecc722ad 1648 //\r
a16170a1 1649 // 32-bits Architecture\r
ecc722ad 1650 //\r
1651 mImageType = ImageType_IA32;\r
1652 mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);\r
1653 }\r
1654 else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)\r
a16170a1
AB
1655 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)\r
1656 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {\r
ecc722ad 1657 //\r
1658 // 64-bits Architecture\r
1659 //\r
1660 mImageType = ImageType_X64;\r
1661 NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);\r
1662 mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);\r
1663 } else {\r
1664 return EFI_UNSUPPORTED;\r
1665 }\r
1666\r
1667 return EFI_SUCCESS;\r
1668}\r
1669\r
1670/**\r
1671 Calculate hash of Pe/Coff image based on the authenticode image hashing in\r
1672 PE/COFF Specification 8.0 Appendix A\r
1673\r
1674 @param[in] HashAlg Hash algorithm type.\r
20333c6d 1675\r
ecc722ad 1676 @retval TRUE Successfully hash image.\r
1677 @retval FALSE Fail in hash image.\r
1678\r
1679**/\r
20333c6d 1680BOOLEAN\r
ecc722ad 1681HashPeImage (\r
1682 IN UINT32 HashAlg\r
1683 )\r
1684{\r
1685 BOOLEAN Status;\r
1686 UINT16 Magic;\r
1687 EFI_IMAGE_SECTION_HEADER *Section;\r
1688 VOID *HashCtx;\r
1689 UINTN CtxSize;\r
1690 UINT8 *HashBase;\r
1691 UINTN HashSize;\r
1692 UINTN SumOfBytesHashed;\r
1693 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
1694 UINTN Index;\r
1695 UINTN Pos;\r
1696\r
1697 HashCtx = NULL;\r
1698 SectionHeader = NULL;\r
1699 Status = FALSE;\r
1700\r
1701 if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {\r
1702 return FALSE;\r
1703 }\r
20333c6d 1704\r
ecc722ad 1705 //\r
1706 // Initialize context of hash.\r
1707 //\r
1708 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
1709\r
1710 if (HashAlg == HASHALG_SHA1) {\r
1711 mImageDigestSize = SHA1_DIGEST_SIZE;\r
20333c6d 1712 mCertType = gEfiCertSha1Guid;\r
ecc722ad 1713 } else if (HashAlg == HASHALG_SHA256) {\r
1714 mImageDigestSize = SHA256_DIGEST_SIZE;\r
1715 mCertType = gEfiCertSha256Guid;\r
1716 }\r
1717\r
1718 CtxSize = mHash[HashAlg].GetContextSize();\r
20333c6d 1719\r
ecc722ad 1720 HashCtx = AllocatePool (CtxSize);\r
1721 ASSERT (HashCtx != NULL);\r
1722\r
1723 // 1. Load the image header into memory.\r
1724\r
1725 // 2. Initialize a SHA hash context.\r
1726 Status = mHash[HashAlg].HashInit(HashCtx);\r
1727 if (!Status) {\r
1728 goto Done;\r
1729 }\r
1730 //\r
1731 // Measuring PE/COFF Image Header;\r
1732 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
1733 //\r
de2447dd 1734 if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1735 //\r
20333c6d
QL
1736 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
1737 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
de2447dd 1738 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
1739 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
1740 //\r
1741 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1742 } else {\r
1743 //\r
1744 // Get the magic value from the PE/COFF Optional Header\r
1745 //\r
1746 Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
1747 }\r
20333c6d 1748\r
ecc722ad 1749 //\r
1750 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
1751 // 4. Hash the image header from its base to beginning of the image checksum.\r
1752 //\r
1753 HashBase = mImageBase;\r
1754 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1755 //\r
1756 // Use PE32 offset.\r
1757 //\r
1758 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
1759 } else {\r
1760 //\r
1761 // Use PE32+ offset.\r
1762 //\r
1763 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
1764 }\r
1765\r
1766 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1767 if (!Status) {\r
1768 goto Done;\r
1769 }\r
1770 //\r
1771 // 5. Skip over the image checksum (it occupies a single ULONG).\r
1772 // 6. Get the address of the beginning of the Cert Directory.\r
1773 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
1774 //\r
1775 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1776 //\r
1777 // Use PE32 offset.\r
1778 //\r
1779 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
1780 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
1781 } else {\r
1782 //\r
1783 // Use PE32+ offset.\r
20333c6d 1784 //\r
ecc722ad 1785 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
1786 HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
1787 }\r
1788\r
1789 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1790 if (!Status) {\r
1791 goto Done;\r
1792 }\r
1793 //\r
1794 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
1795 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
1796 //\r
1797 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1798 //\r
1799 // Use PE32 offset\r
1800 //\r
1801 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
1802 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
1803 } else {\r
1804 //\r
1805 // Use PE32+ offset.\r
1806 //\r
1807 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
1808 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
1809 }\r
1810\r
1811 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1812 if (!Status) {\r
1813 goto Done;\r
1814 }\r
1815 //\r
1816 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
1817 //\r
1818 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1819 //\r
1820 // Use PE32 offset.\r
1821 //\r
1822 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r
1823 } else {\r
1824 //\r
1825 // Use PE32+ offset\r
1826 //\r
1827 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
1828 }\r
1829\r
1830 //\r
1831 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
1832 // structures in the image. The 'NumberOfSections' field of the image\r
1833 // header indicates how big the table should be. Do not include any\r
1834 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
1835 //\r
1836 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r
1837 ASSERT (SectionHeader != NULL);\r
1838 //\r
1839 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
1840 // a key, arrange the elements in the table in ascending order. In other\r
1841 // words, sort the section headers according to the disk-file offset of\r
1842 // the section.\r
1843 //\r
1844 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
1845 mImageBase +\r
1846 mPeCoffHeaderOffset +\r
1847 sizeof (UINT32) +\r
1848 sizeof (EFI_IMAGE_FILE_HEADER) +\r
1849 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
1850 );\r
1851 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
1852 Pos = Index;\r
1853 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
1854 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r
1855 Pos--;\r
1856 }\r
1857 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r
1858 Section += 1;\r
1859 }\r
1860\r
1861 //\r
1862 // 13. Walk through the sorted table, bring the corresponding section\r
1863 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
1864 // field in the section header to determine the amount of data to hash).\r
1865 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
1866 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
1867 //\r
1868 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
1869 Section = &SectionHeader[Index];\r
1870 if (Section->SizeOfRawData == 0) {\r
1871 continue;\r
1872 }\r
1873 HashBase = mImageBase + Section->PointerToRawData;\r
1874 HashSize = (UINTN) Section->SizeOfRawData;\r
1875\r
1876 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1877 if (!Status) {\r
1878 goto Done;\r
1879 }\r
1880\r
1881 SumOfBytesHashed += HashSize;\r
1882 }\r
1883\r
1884 //\r
1885 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
1886 // data in the file that needs to be added to the hash. This data begins\r
1887 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
1888 // FileSize - (CertDirectory->Size)\r
1889 //\r
1890 if (mImageSize > SumOfBytesHashed) {\r
1891 HashBase = mImageBase + SumOfBytesHashed;\r
1892 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1893 //\r
1894 // Use PE32 offset.\r
1895 //\r
1896 HashSize = (UINTN)(\r
1897 mImageSize -\r
1898 mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
1899 SumOfBytesHashed);\r
1900 } else {\r
1901 //\r
1902 // Use PE32+ offset.\r
1903 //\r
1904 HashSize = (UINTN)(\r
1905 mImageSize -\r
1906 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
20333c6d 1907 SumOfBytesHashed);\r
ecc722ad 1908 }\r
1909\r
1910 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1911 if (!Status) {\r
1912 goto Done;\r
1913 }\r
1914 }\r
1915\r
1916 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
1917\r
1918Done:\r
1919 if (HashCtx != NULL) {\r
1920 FreePool (HashCtx);\r
1921 }\r
1922 if (SectionHeader != NULL) {\r
1923 FreePool (SectionHeader);\r
1924 }\r
1925 return Status;\r
1926}\r
1927\r
1928/**\r
69f8bb52 1929 Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of\r
20333c6d 1930 Pe/Coff image based on the authenticated image hashing in PE/COFF Specification\r
ecc722ad 1931 8.0 Appendix A\r
1932\r
1933 @retval EFI_UNSUPPORTED Hash algorithm is not supported.\r
1934 @retval EFI_SUCCESS Hash successfully.\r
1935\r
1936**/\r
20333c6d 1937EFI_STATUS\r
ecc722ad 1938HashPeImageByType (\r
1939 VOID\r
1940 )\r
1941{\r
1942 UINT8 Index;\r
1943 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
1944\r
1945 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset);\r
1946\r
20333c6d 1947 for (Index = 0; Index < HASHALG_MAX; Index++) {\r
ecc722ad 1948 //\r
1949 // Check the Hash algorithm in PE/COFF Authenticode.\r
20333c6d 1950 // According to PKCS#7 Definition:\r
ecc722ad 1951 // SignedData ::= SEQUENCE {\r
1952 // version Version,\r
1953 // digestAlgorithms DigestAlgorithmIdentifiers,\r
1954 // contentInfo ContentInfo,\r
1955 // .... }\r
1956 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
1957 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
1958 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
1959 //\r
1960 if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
1961 //\r
1962 // Only support two bytes of Long Form of Length Encoding.\r
1963 //\r
1964 continue;\r
1965 }\r
1966\r
20333c6d 1967 //\r
ecc722ad 1968 if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
1969 break;\r
1970 }\r
1971 }\r
1972\r
1973 if (Index == HASHALG_MAX) {\r
1974 return EFI_UNSUPPORTED;\r
1975 }\r
1976\r
1977 //\r
1978 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
1979 //\r
1980 if (!HashPeImage(Index)) {\r
1981 return EFI_UNSUPPORTED;\r
1982 }\r
1983\r
1984 return EFI_SUCCESS;\r
1985}\r
1986\r
1987/**\r
20333c6d 1988 Enroll a new executable's signature into Signature Database.\r
ecc722ad 1989\r
1990 @param[in] PrivateData The module's private data.\r
20333c6d
QL
1991 @param[in] VariableName Variable name of signature database, must be\r
1992 EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1\r
1993 or EFI_IMAGE_SECURITY_DATABASE2.\r
ecc722ad 1994\r
1995 @retval EFI_SUCCESS New signature is enrolled successfully.\r
1996 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
1997 @retval EFI_UNSUPPORTED Unsupported command.\r
1998 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
1999\r
2000**/\r
2001EFI_STATUS\r
2002EnrollImageSignatureToSigDB (\r
2003 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2004 IN CHAR16 *VariableName\r
2005 )\r
2006{\r
2007 EFI_STATUS Status;\r
2008 EFI_SIGNATURE_LIST *SigDBCert;\r
2009 EFI_SIGNATURE_DATA *SigDBCertData;\r
2010 VOID *Data;\r
2011 UINTN DataSize;\r
2012 UINTN SigDBSize;\r
2013 UINT32 Attr;\r
2014 WIN_CERTIFICATE_UEFI_GUID *GuidCertData;\r
2015\r
2016 Data = NULL;\r
2017 GuidCertData = NULL;\r
ecc722ad 2018\r
20333c6d
QL
2019 if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {\r
2020 return EFI_UNSUPPORTED;\r
2021 }\r
2022\r
ecc722ad 2023 //\r
2024 // Form the SigDB certificate list.\r
2025 // Format the data item into EFI_SIGNATURE_LIST type.\r
2026 //\r
2027 // We need to parse executable's signature data from specified signed executable file.\r
2028 // In current implementation, we simply trust the pass-in signed executable file.\r
2029 // In reality, it's OS's responsibility to verify the signed executable file.\r
2030 //\r
2031\r
2032 //\r
2033 // Read the whole file content\r
2034 //\r
2035 Status = ReadFileContent(\r
2036 Private->FileContext->FHandle,\r
20333c6d
QL
2037 (VOID **) &mImageBase,\r
2038 &mImageSize,\r
ecc722ad 2039 0\r
2040 );\r
2041 if (EFI_ERROR (Status)) {\r
2042 goto ON_EXIT;\r
20333c6d 2043 }\r
ba57d4fd 2044 ASSERT (mImageBase != NULL);\r
ecc722ad 2045\r
2046 Status = LoadPeImage ();\r
2047 if (EFI_ERROR (Status)) {\r
2048 goto ON_EXIT;\r
2049 }\r
2050\r
2051 if (mSecDataDir->SizeOfCert == 0) {\r
2052 if (!HashPeImage (HASHALG_SHA256)) {\r
2053 Status = EFI_SECURITY_VIOLATION;\r
2054 goto ON_EXIT;\r
2055 }\r
2056 } else {\r
20333c6d 2057\r
ecc722ad 2058 //\r
2059 // Read the certificate data\r
2060 //\r
2061 mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);\r
2062\r
2063 if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
2064 GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;\r
2065 if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {\r
2066 Status = EFI_ABORTED;\r
2067 goto ON_EXIT;\r
2068 }\r
2069\r
2070 if (!HashPeImage (HASHALG_SHA256)) {\r
2071 Status = EFI_ABORTED;\r
2072 goto ON_EXIT;;\r
2073 }\r
20333c6d 2074\r
ecc722ad 2075 } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
2076\r
2077 Status = HashPeImageByType ();\r
2078 if (EFI_ERROR (Status)) {\r
2079 goto ON_EXIT;;\r
2080 }\r
2081 } else {\r
2082 Status = EFI_ABORTED;\r
2083 goto ON_EXIT;\r
2084 }\r
2085 }\r
2086\r
2087 //\r
2088 // Create a new SigDB entry.\r
2089 //\r
20333c6d 2090 SigDBSize = sizeof(EFI_SIGNATURE_LIST)\r
ecc722ad 2091 + sizeof(EFI_SIGNATURE_DATA) - 1\r
2092 + (UINT32) mImageDigestSize;\r
2093\r
2094 Data = (UINT8*) AllocateZeroPool (SigDBSize);\r
2095 if (Data == NULL) {\r
2096 Status = EFI_OUT_OF_RESOURCES;\r
2097 goto ON_EXIT;\r
2098 }\r
20333c6d 2099\r
ecc722ad 2100 //\r
2101 // Adjust the Certificate Database parameters.\r
20333c6d 2102 //\r
ecc722ad 2103 SigDBCert = (EFI_SIGNATURE_LIST*) Data;\r
2104 SigDBCert->SignatureListSize = (UINT32) SigDBSize;\r
2105 SigDBCert->SignatureHeaderSize = 0;\r
2106 SigDBCert->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;\r
2107 CopyGuid (&SigDBCert->SignatureType, &mCertType);\r
2108\r
2109 SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));\r
2110 CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);\r
2111 CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);\r
2112\r
20333c6d 2113 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
8c1babfd 2114 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2115 Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
2116 if (EFI_ERROR (Status)) {\r
2117 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2118 goto ON_EXIT;\r
2119 }\r
20333c6d 2120\r
ecc722ad 2121 //\r
20333c6d
QL
2122 // Check if SigDB variable has been already existed.\r
2123 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
ecc722ad 2124 // new signature data to original variable\r
20333c6d 2125 //\r
ecc722ad 2126 DataSize = 0;\r
2127 Status = gRT->GetVariable(\r
20333c6d
QL
2128 VariableName,\r
2129 &gEfiImageSecurityDatabaseGuid,\r
2130 NULL,\r
2131 &DataSize,\r
ecc722ad 2132 NULL\r
2133 );\r
2134 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2135 Attr |= EFI_VARIABLE_APPEND_WRITE;\r
2136 } else if (Status != EFI_NOT_FOUND) {\r
2137 goto ON_EXIT;\r
20333c6d 2138 }\r
ecc722ad 2139\r
2140 //\r
2141 // Enroll the variable.\r
2142 //\r
2143 Status = gRT->SetVariable(\r
20333c6d
QL
2144 VariableName,\r
2145 &gEfiImageSecurityDatabaseGuid,\r
2146 Attr,\r
2147 SigDBSize,\r
ecc722ad 2148 Data\r
2149 );\r
2150 if (EFI_ERROR (Status)) {\r
2151 goto ON_EXIT;\r
2152 }\r
2153\r
2154ON_EXIT:\r
2155\r
2156 CloseFile (Private->FileContext->FHandle);\r
2157 Private->FileContext->FHandle = NULL;\r
2158 Private->FileContext->FileName = NULL;\r
2159\r
2160 if (Private->SignatureGUID != NULL) {\r
2161 FreePool (Private->SignatureGUID);\r
2162 Private->SignatureGUID = NULL;\r
2163 }\r
2164\r
2165 if (Data != NULL) {\r
2166 FreePool (Data);\r
2167 }\r
2168\r
2169 if (mImageBase != NULL) {\r
2170 FreePool (mImageBase);\r
2171 mImageBase = NULL;\r
2172 }\r
2173\r
2174 return Status;\r
2175}\r
2176\r
2177/**\r
20333c6d 2178 Enroll signature into DB/DBX/DBT without KEK's authentication.\r
ecc722ad 2179 The SignatureOwner GUID will be Private->SignatureGUID.\r
20333c6d 2180\r
ecc722ad 2181 @param[in] PrivateData The module's private data.\r
20333c6d 2182 @param[in] VariableName Variable name of signature database, must be\r
ecc722ad 2183 EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.\r
20333c6d 2184\r
ecc722ad 2185 @retval EFI_SUCCESS New signature enrolled successfully.\r
2186 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
2187 @retval others Fail to enroll signature data.\r
20333c6d 2188\r
ecc722ad 2189**/\r
2190EFI_STATUS\r
2191EnrollSignatureDatabase (\r
2192 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2193 IN CHAR16 *VariableName\r
20333c6d 2194 )\r
ecc722ad 2195{\r
2196 UINT16* FilePostFix;\r
f71ed839 2197 EFI_STATUS Status;\r
fd64f84f 2198 UINTN NameLength;\r
ecc722ad 2199\r
2200 if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {\r
2201 return EFI_INVALID_PARAMETER;\r
2202 }\r
2203\r
20333c6d 2204 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
f71ed839 2205 if (EFI_ERROR (Status)) {\r
2206 return Status;\r
2207 }\r
20333c6d 2208\r
ecc722ad 2209 //\r
20333c6d 2210 // Parse the file's postfix.\r
ecc722ad 2211 //\r
fd64f84f
GCPL
2212 NameLength = StrLen (Private->FileContext->FileName);\r
2213 if (NameLength <= 4) {\r
2214 return EFI_INVALID_PARAMETER;\r
2215 }\r
2216 FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
20333c6d 2217 if (IsDerEncodeCertificate (FilePostFix)) {\r
ecc722ad 2218 //\r
e4d7370d 2219 // Supports DER-encoded X509 certificate.\r
ecc722ad 2220 //\r
2221 return EnrollX509toSigDB (Private, VariableName);\r
2222 }\r
2223\r
2224 return EnrollImageSignatureToSigDB (Private, VariableName);\r
2225}\r
2226\r
2227/**\r
20333c6d 2228 List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)\r
ecc722ad 2229 by GUID in the page for user to select and delete as needed.\r
2230\r
2231 @param[in] PrivateData Module's private data.\r
2232 @param[in] VariableName The variable name of the vendor's signature database.\r
2233 @param[in] VendorGuid A unique identifier for the vendor.\r
2234 @param[in] LabelNumber Label number to insert opcodes.\r
2235 @param[in] FormId Form ID of current page.\r
2236 @param[in] QuestionIdBase Base question id of the signature list.\r
2237\r
2238 @retval EFI_SUCCESS Success to update the signature list page\r
2239 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.\r
20333c6d 2240\r
ecc722ad 2241**/\r
2242EFI_STATUS\r
2243UpdateDeletePage (\r
2244 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,\r
2245 IN CHAR16 *VariableName,\r
2246 IN EFI_GUID *VendorGuid,\r
2247 IN UINT16 LabelNumber,\r
2248 IN EFI_FORM_ID FormId,\r
2249 IN EFI_QUESTION_ID QuestionIdBase\r
2250 )\r
2251{\r
2252 EFI_STATUS Status;\r
2253 UINT32 Index;\r
2254 UINTN CertCount;\r
2255 UINTN GuidIndex;\r
2256 VOID *StartOpCodeHandle;\r
2257 VOID *EndOpCodeHandle;\r
2258 EFI_IFR_GUID_LABEL *StartLabel;\r
20333c6d 2259 EFI_IFR_GUID_LABEL *EndLabel;\r
ecc722ad 2260 UINTN DataSize;\r
2261 UINT8 *Data;\r
2262 EFI_SIGNATURE_LIST *CertList;\r
2263 EFI_SIGNATURE_DATA *Cert;\r
2264 UINT32 ItemDataSize;\r
2265 CHAR16 *GuidStr;\r
2266 EFI_STRING_ID GuidID;\r
2267 EFI_STRING_ID Help;\r
2268\r
2269 Data = NULL;\r
2270 CertList = NULL;\r
2271 Cert = NULL;\r
2272 GuidStr = NULL;\r
2273 StartOpCodeHandle = NULL;\r
2274 EndOpCodeHandle = NULL;\r
20333c6d 2275\r
ecc722ad 2276 //\r
2277 // Initialize the container for dynamic opcodes.\r
2278 //\r
2279 StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2280 if (StartOpCodeHandle == NULL) {\r
2281 Status = EFI_OUT_OF_RESOURCES;\r
20333c6d 2282 goto ON_EXIT;\r
ecc722ad 2283 }\r
2284\r
2285 EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2286 if (EndOpCodeHandle == NULL) {\r
2287 Status = EFI_OUT_OF_RESOURCES;\r
20333c6d 2288 goto ON_EXIT;\r
ecc722ad 2289 }\r
2290\r
2291 //\r
2292 // Create Hii Extend Label OpCode.\r
2293 //\r
2294 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2295 StartOpCodeHandle,\r
2296 &gEfiIfrTianoGuid,\r
2297 NULL,\r
2298 sizeof (EFI_IFR_GUID_LABEL)\r
2299 );\r
2300 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
2301 StartLabel->Number = LabelNumber;\r
2302\r
2303 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2304 EndOpCodeHandle,\r
2305 &gEfiIfrTianoGuid,\r
2306 NULL,\r
2307 sizeof (EFI_IFR_GUID_LABEL)\r
2308 );\r
2309 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
2310 EndLabel->Number = LABEL_END;\r
2311\r
2312 //\r
2313 // Read Variable.\r
2314 //\r
2315 DataSize = 0;\r
20333c6d 2316 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);\r
ecc722ad 2317 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2318 goto ON_EXIT;\r
2319 }\r
2320\r
2321 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
2322 if (Data == NULL) {\r
2323 Status = EFI_OUT_OF_RESOURCES;\r
2324 goto ON_EXIT;\r
2325 }\r
2326\r
2327 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);\r
2328 if (EFI_ERROR (Status)) {\r
2329 goto ON_EXIT;\r
2330 }\r
2331\r
2332 GuidStr = AllocateZeroPool (100);\r
2333 if (GuidStr == NULL) {\r
2334 Status = EFI_OUT_OF_RESOURCES;\r
2335 goto ON_EXIT;\r
2336 }\r
2337\r
2338 //\r
2339 // Enumerate all KEK pub data.\r
2340 //\r
2341 ItemDataSize = (UINT32) DataSize;\r
2342 CertList = (EFI_SIGNATURE_LIST *) Data;\r
2343 GuidIndex = 0;\r
2344\r
2345 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {\r
2346\r
2347 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {\r
2348 Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);\r
2349 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2350 Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);\r
2351 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {\r
2352 Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);\r
2353 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {\r
2354 Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);\r
20333c6d
QL
2355 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
2356 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);\r
2357 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
2358 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);\r
2359 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
2360 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);\r
ecc722ad 2361 } else {\r
2362 //\r
2363 // The signature type is not supported in current implementation.\r
2364 //\r
b7d269ea 2365 ItemDataSize -= CertList->SignatureListSize;\r
2366 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
ecc722ad 2367 continue;\r
2368 }\r
2369\r
2370 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2371 for (Index = 0; Index < CertCount; Index++) {\r
20333c6d
QL
2372 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList\r
2373 + sizeof (EFI_SIGNATURE_LIST)\r
2374 + CertList->SignatureHeaderSize\r
ecc722ad 2375 + Index * CertList->SignatureSize);\r
2376 //\r
20333c6d 2377 // Display GUID and help\r
ecc722ad 2378 //\r
2379 GuidToString (&Cert->SignatureOwner, GuidStr, 100);\r
2380 GuidID = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);\r
2381 HiiCreateCheckBoxOpCode (\r
2382 StartOpCodeHandle,\r
2383 (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),\r
20333c6d
QL
2384 0,\r
2385 0,\r
2386 GuidID,\r
ecc722ad 2387 Help,\r
2388 EFI_IFR_FLAG_CALLBACK,\r
2389 0,\r
2390 NULL\r
20333c6d 2391 );\r
ecc722ad 2392 }\r
2393\r
2394 ItemDataSize -= CertList->SignatureListSize;\r
2395 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2396 }\r
2397\r
2398ON_EXIT:\r
2399 HiiUpdateForm (\r
2400 PrivateData->HiiHandle,\r
2401 &gSecureBootConfigFormSetGuid,\r
2402 FormId,\r
2403 StartOpCodeHandle,\r
2404 EndOpCodeHandle\r
2405 );\r
2406\r
2407 if (StartOpCodeHandle != NULL) {\r
2408 HiiFreeOpCodeHandle (StartOpCodeHandle);\r
2409 }\r
2410\r
2411 if (EndOpCodeHandle != NULL) {\r
2412 HiiFreeOpCodeHandle (EndOpCodeHandle);\r
2413 }\r
20333c6d 2414\r
ecc722ad 2415 if (Data != NULL) {\r
2416 FreePool (Data);\r
2417 }\r
2418\r
2419 if (GuidStr != NULL) {\r
2420 FreePool (GuidStr);\r
2421 }\r
2422\r
2423 return EFI_SUCCESS;\r
2424}\r
2425\r
beda2356 2426/**\r
20333c6d 2427 Delete a KEK entry from KEK database.\r
beda2356 2428\r
ecc722ad 2429 @param[in] PrivateData Module's private data.\r
2430 @param[in] QuestionId Question id of the KEK item to delete.\r
beda2356 2431\r
ecc722ad 2432 @retval EFI_SUCCESS Delete kek item successfully.\r
2433 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
20333c6d 2434\r
ecc722ad 2435**/\r
2436EFI_STATUS\r
2437DeleteKeyExchangeKey (\r
2438 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,\r
2439 IN EFI_QUESTION_ID QuestionId\r
2440 )\r
2441{\r
2442 EFI_STATUS Status;\r
2443 UINTN DataSize;\r
2444 UINT8 *Data;\r
2445 UINT8 *OldData;\r
2446 UINT32 Attr;\r
2447 UINT32 Index;\r
2448 EFI_SIGNATURE_LIST *CertList;\r
2449 EFI_SIGNATURE_LIST *NewCertList;\r
2450 EFI_SIGNATURE_DATA *Cert;\r
2451 UINTN CertCount;\r
2452 UINT32 Offset;\r
2453 BOOLEAN IsKEKItemFound;\r
2454 UINT32 KekDataSize;\r
2455 UINTN DeleteKekIndex;\r
2456 UINTN GuidIndex;\r
2457\r
2458 Data = NULL;\r
2459 OldData = NULL;\r
2460 CertList = NULL;\r
2461 Cert = NULL;\r
20333c6d 2462 Attr = 0;\r
ecc722ad 2463 DeleteKekIndex = QuestionId - OPTION_DEL_KEK_QUESTION_ID;\r
f71ed839 2464\r
2465 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
2466 if (EFI_ERROR (Status)) {\r
2467 return Status;\r
2468 }\r
20333c6d 2469\r
ecc722ad 2470 //\r
2471 // Get original KEK variable.\r
20333c6d
QL
2472 //\r
2473 DataSize = 0;\r
ecc722ad 2474 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);\r
2475 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2476 goto ON_EXIT;\r
2477 }\r
2478\r
2479 OldData = (UINT8*)AllocateZeroPool(DataSize);\r
2480 if (OldData == NULL) {\r
20333c6d 2481 Status = EFI_OUT_OF_RESOURCES;\r
ecc722ad 2482 goto ON_EXIT;\r
2483 }\r
2484\r
2485 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);\r
2486 if (EFI_ERROR(Status)) {\r
2487 goto ON_EXIT;\r
2488 }\r
2489\r
2490 //\r
20333c6d 2491 // Allocate space for new variable.\r
ecc722ad 2492 //\r
2493 Data = (UINT8*) AllocateZeroPool (DataSize);\r
2494 if (Data == NULL) {\r
2495 Status = EFI_OUT_OF_RESOURCES;\r
2496 goto ON_EXIT;\r
2497 }\r
2498\r
2499 //\r
2500 // Enumerate all KEK pub data and erasing the target item.\r
2501 //\r
2502 IsKEKItemFound = FALSE;\r
2503 KekDataSize = (UINT32) DataSize;\r
2504 CertList = (EFI_SIGNATURE_LIST *) OldData;\r
2505 Offset = 0;\r
2506 GuidIndex = 0;\r
2507 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2508 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||\r
2509 CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2510 CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));\r
2511 NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);\r
2512 Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2513 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2514 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2515 for (Index = 0; Index < CertCount; Index++) {\r
2516 if (GuidIndex == DeleteKekIndex ) {\r
2517 //\r
2518 // Find it! Skip it!\r
2519 //\r
2520 NewCertList->SignatureListSize -= CertList->SignatureSize;\r
20333c6d 2521 IsKEKItemFound = TRUE;\r
ecc722ad 2522 } else {\r
2523 //\r
2524 // This item doesn't match. Copy it to the Data buffer.\r
2525 //\r
2526 CopyMem (Data + Offset, Cert, CertList->SignatureSize);\r
2527 Offset += CertList->SignatureSize;\r
2528 }\r
2529 GuidIndex++;\r
2530 Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);\r
2531 }\r
2532 } else {\r
2533 //\r
2534 // This List doesn't match. Copy it to the Data buffer.\r
2535 //\r
2536 CopyMem (Data + Offset, CertList, CertList->SignatureListSize);\r
2537 Offset += CertList->SignatureListSize;\r
2538 }\r
20333c6d 2539\r
ecc722ad 2540 KekDataSize -= CertList->SignatureListSize;\r
2541 CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);\r
2542 }\r
2543\r
2544 if (!IsKEKItemFound) {\r
2545 //\r
2546 // Doesn't find the Kek Item!\r
2547 //\r
2548 Status = EFI_NOT_FOUND;\r
2549 goto ON_EXIT;\r
2550 }\r
2551\r
2552 //\r
2553 // Delete the Signature header if there is no signature in the list.\r
2554 //\r
2555 KekDataSize = Offset;\r
2556 CertList = (EFI_SIGNATURE_LIST*) Data;\r
2557 Offset = 0;\r
2558 ZeroMem (OldData, KekDataSize);\r
2559 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2560 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
33985e3b 2561 DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));\r
ecc722ad 2562 if (CertCount != 0) {\r
2563 CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);\r
2564 Offset += CertList->SignatureListSize;\r
20333c6d 2565 }\r
ecc722ad 2566 KekDataSize -= CertList->SignatureListSize;\r
2567 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2568 }\r
2569\r
ecc722ad 2570 DataSize = Offset;\r
8c1babfd 2571 if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2572 Status = CreateTimeBasedPayload (&DataSize, &OldData);\r
2573 if (EFI_ERROR (Status)) {\r
2574 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2575 goto ON_EXIT;\r
2576 }\r
2577 }\r
ecc722ad 2578\r
2579 Status = gRT->SetVariable(\r
20333c6d
QL
2580 EFI_KEY_EXCHANGE_KEY_NAME,\r
2581 &gEfiGlobalVariableGuid,\r
2582 Attr,\r
2583 DataSize,\r
ecc722ad 2584 OldData\r
2585 );\r
2586 if (EFI_ERROR (Status)) {\r
2587 DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));\r
2588 goto ON_EXIT;\r
2589 }\r
20333c6d 2590\r
ecc722ad 2591ON_EXIT:\r
2592 if (Data != NULL) {\r
2593 FreePool(Data);\r
2594 }\r
2595\r
2596 if (OldData != NULL) {\r
2597 FreePool(OldData);\r
2598 }\r
2599\r
2600 return UpdateDeletePage (\r
20333c6d 2601 PrivateData,\r
ecc722ad 2602 EFI_KEY_EXCHANGE_KEY_NAME,\r
2603 &gEfiGlobalVariableGuid,\r
2604 LABEL_KEK_DELETE,\r
2605 FORMID_DELETE_KEK_FORM,\r
2606 OPTION_DEL_KEK_QUESTION_ID\r
2607 );\r
2608}\r
2609\r
2610/**\r
2611 Delete a signature entry from siganture database.\r
beda2356 2612\r
ecc722ad 2613 @param[in] PrivateData Module's private data.\r
2614 @param[in] VariableName The variable name of the vendor's signature database.\r
2615 @param[in] VendorGuid A unique identifier for the vendor.\r
2616 @param[in] LabelNumber Label number to insert opcodes.\r
2617 @param[in] FormId Form ID of current page.\r
2618 @param[in] QuestionIdBase Base question id of the signature list.\r
2619 @param[in] DeleteIndex Signature index to delete.\r
20333c6d 2620\r
ecc722ad 2621 @retval EFI_SUCCESS Delete siganture successfully.\r
2622 @retval EFI_NOT_FOUND Can't find the signature item,\r
2623 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
beda2356 2624**/\r
2625EFI_STATUS\r
ecc722ad 2626DeleteSignature (\r
2627 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,\r
2628 IN CHAR16 *VariableName,\r
2629 IN EFI_GUID *VendorGuid,\r
2630 IN UINT16 LabelNumber,\r
2631 IN EFI_FORM_ID FormId,\r
2632 IN EFI_QUESTION_ID QuestionIdBase,\r
2633 IN UINTN DeleteIndex\r
beda2356 2634 )\r
2635{\r
ecc722ad 2636 EFI_STATUS Status;\r
2637 UINTN DataSize;\r
2638 UINT8 *Data;\r
2639 UINT8 *OldData;\r
2640 UINT32 Attr;\r
2641 UINT32 Index;\r
2642 EFI_SIGNATURE_LIST *CertList;\r
2643 EFI_SIGNATURE_LIST *NewCertList;\r
2644 EFI_SIGNATURE_DATA *Cert;\r
2645 UINTN CertCount;\r
2646 UINT32 Offset;\r
2647 BOOLEAN IsItemFound;\r
2648 UINT32 ItemDataSize;\r
2649 UINTN GuidIndex;\r
bc0c99b3 2650\r
ecc722ad 2651 Data = NULL;\r
2652 OldData = NULL;\r
2653 CertList = NULL;\r
2654 Cert = NULL;\r
20333c6d 2655 Attr = 0;\r
ecc722ad 2656\r
f71ed839 2657 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
2658 if (EFI_ERROR (Status)) {\r
2659 return Status;\r
2660 }\r
2661\r
ecc722ad 2662 //\r
2663 // Get original signature list data.\r
20333c6d 2664 //\r
ecc722ad 2665 DataSize = 0;\r
2666 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);\r
2667 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2668 goto ON_EXIT;\r
2669 }\r
2670\r
2671 OldData = (UINT8 *) AllocateZeroPool (DataSize);\r
2672 if (OldData == NULL) {\r
20333c6d 2673 Status = EFI_OUT_OF_RESOURCES;\r
ecc722ad 2674 goto ON_EXIT;\r
2675 }\r
2676\r
2677 Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData);\r
2678 if (EFI_ERROR(Status)) {\r
2679 goto ON_EXIT;\r
20333c6d 2680 }\r
ecc722ad 2681\r
2682 //\r
20333c6d 2683 // Allocate space for new variable.\r
ecc722ad 2684 //\r
2685 Data = (UINT8*) AllocateZeroPool (DataSize);\r
2686 if (Data == NULL) {\r
2687 Status = EFI_OUT_OF_RESOURCES;\r
2688 goto ON_EXIT;\r
2689 }\r
2690\r
2691 //\r
2692 // Enumerate all signature data and erasing the target item.\r
2693 //\r
2694 IsItemFound = FALSE;\r
2695 ItemDataSize = (UINT32) DataSize;\r
2696 CertList = (EFI_SIGNATURE_LIST *) OldData;\r
2697 Offset = 0;\r
2698 GuidIndex = 0;\r
2699 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {\r
2700 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||\r
2701 CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid) ||\r
2702 CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid) ||\r
20333c6d
QL
2703 CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid) ||\r
2704 CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid) ||\r
2705 CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid) ||\r
2706 CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)\r
ecc722ad 2707 ) {\r
2708 //\r
2709 // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list.\r
2710 //\r
2711 CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));\r
2712 NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset);\r
2713 Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2714 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2715 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2716 for (Index = 0; Index < CertCount; Index++) {\r
2717 if (GuidIndex == DeleteIndex) {\r
2718 //\r
2719 // Find it! Skip it!\r
2720 //\r
2721 NewCertList->SignatureListSize -= CertList->SignatureSize;\r
20333c6d 2722 IsItemFound = TRUE;\r
ecc722ad 2723 } else {\r
2724 //\r
2725 // This item doesn't match. Copy it to the Data buffer.\r
2726 //\r
2727 CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize);\r
2728 Offset += CertList->SignatureSize;\r
2729 }\r
2730 GuidIndex++;\r
2731 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
2732 }\r
2733 } else {\r
2734 //\r
2735 // This List doesn't match. Just copy it to the Data buffer.\r
2736 //\r
2737 CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize);\r
2738 Offset += CertList->SignatureListSize;\r
2739 }\r
20333c6d 2740\r
ecc722ad 2741 ItemDataSize -= CertList->SignatureListSize;\r
2742 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2743 }\r
2744\r
2745 if (!IsItemFound) {\r
2746 //\r
2747 // Doesn't find the signature Item!\r
2748 //\r
2749 Status = EFI_NOT_FOUND;\r
2750 goto ON_EXIT;\r
2751 }\r
2752\r
2753 //\r
2754 // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list.\r
2755 //\r
2756 ItemDataSize = Offset;\r
2757 CertList = (EFI_SIGNATURE_LIST *) Data;\r
2758 Offset = 0;\r
2759 ZeroMem (OldData, ItemDataSize);\r
2760 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {\r
2761 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
33985e3b 2762 DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));\r
ecc722ad 2763 if (CertCount != 0) {\r
2764 CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize);\r
2765 Offset += CertList->SignatureListSize;\r
20333c6d 2766 }\r
ecc722ad 2767 ItemDataSize -= CertList->SignatureListSize;\r
2768 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2769 }\r
2770\r
ecc722ad 2771 DataSize = Offset;\r
8c1babfd 2772 if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2773 Status = CreateTimeBasedPayload (&DataSize, &OldData);\r
2774 if (EFI_ERROR (Status)) {\r
2775 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2776 goto ON_EXIT;\r
2777 }\r
2778 }\r
ecc722ad 2779\r
2780 Status = gRT->SetVariable(\r
20333c6d
QL
2781 VariableName,\r
2782 VendorGuid,\r
2783 Attr,\r
2784 DataSize,\r
ecc722ad 2785 OldData\r
2786 );\r
beda2356 2787 if (EFI_ERROR (Status)) {\r
ecc722ad 2788 DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));\r
2789 goto ON_EXIT;\r
beda2356 2790 }\r
20333c6d 2791\r
ecc722ad 2792ON_EXIT:\r
2793 if (Data != NULL) {\r
2794 FreePool(Data);\r
2795 }\r
2796\r
2797 if (OldData != NULL) {\r
2798 FreePool(OldData);\r
2799 }\r
2800\r
2801 return UpdateDeletePage (\r
20333c6d 2802 PrivateData,\r
ecc722ad 2803 VariableName,\r
2804 VendorGuid,\r
2805 LabelNumber,\r
2806 FormId,\r
2807 QuestionIdBase\r
2808 );\r
2809}\r
2810\r
2811/**\r
2812 This function extracts configuration from variable.\r
20333c6d 2813\r
ecc722ad 2814 @param[in, out] ConfigData Point to SecureBoot configuration private data.\r
2815\r
2816**/\r
2817VOID\r
2818SecureBootExtractConfigFromVariable (\r
2819 IN OUT SECUREBOOT_CONFIGURATION *ConfigData\r
20333c6d 2820 )\r
ecc722ad 2821{\r
20333c6d
QL
2822 UINT8 *SecureBootEnable;\r
2823 UINT8 *SetupMode;\r
2824 UINT8 *SecureBootMode;\r
2825 EFI_TIME CurrTime;\r
ecc722ad 2826\r
2827 SecureBootEnable = NULL;\r
2828 SetupMode = NULL;\r
2829 SecureBootMode = NULL;\r
20333c6d
QL
2830\r
2831 //\r
2832 // Initilize the Date and Time using system time.\r
2833 //\r
2834 ConfigData->CertificateFormat = HASHALG_RAW;\r
2835 ConfigData->AlwaysRevocation = TRUE;\r
2836 gRT->GetTime (&CurrTime, NULL);\r
2837 ConfigData->RevocationDate.Year = CurrTime.Year;\r
2838 ConfigData->RevocationDate.Month = CurrTime.Month;\r
2839 ConfigData->RevocationDate.Day = CurrTime.Day;\r
2840 ConfigData->RevocationTime.Hour = CurrTime.Hour;\r
2841 ConfigData->RevocationTime.Minute = CurrTime.Minute;\r
2842 ConfigData->RevocationTime.Second = 0;\r
2843\r
ecc722ad 2844 //\r
2845 // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable\r
2846 // Checkbox.\r
2847 //\r
f71ed839 2848 ConfigData->AttemptSecureBoot = FALSE;\r
8f8ca22e 2849 GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
ecc722ad 2850 if (SecureBootEnable == NULL) {\r
2851 ConfigData->HideSecureBoot = TRUE;\r
2852 } else {\r
2853 ConfigData->HideSecureBoot = FALSE;\r
f71ed839 2854 if ((*SecureBootEnable) == SECURE_BOOT_ENABLE) {\r
2855 ConfigData->AttemptSecureBoot = TRUE;\r
2856 }\r
ecc722ad 2857 }\r
20333c6d 2858\r
ecc722ad 2859 //\r
2860 // If it is Physical Presence User, set the PhysicalPresent to true.\r
2861 //\r
2862 if (UserPhysicalPresent()) {\r
2863 ConfigData->PhysicalPresent = TRUE;\r
2864 } else {\r
2865 ConfigData->PhysicalPresent = FALSE;\r
2866 }\r
20333c6d 2867\r
ecc722ad 2868 //\r
2869 // If there is no PK then the Delete Pk button will be gray.\r
2870 //\r
f01b91ae 2871 GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);\r
8f8ca22e 2872 if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {\r
ecc722ad 2873 ConfigData->HasPk = FALSE;\r
2874 } else {\r
2875 ConfigData->HasPk = TRUE;\r
2876 }\r
2877\r
2878 //\r
2879 // Get the SecureBootMode from CustomMode variable.\r
2880 //\r
f01b91ae 2881 GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);\r
ecc722ad 2882 if (SecureBootMode == NULL) {\r
2883 ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;\r
2884 } else {\r
2885 ConfigData->SecureBootMode = *(SecureBootMode);\r
2886 }\r
f71ed839 2887\r
2888 if (SecureBootEnable != NULL) {\r
2889 FreePool (SecureBootEnable);\r
2890 }\r
2891 if (SetupMode != NULL) {\r
2892 FreePool (SetupMode);\r
2893 }\r
2894 if (SecureBootMode != NULL) {\r
2895 FreePool (SecureBootMode);\r
2896 }\r
beda2356 2897}\r
2898\r
2899/**\r
2900 This function allows a caller to extract the current configuration for one\r
2901 or more named elements from the target driver.\r
2902\r
2903 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
2904 @param[in] Request A null-terminated Unicode string in\r
2905 <ConfigRequest> format.\r
2906 @param[out] Progress On return, points to a character in the Request\r
2907 string. Points to the string's null terminator if\r
2908 request was successful. Points to the most recent\r
2909 '&' before the first failing name/value pair (or\r
2910 the beginning of the string if the failure is in\r
2911 the first name/value pair) if the request was not\r
2912 successful.\r
2913 @param[out] Results A null-terminated Unicode string in\r
2914 <ConfigAltResp> format which has all values filled\r
2915 in for the names in the Request string. String to\r
2916 be allocated by the called function.\r
2917\r
2918 @retval EFI_SUCCESS The Results is filled with the requested values.\r
2919 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.\r
2920 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.\r
2921 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this\r
2922 driver.\r
2923\r
2924**/\r
2925EFI_STATUS\r
2926EFIAPI\r
2927SecureBootExtractConfig (\r
2928 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
2929 IN CONST EFI_STRING Request,\r
2930 OUT EFI_STRING *Progress,\r
2931 OUT EFI_STRING *Results\r
2932 )\r
2933{\r
2934 EFI_STATUS Status;\r
2935 UINTN BufferSize;\r
bc0c99b3 2936 UINTN Size;\r
beda2356 2937 SECUREBOOT_CONFIGURATION Configuration;\r
beda2356 2938 EFI_STRING ConfigRequest;\r
bc0c99b3 2939 EFI_STRING ConfigRequestHdr;\r
bc0c99b3 2940 SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;\r
2941 BOOLEAN AllocatedRequest;\r
f71ed839 2942 UINT8 *SecureBoot;\r
bc0c99b3 2943\r
beda2356 2944 if (Progress == NULL || Results == NULL) {\r
2945 return EFI_INVALID_PARAMETER;\r
2946 }\r
20333c6d 2947\r
bc0c99b3 2948 AllocatedRequest = FALSE;\r
2949 ConfigRequestHdr = NULL;\r
2950 ConfigRequest = NULL;\r
2951 Size = 0;\r
f71ed839 2952 SecureBoot = NULL;\r
20333c6d 2953\r
ea71453f 2954 ZeroMem (&Configuration, sizeof (Configuration));\r
bc0c99b3 2955 PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);\r
2956 *Progress = Request;\r
20333c6d 2957\r
beda2356 2958 if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {\r
2959 return EFI_NOT_FOUND;\r
2960 }\r
2961\r
beda2356 2962 //\r
ecc722ad 2963 // Get Configuration from Variable.\r
beda2356 2964 //\r
ecc722ad 2965 SecureBootExtractConfigFromVariable (&Configuration);\r
f71ed839 2966\r
2967 //\r
2968 // Update current secure boot state.\r
2969 //\r
2970 GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);\r
2971 if (SecureBoot != NULL && *SecureBoot == SECURE_BOOT_MODE_ENABLE) {\r
2972 HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);\r
2973 } else {\r
2974 HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);\r
2975 }\r
2976 if (SecureBoot != NULL) {\r
2977 FreePool (SecureBoot);\r
2978 }\r
20333c6d 2979\r
bc0c99b3 2980 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);\r
beda2356 2981 ConfigRequest = Request;\r
bc0c99b3 2982 if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
2983 //\r
2984 // Request is set to NULL or OFFSET is NULL, construct full request string.\r
bc0c99b3 2985 //\r
2986 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
2987 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
2988 //\r
2989 ConfigRequestHdr = HiiConstructConfigHdr (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, PrivateData->DriverHandle);\r
2990 Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
2991 ConfigRequest = AllocateZeroPool (Size);\r
2992 ASSERT (ConfigRequest != NULL);\r
2993 AllocatedRequest = TRUE;\r
2994 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
2995 FreePool (ConfigRequestHdr);\r
2996 ConfigRequestHdr = NULL;\r
2997 }\r
beda2356 2998\r
2999 Status = gHiiConfigRouting->BlockToConfig (\r
3000 gHiiConfigRouting,\r
3001 ConfigRequest,\r
3002 (UINT8 *) &Configuration,\r
3003 BufferSize,\r
3004 Results,\r
3005 Progress\r
3006 );\r
bc0c99b3 3007\r
3008 //\r
3009 // Free the allocated config request string.\r
3010 //\r
3011 if (AllocatedRequest) {\r
3012 FreePool (ConfigRequest);\r
3013 }\r
3014\r
beda2356 3015 //\r
3016 // Set Progress string to the original request string.\r
3017 //\r
3018 if (Request == NULL) {\r
3019 *Progress = NULL;\r
3020 } else if (StrStr (Request, L"OFFSET") == NULL) {\r
3021 *Progress = Request + StrLen (Request);\r
3022 }\r
3023\r
3024 return Status;\r
3025}\r
3026\r
3027/**\r
3028 This function processes the results of changes in configuration.\r
3029\r
3030 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
3031 @param[in] Configuration A null-terminated Unicode string in <ConfigResp>\r
3032 format.\r
3033 @param[out] Progress A pointer to a string filled in with the offset of\r
3034 the most recent '&' before the first failing\r
3035 name/value pair (or the beginning of the string if\r
3036 the failure is in the first name/value pair) or\r
3037 the terminating NULL if all was successful.\r
3038\r
3039 @retval EFI_SUCCESS The Results is processed successfully.\r
3040 @retval EFI_INVALID_PARAMETER Configuration is NULL.\r
3041 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this\r
3042 driver.\r
3043\r
3044**/\r
3045EFI_STATUS\r
3046EFIAPI\r
3047SecureBootRouteConfig (\r
3048 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
3049 IN CONST EFI_STRING Configuration,\r
3050 OUT EFI_STRING *Progress\r
3051 )\r
3052{\r
a2f2c258 3053 UINT8 *SecureBootEnable;\r
3054 SECUREBOOT_CONFIGURATION IfrNvData;\r
3055 UINTN BufferSize;\r
3056 EFI_STATUS Status;\r
20333c6d 3057\r
beda2356 3058 if (Configuration == NULL || Progress == NULL) {\r
3059 return EFI_INVALID_PARAMETER;\r
3060 }\r
3061\r
3062 *Progress = Configuration;\r
3063 if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {\r
3064 return EFI_NOT_FOUND;\r
3065 }\r
3066\r
a365eed4
FS
3067 //\r
3068 // Get Configuration from Variable.\r
3069 //\r
3070 SecureBootExtractConfigFromVariable (&IfrNvData);\r
3071\r
3072 //\r
3073 // Map the Configuration to the configuration block.\r
3074 //\r
a2f2c258 3075 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);\r
3076 Status = gHiiConfigRouting->ConfigToBlock (\r
3077 gHiiConfigRouting,\r
3078 Configuration,\r
3079 (UINT8 *)&IfrNvData,\r
3080 &BufferSize,\r
3081 Progress\r
3082 );\r
3083 if (EFI_ERROR (Status)) {\r
3084 return Status;\r
3085 }\r
3086\r
3087 //\r
3088 // Store Buffer Storage back to EFI variable if needed\r
3089 //\r
3090 SecureBootEnable = NULL;\r
3091 GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
3092 if (NULL != SecureBootEnable) {\r
3093 FreePool (SecureBootEnable);\r
3094 Status = SaveSecureBootVariable (IfrNvData.AttemptSecureBoot);\r
3095 if (EFI_ERROR (Status)) {\r
3096 return Status;\r
3097 }\r
3098 }\r
3099\r
ecc722ad 3100 *Progress = Configuration + StrLen (Configuration);\r
beda2356 3101 return EFI_SUCCESS;\r
3102}\r
3103\r
3104/**\r
ecc722ad 3105 This function is called to provide results data to the driver.\r
beda2356 3106\r
3107 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
3108 @param[in] Action Specifies the type of action taken by the browser.\r
3109 @param[in] QuestionId A unique value which is sent to the original\r
3110 exporting driver so that it can identify the type\r
3111 of data to expect.\r
3112 @param[in] Type The type of value for the question.\r
3113 @param[in] Value A pointer to the data being sent to the original\r
3114 exporting driver.\r
3115 @param[out] ActionRequest On return, points to the action requested by the\r
3116 callback function.\r
3117\r
3118 @retval EFI_SUCCESS The callback successfully handled the action.\r
3119 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
3120 variable and its data.\r
3121 @retval EFI_DEVICE_ERROR The variable could not be saved.\r
3122 @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
3123 callback.\r
3124\r
3125**/\r
3126EFI_STATUS\r
3127EFIAPI\r
3128SecureBootCallback (\r
3129 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
3130 IN EFI_BROWSER_ACTION Action,\r
3131 IN EFI_QUESTION_ID QuestionId,\r
3132 IN UINT8 Type,\r
3133 IN EFI_IFR_TYPE_VALUE *Value,\r
3134 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
3135 )\r
3136{\r
ecc722ad 3137 EFI_INPUT_KEY Key;\r
20333c6d 3138 EFI_STATUS Status;\r
ecc722ad 3139 SECUREBOOT_CONFIG_PRIVATE_DATA *Private;\r
3140 UINTN BufferSize;\r
3141 SECUREBOOT_CONFIGURATION *IfrNvData;\r
3142 UINT16 LabelId;\r
bf4a3dbd 3143 UINT8 *SecureBootEnable;\r
f71ed839 3144 UINT8 *SecureBootMode;\r
3145 UINT8 *SetupMode;\r
e4d7370d 3146 CHAR16 PromptString[100];\r
bf4a3dbd
ED
3147\r
3148 SecureBootEnable = NULL;\r
f71ed839 3149 SecureBootMode = NULL;\r
3150 SetupMode = NULL;\r
bc0c99b3 3151\r
beda2356 3152 if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {\r
3153 return EFI_INVALID_PARAMETER;\r
3154 }\r
3155\r
a365eed4
FS
3156 if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {\r
3157 if (QuestionId == KEY_SECURE_BOOT_MODE) {\r
3158 mIsEnterSecureBootForm = TRUE;\r
3159 }\r
3160\r
3161 return EFI_SUCCESS;\r
3162 }\r
20333c6d 3163\r
a365eed4
FS
3164 if (Action == EFI_BROWSER_ACTION_RETRIEVE) {\r
3165 Status = EFI_UNSUPPORTED;\r
3166 if (QuestionId == KEY_SECURE_BOOT_MODE) {\r
3167 if (mIsEnterSecureBootForm) {\r
3168 Value->u8 = SECURE_BOOT_MODE_STANDARD;\r
3169 Status = EFI_SUCCESS;\r
3170 }\r
3171 }\r
3172 return Status;\r
3173 }\r
20333c6d 3174\r
f71ed839 3175 if ((Action != EFI_BROWSER_ACTION_CHANGED) &&\r
3176 (Action != EFI_BROWSER_ACTION_CHANGING) &&\r
a2f2c258 3177 (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&\r
3178 (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {\r
beda2356 3179 return EFI_UNSUPPORTED;\r
3180 }\r
20333c6d 3181\r
ecc722ad 3182 Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);\r
bc0c99b3 3183\r
ecc722ad 3184 //\r
3185 // Retrieve uncommitted data from Browser\r
3186 //\r
3187 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);\r
3188 IfrNvData = AllocateZeroPool (BufferSize);\r
3189 if (IfrNvData == NULL) {\r
3190 return EFI_OUT_OF_RESOURCES;\r
beda2356 3191 }\r
bc0c99b3 3192\r
ecc722ad 3193 Status = EFI_SUCCESS;\r
3194\r
742d9b3a 3195 HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData);\r
20333c6d 3196\r
ecc722ad 3197 if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
3198\r
3199 switch (QuestionId) {\r
3200 case KEY_SECURE_BOOT_ENABLE:\r
f01b91ae 3201 GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
bf4a3dbd 3202 if (NULL != SecureBootEnable) {\r
f71ed839 3203 FreePool (SecureBootEnable);\r
ecc722ad 3204 if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) {\r
3205 CreatePopUp (\r
3206 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3207 &Key,\r
3208 L"Only Physical Presence User could disable secure boot!",\r
3209 NULL\r
3210 );\r
3211 Status = EFI_UNSUPPORTED;\r
0357efe3 3212 } else {\r
3213 CreatePopUp (\r
3214 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3215 &Key,\r
f71ed839 3216 L"Configuration changed, please reset the platform to take effect!",\r
0357efe3 3217 NULL\r
3218 );\r
ecc722ad 3219 }\r
ecc722ad 3220 }\r
3221 break;\r
3222\r
3223 case KEY_SECURE_BOOT_OPTION:\r
3224 FreeMenu (&DirectoryMenu);\r
3225 FreeMenu (&FsOptionMenu);\r
3226 break;\r
3227\r
3228 case KEY_SECURE_BOOT_KEK_OPTION:\r
3229 case KEY_SECURE_BOOT_DB_OPTION:\r
3230 case KEY_SECURE_BOOT_DBX_OPTION:\r
20333c6d 3231 case KEY_SECURE_BOOT_DBT_OPTION:\r
ecc722ad 3232 //\r
3233 // Clear Signature GUID.\r
3234 //\r
3235 ZeroMem (IfrNvData->SignatureGuid, sizeof (IfrNvData->SignatureGuid));\r
3236 if (Private->SignatureGUID == NULL) {\r
3237 Private->SignatureGUID = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID));\r
3238 if (Private->SignatureGUID == NULL) {\r
3239 return EFI_OUT_OF_RESOURCES;\r
3240 }\r
3241 }\r
beda2356 3242\r
ecc722ad 3243 if (QuestionId == KEY_SECURE_BOOT_DB_OPTION) {\r
3244 LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;\r
3245 } else if (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) {\r
3246 LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;\r
20333c6d
QL
3247 } else if (QuestionId == KEY_SECURE_BOOT_DBT_OPTION) {\r
3248 LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;\r
ecc722ad 3249 } else {\r
3250 LabelId = FORMID_ENROLL_KEK_FORM;\r
3251 }\r
3252\r
3253 //\r
3254 // Refresh selected file.\r
3255 //\r
20333c6d 3256 CleanUpPage (LabelId, Private);\r
ecc722ad 3257 break;\r
20333c6d 3258\r
ecc722ad 3259 case SECUREBOOT_ADD_PK_FILE_FORM_ID:\r
3260 case FORMID_ENROLL_KEK_FORM:\r
3261 case SECUREBOOT_ENROLL_SIGNATURE_TO_DB:\r
3262 case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX:\r
20333c6d 3263 case SECUREBOOT_ENROLL_SIGNATURE_TO_DBT:\r
ecc722ad 3264 if (QuestionId == SECUREBOOT_ADD_PK_FILE_FORM_ID) {\r
3265 Private->FeCurrentState = FileExplorerStateEnrollPkFile;\r
3266 } else if (QuestionId == FORMID_ENROLL_KEK_FORM) {\r
3267 Private->FeCurrentState = FileExplorerStateEnrollKekFile;\r
3268 } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DB) {\r
3269 Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDb;\r
20333c6d 3270 } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DBX) {\r
ecc722ad 3271 Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbx;\r
20333c6d
QL
3272 IfrNvData->CertificateFormat = HASHALG_SHA256;\r
3273 } else {\r
3274 Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbt;\r
ecc722ad 3275 }\r
3276\r
3277 Private->FeDisplayContext = FileExplorerDisplayUnknown;\r
3278 CleanUpPage (FORM_FILE_EXPLORER_ID, Private);\r
3279 UpdateFileExplorer (Private, 0);\r
3280 break;\r
3281\r
20333c6d 3282 case KEY_SECURE_BOOT_DELETE_PK:\r
f71ed839 3283 if (Value->u8) {\r
3284 CreatePopUp (\r
3285 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3286 &Key,\r
3287 L"Are you sure you want to delete PK? Secure boot will be disabled!",\r
3288 L"Press 'Y' to delete PK and exit, 'N' to discard change and return",\r
3289 NULL\r
3290 );\r
3291 if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {\r
ecc722ad 3292 Status = DeletePlatformKey ();\r
f71ed839 3293 if (EFI_ERROR (Status)) {\r
3294 CreatePopUp (\r
3295 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3296 &Key,\r
3297 L"Only Physical Presence User could delete PK in custom mode!",\r
3298 NULL\r
3299 );\r
3300 }\r
ecc722ad 3301 }\r
f71ed839 3302 }\r
ecc722ad 3303 break;\r
3304\r
3305 case KEY_DELETE_KEK:\r
3306 UpdateDeletePage (\r
20333c6d 3307 Private,\r
ecc722ad 3308 EFI_KEY_EXCHANGE_KEY_NAME,\r
3309 &gEfiGlobalVariableGuid,\r
3310 LABEL_KEK_DELETE,\r
3311 FORMID_DELETE_KEK_FORM,\r
20333c6d 3312 OPTION_DEL_KEK_QUESTION_ID\r
ecc722ad 3313 );\r
3314 break;\r
3315\r
20333c6d 3316 case SECUREBOOT_DELETE_SIGNATURE_FROM_DB:\r
ecc722ad 3317 UpdateDeletePage (\r
3318 Private,\r
3319 EFI_IMAGE_SECURITY_DATABASE,\r
3320 &gEfiImageSecurityDatabaseGuid,\r
3321 LABEL_DB_DELETE,\r
3322 SECUREBOOT_DELETE_SIGNATURE_FROM_DB,\r
3323 OPTION_DEL_DB_QUESTION_ID\r
3324 );\r
3325 break;\r
3326\r
3327 case SECUREBOOT_DELETE_SIGNATURE_FROM_DBX:\r
3328 UpdateDeletePage (\r
3329 Private,\r
3330 EFI_IMAGE_SECURITY_DATABASE1,\r
3331 &gEfiImageSecurityDatabaseGuid,\r
3332 LABEL_DBX_DELETE,\r
3333 SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,\r
3334 OPTION_DEL_DBX_QUESTION_ID\r
3335 );\r
3336\r
3337 break;\r
3338\r
20333c6d
QL
3339 case SECUREBOOT_DELETE_SIGNATURE_FROM_DBT:\r
3340 UpdateDeletePage (\r
3341 Private,\r
3342 EFI_IMAGE_SECURITY_DATABASE2,\r
3343 &gEfiImageSecurityDatabaseGuid,\r
3344 LABEL_DBT_DELETE,\r
3345 SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,\r
3346 OPTION_DEL_DBT_QUESTION_ID\r
3347 );\r
3348\r
3349 break;\r
3350\r
ecc722ad 3351 case KEY_VALUE_SAVE_AND_EXIT_KEK:\r
3352 Status = EnrollKeyExchangeKey (Private);\r
ee79ac8d 3353 if (EFI_ERROR (Status)) {\r
3354 CreatePopUp (\r
3355 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3356 &Key,\r
3357 L"ERROR: Unsupported file type!",\r
3358 L"Only supports DER-encoded X509 certificate",\r
3359 NULL\r
3360 );\r
3361 }\r
ecc722ad 3362 break;\r
3363\r
3364 case KEY_VALUE_SAVE_AND_EXIT_DB:\r
3365 Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE);\r
ee79ac8d 3366 if (EFI_ERROR (Status)) {\r
3367 CreatePopUp (\r
3368 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3369 &Key,\r
3370 L"ERROR: Unsupported file type!",\r
3371 L"Only supports DER-encoded X509 certificate and executable EFI image",\r
3372 NULL\r
3373 );\r
3374 }\r
ecc722ad 3375 break;\r
3376\r
3377 case KEY_VALUE_SAVE_AND_EXIT_DBX:\r
20333c6d
QL
3378 if (IsX509CertInDbx (Private, EFI_IMAGE_SECURITY_DATABASE1)) {\r
3379 CreatePopUp (\r
3380 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3381 &Key,\r
3382 L"Enrollment failed! Same certificate had already been in the dbx!",\r
3383 NULL\r
3384 );\r
3385 break;\r
3386 }\r
3387\r
3388 if ((IfrNvData != NULL) && (IfrNvData->CertificateFormat < HASHALG_MAX)) {\r
3389 Status = EnrollX509HashtoSigDB (\r
3390 Private,\r
3391 IfrNvData->CertificateFormat,\r
3392 &IfrNvData->RevocationDate,\r
3393 &IfrNvData->RevocationTime,\r
3394 IfrNvData->AlwaysRevocation\r
3395 );\r
3396 } else {\r
3397 Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE1);\r
3398 }\r
ee79ac8d 3399 if (EFI_ERROR (Status)) {\r
3400 CreatePopUp (\r
3401 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3402 &Key,\r
3403 L"ERROR: Unsupported file type!",\r
3404 L"Only supports DER-encoded X509 certificate and executable EFI image",\r
3405 NULL\r
3406 );\r
3407 }\r
ecc722ad 3408 break;\r
3409\r
20333c6d
QL
3410 case KEY_VALUE_SAVE_AND_EXIT_DBT:\r
3411 Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE2);\r
3412 if (EFI_ERROR (Status)) {\r
3413 CreatePopUp (\r
3414 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3415 &Key,\r
3416 L"ERROR: Unsupported file type!",\r
3417 L"Only supports DER-encoded X509 certificate.",\r
3418 NULL\r
3419 );\r
3420 }\r
3421 break;\r
3422\r
ecc722ad 3423 default:\r
c93bcb7e 3424 if (QuestionId >= FILE_OPTION_GOTO_OFFSET) {\r
ecc722ad 3425 UpdateFileExplorer (Private, QuestionId);\r
3426 } else if ((QuestionId >= OPTION_DEL_KEK_QUESTION_ID) &&\r
3427 (QuestionId < (OPTION_DEL_KEK_QUESTION_ID + OPTION_CONFIG_RANGE))) {\r
3428 DeleteKeyExchangeKey (Private, QuestionId);\r
3429 } else if ((QuestionId >= OPTION_DEL_DB_QUESTION_ID) &&\r
3430 (QuestionId < (OPTION_DEL_DB_QUESTION_ID + OPTION_CONFIG_RANGE))) {\r
3431 DeleteSignature (\r
3432 Private,\r
3433 EFI_IMAGE_SECURITY_DATABASE,\r
3434 &gEfiImageSecurityDatabaseGuid,\r
20333c6d 3435 LABEL_DB_DELETE,\r
ecc722ad 3436 SECUREBOOT_DELETE_SIGNATURE_FROM_DB,\r
3437 OPTION_DEL_DB_QUESTION_ID,\r
3438 QuestionId - OPTION_DEL_DB_QUESTION_ID\r
3439 );\r
3440 } else if ((QuestionId >= OPTION_DEL_DBX_QUESTION_ID) &&\r
3441 (QuestionId < (OPTION_DEL_DBX_QUESTION_ID + OPTION_CONFIG_RANGE))) {\r
3442 DeleteSignature (\r
3443 Private,\r
3444 EFI_IMAGE_SECURITY_DATABASE1,\r
3445 &gEfiImageSecurityDatabaseGuid,\r
20333c6d 3446 LABEL_DBX_DELETE,\r
ecc722ad 3447 SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,\r
3448 OPTION_DEL_DBX_QUESTION_ID,\r
3449 QuestionId - OPTION_DEL_DBX_QUESTION_ID\r
3450 );\r
20333c6d
QL
3451 } else if ((QuestionId >= OPTION_DEL_DBT_QUESTION_ID) &&\r
3452 (QuestionId < (OPTION_DEL_DBT_QUESTION_ID + OPTION_CONFIG_RANGE))) {\r
3453 DeleteSignature (\r
3454 Private,\r
3455 EFI_IMAGE_SECURITY_DATABASE2,\r
3456 &gEfiImageSecurityDatabaseGuid,\r
3457 LABEL_DBT_DELETE,\r
3458 SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,\r
3459 OPTION_DEL_DBT_QUESTION_ID,\r
3460 QuestionId - OPTION_DEL_DBT_QUESTION_ID\r
3461 );\r
ecc722ad 3462 }\r
3463 break;\r
3464 }\r
3465 } else if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
3466 switch (QuestionId) {\r
3467 case KEY_SECURE_BOOT_ENABLE:\r
f71ed839 3468 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
20333c6d 3469 break;\r
ecc722ad 3470 case KEY_VALUE_SAVE_AND_EXIT_PK:\r
3471 Status = EnrollPlatformKey (Private);\r
3472 if (EFI_ERROR (Status)) {\r
ee79ac8d 3473 UnicodeSPrint (\r
3474 PromptString,\r
3475 sizeof (PromptString),\r
3476 L"Only DER encoded certificate file (%s) is supported.",\r
3477 mSupportX509Suffix\r
3478 );\r
ecc722ad 3479 CreatePopUp (\r
3480 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
3481 &Key,\r
e4d7370d 3482 L"ERROR: Unsupported file type!",\r
3483 PromptString,\r
ecc722ad 3484 NULL\r
3485 );\r
3486 } else {\r
20333c6d
QL
3487 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;\r
3488 }\r
ecc722ad 3489 break;\r
3490\r
3491 case KEY_VALUE_NO_SAVE_AND_EXIT_PK:\r
3492 case KEY_VALUE_NO_SAVE_AND_EXIT_KEK:\r
3493 case KEY_VALUE_NO_SAVE_AND_EXIT_DB:\r
3494 case KEY_VALUE_NO_SAVE_AND_EXIT_DBX:\r
20333c6d 3495 case KEY_VALUE_NO_SAVE_AND_EXIT_DBT:\r
ecc722ad 3496 if (Private->FileContext->FHandle != NULL) {\r
3497 CloseFile (Private->FileContext->FHandle);\r
3498 Private->FileContext->FHandle = NULL;\r
3499 Private->FileContext->FileName = NULL;\r
3500 }\r
20333c6d 3501\r
ecc722ad 3502 if (Private->SignatureGUID != NULL) {\r
3503 FreePool (Private->SignatureGUID);\r
3504 Private->SignatureGUID = NULL;\r
3505 }\r
3506 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
3507 break;\r
20333c6d 3508\r
ecc722ad 3509 case KEY_SECURE_BOOT_MODE:\r
a365eed4 3510 mIsEnterSecureBootForm = FALSE;\r
ecc722ad 3511 break;\r
3512\r
3513 case KEY_SECURE_BOOT_KEK_GUID:\r
3514 case KEY_SECURE_BOOT_SIGNATURE_GUID_DB:\r
3515 case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX:\r
20333c6d 3516 case KEY_SECURE_BOOT_SIGNATURE_GUID_DBT:\r
ecc722ad 3517 ASSERT (Private->SignatureGUID != NULL);\r
3518 Status = StringToGuid (\r
3519 IfrNvData->SignatureGuid,\r
3520 StrLen (IfrNvData->SignatureGuid),\r
3521 Private->SignatureGUID\r
3522 );\r
3523 if (EFI_ERROR (Status)) {\r
3524 break;\r
3525 }\r
3526\r
3527 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
3528 break;\r
3529\r
3530 case KEY_SECURE_BOOT_DELETE_PK:\r
f71ed839 3531 GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);\r
3532 if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {\r
3533 IfrNvData->DeletePk = TRUE;\r
3534 IfrNvData->HasPk = FALSE;\r
ecc722ad 3535 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
f71ed839 3536 } else {\r
3537 IfrNvData->DeletePk = FALSE;\r
3538 IfrNvData->HasPk = TRUE;\r
3539 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
3540 }\r
3541 if (SetupMode != NULL) {\r
3542 FreePool (SetupMode);\r
ecc722ad 3543 }\r
c93bcb7e
ED
3544 break;\r
3545 default:\r
3546 if (QuestionId >= FILE_OPTION_OFFSET && QuestionId < FILE_OPTION_GOTO_OFFSET) {\r
3547 if (UpdateFileExplorer (Private, QuestionId)) {\r
3548 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
3549 }\r
3550 }\r
3551 break;\r
ecc722ad 3552 }\r
a2f2c258 3553 } else if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {\r
3554 if (QuestionId == KEY_HIDE_SECURE_BOOT) {\r
3555 GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
3556 if (SecureBootEnable == NULL) {\r
3557 IfrNvData->HideSecureBoot = TRUE;\r
3558 } else {\r
3559 FreePool (SecureBootEnable);\r
3560 IfrNvData->HideSecureBoot = FALSE;\r
3561 }\r
3562 Value->b = IfrNvData->HideSecureBoot;\r
3563 }\r
f71ed839 3564 } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {\r
3565 //\r
3566 // Force the platform back to Standard Mode once user leave the setup screen.\r
3567 //\r
3568 GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);\r
3569 if (NULL != SecureBootMode && *SecureBootMode == CUSTOM_SECURE_BOOT_MODE) {\r
3570 IfrNvData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;\r
3571 SetSecureBootMode(STANDARD_SECURE_BOOT_MODE);\r
3572 }\r
3573 if (SecureBootMode != NULL) {\r
3574 FreePool (SecureBootMode);\r
3575 }\r
ecc722ad 3576 }\r
20333c6d 3577\r
ecc722ad 3578 if (!EFI_ERROR (Status)) {\r
3579 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);\r
742d9b3a 3580 HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL);\r
ecc722ad 3581 }\r
3582 FreePool (IfrNvData);\r
20333c6d 3583\r
ecc722ad 3584 return EFI_SUCCESS;\r
beda2356 3585}\r
3586\r
3587/**\r
3588 This function publish the SecureBoot configuration Form.\r
3589\r
3590 @param[in, out] PrivateData Points to SecureBoot configuration private data.\r
3591\r
ecc722ad 3592 @retval EFI_SUCCESS HII Form is installed successfully.\r
beda2356 3593 @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.\r
3594 @retval Others Other errors as indicated.\r
3595\r
3596**/\r
3597EFI_STATUS\r
3598InstallSecureBootConfigForm (\r
3599 IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData\r
3600 )\r
3601{\r
3602 EFI_STATUS Status;\r
3603 EFI_HII_HANDLE HiiHandle;\r
3604 EFI_HANDLE DriverHandle;\r
beda2356 3605 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;\r
3606\r
3607 DriverHandle = NULL;\r
3608 ConfigAccess = &PrivateData->ConfigAccess;\r
3609 Status = gBS->InstallMultipleProtocolInterfaces (\r
3610 &DriverHandle,\r
3611 &gEfiDevicePathProtocolGuid,\r
3612 &mSecureBootHiiVendorDevicePath,\r
3613 &gEfiHiiConfigAccessProtocolGuid,\r
3614 ConfigAccess,\r
3615 NULL\r
3616 );\r
3617 if (EFI_ERROR (Status)) {\r
3618 return Status;\r
3619 }\r
3620\r
3621 PrivateData->DriverHandle = DriverHandle;\r
3622\r
3623 //\r
3624 // Publish the HII package list\r
3625 //\r
3626 HiiHandle = HiiAddPackages (\r
3627 &gSecureBootConfigFormSetGuid,\r
3628 DriverHandle,\r
3629 SecureBootConfigDxeStrings,\r
3630 SecureBootConfigBin,\r
3631 NULL\r
3632 );\r
3633 if (HiiHandle == NULL) {\r
3634 gBS->UninstallMultipleProtocolInterfaces (\r
3635 DriverHandle,\r
3636 &gEfiDevicePathProtocolGuid,\r
3637 &mSecureBootHiiVendorDevicePath,\r
3638 &gEfiHiiConfigAccessProtocolGuid,\r
3639 ConfigAccess,\r
3640 NULL\r
bc0c99b3 3641 );\r
beda2356 3642 return EFI_OUT_OF_RESOURCES;\r
3643 }\r
bc0c99b3 3644\r
beda2356 3645 PrivateData->HiiHandle = HiiHandle;\r
ecc722ad 3646\r
3647 PrivateData->FileContext = AllocateZeroPool (sizeof (SECUREBOOT_FILE_CONTEXT));\r
3648 PrivateData->MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));\r
20333c6d 3649\r
ecc722ad 3650 if (PrivateData->FileContext == NULL || PrivateData->MenuEntry == NULL) {\r
3651 UninstallSecureBootConfigForm (PrivateData);\r
3652 return EFI_OUT_OF_RESOURCES;\r
3653 }\r
20333c6d 3654\r
ecc722ad 3655 PrivateData->FeCurrentState = FileExplorerStateInActive;\r
3656 PrivateData->FeDisplayContext = FileExplorerDisplayUnknown;\r
20333c6d 3657\r
ecc722ad 3658 InitializeListHead (&FsOptionMenu.Head);\r
3659 InitializeListHead (&DirectoryMenu.Head);\r
3660\r
3661 //\r
3662 // Init OpCode Handle and Allocate space for creation of Buffer\r
3663 //\r
3664 mStartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
3665 if (mStartOpCodeHandle == NULL) {\r
3666 UninstallSecureBootConfigForm (PrivateData);\r
3667 return EFI_OUT_OF_RESOURCES;\r
3668 }\r
3669\r
3670 mEndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
3671 if (mEndOpCodeHandle == NULL) {\r
3672 UninstallSecureBootConfigForm (PrivateData);\r
3673 return EFI_OUT_OF_RESOURCES;\r
3674 }\r
3675\r
3676 //\r
3677 // Create Hii Extend Label OpCode as the start opcode\r
3678 //\r
3679 mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
3680 mStartOpCodeHandle,\r
3681 &gEfiIfrTianoGuid,\r
3682 NULL,\r
3683 sizeof (EFI_IFR_GUID_LABEL)\r
3684 );\r
3685 mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
3686\r
3687 //\r
3688 // Create Hii Extend Label OpCode as the end opcode\r
3689 //\r
3690 mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
3691 mEndOpCodeHandle,\r
3692 &gEfiIfrTianoGuid,\r
3693 NULL,\r
3694 sizeof (EFI_IFR_GUID_LABEL)\r
3695 );\r
3696 mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
3697 mEndLabel->Number = LABEL_END;\r
20333c6d 3698\r
bc0c99b3 3699 return EFI_SUCCESS;\r
beda2356 3700}\r
3701\r
3702/**\r
3703 This function removes SecureBoot configuration Form.\r
3704\r
3705 @param[in, out] PrivateData Points to SecureBoot configuration private data.\r
3706\r
3707**/\r
3708VOID\r
3709UninstallSecureBootConfigForm (\r
3710 IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData\r
3711 )\r
3712{\r
3713 //\r
3714 // Uninstall HII package list\r
3715 //\r
3716 if (PrivateData->HiiHandle != NULL) {\r
3717 HiiRemovePackages (PrivateData->HiiHandle);\r
3718 PrivateData->HiiHandle = NULL;\r
3719 }\r
3720\r
3721 //\r
3722 // Uninstall HII Config Access Protocol\r
3723 //\r
3724 if (PrivateData->DriverHandle != NULL) {\r
3725 gBS->UninstallMultipleProtocolInterfaces (\r
3726 PrivateData->DriverHandle,\r
3727 &gEfiDevicePathProtocolGuid,\r
3728 &mSecureBootHiiVendorDevicePath,\r
3729 &gEfiHiiConfigAccessProtocolGuid,\r
3730 &PrivateData->ConfigAccess,\r
3731 NULL\r
3732 );\r
3733 PrivateData->DriverHandle = NULL;\r
3734 }\r
bc0c99b3 3735\r
ecc722ad 3736 if (PrivateData->SignatureGUID != NULL) {\r
3737 FreePool (PrivateData->SignatureGUID);\r
3738 }\r
3739\r
3740 if (PrivateData->MenuEntry != NULL) {\r
3741 FreePool (PrivateData->MenuEntry);\r
3742 }\r
3743\r
3744 if (PrivateData->FileContext != NULL) {\r
3745 FreePool (PrivateData->FileContext);\r
3746 }\r
3747\r
beda2356 3748 FreePool (PrivateData);\r
ecc722ad 3749\r
3750 FreeMenu (&DirectoryMenu);\r
3751 FreeMenu (&FsOptionMenu);\r
3752\r
3753 if (mStartOpCodeHandle != NULL) {\r
3754 HiiFreeOpCodeHandle (mStartOpCodeHandle);\r
3755 }\r
3756\r
3757 if (mEndOpCodeHandle != NULL) {\r
3758 HiiFreeOpCodeHandle (mEndOpCodeHandle);\r
3759 }\r
beda2356 3760}\r