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