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