]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
OvmfPkg/EnrollDefaultKeys: enroll PK/KEK1 from the Type 11 SMBIOS table
[mirror_edk2.git] / OvmfPkg / EnrollDefaultKeys / EnrollDefaultKeys.c
1 /** @file
2 Enroll default PK, KEK, db, dbx.
3
4 Copyright (C) 2014-2019, Red Hat, Inc.
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8 #include <Guid/AuthenticatedVariableFormat.h> // gEfiCustomModeEnableGuid
9 #include <Guid/GlobalVariable.h> // EFI_SETUP_MODE_NAME
10 #include <Guid/ImageAuthentication.h> // EFI_IMAGE_SECURITY_DATABASE
11 #include <Guid/MicrosoftVendor.h> // gMicrosoftVendorGuid
12 #include <Guid/OvmfPkKek1AppPrefix.h> // gOvmfPkKek1AppPrefixGuid
13 #include <IndustryStandard/SmBios.h> // SMBIOS_HANDLE_PI_RESERVED
14 #include <Library/BaseLib.h> // GUID_STRING_LENGTH
15 #include <Library/BaseMemoryLib.h> // CopyGuid()
16 #include <Library/DebugLib.h> // ASSERT()
17 #include <Library/MemoryAllocationLib.h> // FreePool()
18 #include <Library/PrintLib.h> // AsciiSPrint()
19 #include <Library/ShellCEntryLib.h> // ShellAppMain()
20 #include <Library/UefiBootServicesTableLib.h> // gBS
21 #include <Library/UefiLib.h> // AsciiPrint()
22 #include <Library/UefiRuntimeServicesTableLib.h> // gRT
23 #include <Protocol/Smbios.h> // EFI_SMBIOS_PROTOCOL
24
25 #include "EnrollDefaultKeys.h"
26
27
28 /**
29 Fetch the X509 certificate (to be used as Platform Key and first Key Exchange
30 Key) from SMBIOS.
31
32 @param[out] PkKek1 The X509 certificate in DER encoding from the
33 hypervisor, to be enrolled as PK and first KEK
34 entry. On success, the caller is responsible for
35 releasing PkKek1 with FreePool().
36
37 @param[out] SizeOfPkKek1 The size of PkKek1 in bytes.
38
39 @retval EFI_SUCCESS PkKek1 and SizeOfPkKek1 have been set
40 successfully.
41
42 @retval EFI_NOT_FOUND An OEM String matching
43 OVMF_PK_KEK1_APP_PREFIX_GUID has not been
44 found.
45
46 @retval EFI_PROTOCOL_ERROR In the OEM String matching
47 OVMF_PK_KEK1_APP_PREFIX_GUID, the certificate
48 is empty, or it has invalid base64 encoding.
49
50 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
51
52 @return Error codes from gBS->LocateProtocol().
53 **/
54 STATIC
55 EFI_STATUS
56 GetPkKek1 (
57 OUT UINT8 **PkKek1,
58 OUT UINTN *SizeOfPkKek1
59 )
60 {
61 CONST CHAR8 *Base64Cert;
62 CHAR8 OvmfPkKek1AppPrefix[GUID_STRING_LENGTH + 1 + 1];
63 EFI_STATUS Status;
64 EFI_SMBIOS_PROTOCOL *Smbios;
65 EFI_SMBIOS_HANDLE Handle;
66 EFI_SMBIOS_TYPE Type;
67 EFI_SMBIOS_TABLE_HEADER *Header;
68 SMBIOS_TABLE_TYPE11 *OemStringsTable;
69 UINTN Base64CertLen;
70 UINTN DecodedCertSize;
71 UINT8 *DecodedCert;
72
73 Base64Cert = NULL;
74
75 //
76 // Format the application prefix, for OEM String matching.
77 //
78 AsciiSPrint (OvmfPkKek1AppPrefix, sizeof OvmfPkKek1AppPrefix, "%g:",
79 &gOvmfPkKek1AppPrefixGuid);
80
81 //
82 // Scan all "OEM Strings" tables.
83 //
84 Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL,
85 (VOID **)&Smbios);
86 if (EFI_ERROR (Status)) {
87 AsciiPrint ("error: failed to locate EFI_SMBIOS_PROTOCOL: %r\n", Status);
88 return Status;
89 }
90
91 Handle = SMBIOS_HANDLE_PI_RESERVED;
92 Type = SMBIOS_TYPE_OEM_STRINGS;
93 for (Status = Smbios->GetNext (Smbios, &Handle, &Type, &Header, NULL);
94 !EFI_ERROR (Status);
95 Status = Smbios->GetNext (Smbios, &Handle, &Type, &Header, NULL)) {
96 CONST CHAR8 *OemString;
97 UINTN Idx;
98
99 if (Header->Length < sizeof *OemStringsTable) {
100 //
101 // Malformed table header, skip to next.
102 //
103 continue;
104 }
105 OemStringsTable = (SMBIOS_TABLE_TYPE11 *)Header;
106
107 //
108 // Scan all strings in the unformatted area of the current "OEM Strings"
109 // table.
110 //
111 OemString = (CONST CHAR8 *)(OemStringsTable + 1);
112 for (Idx = 0; Idx < OemStringsTable->StringCount; ++Idx) {
113 CHAR8 CandidatePrefix[sizeof OvmfPkKek1AppPrefix];
114
115 //
116 // NUL-terminate the candidate prefix for case-insensitive comparison.
117 //
118 AsciiStrnCpyS (CandidatePrefix, sizeof CandidatePrefix, OemString,
119 GUID_STRING_LENGTH + 1);
120 if (AsciiStriCmp (OvmfPkKek1AppPrefix, CandidatePrefix) == 0) {
121 //
122 // The current string matches the prefix.
123 //
124 Base64Cert = OemString + GUID_STRING_LENGTH + 1;
125 break;
126 }
127 OemString += AsciiStrSize (OemString);
128 }
129
130 if (Idx < OemStringsTable->StringCount) {
131 //
132 // The current table has a matching string.
133 //
134 break;
135 }
136 }
137
138 if (EFI_ERROR (Status)) {
139 //
140 // No table with a matching string has been found.
141 //
142 AsciiPrint ("error: OEM String with app prefix %g not found: %r\n",
143 &gOvmfPkKek1AppPrefixGuid, Status);
144 return EFI_NOT_FOUND;
145 }
146
147 ASSERT (Base64Cert != NULL);
148 Base64CertLen = AsciiStrLen (Base64Cert);
149
150 //
151 // Verify the base64 encoding, and determine the decoded size.
152 //
153 DecodedCertSize = 0;
154 Status = Base64Decode (Base64Cert, Base64CertLen, NULL, &DecodedCertSize);
155 switch (Status) {
156 case EFI_BUFFER_TOO_SMALL:
157 if (DecodedCertSize > 0) {
158 break;
159 }
160 //
161 // Fall through: the above Base64Decode() call is ill-specified in BaseLib
162 // if Source decodes to zero bytes (for example if it consists of ignored
163 // whitespace only).
164 //
165 case EFI_SUCCESS:
166 AsciiPrint ("error: empty certificate after app prefix %g\n",
167 &gOvmfPkKek1AppPrefixGuid);
168 return EFI_PROTOCOL_ERROR;
169 default:
170 AsciiPrint ("error: invalid base64 string after app prefix %g\n",
171 &gOvmfPkKek1AppPrefixGuid);
172 return EFI_PROTOCOL_ERROR;
173 }
174
175 //
176 // Allocate the output buffer.
177 //
178 DecodedCert = AllocatePool (DecodedCertSize);
179 if (DecodedCert == NULL) {
180 AsciiPrint ("error: failed to allocate memory\n");
181 return EFI_OUT_OF_RESOURCES;
182 }
183
184 //
185 // Decoding will succeed at this point.
186 //
187 Status = Base64Decode (Base64Cert, Base64CertLen, DecodedCert,
188 &DecodedCertSize);
189 ASSERT_EFI_ERROR (Status);
190
191 *PkKek1 = DecodedCert;
192 *SizeOfPkKek1 = DecodedCertSize;
193 return EFI_SUCCESS;
194 }
195
196
197 /**
198 Enroll a set of certificates in a global variable, overwriting it.
199
200 The variable will be rewritten with NV+BS+RT+AT attributes.
201
202 @param[in] VariableName The name of the variable to overwrite.
203
204 @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable to
205 overwrite.
206
207 @param[in] CertType The GUID determining the type of all the
208 certificates in the set that is passed in. For
209 example, gEfiCertX509Guid stands for DER-encoded
210 X.509 certificates, while gEfiCertSha256Guid stands
211 for SHA256 image hashes.
212
213 @param[in] ... A list of
214
215 IN CONST UINT8 *Cert,
216 IN UINTN CertSize,
217 IN CONST EFI_GUID *OwnerGuid
218
219 triplets. If the first component of a triplet is
220 NULL, then the other two components are not
221 accessed, and processing is terminated. The list of
222 certificates is enrolled in the variable specified,
223 overwriting it. The OwnerGuid component identifies
224 the agent installing the certificate.
225
226 @retval EFI_INVALID_PARAMETER The triplet list is empty (ie. the first Cert
227 value is NULL), or one of the CertSize values
228 is 0, or one of the CertSize values would
229 overflow the accumulated UINT32 data size.
230
231 @retval EFI_OUT_OF_RESOURCES Out of memory while formatting variable
232 payload.
233
234 @retval EFI_SUCCESS Enrollment successful; the variable has been
235 overwritten (or created).
236
237 @return Error codes from gRT->GetTime() and
238 gRT->SetVariable().
239 **/
240 STATIC
241 EFI_STATUS
242 EFIAPI
243 EnrollListOfCerts (
244 IN CHAR16 *VariableName,
245 IN EFI_GUID *VendorGuid,
246 IN EFI_GUID *CertType,
247 ...
248 )
249 {
250 UINTN DataSize;
251 SINGLE_HEADER *SingleHeader;
252 REPEATING_HEADER *RepeatingHeader;
253 VA_LIST Marker;
254 CONST UINT8 *Cert;
255 EFI_STATUS Status;
256 UINT8 *Data;
257 UINT8 *Position;
258
259 Status = EFI_SUCCESS;
260
261 //
262 // compute total size first, for UINT32 range check, and allocation
263 //
264 DataSize = sizeof *SingleHeader;
265 VA_START (Marker, CertType);
266 for (Cert = VA_ARG (Marker, CONST UINT8 *);
267 Cert != NULL;
268 Cert = VA_ARG (Marker, CONST UINT8 *)) {
269 UINTN CertSize;
270
271 CertSize = VA_ARG (Marker, UINTN);
272 (VOID)VA_ARG (Marker, CONST EFI_GUID *);
273
274 if (CertSize == 0 ||
275 CertSize > MAX_UINT32 - sizeof *RepeatingHeader ||
276 DataSize > MAX_UINT32 - sizeof *RepeatingHeader - CertSize) {
277 Status = EFI_INVALID_PARAMETER;
278 break;
279 }
280 DataSize += sizeof *RepeatingHeader + CertSize;
281 }
282 VA_END (Marker);
283
284 if (DataSize == sizeof *SingleHeader) {
285 Status = EFI_INVALID_PARAMETER;
286 }
287 if (EFI_ERROR (Status)) {
288 goto Out;
289 }
290
291 Data = AllocatePool (DataSize);
292 if (Data == NULL) {
293 Status = EFI_OUT_OF_RESOURCES;
294 goto Out;
295 }
296
297 Position = Data;
298
299 SingleHeader = (SINGLE_HEADER *)Position;
300 Status = gRT->GetTime (&SingleHeader->TimeStamp, NULL);
301 if (EFI_ERROR (Status)) {
302 goto FreeData;
303 }
304 SingleHeader->TimeStamp.Pad1 = 0;
305 SingleHeader->TimeStamp.Nanosecond = 0;
306 SingleHeader->TimeStamp.TimeZone = 0;
307 SingleHeader->TimeStamp.Daylight = 0;
308 SingleHeader->TimeStamp.Pad2 = 0;
309 #if 0
310 SingleHeader->dwLength = DataSize - sizeof SingleHeader->TimeStamp;
311 #else
312 //
313 // This looks like a bug in edk2. According to the UEFI specification,
314 // dwLength is "The length of the entire certificate, including the length of
315 // the header, in bytes". That shouldn't stop right after CertType -- it
316 // should include everything below it.
317 //
318 SingleHeader->dwLength = sizeof *SingleHeader
319 - sizeof SingleHeader->TimeStamp;
320 #endif
321 SingleHeader->wRevision = 0x0200;
322 SingleHeader->wCertificateType = WIN_CERT_TYPE_EFI_GUID;
323 CopyGuid (&SingleHeader->CertType, &gEfiCertPkcs7Guid);
324 Position += sizeof *SingleHeader;
325
326 VA_START (Marker, CertType);
327 for (Cert = VA_ARG (Marker, CONST UINT8 *);
328 Cert != NULL;
329 Cert = VA_ARG (Marker, CONST UINT8 *)) {
330 UINTN CertSize;
331 CONST EFI_GUID *OwnerGuid;
332
333 CertSize = VA_ARG (Marker, UINTN);
334 OwnerGuid = VA_ARG (Marker, CONST EFI_GUID *);
335
336 RepeatingHeader = (REPEATING_HEADER *)Position;
337 CopyGuid (&RepeatingHeader->SignatureType, CertType);
338 RepeatingHeader->SignatureListSize =
339 (UINT32)(sizeof *RepeatingHeader + CertSize);
340 RepeatingHeader->SignatureHeaderSize = 0;
341 RepeatingHeader->SignatureSize =
342 (UINT32)(sizeof RepeatingHeader->SignatureOwner + CertSize);
343 CopyGuid (&RepeatingHeader->SignatureOwner, OwnerGuid);
344 Position += sizeof *RepeatingHeader;
345
346 CopyMem (Position, Cert, CertSize);
347 Position += CertSize;
348 }
349 VA_END (Marker);
350
351 ASSERT (Data + DataSize == Position);
352
353 Status = gRT->SetVariable (VariableName, VendorGuid,
354 (EFI_VARIABLE_NON_VOLATILE |
355 EFI_VARIABLE_BOOTSERVICE_ACCESS |
356 EFI_VARIABLE_RUNTIME_ACCESS |
357 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),
358 DataSize, Data);
359
360 FreeData:
361 FreePool (Data);
362
363 Out:
364 if (EFI_ERROR (Status)) {
365 AsciiPrint ("error: %a(\"%s\", %g): %r\n", __FUNCTION__, VariableName,
366 VendorGuid, Status);
367 }
368 return Status;
369 }
370
371
372 /**
373 Read a UEFI variable into a caller-allocated buffer, enforcing an exact size.
374
375 @param[in] VariableName The name of the variable to read; passed to
376 gRT->GetVariable().
377
378 @param[in] VendorGuid The vendor (namespace) GUID of the variable to read;
379 passed to gRT->GetVariable().
380
381 @param[out] Data The caller-allocated buffer that is supposed to
382 receive the variable's contents. On error, the
383 contents of Data are indeterminate.
384
385 @param[in] DataSize The size in bytes that the caller requires the UEFI
386 variable to have. The caller is responsible for
387 providing room for DataSize bytes in Data.
388
389 @param[in] AllowMissing If FALSE, the variable is required to exist. If
390 TRUE, the variable is permitted to be missing.
391
392 @retval EFI_SUCCESS The UEFI variable exists, has the required size
393 (DataSize), and has been read into Data.
394
395 @retval EFI_SUCCESS The UEFI variable doesn't exist, and
396 AllowMissing is TRUE. DataSize bytes in Data
397 have been zeroed out.
398
399 @retval EFI_NOT_FOUND The UEFI variable doesn't exist, and
400 AllowMissing is FALSE.
401
402 @retval EFI_BUFFER_TOO_SMALL The UEFI variable exists, but its size is
403 greater than DataSize.
404
405 @retval EFI_PROTOCOL_ERROR The UEFI variable exists, but its size is
406 smaller than DataSize.
407
408 @return Error codes propagated from gRT->GetVariable().
409 **/
410 STATIC
411 EFI_STATUS
412 GetExact (
413 IN CHAR16 *VariableName,
414 IN EFI_GUID *VendorGuid,
415 OUT VOID *Data,
416 IN UINTN DataSize,
417 IN BOOLEAN AllowMissing
418 )
419 {
420 UINTN Size;
421 EFI_STATUS Status;
422
423 Size = DataSize;
424 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &Size, Data);
425 if (EFI_ERROR (Status)) {
426 if (Status == EFI_NOT_FOUND && AllowMissing) {
427 ZeroMem (Data, DataSize);
428 return EFI_SUCCESS;
429 }
430
431 AsciiPrint ("error: GetVariable(\"%s\", %g): %r\n", VariableName,
432 VendorGuid, Status);
433 return Status;
434 }
435
436 if (Size != DataSize) {
437 AsciiPrint ("error: GetVariable(\"%s\", %g): expected size 0x%Lx, "
438 "got 0x%Lx\n", VariableName, VendorGuid, (UINT64)DataSize, (UINT64)Size);
439 return EFI_PROTOCOL_ERROR;
440 }
441
442 return EFI_SUCCESS;
443 }
444
445
446 /**
447 Populate a SETTINGS structure from the underlying UEFI variables.
448
449 The following UEFI variables are standard variables:
450 - L"SetupMode" (EFI_SETUP_MODE_NAME)
451 - L"SecureBoot" (EFI_SECURE_BOOT_MODE_NAME)
452 - L"VendorKeys" (EFI_VENDOR_KEYS_VARIABLE_NAME)
453
454 The following UEFI variables are edk2 extensions:
455 - L"SecureBootEnable" (EFI_SECURE_BOOT_ENABLE_NAME)
456 - L"CustomMode" (EFI_CUSTOM_MODE_NAME)
457
458 The L"SecureBootEnable" UEFI variable is permitted to be missing, in which
459 case the corresponding field in the SETTINGS object will be zeroed out. The
460 rest of the covered UEFI variables are required to exist; otherwise, the
461 function will fail.
462
463 @param[out] Settings The SETTINGS object to fill.
464
465 @retval EFI_SUCCESS Settings has been populated.
466
467 @return Error codes propagated from the GetExact() function. The
468 contents of Settings are indeterminate.
469 **/
470 STATIC
471 EFI_STATUS
472 GetSettings (
473 OUT SETTINGS *Settings
474 )
475 {
476 EFI_STATUS Status;
477
478 Status = GetExact (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid,
479 &Settings->SetupMode, sizeof Settings->SetupMode, FALSE);
480 if (EFI_ERROR (Status)) {
481 return Status;
482 }
483
484 Status = GetExact (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid,
485 &Settings->SecureBoot, sizeof Settings->SecureBoot, FALSE);
486 if (EFI_ERROR (Status)) {
487 return Status;
488 }
489
490 Status = GetExact (EFI_SECURE_BOOT_ENABLE_NAME,
491 &gEfiSecureBootEnableDisableGuid, &Settings->SecureBootEnable,
492 sizeof Settings->SecureBootEnable, TRUE);
493 if (EFI_ERROR (Status)) {
494 return Status;
495 }
496
497 Status = GetExact (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,
498 &Settings->CustomMode, sizeof Settings->CustomMode, FALSE);
499 if (EFI_ERROR (Status)) {
500 return Status;
501 }
502
503 Status = GetExact (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid,
504 &Settings->VendorKeys, sizeof Settings->VendorKeys, FALSE);
505 return Status;
506 }
507
508
509 /**
510 Print the contents of a SETTINGS structure to the UEFI console.
511
512 @param[in] Settings The SETTINGS object to print the contents of.
513 **/
514 STATIC
515 VOID
516 PrintSettings (
517 IN CONST SETTINGS *Settings
518 )
519 {
520 AsciiPrint ("info: SetupMode=%d SecureBoot=%d SecureBootEnable=%d "
521 "CustomMode=%d VendorKeys=%d\n", Settings->SetupMode, Settings->SecureBoot,
522 Settings->SecureBootEnable, Settings->CustomMode, Settings->VendorKeys);
523 }
524
525
526 /**
527 Entry point function of this shell application.
528 **/
529 INTN
530 EFIAPI
531 ShellAppMain (
532 IN UINTN Argc,
533 IN CHAR16 **Argv
534 )
535 {
536 INTN RetVal;
537 EFI_STATUS Status;
538 SETTINGS Settings;
539 UINT8 *PkKek1;
540 UINTN SizeOfPkKek1;
541
542 //
543 // Prepare for failure.
544 //
545 RetVal = 1;
546
547 //
548 // If we're not in Setup Mode, we can't do anything.
549 //
550 Status = GetSettings (&Settings);
551 if (EFI_ERROR (Status)) {
552 return RetVal;
553 }
554 PrintSettings (&Settings);
555
556 if (Settings.SetupMode != 1) {
557 AsciiPrint ("error: already in User Mode\n");
558 return RetVal;
559 }
560
561 //
562 // Fetch the X509 certificate (to be used as Platform Key and first Key
563 // Exchange Key) from SMBIOS.
564 //
565 Status = GetPkKek1 (&PkKek1, &SizeOfPkKek1);
566 if (EFI_ERROR (Status)) {
567 return RetVal;
568 }
569
570 //
571 // Enter Custom Mode so we can enroll PK, KEK, db, and dbx without signature
572 // checks on those variable writes.
573 //
574 if (Settings.CustomMode != CUSTOM_SECURE_BOOT_MODE) {
575 Settings.CustomMode = CUSTOM_SECURE_BOOT_MODE;
576 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,
577 (EFI_VARIABLE_NON_VOLATILE |
578 EFI_VARIABLE_BOOTSERVICE_ACCESS),
579 sizeof Settings.CustomMode, &Settings.CustomMode);
580 if (EFI_ERROR (Status)) {
581 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,
582 &gEfiCustomModeEnableGuid, Status);
583 goto FreePkKek1;
584 }
585 }
586
587 //
588 // Enroll db.
589 //
590 Status = EnrollListOfCerts (
591 EFI_IMAGE_SECURITY_DATABASE,
592 &gEfiImageSecurityDatabaseGuid,
593 &gEfiCertX509Guid,
594 mMicrosoftPca, mSizeOfMicrosoftPca, &gMicrosoftVendorGuid,
595 mMicrosoftUefiCa, mSizeOfMicrosoftUefiCa, &gMicrosoftVendorGuid,
596 NULL);
597 if (EFI_ERROR (Status)) {
598 goto FreePkKek1;
599 }
600
601 //
602 // Enroll dbx.
603 //
604 Status = EnrollListOfCerts (
605 EFI_IMAGE_SECURITY_DATABASE1,
606 &gEfiImageSecurityDatabaseGuid,
607 &gEfiCertSha256Guid,
608 mSha256OfDevNull, mSizeOfSha256OfDevNull, &gEfiCallerIdGuid,
609 NULL);
610 if (EFI_ERROR (Status)) {
611 goto FreePkKek1;
612 }
613
614 //
615 // Enroll KEK.
616 //
617 Status = EnrollListOfCerts (
618 EFI_KEY_EXCHANGE_KEY_NAME,
619 &gEfiGlobalVariableGuid,
620 &gEfiCertX509Guid,
621 PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,
622 mMicrosoftKek, mSizeOfMicrosoftKek, &gMicrosoftVendorGuid,
623 NULL);
624 if (EFI_ERROR (Status)) {
625 goto FreePkKek1;
626 }
627
628 //
629 // Enroll PK, leaving Setup Mode (entering User Mode) at once.
630 //
631 Status = EnrollListOfCerts (
632 EFI_PLATFORM_KEY_NAME,
633 &gEfiGlobalVariableGuid,
634 &gEfiCertX509Guid,
635 PkKek1, SizeOfPkKek1, &gEfiGlobalVariableGuid,
636 NULL);
637 if (EFI_ERROR (Status)) {
638 goto FreePkKek1;
639 }
640
641 //
642 // Leave Custom Mode, so that updates to PK, KEK, db, and dbx require valid
643 // signatures.
644 //
645 Settings.CustomMode = STANDARD_SECURE_BOOT_MODE;
646 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,
647 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
648 sizeof Settings.CustomMode, &Settings.CustomMode);
649 if (EFI_ERROR (Status)) {
650 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,
651 &gEfiCustomModeEnableGuid, Status);
652 goto FreePkKek1;
653 }
654
655 //
656 // Final sanity check:
657 //
658 // [SetupMode]
659 // (read-only, standardized by UEFI)
660 // / \_
661 // 0 1, default
662 // / \_
663 // PK enrolled no PK enrolled yet,
664 // (this is called "User Mode") PK enrollment possible
665 // |
666 // |
667 // [SecureBootEnable]
668 // (read-write, edk2-specific, boot service only)
669 // / \_
670 // 0 1, default
671 // / \_
672 // [SecureBoot]=0 [SecureBoot]=1
673 // (read-only, standardized by UEFI) (read-only, standardized by UEFI)
674 // images are not verified images are verified, platform is
675 // operating in Secure Boot mode
676 // |
677 // |
678 // [CustomMode]
679 // (read-write, edk2-specific, boot service only)
680 // / \_
681 // 0, default 1
682 // / \_
683 // PK, KEK, db, dbx PK, KEK, db, dbx
684 // updates are verified updates are not verified
685 //
686 Status = GetSettings (&Settings);
687 if (EFI_ERROR (Status)) {
688 goto FreePkKek1;
689 }
690 PrintSettings (&Settings);
691
692 if (Settings.SetupMode != 0 || Settings.SecureBoot != 1 ||
693 Settings.SecureBootEnable != 1 || Settings.CustomMode != 0 ||
694 Settings.VendorKeys != 0) {
695 AsciiPrint ("error: unexpected\n");
696 goto FreePkKek1;
697 }
698
699 AsciiPrint ("info: success\n");
700 RetVal = 0;
701
702 FreePkKek1:
703 FreePool (PkKek1);
704
705 return RetVal;
706 }