]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
SecurityPkg: Add constraints on PK strength
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / SecureBootConfigDxe / SecureBootConfigImpl.c
1 /** @file
2 HII Config Access protocol implementation of SecureBoot configuration module.
3
4 Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "SecureBootConfigImpl.h"
11 #include <Library/BaseCryptLib.h>
12
13 CHAR16 mSecureBootStorageName[] = L"SECUREBOOT_CONFIGURATION";
14
15 SECUREBOOT_CONFIG_PRIVATE_DATA mSecureBootConfigPrivateDateTemplate = {
16 SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE,
17 {
18 SecureBootExtractConfig,
19 SecureBootRouteConfig,
20 SecureBootCallback
21 }
22 };
23
24 HII_VENDOR_DEVICE_PATH mSecureBootHiiVendorDevicePath = {
25 {
26 {
27 HARDWARE_DEVICE_PATH,
28 HW_VENDOR_DP,
29 {
30 (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
31 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
32 }
33 },
34 SECUREBOOT_CONFIG_FORM_SET_GUID
35 },
36 {
37 END_DEVICE_PATH_TYPE,
38 END_ENTIRE_DEVICE_PATH_SUBTYPE,
39 {
40 (UINT8) (END_DEVICE_PATH_LENGTH),
41 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
42 }
43 }
44 };
45
46
47 BOOLEAN mIsEnterSecureBootForm = FALSE;
48
49 //
50 // OID ASN.1 Value for Hash Algorithms
51 //
52 UINT8 mHashOidValue[] = {
53 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5
54 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1
55 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224
56 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256
57 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384
58 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512
59 };
60
61 HASH_TABLE mHash[] = {
62 { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL },
63 { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},
64 { L"SHA384", 48, &mHashOidValue[31], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},
65 { L"SHA512", 64, &mHashOidValue[40], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}
66 };
67
68 //
69 // Variable Definitions
70 //
71 UINT32 mPeCoffHeaderOffset = 0;
72 WIN_CERTIFICATE *mCertificate = NULL;
73 IMAGE_TYPE mImageType;
74 UINT8 *mImageBase = NULL;
75 UINTN mImageSize = 0;
76 UINT8 mImageDigest[MAX_DIGEST_SIZE];
77 UINTN mImageDigestSize;
78 EFI_GUID mCertType;
79 EFI_IMAGE_SECURITY_DATA_DIRECTORY *mSecDataDir = NULL;
80 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
81
82 //
83 // Possible DER-encoded certificate file suffixes, end with NULL pointer.
84 //
85 CHAR16* mDerEncodedSuffix[] = {
86 L".cer",
87 L".der",
88 L".crt",
89 NULL
90 };
91 CHAR16* mSupportX509Suffix = L"*.cer/der/crt";
92
93 //
94 // Prompt strings during certificate enrollment.
95 //
96 CHAR16* mX509EnrollPromptTitle[] = {
97 L"",
98 L"ERROR: Unsupported file type!",
99 L"ERROR: Unsupported certificate!",
100 NULL
101 };
102 CHAR16* mX509EnrollPromptString[] = {
103 L"",
104 L"Only DER encoded certificate file (*.cer/der/crt) is supported.",
105 L"Public key length should be equal to or greater than 2048 bits.",
106 NULL
107 };
108
109 SECUREBOOT_CONFIG_PRIVATE_DATA *gSecureBootPrivateData = NULL;
110
111 /**
112 This code cleans up enrolled file by closing file & free related resources attached to
113 enrolled file.
114
115 @param[in] FileContext FileContext cached in SecureBootConfig driver
116
117 **/
118 VOID
119 CloseEnrolledFile(
120 IN SECUREBOOT_FILE_CONTEXT *FileContext
121 )
122 {
123 if (FileContext->FHandle != NULL) {
124 CloseFile (FileContext->FHandle);
125 FileContext->FHandle = NULL;
126 }
127
128 if (FileContext->FileName != NULL){
129 FreePool(FileContext->FileName);
130 FileContext->FileName = NULL;
131 }
132 FileContext->FileType = UNKNOWN_FILE_TYPE;
133
134 }
135
136 /**
137 This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.
138
139 @param[in] FileSuffix The suffix of the input certificate file
140
141 @retval TRUE It's a DER-encoded certificate.
142 @retval FALSE It's NOT a DER-encoded certificate.
143
144 **/
145 BOOLEAN
146 IsDerEncodeCertificate (
147 IN CONST CHAR16 *FileSuffix
148 )
149 {
150 UINTN Index;
151 for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {
152 if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {
153 return TRUE;
154 }
155 }
156 return FALSE;
157 }
158
159 /**
160 This code checks if the file content complies with EFI_VARIABLE_AUTHENTICATION_2 format
161 The function reads file content but won't open/close given FileHandle.
162
163 @param[in] FileHandle The FileHandle to be checked
164
165 @retval TRUE The content is EFI_VARIABLE_AUTHENTICATION_2 format.
166 @retval FALSE The content is NOT a EFI_VARIABLE_AUTHENTICATION_2 format.
167
168 **/
169 BOOLEAN
170 IsAuthentication2Format (
171 IN EFI_FILE_HANDLE FileHandle
172 )
173 {
174 EFI_STATUS Status;
175 EFI_VARIABLE_AUTHENTICATION_2 *Auth2;
176 BOOLEAN IsAuth2Format;
177
178 IsAuth2Format = FALSE;
179
180 //
181 // Read the whole file content
182 //
183 Status = ReadFileContent(
184 FileHandle,
185 (VOID **) &mImageBase,
186 &mImageSize,
187 0
188 );
189 if (EFI_ERROR (Status)) {
190 goto ON_EXIT;
191 }
192
193 Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)mImageBase;
194 if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {
195 goto ON_EXIT;
196 }
197
198 if (CompareGuid(&gEfiCertPkcs7Guid, &Auth2->AuthInfo.CertType)) {
199 IsAuth2Format = TRUE;
200 }
201
202 ON_EXIT:
203 //
204 // Do not close File. simply check file content
205 //
206 if (mImageBase != NULL) {
207 FreePool (mImageBase);
208 mImageBase = NULL;
209 }
210
211 return IsAuth2Format;
212 }
213
214 /**
215 Set Secure Boot option into variable space.
216
217 @param[in] VarValue The option of Secure Boot.
218
219 @retval EFI_SUCCESS The operation is finished successfully.
220 @retval Others Other errors as indicated.
221
222 **/
223 EFI_STATUS
224 SaveSecureBootVariable (
225 IN UINT8 VarValue
226 )
227 {
228 EFI_STATUS Status;
229
230 Status = gRT->SetVariable (
231 EFI_SECURE_BOOT_ENABLE_NAME,
232 &gEfiSecureBootEnableDisableGuid,
233 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
234 sizeof (UINT8),
235 &VarValue
236 );
237 return Status;
238 }
239
240 /**
241 Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
242 descriptor with the input data. NO authentication is required in this function.
243
244 @param[in, out] DataSize On input, the size of Data buffer in bytes.
245 On output, the size of data returned in Data
246 buffer in bytes.
247 @param[in, out] Data On input, Pointer to data buffer to be wrapped or
248 pointer to NULL to wrap an empty payload.
249 On output, Pointer to the new payload date buffer allocated from pool,
250 it's caller's responsibility to free the memory when finish using it.
251
252 @retval EFI_SUCCESS Create time based payload successfully.
253 @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload.
254 @retval EFI_INVALID_PARAMETER The parameter is invalid.
255 @retval Others Unexpected error happens.
256
257 **/
258 EFI_STATUS
259 CreateTimeBasedPayload (
260 IN OUT UINTN *DataSize,
261 IN OUT UINT8 **Data
262 )
263 {
264 EFI_STATUS Status;
265 UINT8 *NewData;
266 UINT8 *Payload;
267 UINTN PayloadSize;
268 EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
269 UINTN DescriptorSize;
270 EFI_TIME Time;
271
272 if (Data == NULL || DataSize == NULL) {
273 return EFI_INVALID_PARAMETER;
274 }
275
276 //
277 // In Setup mode or Custom mode, the variable does not need to be signed but the
278 // parameters to the SetVariable() call still need to be prepared as authenticated
279 // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
280 // data in it.
281 //
282 Payload = *Data;
283 PayloadSize = *DataSize;
284
285 DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
286 NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
287 if (NewData == NULL) {
288 return EFI_OUT_OF_RESOURCES;
289 }
290
291 if ((Payload != NULL) && (PayloadSize != 0)) {
292 CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
293 }
294
295 DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
296
297 ZeroMem (&Time, sizeof (EFI_TIME));
298 Status = gRT->GetTime (&Time, NULL);
299 if (EFI_ERROR (Status)) {
300 FreePool(NewData);
301 return Status;
302 }
303 Time.Pad1 = 0;
304 Time.Nanosecond = 0;
305 Time.TimeZone = 0;
306 Time.Daylight = 0;
307 Time.Pad2 = 0;
308 CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
309
310 DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
311 DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
312 DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
313 CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
314
315 if (Payload != NULL) {
316 FreePool(Payload);
317 }
318
319 *DataSize = DescriptorSize + PayloadSize;
320 *Data = NewData;
321 return EFI_SUCCESS;
322 }
323
324 /**
325 Internal helper function to delete a Variable given its name and GUID, NO authentication
326 required.
327
328 @param[in] VariableName Name of the Variable.
329 @param[in] VendorGuid GUID of the Variable.
330
331 @retval EFI_SUCCESS Variable deleted successfully.
332 @retval Others The driver failed to start the device.
333
334 **/
335 EFI_STATUS
336 DeleteVariable (
337 IN CHAR16 *VariableName,
338 IN EFI_GUID *VendorGuid
339 )
340 {
341 EFI_STATUS Status;
342 VOID* Variable;
343 UINT8 *Data;
344 UINTN DataSize;
345 UINT32 Attr;
346
347 GetVariable2 (VariableName, VendorGuid, &Variable, NULL);
348 if (Variable == NULL) {
349 return EFI_SUCCESS;
350 }
351 FreePool (Variable);
352
353 Data = NULL;
354 DataSize = 0;
355 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
356 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
357
358 Status = CreateTimeBasedPayload (&DataSize, &Data);
359 if (EFI_ERROR (Status)) {
360 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
361 return Status;
362 }
363
364 Status = gRT->SetVariable (
365 VariableName,
366 VendorGuid,
367 Attr,
368 DataSize,
369 Data
370 );
371 if (Data != NULL) {
372 FreePool (Data);
373 }
374 return Status;
375 }
376
377 /**
378
379 Set the platform secure boot mode into "Custom" or "Standard" mode.
380
381 @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or
382 CUSTOM_SECURE_BOOT_MODE.
383
384 @return EFI_SUCCESS The platform has switched to the special mode successfully.
385 @return other Fail to operate the secure boot mode.
386
387 **/
388 EFI_STATUS
389 SetSecureBootMode (
390 IN UINT8 SecureBootMode
391 )
392 {
393 return gRT->SetVariable (
394 EFI_CUSTOM_MODE_NAME,
395 &gEfiCustomModeEnableGuid,
396 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
397 sizeof (UINT8),
398 &SecureBootMode
399 );
400 }
401
402 /**
403 This code checks if the encode type and key strength of X.509
404 certificate is qualified.
405
406 @param[in] X509FileContext FileContext of X.509 certificate storing
407 file.
408 @param[out] Error Error type checked in the certificate.
409
410 @return EFI_SUCCESS The certificate checked successfully.
411 @return EFI_INVALID_PARAMETER The parameter is invalid.
412 @return EFI_OUT_OF_RESOURCES Memory allocation failed.
413
414 **/
415 EFI_STATUS
416 CheckX509Certificate (
417 IN SECUREBOOT_FILE_CONTEXT* X509FileContext,
418 OUT ENROLL_KEY_ERROR* Error
419 )
420 {
421 EFI_STATUS Status;
422 UINT16* FilePostFix;
423 UINTN NameLength;
424 UINT8* X509Data;
425 UINTN X509DataSize;
426 void* X509PubKey;
427 UINTN PubKeyModSize;
428
429 if (X509FileContext->FileName == NULL) {
430 *Error = Unsupported_Type;
431 return EFI_INVALID_PARAMETER;
432 }
433
434 X509Data = NULL;
435 X509DataSize = 0;
436 X509PubKey = NULL;
437 PubKeyModSize = 0;
438
439 //
440 // Parse the file's postfix. Only support DER encoded X.509 certificate files.
441 //
442 NameLength = StrLen (X509FileContext->FileName);
443 if (NameLength <= 4) {
444 DEBUG ((DEBUG_ERROR, "Wrong X509 NameLength\n"));
445 *Error = Unsupported_Type;
446 return EFI_INVALID_PARAMETER;
447 }
448 FilePostFix = X509FileContext->FileName + NameLength - 4;
449 if (!IsDerEncodeCertificate (FilePostFix)) {
450 DEBUG ((DEBUG_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.\n", mSupportX509Suffix));
451 *Error = Unsupported_Type;
452 return EFI_INVALID_PARAMETER;
453 }
454 DEBUG ((DEBUG_INFO, "FileName= %s\n", X509FileContext->FileName));
455 DEBUG ((DEBUG_INFO, "FilePostFix = %s\n", FilePostFix));
456
457 //
458 // Read the certificate file content
459 //
460 Status = ReadFileContent (X509FileContext->FHandle, (VOID**) &X509Data, &X509DataSize, 0);
461 if (EFI_ERROR (Status)) {
462 DEBUG ((DEBUG_ERROR, "Error occured while reading the file.\n"));
463 goto ON_EXIT;
464 }
465
466 //
467 // Parse the public key context.
468 //
469 if (RsaGetPublicKeyFromX509 (X509Data, X509DataSize, &X509PubKey) == FALSE) {
470 DEBUG ((DEBUG_ERROR, "Error occured while parsing the pubkey from certificate.\n"));
471 Status = EFI_INVALID_PARAMETER;
472 *Error = Unsupported_Type;
473 goto ON_EXIT;
474 }
475
476 //
477 // Parse Module size of public key using interface provided by CryptoPkg, which is
478 // actually the size of public key.
479 //
480 if (X509PubKey != NULL) {
481 RsaGetKey (X509PubKey, RsaKeyN, NULL, &PubKeyModSize);
482 if (PubKeyModSize < CER_PUBKEY_MIN_SIZE) {
483 DEBUG ((DEBUG_ERROR, "Unqualified PK size, key size should be equal to or greater than 2048 bits.\n"));
484 Status = EFI_INVALID_PARAMETER;
485 *Error = Unqualified_Key;
486 }
487 RsaFree (X509PubKey);
488 }
489
490 ON_EXIT:
491 if (X509Data != NULL) {
492 FreePool (X509Data);
493 }
494
495 return Status;
496 }
497
498 /**
499 Generate the PK signature list from the X509 Certificate storing file (.cer)
500
501 @param[in] X509File FileHandle of X509 Certificate storing file.
502 @param[out] PkCert Point to the data buffer to store the signature list.
503
504 @return EFI_UNSUPPORTED Unsupported Key Length.
505 @return EFI_OUT_OF_RESOURCES There are not enough memory resources to form the signature list.
506
507 **/
508 EFI_STATUS
509 CreatePkX509SignatureList (
510 IN EFI_FILE_HANDLE X509File,
511 OUT EFI_SIGNATURE_LIST **PkCert
512 )
513 {
514 EFI_STATUS Status;
515 UINT8 *X509Data;
516 UINTN X509DataSize;
517 EFI_SIGNATURE_DATA *PkCertData;
518
519 X509Data = NULL;
520 PkCertData = NULL;
521 X509DataSize = 0;
522
523 Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);
524 if (EFI_ERROR (Status)) {
525 goto ON_EXIT;
526 }
527 ASSERT (X509Data != NULL);
528
529 //
530 // Allocate space for PK certificate list and initialize it.
531 // Create PK database entry with SignatureHeaderSize equals 0.
532 //
533 *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool (
534 sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
535 + X509DataSize
536 );
537 if (*PkCert == NULL) {
538 Status = EFI_OUT_OF_RESOURCES;
539 goto ON_EXIT;
540 }
541
542 (*PkCert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
543 + sizeof(EFI_SIGNATURE_DATA) - 1
544 + X509DataSize);
545 (*PkCert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
546 (*PkCert)->SignatureHeaderSize = 0;
547 CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid);
548 PkCertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert)
549 + sizeof(EFI_SIGNATURE_LIST)
550 + (*PkCert)->SignatureHeaderSize);
551 CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);
552 //
553 // Fill the PK database with PKpub data from X509 certificate file.
554 //
555 CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize);
556
557 ON_EXIT:
558
559 if (X509Data != NULL) {
560 FreePool (X509Data);
561 }
562
563 if (EFI_ERROR(Status) && *PkCert != NULL) {
564 FreePool (*PkCert);
565 *PkCert = NULL;
566 }
567
568 return Status;
569 }
570
571 /**
572 Enroll new PK into the System without original PK's authentication.
573
574 The SignatureOwner GUID will be the same with PK's vendorguid.
575
576 @param[in] PrivateData The module's private data.
577
578 @retval EFI_SUCCESS New PK enrolled successfully.
579 @retval EFI_INVALID_PARAMETER The parameter is invalid.
580 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
581
582 **/
583 EFI_STATUS
584 EnrollPlatformKey (
585 IN SECUREBOOT_CONFIG_PRIVATE_DATA* Private
586 )
587 {
588 EFI_STATUS Status;
589 UINT32 Attr;
590 UINTN DataSize;
591 EFI_SIGNATURE_LIST *PkCert;
592
593 PkCert = NULL;
594
595 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
596 if (EFI_ERROR (Status)) {
597 return Status;
598 }
599
600 //
601 // Prase the selected PK file and generate PK certificate list.
602 //
603 Status = CreatePkX509SignatureList (
604 Private->FileContext->FHandle,
605 &PkCert
606 );
607 if (EFI_ERROR (Status)) {
608 goto ON_EXIT;
609 }
610 ASSERT (PkCert != NULL);
611
612 //
613 // Set Platform Key variable.
614 //
615 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
616 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
617 DataSize = PkCert->SignatureListSize;
618 Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);
619 if (EFI_ERROR (Status)) {
620 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
621 goto ON_EXIT;
622 }
623
624 Status = gRT->SetVariable(
625 EFI_PLATFORM_KEY_NAME,
626 &gEfiGlobalVariableGuid,
627 Attr,
628 DataSize,
629 PkCert
630 );
631 if (EFI_ERROR (Status)) {
632 if (Status == EFI_OUT_OF_RESOURCES) {
633 DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n"));
634 }
635 goto ON_EXIT;
636 }
637
638 ON_EXIT:
639
640 if (PkCert != NULL) {
641 FreePool(PkCert);
642 }
643
644 CloseEnrolledFile(Private->FileContext);
645
646 return Status;
647 }
648
649 /**
650 Remove the PK variable.
651
652 @retval EFI_SUCCESS Delete PK successfully.
653 @retval Others Could not allow to delete PK.
654
655 **/
656 EFI_STATUS
657 DeletePlatformKey (
658 VOID
659 )
660 {
661 EFI_STATUS Status;
662
663 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
664 if (EFI_ERROR (Status)) {
665 return Status;
666 }
667
668 Status = DeleteVariable (
669 EFI_PLATFORM_KEY_NAME,
670 &gEfiGlobalVariableGuid
671 );
672 return Status;
673 }
674
675 /**
676 Enroll a new KEK item from public key storing file (*.pbk).
677
678 @param[in] PrivateData The module's private data.
679
680 @retval EFI_SUCCESS New KEK enrolled successfully.
681 @retval EFI_INVALID_PARAMETER The parameter is invalid.
682 @retval EFI_UNSUPPORTED Unsupported command.
683 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
684
685 **/
686 EFI_STATUS
687 EnrollRsa2048ToKek (
688 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
689 )
690 {
691 EFI_STATUS Status;
692 UINT32 Attr;
693 UINTN DataSize;
694 EFI_SIGNATURE_LIST *KekSigList;
695 UINTN KeyBlobSize;
696 UINT8 *KeyBlob;
697 CPL_KEY_INFO *KeyInfo;
698 EFI_SIGNATURE_DATA *KEKSigData;
699 UINTN KekSigListSize;
700 UINT8 *KeyBuffer;
701 UINTN KeyLenInBytes;
702
703 Attr = 0;
704 DataSize = 0;
705 KeyBuffer = NULL;
706 KeyBlobSize = 0;
707 KeyBlob = NULL;
708 KeyInfo = NULL;
709 KEKSigData = NULL;
710 KekSigList = NULL;
711 KekSigListSize = 0;
712
713 //
714 // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type.
715 // First, We have to parse out public key data from the pbk key file.
716 //
717 Status = ReadFileContent (
718 Private->FileContext->FHandle,
719 (VOID**) &KeyBlob,
720 &KeyBlobSize,
721 0
722 );
723 if (EFI_ERROR (Status)) {
724 goto ON_EXIT;
725 }
726 ASSERT (KeyBlob != NULL);
727 KeyInfo = (CPL_KEY_INFO *) KeyBlob;
728 if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {
729 DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));
730 Status = EFI_UNSUPPORTED;
731 goto ON_EXIT;
732 }
733
734 //
735 // Convert the Public key to fix octet string format represented in RSA PKCS#1.
736 //
737 KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;
738 KeyBuffer = AllocateZeroPool (KeyLenInBytes);
739 if (KeyBuffer == NULL) {
740 Status = EFI_OUT_OF_RESOURCES;
741 goto ON_EXIT;
742 }
743 Int2OctStr (
744 (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)),
745 KeyLenInBytes / sizeof (UINTN),
746 KeyBuffer,
747 KeyLenInBytes
748 );
749 CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes);
750
751 //
752 // Form an new EFI_SIGNATURE_LIST.
753 //
754 KekSigListSize = sizeof(EFI_SIGNATURE_LIST)
755 + sizeof(EFI_SIGNATURE_DATA) - 1
756 + WIN_CERT_UEFI_RSA2048_SIZE;
757
758 KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
759 if (KekSigList == NULL) {
760 Status = EFI_OUT_OF_RESOURCES;
761 goto ON_EXIT;
762 }
763
764 KekSigList->SignatureListSize = sizeof(EFI_SIGNATURE_LIST)
765 + sizeof(EFI_SIGNATURE_DATA) - 1
766 + WIN_CERT_UEFI_RSA2048_SIZE;
767 KekSigList->SignatureHeaderSize = 0;
768 KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;
769 CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid);
770
771 KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST));
772 CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
773 CopyMem (
774 KEKSigData->SignatureData,
775 KeyBlob + sizeof(CPL_KEY_INFO),
776 WIN_CERT_UEFI_RSA2048_SIZE
777 );
778
779 //
780 // Check if KEK entry has been already existed.
781 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
782 // new KEK to original variable.
783 //
784 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
785 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
786 Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
787 if (EFI_ERROR (Status)) {
788 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
789 goto ON_EXIT;
790 }
791
792 Status = gRT->GetVariable(
793 EFI_KEY_EXCHANGE_KEY_NAME,
794 &gEfiGlobalVariableGuid,
795 NULL,
796 &DataSize,
797 NULL
798 );
799 if (Status == EFI_BUFFER_TOO_SMALL) {
800 Attr |= EFI_VARIABLE_APPEND_WRITE;
801 } else if (Status != EFI_NOT_FOUND) {
802 goto ON_EXIT;
803 }
804
805 //
806 // Done. Now we have formed the correct KEKpub database item, just set it into variable storage,
807 //
808 Status = gRT->SetVariable(
809 EFI_KEY_EXCHANGE_KEY_NAME,
810 &gEfiGlobalVariableGuid,
811 Attr,
812 KekSigListSize,
813 KekSigList
814 );
815 if (EFI_ERROR (Status)) {
816 goto ON_EXIT;
817 }
818
819 ON_EXIT:
820
821 CloseEnrolledFile(Private->FileContext);
822
823 if (Private->SignatureGUID != NULL) {
824 FreePool (Private->SignatureGUID);
825 Private->SignatureGUID = NULL;
826 }
827
828 if (KeyBlob != NULL) {
829 FreePool (KeyBlob);
830 }
831 if (KeyBuffer != NULL) {
832 FreePool (KeyBuffer);
833 }
834 if (KekSigList != NULL) {
835 FreePool (KekSigList);
836 }
837
838 return Status;
839 }
840
841 /**
842 Enroll a new KEK item from X509 certificate file.
843
844 @param[in] PrivateData The module's private data.
845
846 @retval EFI_SUCCESS New X509 is enrolled successfully.
847 @retval EFI_INVALID_PARAMETER The parameter is invalid.
848 @retval EFI_UNSUPPORTED Unsupported command.
849 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
850
851 **/
852 EFI_STATUS
853 EnrollX509ToKek (
854 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
855 )
856 {
857 EFI_STATUS Status;
858 UINTN X509DataSize;
859 VOID *X509Data;
860 EFI_SIGNATURE_DATA *KEKSigData;
861 EFI_SIGNATURE_LIST *KekSigList;
862 UINTN DataSize;
863 UINTN KekSigListSize;
864 UINT32 Attr;
865
866 X509Data = NULL;
867 X509DataSize = 0;
868 KekSigList = NULL;
869 KekSigListSize = 0;
870 DataSize = 0;
871 KEKSigData = NULL;
872
873 Status = ReadFileContent (
874 Private->FileContext->FHandle,
875 &X509Data,
876 &X509DataSize,
877 0
878 );
879 if (EFI_ERROR (Status)) {
880 goto ON_EXIT;
881 }
882 ASSERT (X509Data != NULL);
883
884 KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
885 KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
886 if (KekSigList == NULL) {
887 Status = EFI_OUT_OF_RESOURCES;
888 goto ON_EXIT;
889 }
890
891 //
892 // Fill Certificate Database parameters.
893 //
894 KekSigList->SignatureListSize = (UINT32) KekSigListSize;
895 KekSigList->SignatureHeaderSize = 0;
896 KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
897 CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid);
898
899 KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST));
900 CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
901 CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize);
902
903 //
904 // Check if KEK been already existed.
905 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
906 // new kek to original variable
907 //
908 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
909 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
910 Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
911 if (EFI_ERROR (Status)) {
912 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
913 goto ON_EXIT;
914 }
915
916 Status = gRT->GetVariable(
917 EFI_KEY_EXCHANGE_KEY_NAME,
918 &gEfiGlobalVariableGuid,
919 NULL,
920 &DataSize,
921 NULL
922 );
923 if (Status == EFI_BUFFER_TOO_SMALL) {
924 Attr |= EFI_VARIABLE_APPEND_WRITE;
925 } else if (Status != EFI_NOT_FOUND) {
926 goto ON_EXIT;
927 }
928
929 Status = gRT->SetVariable(
930 EFI_KEY_EXCHANGE_KEY_NAME,
931 &gEfiGlobalVariableGuid,
932 Attr,
933 KekSigListSize,
934 KekSigList
935 );
936 if (EFI_ERROR (Status)) {
937 goto ON_EXIT;
938 }
939
940 ON_EXIT:
941
942 CloseEnrolledFile(Private->FileContext);
943
944 if (Private->SignatureGUID != NULL) {
945 FreePool (Private->SignatureGUID);
946 Private->SignatureGUID = NULL;
947 }
948
949 if (KekSigList != NULL) {
950 FreePool (KekSigList);
951 }
952
953 return Status;
954 }
955
956 /**
957 Enroll new KEK into the System without PK's authentication.
958 The SignatureOwner GUID will be Private->SignatureGUID.
959
960 @param[in] PrivateData The module's private data.
961
962 @retval EFI_SUCCESS New KEK enrolled successful.
963 @retval EFI_INVALID_PARAMETER The parameter is invalid.
964 @retval others Fail to enroll KEK data.
965
966 **/
967 EFI_STATUS
968 EnrollKeyExchangeKey (
969 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
970 )
971 {
972 UINT16* FilePostFix;
973 EFI_STATUS Status;
974 UINTN NameLength;
975
976 if ((Private->FileContext->FHandle == NULL) || (Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {
977 return EFI_INVALID_PARAMETER;
978 }
979
980 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
981 if (EFI_ERROR (Status)) {
982 return Status;
983 }
984
985 //
986 // Parse the file's postfix. Supports DER-encoded X509 certificate,
987 // and .pbk as RSA public key file.
988 //
989 NameLength = StrLen (Private->FileContext->FileName);
990 if (NameLength <= 4) {
991 return EFI_INVALID_PARAMETER;
992 }
993 FilePostFix = Private->FileContext->FileName + NameLength - 4;
994 if (IsDerEncodeCertificate(FilePostFix)) {
995 return EnrollX509ToKek (Private);
996 } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {
997 return EnrollRsa2048ToKek (Private);
998 } else {
999 //
1000 // File type is wrong, simply close it
1001 //
1002 CloseEnrolledFile(Private->FileContext);
1003
1004 return EFI_INVALID_PARAMETER;
1005 }
1006 }
1007
1008 /**
1009 Enroll a new X509 certificate into Signature Database (DB or DBX or DBT) without
1010 KEK's authentication.
1011
1012 @param[in] PrivateData The module's private data.
1013 @param[in] VariableName Variable name of signature database, must be
1014 EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
1015
1016 @retval EFI_SUCCESS New X509 is enrolled successfully.
1017 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
1018
1019 **/
1020 EFI_STATUS
1021 EnrollX509toSigDB (
1022 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1023 IN CHAR16 *VariableName
1024 )
1025 {
1026 EFI_STATUS Status;
1027 UINTN X509DataSize;
1028 VOID *X509Data;
1029 EFI_SIGNATURE_LIST *SigDBCert;
1030 EFI_SIGNATURE_DATA *SigDBCertData;
1031 VOID *Data;
1032 UINTN DataSize;
1033 UINTN SigDBSize;
1034 UINT32 Attr;
1035
1036 X509DataSize = 0;
1037 SigDBSize = 0;
1038 DataSize = 0;
1039 X509Data = NULL;
1040 SigDBCert = NULL;
1041 SigDBCertData = NULL;
1042 Data = NULL;
1043
1044 Status = ReadFileContent (
1045 Private->FileContext->FHandle,
1046 &X509Data,
1047 &X509DataSize,
1048 0
1049 );
1050 if (EFI_ERROR (Status)) {
1051 goto ON_EXIT;
1052 }
1053 ASSERT (X509Data != NULL);
1054
1055 SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
1056
1057 Data = AllocateZeroPool (SigDBSize);
1058 if (Data == NULL) {
1059 Status = EFI_OUT_OF_RESOURCES;
1060 goto ON_EXIT;
1061 }
1062
1063 //
1064 // Fill Certificate Database parameters.
1065 //
1066 SigDBCert = (EFI_SIGNATURE_LIST*) Data;
1067 SigDBCert->SignatureListSize = (UINT32) SigDBSize;
1068 SigDBCert->SignatureHeaderSize = 0;
1069 SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
1070 CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid);
1071
1072 SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST));
1073 CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
1074 CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize);
1075
1076 //
1077 // Check if signature database entry has been already existed.
1078 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
1079 // new signature data to original variable
1080 //
1081 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
1082 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1083 Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
1084 if (EFI_ERROR (Status)) {
1085 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
1086 goto ON_EXIT;
1087 }
1088
1089 Status = gRT->GetVariable(
1090 VariableName,
1091 &gEfiImageSecurityDatabaseGuid,
1092 NULL,
1093 &DataSize,
1094 NULL
1095 );
1096 if (Status == EFI_BUFFER_TOO_SMALL) {
1097 Attr |= EFI_VARIABLE_APPEND_WRITE;
1098 } else if (Status != EFI_NOT_FOUND) {
1099 goto ON_EXIT;
1100 }
1101
1102 Status = gRT->SetVariable(
1103 VariableName,
1104 &gEfiImageSecurityDatabaseGuid,
1105 Attr,
1106 SigDBSize,
1107 Data
1108 );
1109 if (EFI_ERROR (Status)) {
1110 goto ON_EXIT;
1111 }
1112
1113 ON_EXIT:
1114
1115 CloseEnrolledFile(Private->FileContext);
1116
1117 if (Private->SignatureGUID != NULL) {
1118 FreePool (Private->SignatureGUID);
1119 Private->SignatureGUID = NULL;
1120 }
1121
1122 if (Data != NULL) {
1123 FreePool (Data);
1124 }
1125
1126 if (X509Data != NULL) {
1127 FreePool (X509Data);
1128 }
1129
1130 return Status;
1131 }
1132
1133 /**
1134 Check whether signature is in specified database.
1135
1136 @param[in] VariableName Name of database variable that is searched in.
1137 @param[in] Signature Pointer to signature that is searched for.
1138 @param[in] SignatureSize Size of Signature.
1139
1140 @return TRUE Found the signature in the variable database.
1141 @return FALSE Not found the signature in the variable database.
1142
1143 **/
1144 BOOLEAN
1145 IsSignatureFoundInDatabase (
1146 IN CHAR16 *VariableName,
1147 IN UINT8 *Signature,
1148 IN UINTN SignatureSize
1149 )
1150 {
1151 EFI_STATUS Status;
1152 EFI_SIGNATURE_LIST *CertList;
1153 EFI_SIGNATURE_DATA *Cert;
1154 UINTN DataSize;
1155 UINT8 *Data;
1156 UINTN Index;
1157 UINTN CertCount;
1158 BOOLEAN IsFound;
1159
1160 //
1161 // Read signature database variable.
1162 //
1163 IsFound = FALSE;
1164 Data = NULL;
1165 DataSize = 0;
1166 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1167 if (Status != EFI_BUFFER_TOO_SMALL) {
1168 return FALSE;
1169 }
1170
1171 Data = (UINT8 *) AllocateZeroPool (DataSize);
1172 if (Data == NULL) {
1173 return FALSE;
1174 }
1175
1176 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1177 if (EFI_ERROR (Status)) {
1178 goto Done;
1179 }
1180
1181 //
1182 // Enumerate all signature data in SigDB to check if signature exists for executable.
1183 //
1184 CertList = (EFI_SIGNATURE_LIST *) Data;
1185 while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
1186 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
1187 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
1188 if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, &gEfiCertX509Guid))) {
1189 for (Index = 0; Index < CertCount; Index++) {
1190 if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {
1191 //
1192 // Find the signature in database.
1193 //
1194 IsFound = TRUE;
1195 break;
1196 }
1197 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
1198 }
1199
1200 if (IsFound) {
1201 break;
1202 }
1203 }
1204
1205 DataSize -= CertList->SignatureListSize;
1206 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
1207 }
1208
1209 Done:
1210 if (Data != NULL) {
1211 FreePool (Data);
1212 }
1213
1214 return IsFound;
1215 }
1216
1217 /**
1218 Calculate the hash of a certificate data with the specified hash algorithm.
1219
1220 @param[in] CertData The certificate data to be hashed.
1221 @param[in] CertSize The certificate size in bytes.
1222 @param[in] HashAlg The specified hash algorithm.
1223 @param[out] CertHash The output digest of the certificate
1224
1225 @retval TRUE Successfully got the hash of the CertData.
1226 @retval FALSE Failed to get the hash of CertData.
1227
1228 **/
1229 BOOLEAN
1230 CalculateCertHash (
1231 IN UINT8 *CertData,
1232 IN UINTN CertSize,
1233 IN UINT32 HashAlg,
1234 OUT UINT8 *CertHash
1235 )
1236 {
1237 BOOLEAN Status;
1238 VOID *HashCtx;
1239 UINTN CtxSize;
1240 UINT8 *TBSCert;
1241 UINTN TBSCertSize;
1242
1243 HashCtx = NULL;
1244 Status = FALSE;
1245
1246 if (HashAlg >= HASHALG_MAX) {
1247 return FALSE;
1248 }
1249
1250 //
1251 // Retrieve the TBSCertificate for Hash Calculation.
1252 //
1253 if (!X509GetTBSCert (CertData, CertSize, &TBSCert, &TBSCertSize)) {
1254 return FALSE;
1255 }
1256
1257 //
1258 // 1. Initialize context of hash.
1259 //
1260 CtxSize = mHash[HashAlg].GetContextSize ();
1261 HashCtx = AllocatePool (CtxSize);
1262 ASSERT (HashCtx != NULL);
1263
1264 //
1265 // 2. Initialize a hash context.
1266 //
1267 Status = mHash[HashAlg].HashInit (HashCtx);
1268 if (!Status) {
1269 goto Done;
1270 }
1271
1272 //
1273 // 3. Calculate the hash.
1274 //
1275 Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
1276 if (!Status) {
1277 goto Done;
1278 }
1279
1280 //
1281 // 4. Get the hash result.
1282 //
1283 ZeroMem (CertHash, mHash[HashAlg].DigestLength);
1284 Status = mHash[HashAlg].HashFinal (HashCtx, CertHash);
1285
1286 Done:
1287 if (HashCtx != NULL) {
1288 FreePool (HashCtx);
1289 }
1290
1291 return Status;
1292 }
1293
1294 /**
1295 Check whether the hash of an X.509 certificate is in forbidden database (DBX).
1296
1297 @param[in] Certificate Pointer to X.509 Certificate that is searched for.
1298 @param[in] CertSize Size of X.509 Certificate.
1299
1300 @return TRUE Found the certificate hash in the forbidden database.
1301 @return FALSE Certificate hash is Not found in the forbidden database.
1302
1303 **/
1304 BOOLEAN
1305 IsCertHashFoundInDbx (
1306 IN UINT8 *Certificate,
1307 IN UINTN CertSize
1308 )
1309 {
1310 BOOLEAN IsFound;
1311 EFI_STATUS Status;
1312 EFI_SIGNATURE_LIST *DbxList;
1313 EFI_SIGNATURE_DATA *CertHash;
1314 UINTN CertHashCount;
1315 UINTN Index;
1316 UINT32 HashAlg;
1317 UINT8 CertDigest[MAX_DIGEST_SIZE];
1318 UINT8 *DbxCertHash;
1319 UINTN SiglistHeaderSize;
1320 UINT8 *Data;
1321 UINTN DataSize;
1322
1323 IsFound = FALSE;
1324 HashAlg = HASHALG_MAX;
1325 Data = NULL;
1326
1327 //
1328 // Read signature database variable.
1329 //
1330 DataSize = 0;
1331 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1332 if (Status != EFI_BUFFER_TOO_SMALL) {
1333 return FALSE;
1334 }
1335
1336 Data = (UINT8 *) AllocateZeroPool (DataSize);
1337 if (Data == NULL) {
1338 return FALSE;
1339 }
1340
1341 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1342 if (EFI_ERROR (Status)) {
1343 goto Done;
1344 }
1345
1346 //
1347 // Check whether the certificate hash exists in the forbidden database.
1348 //
1349 DbxList = (EFI_SIGNATURE_LIST *) Data;
1350 while ((DataSize > 0) && (DataSize >= DbxList->SignatureListSize)) {
1351 //
1352 // Determine Hash Algorithm of Certificate in the forbidden database.
1353 //
1354 if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
1355 HashAlg = HASHALG_SHA256;
1356 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
1357 HashAlg = HASHALG_SHA384;
1358 } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
1359 HashAlg = HASHALG_SHA512;
1360 } else {
1361 DataSize -= DbxList->SignatureListSize;
1362 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1363 continue;
1364 }
1365
1366 //
1367 // Calculate the hash value of current db certificate for comparision.
1368 //
1369 if (!CalculateCertHash (Certificate, CertSize, HashAlg, CertDigest)) {
1370 goto Done;
1371 }
1372
1373 SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
1374 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
1375 CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
1376 for (Index = 0; Index < CertHashCount; Index++) {
1377 //
1378 // Iterate each Signature Data Node within this CertList for verify.
1379 //
1380 DbxCertHash = CertHash->SignatureData;
1381 if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
1382 //
1383 // Hash of Certificate is found in forbidden database.
1384 //
1385 IsFound = TRUE;
1386 goto Done;
1387 }
1388 CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
1389 }
1390
1391 DataSize -= DbxList->SignatureListSize;
1392 DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
1393 }
1394
1395 Done:
1396 if (Data != NULL) {
1397 FreePool (Data);
1398 }
1399
1400 return IsFound;
1401 }
1402
1403 /**
1404 Check whether the signature list exists in given variable data.
1405
1406 It searches the signature list for the certificate hash by CertType.
1407 If the signature list is found, get the offset of Database for the
1408 next hash of a certificate.
1409
1410 @param[in] Database Variable data to save signature list.
1411 @param[in] DatabaseSize Variable size.
1412 @param[in] SignatureType The type of the signature.
1413 @param[out] Offset The offset to save a new hash of certificate.
1414
1415 @return TRUE The signature list is found in the forbidden database.
1416 @return FALSE The signature list is not found in the forbidden database.
1417 **/
1418 BOOLEAN
1419 GetSignaturelistOffset (
1420 IN EFI_SIGNATURE_LIST *Database,
1421 IN UINTN DatabaseSize,
1422 IN EFI_GUID *SignatureType,
1423 OUT UINTN *Offset
1424 )
1425 {
1426 EFI_SIGNATURE_LIST *SigList;
1427 UINTN SiglistSize;
1428
1429 if ((Database == NULL) || (DatabaseSize == 0)) {
1430 *Offset = 0;
1431 return FALSE;
1432 }
1433
1434 SigList = Database;
1435 SiglistSize = DatabaseSize;
1436 while ((SiglistSize > 0) && (SiglistSize >= SigList->SignatureListSize)) {
1437 if (CompareGuid (&SigList->SignatureType, SignatureType)) {
1438 *Offset = DatabaseSize - SiglistSize;
1439 return TRUE;
1440 }
1441 SiglistSize -= SigList->SignatureListSize;
1442 SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
1443 }
1444 *Offset = 0;
1445 return FALSE;
1446 }
1447
1448 /**
1449 Enroll a new X509 certificate hash into Signature Database (dbx) without
1450 KEK's authentication.
1451
1452 @param[in] PrivateData The module's private data.
1453 @param[in] HashAlg The hash algorithm to enroll the certificate.
1454 @param[in] RevocationDate The revocation date of the certificate.
1455 @param[in] RevocationTime The revocation time of the certificate.
1456 @param[in] AlwaysRevocation Indicate whether the certificate is always revoked.
1457
1458 @retval EFI_SUCCESS New X509 is enrolled successfully.
1459 @retval EFI_INVALID_PARAMETER The parameter is invalid.
1460 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
1461
1462 **/
1463 EFI_STATUS
1464 EnrollX509HashtoSigDB (
1465 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1466 IN UINT32 HashAlg,
1467 IN EFI_HII_DATE *RevocationDate,
1468 IN EFI_HII_TIME *RevocationTime,
1469 IN BOOLEAN AlwaysRevocation
1470 )
1471 {
1472 EFI_STATUS Status;
1473 UINTN X509DataSize;
1474 VOID *X509Data;
1475 EFI_SIGNATURE_LIST *SignatureList;
1476 UINTN SignatureListSize;
1477 UINT8 *Data;
1478 UINT8 *NewData;
1479 UINTN DataSize;
1480 UINTN DbSize;
1481 UINT32 Attr;
1482 EFI_SIGNATURE_DATA *SignatureData;
1483 UINTN SignatureSize;
1484 EFI_GUID SignatureType;
1485 UINTN Offset;
1486 UINT8 CertHash[MAX_DIGEST_SIZE];
1487 UINT16* FilePostFix;
1488 UINTN NameLength;
1489 EFI_TIME *Time;
1490
1491 X509DataSize = 0;
1492 DbSize = 0;
1493 X509Data = NULL;
1494 SignatureData = NULL;
1495 SignatureList = NULL;
1496 Data = NULL;
1497 NewData = NULL;
1498
1499 if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
1500 return EFI_INVALID_PARAMETER;
1501 }
1502
1503 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
1504 if (EFI_ERROR (Status)) {
1505 return Status;
1506 }
1507
1508 //
1509 // Parse the file's postfix.
1510 //
1511 NameLength = StrLen (Private->FileContext->FileName);
1512 if (NameLength <= 4) {
1513 return EFI_INVALID_PARAMETER;
1514 }
1515 FilePostFix = Private->FileContext->FileName + NameLength - 4;
1516 if (!IsDerEncodeCertificate(FilePostFix)) {
1517 //
1518 // Only supports DER-encoded X509 certificate.
1519 //
1520 return EFI_INVALID_PARAMETER;
1521 }
1522
1523 //
1524 // Get the certificate from file and calculate its hash.
1525 //
1526 Status = ReadFileContent (
1527 Private->FileContext->FHandle,
1528 &X509Data,
1529 &X509DataSize,
1530 0
1531 );
1532 if (EFI_ERROR (Status)) {
1533 goto ON_EXIT;
1534 }
1535 ASSERT (X509Data != NULL);
1536
1537 if (!CalculateCertHash (X509Data, X509DataSize, HashAlg, CertHash)) {
1538 goto ON_EXIT;
1539 }
1540
1541 //
1542 // Get the variable for enrollment.
1543 //
1544 DataSize = 0;
1545 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
1546 if (Status == EFI_BUFFER_TOO_SMALL) {
1547 Data = (UINT8 *) AllocateZeroPool (DataSize);
1548 if (Data == NULL) {
1549 return EFI_OUT_OF_RESOURCES;
1550 }
1551
1552 Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
1553 if (EFI_ERROR (Status)) {
1554 goto ON_EXIT;
1555 }
1556 }
1557
1558 //
1559 // Allocate memory for Signature and fill the Signature
1560 //
1561 SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + sizeof (EFI_TIME) + mHash[HashAlg].DigestLength;
1562 SignatureData = (EFI_SIGNATURE_DATA *) AllocateZeroPool (SignatureSize);
1563 if (SignatureData == NULL) {
1564 return EFI_OUT_OF_RESOURCES;
1565 }
1566 CopyGuid (&SignatureData->SignatureOwner, Private->SignatureGUID);
1567 CopyMem (SignatureData->SignatureData, CertHash, mHash[HashAlg].DigestLength);
1568
1569 //
1570 // Fill the time.
1571 //
1572 if (!AlwaysRevocation) {
1573 Time = (EFI_TIME *)(&SignatureData->SignatureData + mHash[HashAlg].DigestLength);
1574 Time->Year = RevocationDate->Year;
1575 Time->Month = RevocationDate->Month;
1576 Time->Day = RevocationDate->Day;
1577 Time->Hour = RevocationTime->Hour;
1578 Time->Minute = RevocationTime->Minute;
1579 Time->Second = RevocationTime->Second;
1580 }
1581
1582 //
1583 // Determine the GUID for certificate hash.
1584 //
1585 switch (HashAlg) {
1586 case HASHALG_SHA256:
1587 SignatureType = gEfiCertX509Sha256Guid;
1588 break;
1589 case HASHALG_SHA384:
1590 SignatureType = gEfiCertX509Sha384Guid;
1591 break;
1592 case HASHALG_SHA512:
1593 SignatureType = gEfiCertX509Sha512Guid;
1594 break;
1595 default:
1596 return FALSE;
1597 }
1598
1599 //
1600 // Add signature into the new variable data buffer
1601 //
1602 if (GetSignaturelistOffset((EFI_SIGNATURE_LIST *)Data, DataSize, &SignatureType, &Offset)) {
1603 //
1604 // Add the signature to the found signaturelist.
1605 //
1606 DbSize = DataSize + SignatureSize;
1607 NewData = AllocateZeroPool (DbSize);
1608 if (NewData == NULL) {
1609 Status = EFI_OUT_OF_RESOURCES;
1610 goto ON_EXIT;
1611 }
1612
1613 SignatureList = (EFI_SIGNATURE_LIST *)(Data + Offset);
1614 SignatureListSize = (UINTN) ReadUnaligned32 ((UINT32 *)&SignatureList->SignatureListSize);
1615 CopyMem (NewData, Data, Offset + SignatureListSize);
1616
1617 SignatureList = (EFI_SIGNATURE_LIST *)(NewData + Offset);
1618 WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32)(SignatureListSize + SignatureSize));
1619
1620 Offset += SignatureListSize;
1621 CopyMem (NewData + Offset, SignatureData, SignatureSize);
1622 CopyMem (NewData + Offset + SignatureSize, Data + Offset, DataSize - Offset);
1623
1624 FreePool (Data);
1625 Data = NewData;
1626 DataSize = DbSize;
1627 } else {
1628 //
1629 // Create a new signaturelist, and add the signature into the signaturelist.
1630 //
1631 DbSize = DataSize + sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
1632 NewData = AllocateZeroPool (DbSize);
1633 if (NewData == NULL) {
1634 Status = EFI_OUT_OF_RESOURCES;
1635 goto ON_EXIT;
1636 }
1637 //
1638 // Fill Certificate Database parameters.
1639 //
1640 SignatureList = (EFI_SIGNATURE_LIST*) (NewData + DataSize);
1641 SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
1642 WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32) SignatureListSize);
1643 WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureSize, (UINT32) SignatureSize);
1644 CopyGuid (&SignatureList->SignatureType, &SignatureType);
1645 CopyMem ((UINT8* ) SignatureList + sizeof (EFI_SIGNATURE_LIST), SignatureData, SignatureSize);
1646 if ((DataSize != 0) && (Data != NULL)) {
1647 CopyMem (NewData, Data, DataSize);
1648 FreePool (Data);
1649 }
1650 Data = NewData;
1651 DataSize = DbSize;
1652 }
1653
1654 Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &Data);
1655 if (EFI_ERROR (Status)) {
1656 goto ON_EXIT;
1657 }
1658
1659 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
1660 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
1661 Status = gRT->SetVariable(
1662 EFI_IMAGE_SECURITY_DATABASE1,
1663 &gEfiImageSecurityDatabaseGuid,
1664 Attr,
1665 DataSize,
1666 Data
1667 );
1668 if (EFI_ERROR (Status)) {
1669 goto ON_EXIT;
1670 }
1671
1672 ON_EXIT:
1673
1674 CloseEnrolledFile(Private->FileContext);
1675
1676 if (Private->SignatureGUID != NULL) {
1677 FreePool (Private->SignatureGUID);
1678 Private->SignatureGUID = NULL;
1679 }
1680
1681 if (Data != NULL) {
1682 FreePool (Data);
1683 }
1684
1685 if (SignatureData != NULL) {
1686 FreePool (SignatureData);
1687 }
1688
1689 if (X509Data != NULL) {
1690 FreePool (X509Data);
1691 }
1692
1693 return Status;
1694 }
1695
1696 /**
1697 Check whether a certificate from a file exists in dbx.
1698
1699 @param[in] PrivateData The module's private data.
1700 @param[in] VariableName Variable name of signature database, must be
1701 EFI_IMAGE_SECURITY_DATABASE1.
1702
1703 @retval TRUE The X509 certificate is found in dbx successfully.
1704 @retval FALSE The X509 certificate is not found in dbx.
1705 **/
1706 BOOLEAN
1707 IsX509CertInDbx (
1708 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
1709 IN CHAR16 *VariableName
1710 )
1711 {
1712 EFI_STATUS Status;
1713 UINTN X509DataSize;
1714 VOID *X509Data;
1715 BOOLEAN IsFound;
1716
1717 //
1718 // Read the certificate from file
1719 //
1720 X509DataSize = 0;
1721 X509Data = NULL;
1722 Status = ReadFileContent (
1723 Private->FileContext->FHandle,
1724 &X509Data,
1725 &X509DataSize,
1726 0
1727 );
1728 if (EFI_ERROR (Status)) {
1729 return FALSE;
1730 }
1731
1732 //
1733 // Check the raw certificate.
1734 //
1735 IsFound = FALSE;
1736 if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, X509Data, X509DataSize)) {
1737 IsFound = TRUE;
1738 goto ON_EXIT;
1739 }
1740
1741 //
1742 // Check the hash of certificate.
1743 //
1744 if (IsCertHashFoundInDbx (X509Data, X509DataSize)) {
1745 IsFound = TRUE;
1746 goto ON_EXIT;
1747 }
1748
1749 ON_EXIT:
1750 if (X509Data != NULL) {
1751 FreePool (X509Data);
1752 }
1753
1754 return IsFound;
1755 }
1756
1757 /**
1758 Reads contents of a PE/COFF image in memory buffer.
1759
1760 Caution: This function may receive untrusted input.
1761 PE/COFF image is external input, so this function will make sure the PE/COFF image content
1762 read is within the image buffer.
1763
1764 @param FileHandle Pointer to the file handle to read the PE/COFF image.
1765 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1766 @param ReadSize On input, the size in bytes of the requested read operation.
1767 On output, the number of bytes actually read.
1768 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1769
1770 @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
1771 **/
1772 EFI_STATUS
1773 EFIAPI
1774 SecureBootConfigImageRead (
1775 IN VOID *FileHandle,
1776 IN UINTN FileOffset,
1777 IN OUT UINTN *ReadSize,
1778 OUT VOID *Buffer
1779 )
1780 {
1781 UINTN EndPosition;
1782
1783 if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
1784 return EFI_INVALID_PARAMETER;
1785 }
1786
1787 if (MAX_ADDRESS - FileOffset < *ReadSize) {
1788 return EFI_INVALID_PARAMETER;
1789 }
1790
1791 EndPosition = FileOffset + *ReadSize;
1792 if (EndPosition > mImageSize) {
1793 *ReadSize = (UINT32)(mImageSize - FileOffset);
1794 }
1795
1796 if (FileOffset >= mImageSize) {
1797 *ReadSize = 0;
1798 }
1799
1800 CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
1801
1802 return EFI_SUCCESS;
1803 }
1804
1805 /**
1806 Load PE/COFF image information into internal buffer and check its validity.
1807
1808 @retval EFI_SUCCESS Successful
1809 @retval EFI_UNSUPPORTED Invalid PE/COFF file
1810 @retval EFI_ABORTED Serious error occurs, like file I/O error etc.
1811
1812 **/
1813 EFI_STATUS
1814 LoadPeImage (
1815 VOID
1816 )
1817 {
1818 EFI_IMAGE_DOS_HEADER *DosHdr;
1819 EFI_IMAGE_NT_HEADERS32 *NtHeader32;
1820 EFI_IMAGE_NT_HEADERS64 *NtHeader64;
1821 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
1822 EFI_STATUS Status;
1823
1824 NtHeader32 = NULL;
1825 NtHeader64 = NULL;
1826
1827 ZeroMem (&ImageContext, sizeof (ImageContext));
1828 ImageContext.Handle = (VOID *) mImageBase;
1829 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecureBootConfigImageRead;
1830
1831 //
1832 // Get information about the image being loaded
1833 //
1834 Status = PeCoffLoaderGetImageInfo (&ImageContext);
1835 if (EFI_ERROR (Status)) {
1836 //
1837 // The information can't be got from the invalid PeImage
1838 //
1839 DEBUG ((DEBUG_INFO, "SecureBootConfigDxe: PeImage invalid. \n"));
1840 return Status;
1841 }
1842
1843 //
1844 // Read the Dos header
1845 //
1846 DosHdr = (EFI_IMAGE_DOS_HEADER*)(mImageBase);
1847 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
1848 {
1849 //
1850 // DOS image header is present,
1851 // So read the PE header after the DOS image header
1852 //
1853 mPeCoffHeaderOffset = DosHdr->e_lfanew;
1854 }
1855 else
1856 {
1857 mPeCoffHeaderOffset = 0;
1858 }
1859
1860 //
1861 // Read PE header and check the signature validity and machine compatibility
1862 //
1863 NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset);
1864 if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE)
1865 {
1866 return EFI_UNSUPPORTED;
1867 }
1868
1869 mNtHeader.Pe32 = NtHeader32;
1870
1871 //
1872 // Check the architecture field of PE header and get the Certificate Data Directory data
1873 // Note the size of FileHeader field is constant for both IA32 and X64 arch
1874 //
1875 if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32)
1876 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)
1877 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {
1878 //
1879 // 32-bits Architecture
1880 //
1881 mImageType = ImageType_IA32;
1882 mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
1883 }
1884 else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)
1885 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)
1886 || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
1887 //
1888 // 64-bits Architecture
1889 //
1890 mImageType = ImageType_X64;
1891 NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);
1892 mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
1893 } else {
1894 return EFI_UNSUPPORTED;
1895 }
1896
1897 return EFI_SUCCESS;
1898 }
1899
1900 /**
1901 Calculate hash of Pe/Coff image based on the authenticode image hashing in
1902 PE/COFF Specification 8.0 Appendix A
1903
1904 Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
1905 the function LoadPeImage ().
1906
1907 @param[in] HashAlg Hash algorithm type.
1908
1909 @retval TRUE Successfully hash image.
1910 @retval FALSE Fail in hash image.
1911
1912 **/
1913 BOOLEAN
1914 HashPeImage (
1915 IN UINT32 HashAlg
1916 )
1917 {
1918 BOOLEAN Status;
1919 EFI_IMAGE_SECTION_HEADER *Section;
1920 VOID *HashCtx;
1921 UINTN CtxSize;
1922 UINT8 *HashBase;
1923 UINTN HashSize;
1924 UINTN SumOfBytesHashed;
1925 EFI_IMAGE_SECTION_HEADER *SectionHeader;
1926 UINTN Index;
1927 UINTN Pos;
1928
1929 HashCtx = NULL;
1930 SectionHeader = NULL;
1931 Status = FALSE;
1932
1933 if (HashAlg != HASHALG_SHA256) {
1934 return FALSE;
1935 }
1936
1937 //
1938 // Initialize context of hash.
1939 //
1940 ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
1941
1942 mImageDigestSize = SHA256_DIGEST_SIZE;
1943 mCertType = gEfiCertSha256Guid;
1944
1945 CtxSize = mHash[HashAlg].GetContextSize();
1946
1947 HashCtx = AllocatePool (CtxSize);
1948 ASSERT (HashCtx != NULL);
1949
1950 // 1. Load the image header into memory.
1951
1952 // 2. Initialize a SHA hash context.
1953 Status = mHash[HashAlg].HashInit(HashCtx);
1954 if (!Status) {
1955 goto Done;
1956 }
1957 //
1958 // Measuring PE/COFF Image Header;
1959 // But CheckSum field and SECURITY data directory (certificate) are excluded
1960 //
1961
1962 //
1963 // 3. Calculate the distance from the base of the image header to the image checksum address.
1964 // 4. Hash the image header from its base to beginning of the image checksum.
1965 //
1966 HashBase = mImageBase;
1967 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1968 //
1969 // Use PE32 offset.
1970 //
1971 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
1972 } else {
1973 //
1974 // Use PE32+ offset.
1975 //
1976 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
1977 }
1978
1979 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
1980 if (!Status) {
1981 goto Done;
1982 }
1983 //
1984 // 5. Skip over the image checksum (it occupies a single ULONG).
1985 // 6. Get the address of the beginning of the Cert Directory.
1986 // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
1987 //
1988 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
1989 //
1990 // Use PE32 offset.
1991 //
1992 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
1993 HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
1994 } else {
1995 //
1996 // Use PE32+ offset.
1997 //
1998 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
1999 HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
2000 }
2001
2002 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
2003 if (!Status) {
2004 goto Done;
2005 }
2006 //
2007 // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
2008 // 9. Hash everything from the end of the Cert Directory to the end of image header.
2009 //
2010 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2011 //
2012 // Use PE32 offset
2013 //
2014 HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
2015 HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);
2016 } else {
2017 //
2018 // Use PE32+ offset.
2019 //
2020 HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
2021 HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);
2022 }
2023
2024 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
2025 if (!Status) {
2026 goto Done;
2027 }
2028 //
2029 // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
2030 //
2031 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2032 //
2033 // Use PE32 offset.
2034 //
2035 SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
2036 } else {
2037 //
2038 // Use PE32+ offset
2039 //
2040 SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
2041 }
2042
2043 //
2044 // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
2045 // structures in the image. The 'NumberOfSections' field of the image
2046 // header indicates how big the table should be. Do not include any
2047 // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
2048 //
2049 SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
2050 ASSERT (SectionHeader != NULL);
2051 //
2052 // 12. Using the 'PointerToRawData' in the referenced section headers as
2053 // a key, arrange the elements in the table in ascending order. In other
2054 // words, sort the section headers according to the disk-file offset of
2055 // the section.
2056 //
2057 Section = (EFI_IMAGE_SECTION_HEADER *) (
2058 mImageBase +
2059 mPeCoffHeaderOffset +
2060 sizeof (UINT32) +
2061 sizeof (EFI_IMAGE_FILE_HEADER) +
2062 mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
2063 );
2064 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
2065 Pos = Index;
2066 while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
2067 CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
2068 Pos--;
2069 }
2070 CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
2071 Section += 1;
2072 }
2073
2074 //
2075 // 13. Walk through the sorted table, bring the corresponding section
2076 // into memory, and hash the entire section (using the 'SizeOfRawData'
2077 // field in the section header to determine the amount of data to hash).
2078 // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
2079 // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
2080 //
2081 for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
2082 Section = &SectionHeader[Index];
2083 if (Section->SizeOfRawData == 0) {
2084 continue;
2085 }
2086 HashBase = mImageBase + Section->PointerToRawData;
2087 HashSize = (UINTN) Section->SizeOfRawData;
2088
2089 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
2090 if (!Status) {
2091 goto Done;
2092 }
2093
2094 SumOfBytesHashed += HashSize;
2095 }
2096
2097 //
2098 // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
2099 // data in the file that needs to be added to the hash. This data begins
2100 // at file offset SUM_OF_BYTES_HASHED and its length is:
2101 // FileSize - (CertDirectory->Size)
2102 //
2103 if (mImageSize > SumOfBytesHashed) {
2104 HashBase = mImageBase + SumOfBytesHashed;
2105 if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
2106 //
2107 // Use PE32 offset.
2108 //
2109 HashSize = (UINTN)(
2110 mImageSize -
2111 mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
2112 SumOfBytesHashed);
2113 } else {
2114 //
2115 // Use PE32+ offset.
2116 //
2117 HashSize = (UINTN)(
2118 mImageSize -
2119 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
2120 SumOfBytesHashed);
2121 }
2122
2123 Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
2124 if (!Status) {
2125 goto Done;
2126 }
2127 }
2128
2129 Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
2130
2131 Done:
2132 if (HashCtx != NULL) {
2133 FreePool (HashCtx);
2134 }
2135 if (SectionHeader != NULL) {
2136 FreePool (SectionHeader);
2137 }
2138 return Status;
2139 }
2140
2141 /**
2142 Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of
2143 Pe/Coff image based on the authenticated image hashing in PE/COFF Specification
2144 8.0 Appendix A
2145
2146 @retval EFI_UNSUPPORTED Hash algorithm is not supported.
2147 @retval EFI_SUCCESS Hash successfully.
2148
2149 **/
2150 EFI_STATUS
2151 HashPeImageByType (
2152 VOID
2153 )
2154 {
2155 UINT8 Index;
2156 WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
2157
2158 PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->Offset);
2159
2160 for (Index = 0; Index < HASHALG_MAX; Index++) {
2161 //
2162 // Check the Hash algorithm in PE/COFF Authenticode.
2163 // According to PKCS#7 Definition:
2164 // SignedData ::= SEQUENCE {
2165 // version Version,
2166 // digestAlgorithms DigestAlgorithmIdentifiers,
2167 // contentInfo ContentInfo,
2168 // .... }
2169 // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
2170 // This field has the fixed offset (+32) in final Authenticode ASN.1 data.
2171 // Fixed offset (+32) is calculated based on two bytes of length encoding.
2172 //
2173 if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
2174 //
2175 // Only support two bytes of Long Form of Length Encoding.
2176 //
2177 continue;
2178 }
2179
2180 //
2181 if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
2182 break;
2183 }
2184 }
2185
2186 if (Index == HASHALG_MAX) {
2187 return EFI_UNSUPPORTED;
2188 }
2189
2190 //
2191 // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
2192 //
2193 if (!HashPeImage(Index)) {
2194 return EFI_UNSUPPORTED;
2195 }
2196
2197 return EFI_SUCCESS;
2198 }
2199
2200 /**
2201 Enroll a new signature of executable into Signature Database.
2202
2203 @param[in] PrivateData The module's private data.
2204 @param[in] VariableName Variable name of signature database, must be
2205 EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
2206 or EFI_IMAGE_SECURITY_DATABASE2.
2207
2208 @retval EFI_SUCCESS New signature is enrolled successfully.
2209 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2210 @retval EFI_UNSUPPORTED Unsupported command.
2211 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
2212
2213 **/
2214 EFI_STATUS
2215 EnrollAuthentication2Descriptor (
2216 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
2217 IN CHAR16 *VariableName
2218 )
2219 {
2220 EFI_STATUS Status;
2221 VOID *Data;
2222 UINTN DataSize;
2223 UINT32 Attr;
2224
2225 Data = NULL;
2226
2227 //
2228 // DBT only support DER-X509 Cert Enrollment
2229 //
2230 if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
2231 return EFI_UNSUPPORTED;
2232 }
2233
2234 //
2235 // Read the whole file content
2236 //
2237 Status = ReadFileContent(
2238 Private->FileContext->FHandle,
2239 (VOID **) &mImageBase,
2240 &mImageSize,
2241 0
2242 );
2243 if (EFI_ERROR (Status)) {
2244 goto ON_EXIT;
2245 }
2246 ASSERT (mImageBase != NULL);
2247
2248 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
2249 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2250
2251 //
2252 // Check if SigDB variable has been already existed.
2253 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
2254 // new signature data to original variable
2255 //
2256 DataSize = 0;
2257 Status = gRT->GetVariable(
2258 VariableName,
2259 &gEfiImageSecurityDatabaseGuid,
2260 NULL,
2261 &DataSize,
2262 NULL
2263 );
2264 if (Status == EFI_BUFFER_TOO_SMALL) {
2265 Attr |= EFI_VARIABLE_APPEND_WRITE;
2266 } else if (Status != EFI_NOT_FOUND) {
2267 goto ON_EXIT;
2268 }
2269
2270 //
2271 // Directly set AUTHENTICATION_2 data to SetVariable
2272 //
2273 Status = gRT->SetVariable(
2274 VariableName,
2275 &gEfiImageSecurityDatabaseGuid,
2276 Attr,
2277 mImageSize,
2278 mImageBase
2279 );
2280
2281 DEBUG((DEBUG_INFO, "Enroll AUTH_2 data to Var:%s Status: %x\n", VariableName, Status));
2282
2283 ON_EXIT:
2284
2285 CloseEnrolledFile(Private->FileContext);
2286
2287 if (Data != NULL) {
2288 FreePool (Data);
2289 }
2290
2291 if (mImageBase != NULL) {
2292 FreePool (mImageBase);
2293 mImageBase = NULL;
2294 }
2295
2296 return Status;
2297
2298 }
2299
2300
2301 /**
2302 Enroll a new signature of executable into Signature Database.
2303
2304 @param[in] PrivateData The module's private data.
2305 @param[in] VariableName Variable name of signature database, must be
2306 EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
2307 or EFI_IMAGE_SECURITY_DATABASE2.
2308
2309 @retval EFI_SUCCESS New signature is enrolled successfully.
2310 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2311 @retval EFI_UNSUPPORTED Unsupported command.
2312 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
2313
2314 **/
2315 EFI_STATUS
2316 EnrollImageSignatureToSigDB (
2317 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
2318 IN CHAR16 *VariableName
2319 )
2320 {
2321 EFI_STATUS Status;
2322 EFI_SIGNATURE_LIST *SigDBCert;
2323 EFI_SIGNATURE_DATA *SigDBCertData;
2324 VOID *Data;
2325 UINTN DataSize;
2326 UINTN SigDBSize;
2327 UINT32 Attr;
2328 WIN_CERTIFICATE_UEFI_GUID *GuidCertData;
2329
2330 Data = NULL;
2331 GuidCertData = NULL;
2332
2333 if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
2334 return EFI_UNSUPPORTED;
2335 }
2336
2337 //
2338 // Form the SigDB certificate list.
2339 // Format the data item into EFI_SIGNATURE_LIST type.
2340 //
2341 // We need to parse signature data of executable from specified signed executable file.
2342 // In current implementation, we simply trust the pass-in signed executable file.
2343 // In reality, it's OS's responsibility to verify the signed executable file.
2344 //
2345
2346 //
2347 // Read the whole file content
2348 //
2349 Status = ReadFileContent(
2350 Private->FileContext->FHandle,
2351 (VOID **) &mImageBase,
2352 &mImageSize,
2353 0
2354 );
2355 if (EFI_ERROR (Status)) {
2356 goto ON_EXIT;
2357 }
2358 ASSERT (mImageBase != NULL);
2359
2360 Status = LoadPeImage ();
2361 if (EFI_ERROR (Status)) {
2362 goto ON_EXIT;
2363 }
2364
2365 if (mSecDataDir->SizeOfCert == 0) {
2366 if (!HashPeImage (HASHALG_SHA256)) {
2367 Status = EFI_SECURITY_VIOLATION;
2368 goto ON_EXIT;
2369 }
2370 } else {
2371
2372 //
2373 // Read the certificate data
2374 //
2375 mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);
2376
2377 if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
2378 GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;
2379 if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {
2380 Status = EFI_ABORTED;
2381 goto ON_EXIT;
2382 }
2383
2384 if (!HashPeImage (HASHALG_SHA256)) {
2385 Status = EFI_ABORTED;
2386 goto ON_EXIT;;
2387 }
2388
2389 } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
2390
2391 Status = HashPeImageByType ();
2392 if (EFI_ERROR (Status)) {
2393 goto ON_EXIT;;
2394 }
2395 } else {
2396 Status = EFI_ABORTED;
2397 goto ON_EXIT;
2398 }
2399 }
2400
2401 //
2402 // Create a new SigDB entry.
2403 //
2404 SigDBSize = sizeof(EFI_SIGNATURE_LIST)
2405 + sizeof(EFI_SIGNATURE_DATA) - 1
2406 + (UINT32) mImageDigestSize;
2407
2408 Data = (UINT8*) AllocateZeroPool (SigDBSize);
2409 if (Data == NULL) {
2410 Status = EFI_OUT_OF_RESOURCES;
2411 goto ON_EXIT;
2412 }
2413
2414 //
2415 // Adjust the Certificate Database parameters.
2416 //
2417 SigDBCert = (EFI_SIGNATURE_LIST*) Data;
2418 SigDBCert->SignatureListSize = (UINT32) SigDBSize;
2419 SigDBCert->SignatureHeaderSize = 0;
2420 SigDBCert->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;
2421 CopyGuid (&SigDBCert->SignatureType, &mCertType);
2422
2423 SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));
2424 CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
2425 CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);
2426
2427 Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
2428 | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
2429 Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
2430 if (EFI_ERROR (Status)) {
2431 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2432 goto ON_EXIT;
2433 }
2434
2435 //
2436 // Check if SigDB variable has been already existed.
2437 // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
2438 // new signature data to original variable
2439 //
2440 DataSize = 0;
2441 Status = gRT->GetVariable(
2442 VariableName,
2443 &gEfiImageSecurityDatabaseGuid,
2444 NULL,
2445 &DataSize,
2446 NULL
2447 );
2448 if (Status == EFI_BUFFER_TOO_SMALL) {
2449 Attr |= EFI_VARIABLE_APPEND_WRITE;
2450 } else if (Status != EFI_NOT_FOUND) {
2451 goto ON_EXIT;
2452 }
2453
2454 //
2455 // Enroll the variable.
2456 //
2457 Status = gRT->SetVariable(
2458 VariableName,
2459 &gEfiImageSecurityDatabaseGuid,
2460 Attr,
2461 SigDBSize,
2462 Data
2463 );
2464 if (EFI_ERROR (Status)) {
2465 goto ON_EXIT;
2466 }
2467
2468 ON_EXIT:
2469
2470 CloseEnrolledFile(Private->FileContext);
2471
2472 if (Private->SignatureGUID != NULL) {
2473 FreePool (Private->SignatureGUID);
2474 Private->SignatureGUID = NULL;
2475 }
2476
2477 if (Data != NULL) {
2478 FreePool (Data);
2479 }
2480
2481 if (mImageBase != NULL) {
2482 FreePool (mImageBase);
2483 mImageBase = NULL;
2484 }
2485
2486 return Status;
2487 }
2488
2489 /**
2490 Enroll signature into DB/DBX/DBT without KEK's authentication.
2491 The SignatureOwner GUID will be Private->SignatureGUID.
2492
2493 @param[in] PrivateData The module's private data.
2494 @param[in] VariableName Variable name of signature database, must be
2495 EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
2496
2497 @retval EFI_SUCCESS New signature enrolled successfully.
2498 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2499 @retval others Fail to enroll signature data.
2500
2501 **/
2502 EFI_STATUS
2503 EnrollSignatureDatabase (
2504 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
2505 IN CHAR16 *VariableName
2506 )
2507 {
2508 UINT16* FilePostFix;
2509 EFI_STATUS Status;
2510 UINTN NameLength;
2511
2512 if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
2513 return EFI_INVALID_PARAMETER;
2514 }
2515
2516 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
2517 if (EFI_ERROR (Status)) {
2518 return Status;
2519 }
2520
2521 //
2522 // Parse the file's postfix.
2523 //
2524 NameLength = StrLen (Private->FileContext->FileName);
2525 if (NameLength <= 4) {
2526 return EFI_INVALID_PARAMETER;
2527 }
2528 FilePostFix = Private->FileContext->FileName + NameLength - 4;
2529 if (IsDerEncodeCertificate (FilePostFix)) {
2530 //
2531 // Supports DER-encoded X509 certificate.
2532 //
2533 return EnrollX509toSigDB (Private, VariableName);
2534 } else if (IsAuthentication2Format(Private->FileContext->FHandle)){
2535 return EnrollAuthentication2Descriptor(Private, VariableName);
2536 } else {
2537 return EnrollImageSignatureToSigDB (Private, VariableName);
2538 }
2539 }
2540
2541 /**
2542 List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)
2543 by GUID in the page for user to select and delete as needed.
2544
2545 @param[in] PrivateData Module's private data.
2546 @param[in] VariableName The variable name of the vendor's signature database.
2547 @param[in] VendorGuid A unique identifier for the vendor.
2548 @param[in] LabelNumber Label number to insert opcodes.
2549 @param[in] FormId Form ID of current page.
2550 @param[in] QuestionIdBase Base question id of the signature list.
2551
2552 @retval EFI_SUCCESS Success to update the signature list page
2553 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
2554
2555 **/
2556 EFI_STATUS
2557 UpdateDeletePage (
2558 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
2559 IN CHAR16 *VariableName,
2560 IN EFI_GUID *VendorGuid,
2561 IN UINT16 LabelNumber,
2562 IN EFI_FORM_ID FormId,
2563 IN EFI_QUESTION_ID QuestionIdBase
2564 )
2565 {
2566 EFI_STATUS Status;
2567 UINT32 Index;
2568 UINTN CertCount;
2569 UINTN GuidIndex;
2570 VOID *StartOpCodeHandle;
2571 VOID *EndOpCodeHandle;
2572 EFI_IFR_GUID_LABEL *StartLabel;
2573 EFI_IFR_GUID_LABEL *EndLabel;
2574 UINTN DataSize;
2575 UINT8 *Data;
2576 EFI_SIGNATURE_LIST *CertList;
2577 EFI_SIGNATURE_DATA *Cert;
2578 UINT32 ItemDataSize;
2579 CHAR16 *GuidStr;
2580 EFI_STRING_ID GuidID;
2581 EFI_STRING_ID Help;
2582
2583 Data = NULL;
2584 CertList = NULL;
2585 Cert = NULL;
2586 GuidStr = NULL;
2587 StartOpCodeHandle = NULL;
2588 EndOpCodeHandle = NULL;
2589
2590 //
2591 // Initialize the container for dynamic opcodes.
2592 //
2593 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
2594 if (StartOpCodeHandle == NULL) {
2595 Status = EFI_OUT_OF_RESOURCES;
2596 goto ON_EXIT;
2597 }
2598
2599 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
2600 if (EndOpCodeHandle == NULL) {
2601 Status = EFI_OUT_OF_RESOURCES;
2602 goto ON_EXIT;
2603 }
2604
2605 //
2606 // Create Hii Extend Label OpCode.
2607 //
2608 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
2609 StartOpCodeHandle,
2610 &gEfiIfrTianoGuid,
2611 NULL,
2612 sizeof (EFI_IFR_GUID_LABEL)
2613 );
2614 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
2615 StartLabel->Number = LabelNumber;
2616
2617 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
2618 EndOpCodeHandle,
2619 &gEfiIfrTianoGuid,
2620 NULL,
2621 sizeof (EFI_IFR_GUID_LABEL)
2622 );
2623 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
2624 EndLabel->Number = LABEL_END;
2625
2626 //
2627 // Read Variable.
2628 //
2629 DataSize = 0;
2630 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
2631 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
2632 goto ON_EXIT;
2633 }
2634
2635 Data = (UINT8 *) AllocateZeroPool (DataSize);
2636 if (Data == NULL) {
2637 Status = EFI_OUT_OF_RESOURCES;
2638 goto ON_EXIT;
2639 }
2640
2641 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
2642 if (EFI_ERROR (Status)) {
2643 goto ON_EXIT;
2644 }
2645
2646 GuidStr = AllocateZeroPool (100);
2647 if (GuidStr == NULL) {
2648 Status = EFI_OUT_OF_RESOURCES;
2649 goto ON_EXIT;
2650 }
2651
2652 //
2653 // Enumerate all KEK pub data.
2654 //
2655 ItemDataSize = (UINT32) DataSize;
2656 CertList = (EFI_SIGNATURE_LIST *) Data;
2657 GuidIndex = 0;
2658
2659 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
2660
2661 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {
2662 Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);
2663 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2664 Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);
2665 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {
2666 Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);
2667 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {
2668 Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);
2669 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {
2670 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);
2671 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {
2672 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);
2673 } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {
2674 Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);
2675 } else {
2676 //
2677 // The signature type is not supported in current implementation.
2678 //
2679 ItemDataSize -= CertList->SignatureListSize;
2680 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2681 continue;
2682 }
2683
2684 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2685 for (Index = 0; Index < CertCount; Index++) {
2686 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList
2687 + sizeof (EFI_SIGNATURE_LIST)
2688 + CertList->SignatureHeaderSize
2689 + Index * CertList->SignatureSize);
2690 //
2691 // Display GUID and help
2692 //
2693 GuidToString (&Cert->SignatureOwner, GuidStr, 100);
2694 GuidID = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);
2695 HiiCreateCheckBoxOpCode (
2696 StartOpCodeHandle,
2697 (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),
2698 0,
2699 0,
2700 GuidID,
2701 Help,
2702 EFI_IFR_FLAG_CALLBACK,
2703 0,
2704 NULL
2705 );
2706 }
2707
2708 ItemDataSize -= CertList->SignatureListSize;
2709 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2710 }
2711
2712 ON_EXIT:
2713 HiiUpdateForm (
2714 PrivateData->HiiHandle,
2715 &gSecureBootConfigFormSetGuid,
2716 FormId,
2717 StartOpCodeHandle,
2718 EndOpCodeHandle
2719 );
2720
2721 if (StartOpCodeHandle != NULL) {
2722 HiiFreeOpCodeHandle (StartOpCodeHandle);
2723 }
2724
2725 if (EndOpCodeHandle != NULL) {
2726 HiiFreeOpCodeHandle (EndOpCodeHandle);
2727 }
2728
2729 if (Data != NULL) {
2730 FreePool (Data);
2731 }
2732
2733 if (GuidStr != NULL) {
2734 FreePool (GuidStr);
2735 }
2736
2737 return EFI_SUCCESS;
2738 }
2739
2740 /**
2741 Delete a KEK entry from KEK database.
2742
2743 @param[in] PrivateData Module's private data.
2744 @param[in] QuestionId Question id of the KEK item to delete.
2745
2746 @retval EFI_SUCCESS Delete kek item successfully.
2747 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
2748
2749 **/
2750 EFI_STATUS
2751 DeleteKeyExchangeKey (
2752 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
2753 IN EFI_QUESTION_ID QuestionId
2754 )
2755 {
2756 EFI_STATUS Status;
2757 UINTN DataSize;
2758 UINT8 *Data;
2759 UINT8 *OldData;
2760 UINT32 Attr;
2761 UINT32 Index;
2762 EFI_SIGNATURE_LIST *CertList;
2763 EFI_SIGNATURE_LIST *NewCertList;
2764 EFI_SIGNATURE_DATA *Cert;
2765 UINTN CertCount;
2766 UINT32 Offset;
2767 BOOLEAN IsKEKItemFound;
2768 UINT32 KekDataSize;
2769 UINTN DeleteKekIndex;
2770 UINTN GuidIndex;
2771
2772 Data = NULL;
2773 OldData = NULL;
2774 CertList = NULL;
2775 Cert = NULL;
2776 Attr = 0;
2777 DeleteKekIndex = QuestionId - OPTION_DEL_KEK_QUESTION_ID;
2778
2779 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2780 if (EFI_ERROR (Status)) {
2781 return Status;
2782 }
2783
2784 //
2785 // Get original KEK variable.
2786 //
2787 DataSize = 0;
2788 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);
2789 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
2790 goto ON_EXIT;
2791 }
2792
2793 OldData = (UINT8*)AllocateZeroPool(DataSize);
2794 if (OldData == NULL) {
2795 Status = EFI_OUT_OF_RESOURCES;
2796 goto ON_EXIT;
2797 }
2798
2799 Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);
2800 if (EFI_ERROR(Status)) {
2801 goto ON_EXIT;
2802 }
2803
2804 //
2805 // Allocate space for new variable.
2806 //
2807 Data = (UINT8*) AllocateZeroPool (DataSize);
2808 if (Data == NULL) {
2809 Status = EFI_OUT_OF_RESOURCES;
2810 goto ON_EXIT;
2811 }
2812
2813 //
2814 // Enumerate all KEK pub data and erasing the target item.
2815 //
2816 IsKEKItemFound = FALSE;
2817 KekDataSize = (UINT32) DataSize;
2818 CertList = (EFI_SIGNATURE_LIST *) OldData;
2819 Offset = 0;
2820 GuidIndex = 0;
2821 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2822 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
2823 CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
2824 CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
2825 NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);
2826 Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2827 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
2828 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2829 for (Index = 0; Index < CertCount; Index++) {
2830 if (GuidIndex == DeleteKekIndex ) {
2831 //
2832 // Find it! Skip it!
2833 //
2834 NewCertList->SignatureListSize -= CertList->SignatureSize;
2835 IsKEKItemFound = TRUE;
2836 } else {
2837 //
2838 // This item doesn't match. Copy it to the Data buffer.
2839 //
2840 CopyMem (Data + Offset, Cert, CertList->SignatureSize);
2841 Offset += CertList->SignatureSize;
2842 }
2843 GuidIndex++;
2844 Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);
2845 }
2846 } else {
2847 //
2848 // This List doesn't match. Copy it to the Data buffer.
2849 //
2850 CopyMem (Data + Offset, CertList, CertList->SignatureListSize);
2851 Offset += CertList->SignatureListSize;
2852 }
2853
2854 KekDataSize -= CertList->SignatureListSize;
2855 CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);
2856 }
2857
2858 if (!IsKEKItemFound) {
2859 //
2860 // Doesn't find the Kek Item!
2861 //
2862 Status = EFI_NOT_FOUND;
2863 goto ON_EXIT;
2864 }
2865
2866 //
2867 // Delete the Signature header if there is no signature in the list.
2868 //
2869 KekDataSize = Offset;
2870 CertList = (EFI_SIGNATURE_LIST*) Data;
2871 Offset = 0;
2872 ZeroMem (OldData, KekDataSize);
2873 while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
2874 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
2875 DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));
2876 if (CertCount != 0) {
2877 CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);
2878 Offset += CertList->SignatureListSize;
2879 }
2880 KekDataSize -= CertList->SignatureListSize;
2881 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
2882 }
2883
2884 DataSize = Offset;
2885 if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
2886 Status = CreateTimeBasedPayload (&DataSize, &OldData);
2887 if (EFI_ERROR (Status)) {
2888 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
2889 goto ON_EXIT;
2890 }
2891 }
2892
2893 Status = gRT->SetVariable(
2894 EFI_KEY_EXCHANGE_KEY_NAME,
2895 &gEfiGlobalVariableGuid,
2896 Attr,
2897 DataSize,
2898 OldData
2899 );
2900 if (EFI_ERROR (Status)) {
2901 DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
2902 goto ON_EXIT;
2903 }
2904
2905 ON_EXIT:
2906 if (Data != NULL) {
2907 FreePool(Data);
2908 }
2909
2910 if (OldData != NULL) {
2911 FreePool(OldData);
2912 }
2913
2914 return UpdateDeletePage (
2915 PrivateData,
2916 EFI_KEY_EXCHANGE_KEY_NAME,
2917 &gEfiGlobalVariableGuid,
2918 LABEL_KEK_DELETE,
2919 FORMID_DELETE_KEK_FORM,
2920 OPTION_DEL_KEK_QUESTION_ID
2921 );
2922 }
2923
2924 /**
2925 Delete a signature entry from signature database.
2926
2927 @param[in] PrivateData Module's private data.
2928 @param[in] VariableName The variable name of the vendor's signature database.
2929 @param[in] VendorGuid A unique identifier for the vendor.
2930 @param[in] LabelNumber Label number to insert opcodes.
2931 @param[in] FormId Form ID of current page.
2932 @param[in] QuestionIdBase Base question id of the signature list.
2933 @param[in] DeleteIndex Signature index to delete.
2934
2935 @retval EFI_SUCCESS Delete signature successfully.
2936 @retval EFI_NOT_FOUND Can't find the signature item,
2937 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
2938 **/
2939 EFI_STATUS
2940 DeleteSignature (
2941 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
2942 IN CHAR16 *VariableName,
2943 IN EFI_GUID *VendorGuid,
2944 IN UINT16 LabelNumber,
2945 IN EFI_FORM_ID FormId,
2946 IN EFI_QUESTION_ID QuestionIdBase,
2947 IN UINTN DeleteIndex
2948 )
2949 {
2950 EFI_STATUS Status;
2951 UINTN DataSize;
2952 UINT8 *Data;
2953 UINT8 *OldData;
2954 UINT32 Attr;
2955 UINT32 Index;
2956 EFI_SIGNATURE_LIST *CertList;
2957 EFI_SIGNATURE_LIST *NewCertList;
2958 EFI_SIGNATURE_DATA *Cert;
2959 UINTN CertCount;
2960 UINT32 Offset;
2961 BOOLEAN IsItemFound;
2962 UINT32 ItemDataSize;
2963 UINTN GuidIndex;
2964
2965 Data = NULL;
2966 OldData = NULL;
2967 CertList = NULL;
2968 Cert = NULL;
2969 Attr = 0;
2970
2971 Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
2972 if (EFI_ERROR (Status)) {
2973 return Status;
2974 }
2975
2976 //
2977 // Get original signature list data.
2978 //
2979 DataSize = 0;
2980 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);
2981 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
2982 goto ON_EXIT;
2983 }
2984
2985 OldData = (UINT8 *) AllocateZeroPool (DataSize);
2986 if (OldData == NULL) {
2987 Status = EFI_OUT_OF_RESOURCES;
2988 goto ON_EXIT;
2989 }
2990
2991 Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData);
2992 if (EFI_ERROR(Status)) {
2993 goto ON_EXIT;
2994 }
2995
2996 //
2997 // Allocate space for new variable.
2998 //
2999 Data = (UINT8*) AllocateZeroPool (DataSize);
3000 if (Data == NULL) {
3001 Status = EFI_OUT_OF_RESOURCES;
3002 goto ON_EXIT;
3003 }
3004
3005 //
3006 // Enumerate all signature data and erasing the target item.
3007 //
3008 IsItemFound = FALSE;
3009 ItemDataSize = (UINT32) DataSize;
3010 CertList = (EFI_SIGNATURE_LIST *) OldData;
3011 Offset = 0;
3012 GuidIndex = 0;
3013 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
3014 if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
3015 CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid) ||
3016 CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid) ||
3017 CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid) ||
3018 CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid) ||
3019 CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid) ||
3020 CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)
3021 ) {
3022 //
3023 // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list.
3024 //
3025 CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
3026 NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset);
3027 Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
3028 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
3029 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
3030 for (Index = 0; Index < CertCount; Index++) {
3031 if (GuidIndex == DeleteIndex) {
3032 //
3033 // Find it! Skip it!
3034 //
3035 NewCertList->SignatureListSize -= CertList->SignatureSize;
3036 IsItemFound = TRUE;
3037 } else {
3038 //
3039 // This item doesn't match. Copy it to the Data buffer.
3040 //
3041 CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize);
3042 Offset += CertList->SignatureSize;
3043 }
3044 GuidIndex++;
3045 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
3046 }
3047 } else {
3048 //
3049 // This List doesn't match. Just copy it to the Data buffer.
3050 //
3051 CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
3052 Offset += CertList->SignatureListSize;
3053 }
3054
3055 ItemDataSize -= CertList->SignatureListSize;
3056 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
3057 }
3058
3059 if (!IsItemFound) {
3060 //
3061 // Doesn't find the signature Item!
3062 //
3063 Status = EFI_NOT_FOUND;
3064 goto ON_EXIT;
3065 }
3066
3067 //
3068 // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list.
3069 //
3070 ItemDataSize = Offset;
3071 CertList = (EFI_SIGNATURE_LIST *) Data;
3072 Offset = 0;
3073 ZeroMem (OldData, ItemDataSize);
3074 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
3075 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
3076 DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));
3077 if (CertCount != 0) {
3078 CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
3079 Offset += CertList->SignatureListSize;
3080 }
3081 ItemDataSize -= CertList->SignatureListSize;
3082 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
3083 }
3084
3085 DataSize = Offset;
3086 if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
3087 Status = CreateTimeBasedPayload (&DataSize, &OldData);
3088 if (EFI_ERROR (Status)) {
3089 DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
3090 goto ON_EXIT;
3091 }
3092 }
3093
3094 Status = gRT->SetVariable(
3095 VariableName,
3096 VendorGuid,
3097 Attr,
3098 DataSize,
3099 OldData
3100 );
3101 if (EFI_ERROR (Status)) {
3102 DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
3103 goto ON_EXIT;
3104 }
3105
3106 ON_EXIT:
3107 if (Data != NULL) {
3108 FreePool(Data);
3109 }
3110
3111 if (OldData != NULL) {
3112 FreePool(OldData);
3113 }
3114
3115 return UpdateDeletePage (
3116 PrivateData,
3117 VariableName,
3118 VendorGuid,
3119 LabelNumber,
3120 FormId,
3121 QuestionIdBase
3122 );
3123 }
3124
3125 /**
3126 This function to delete signature list or data, according by DelType.
3127
3128 @param[in] PrivateData Module's private data.
3129 @param[in] DelType Indicate delete signature list or data.
3130 @param[in] CheckedCount Indicate how many signature data have
3131 been checked in current signature list.
3132
3133 @retval EFI_SUCCESS Success to update the signature list page
3134 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
3135 **/
3136 EFI_STATUS
3137 DeleteSignatureEx (
3138 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
3139 IN SIGNATURE_DELETE_TYPE DelType,
3140 IN UINT32 CheckedCount
3141 )
3142 {
3143 EFI_STATUS Status;
3144 EFI_SIGNATURE_LIST *ListWalker;
3145 EFI_SIGNATURE_LIST *NewCertList;
3146 EFI_SIGNATURE_DATA *DataWalker;
3147 CHAR16 VariableName[BUFFER_MAX_SIZE];
3148 UINT32 VariableAttr;
3149 UINTN VariableDataSize;
3150 UINTN RemainingSize;
3151 UINTN ListIndex;
3152 UINTN Index;
3153 UINTN Offset;
3154 UINT8 *VariableData;
3155 UINT8 *NewVariableData;
3156
3157 Status = EFI_SUCCESS;
3158 VariableAttr = 0;
3159 VariableDataSize = 0;
3160 ListIndex = 0;
3161 Offset = 0;
3162 VariableData = NULL;
3163 NewVariableData = NULL;
3164
3165 if (PrivateData->VariableName == Variable_DB) {
3166 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE);
3167 } else if (PrivateData->VariableName == Variable_DBX) {
3168 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE1);
3169 } else if (PrivateData->VariableName == Variable_DBT) {
3170 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE2);
3171 } else {
3172 goto ON_EXIT;
3173 }
3174
3175 Status = gRT->GetVariable (
3176 VariableName,
3177 &gEfiImageSecurityDatabaseGuid,
3178 &VariableAttr,
3179 &VariableDataSize,
3180 VariableData
3181 );
3182 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
3183 goto ON_EXIT;
3184 }
3185
3186 VariableData = AllocateZeroPool (VariableDataSize);
3187 if (VariableData == NULL) {
3188 Status = EFI_OUT_OF_RESOURCES;
3189 goto ON_EXIT;
3190 }
3191
3192 Status = gRT->GetVariable (
3193 VariableName,
3194 &gEfiImageSecurityDatabaseGuid,
3195 &VariableAttr,
3196 &VariableDataSize,
3197 VariableData
3198 );
3199 if (EFI_ERROR (Status)) {
3200 goto ON_EXIT;
3201 }
3202
3203 Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
3204 if (EFI_ERROR (Status)) {
3205 goto ON_EXIT;
3206 }
3207
3208 NewVariableData = AllocateZeroPool (VariableDataSize);
3209 if (NewVariableData == NULL) {
3210 Status = EFI_OUT_OF_RESOURCES;
3211 goto ON_EXIT;
3212 }
3213
3214 RemainingSize = VariableDataSize;
3215 ListWalker = (EFI_SIGNATURE_LIST *)(VariableData);
3216 if (DelType == Delete_Signature_List_All) {
3217 VariableDataSize = 0;
3218 } else {
3219 //
3220 // Traverse to target EFI_SIGNATURE_LIST but others will be skipped.
3221 //
3222 while ((RemainingSize > 0) && (RemainingSize >= ListWalker->SignatureListSize) && ListIndex < PrivateData->ListIndex) {
3223 CopyMem ((UINT8 *)NewVariableData + Offset, ListWalker, ListWalker->SignatureListSize);
3224 Offset += ListWalker->SignatureListSize;
3225
3226 RemainingSize -= ListWalker->SignatureListSize;
3227 ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
3228 ListIndex++;
3229 }
3230
3231 //
3232 // Handle the target EFI_SIGNATURE_LIST.
3233 // If CheckedCount == SIGNATURE_DATA_COUNTS (ListWalker) or DelType == Delete_Signature_List_One
3234 // it means delete the whole EFI_SIGNATURE_LIST, So we just skip this EFI_SIGNATURE_LIST.
3235 //
3236 if (CheckedCount < SIGNATURE_DATA_COUNTS (ListWalker) && DelType == Delete_Signature_Data) {
3237 NewCertList = (EFI_SIGNATURE_LIST *)(NewVariableData + Offset);
3238 //
3239 // Copy header.
3240 //
3241 CopyMem ((UINT8 *)NewVariableData + Offset, ListWalker, sizeof (EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize);
3242 Offset += sizeof (EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize;
3243
3244 DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)ListWalker + sizeof(EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize);
3245 for (Index = 0; Index < SIGNATURE_DATA_COUNTS(ListWalker); Index = Index + 1) {
3246 if (PrivateData->CheckArray[Index]) {
3247 //
3248 // Delete checked signature data, and update the size of whole signature list.
3249 //
3250 NewCertList->SignatureListSize -= NewCertList->SignatureSize;
3251 } else {
3252 //
3253 // Remain the unchecked signature data.
3254 //
3255 CopyMem ((UINT8 *)NewVariableData + Offset, DataWalker, ListWalker->SignatureSize);
3256 Offset += ListWalker->SignatureSize;
3257 }
3258 DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)DataWalker + ListWalker->SignatureSize);
3259 }
3260 }
3261
3262 RemainingSize -= ListWalker->SignatureListSize;
3263 ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
3264
3265 //
3266 // Copy remaining data, maybe 0.
3267 //
3268 CopyMem((UINT8 *)NewVariableData + Offset, ListWalker, RemainingSize);
3269 Offset += RemainingSize;
3270
3271 VariableDataSize = Offset;
3272 }
3273
3274 if ((VariableAttr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
3275 Status = CreateTimeBasedPayload (&VariableDataSize, &NewVariableData);
3276 if (EFI_ERROR (Status)) {
3277 DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status));
3278 goto ON_EXIT;
3279 }
3280 }
3281
3282 Status = gRT->SetVariable (
3283 VariableName,
3284 &gEfiImageSecurityDatabaseGuid,
3285 VariableAttr,
3286 VariableDataSize,
3287 NewVariableData
3288 );
3289 if (EFI_ERROR (Status)) {
3290 DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r", Status));
3291 goto ON_EXIT;
3292 }
3293
3294 ON_EXIT:
3295 SECUREBOOT_FREE_NON_NULL (VariableData);
3296 SECUREBOOT_FREE_NON_NULL (NewVariableData);
3297
3298 return Status;
3299 }
3300
3301 /**
3302
3303 Update SecureBoot strings based on new Secure Boot Mode State. String includes STR_SECURE_BOOT_STATE_CONTENT
3304 and STR_CUR_SECURE_BOOT_MODE_CONTENT.
3305
3306 @param[in] PrivateData Module's private data.
3307
3308 @return EFI_SUCCESS Update secure boot strings successfully.
3309 @return other Fail to update secure boot strings.
3310
3311 **/
3312 EFI_STATUS
3313 UpdateSecureBootString(
3314 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
3315 )
3316 {
3317 UINT8 *SecureBoot;
3318
3319 SecureBoot = NULL;
3320
3321 //
3322 // Get current secure boot state.
3323 //
3324 GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);
3325 if (SecureBoot == NULL) {
3326 return EFI_NOT_FOUND;
3327 }
3328
3329 if (*SecureBoot == SECURE_BOOT_MODE_ENABLE) {
3330 HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);
3331 } else {
3332 HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);
3333 }
3334
3335 FreePool(SecureBoot);
3336
3337 return EFI_SUCCESS;
3338 }
3339
3340 /**
3341 This function extracts configuration from variable.
3342
3343 @param[in] Private Point to SecureBoot configuration driver private data.
3344 @param[in, out] ConfigData Point to SecureBoot configuration private data.
3345
3346 **/
3347 VOID
3348 SecureBootExtractConfigFromVariable (
3349 IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
3350 IN OUT SECUREBOOT_CONFIGURATION *ConfigData
3351 )
3352 {
3353 UINT8 *SecureBootEnable;
3354 UINT8 *SetupMode;
3355 UINT8 *SecureBootMode;
3356 EFI_TIME CurrTime;
3357
3358 SecureBootEnable = NULL;
3359 SetupMode = NULL;
3360 SecureBootMode = NULL;
3361
3362 //
3363 // Initialize the Date and Time using system time.
3364 //
3365 ConfigData->CertificateFormat = HASHALG_RAW;
3366 ConfigData->AlwaysRevocation = TRUE;
3367 gRT->GetTime (&CurrTime, NULL);
3368 ConfigData->RevocationDate.Year = CurrTime.Year;
3369 ConfigData->RevocationDate.Month = CurrTime.Month;
3370 ConfigData->RevocationDate.Day = CurrTime.Day;
3371 ConfigData->RevocationTime.Hour = CurrTime.Hour;
3372 ConfigData->RevocationTime.Minute = CurrTime.Minute;
3373 ConfigData->RevocationTime.Second = 0;
3374 if (Private->FileContext->FHandle != NULL) {
3375 ConfigData->FileEnrollType = Private->FileContext->FileType;
3376 } else {
3377 ConfigData->FileEnrollType = UNKNOWN_FILE_TYPE;
3378 }
3379
3380 //
3381 // If it is Physical Presence User, set the PhysicalPresent to true.
3382 //
3383 if (UserPhysicalPresent()) {
3384 ConfigData->PhysicalPresent = TRUE;
3385 } else {
3386 ConfigData->PhysicalPresent = FALSE;
3387 }
3388
3389 //
3390 // If there is no PK then the Delete Pk button will be gray.
3391 //
3392 GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
3393 if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {
3394 ConfigData->HasPk = FALSE;
3395 } else {
3396 ConfigData->HasPk = TRUE;
3397 }
3398
3399 //
3400 // Check SecureBootEnable & Pk status, fix the inconsistency.
3401 // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable
3402 // Checkbox.
3403 //
3404 ConfigData->AttemptSecureBoot = FALSE;
3405 GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
3406
3407 //
3408 // Fix Pk and SecureBootEnable inconsistency
3409 //
3410 if ((SetupMode != NULL) && (*SetupMode) == USER_MODE) {
3411 ConfigData->HideSecureBoot = FALSE;
3412 if ((SecureBootEnable != NULL) && (*SecureBootEnable == SECURE_BOOT_ENABLE)) {
3413 ConfigData->AttemptSecureBoot = TRUE;
3414 }
3415 } else {
3416 ConfigData->HideSecureBoot = TRUE;
3417 }
3418
3419 //
3420 // Get the SecureBootMode from CustomMode variable.
3421 //
3422 GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
3423 if (SecureBootMode == NULL) {
3424 ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
3425 } else {
3426 ConfigData->SecureBootMode = *(SecureBootMode);
3427 }
3428
3429 if (SecureBootEnable != NULL) {
3430 FreePool (SecureBootEnable);
3431 }
3432 if (SetupMode != NULL) {
3433 FreePool (SetupMode);
3434 }
3435 if (SecureBootMode != NULL) {
3436 FreePool (SecureBootMode);
3437 }
3438 }
3439
3440 /**
3441 This function allows a caller to extract the current configuration for one
3442 or more named elements from the target driver.
3443
3444 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3445 @param[in] Request A null-terminated Unicode string in
3446 <ConfigRequest> format.
3447 @param[out] Progress On return, points to a character in the Request
3448 string. Points to the string's null terminator if
3449 request was successful. Points to the most recent
3450 '&' before the first failing name/value pair (or
3451 the beginning of the string if the failure is in
3452 the first name/value pair) if the request was not
3453 successful.
3454 @param[out] Results A null-terminated Unicode string in
3455 <ConfigAltResp> format which has all values filled
3456 in for the names in the Request string. String to
3457 be allocated by the called function.
3458
3459 @retval EFI_SUCCESS The Results is filled with the requested values.
3460 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
3461 @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
3462 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
3463 driver.
3464
3465 **/
3466 EFI_STATUS
3467 EFIAPI
3468 SecureBootExtractConfig (
3469 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
3470 IN CONST EFI_STRING Request,
3471 OUT EFI_STRING *Progress,
3472 OUT EFI_STRING *Results
3473 )
3474 {
3475 EFI_STATUS Status;
3476 UINTN BufferSize;
3477 UINTN Size;
3478 SECUREBOOT_CONFIGURATION Configuration;
3479 EFI_STRING ConfigRequest;
3480 EFI_STRING ConfigRequestHdr;
3481 SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
3482 BOOLEAN AllocatedRequest;
3483
3484 if (Progress == NULL || Results == NULL) {
3485 return EFI_INVALID_PARAMETER;
3486 }
3487
3488 AllocatedRequest = FALSE;
3489 ConfigRequestHdr = NULL;
3490 ConfigRequest = NULL;
3491 Size = 0;
3492
3493 ZeroMem (&Configuration, sizeof (Configuration));
3494 PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
3495 *Progress = Request;
3496
3497 if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
3498 return EFI_NOT_FOUND;
3499 }
3500
3501 ZeroMem(&Configuration, sizeof(SECUREBOOT_CONFIGURATION));
3502
3503 //
3504 // Get Configuration from Variable.
3505 //
3506 SecureBootExtractConfigFromVariable (PrivateData, &Configuration);
3507
3508 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3509 ConfigRequest = Request;
3510 if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
3511 //
3512 // Request is set to NULL or OFFSET is NULL, construct full request string.
3513 //
3514 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
3515 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
3516 //
3517 ConfigRequestHdr = HiiConstructConfigHdr (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, PrivateData->DriverHandle);
3518 Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
3519 ConfigRequest = AllocateZeroPool (Size);
3520 ASSERT (ConfigRequest != NULL);
3521 AllocatedRequest = TRUE;
3522 UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
3523 FreePool (ConfigRequestHdr);
3524 ConfigRequestHdr = NULL;
3525 }
3526
3527 Status = gHiiConfigRouting->BlockToConfig (
3528 gHiiConfigRouting,
3529 ConfigRequest,
3530 (UINT8 *) &Configuration,
3531 BufferSize,
3532 Results,
3533 Progress
3534 );
3535
3536 //
3537 // Free the allocated config request string.
3538 //
3539 if (AllocatedRequest) {
3540 FreePool (ConfigRequest);
3541 }
3542
3543 //
3544 // Set Progress string to the original request string.
3545 //
3546 if (Request == NULL) {
3547 *Progress = NULL;
3548 } else if (StrStr (Request, L"OFFSET") == NULL) {
3549 *Progress = Request + StrLen (Request);
3550 }
3551
3552 return Status;
3553 }
3554
3555 /**
3556 This function processes the results of changes in configuration.
3557
3558 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
3559 @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
3560 format.
3561 @param[out] Progress A pointer to a string filled in with the offset of
3562 the most recent '&' before the first failing
3563 name/value pair (or the beginning of the string if
3564 the failure is in the first name/value pair) or
3565 the terminating NULL if all was successful.
3566
3567 @retval EFI_SUCCESS The Results is processed successfully.
3568 @retval EFI_INVALID_PARAMETER Configuration is NULL.
3569 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
3570 driver.
3571
3572 **/
3573 EFI_STATUS
3574 EFIAPI
3575 SecureBootRouteConfig (
3576 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
3577 IN CONST EFI_STRING Configuration,
3578 OUT EFI_STRING *Progress
3579 )
3580 {
3581 SECUREBOOT_CONFIGURATION IfrNvData;
3582 UINTN BufferSize;
3583 SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
3584 EFI_STATUS Status;
3585
3586 if (Configuration == NULL || Progress == NULL) {
3587 return EFI_INVALID_PARAMETER;
3588 }
3589
3590 *Progress = Configuration;
3591 if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
3592 return EFI_NOT_FOUND;
3593 }
3594
3595 PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
3596
3597 //
3598 // Get Configuration from Variable.
3599 //
3600 SecureBootExtractConfigFromVariable (PrivateData, &IfrNvData);
3601
3602 //
3603 // Map the Configuration to the configuration block.
3604 //
3605 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
3606 Status = gHiiConfigRouting->ConfigToBlock (
3607 gHiiConfigRouting,
3608 Configuration,
3609 (UINT8 *)&IfrNvData,
3610 &BufferSize,
3611 Progress
3612 );
3613 if (EFI_ERROR (Status)) {
3614 return Status;
3615 }
3616
3617 //
3618 // Store Buffer Storage back to EFI variable if needed
3619 //
3620 if (!IfrNvData.HideSecureBoot) {
3621 Status = SaveSecureBootVariable (IfrNvData.AttemptSecureBoot);
3622 if (EFI_ERROR (Status)) {
3623 return Status;
3624 }
3625 }
3626
3627 *Progress = Configuration + StrLen (Configuration);
3628 return EFI_SUCCESS;
3629 }
3630
3631 /**
3632 This function to load signature list, the update the menu page.
3633
3634 @param[in] PrivateData Module's private data.
3635 @param[in] LabelId Label number to insert opcodes.
3636 @param[in] FormId Form ID of current page.
3637 @param[in] QuestionIdBase Base question id of the signature list.
3638
3639 @retval EFI_SUCCESS Success to update the signature list page
3640 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
3641 **/
3642 EFI_STATUS
3643 LoadSignatureList (
3644 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
3645 IN UINT16 LabelId,
3646 IN EFI_FORM_ID FormId,
3647 IN EFI_QUESTION_ID QuestionIdBase
3648 )
3649 {
3650 EFI_STATUS Status;
3651 EFI_STRING_ID ListType;
3652 EFI_STRING FormatNameString;
3653 EFI_STRING FormatHelpString;
3654 EFI_STRING FormatTypeString;
3655 EFI_SIGNATURE_LIST *ListWalker;
3656 EFI_IFR_GUID_LABEL *StartLabel;
3657 EFI_IFR_GUID_LABEL *EndLabel;
3658 EFI_IFR_GUID_LABEL *StartGoto;
3659 EFI_IFR_GUID_LABEL *EndGoto;
3660 EFI_FORM_ID DstFormId;
3661 VOID *StartOpCodeHandle;
3662 VOID *EndOpCodeHandle;
3663 VOID *StartGotoHandle;
3664 VOID *EndGotoHandle;
3665 UINTN DataSize;
3666 UINTN RemainingSize;
3667 UINT16 Index;
3668 UINT8 *VariableData;
3669 CHAR16 VariableName[BUFFER_MAX_SIZE];
3670 CHAR16 NameBuffer[BUFFER_MAX_SIZE];
3671 CHAR16 HelpBuffer[BUFFER_MAX_SIZE];
3672
3673 Status = EFI_SUCCESS;
3674 FormatNameString = NULL;
3675 FormatHelpString = NULL;
3676 StartOpCodeHandle = NULL;
3677 EndOpCodeHandle = NULL;
3678 StartGotoHandle = NULL;
3679 EndGotoHandle = NULL;
3680 Index = 0;
3681 VariableData = NULL;
3682
3683 //
3684 // Initialize the container for dynamic opcodes.
3685 //
3686 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
3687 if (StartOpCodeHandle == NULL) {
3688 Status = EFI_OUT_OF_RESOURCES;
3689 goto ON_EXIT;
3690 }
3691
3692 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
3693 if (EndOpCodeHandle == NULL) {
3694 Status = EFI_OUT_OF_RESOURCES;
3695 goto ON_EXIT;
3696 }
3697
3698 StartGotoHandle = HiiAllocateOpCodeHandle ();
3699 if (StartGotoHandle == NULL) {
3700 Status = EFI_OUT_OF_RESOURCES;
3701 goto ON_EXIT;
3702 }
3703
3704 EndGotoHandle = HiiAllocateOpCodeHandle ();
3705 if (EndGotoHandle == NULL) {
3706 Status = EFI_OUT_OF_RESOURCES;
3707 goto ON_EXIT;
3708 }
3709
3710 //
3711 // Create Hii Extend Label OpCode.
3712 //
3713 StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
3714 StartOpCodeHandle,
3715 &gEfiIfrTianoGuid,
3716 NULL,
3717 sizeof (EFI_IFR_GUID_LABEL)
3718 );
3719 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
3720 StartLabel->Number = LabelId;
3721
3722 EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
3723 EndOpCodeHandle,
3724 &gEfiIfrTianoGuid,
3725 NULL,
3726 sizeof (EFI_IFR_GUID_LABEL)
3727 );
3728 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
3729 EndLabel->Number = LABEL_END;
3730
3731 StartGoto = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode(
3732 StartGotoHandle,
3733 &gEfiIfrTianoGuid,
3734 NULL,
3735 sizeof(EFI_IFR_GUID_LABEL)
3736 );
3737 StartGoto->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
3738 StartGoto->Number = LABEL_DELETE_ALL_LIST_BUTTON;
3739
3740 EndGoto = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode(
3741 EndGotoHandle,
3742 &gEfiIfrTianoGuid,
3743 NULL,
3744 sizeof(EFI_IFR_GUID_LABEL)
3745 );
3746 EndGoto->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
3747 EndGoto->Number = LABEL_END;
3748
3749 if (PrivateData->VariableName == Variable_DB) {
3750 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE);
3751 DstFormId = FORMID_SECURE_BOOT_DB_OPTION_FORM;
3752 } else if (PrivateData->VariableName == Variable_DBX) {
3753 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE1);
3754 DstFormId = FORMID_SECURE_BOOT_DBX_OPTION_FORM;
3755 } else if (PrivateData->VariableName == Variable_DBT) {
3756 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE2);
3757 DstFormId = FORMID_SECURE_BOOT_DBT_OPTION_FORM;
3758 } else {
3759 goto ON_EXIT;
3760 }
3761
3762 HiiCreateGotoOpCode (
3763 StartGotoHandle,
3764 DstFormId,
3765 STRING_TOKEN (STR_SECURE_BOOT_DELETE_ALL_LIST),
3766 STRING_TOKEN (STR_SECURE_BOOT_DELETE_ALL_LIST),
3767 EFI_IFR_FLAG_CALLBACK,
3768 KEY_SECURE_BOOT_DELETE_ALL_LIST
3769 );
3770
3771 //
3772 // Read Variable, the variable name save in the PrivateData->VariableName.
3773 //
3774 DataSize = 0;
3775 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
3776 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
3777 goto ON_EXIT;
3778 }
3779
3780 VariableData = AllocateZeroPool (DataSize);
3781 if (VariableData == NULL) {
3782 Status = EFI_OUT_OF_RESOURCES;
3783 goto ON_EXIT;
3784 }
3785 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
3786 if (EFI_ERROR (Status)) {
3787 goto ON_EXIT;
3788 }
3789
3790 FormatNameString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_LIST_NAME_FORMAT), NULL);
3791 FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_LIST_HELP_FORMAT), NULL);
3792 if (FormatNameString == NULL || FormatHelpString == NULL) {
3793 goto ON_EXIT;
3794 }
3795
3796 RemainingSize = DataSize;
3797 ListWalker = (EFI_SIGNATURE_LIST *)VariableData;
3798 while ((RemainingSize > 0) && (RemainingSize >= ListWalker->SignatureListSize)) {
3799 if (CompareGuid (&ListWalker->SignatureType, &gEfiCertRsa2048Guid)) {
3800 ListType = STRING_TOKEN (STR_LIST_TYPE_RSA2048_SHA256);
3801 } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Guid)) {
3802 ListType = STRING_TOKEN (STR_LIST_TYPE_X509);
3803 } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertSha1Guid)) {
3804 ListType = STRING_TOKEN (STR_LIST_TYPE_SHA1);
3805 } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertSha256Guid)) {
3806 ListType = STRING_TOKEN (STR_LIST_TYPE_SHA256);
3807 } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Sha256Guid)) {
3808 ListType = STRING_TOKEN (STR_LIST_TYPE_X509_SHA256);
3809 } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Sha384Guid)) {
3810 ListType = STRING_TOKEN (STR_LIST_TYPE_X509_SHA384);
3811 } else if (CompareGuid (&ListWalker->SignatureType, &gEfiCertX509Sha512Guid)) {
3812 ListType = STRING_TOKEN (STR_LIST_TYPE_X509_SHA512);
3813 } else {
3814 ListType = STRING_TOKEN (STR_LIST_TYPE_UNKNOWN);
3815 }
3816 FormatTypeString = HiiGetString (PrivateData->HiiHandle, ListType, NULL);
3817 if (FormatTypeString == NULL) {
3818 goto ON_EXIT;
3819 }
3820
3821 ZeroMem (NameBuffer, sizeof (NameBuffer));
3822 UnicodeSPrint (NameBuffer, sizeof (NameBuffer), FormatNameString, Index + 1);
3823
3824 ZeroMem (HelpBuffer, sizeof (HelpBuffer));
3825 UnicodeSPrint (HelpBuffer,
3826 sizeof (HelpBuffer),
3827 FormatHelpString,
3828 FormatTypeString,
3829 SIGNATURE_DATA_COUNTS (ListWalker)
3830 );
3831 SECUREBOOT_FREE_NON_NULL (FormatTypeString);
3832 FormatTypeString = NULL;
3833
3834 HiiCreateGotoOpCode (
3835 StartOpCodeHandle,
3836 SECUREBOOT_DELETE_SIGNATURE_DATA_FORM,
3837 HiiSetString (PrivateData->HiiHandle, 0, NameBuffer, NULL),
3838 HiiSetString (PrivateData->HiiHandle, 0, HelpBuffer, NULL),
3839 EFI_IFR_FLAG_CALLBACK,
3840 QuestionIdBase + Index++
3841 );
3842
3843 RemainingSize -= ListWalker->SignatureListSize;
3844 ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
3845 }
3846
3847 ON_EXIT:
3848 HiiUpdateForm (
3849 PrivateData->HiiHandle,
3850 &gSecureBootConfigFormSetGuid,
3851 FormId,
3852 StartOpCodeHandle,
3853 EndOpCodeHandle
3854 );
3855
3856 HiiUpdateForm (
3857 PrivateData->HiiHandle,
3858 &gSecureBootConfigFormSetGuid,
3859 FormId,
3860 StartGotoHandle,
3861 EndGotoHandle
3862 );
3863
3864 SECUREBOOT_FREE_NON_OPCODE (StartOpCodeHandle);
3865 SECUREBOOT_FREE_NON_OPCODE (EndOpCodeHandle);
3866 SECUREBOOT_FREE_NON_OPCODE (StartGotoHandle);
3867 SECUREBOOT_FREE_NON_OPCODE (EndGotoHandle);
3868
3869 SECUREBOOT_FREE_NON_NULL (VariableData);
3870 SECUREBOOT_FREE_NON_NULL (FormatNameString);
3871 SECUREBOOT_FREE_NON_NULL (FormatHelpString);
3872
3873 PrivateData->ListCount = Index;
3874
3875 return Status;
3876 }
3877
3878 /**
3879 Parse hash value from EFI_SIGNATURE_DATA, and save in the CHAR16 type array.
3880 The buffer is callee allocated and should be freed by the caller.
3881
3882 @param[in] ListEntry The pointer point to the signature list.
3883 @param[in] DataEntry The signature data we are processing.
3884 @param[out] BufferToReturn Buffer to save the hash value.
3885
3886 @retval EFI_INVALID_PARAMETER Invalid List or Data or Buffer.
3887 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3888 @retval EFI_SUCCESS Operation success.
3889 **/
3890 EFI_STATUS
3891 ParseHashValue (
3892 IN EFI_SIGNATURE_LIST *ListEntry,
3893 IN EFI_SIGNATURE_DATA *DataEntry,
3894 OUT CHAR16 **BufferToReturn
3895 )
3896 {
3897 UINTN Index;
3898 UINTN BufferIndex;
3899 UINTN TotalSize;
3900 UINTN DataSize;
3901 UINTN Line;
3902 UINTN OneLineBytes;
3903
3904 //
3905 // Assume that, display 8 bytes in one line.
3906 //
3907 OneLineBytes = 8;
3908
3909 if (ListEntry == NULL || DataEntry == NULL || BufferToReturn == NULL) {
3910 return EFI_INVALID_PARAMETER;
3911 }
3912
3913 DataSize = ListEntry->SignatureSize - sizeof(EFI_GUID);
3914 Line = (DataSize + OneLineBytes - 1) / OneLineBytes;
3915
3916 //
3917 // Each byte will split two Hex-number, and each line need additional memory to save '\r\n'.
3918 //
3919 TotalSize = ((DataSize + Line) * 2 * sizeof(CHAR16));
3920
3921 *BufferToReturn = AllocateZeroPool(TotalSize);
3922 if (*BufferToReturn == NULL) {
3923 return EFI_OUT_OF_RESOURCES;
3924 }
3925
3926 for (Index = 0, BufferIndex = 0; Index < DataSize; Index = Index + 1) {
3927 if ((Index > 0) && (Index % OneLineBytes == 0)) {
3928 BufferIndex += UnicodeSPrint(&(*BufferToReturn)[BufferIndex], TotalSize - sizeof(CHAR16) * BufferIndex, L"\n");
3929 }
3930 BufferIndex += UnicodeSPrint(&(*BufferToReturn)[BufferIndex], TotalSize - sizeof(CHAR16) * BufferIndex, L"%02x", DataEntry->SignatureData[Index]);
3931 }
3932 BufferIndex += UnicodeSPrint(&(*BufferToReturn)[BufferIndex], TotalSize - sizeof(CHAR16) * BufferIndex, L"\n");
3933
3934 return EFI_SUCCESS;
3935 }
3936
3937 /**
3938 Function to get the common name from the X509 format certificate.
3939 The buffer is callee allocated and should be freed by the caller.
3940
3941 @param[in] ListEntry The pointer point to the signature list.
3942 @param[in] DataEntry The signature data we are processing.
3943 @param[out] BufferToReturn Buffer to save the CN of X509 certificate.
3944
3945 @retval EFI_INVALID_PARAMETER Invalid List or Data or Buffer.
3946 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3947 @retval EFI_SUCCESS Operation success.
3948 @retval EFI_NOT_FOUND Not found CN field in the X509 certificate.
3949 **/
3950 EFI_STATUS
3951 GetCommonNameFromX509 (
3952 IN EFI_SIGNATURE_LIST *ListEntry,
3953 IN EFI_SIGNATURE_DATA *DataEntry,
3954 OUT CHAR16 **BufferToReturn
3955 )
3956 {
3957 EFI_STATUS Status;
3958 CHAR8 *CNBuffer;
3959 UINTN CNBufferSize;
3960
3961 Status = EFI_SUCCESS;
3962 CNBuffer = NULL;
3963
3964 CNBuffer = AllocateZeroPool(256);
3965 if (CNBuffer == NULL) {
3966 Status = EFI_OUT_OF_RESOURCES;
3967 goto ON_EXIT;
3968 }
3969
3970 CNBufferSize = 256;
3971 X509GetCommonName (
3972 (UINT8 *)DataEntry + sizeof(EFI_GUID),
3973 ListEntry->SignatureSize - sizeof(EFI_GUID),
3974 CNBuffer,
3975 &CNBufferSize
3976 );
3977
3978 *BufferToReturn = AllocateZeroPool(256 * sizeof(CHAR16));
3979 if (*BufferToReturn == NULL) {
3980 Status = EFI_OUT_OF_RESOURCES;
3981 goto ON_EXIT;
3982 }
3983
3984 AsciiStrToUnicodeStrS (CNBuffer, *BufferToReturn, 256);
3985
3986 ON_EXIT:
3987 SECUREBOOT_FREE_NON_NULL (CNBuffer);
3988
3989 return Status;
3990 }
3991
3992 /**
3993 Format the help info for the signature data, each help info contain 3 parts.
3994 1. Onwer Guid.
3995 2. Content, depends on the type of the signature list.
3996 3. Revocation time.
3997
3998 @param[in] PrivateData Module's private data.
3999 @param[in] ListEntry Point to the signature list.
4000 @param[in] DataEntry Point to the signature data we are processing.
4001 @param[out] StringId Save the string id of help info.
4002
4003 @retval EFI_SUCCESS Operation success.
4004 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
4005 **/
4006 EFI_STATUS
4007 FormatHelpInfo (
4008 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
4009 IN EFI_SIGNATURE_LIST *ListEntry,
4010 IN EFI_SIGNATURE_DATA *DataEntry,
4011 OUT EFI_STRING_ID *StringId
4012 )
4013 {
4014 EFI_STATUS Status;
4015 EFI_TIME *Time;
4016 EFI_STRING_ID ListTypeId;
4017 EFI_STRING FormatHelpString;
4018 EFI_STRING FormatTypeString;
4019 UINTN DataSize;
4020 UINTN HelpInfoIndex;
4021 UINTN TotalSize;
4022 CHAR16 GuidString[BUFFER_MAX_SIZE];
4023 CHAR16 TimeString[BUFFER_MAX_SIZE];
4024 CHAR16 *DataString;
4025 CHAR16 *HelpInfoString;
4026 BOOLEAN IsCert;
4027
4028 Status = EFI_SUCCESS;
4029 Time = NULL;
4030 FormatTypeString = NULL;
4031 HelpInfoIndex = 0;
4032 DataString = NULL;
4033 HelpInfoString = NULL;
4034 IsCert = FALSE;
4035
4036 if (CompareGuid(&ListEntry->SignatureType, &gEfiCertRsa2048Guid)) {
4037 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_RSA2048_SHA256);
4038 DataSize = ListEntry->SignatureSize - sizeof(EFI_GUID);
4039 IsCert = TRUE;
4040 } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Guid)) {
4041 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509);
4042 DataSize = ListEntry->SignatureSize - sizeof(EFI_GUID);
4043 IsCert = TRUE;
4044 } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertSha1Guid)) {
4045 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_SHA1);
4046 DataSize = 20;
4047 } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertSha256Guid)) {
4048 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_SHA256);
4049 DataSize = 32;
4050 } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Sha256Guid)) {
4051 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509_SHA256);
4052 DataSize = 32;
4053 Time = (EFI_TIME *)(DataEntry->SignatureData + DataSize);
4054 } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Sha384Guid)) {
4055 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509_SHA384);
4056 DataSize = 48;
4057 Time = (EFI_TIME *)(DataEntry->SignatureData + DataSize);
4058 } else if (CompareGuid(&ListEntry->SignatureType, &gEfiCertX509Sha512Guid)) {
4059 ListTypeId = STRING_TOKEN(STR_LIST_TYPE_X509_SHA512);
4060 DataSize = 64;
4061 Time = (EFI_TIME *)(DataEntry->SignatureData + DataSize);
4062 } else {
4063 Status = EFI_UNSUPPORTED;
4064 goto ON_EXIT;
4065 }
4066
4067 FormatTypeString = HiiGetString (PrivateData->HiiHandle, ListTypeId, NULL);
4068 if (FormatTypeString == NULL) {
4069 goto ON_EXIT;
4070 }
4071
4072 TotalSize = 1024;
4073 HelpInfoString = AllocateZeroPool (TotalSize);
4074 if (HelpInfoString == NULL) {
4075 Status = EFI_OUT_OF_RESOURCES;
4076 goto ON_EXIT;
4077 }
4078
4079 //
4080 // Format GUID part.
4081 //
4082 ZeroMem (GuidString, sizeof (GuidString));
4083 GuidToString(&DataEntry->SignatureOwner, GuidString, BUFFER_MAX_SIZE);
4084 FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_GUID), NULL);
4085 if (FormatHelpString == NULL) {
4086 goto ON_EXIT;
4087 }
4088 HelpInfoIndex += UnicodeSPrint (
4089 &HelpInfoString[HelpInfoIndex],
4090 TotalSize - sizeof(CHAR16) * HelpInfoIndex,
4091 FormatHelpString,
4092 GuidString
4093 );
4094 SECUREBOOT_FREE_NON_NULL (FormatHelpString);
4095 FormatHelpString = NULL;
4096
4097 //
4098 // Format content part, it depends on the type of signature list, hash value or CN.
4099 //
4100 if (IsCert) {
4101 GetCommonNameFromX509 (ListEntry, DataEntry, &DataString);
4102 FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_CN), NULL);
4103 } else {
4104 //
4105 // Format hash value for each signature data entry.
4106 //
4107 ParseHashValue (ListEntry, DataEntry, &DataString);
4108 FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_HASH), NULL);
4109 }
4110 if (FormatHelpString == NULL) {
4111 goto ON_EXIT;
4112 }
4113 HelpInfoIndex += UnicodeSPrint (
4114 &HelpInfoString[HelpInfoIndex],
4115 TotalSize - sizeof (CHAR16) * HelpInfoIndex,
4116 FormatHelpString,
4117 FormatTypeString,
4118 DataSize,
4119 DataString
4120 );
4121 SECUREBOOT_FREE_NON_NULL (FormatHelpString);
4122 FormatHelpString = NULL;
4123
4124 //
4125 // Format revocation time part.
4126 //
4127 if (Time != NULL) {
4128 ZeroMem (TimeString, sizeof (TimeString));
4129 UnicodeSPrint (
4130 TimeString,
4131 sizeof (TimeString),
4132 L"%d-%d-%d %d:%d:%d",
4133 Time->Year,
4134 Time->Month,
4135 Time->Day,
4136 Time->Hour,
4137 Time->Minute,
4138 Time->Second
4139 );
4140 FormatHelpString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_HELP_FORMAT_TIME), NULL);
4141 if (FormatHelpString == NULL) {
4142 goto ON_EXIT;
4143 }
4144 UnicodeSPrint (
4145 &HelpInfoString[HelpInfoIndex],
4146 TotalSize - sizeof (CHAR16) * HelpInfoIndex,
4147 FormatHelpString,
4148 TimeString
4149 );
4150 SECUREBOOT_FREE_NON_NULL (FormatHelpString);
4151 FormatHelpString = NULL;
4152 }
4153
4154 *StringId = HiiSetString (PrivateData->HiiHandle, 0, HelpInfoString, NULL);
4155 ON_EXIT:
4156 SECUREBOOT_FREE_NON_NULL (DataString);
4157 SECUREBOOT_FREE_NON_NULL (HelpInfoString);
4158
4159 SECUREBOOT_FREE_NON_NULL (FormatTypeString);
4160
4161 return Status;
4162 }
4163
4164 /**
4165 This function to load signature data under the signature list.
4166
4167 @param[in] PrivateData Module's private data.
4168 @param[in] LabelId Label number to insert opcodes.
4169 @param[in] FormId Form ID of current page.
4170 @param[in] QuestionIdBase Base question id of the signature list.
4171 @param[in] ListIndex Indicate to load which signature list.
4172
4173 @retval EFI_SUCCESS Success to update the signature list page
4174 @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
4175 **/
4176 EFI_STATUS
4177 LoadSignatureData (
4178 IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
4179 IN UINT16 LabelId,
4180 IN EFI_FORM_ID FormId,
4181 IN EFI_QUESTION_ID QuestionIdBase,
4182 IN UINT16 ListIndex
4183 )
4184 {
4185 EFI_STATUS Status;
4186 EFI_SIGNATURE_LIST *ListWalker;
4187 EFI_SIGNATURE_DATA *DataWalker;
4188 EFI_IFR_GUID_LABEL *StartLabel;
4189 EFI_IFR_GUID_LABEL *EndLabel;
4190 EFI_STRING_ID HelpStringId;
4191 EFI_STRING FormatNameString;
4192 VOID *StartOpCodeHandle;
4193 VOID *EndOpCodeHandle;
4194 UINTN DataSize;
4195 UINTN RemainingSize;
4196 UINT16 Index;
4197 UINT8 *VariableData;
4198 CHAR16 VariableName[BUFFER_MAX_SIZE];
4199 CHAR16 NameBuffer[BUFFER_MAX_SIZE];
4200
4201 Status = EFI_SUCCESS;
4202 FormatNameString = NULL;
4203 StartOpCodeHandle = NULL;
4204 EndOpCodeHandle = NULL;
4205 Index = 0;
4206 VariableData = NULL;
4207
4208 //
4209 // Initialize the container for dynamic opcodes.
4210 //
4211 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
4212 if (StartOpCodeHandle == NULL) {
4213 Status = EFI_OUT_OF_RESOURCES;
4214 goto ON_EXIT;
4215 }
4216
4217 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
4218 if (EndOpCodeHandle == NULL) {
4219 Status = EFI_OUT_OF_RESOURCES;
4220 goto ON_EXIT;
4221 }
4222
4223 //
4224 // Create Hii Extend Label OpCode.
4225 //
4226 StartLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
4227 StartOpCodeHandle,
4228 &gEfiIfrTianoGuid,
4229 NULL,
4230 sizeof (EFI_IFR_GUID_LABEL)
4231 );
4232 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
4233 StartLabel->Number = LabelId;
4234
4235 EndLabel = (EFI_IFR_GUID_LABEL *)HiiCreateGuidOpCode (
4236 EndOpCodeHandle,
4237 &gEfiIfrTianoGuid,
4238 NULL,
4239 sizeof (EFI_IFR_GUID_LABEL)
4240 );
4241 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
4242 EndLabel->Number = LABEL_END;
4243
4244 if (PrivateData->VariableName == Variable_DB) {
4245 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE);
4246 } else if (PrivateData->VariableName == Variable_DBX) {
4247 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE1);
4248 } else if (PrivateData->VariableName == Variable_DBT) {
4249 UnicodeSPrint (VariableName, sizeof (VariableName), EFI_IMAGE_SECURITY_DATABASE2);
4250 } else {
4251 goto ON_EXIT;
4252 }
4253
4254 //
4255 // Read Variable, the variable name save in the PrivateData->VariableName.
4256 //
4257 DataSize = 0;
4258 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
4259 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
4260 goto ON_EXIT;
4261 }
4262
4263 VariableData = AllocateZeroPool (DataSize);
4264 if (VariableData == NULL) {
4265 Status = EFI_OUT_OF_RESOURCES;
4266 goto ON_EXIT;
4267 }
4268 Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, VariableData);
4269 if (EFI_ERROR (Status)) {
4270 goto ON_EXIT;
4271 }
4272
4273 RemainingSize = DataSize;
4274 ListWalker = (EFI_SIGNATURE_LIST *)VariableData;
4275
4276 //
4277 // Skip signature list.
4278 //
4279 while ((RemainingSize > 0) && (RemainingSize >= ListWalker->SignatureListSize) && ListIndex-- > 0) {
4280 RemainingSize -= ListWalker->SignatureListSize;
4281 ListWalker = (EFI_SIGNATURE_LIST *)((UINT8 *)ListWalker + ListWalker->SignatureListSize);
4282 }
4283
4284 FormatNameString = HiiGetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SIGNATURE_DATA_NAME_FORMAT), NULL);
4285 if (FormatNameString == NULL) {
4286 goto ON_EXIT;
4287 }
4288
4289 DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)ListWalker + sizeof(EFI_SIGNATURE_LIST) + ListWalker->SignatureHeaderSize);
4290 for (Index = 0; Index < SIGNATURE_DATA_COUNTS(ListWalker); Index = Index + 1) {
4291 //
4292 // Format name buffer.
4293 //
4294 ZeroMem (NameBuffer, sizeof (NameBuffer));
4295 UnicodeSPrint (NameBuffer, sizeof (NameBuffer), FormatNameString, Index + 1);
4296
4297 //
4298 // Format help info buffer.
4299 //
4300 Status = FormatHelpInfo (PrivateData, ListWalker, DataWalker, &HelpStringId);
4301 if (EFI_ERROR (Status)) {
4302 goto ON_EXIT;
4303 }
4304
4305 HiiCreateCheckBoxOpCode (
4306 StartOpCodeHandle,
4307 (EFI_QUESTION_ID)(QuestionIdBase + Index),
4308 0,
4309 0,
4310 HiiSetString (PrivateData->HiiHandle, 0, NameBuffer, NULL),
4311 HelpStringId,
4312 EFI_IFR_FLAG_CALLBACK,
4313 0,
4314 NULL
4315 );
4316
4317 ZeroMem(NameBuffer, 100);
4318 DataWalker = (EFI_SIGNATURE_DATA *)((UINT8 *)DataWalker + ListWalker->SignatureSize);
4319 }
4320
4321 //
4322 // Allocate a buffer to record which signature data will be checked.
4323 // This memory buffer will be freed when exit from the SECUREBOOT_DELETE_SIGNATURE_DATA_FORM form.
4324 //
4325 PrivateData->CheckArray = AllocateZeroPool (SIGNATURE_DATA_COUNTS (ListWalker) * sizeof (BOOLEAN));
4326 ON_EXIT:
4327 HiiUpdateForm (
4328 PrivateData->HiiHandle,
4329 &gSecureBootConfigFormSetGuid,
4330 FormId,
4331 StartOpCodeHandle,
4332 EndOpCodeHandle
4333 );
4334
4335 SECUREBOOT_FREE_NON_OPCODE (StartOpCodeHandle);
4336 SECUREBOOT_FREE_NON_OPCODE (EndOpCodeHandle);
4337
4338 SECUREBOOT_FREE_NON_NULL (VariableData);
4339 SECUREBOOT_FREE_NON_NULL (FormatNameString);
4340
4341 return Status;
4342 }
4343
4344 /**
4345 This function is called to provide results data to the driver.
4346
4347 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
4348 @param[in] Action Specifies the type of action taken by the browser.
4349 @param[in] QuestionId A unique value which is sent to the original
4350 exporting driver so that it can identify the type
4351 of data to expect.
4352 @param[in] Type The type of value for the question.
4353 @param[in] Value A pointer to the data being sent to the original
4354 exporting driver.
4355 @param[out] ActionRequest On return, points to the action requested by the
4356 callback function.
4357
4358 @retval EFI_SUCCESS The callback successfully handled the action.
4359 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
4360 variable and its data.
4361 @retval EFI_DEVICE_ERROR The variable could not be saved.
4362 @retval EFI_UNSUPPORTED The specified Action is not supported by the
4363 callback.
4364
4365 **/
4366 EFI_STATUS
4367 EFIAPI
4368 SecureBootCallback (
4369 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
4370 IN EFI_BROWSER_ACTION Action,
4371 IN EFI_QUESTION_ID QuestionId,
4372 IN UINT8 Type,
4373 IN EFI_IFR_TYPE_VALUE *Value,
4374 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
4375 )
4376 {
4377 EFI_INPUT_KEY Key;
4378 EFI_STATUS Status;
4379 RETURN_STATUS RStatus;
4380 SECUREBOOT_CONFIG_PRIVATE_DATA *Private;
4381 UINTN BufferSize;
4382 SECUREBOOT_CONFIGURATION *IfrNvData;
4383 UINT16 LabelId;
4384 UINT8 *SecureBootEnable;
4385 UINT8 *Pk;
4386 UINT8 *SecureBootMode;
4387 UINT8 *SetupMode;
4388 CHAR16 PromptString[100];
4389 EFI_DEVICE_PATH_PROTOCOL *File;
4390 UINTN NameLength;
4391 UINT16 *FilePostFix;
4392 SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
4393 BOOLEAN GetBrowserDataResult;
4394 ENROLL_KEY_ERROR EnrollKeyErrorCode;
4395
4396 Status = EFI_SUCCESS;
4397 SecureBootEnable = NULL;
4398 SecureBootMode = NULL;
4399 SetupMode = NULL;
4400 File = NULL;
4401 EnrollKeyErrorCode = None_Error;
4402
4403 if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
4404 return EFI_INVALID_PARAMETER;
4405 }
4406
4407 Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
4408
4409 gSecureBootPrivateData = Private;
4410
4411 //
4412 // Retrieve uncommitted data from Browser
4413 //
4414 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
4415 IfrNvData = AllocateZeroPool (BufferSize);
4416 if (IfrNvData == NULL) {
4417 return EFI_OUT_OF_RESOURCES;
4418 }
4419
4420 GetBrowserDataResult = HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData);
4421
4422 if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
4423 if (QuestionId == KEY_SECURE_BOOT_MODE) {
4424 //
4425 // Update secure boot strings when opening this form
4426 //
4427 Status = UpdateSecureBootString(Private);
4428 SecureBootExtractConfigFromVariable (Private, IfrNvData);
4429 mIsEnterSecureBootForm = TRUE;
4430 } else {
4431 //
4432 // When entering SecureBoot OPTION Form
4433 // always close opened file & free resource
4434 //
4435 if ((QuestionId == KEY_SECURE_BOOT_PK_OPTION) ||
4436 (QuestionId == KEY_SECURE_BOOT_KEK_OPTION) ||
4437 (QuestionId == KEY_SECURE_BOOT_DB_OPTION) ||
4438 (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) ||
4439 (QuestionId == KEY_SECURE_BOOT_DBT_OPTION)) {
4440 CloseEnrolledFile(Private->FileContext);
4441 } else if (QuestionId == KEY_SECURE_BOOT_DELETE_ALL_LIST) {
4442 //
4443 // Update ListCount field in varstore
4444 // Button "Delete All Signature List" is
4445 // enable when ListCount is greater than 0.
4446 //
4447 IfrNvData->ListCount = Private->ListCount;
4448 }
4449 }
4450 goto EXIT;
4451 }
4452
4453 if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
4454 Status = EFI_UNSUPPORTED;
4455 if (QuestionId == KEY_SECURE_BOOT_MODE) {
4456 if (mIsEnterSecureBootForm) {
4457 Value->u8 = SECURE_BOOT_MODE_STANDARD;
4458 Status = EFI_SUCCESS;
4459 }
4460 }
4461 goto EXIT;
4462 }
4463
4464 if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
4465 (Action != EFI_BROWSER_ACTION_CHANGING) &&
4466 (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&
4467 (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {
4468 Status = EFI_UNSUPPORTED;
4469 goto EXIT;
4470 }
4471
4472 if (Action == EFI_BROWSER_ACTION_CHANGING) {
4473
4474 switch (QuestionId) {
4475 case KEY_SECURE_BOOT_ENABLE:
4476 GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
4477 if (NULL != SecureBootEnable) {
4478 FreePool (SecureBootEnable);
4479 if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) {
4480 CreatePopUp (
4481 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4482 &Key,
4483 L"Only Physical Presence User could disable secure boot!",
4484 NULL
4485 );
4486 Status = EFI_UNSUPPORTED;
4487 } else {
4488 CreatePopUp (
4489 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4490 &Key,
4491 L"Configuration changed, please reset the platform to take effect!",
4492 NULL
4493 );
4494 }
4495 }
4496 break;
4497
4498 case KEY_SECURE_BOOT_KEK_OPTION:
4499 case KEY_SECURE_BOOT_DB_OPTION:
4500 case KEY_SECURE_BOOT_DBX_OPTION:
4501 case KEY_SECURE_BOOT_DBT_OPTION:
4502 PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
4503 //
4504 // Clear Signature GUID.
4505 //
4506 ZeroMem (IfrNvData->SignatureGuid, sizeof (IfrNvData->SignatureGuid));
4507 if (Private->SignatureGUID == NULL) {
4508 Private->SignatureGUID = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID));
4509 if (Private->SignatureGUID == NULL) {
4510 return EFI_OUT_OF_RESOURCES;
4511 }
4512 }
4513
4514 //
4515 // Cleanup VFRData once leaving PK/KEK/DB/DBX/DBT enroll/delete page
4516 //
4517 SecureBootExtractConfigFromVariable (PrivateData, IfrNvData);
4518
4519 if (QuestionId == KEY_SECURE_BOOT_DB_OPTION) {
4520 LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
4521 } else if (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) {
4522 LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
4523 } else if (QuestionId == KEY_SECURE_BOOT_DBT_OPTION) {
4524 LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
4525 } else {
4526 LabelId = FORMID_ENROLL_KEK_FORM;
4527 }
4528
4529 //
4530 // Refresh selected file.
4531 //
4532 CleanUpPage (LabelId, Private);
4533 break;
4534 case KEY_SECURE_BOOT_PK_OPTION:
4535 LabelId = FORMID_ENROLL_PK_FORM;
4536 //
4537 // Refresh selected file.
4538 //
4539 CleanUpPage (LabelId, Private);
4540 break;
4541
4542 case FORMID_ENROLL_PK_FORM:
4543 ChooseFile (NULL, NULL, UpdatePKFromFile, &File);
4544 break;
4545
4546 case FORMID_ENROLL_KEK_FORM:
4547 ChooseFile (NULL, NULL, UpdateKEKFromFile, &File);
4548 break;
4549
4550 case SECUREBOOT_ENROLL_SIGNATURE_TO_DB:
4551 ChooseFile (NULL, NULL, UpdateDBFromFile, &File);
4552 break;
4553
4554 case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX:
4555 ChooseFile (NULL, NULL, UpdateDBXFromFile, &File);
4556
4557 if (Private->FileContext->FHandle != NULL) {
4558 //
4559 // Parse the file's postfix.
4560 //
4561 NameLength = StrLen (Private->FileContext->FileName);
4562 if (NameLength <= 4) {
4563 return FALSE;
4564 }
4565 FilePostFix = Private->FileContext->FileName + NameLength - 4;
4566
4567 if (IsDerEncodeCertificate (FilePostFix)) {
4568 //
4569 // Supports DER-encoded X509 certificate.
4570 //
4571 IfrNvData->FileEnrollType = X509_CERT_FILE_TYPE;
4572 } else if (IsAuthentication2Format(Private->FileContext->FHandle)){
4573 IfrNvData->FileEnrollType = AUTHENTICATION_2_FILE_TYPE;
4574 } else {
4575 IfrNvData->FileEnrollType = PE_IMAGE_FILE_TYPE;
4576 }
4577 Private->FileContext->FileType = IfrNvData->FileEnrollType;
4578
4579 //
4580 // Clean up Certificate Format if File type is not X509 DER
4581 //
4582 if (IfrNvData->FileEnrollType != X509_CERT_FILE_TYPE) {
4583 IfrNvData->CertificateFormat = HASHALG_RAW;
4584 }
4585 DEBUG((DEBUG_ERROR, "IfrNvData->FileEnrollType %d\n", Private->FileContext->FileType));
4586 }
4587
4588 break;
4589
4590 case SECUREBOOT_ENROLL_SIGNATURE_TO_DBT:
4591 ChooseFile (NULL, NULL, UpdateDBTFromFile, &File);
4592 break;
4593
4594 case KEY_SECURE_BOOT_DELETE_PK:
4595 if (Value->u8) {
4596 CreatePopUp (
4597 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4598 &Key,
4599 L"Are you sure you want to delete PK? Secure boot will be disabled!",
4600 L"Press 'Y' to delete PK and exit, 'N' to discard change and return",
4601 NULL
4602 );
4603 if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
4604 Status = DeletePlatformKey ();
4605 if (EFI_ERROR (Status)) {
4606 CreatePopUp (
4607 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4608 &Key,
4609 L"Only Physical Presence User could delete PK in custom mode!",
4610 NULL
4611 );
4612 }
4613 }
4614 }
4615 break;
4616
4617 case KEY_DELETE_KEK:
4618 UpdateDeletePage (
4619 Private,
4620 EFI_KEY_EXCHANGE_KEY_NAME,
4621 &gEfiGlobalVariableGuid,
4622 LABEL_KEK_DELETE,
4623 FORMID_DELETE_KEK_FORM,
4624 OPTION_DEL_KEK_QUESTION_ID
4625 );
4626 break;
4627
4628 case SECUREBOOT_DELETE_SIGNATURE_FROM_DB:
4629 UpdateDeletePage (
4630 Private,
4631 EFI_IMAGE_SECURITY_DATABASE,
4632 &gEfiImageSecurityDatabaseGuid,
4633 LABEL_DB_DELETE,
4634 SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
4635 OPTION_DEL_DB_QUESTION_ID
4636 );
4637 break;
4638
4639 //
4640 // From DBX option to the level-1 form, display signature list.
4641 //
4642 case KEY_VALUE_FROM_DBX_TO_LIST_FORM:
4643 Private->VariableName = Variable_DBX;
4644 LoadSignatureList (
4645 Private,
4646 LABEL_SIGNATURE_LIST_START,
4647 SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4648 OPTION_SIGNATURE_LIST_QUESTION_ID
4649 );
4650 break;
4651
4652 //
4653 // Delete all signature list and reload.
4654 //
4655 case KEY_SECURE_BOOT_DELETE_ALL_LIST:
4656 CreatePopUp(
4657 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4658 &Key,
4659 L"Press 'Y' to delete signature list.",
4660 L"Press other key to cancel and exit.",
4661 NULL
4662 );
4663
4664 if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
4665 DeleteSignatureEx (Private, Delete_Signature_List_All, IfrNvData->CheckedDataCount);
4666 }
4667
4668 LoadSignatureList (
4669 Private,
4670 LABEL_SIGNATURE_LIST_START,
4671 SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4672 OPTION_SIGNATURE_LIST_QUESTION_ID
4673 );
4674 break;
4675
4676 //
4677 // Delete one signature list and reload.
4678 //
4679 case KEY_SECURE_BOOT_DELETE_ALL_DATA:
4680 CreatePopUp(
4681 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4682 &Key,
4683 L"Press 'Y' to delete signature data.",
4684 L"Press other key to cancel and exit.",
4685 NULL
4686 );
4687
4688 if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
4689 DeleteSignatureEx (Private, Delete_Signature_List_One, IfrNvData->CheckedDataCount);
4690 }
4691
4692 LoadSignatureList (
4693 Private,
4694 LABEL_SIGNATURE_LIST_START,
4695 SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4696 OPTION_SIGNATURE_LIST_QUESTION_ID
4697 );
4698 break;
4699
4700 //
4701 // Delete checked signature data and reload.
4702 //
4703 case KEY_SECURE_BOOT_DELETE_CHECK_DATA:
4704 CreatePopUp(
4705 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4706 &Key,
4707 L"Press 'Y' to delete signature data.",
4708 L"Press other key to cancel and exit.",
4709 NULL
4710 );
4711
4712 if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
4713 DeleteSignatureEx (Private, Delete_Signature_Data, IfrNvData->CheckedDataCount);
4714 }
4715
4716 LoadSignatureList (
4717 Private,
4718 LABEL_SIGNATURE_LIST_START,
4719 SECUREBOOT_DELETE_SIGNATURE_LIST_FORM,
4720 OPTION_SIGNATURE_LIST_QUESTION_ID
4721 );
4722 break;
4723
4724 case SECUREBOOT_DELETE_SIGNATURE_FROM_DBT:
4725 UpdateDeletePage (
4726 Private,
4727 EFI_IMAGE_SECURITY_DATABASE2,
4728 &gEfiImageSecurityDatabaseGuid,
4729 LABEL_DBT_DELETE,
4730 SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
4731 OPTION_DEL_DBT_QUESTION_ID
4732 );
4733
4734 break;
4735
4736 case KEY_VALUE_SAVE_AND_EXIT_KEK:
4737 Status = EnrollKeyExchangeKey (Private);
4738 if (EFI_ERROR (Status)) {
4739 CreatePopUp (
4740 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4741 &Key,
4742 L"ERROR: Unsupported file type!",
4743 L"Only supports DER-encoded X509 certificate",
4744 NULL
4745 );
4746 }
4747 break;
4748
4749 case KEY_VALUE_SAVE_AND_EXIT_DB:
4750 Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE);
4751 if (EFI_ERROR (Status)) {
4752 CreatePopUp (
4753 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4754 &Key,
4755 L"ERROR: Unsupported file type!",
4756 L"Only supports DER-encoded X509 certificate and executable EFI image",
4757 NULL
4758 );
4759 }
4760 break;
4761
4762 case KEY_VALUE_SAVE_AND_EXIT_DBX:
4763 if (IsX509CertInDbx (Private, EFI_IMAGE_SECURITY_DATABASE1)) {
4764 CreatePopUp (
4765 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4766 &Key,
4767 L"Enrollment failed! Same certificate had already been in the dbx!",
4768 NULL
4769 );
4770
4771 //
4772 // Cert already exists in DBX. Close opened file before exit.
4773 //
4774 CloseEnrolledFile(Private->FileContext);
4775 break;
4776 }
4777
4778 if ((IfrNvData != NULL) && (IfrNvData->CertificateFormat < HASHALG_MAX)) {
4779 Status = EnrollX509HashtoSigDB (
4780 Private,
4781 IfrNvData->CertificateFormat,
4782 &IfrNvData->RevocationDate,
4783 &IfrNvData->RevocationTime,
4784 IfrNvData->AlwaysRevocation
4785 );
4786 IfrNvData->CertificateFormat = HASHALG_RAW;
4787 } else {
4788 Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE1);
4789 }
4790 if (EFI_ERROR (Status)) {
4791 CreatePopUp (
4792 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4793 &Key,
4794 L"ERROR: Unsupported file type!",
4795 L"Only supports DER-encoded X509 certificate, AUTH_2 format data & executable EFI image",
4796 NULL
4797 );
4798 }
4799 break;
4800
4801 case KEY_VALUE_SAVE_AND_EXIT_DBT:
4802 Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE2);
4803 if (EFI_ERROR (Status)) {
4804 CreatePopUp (
4805 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4806 &Key,
4807 L"ERROR: Unsupported file type!",
4808 L"Only supports DER-encoded X509 certificate.",
4809 NULL
4810 );
4811 }
4812 break;
4813 case KEY_VALUE_SAVE_AND_EXIT_PK:
4814 //
4815 // Check the suffix, encode type and the key strength of PK certificate.
4816 //
4817 Status = CheckX509Certificate (Private->FileContext, &EnrollKeyErrorCode);
4818 if (EFI_ERROR (Status)) {
4819 if (EnrollKeyErrorCode != None_Error && EnrollKeyErrorCode < Enroll_Error_Max) {
4820 CreatePopUp (
4821 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4822 &Key,
4823 mX509EnrollPromptTitle[EnrollKeyErrorCode],
4824 mX509EnrollPromptString[EnrollKeyErrorCode],
4825 NULL
4826 );
4827 break;
4828 }
4829 } else {
4830 Status = EnrollPlatformKey (Private);
4831 }
4832 if (EFI_ERROR (Status)) {
4833 UnicodeSPrint (
4834 PromptString,
4835 sizeof (PromptString),
4836 L"Error status: %x.",
4837 Status
4838 );
4839 CreatePopUp (
4840 EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
4841 &Key,
4842 L"ERROR: Enrollment failed!",
4843 PromptString,
4844 NULL
4845 );
4846 }
4847 break;
4848 default:
4849 if ((QuestionId >= OPTION_DEL_KEK_QUESTION_ID) &&
4850 (QuestionId < (OPTION_DEL_KEK_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4851 DeleteKeyExchangeKey (Private, QuestionId);
4852 } else if ((QuestionId >= OPTION_DEL_DB_QUESTION_ID) &&
4853 (QuestionId < (OPTION_DEL_DB_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4854 DeleteSignature (
4855 Private,
4856 EFI_IMAGE_SECURITY_DATABASE,
4857 &gEfiImageSecurityDatabaseGuid,
4858 LABEL_DB_DELETE,
4859 SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
4860 OPTION_DEL_DB_QUESTION_ID,
4861 QuestionId - OPTION_DEL_DB_QUESTION_ID
4862 );
4863 } else if ((QuestionId >= OPTION_SIGNATURE_LIST_QUESTION_ID) &&
4864 (QuestionId < (OPTION_SIGNATURE_LIST_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4865 LoadSignatureData (
4866 Private,
4867 LABEL_SIGNATURE_DATA_START,
4868 SECUREBOOT_DELETE_SIGNATURE_DATA_FORM,
4869 OPTION_SIGNATURE_DATA_QUESTION_ID,
4870 QuestionId - OPTION_SIGNATURE_LIST_QUESTION_ID
4871 );
4872 Private->ListIndex = QuestionId - OPTION_SIGNATURE_LIST_QUESTION_ID;
4873 } else if ((QuestionId >= OPTION_SIGNATURE_DATA_QUESTION_ID) &&
4874 (QuestionId < (OPTION_SIGNATURE_DATA_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4875 if (Private->CheckArray[QuestionId - OPTION_SIGNATURE_DATA_QUESTION_ID]) {
4876 IfrNvData->CheckedDataCount--;
4877 Private->CheckArray[QuestionId - OPTION_SIGNATURE_DATA_QUESTION_ID] = FALSE;
4878 } else {
4879 IfrNvData->CheckedDataCount++;
4880 Private->CheckArray[QuestionId - OPTION_SIGNATURE_DATA_QUESTION_ID] = TRUE;
4881 }
4882 } else if ((QuestionId >= OPTION_DEL_DBT_QUESTION_ID) &&
4883 (QuestionId < (OPTION_DEL_DBT_QUESTION_ID + OPTION_CONFIG_RANGE))) {
4884 DeleteSignature (
4885 Private,
4886 EFI_IMAGE_SECURITY_DATABASE2,
4887 &gEfiImageSecurityDatabaseGuid,
4888 LABEL_DBT_DELETE,
4889 SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
4890 OPTION_DEL_DBT_QUESTION_ID,
4891 QuestionId - OPTION_DEL_DBT_QUESTION_ID
4892 );
4893 }
4894 break;
4895
4896 case KEY_VALUE_NO_SAVE_AND_EXIT_PK:
4897 case KEY_VALUE_NO_SAVE_AND_EXIT_KEK:
4898 case KEY_VALUE_NO_SAVE_AND_EXIT_DB:
4899 case KEY_VALUE_NO_SAVE_AND_EXIT_DBX:
4900 case KEY_VALUE_NO_SAVE_AND_EXIT_DBT:
4901 CloseEnrolledFile(Private->FileContext);
4902
4903 if (Private->SignatureGUID != NULL) {
4904 FreePool (Private->SignatureGUID);
4905 Private->SignatureGUID = NULL;
4906 }
4907 break;
4908 }
4909 } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
4910 switch (QuestionId) {
4911 case KEY_SECURE_BOOT_ENABLE:
4912 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
4913 break;
4914 case KEY_SECURE_BOOT_MODE:
4915 mIsEnterSecureBootForm = FALSE;
4916 break;
4917 case KEY_SECURE_BOOT_KEK_GUID:
4918 case KEY_SECURE_BOOT_SIGNATURE_GUID_DB:
4919 case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX:
4920 case KEY_SECURE_BOOT_SIGNATURE_GUID_DBT:
4921 ASSERT (Private->SignatureGUID != NULL);
4922 RStatus = StrToGuid (IfrNvData->SignatureGuid, Private->SignatureGUID);
4923 if (RETURN_ERROR (RStatus) || (IfrNvData->SignatureGuid[GUID_STRING_LENGTH] != L'\0')) {
4924 Status = EFI_INVALID_PARAMETER;
4925 break;
4926 }
4927
4928 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
4929 break;
4930 case KEY_SECURE_BOOT_DELETE_PK:
4931 GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
4932 if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {
4933 IfrNvData->DeletePk = TRUE;
4934 IfrNvData->HasPk = FALSE;
4935 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
4936 } else {
4937 IfrNvData->DeletePk = FALSE;
4938 IfrNvData->HasPk = TRUE;
4939 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
4940 }
4941 if (SetupMode != NULL) {
4942 FreePool (SetupMode);
4943 }
4944 break;
4945 default:
4946 break;
4947 }
4948 } else if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
4949 if (QuestionId == KEY_HIDE_SECURE_BOOT) {
4950 GetVariable2 (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID**)&Pk, NULL);
4951 if (Pk == NULL) {
4952 IfrNvData->HideSecureBoot = TRUE;
4953 } else {
4954 FreePool (Pk);
4955 IfrNvData->HideSecureBoot = FALSE;
4956 }
4957 Value->b = IfrNvData->HideSecureBoot;
4958 }
4959 } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
4960 //
4961 // Force the platform back to Standard Mode once user leave the setup screen.
4962 //
4963 GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
4964 if (NULL != SecureBootMode && *SecureBootMode == CUSTOM_SECURE_BOOT_MODE) {
4965 IfrNvData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
4966 SetSecureBootMode(STANDARD_SECURE_BOOT_MODE);
4967 }
4968 if (SecureBootMode != NULL) {
4969 FreePool (SecureBootMode);
4970 }
4971
4972 if (QuestionId == KEY_SECURE_BOOT_DELETE_ALL_DATA) {
4973 //
4974 // Free memory when exit from the SECUREBOOT_DELETE_SIGNATURE_DATA_FORM form.
4975 //
4976 SECUREBOOT_FREE_NON_NULL (Private->CheckArray);
4977 IfrNvData->CheckedDataCount = 0;
4978 }
4979 }
4980
4981 EXIT:
4982
4983 if (!EFI_ERROR (Status) && GetBrowserDataResult) {
4984 BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
4985 HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL);
4986 }
4987
4988 FreePool (IfrNvData);
4989
4990 if (File != NULL){
4991 FreePool(File);
4992 File = NULL;
4993 }
4994
4995 return EFI_SUCCESS;
4996 }
4997
4998 /**
4999 This function publish the SecureBoot configuration Form.
5000
5001 @param[in, out] PrivateData Points to SecureBoot configuration private data.
5002
5003 @retval EFI_SUCCESS HII Form is installed successfully.
5004 @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
5005 @retval Others Other errors as indicated.
5006
5007 **/
5008 EFI_STATUS
5009 InstallSecureBootConfigForm (
5010 IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
5011 )
5012 {
5013 EFI_STATUS Status;
5014 EFI_HII_HANDLE HiiHandle;
5015 EFI_HANDLE DriverHandle;
5016 EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
5017
5018 DriverHandle = NULL;
5019 ConfigAccess = &PrivateData->ConfigAccess;
5020 Status = gBS->InstallMultipleProtocolInterfaces (
5021 &DriverHandle,
5022 &gEfiDevicePathProtocolGuid,
5023 &mSecureBootHiiVendorDevicePath,
5024 &gEfiHiiConfigAccessProtocolGuid,
5025 ConfigAccess,
5026 NULL
5027 );
5028 if (EFI_ERROR (Status)) {
5029 return Status;
5030 }
5031
5032 PrivateData->DriverHandle = DriverHandle;
5033
5034 //
5035 // Publish the HII package list
5036 //
5037 HiiHandle = HiiAddPackages (
5038 &gSecureBootConfigFormSetGuid,
5039 DriverHandle,
5040 SecureBootConfigDxeStrings,
5041 SecureBootConfigBin,
5042 NULL
5043 );
5044 if (HiiHandle == NULL) {
5045 gBS->UninstallMultipleProtocolInterfaces (
5046 DriverHandle,
5047 &gEfiDevicePathProtocolGuid,
5048 &mSecureBootHiiVendorDevicePath,
5049 &gEfiHiiConfigAccessProtocolGuid,
5050 ConfigAccess,
5051 NULL
5052 );
5053 return EFI_OUT_OF_RESOURCES;
5054 }
5055
5056 PrivateData->HiiHandle = HiiHandle;
5057
5058 PrivateData->FileContext = AllocateZeroPool (sizeof (SECUREBOOT_FILE_CONTEXT));
5059
5060 if (PrivateData->FileContext == NULL) {
5061 UninstallSecureBootConfigForm (PrivateData);
5062 return EFI_OUT_OF_RESOURCES;
5063 }
5064
5065 //
5066 // Init OpCode Handle and Allocate space for creation of Buffer
5067 //
5068 mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
5069 if (mStartOpCodeHandle == NULL) {
5070 UninstallSecureBootConfigForm (PrivateData);
5071 return EFI_OUT_OF_RESOURCES;
5072 }
5073
5074 mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
5075 if (mEndOpCodeHandle == NULL) {
5076 UninstallSecureBootConfigForm (PrivateData);
5077 return EFI_OUT_OF_RESOURCES;
5078 }
5079
5080 //
5081 // Create Hii Extend Label OpCode as the start opcode
5082 //
5083 mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
5084 mStartOpCodeHandle,
5085 &gEfiIfrTianoGuid,
5086 NULL,
5087 sizeof (EFI_IFR_GUID_LABEL)
5088 );
5089 mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
5090
5091 //
5092 // Create Hii Extend Label OpCode as the end opcode
5093 //
5094 mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
5095 mEndOpCodeHandle,
5096 &gEfiIfrTianoGuid,
5097 NULL,
5098 sizeof (EFI_IFR_GUID_LABEL)
5099 );
5100 mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
5101 mEndLabel->Number = LABEL_END;
5102
5103 return EFI_SUCCESS;
5104 }
5105
5106 /**
5107 This function removes SecureBoot configuration Form.
5108
5109 @param[in, out] PrivateData Points to SecureBoot configuration private data.
5110
5111 **/
5112 VOID
5113 UninstallSecureBootConfigForm (
5114 IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
5115 )
5116 {
5117 //
5118 // Uninstall HII package list
5119 //
5120 if (PrivateData->HiiHandle != NULL) {
5121 HiiRemovePackages (PrivateData->HiiHandle);
5122 PrivateData->HiiHandle = NULL;
5123 }
5124
5125 //
5126 // Uninstall HII Config Access Protocol
5127 //
5128 if (PrivateData->DriverHandle != NULL) {
5129 gBS->UninstallMultipleProtocolInterfaces (
5130 PrivateData->DriverHandle,
5131 &gEfiDevicePathProtocolGuid,
5132 &mSecureBootHiiVendorDevicePath,
5133 &gEfiHiiConfigAccessProtocolGuid,
5134 &PrivateData->ConfigAccess,
5135 NULL
5136 );
5137 PrivateData->DriverHandle = NULL;
5138 }
5139
5140 if (PrivateData->SignatureGUID != NULL) {
5141 FreePool (PrivateData->SignatureGUID);
5142 }
5143
5144 if (PrivateData->FileContext != NULL) {
5145 FreePool (PrivateData->FileContext);
5146 }
5147
5148 FreePool (PrivateData);
5149
5150 if (mStartOpCodeHandle != NULL) {
5151 HiiFreeOpCodeHandle (mStartOpCodeHandle);
5152 }
5153
5154 if (mEndOpCodeHandle != NULL) {
5155 HiiFreeOpCodeHandle (mEndOpCodeHandle);
5156 }
5157 }