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