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