SecurityPkg: SecureBootConfigDxe: Update CloseEnrolledFile comment
[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
4de754e1
ZC
99/**\r
100 This code cleans up enrolled file by closing file & free related resources attached to\r
9d9b8b77 101 enrolled file.\r
4de754e1 102\r
9d9b8b77 103 @param[in] FileContext FileContext cached in SecureBootConfig driver\r
4de754e1
ZC
104\r
105**/\r
4de754e1
ZC
106VOID\r
107CloseEnrolledFile(\r
108 IN SECUREBOOT_FILE_CONTEXT *FileContext\r
109)\r
110{\r
111 if (FileContext->FHandle != NULL) {\r
112 CloseFile (FileContext->FHandle);\r
113 FileContext->FHandle = NULL;\r
114 }\r
115\r
116 if (FileContext->FileName != NULL){\r
117 FreePool(FileContext->FileName);\r
118 FileContext->FileName = NULL;\r
119 }\r
120 FileContext->FileType = UNKNOWN_FILE_TYPE;\r
121\r
122}\r
123\r
e4d7370d 124/**\r
125 This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.\r
126\r
127 @param[in] FileSuffix The suffix of the input certificate file\r
128\r
129 @retval TRUE It's a DER-encoded certificate.\r
130 @retval FALSE It's NOT a DER-encoded certificate.\r
131\r
132**/\r
133BOOLEAN\r
134IsDerEncodeCertificate (\r
135 IN CONST CHAR16 *FileSuffix\r
136)\r
137{\r
20333c6d 138 UINTN Index;\r
e4d7370d 139 for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {\r
140 if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {\r
141 return TRUE;\r
142 }\r
143 }\r
144 return FALSE;\r
145}\r
ecc722ad 146\r
4de754e1
ZC
147/**\r
148 This code checks if the file content complies with EFI_VARIABLE_AUTHENTICATION_2 format\r
149The function reads file content but won't open/close given FileHandle.\r
150\r
151 @param[in] FileHandle The FileHandle to be checked\r
152\r
153 @retval TRUE The content is EFI_VARIABLE_AUTHENTICATION_2 format.\r
154 @retval FALSE The content is NOT a EFI_VARIABLE_AUTHENTICATION_2 format.\r
155\r
156**/\r
157BOOLEAN\r
158IsAuthentication2Format (\r
159 IN EFI_FILE_HANDLE FileHandle\r
160)\r
161{\r
162 EFI_STATUS Status;\r
163 EFI_VARIABLE_AUTHENTICATION_2 *Auth2;\r
164 BOOLEAN IsAuth2Format;\r
165\r
166 IsAuth2Format = FALSE;\r
167\r
168 //\r
169 // Read the whole file content\r
170 //\r
171 Status = ReadFileContent(\r
172 FileHandle,\r
173 (VOID **) &mImageBase,\r
174 &mImageSize,\r
175 0\r
176 );\r
177 if (EFI_ERROR (Status)) {\r
178 goto ON_EXIT;\r
179 }\r
180\r
181 Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)mImageBase;\r
182 if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {\r
183 goto ON_EXIT;\r
184 }\r
185\r
186 if (CompareGuid(&gEfiCertPkcs7Guid, &Auth2->AuthInfo.CertType)) {\r
187 IsAuth2Format = TRUE;\r
188 }\r
189\r
190ON_EXIT:\r
191 //\r
192 // Do not close File. simply check file content\r
193 //\r
194 if (mImageBase != NULL) {\r
195 FreePool (mImageBase);\r
196 mImageBase = NULL;\r
197 }\r
198\r
199 return IsAuth2Format;\r
200}\r
201\r
ecc722ad 202/**\r
203 Set Secure Boot option into variable space.\r
204\r
205 @param[in] VarValue The option of Secure Boot.\r
206\r
207 @retval EFI_SUCCESS The operation is finished successfully.\r
208 @retval Others Other errors as indicated.\r
209\r
210**/\r
211EFI_STATUS\r
212SaveSecureBootVariable (\r
213 IN UINT8 VarValue\r
214 )\r
215{\r
216 EFI_STATUS Status;\r
217\r
218 Status = gRT->SetVariable (\r
219 EFI_SECURE_BOOT_ENABLE_NAME,\r
220 &gEfiSecureBootEnableDisableGuid,\r
221 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
222 sizeof (UINT8),\r
223 &VarValue\r
224 );\r
225 return Status;\r
226}\r
227\r
8c1babfd 228/**\r
229 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2\r
230 descriptor with the input data. NO authentication is required in this function.\r
20333c6d 231\r
8c1babfd 232 @param[in, out] DataSize On input, the size of Data buffer in bytes.\r
233 On output, the size of data returned in Data\r
234 buffer in bytes.\r
20333c6d 235 @param[in, out] Data On input, Pointer to data buffer to be wrapped or\r
8c1babfd 236 pointer to NULL to wrap an empty payload.\r
237 On output, Pointer to the new payload date buffer allocated from pool,\r
20333c6d 238 it's caller's responsibility to free the memory when finish using it.\r
8c1babfd 239\r
240 @retval EFI_SUCCESS Create time based payload successfully.\r
241 @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.\r
242 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
243 @retval Others Unexpected error happens.\r
244\r
245**/\r
246EFI_STATUS\r
247CreateTimeBasedPayload (\r
248 IN OUT UINTN *DataSize,\r
249 IN OUT UINT8 **Data\r
250 )\r
251{\r
252 EFI_STATUS Status;\r
253 UINT8 *NewData;\r
254 UINT8 *Payload;\r
255 UINTN PayloadSize;\r
256 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;\r
257 UINTN DescriptorSize;\r
258 EFI_TIME Time;\r
20333c6d 259\r
8c1babfd 260 if (Data == NULL || DataSize == NULL) {\r
261 return EFI_INVALID_PARAMETER;\r
262 }\r
20333c6d 263\r
8c1babfd 264 //\r
20333c6d 265 // In Setup mode or Custom mode, the variable does not need to be signed but the\r
8c1babfd 266 // parameters to the SetVariable() call still need to be prepared as authenticated\r
267 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate\r
268 // data in it.\r
269 //\r
270 Payload = *Data;\r
271 PayloadSize = *DataSize;\r
20333c6d 272\r
8c1babfd 273 DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
274 NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);\r
275 if (NewData == NULL) {\r
276 return EFI_OUT_OF_RESOURCES;\r
277 }\r
278\r
279 if ((Payload != NULL) && (PayloadSize != 0)) {\r
280 CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
281 }\r
282\r
283 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);\r
284\r
285 ZeroMem (&Time, sizeof (EFI_TIME));\r
286 Status = gRT->GetTime (&Time, NULL);\r
287 if (EFI_ERROR (Status)) {\r
288 FreePool(NewData);\r
289 return Status;\r
290 }\r
291 Time.Pad1 = 0;\r
292 Time.Nanosecond = 0;\r
293 Time.TimeZone = 0;\r
294 Time.Daylight = 0;\r
295 Time.Pad2 = 0;\r
296 CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));\r
20333c6d 297\r
8c1babfd 298 DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
299 DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;\r
300 DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
301 CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);\r
20333c6d 302\r
8c1babfd 303 if (Payload != NULL) {\r
304 FreePool(Payload);\r
305 }\r
20333c6d 306\r
8c1babfd 307 *DataSize = DescriptorSize + PayloadSize;\r
308 *Data = NewData;\r
309 return EFI_SUCCESS;\r
310}\r
311\r
ecc722ad 312/**\r
313 Internal helper function to delete a Variable given its name and GUID, NO authentication\r
314 required.\r
315\r
316 @param[in] VariableName Name of the Variable.\r
317 @param[in] VendorGuid GUID of the Variable.\r
318\r
319 @retval EFI_SUCCESS Variable deleted successfully.\r
320 @retval Others The driver failed to start the device.\r
321\r
322**/\r
323EFI_STATUS\r
324DeleteVariable (\r
325 IN CHAR16 *VariableName,\r
326 IN EFI_GUID *VendorGuid\r
327 )\r
328{\r
329 EFI_STATUS Status;\r
330 VOID* Variable;\r
8c1babfd 331 UINT8 *Data;\r
332 UINTN DataSize;\r
333 UINT32 Attr;\r
ecc722ad 334\r
bf4a3dbd 335 GetVariable2 (VariableName, VendorGuid, &Variable, NULL);\r
ecc722ad 336 if (Variable == NULL) {\r
337 return EFI_SUCCESS;\r
338 }\r
f71ed839 339 FreePool (Variable);\r
ecc722ad 340\r
8c1babfd 341 Data = NULL;\r
342 DataSize = 0;\r
343 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
344 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
ecc722ad 345\r
8c1babfd 346 Status = CreateTimeBasedPayload (&DataSize, &Data);\r
347 if (EFI_ERROR (Status)) {\r
348 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
349 return Status;\r
ecc722ad 350 }\r
351\r
8c1babfd 352 Status = gRT->SetVariable (\r
353 VariableName,\r
354 VendorGuid,\r
355 Attr,\r
356 DataSize,\r
357 Data\r
358 );\r
359 if (Data != NULL) {\r
360 FreePool (Data);\r
ecc722ad 361 }\r
ecc722ad 362 return Status;\r
363}\r
364\r
f71ed839 365/**\r
366\r
367 Set the platform secure boot mode into "Custom" or "Standard" mode.\r
368\r
369 @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or\r
370 CUSTOM_SECURE_BOOT_MODE.\r
20333c6d 371\r
f71ed839 372 @return EFI_SUCCESS The platform has switched to the special mode successfully.\r
373 @return other Fail to operate the secure boot mode.\r
20333c6d 374\r
f71ed839 375**/\r
376EFI_STATUS\r
377SetSecureBootMode (\r
378 IN UINT8 SecureBootMode\r
379 )\r
380{\r
20333c6d 381 return gRT->SetVariable (\r
f71ed839 382 EFI_CUSTOM_MODE_NAME,\r
383 &gEfiCustomModeEnableGuid,\r
384 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
385 sizeof (UINT8),\r
386 &SecureBootMode\r
387 );\r
388}\r
389\r
ecc722ad 390/**\r
391 Generate the PK signature list from the X509 Certificate storing file (.cer)\r
392\r
393 @param[in] X509File FileHandle of X509 Certificate storing file.\r
394 @param[out] PkCert Point to the data buffer to store the signature list.\r
20333c6d 395\r
ecc722ad 396 @return EFI_UNSUPPORTED Unsupported Key Length.\r
397 @return EFI_OUT_OF_RESOURCES There are not enough memory resourses to form the signature list.\r
20333c6d 398\r
ecc722ad 399**/\r
400EFI_STATUS\r
401CreatePkX509SignatureList (\r
20333c6d
QL
402 IN EFI_FILE_HANDLE X509File,\r
403 OUT EFI_SIGNATURE_LIST **PkCert\r
ecc722ad 404 )\r
405{\r
20333c6d 406 EFI_STATUS Status;\r
ecc722ad 407 UINT8 *X509Data;\r
408 UINTN X509DataSize;\r
409 EFI_SIGNATURE_DATA *PkCertData;\r
410\r
411 X509Data = NULL;\r
412 PkCertData = NULL;\r
20333c6d
QL
413 X509DataSize = 0;\r
414\r
4adc12bf 415 Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);\r
ecc722ad 416 if (EFI_ERROR (Status)) {\r
417 goto ON_EXIT;\r
418 }\r
ba57d4fd 419 ASSERT (X509Data != NULL);\r
ecc722ad 420\r
421 //\r
422 // Allocate space for PK certificate list and initialize it.\r
423 // Create PK database entry with SignatureHeaderSize equals 0.\r
424 //\r
425 *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool (\r
426 sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1\r
427 + X509DataSize\r
428 );\r
429 if (*PkCert == NULL) {\r
430 Status = EFI_OUT_OF_RESOURCES;\r
431 goto ON_EXIT;\r
432 }\r
433\r
20333c6d 434 (*PkCert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST)\r
ecc722ad 435 + sizeof(EFI_SIGNATURE_DATA) - 1\r
436 + X509DataSize);\r
437 (*PkCert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);\r
438 (*PkCert)->SignatureHeaderSize = 0;\r
439 CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid);\r
20333c6d 440 PkCertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert)\r
ecc722ad 441 + sizeof(EFI_SIGNATURE_LIST)\r
442 + (*PkCert)->SignatureHeaderSize);\r
20333c6d 443 CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);\r
ecc722ad 444 //\r
445 // Fill the PK database with PKpub data from X509 certificate file.\r
20333c6d 446 //\r
ecc722ad 447 CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize);\r
20333c6d 448\r
ecc722ad 449ON_EXIT:\r
20333c6d 450\r
ecc722ad 451 if (X509Data != NULL) {\r
452 FreePool (X509Data);\r
453 }\r
20333c6d 454\r
ecc722ad 455 if (EFI_ERROR(Status) && *PkCert != NULL) {\r
456 FreePool (*PkCert);\r
457 *PkCert = NULL;\r
458 }\r
20333c6d 459\r
ecc722ad 460 return Status;\r
461}\r
462\r
463/**\r
464 Enroll new PK into the System without original PK's authentication.\r
465\r
466 The SignatureOwner GUID will be the same with PK's vendorguid.\r
467\r
468 @param[in] PrivateData The module's private data.\r
469\r
470 @retval EFI_SUCCESS New PK enrolled successfully.\r
471 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
472 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
20333c6d 473\r
ecc722ad 474**/\r
475EFI_STATUS\r
476EnrollPlatformKey (\r
477 IN SECUREBOOT_CONFIG_PRIVATE_DATA* Private\r
20333c6d 478 )\r
ecc722ad 479{\r
480 EFI_STATUS Status;\r
481 UINT32 Attr;\r
482 UINTN DataSize;\r
483 EFI_SIGNATURE_LIST *PkCert;\r
484 UINT16* FilePostFix;\r
fd64f84f 485 UINTN NameLength;\r
20333c6d 486\r
ecc722ad 487 if (Private->FileContext->FileName == NULL) {\r
488 return EFI_INVALID_PARAMETER;\r
489 }\r
490\r
491 PkCert = NULL;\r
492\r
f71ed839 493 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
494 if (EFI_ERROR (Status)) {\r
495 return Status;\r
496 }\r
497\r
ecc722ad 498 //\r
e4d7370d 499 // Parse the file's postfix. Only support DER encoded X.509 certificate files.\r
ecc722ad 500 //\r
fd64f84f
GCPL
501 NameLength = StrLen (Private->FileContext->FileName);\r
502 if (NameLength <= 4) {\r
503 return EFI_INVALID_PARAMETER;\r
504 }\r
505 FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
e4d7370d 506 if (!IsDerEncodeCertificate(FilePostFix)) {\r
507 DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix));\r
ecc722ad 508 return EFI_INVALID_PARAMETER;\r
509 }\r
510 DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName));\r
511 DEBUG ((EFI_D_INFO, "FilePostFix = %s\n", FilePostFix));\r
512\r
513 //\r
514 // Prase the selected PK file and generature PK certificate list.\r
515 //\r
8c1babfd 516 Status = CreatePkX509SignatureList (\r
20333c6d
QL
517 Private->FileContext->FHandle,\r
518 &PkCert\r
8c1babfd 519 );\r
520 if (EFI_ERROR (Status)) {\r
521 goto ON_EXIT;\r
ecc722ad 522 }\r
ba57d4fd 523 ASSERT (PkCert != NULL);\r
20333c6d 524\r
ecc722ad 525 //\r
526 // Set Platform Key variable.\r
20333c6d
QL
527 //\r
528 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
8c1babfd 529 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
ecc722ad 530 DataSize = PkCert->SignatureListSize;\r
8c1babfd 531 Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);\r
532 if (EFI_ERROR (Status)) {\r
533 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
534 goto ON_EXIT;\r
535 }\r
20333c6d 536\r
ecc722ad 537 Status = gRT->SetVariable(\r
20333c6d
QL
538 EFI_PLATFORM_KEY_NAME,\r
539 &gEfiGlobalVariableGuid,\r
540 Attr,\r
541 DataSize,\r
ecc722ad 542 PkCert\r
543 );\r
544 if (EFI_ERROR (Status)) {\r
545 if (Status == EFI_OUT_OF_RESOURCES) {\r
546 DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n"));\r
547 }\r
548 goto ON_EXIT;\r
549 }\r
20333c6d 550\r
ecc722ad 551ON_EXIT:\r
552\r
553 if (PkCert != NULL) {\r
554 FreePool(PkCert);\r
555 }\r
20333c6d 556\r
4de754e1 557 CloseEnrolledFile(Private->FileContext);\r
ecc722ad 558\r
559 return Status;\r
560}\r
561\r
562/**\r
563 Remove the PK variable.\r
564\r
565 @retval EFI_SUCCESS Delete PK successfully.\r
566 @retval Others Could not allow to delete PK.\r
20333c6d 567\r
ecc722ad 568**/\r
569EFI_STATUS\r
570DeletePlatformKey (\r
571 VOID\r
572)\r
573{\r
574 EFI_STATUS Status;\r
575\r
f71ed839 576 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
577 if (EFI_ERROR (Status)) {\r
578 return Status;\r
579 }\r
580\r
8c1babfd 581 Status = DeleteVariable (\r
582 EFI_PLATFORM_KEY_NAME,\r
583 &gEfiGlobalVariableGuid\r
584 );\r
ecc722ad 585 return Status;\r
586}\r
587\r
588/**\r
589 Enroll a new KEK item from public key storing file (*.pbk).\r
590\r
591 @param[in] PrivateData The module's private data.\r
592\r
593 @retval EFI_SUCCESS New KEK enrolled successfully.\r
594 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
595 @retval EFI_UNSUPPORTED Unsupported command.\r
596 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
597\r
598**/\r
599EFI_STATUS\r
600EnrollRsa2048ToKek (\r
601 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private\r
602 )\r
603{\r
604 EFI_STATUS Status;\r
605 UINT32 Attr;\r
606 UINTN DataSize;\r
607 EFI_SIGNATURE_LIST *KekSigList;\r
608 UINTN KeyBlobSize;\r
609 UINT8 *KeyBlob;\r
610 CPL_KEY_INFO *KeyInfo;\r
611 EFI_SIGNATURE_DATA *KEKSigData;\r
612 UINTN KekSigListSize;\r
20333c6d 613 UINT8 *KeyBuffer;\r
ecc722ad 614 UINTN KeyLenInBytes;\r
615\r
616 Attr = 0;\r
617 DataSize = 0;\r
618 KeyBuffer = NULL;\r
619 KeyBlobSize = 0;\r
620 KeyBlob = NULL;\r
621 KeyInfo = NULL;\r
622 KEKSigData = NULL;\r
623 KekSigList = NULL;\r
624 KekSigListSize = 0;\r
20333c6d 625\r
ecc722ad 626 //\r
627 // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type.\r
628 // First, We have to parse out public key data from the pbk key file.\r
20333c6d 629 //\r
ecc722ad 630 Status = ReadFileContent (\r
631 Private->FileContext->FHandle,\r
4adc12bf 632 (VOID**) &KeyBlob,\r
ecc722ad 633 &KeyBlobSize,\r
634 0\r
635 );\r
636 if (EFI_ERROR (Status)) {\r
637 goto ON_EXIT;\r
638 }\r
ba57d4fd 639 ASSERT (KeyBlob != NULL);\r
ecc722ad 640 KeyInfo = (CPL_KEY_INFO *) KeyBlob;\r
641 if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {\r
642 DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));\r
643 Status = EFI_UNSUPPORTED;\r
644 goto ON_EXIT;\r
645 }\r
20333c6d 646\r
ecc722ad 647 //\r
648 // Convert the Public key to fix octet string format represented in RSA PKCS#1.\r
20333c6d 649 //\r
ecc722ad 650 KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;\r
651 KeyBuffer = AllocateZeroPool (KeyLenInBytes);\r
652 if (KeyBuffer == NULL) {\r
653 Status = EFI_OUT_OF_RESOURCES;\r
654 goto ON_EXIT;\r
655 }\r
656 Int2OctStr (\r
20333c6d
QL
657 (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)),\r
658 KeyLenInBytes / sizeof (UINTN),\r
659 KeyBuffer,\r
ecc722ad 660 KeyLenInBytes\r
661 );\r
662 CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes);\r
20333c6d 663\r
ecc722ad 664 //\r
665 // Form an new EFI_SIGNATURE_LIST.\r
666 //\r
667 KekSigListSize = sizeof(EFI_SIGNATURE_LIST)\r
668 + sizeof(EFI_SIGNATURE_DATA) - 1\r
669 + WIN_CERT_UEFI_RSA2048_SIZE;\r
670\r
671 KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);\r
672 if (KekSigList == NULL) {\r
673 Status = EFI_OUT_OF_RESOURCES;\r
674 goto ON_EXIT;\r
675 }\r
676\r
677 KekSigList->SignatureListSize = sizeof(EFI_SIGNATURE_LIST)\r
678 + sizeof(EFI_SIGNATURE_DATA) - 1\r
679 + WIN_CERT_UEFI_RSA2048_SIZE;\r
680 KekSigList->SignatureHeaderSize = 0;\r
681 KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;\r
682 CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid);\r
20333c6d 683\r
ecc722ad 684 KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST));\r
685 CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);\r
686 CopyMem (\r
687 KEKSigData->SignatureData,\r
688 KeyBlob + sizeof(CPL_KEY_INFO),\r
689 WIN_CERT_UEFI_RSA2048_SIZE\r
690 );\r
20333c6d 691\r
ecc722ad 692 //\r
20333c6d
QL
693 // Check if KEK entry has been already existed.\r
694 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
ecc722ad 695 // new KEK to original variable.\r
20333c6d
QL
696 //\r
697 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
8c1babfd 698 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
699 Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);\r
700 if (EFI_ERROR (Status)) {\r
701 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
702 goto ON_EXIT;\r
703 }\r
704\r
ecc722ad 705 Status = gRT->GetVariable(\r
20333c6d
QL
706 EFI_KEY_EXCHANGE_KEY_NAME,\r
707 &gEfiGlobalVariableGuid,\r
708 NULL,\r
709 &DataSize,\r
ecc722ad 710 NULL\r
711 );\r
712 if (Status == EFI_BUFFER_TOO_SMALL) {\r
713 Attr |= EFI_VARIABLE_APPEND_WRITE;\r
714 } else if (Status != EFI_NOT_FOUND) {\r
715 goto ON_EXIT;\r
716 }\r
20333c6d 717\r
ecc722ad 718 //\r
719 // Done. Now we have formed the correct KEKpub database item, just set it into variable storage,\r
20333c6d 720 //\r
ecc722ad 721 Status = gRT->SetVariable(\r
20333c6d
QL
722 EFI_KEY_EXCHANGE_KEY_NAME,\r
723 &gEfiGlobalVariableGuid,\r
724 Attr,\r
725 KekSigListSize,\r
ecc722ad 726 KekSigList\r
727 );\r
728 if (EFI_ERROR (Status)) {\r
729 goto ON_EXIT;\r
730 }\r
20333c6d 731\r
ecc722ad 732ON_EXIT:\r
733\r
4de754e1 734 CloseEnrolledFile(Private->FileContext);\r
ecc722ad 735\r
736 if (Private->SignatureGUID != NULL) {\r
737 FreePool (Private->SignatureGUID);\r
738 Private->SignatureGUID = NULL;\r
739 }\r
740\r
741 if (KeyBlob != NULL) {\r
742 FreePool (KeyBlob);\r
743 }\r
744 if (KeyBuffer != NULL) {\r
745 FreePool (KeyBuffer);\r
746 }\r
747 if (KekSigList != NULL) {\r
748 FreePool (KekSigList);\r
749 }\r
20333c6d 750\r
ecc722ad 751 return Status;\r
752}\r
753\r
754/**\r
755 Enroll a new KEK item from X509 certificate file.\r
756\r
757 @param[in] PrivateData The module's private data.\r
758\r
759 @retval EFI_SUCCESS New X509 is enrolled successfully.\r
760 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
761 @retval EFI_UNSUPPORTED Unsupported command.\r
762 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
763\r
764**/\r
765EFI_STATUS\r
766EnrollX509ToKek (\r
767 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private\r
20333c6d 768 )\r
ecc722ad 769{\r
770 EFI_STATUS Status;\r
771 UINTN X509DataSize;\r
772 VOID *X509Data;\r
773 EFI_SIGNATURE_DATA *KEKSigData;\r
774 EFI_SIGNATURE_LIST *KekSigList;\r
775 UINTN DataSize;\r
776 UINTN KekSigListSize;\r
777 UINT32 Attr;\r
778\r
779 X509Data = NULL;\r
780 X509DataSize = 0;\r
781 KekSigList = NULL;\r
782 KekSigListSize = 0;\r
783 DataSize = 0;\r
784 KEKSigData = NULL;\r
785\r
786 Status = ReadFileContent (\r
787 Private->FileContext->FHandle,\r
788 &X509Data,\r
789 &X509DataSize,\r
790 0\r
791 );\r
792 if (EFI_ERROR (Status)) {\r
793 goto ON_EXIT;\r
794 }\r
ba57d4fd 795 ASSERT (X509Data != NULL);\r
ecc722ad 796\r
797 KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;\r
798 KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);\r
799 if (KekSigList == NULL) {\r
800 Status = EFI_OUT_OF_RESOURCES;\r
801 goto ON_EXIT;\r
802 }\r
803\r
804 //\r
805 // Fill Certificate Database parameters.\r
20333c6d 806 //\r
ecc722ad 807 KekSigList->SignatureListSize = (UINT32) KekSigListSize;\r
808 KekSigList->SignatureHeaderSize = 0;\r
809 KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);\r
810 CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid);\r
811\r
812 KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST));\r
813 CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);\r
814 CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize);\r
815\r
816 //\r
20333c6d
QL
817 // Check if KEK been already existed.\r
818 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
ecc722ad 819 // new kek to original variable\r
20333c6d
QL
820 //\r
821 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
8c1babfd 822 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
823 Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);\r
824 if (EFI_ERROR (Status)) {\r
825 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
826 goto ON_EXIT;\r
827 }\r
20333c6d 828\r
ecc722ad 829 Status = gRT->GetVariable(\r
20333c6d
QL
830 EFI_KEY_EXCHANGE_KEY_NAME,\r
831 &gEfiGlobalVariableGuid,\r
832 NULL,\r
833 &DataSize,\r
ecc722ad 834 NULL\r
835 );\r
836 if (Status == EFI_BUFFER_TOO_SMALL) {\r
837 Attr |= EFI_VARIABLE_APPEND_WRITE;\r
838 } else if (Status != EFI_NOT_FOUND) {\r
839 goto ON_EXIT;\r
20333c6d 840 }\r
ecc722ad 841\r
842 Status = gRT->SetVariable(\r
20333c6d
QL
843 EFI_KEY_EXCHANGE_KEY_NAME,\r
844 &gEfiGlobalVariableGuid,\r
845 Attr,\r
ecc722ad 846 KekSigListSize,\r
847 KekSigList\r
848 );\r
849 if (EFI_ERROR (Status)) {\r
850 goto ON_EXIT;\r
851 }\r
852\r
853ON_EXIT:\r
20333c6d 854\r
4de754e1 855 CloseEnrolledFile(Private->FileContext);\r
20333c6d
QL
856\r
857 if (Private->SignatureGUID != NULL) {\r
858 FreePool (Private->SignatureGUID);\r
859 Private->SignatureGUID = NULL;\r
860 }\r
861\r
862 if (KekSigList != NULL) {\r
863 FreePool (KekSigList);\r
864 }\r
865\r
866 return Status;\r
867}\r
868\r
869/**\r
870 Enroll new KEK into the System without PK's authentication.\r
871 The SignatureOwner GUID will be Private->SignatureGUID.\r
872\r
873 @param[in] PrivateData The module's private data.\r
874\r
875 @retval EFI_SUCCESS New KEK enrolled successful.\r
876 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
877 @retval others Fail to enroll KEK data.\r
878\r
879**/\r
880EFI_STATUS\r
881EnrollKeyExchangeKey (\r
882 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private\r
883 )\r
884{\r
885 UINT16* FilePostFix;\r
886 EFI_STATUS Status;\r
887 UINTN NameLength;\r
888\r
4de754e1 889 if ((Private->FileContext->FHandle == NULL) || (Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {\r
20333c6d
QL
890 return EFI_INVALID_PARAMETER;\r
891 }\r
892\r
893 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
894 if (EFI_ERROR (Status)) {\r
895 return Status;\r
896 }\r
897\r
898 //\r
899 // Parse the file's postfix. Supports DER-encoded X509 certificate,\r
900 // and .pbk as RSA public key file.\r
901 //\r
902 NameLength = StrLen (Private->FileContext->FileName);\r
903 if (NameLength <= 4) {\r
904 return EFI_INVALID_PARAMETER;\r
905 }\r
906 FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
907 if (IsDerEncodeCertificate(FilePostFix)) {\r
908 return EnrollX509ToKek (Private);\r
909 } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {\r
910 return EnrollRsa2048ToKek (Private);\r
911 } else {\r
4de754e1
ZC
912 //\r
913 // File type is wrong, simply close it\r
914 //\r
915 CloseEnrolledFile(Private->FileContext);\r
916\r
20333c6d
QL
917 return EFI_INVALID_PARAMETER;\r
918 }\r
919}\r
920\r
921/**\r
922 Enroll a new X509 certificate into Signature Database (DB or DBX or DBT) without\r
923 KEK's authentication.\r
924\r
925 @param[in] PrivateData The module's private data.\r
926 @param[in] VariableName Variable name of signature database, must be\r
927 EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.\r
928\r
929 @retval EFI_SUCCESS New X509 is enrolled successfully.\r
930 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
931\r
932**/\r
933EFI_STATUS\r
934EnrollX509toSigDB (\r
935 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
936 IN CHAR16 *VariableName\r
937 )\r
938{\r
939 EFI_STATUS Status;\r
940 UINTN X509DataSize;\r
941 VOID *X509Data;\r
942 EFI_SIGNATURE_LIST *SigDBCert;\r
943 EFI_SIGNATURE_DATA *SigDBCertData;\r
944 VOID *Data;\r
945 UINTN DataSize;\r
946 UINTN SigDBSize;\r
947 UINT32 Attr;\r
948\r
949 X509DataSize = 0;\r
950 SigDBSize = 0;\r
951 DataSize = 0;\r
952 X509Data = NULL;\r
953 SigDBCert = NULL;\r
954 SigDBCertData = NULL;\r
955 Data = NULL;\r
956\r
957 Status = ReadFileContent (\r
958 Private->FileContext->FHandle,\r
959 &X509Data,\r
960 &X509DataSize,\r
961 0\r
962 );\r
963 if (EFI_ERROR (Status)) {\r
964 goto ON_EXIT;\r
965 }\r
966 ASSERT (X509Data != NULL);\r
967\r
968 SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;\r
969\r
970 Data = AllocateZeroPool (SigDBSize);\r
971 if (Data == NULL) {\r
972 Status = EFI_OUT_OF_RESOURCES;\r
973 goto ON_EXIT;\r
974 }\r
975\r
976 //\r
977 // Fill Certificate Database parameters.\r
978 //\r
979 SigDBCert = (EFI_SIGNATURE_LIST*) Data;\r
980 SigDBCert->SignatureListSize = (UINT32) SigDBSize;\r
981 SigDBCert->SignatureHeaderSize = 0;\r
982 SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);\r
983 CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid);\r
984\r
985 SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST));\r
986 CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);\r
987 CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize);\r
988\r
989 //\r
990 // Check if signature database entry has been already existed.\r
991 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
992 // new signature data to original variable\r
993 //\r
994 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
995 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
996 Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
997 if (EFI_ERROR (Status)) {\r
998 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
999 goto ON_EXIT;\r
1000 }\r
1001\r
1002 Status = gRT->GetVariable(\r
1003 VariableName,\r
1004 &gEfiImageSecurityDatabaseGuid,\r
1005 NULL,\r
1006 &DataSize,\r
1007 NULL\r
1008 );\r
1009 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1010 Attr |= EFI_VARIABLE_APPEND_WRITE;\r
1011 } else if (Status != EFI_NOT_FOUND) {\r
1012 goto ON_EXIT;\r
1013 }\r
1014\r
1015 Status = gRT->SetVariable(\r
1016 VariableName,\r
1017 &gEfiImageSecurityDatabaseGuid,\r
1018 Attr,\r
1019 SigDBSize,\r
1020 Data\r
1021 );\r
1022 if (EFI_ERROR (Status)) {\r
1023 goto ON_EXIT;\r
1024 }\r
1025\r
1026ON_EXIT:\r
1027\r
4de754e1 1028 CloseEnrolledFile(Private->FileContext);\r
20333c6d
QL
1029\r
1030 if (Private->SignatureGUID != NULL) {\r
1031 FreePool (Private->SignatureGUID);\r
1032 Private->SignatureGUID = NULL;\r
1033 }\r
1034\r
1035 if (Data != NULL) {\r
1036 FreePool (Data);\r
1037 }\r
1038\r
1039 if (X509Data != NULL) {\r
1040 FreePool (X509Data);\r
1041 }\r
1042\r
1043 return Status;\r
1044}\r
1045\r
1046/**\r
1047 Check whether signature is in specified database.\r
1048\r
1049 @param[in] VariableName Name of database variable that is searched in.\r
1050 @param[in] Signature Pointer to signature that is searched for.\r
1051 @param[in] SignatureSize Size of Signature.\r
1052\r
1053 @return TRUE Found the signature in the variable database.\r
1054 @return FALSE Not found the signature in the variable database.\r
1055\r
1056**/\r
1057BOOLEAN\r
1058IsSignatureFoundInDatabase (\r
1059 IN CHAR16 *VariableName,\r
1060 IN UINT8 *Signature,\r
1061 IN UINTN SignatureSize\r
1062 )\r
1063{\r
1064 EFI_STATUS Status;\r
1065 EFI_SIGNATURE_LIST *CertList;\r
1066 EFI_SIGNATURE_DATA *Cert;\r
1067 UINTN DataSize;\r
1068 UINT8 *Data;\r
1069 UINTN Index;\r
1070 UINTN CertCount;\r
1071 BOOLEAN IsFound;\r
1072\r
1073 //\r
1074 // Read signature database variable.\r
1075 //\r
1076 IsFound = FALSE;\r
1077 Data = NULL;\r
1078 DataSize = 0;\r
1079 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
1080 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1081 return FALSE;\r
1082 }\r
1083\r
1084 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1085 if (Data == NULL) {\r
1086 return FALSE;\r
1087 }\r
1088\r
1089 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
1090 if (EFI_ERROR (Status)) {\r
1091 goto Done;\r
1092 }\r
1093\r
1094 //\r
1095 // Enumerate all signature data in SigDB to check if executable's signature exists.\r
1096 //\r
1097 CertList = (EFI_SIGNATURE_LIST *) Data;\r
1098 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
1099 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
1100 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
1101 if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &gEfiCertX509Guid))) {\r
1102 for (Index = 0; Index < CertCount; Index++) {\r
1103 if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r
1104 //\r
1105 // Find the signature in database.\r
1106 //\r
1107 IsFound = TRUE;\r
1108 break;\r
1109 }\r
1110 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
1111 }\r
1112\r
1113 if (IsFound) {\r
1114 break;\r
1115 }\r
1116 }\r
1117\r
1118 DataSize -= CertList->SignatureListSize;\r
1119 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
1120 }\r
1121\r
1122Done:\r
1123 if (Data != NULL) {\r
1124 FreePool (Data);\r
1125 }\r
1126\r
1127 return IsFound;\r
1128}\r
1129\r
1130/**\r
1131 Calculate the hash of a certificate data with the specified hash algorithm.\r
1132\r
1133 @param[in] CertData The certificate data to be hashed.\r
1134 @param[in] CertSize The certificate size in bytes.\r
1135 @param[in] HashAlg The specified hash algorithm.\r
1136 @param[out] CertHash The output digest of the certificate\r
1137\r
1138 @retval TRUE Successfully got the hash of the CertData.\r
1139 @retval FALSE Failed to get the hash of CertData.\r
1140\r
1141**/\r
1142BOOLEAN\r
1143CalculateCertHash (\r
1144 IN UINT8 *CertData,\r
1145 IN UINTN CertSize,\r
1146 IN UINT32 HashAlg,\r
1147 OUT UINT8 *CertHash\r
1148 )\r
1149{\r
1150 BOOLEAN Status;\r
1151 VOID *HashCtx;\r
1152 UINTN CtxSize;\r
12d95665
LQ
1153 UINT8 *TBSCert;\r
1154 UINTN TBSCertSize;\r
20333c6d
QL
1155\r
1156 HashCtx = NULL;\r
1157 Status = FALSE;\r
1158\r
1159 if (HashAlg >= HASHALG_MAX) {\r
1160 return FALSE;\r
1161 }\r
1162\r
12d95665
LQ
1163 //\r
1164 // Retrieve the TBSCertificate for Hash Calculation.\r
1165 //\r
1166 if (!X509GetTBSCert (CertData, CertSize, &TBSCert, &TBSCertSize)) {\r
1167 return FALSE;\r
1168 }\r
1169\r
20333c6d
QL
1170 //\r
1171 // 1. Initialize context of hash.\r
1172 //\r
1173 CtxSize = mHash[HashAlg].GetContextSize ();\r
1174 HashCtx = AllocatePool (CtxSize);\r
1175 ASSERT (HashCtx != NULL);\r
1176\r
1177 //\r
1178 // 2. Initialize a hash context.\r
1179 //\r
1180 Status = mHash[HashAlg].HashInit (HashCtx);\r
1181 if (!Status) {\r
1182 goto Done;\r
1183 }\r
1184\r
1185 //\r
1186 // 3. Calculate the hash.\r
1187 //\r
12d95665 1188 Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);\r
20333c6d
QL
1189 if (!Status) {\r
1190 goto Done;\r
1191 }\r
1192\r
1193 //\r
1194 // 4. Get the hash result.\r
1195 //\r
1196 ZeroMem (CertHash, mHash[HashAlg].DigestLength);\r
1197 Status = mHash[HashAlg].HashFinal (HashCtx, CertHash);\r
1198\r
1199Done:\r
1200 if (HashCtx != NULL) {\r
1201 FreePool (HashCtx);\r
1202 }\r
1203\r
1204 return Status;\r
1205}\r
1206\r
1207/**\r
1208 Check whether the hash of an X.509 certificate is in forbidden database (DBX).\r
1209\r
1210 @param[in] Certificate Pointer to X.509 Certificate that is searched for.\r
1211 @param[in] CertSize Size of X.509 Certificate.\r
1212\r
1213 @return TRUE Found the certificate hash in the forbidden database.\r
1214 @return FALSE Certificate hash is Not found in the forbidden database.\r
1215\r
1216**/\r
1217BOOLEAN\r
1218IsCertHashFoundInDbx (\r
1219 IN UINT8 *Certificate,\r
1220 IN UINTN CertSize\r
1221 )\r
1222{\r
1223 BOOLEAN IsFound;\r
1224 EFI_STATUS Status;\r
1225 EFI_SIGNATURE_LIST *DbxList;\r
1226 EFI_SIGNATURE_DATA *CertHash;\r
1227 UINTN CertHashCount;\r
1228 UINTN Index;\r
1229 UINT32 HashAlg;\r
1230 UINT8 CertDigest[MAX_DIGEST_SIZE];\r
1231 UINT8 *DbxCertHash;\r
1232 UINTN SiglistHeaderSize;\r
1233 UINT8 *Data;\r
1234 UINTN DataSize;\r
1235\r
1236 IsFound = FALSE;\r
1237 HashAlg = HASHALG_MAX;\r
1238 Data = NULL;\r
1239\r
1240 //\r
1241 // Read signature database variable.\r
1242 //\r
1243 DataSize = 0;\r
1244 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
1245 if (Status != EFI_BUFFER_TOO_SMALL) {\r
1246 return FALSE;\r
1247 }\r
1248\r
1249 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1250 if (Data == NULL) {\r
1251 return FALSE;\r
1252 }\r
1253\r
1254 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
1255 if (EFI_ERROR (Status)) {\r
1256 goto Done;\r
1257 }\r
1258\r
1259 //\r
1260 // Check whether the certificate hash exists in the forbidden database.\r
1261 //\r
1262 DbxList = (EFI_SIGNATURE_LIST *) Data;\r
1263 while ((DataSize > 0) && (DataSize >= DbxList->SignatureListSize)) {\r
1264 //\r
1265 // Determine Hash Algorithm of Certificate in the forbidden database.\r
1266 //\r
1267 if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
1268 HashAlg = HASHALG_SHA256;\r
1269 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
1270 HashAlg = HASHALG_SHA384;\r
1271 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
1272 HashAlg = HASHALG_SHA512;\r
1273 } else {\r
1274 DataSize -= DbxList->SignatureListSize;\r
1275 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
1276 continue;\r
1277 }\r
1278\r
1279 //\r
1280 // Calculate the hash value of current db certificate for comparision.\r
1281 //\r
1282 if (!CalculateCertHash (Certificate, CertSize, HashAlg, CertDigest)) {\r
1283 goto Done;\r
1284 }\r
1285\r
1286 SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;\r
1287 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);\r
1288 CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;\r
1289 for (Index = 0; Index < CertHashCount; Index++) {\r
1290 //\r
1291 // Iterate each Signature Data Node within this CertList for verify.\r
1292 //\r
1293 DbxCertHash = CertHash->SignatureData;\r
1294 if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {\r
1295 //\r
1296 // Hash of Certificate is found in forbidden database.\r
1297 //\r
1298 IsFound = TRUE;\r
1299 goto Done;\r
1300 }\r
1301 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);\r
1302 }\r
1303\r
1304 DataSize -= DbxList->SignatureListSize;\r
1305 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);\r
1306 }\r
1307\r
1308Done:\r
1309 if (Data != NULL) {\r
1310 FreePool (Data);\r
1311 }\r
1312\r
1313 return IsFound;\r
1314}\r
1315\r
1316/**\r
1317 Check whether the signature list exists in given variable data.\r
1318\r
1319 It searches the signature list for the ceritificate hash by CertType.\r
1320 If the signature list is found, get the offset of Database for the\r
1321 next hash of a certificate.\r
1322\r
1323 @param[in] Database Variable data to save signature list.\r
1324 @param[in] DatabaseSize Variable size.\r
1325 @param[in] SignatureType The type of the signature.\r
1326 @param[out] Offset The offset to save a new hash of certificate.\r
1327\r
1328 @return TRUE The signature list is found in the forbidden database.\r
1329 @return FALSE The signature list is not found in the forbidden database.\r
1330**/\r
1331BOOLEAN\r
1332GetSignaturelistOffset (\r
1333 IN EFI_SIGNATURE_LIST *Database,\r
1334 IN UINTN DatabaseSize,\r
1335 IN EFI_GUID *SignatureType,\r
1336 OUT UINTN *Offset\r
1337 )\r
1338{\r
1339 EFI_SIGNATURE_LIST *SigList;\r
1340 UINTN SiglistSize;\r
1341\r
1342 if ((Database == NULL) || (DatabaseSize == 0)) {\r
1343 *Offset = 0;\r
1344 return FALSE;\r
1345 }\r
1346\r
1347 SigList = Database;\r
1348 SiglistSize = DatabaseSize;\r
1349 while ((SiglistSize > 0) && (SiglistSize >= SigList->SignatureListSize)) {\r
1350 if (CompareGuid (&SigList->SignatureType, SignatureType)) {\r
1351 *Offset = DatabaseSize - SiglistSize;\r
1352 return TRUE;\r
1353 }\r
1354 SiglistSize -= SigList->SignatureListSize;\r
1355 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
1356 }\r
1357 *Offset = 0;\r
1358 return FALSE;\r
1359}\r
1360\r
1361/**\r
1362 Enroll a new X509 certificate hash into Signature Database (dbx) without\r
1363 KEK's authentication.\r
1364\r
1365 @param[in] PrivateData The module's private data.\r
1366 @param[in] HashAlg The hash algorithm to enroll the certificate.\r
1367 @param[in] RevocationDate The revocation date of the certificate.\r
1368 @param[in] RevocationTime The revocation time of the certificate.\r
1369 @param[in] AlwaysRevocation Indicate whether the certificate is always revoked.\r
1370\r
1371 @retval EFI_SUCCESS New X509 is enrolled successfully.\r
1372 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
1373 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
1374\r
1375**/\r
1376EFI_STATUS\r
1377EnrollX509HashtoSigDB (\r
1378 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
1379 IN UINT32 HashAlg,\r
1380 IN EFI_HII_DATE *RevocationDate,\r
1381 IN EFI_HII_TIME *RevocationTime,\r
1382 IN BOOLEAN AlwaysRevocation\r
1383 )\r
1384{\r
1385 EFI_STATUS Status;\r
1386 UINTN X509DataSize;\r
1387 VOID *X509Data;\r
1388 EFI_SIGNATURE_LIST *SignatureList;\r
1389 UINTN SignatureListSize;\r
1390 UINT8 *Data;\r
1391 UINT8 *NewData;\r
1392 UINTN DataSize;\r
1393 UINTN DbSize;\r
1394 UINT32 Attr;\r
1395 EFI_SIGNATURE_DATA *SignatureData;\r
1396 UINTN SignatureSize;\r
1397 EFI_GUID SignatureType;\r
1398 UINTN Offset;\r
1399 UINT8 CertHash[MAX_DIGEST_SIZE];\r
1400 UINT16* FilePostFix;\r
1401 UINTN NameLength;\r
1402 EFI_TIME *Time;\r
1403\r
1404 X509DataSize = 0;\r
1405 DbSize = 0;\r
1406 X509Data = NULL;\r
1407 SignatureData = NULL;\r
1408 SignatureList = NULL;\r
1409 Data = NULL;\r
1410 NewData = NULL;\r
1411\r
1412 if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {\r
1413 return EFI_INVALID_PARAMETER;\r
1414 }\r
1415\r
1416 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
1417 if (EFI_ERROR (Status)) {\r
1418 return Status;\r
1419 }\r
1420\r
1421 //\r
1422 // Parse the file's postfix.\r
1423 //\r
1424 NameLength = StrLen (Private->FileContext->FileName);\r
1425 if (NameLength <= 4) {\r
1426 return EFI_INVALID_PARAMETER;\r
1427 }\r
1428 FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
1429 if (!IsDerEncodeCertificate(FilePostFix)) {\r
1430 //\r
1431 // Only supports DER-encoded X509 certificate.\r
1432 //\r
1433 return EFI_INVALID_PARAMETER;\r
1434 }\r
1435\r
1436 //\r
1437 // Get the certificate from file and calculate its hash.\r
1438 //\r
1439 Status = ReadFileContent (\r
1440 Private->FileContext->FHandle,\r
1441 &X509Data,\r
1442 &X509DataSize,\r
1443 0\r
1444 );\r
1445 if (EFI_ERROR (Status)) {\r
1446 goto ON_EXIT;\r
1447 }\r
1448 ASSERT (X509Data != NULL);\r
1449\r
1450 if (!CalculateCertHash (X509Data, X509DataSize, HashAlg, CertHash)) {\r
1451 goto ON_EXIT;\r
1452 }\r
1453\r
1454 //\r
1455 // Get the variable for enrollment.\r
1456 //\r
1457 DataSize = 0;\r
1458 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
1459 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1460 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
1461 if (Data == NULL) {\r
1462 return EFI_OUT_OF_RESOURCES;\r
1463 }\r
1464\r
1465 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
1466 if (EFI_ERROR (Status)) {\r
1467 goto ON_EXIT;\r
1468 }\r
1469 }\r
1470\r
1471 //\r
1472 // Allocate memory for Signature and fill the Signature\r
1473 //\r
1474 SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + sizeof (EFI_TIME) + mHash[HashAlg].DigestLength;\r
1475 SignatureData = (EFI_SIGNATURE_DATA *) AllocateZeroPool (SignatureSize);\r
1476 if (SignatureData == NULL) {\r
1477 return EFI_OUT_OF_RESOURCES;\r
1478 }\r
1479 CopyGuid (&SignatureData->SignatureOwner, Private->SignatureGUID);\r
1480 CopyMem (SignatureData->SignatureData, CertHash, mHash[HashAlg].DigestLength);\r
1481\r
1482 //\r
1483 // Fill the time.\r
1484 //\r
1485 if (!AlwaysRevocation) {\r
1486 Time = (EFI_TIME *)(&SignatureData->SignatureData + mHash[HashAlg].DigestLength);\r
1487 Time->Year = RevocationDate->Year;\r
1488 Time->Month = RevocationDate->Month;\r
1489 Time->Day = RevocationDate->Day;\r
1490 Time->Hour = RevocationTime->Hour;\r
1491 Time->Minute = RevocationTime->Minute;\r
1492 Time->Second = RevocationTime->Second;\r
1493 }\r
1494\r
1495 //\r
1496 // Determine the GUID for certificate hash.\r
1497 //\r
1498 switch (HashAlg) {\r
1499 case HASHALG_SHA256:\r
1500 SignatureType = gEfiCertX509Sha256Guid;\r
1501 break;\r
1502 case HASHALG_SHA384:\r
1503 SignatureType = gEfiCertX509Sha384Guid;\r
1504 break;\r
1505 case HASHALG_SHA512:\r
1506 SignatureType = gEfiCertX509Sha512Guid;\r
1507 break;\r
1508 default:\r
1509 return FALSE;\r
1510 }\r
1511\r
1512 //\r
1513 // Add signature into the new variable data buffer\r
1514 //\r
1515 if (GetSignaturelistOffset((EFI_SIGNATURE_LIST *)Data, DataSize, &SignatureType, &Offset)) {\r
1516 //\r
1517 // Add the signature to the found signaturelist.\r
1518 //\r
1519 DbSize = DataSize + SignatureSize;\r
1520 NewData = AllocateZeroPool (DbSize);\r
1521 if (NewData == NULL) {\r
1522 Status = EFI_OUT_OF_RESOURCES;\r
1523 goto ON_EXIT;\r
1524 }\r
1525\r
1526 SignatureList = (EFI_SIGNATURE_LIST *)(Data + Offset);\r
1527 SignatureListSize = (UINTN) ReadUnaligned32 ((UINT32 *)&SignatureList->SignatureListSize);\r
1528 CopyMem (NewData, Data, Offset + SignatureListSize);\r
1529\r
1530 SignatureList = (EFI_SIGNATURE_LIST *)(NewData + Offset);\r
1531 WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32)(SignatureListSize + SignatureSize));\r
1532\r
1533 Offset += SignatureListSize;\r
1534 CopyMem (NewData + Offset, SignatureData, SignatureSize);\r
1535 CopyMem (NewData + Offset + SignatureSize, Data + Offset, DataSize - Offset);\r
1536\r
1537 FreePool (Data);\r
1538 Data = NewData;\r
1539 DataSize = DbSize;\r
1540 } else {\r
1541 //\r
1542 // Create a new signaturelist, and add the signature into the signaturelist.\r
1543 //\r
1544 DbSize = DataSize + sizeof(EFI_SIGNATURE_LIST) + SignatureSize;\r
1545 NewData = AllocateZeroPool (DbSize);\r
1546 if (NewData == NULL) {\r
1547 Status = EFI_OUT_OF_RESOURCES;\r
1548 goto ON_EXIT;\r
1549 }\r
1550 //\r
1551 // Fill Certificate Database parameters.\r
1552 //\r
1553 SignatureList = (EFI_SIGNATURE_LIST*) (NewData + DataSize);\r
1554 SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + SignatureSize;\r
1555 WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32) SignatureListSize);\r
1556 WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureSize, (UINT32) SignatureSize);\r
1557 CopyGuid (&SignatureList->SignatureType, &SignatureType);\r
1558 CopyMem ((UINT8* ) SignatureList + sizeof (EFI_SIGNATURE_LIST), SignatureData, SignatureSize);\r
1559 if ((DataSize != 0) && (Data != NULL)) {\r
1560 CopyMem (NewData, Data, DataSize);\r
1561 FreePool (Data);\r
1562 }\r
1563 Data = NewData;\r
1564 DataSize = DbSize;\r
1565 }\r
1566\r
1567 Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &Data);\r
1568 if (EFI_ERROR (Status)) {\r
1569 goto ON_EXIT;\r
1570 }\r
1571\r
1572 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
1573 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
1574 Status = gRT->SetVariable(\r
1575 EFI_IMAGE_SECURITY_DATABASE1,\r
1576 &gEfiImageSecurityDatabaseGuid,\r
1577 Attr,\r
1578 DataSize,\r
1579 Data\r
1580 );\r
1581 if (EFI_ERROR (Status)) {\r
1582 goto ON_EXIT;\r
1583 }\r
1584\r
1585ON_EXIT:\r
762d8ddb 1586\r
4de754e1 1587 CloseEnrolledFile(Private->FileContext);\r
ecc722ad 1588\r
1589 if (Private->SignatureGUID != NULL) {\r
1590 FreePool (Private->SignatureGUID);\r
1591 Private->SignatureGUID = NULL;\r
1592 }\r
1593\r
20333c6d
QL
1594 if (Data != NULL) {\r
1595 FreePool (Data);\r
ecc722ad 1596 }\r
1597\r
20333c6d
QL
1598 if (SignatureData != NULL) {\r
1599 FreePool (SignatureData);\r
ecc722ad 1600 }\r
1601\r
20333c6d
QL
1602 if (X509Data != NULL) {\r
1603 FreePool (X509Data);\r
f71ed839 1604 }\r
1605\r
20333c6d 1606 return Status;\r
ecc722ad 1607}\r
1608\r
1609/**\r
20333c6d 1610 Check whether a certificate from a file exists in dbx.\r
ecc722ad 1611\r
1612 @param[in] PrivateData The module's private data.\r
20333c6d
QL
1613 @param[in] VariableName Variable name of signature database, must be\r
1614 EFI_IMAGE_SECURITY_DATABASE1.\r
ecc722ad 1615\r
20333c6d
QL
1616 @retval TRUE The X509 certificate is found in dbx successfully.\r
1617 @retval FALSE The X509 certificate is not found in dbx.\r
ecc722ad 1618**/\r
20333c6d
QL
1619BOOLEAN\r
1620IsX509CertInDbx (\r
ecc722ad 1621 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
1622 IN CHAR16 *VariableName\r
20333c6d 1623 )\r
ecc722ad 1624{\r
20333c6d
QL
1625 EFI_STATUS Status;\r
1626 UINTN X509DataSize;\r
1627 VOID *X509Data;\r
1628 BOOLEAN IsFound;\r
ecc722ad 1629\r
20333c6d
QL
1630 //\r
1631 // Read the certificate from file\r
1632 //\r
ecc722ad 1633 X509DataSize = 0;\r
ecc722ad 1634 X509Data = NULL;\r
ecc722ad 1635 Status = ReadFileContent (\r
1636 Private->FileContext->FHandle,\r
1637 &X509Data,\r
1638 &X509DataSize,\r
1639 0\r
1640 );\r
1641 if (EFI_ERROR (Status)) {\r
20333c6d 1642 return FALSE;\r
ecc722ad 1643 }\r
1644\r
1645 //\r
20333c6d 1646 // Check the raw certificate.\r
ecc722ad 1647 //\r
20333c6d
QL
1648 IsFound = FALSE;\r
1649 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, X509Data, X509DataSize)) {\r
1650 IsFound = TRUE;\r
8c1babfd 1651 goto ON_EXIT;\r
1652 }\r
ecc722ad 1653\r
20333c6d
QL
1654 //\r
1655 // Check the hash of certificate.\r
1656 //\r
1657 if (IsCertHashFoundInDbx (X509Data, X509DataSize)) {\r
1658 IsFound = TRUE;\r
ecc722ad 1659 goto ON_EXIT;\r
1660 }\r
1661\r
1662ON_EXIT:\r
ecc722ad 1663 if (X509Data != NULL) {\r
1664 FreePool (X509Data);\r
1665 }\r
1666\r
20333c6d 1667 return IsFound;\r
ecc722ad 1668}\r
1669\r
5e9dfc67
LG
1670/**\r
1671 Reads contents of a PE/COFF image in memory buffer.\r
1672\r
1673 Caution: This function may receive untrusted input.\r
1674 PE/COFF image is external input, so this function will make sure the PE/COFF image content\r
1675 read is within the image buffer.\r
1676\r
1677 @param FileHandle Pointer to the file handle to read the PE/COFF image.\r
1678 @param FileOffset Offset into the PE/COFF image to begin the read operation.\r
1679 @param ReadSize On input, the size in bytes of the requested read operation.\r
1680 On output, the number of bytes actually read.\r
1681 @param Buffer Output buffer that contains the data read from the PE/COFF image.\r
1682\r
1683 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size\r
1684**/\r
1685EFI_STATUS\r
1686EFIAPI\r
1687SecureBootConfigImageRead (\r
1688 IN VOID *FileHandle,\r
1689 IN UINTN FileOffset,\r
1690 IN OUT UINTN *ReadSize,\r
1691 OUT VOID *Buffer\r
1692 )\r
1693{\r
1694 UINTN EndPosition;\r
1695\r
1696 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {\r
1697 return EFI_INVALID_PARAMETER;\r
1698 }\r
1699\r
1700 if (MAX_ADDRESS - FileOffset < *ReadSize) {\r
1701 return EFI_INVALID_PARAMETER;\r
1702 }\r
1703\r
1704 EndPosition = FileOffset + *ReadSize;\r
1705 if (EndPosition > mImageSize) {\r
1706 *ReadSize = (UINT32)(mImageSize - FileOffset);\r
1707 }\r
1708\r
1709 if (FileOffset >= mImageSize) {\r
1710 *ReadSize = 0;\r
1711 }\r
1712\r
1713 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
1714\r
1715 return EFI_SUCCESS;\r
1716}\r
1717\r
ecc722ad 1718/**\r
1719 Load PE/COFF image information into internal buffer and check its validity.\r
1720\r
1721 @retval EFI_SUCCESS Successful\r
1722 @retval EFI_UNSUPPORTED Invalid PE/COFF file\r
1723 @retval EFI_ABORTED Serious error occurs, like file I/O error etc.\r
1724\r
1725**/\r
1726EFI_STATUS\r
1727LoadPeImage (\r
20333c6d
QL
1728 VOID\r
1729 )\r
ecc722ad 1730{\r
1731 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1732 EFI_IMAGE_NT_HEADERS32 *NtHeader32;\r
1733 EFI_IMAGE_NT_HEADERS64 *NtHeader64;\r
5e9dfc67
LG
1734 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
1735 EFI_STATUS Status;\r
ecc722ad 1736\r
1737 NtHeader32 = NULL;\r
1738 NtHeader64 = NULL;\r
5e9dfc67
LG
1739\r
1740 ZeroMem (&ImageContext, sizeof (ImageContext));\r
1741 ImageContext.Handle = (VOID *) mImageBase;\r
1742 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecureBootConfigImageRead;\r
1743\r
1744 //\r
1745 // Get information about the image being loaded\r
1746 //\r
1747 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
1748 if (EFI_ERROR (Status)) {\r
1749 //\r
1750 // The information can't be got from the invalid PeImage\r
1751 //\r
1752 DEBUG ((DEBUG_INFO, "SecureBootConfigDxe: PeImage invalid. \n"));\r
1753 return Status;\r
1754 }\r
1755\r
ecc722ad 1756 //\r
1757 // Read the Dos header\r
1758 //\r
1759 DosHdr = (EFI_IMAGE_DOS_HEADER*)(mImageBase);\r
1760 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)\r
1761 {\r
1762 //\r
20333c6d 1763 // DOS image header is present,\r
ecc722ad 1764 // So read the PE header after the DOS image header\r
1765 //\r
1766 mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
1767 }\r
1768 else\r
1769 {\r
1770 mPeCoffHeaderOffset = 0;\r
1771 }\r
1772\r
1773 //\r
1774 // Read PE header and check the signature validity and machine compatibility\r
1775 //\r
1776 NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset);\r
1777 if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE)\r
1778 {\r
1779 return EFI_UNSUPPORTED;\r
1780 }\r
1781\r
1782 mNtHeader.Pe32 = NtHeader32;\r
1783\r
1784 //\r
1785 // Check the architecture field of PE header and get the Certificate Data Directory data\r
1786 // Note the size of FileHeader field is constant for both IA32 and X64 arch\r
1787 //\r
20333c6d 1788 if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32)\r
a16170a1
AB
1789 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)\r
1790 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {\r
ecc722ad 1791 //\r
a16170a1 1792 // 32-bits Architecture\r
ecc722ad 1793 //\r
1794 mImageType = ImageType_IA32;\r
1795 mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);\r
1796 }\r
1797 else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)\r
a16170a1
AB
1798 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)\r
1799 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {\r
ecc722ad 1800 //\r
1801 // 64-bits Architecture\r
1802 //\r
1803 mImageType = ImageType_X64;\r
1804 NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);\r
1805 mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);\r
1806 } else {\r
1807 return EFI_UNSUPPORTED;\r
1808 }\r
1809\r
1810 return EFI_SUCCESS;\r
1811}\r
1812\r
1813/**\r
1814 Calculate hash of Pe/Coff image based on the authenticode image hashing in\r
1815 PE/COFF Specification 8.0 Appendix A\r
1816\r
5e9dfc67
LG
1817 Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in \r
1818 the function LoadPeImage ().\r
1819\r
ecc722ad 1820 @param[in] HashAlg Hash algorithm type.\r
20333c6d 1821\r
ecc722ad 1822 @retval TRUE Successfully hash image.\r
1823 @retval FALSE Fail in hash image.\r
1824\r
1825**/\r
20333c6d 1826BOOLEAN\r
ecc722ad 1827HashPeImage (\r
1828 IN UINT32 HashAlg\r
1829 )\r
1830{\r
1831 BOOLEAN Status;\r
1832 UINT16 Magic;\r
1833 EFI_IMAGE_SECTION_HEADER *Section;\r
1834 VOID *HashCtx;\r
1835 UINTN CtxSize;\r
1836 UINT8 *HashBase;\r
1837 UINTN HashSize;\r
1838 UINTN SumOfBytesHashed;\r
1839 EFI_IMAGE_SECTION_HEADER *SectionHeader;\r
1840 UINTN Index;\r
1841 UINTN Pos;\r
1842\r
1843 HashCtx = NULL;\r
1844 SectionHeader = NULL;\r
1845 Status = FALSE;\r
1846\r
c035e373 1847 if (HashAlg != HASHALG_SHA256) {\r
ecc722ad 1848 return FALSE;\r
1849 }\r
20333c6d 1850\r
ecc722ad 1851 //\r
1852 // Initialize context of hash.\r
1853 //\r
1854 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
1855\r
c035e373
ZL
1856 mImageDigestSize = SHA256_DIGEST_SIZE;\r
1857 mCertType = gEfiCertSha256Guid;\r
ecc722ad 1858\r
1859 CtxSize = mHash[HashAlg].GetContextSize();\r
20333c6d 1860\r
ecc722ad 1861 HashCtx = AllocatePool (CtxSize);\r
1862 ASSERT (HashCtx != NULL);\r
1863\r
1864 // 1. Load the image header into memory.\r
1865\r
1866 // 2. Initialize a SHA hash context.\r
1867 Status = mHash[HashAlg].HashInit(HashCtx);\r
1868 if (!Status) {\r
1869 goto Done;\r
1870 }\r
1871 //\r
1872 // Measuring PE/COFF Image Header;\r
1873 // But CheckSum field and SECURITY data directory (certificate) are excluded\r
1874 //\r
de2447dd 1875 if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1876 //\r
20333c6d
QL
1877 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value\r
1878 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the\r
de2447dd 1879 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
1880 // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
1881 //\r
1882 Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
1883 } else {\r
1884 //\r
1885 // Get the magic value from the PE/COFF Optional Header\r
1886 //\r
1887 Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
1888 }\r
20333c6d 1889\r
ecc722ad 1890 //\r
1891 // 3. Calculate the distance from the base of the image header to the image checksum address.\r
1892 // 4. Hash the image header from its base to beginning of the image checksum.\r
1893 //\r
1894 HashBase = mImageBase;\r
1895 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1896 //\r
1897 // Use PE32 offset.\r
1898 //\r
4333b99d 1899 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
ecc722ad 1900 } else {\r
1901 //\r
1902 // Use PE32+ offset.\r
1903 //\r
4333b99d 1904 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;\r
ecc722ad 1905 }\r
1906\r
1907 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1908 if (!Status) {\r
1909 goto Done;\r
1910 }\r
1911 //\r
1912 // 5. Skip over the image checksum (it occupies a single ULONG).\r
1913 // 6. Get the address of the beginning of the Cert Directory.\r
1914 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r
1915 //\r
1916 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1917 //\r
1918 // Use PE32 offset.\r
1919 //\r
1920 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 1921 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
ecc722ad 1922 } else {\r
1923 //\r
1924 // Use PE32+ offset.\r
20333c6d 1925 //\r
ecc722ad 1926 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
4333b99d 1927 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;\r
ecc722ad 1928 }\r
1929\r
1930 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1931 if (!Status) {\r
1932 goto Done;\r
1933 }\r
1934 //\r
1935 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
1936 // 9. Hash everything from the end of the Cert Directory to the end of image header.\r
1937 //\r
1938 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1939 //\r
1940 // Use PE32 offset\r
1941 //\r
1942 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
4333b99d 1943 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);\r
ecc722ad 1944 } else {\r
1945 //\r
1946 // Use PE32+ offset.\r
1947 //\r
1948 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
4333b99d 1949 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);\r
ecc722ad 1950 }\r
1951\r
1952 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
1953 if (!Status) {\r
1954 goto Done;\r
1955 }\r
1956 //\r
1957 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
1958 //\r
1959 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1960 //\r
1961 // Use PE32 offset.\r
1962 //\r
1963 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r
1964 } else {\r
1965 //\r
1966 // Use PE32+ offset\r
1967 //\r
1968 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
1969 }\r
1970\r
1971 //\r
1972 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
1973 // structures in the image. The 'NumberOfSections' field of the image\r
1974 // header indicates how big the table should be. Do not include any\r
1975 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
1976 //\r
1977 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r
1978 ASSERT (SectionHeader != NULL);\r
1979 //\r
1980 // 12. Using the 'PointerToRawData' in the referenced section headers as\r
1981 // a key, arrange the elements in the table in ascending order. In other\r
1982 // words, sort the section headers according to the disk-file offset of\r
1983 // the section.\r
1984 //\r
1985 Section = (EFI_IMAGE_SECTION_HEADER *) (\r
1986 mImageBase +\r
1987 mPeCoffHeaderOffset +\r
1988 sizeof (UINT32) +\r
1989 sizeof (EFI_IMAGE_FILE_HEADER) +\r
1990 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
1991 );\r
1992 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
1993 Pos = Index;\r
1994 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
1995 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r
1996 Pos--;\r
1997 }\r
1998 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r
1999 Section += 1;\r
2000 }\r
2001\r
2002 //\r
2003 // 13. Walk through the sorted table, bring the corresponding section\r
2004 // into memory, and hash the entire section (using the 'SizeOfRawData'\r
2005 // field in the section header to determine the amount of data to hash).\r
2006 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
2007 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r
2008 //\r
2009 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
2010 Section = &SectionHeader[Index];\r
2011 if (Section->SizeOfRawData == 0) {\r
2012 continue;\r
2013 }\r
2014 HashBase = mImageBase + Section->PointerToRawData;\r
2015 HashSize = (UINTN) Section->SizeOfRawData;\r
2016\r
2017 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
2018 if (!Status) {\r
2019 goto Done;\r
2020 }\r
2021\r
2022 SumOfBytesHashed += HashSize;\r
2023 }\r
2024\r
2025 //\r
2026 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
2027 // data in the file that needs to be added to the hash. This data begins\r
2028 // at file offset SUM_OF_BYTES_HASHED and its length is:\r
2029 // FileSize - (CertDirectory->Size)\r
2030 //\r
2031 if (mImageSize > SumOfBytesHashed) {\r
2032 HashBase = mImageBase + SumOfBytesHashed;\r
2033 if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
2034 //\r
2035 // Use PE32 offset.\r
2036 //\r
2037 HashSize = (UINTN)(\r
2038 mImageSize -\r
2039 mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
2040 SumOfBytesHashed);\r
2041 } else {\r
2042 //\r
2043 // Use PE32+ offset.\r
2044 //\r
2045 HashSize = (UINTN)(\r
2046 mImageSize -\r
2047 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
20333c6d 2048 SumOfBytesHashed);\r
ecc722ad 2049 }\r
2050\r
2051 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
2052 if (!Status) {\r
2053 goto Done;\r
2054 }\r
2055 }\r
2056\r
2057 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
2058\r
2059Done:\r
2060 if (HashCtx != NULL) {\r
2061 FreePool (HashCtx);\r
2062 }\r
2063 if (SectionHeader != NULL) {\r
2064 FreePool (SectionHeader);\r
2065 }\r
2066 return Status;\r
2067}\r
2068\r
2069/**\r
69f8bb52 2070 Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of\r
20333c6d 2071 Pe/Coff image based on the authenticated image hashing in PE/COFF Specification\r
ecc722ad 2072 8.0 Appendix A\r
2073\r
2074 @retval EFI_UNSUPPORTED Hash algorithm is not supported.\r
2075 @retval EFI_SUCCESS Hash successfully.\r
2076\r
2077**/\r
20333c6d 2078EFI_STATUS\r
ecc722ad 2079HashPeImageByType (\r
2080 VOID\r
2081 )\r
2082{\r
2083 UINT8 Index;\r
2084 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r
2085\r
2086 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset);\r
2087\r
20333c6d 2088 for (Index = 0; Index < HASHALG_MAX; Index++) {\r
ecc722ad 2089 //\r
2090 // Check the Hash algorithm in PE/COFF Authenticode.\r
20333c6d 2091 // According to PKCS#7 Definition:\r
ecc722ad 2092 // SignedData ::= SEQUENCE {\r
2093 // version Version,\r
2094 // digestAlgorithms DigestAlgorithmIdentifiers,\r
2095 // contentInfo ContentInfo,\r
2096 // .... }\r
2097 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
2098 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
2099 // Fixed offset (+32) is calculated based on two bytes of length encoding.\r
2100 //\r
2101 if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r
2102 //\r
2103 // Only support two bytes of Long Form of Length Encoding.\r
2104 //\r
2105 continue;\r
2106 }\r
2107\r
20333c6d 2108 //\r
ecc722ad 2109 if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
2110 break;\r
2111 }\r
2112 }\r
2113\r
2114 if (Index == HASHALG_MAX) {\r
2115 return EFI_UNSUPPORTED;\r
2116 }\r
2117\r
2118 //\r
2119 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
2120 //\r
2121 if (!HashPeImage(Index)) {\r
2122 return EFI_UNSUPPORTED;\r
2123 }\r
2124\r
2125 return EFI_SUCCESS;\r
2126}\r
2127\r
4de754e1
ZC
2128/**\r
2129 Enroll a new executable's signature into Signature Database.\r
2130\r
2131 @param[in] PrivateData The module's private data.\r
2132 @param[in] VariableName Variable name of signature database, must be\r
2133 EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1\r
2134 or EFI_IMAGE_SECURITY_DATABASE2.\r
2135\r
2136 @retval EFI_SUCCESS New signature is enrolled successfully.\r
2137 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
2138 @retval EFI_UNSUPPORTED Unsupported command.\r
2139 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
2140\r
2141**/\r
2142EFI_STATUS\r
2143EnrollAuthentication2Descriptor (\r
2144 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2145 IN CHAR16 *VariableName\r
2146 )\r
2147{\r
2148 EFI_STATUS Status;\r
2149 VOID *Data;\r
2150 UINTN DataSize;\r
2151 UINT32 Attr;\r
2152\r
2153 Data = NULL;\r
2154\r
2155 //\r
2156 // DBT only support DER-X509 Cert Enrollment\r
2157 //\r
2158 if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {\r
2159 return EFI_UNSUPPORTED;\r
2160 }\r
2161\r
2162 //\r
2163 // Read the whole file content\r
2164 //\r
2165 Status = ReadFileContent(\r
2166 Private->FileContext->FHandle,\r
2167 (VOID **) &mImageBase,\r
2168 &mImageSize,\r
2169 0\r
2170 );\r
2171 if (EFI_ERROR (Status)) {\r
2172 goto ON_EXIT;\r
2173 }\r
2174 ASSERT (mImageBase != NULL);\r
2175\r
2176 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
2177 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2178\r
2179 //\r
2180 // Check if SigDB variable has been already existed.\r
2181 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
2182 // new signature data to original variable\r
2183 //\r
2184 DataSize = 0;\r
2185 Status = gRT->GetVariable(\r
2186 VariableName,\r
2187 &gEfiImageSecurityDatabaseGuid,\r
2188 NULL,\r
2189 &DataSize,\r
2190 NULL\r
2191 );\r
2192 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2193 Attr |= EFI_VARIABLE_APPEND_WRITE;\r
2194 } else if (Status != EFI_NOT_FOUND) {\r
2195 goto ON_EXIT;\r
2196 }\r
2197\r
2198 //\r
2199 // Diretly set AUTHENTICATION_2 data to SetVariable\r
2200 //\r
2201 Status = gRT->SetVariable(\r
2202 VariableName,\r
2203 &gEfiImageSecurityDatabaseGuid,\r
2204 Attr,\r
2205 mImageSize,\r
2206 mImageBase\r
2207 );\r
2208\r
2209 DEBUG((DEBUG_INFO, "Enroll AUTH_2 data to Var:%s Status: %x\n", VariableName, Status));\r
2210\r
2211ON_EXIT:\r
2212\r
2213 CloseEnrolledFile(Private->FileContext);\r
2214\r
2215 if (Data != NULL) {\r
2216 FreePool (Data);\r
2217 }\r
2218\r
2219 if (mImageBase != NULL) {\r
2220 FreePool (mImageBase);\r
2221 mImageBase = NULL;\r
2222 }\r
2223\r
2224 return Status;\r
2225\r
2226}\r
2227\r
2228\r
ecc722ad 2229/**\r
20333c6d 2230 Enroll a new executable's signature into Signature Database.\r
ecc722ad 2231\r
2232 @param[in] PrivateData The module's private data.\r
20333c6d
QL
2233 @param[in] VariableName Variable name of signature database, must be\r
2234 EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1\r
2235 or EFI_IMAGE_SECURITY_DATABASE2.\r
ecc722ad 2236\r
2237 @retval EFI_SUCCESS New signature is enrolled successfully.\r
2238 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
2239 @retval EFI_UNSUPPORTED Unsupported command.\r
2240 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
2241\r
2242**/\r
2243EFI_STATUS\r
2244EnrollImageSignatureToSigDB (\r
2245 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2246 IN CHAR16 *VariableName\r
2247 )\r
2248{\r
2249 EFI_STATUS Status;\r
2250 EFI_SIGNATURE_LIST *SigDBCert;\r
2251 EFI_SIGNATURE_DATA *SigDBCertData;\r
2252 VOID *Data;\r
2253 UINTN DataSize;\r
2254 UINTN SigDBSize;\r
2255 UINT32 Attr;\r
2256 WIN_CERTIFICATE_UEFI_GUID *GuidCertData;\r
2257\r
2258 Data = NULL;\r
2259 GuidCertData = NULL;\r
ecc722ad 2260\r
20333c6d
QL
2261 if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {\r
2262 return EFI_UNSUPPORTED;\r
2263 }\r
2264\r
ecc722ad 2265 //\r
2266 // Form the SigDB certificate list.\r
2267 // Format the data item into EFI_SIGNATURE_LIST type.\r
2268 //\r
2269 // We need to parse executable's signature data from specified signed executable file.\r
2270 // In current implementation, we simply trust the pass-in signed executable file.\r
2271 // In reality, it's OS's responsibility to verify the signed executable file.\r
2272 //\r
2273\r
2274 //\r
2275 // Read the whole file content\r
2276 //\r
2277 Status = ReadFileContent(\r
2278 Private->FileContext->FHandle,\r
20333c6d
QL
2279 (VOID **) &mImageBase,\r
2280 &mImageSize,\r
ecc722ad 2281 0\r
2282 );\r
2283 if (EFI_ERROR (Status)) {\r
2284 goto ON_EXIT;\r
20333c6d 2285 }\r
ba57d4fd 2286 ASSERT (mImageBase != NULL);\r
ecc722ad 2287\r
2288 Status = LoadPeImage ();\r
2289 if (EFI_ERROR (Status)) {\r
2290 goto ON_EXIT;\r
2291 }\r
2292\r
2293 if (mSecDataDir->SizeOfCert == 0) {\r
2294 if (!HashPeImage (HASHALG_SHA256)) {\r
2295 Status = EFI_SECURITY_VIOLATION;\r
2296 goto ON_EXIT;\r
2297 }\r
2298 } else {\r
20333c6d 2299\r
ecc722ad 2300 //\r
2301 // Read the certificate data\r
2302 //\r
2303 mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);\r
2304\r
2305 if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r
2306 GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;\r
2307 if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {\r
2308 Status = EFI_ABORTED;\r
2309 goto ON_EXIT;\r
2310 }\r
2311\r
2312 if (!HashPeImage (HASHALG_SHA256)) {\r
2313 Status = EFI_ABORTED;\r
2314 goto ON_EXIT;;\r
2315 }\r
20333c6d 2316\r
ecc722ad 2317 } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r
2318\r
2319 Status = HashPeImageByType ();\r
2320 if (EFI_ERROR (Status)) {\r
2321 goto ON_EXIT;;\r
2322 }\r
2323 } else {\r
2324 Status = EFI_ABORTED;\r
2325 goto ON_EXIT;\r
2326 }\r
2327 }\r
2328\r
2329 //\r
2330 // Create a new SigDB entry.\r
2331 //\r
20333c6d 2332 SigDBSize = sizeof(EFI_SIGNATURE_LIST)\r
ecc722ad 2333 + sizeof(EFI_SIGNATURE_DATA) - 1\r
2334 + (UINT32) mImageDigestSize;\r
2335\r
2336 Data = (UINT8*) AllocateZeroPool (SigDBSize);\r
2337 if (Data == NULL) {\r
2338 Status = EFI_OUT_OF_RESOURCES;\r
2339 goto ON_EXIT;\r
2340 }\r
20333c6d 2341\r
ecc722ad 2342 //\r
2343 // Adjust the Certificate Database parameters.\r
20333c6d 2344 //\r
ecc722ad 2345 SigDBCert = (EFI_SIGNATURE_LIST*) Data;\r
2346 SigDBCert->SignatureListSize = (UINT32) SigDBSize;\r
2347 SigDBCert->SignatureHeaderSize = 0;\r
2348 SigDBCert->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;\r
2349 CopyGuid (&SigDBCert->SignatureType, &mCertType);\r
2350\r
2351 SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));\r
2352 CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);\r
2353 CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);\r
2354\r
20333c6d 2355 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS\r
8c1babfd 2356 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
2357 Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
2358 if (EFI_ERROR (Status)) {\r
2359 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2360 goto ON_EXIT;\r
2361 }\r
20333c6d 2362\r
ecc722ad 2363 //\r
20333c6d
QL
2364 // Check if SigDB variable has been already existed.\r
2365 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the\r
ecc722ad 2366 // new signature data to original variable\r
20333c6d 2367 //\r
ecc722ad 2368 DataSize = 0;\r
2369 Status = gRT->GetVariable(\r
20333c6d
QL
2370 VariableName,\r
2371 &gEfiImageSecurityDatabaseGuid,\r
2372 NULL,\r
2373 &DataSize,\r
ecc722ad 2374 NULL\r
2375 );\r
2376 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2377 Attr |= EFI_VARIABLE_APPEND_WRITE;\r
2378 } else if (Status != EFI_NOT_FOUND) {\r
2379 goto ON_EXIT;\r
20333c6d 2380 }\r
ecc722ad 2381\r
2382 //\r
2383 // Enroll the variable.\r
2384 //\r
2385 Status = gRT->SetVariable(\r
20333c6d
QL
2386 VariableName,\r
2387 &gEfiImageSecurityDatabaseGuid,\r
2388 Attr,\r
2389 SigDBSize,\r
ecc722ad 2390 Data\r
2391 );\r
2392 if (EFI_ERROR (Status)) {\r
2393 goto ON_EXIT;\r
2394 }\r
2395\r
2396ON_EXIT:\r
2397\r
4de754e1 2398 CloseEnrolledFile(Private->FileContext);\r
ecc722ad 2399\r
2400 if (Private->SignatureGUID != NULL) {\r
2401 FreePool (Private->SignatureGUID);\r
2402 Private->SignatureGUID = NULL;\r
2403 }\r
2404\r
2405 if (Data != NULL) {\r
2406 FreePool (Data);\r
2407 }\r
2408\r
2409 if (mImageBase != NULL) {\r
2410 FreePool (mImageBase);\r
2411 mImageBase = NULL;\r
2412 }\r
2413\r
2414 return Status;\r
2415}\r
2416\r
2417/**\r
20333c6d 2418 Enroll signature into DB/DBX/DBT without KEK's authentication.\r
ecc722ad 2419 The SignatureOwner GUID will be Private->SignatureGUID.\r
20333c6d 2420\r
ecc722ad 2421 @param[in] PrivateData The module's private data.\r
20333c6d 2422 @param[in] VariableName Variable name of signature database, must be\r
ecc722ad 2423 EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.\r
20333c6d 2424\r
ecc722ad 2425 @retval EFI_SUCCESS New signature enrolled successfully.\r
2426 @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
2427 @retval others Fail to enroll signature data.\r
20333c6d 2428\r
ecc722ad 2429**/\r
2430EFI_STATUS\r
2431EnrollSignatureDatabase (\r
2432 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,\r
2433 IN CHAR16 *VariableName\r
20333c6d 2434 )\r
ecc722ad 2435{\r
2436 UINT16* FilePostFix;\r
f71ed839 2437 EFI_STATUS Status;\r
fd64f84f 2438 UINTN NameLength;\r
ecc722ad 2439\r
2440 if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {\r
2441 return EFI_INVALID_PARAMETER;\r
2442 }\r
2443\r
20333c6d 2444 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);\r
f71ed839 2445 if (EFI_ERROR (Status)) {\r
2446 return Status;\r
2447 }\r
20333c6d 2448\r
ecc722ad 2449 //\r
20333c6d 2450 // Parse the file's postfix.\r
ecc722ad 2451 //\r
fd64f84f
GCPL
2452 NameLength = StrLen (Private->FileContext->FileName);\r
2453 if (NameLength <= 4) {\r
2454 return EFI_INVALID_PARAMETER;\r
2455 }\r
2456 FilePostFix = Private->FileContext->FileName + NameLength - 4;\r
20333c6d 2457 if (IsDerEncodeCertificate (FilePostFix)) {\r
ecc722ad 2458 //\r
e4d7370d 2459 // Supports DER-encoded X509 certificate.\r
ecc722ad 2460 //\r
2461 return EnrollX509toSigDB (Private, VariableName);\r
4de754e1
ZC
2462 } else if (IsAuthentication2Format(Private->FileContext->FHandle)){\r
2463 return EnrollAuthentication2Descriptor(Private, VariableName);\r
2464 } else {\r
2465 return EnrollImageSignatureToSigDB (Private, VariableName);\r
ecc722ad 2466 }\r
ecc722ad 2467}\r
2468\r
2469/**\r
20333c6d 2470 List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)\r
ecc722ad 2471 by GUID in the page for user to select and delete as needed.\r
2472\r
2473 @param[in] PrivateData Module's private data.\r
2474 @param[in] VariableName The variable name of the vendor's signature database.\r
2475 @param[in] VendorGuid A unique identifier for the vendor.\r
2476 @param[in] LabelNumber Label number to insert opcodes.\r
2477 @param[in] FormId Form ID of current page.\r
2478 @param[in] QuestionIdBase Base question id of the signature list.\r
2479\r
2480 @retval EFI_SUCCESS Success to update the signature list page\r
2481 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.\r
20333c6d 2482\r
ecc722ad 2483**/\r
2484EFI_STATUS\r
2485UpdateDeletePage (\r
2486 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,\r
2487 IN CHAR16 *VariableName,\r
2488 IN EFI_GUID *VendorGuid,\r
2489 IN UINT16 LabelNumber,\r
2490 IN EFI_FORM_ID FormId,\r
2491 IN EFI_QUESTION_ID QuestionIdBase\r
2492 )\r
2493{\r
2494 EFI_STATUS Status;\r
2495 UINT32 Index;\r
2496 UINTN CertCount;\r
2497 UINTN GuidIndex;\r
2498 VOID *StartOpCodeHandle;\r
2499 VOID *EndOpCodeHandle;\r
2500 EFI_IFR_GUID_LABEL *StartLabel;\r
20333c6d 2501 EFI_IFR_GUID_LABEL *EndLabel;\r
ecc722ad 2502 UINTN DataSize;\r
2503 UINT8 *Data;\r
2504 EFI_SIGNATURE_LIST *CertList;\r
2505 EFI_SIGNATURE_DATA *Cert;\r
2506 UINT32 ItemDataSize;\r
2507 CHAR16 *GuidStr;\r
2508 EFI_STRING_ID GuidID;\r
2509 EFI_STRING_ID Help;\r
2510\r
2511 Data = NULL;\r
2512 CertList = NULL;\r
2513 Cert = NULL;\r
2514 GuidStr = NULL;\r
2515 StartOpCodeHandle = NULL;\r
2516 EndOpCodeHandle = NULL;\r
20333c6d 2517\r
ecc722ad 2518 //\r
2519 // Initialize the container for dynamic opcodes.\r
2520 //\r
2521 StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2522 if (StartOpCodeHandle == NULL) {\r
2523 Status = EFI_OUT_OF_RESOURCES;\r
20333c6d 2524 goto ON_EXIT;\r
ecc722ad 2525 }\r
2526\r
2527 EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
2528 if (EndOpCodeHandle == NULL) {\r
2529 Status = EFI_OUT_OF_RESOURCES;\r
20333c6d 2530 goto ON_EXIT;\r
ecc722ad 2531 }\r
2532\r
2533 //\r
2534 // Create Hii Extend Label OpCode.\r
2535 //\r
2536 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2537 StartOpCodeHandle,\r
2538 &gEfiIfrTianoGuid,\r
2539 NULL,\r
2540 sizeof (EFI_IFR_GUID_LABEL)\r
2541 );\r
2542 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
2543 StartLabel->Number = LabelNumber;\r
2544\r
2545 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
2546 EndOpCodeHandle,\r
2547 &gEfiIfrTianoGuid,\r
2548 NULL,\r
2549 sizeof (EFI_IFR_GUID_LABEL)\r
2550 );\r
2551 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
2552 EndLabel->Number = LABEL_END;\r
2553\r
2554 //\r
2555 // Read Variable.\r
2556 //\r
2557 DataSize = 0;\r
20333c6d 2558 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);\r
ecc722ad 2559 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2560 goto ON_EXIT;\r
2561 }\r
2562\r
2563 Data = (UINT8 *) AllocateZeroPool (DataSize);\r
2564 if (Data == NULL) {\r
2565 Status = EFI_OUT_OF_RESOURCES;\r
2566 goto ON_EXIT;\r
2567 }\r
2568\r
2569 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);\r
2570 if (EFI_ERROR (Status)) {\r
2571 goto ON_EXIT;\r
2572 }\r
2573\r
2574 GuidStr = AllocateZeroPool (100);\r
2575 if (GuidStr == NULL) {\r
2576 Status = EFI_OUT_OF_RESOURCES;\r
2577 goto ON_EXIT;\r
2578 }\r
2579\r
2580 //\r
2581 // Enumerate all KEK pub data.\r
2582 //\r
2583 ItemDataSize = (UINT32) DataSize;\r
2584 CertList = (EFI_SIGNATURE_LIST *) Data;\r
2585 GuidIndex = 0;\r
2586\r
2587 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {\r
2588\r
2589 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {\r
2590 Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);\r
2591 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2592 Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);\r
2593 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {\r
2594 Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);\r
2595 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {\r
2596 Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);\r
20333c6d
QL
2597 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
2598 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);\r
2599 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
2600 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);\r
2601 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
2602 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);\r
ecc722ad 2603 } else {\r
2604 //\r
2605 // The signature type is not supported in current implementation.\r
2606 //\r
b7d269ea 2607 ItemDataSize -= CertList->SignatureListSize;\r
2608 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
ecc722ad 2609 continue;\r
2610 }\r
2611\r
2612 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2613 for (Index = 0; Index < CertCount; Index++) {\r
20333c6d
QL
2614 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList\r
2615 + sizeof (EFI_SIGNATURE_LIST)\r
2616 + CertList->SignatureHeaderSize\r
ecc722ad 2617 + Index * CertList->SignatureSize);\r
2618 //\r
20333c6d 2619 // Display GUID and help\r
ecc722ad 2620 //\r
2621 GuidToString (&Cert->SignatureOwner, GuidStr, 100);\r
2622 GuidID = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);\r
2623 HiiCreateCheckBoxOpCode (\r
2624 StartOpCodeHandle,\r
2625 (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),\r
20333c6d
QL
2626 0,\r
2627 0,\r
2628 GuidID,\r
ecc722ad 2629 Help,\r
2630 EFI_IFR_FLAG_CALLBACK,\r
2631 0,\r
2632 NULL\r
20333c6d 2633 );\r
ecc722ad 2634 }\r
2635\r
2636 ItemDataSize -= CertList->SignatureListSize;\r
2637 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2638 }\r
2639\r
2640ON_EXIT:\r
2641 HiiUpdateForm (\r
2642 PrivateData->HiiHandle,\r
2643 &gSecureBootConfigFormSetGuid,\r
2644 FormId,\r
2645 StartOpCodeHandle,\r
2646 EndOpCodeHandle\r
2647 );\r
2648\r
2649 if (StartOpCodeHandle != NULL) {\r
2650 HiiFreeOpCodeHandle (StartOpCodeHandle);\r
2651 }\r
2652\r
2653 if (EndOpCodeHandle != NULL) {\r
2654 HiiFreeOpCodeHandle (EndOpCodeHandle);\r
2655 }\r
20333c6d 2656\r
ecc722ad 2657 if (Data != NULL) {\r
2658 FreePool (Data);\r
2659 }\r
2660\r
2661 if (GuidStr != NULL) {\r
2662 FreePool (GuidStr);\r
2663 }\r
2664\r
2665 return EFI_SUCCESS;\r
2666}\r
2667\r
beda2356 2668/**\r
20333c6d 2669 Delete a KEK entry from KEK database.\r
beda2356 2670\r
ecc722ad 2671 @param[in] PrivateData Module's private data.\r
2672 @param[in] QuestionId Question id of the KEK item to delete.\r
beda2356 2673\r
ecc722ad 2674 @retval EFI_SUCCESS Delete kek item successfully.\r
2675 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.\r
20333c6d 2676\r
ecc722ad 2677**/\r
2678EFI_STATUS\r
2679DeleteKeyExchangeKey (\r
2680 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,\r
2681 IN EFI_QUESTION_ID QuestionId\r
2682 )\r
2683{\r
2684 EFI_STATUS Status;\r
2685 UINTN DataSize;\r
2686 UINT8 *Data;\r
2687 UINT8 *OldData;\r
2688 UINT32 Attr;\r
2689 UINT32 Index;\r
2690 EFI_SIGNATURE_LIST *CertList;\r
2691 EFI_SIGNATURE_LIST *NewCertList;\r
2692 EFI_SIGNATURE_DATA *Cert;\r
2693 UINTN CertCount;\r
2694 UINT32 Offset;\r
2695 BOOLEAN IsKEKItemFound;\r
2696 UINT32 KekDataSize;\r
2697 UINTN DeleteKekIndex;\r
2698 UINTN GuidIndex;\r
2699\r
2700 Data = NULL;\r
2701 OldData = NULL;\r
2702 CertList = NULL;\r
2703 Cert = NULL;\r
20333c6d 2704 Attr = 0;\r
ecc722ad 2705 DeleteKekIndex = QuestionId - OPTION_DEL_KEK_QUESTION_ID;\r
f71ed839 2706\r
2707 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
2708 if (EFI_ERROR (Status)) {\r
2709 return Status;\r
2710 }\r
20333c6d 2711\r
ecc722ad 2712 //\r
2713 // Get original KEK variable.\r
20333c6d
QL
2714 //\r
2715 DataSize = 0;\r
ecc722ad 2716 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);\r
2717 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
2718 goto ON_EXIT;\r
2719 }\r
2720\r
2721 OldData = (UINT8*)AllocateZeroPool(DataSize);\r
2722 if (OldData == NULL) {\r
20333c6d 2723 Status = EFI_OUT_OF_RESOURCES;\r
ecc722ad 2724 goto ON_EXIT;\r
2725 }\r
2726\r
2727 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);\r
2728 if (EFI_ERROR(Status)) {\r
2729 goto ON_EXIT;\r
2730 }\r
2731\r
2732 //\r
20333c6d 2733 // Allocate space for new variable.\r
ecc722ad 2734 //\r
2735 Data = (UINT8*) AllocateZeroPool (DataSize);\r
2736 if (Data == NULL) {\r
2737 Status = EFI_OUT_OF_RESOURCES;\r
2738 goto ON_EXIT;\r
2739 }\r
2740\r
2741 //\r
2742 // Enumerate all KEK pub data and erasing the target item.\r
2743 //\r
2744 IsKEKItemFound = FALSE;\r
2745 KekDataSize = (UINT32) DataSize;\r
2746 CertList = (EFI_SIGNATURE_LIST *) OldData;\r
2747 Offset = 0;\r
2748 GuidIndex = 0;\r
2749 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2750 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||\r
2751 CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
2752 CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));\r
2753 NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);\r
2754 Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2755 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
2756 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
2757 for (Index = 0; Index < CertCount; Index++) {\r
2758 if (GuidIndex == DeleteKekIndex ) {\r
2759 //\r
2760 // Find it! Skip it!\r
2761 //\r
2762 NewCertList->SignatureListSize -= CertList->SignatureSize;\r
20333c6d 2763 IsKEKItemFound = TRUE;\r
ecc722ad 2764 } else {\r
2765 //\r
2766 // This item doesn't match. Copy it to the Data buffer.\r
2767 //\r
2768 CopyMem (Data + Offset, Cert, CertList->SignatureSize);\r
2769 Offset += CertList->SignatureSize;\r
2770 }\r
2771 GuidIndex++;\r
2772 Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);\r
2773 }\r
2774 } else {\r
2775 //\r
2776 // This List doesn't match. Copy it to the Data buffer.\r
2777 //\r
2778 CopyMem (Data + Offset, CertList, CertList->SignatureListSize);\r
2779 Offset += CertList->SignatureListSize;\r
2780 }\r
20333c6d 2781\r
ecc722ad 2782 KekDataSize -= CertList->SignatureListSize;\r
2783 CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);\r
2784 }\r
2785\r
2786 if (!IsKEKItemFound) {\r
2787 //\r
2788 // Doesn't find the Kek Item!\r
2789 //\r
2790 Status = EFI_NOT_FOUND;\r
2791 goto ON_EXIT;\r
2792 }\r
2793\r
2794 //\r
2795 // Delete the Signature header if there is no signature in the list.\r
2796 //\r
2797 KekDataSize = Offset;\r
2798 CertList = (EFI_SIGNATURE_LIST*) Data;\r
2799 Offset = 0;\r
2800 ZeroMem (OldData, KekDataSize);\r
2801 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
2802 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
33985e3b 2803 DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));\r
ecc722ad 2804 if (CertCount != 0) {\r
2805 CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);\r
2806 Offset += CertList->SignatureListSize;\r
20333c6d 2807 }\r
ecc722ad 2808 KekDataSize -= CertList->SignatureListSize;\r
2809 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
2810 }\r
2811\r
ecc722ad 2812 DataSize = Offset;\r
8c1babfd 2813 if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2814 Status = CreateTimeBasedPayload (&DataSize, &OldData);\r
2815 if (EFI_ERROR (Status)) {\r
2816 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
2817 goto ON_EXIT;\r
2818 }\r
2819 }\r
ecc722ad 2820\r
2821 Status = gRT->SetVariable(\r
20333c6d
QL
2822 EFI_KEY_EXCHANGE_KEY_NAME,\r
2823 &gEfiGlobalVariableGuid,\r
2824 Attr,\r
2825 DataSize,\r
ecc722ad 2826 OldData\r
2827 );\r
2828 if (EFI_ERROR (Status)) {\r
2829 DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));\r
2830 goto ON_EXIT;\r