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