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