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