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