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