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