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