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