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