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