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