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