]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
UefiCpuPkg CpuCommFeaturesLib: Fix GP fault issue about ProcTrace
[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
157 if (DecodedCertSize > 0) {\r
158 break;\r
159 }\r
160 //\r
161 // Fall through: the above Base64Decode() call is ill-specified in BaseLib\r
162 // if Source decodes to zero bytes (for example if it consists of ignored\r
163 // whitespace only).\r
164 //\r
165 case EFI_SUCCESS:\r
166 AsciiPrint ("error: empty certificate after app prefix %g\n",\r
167 &gOvmfPkKek1AppPrefixGuid);\r
168 return EFI_PROTOCOL_ERROR;\r
169 default:\r
170 AsciiPrint ("error: invalid base64 string after app prefix %g\n",\r
171 &gOvmfPkKek1AppPrefixGuid);\r
172 return EFI_PROTOCOL_ERROR;\r
173 }\r
174\r
175 //\r
176 // Allocate the output buffer.\r
177 //\r
178 DecodedCert = AllocatePool (DecodedCertSize);\r
179 if (DecodedCert == NULL) {\r
180 AsciiPrint ("error: failed to allocate memory\n");\r
181 return EFI_OUT_OF_RESOURCES;\r
182 }\r
183\r
184 //\r
185 // Decoding will succeed at this point.\r
186 //\r
187 Status = Base64Decode (Base64Cert, Base64CertLen, DecodedCert,\r
188 &DecodedCertSize);\r
189 ASSERT_EFI_ERROR (Status);\r
190\r
191 *PkKek1 = DecodedCert;\r
192 *SizeOfPkKek1 = DecodedCertSize;\r
193 return EFI_SUCCESS;\r
194}\r
195\r
196\r
b1163623
LE
197/**\r
198 Enroll a set of certificates in a global variable, overwriting it.\r
199\r
200 The variable will be rewritten with NV+BS+RT+AT attributes.\r
201\r
202 @param[in] VariableName The name of the variable to overwrite.\r
203\r
204 @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable to\r
205 overwrite.\r
206\r
207 @param[in] CertType The GUID determining the type of all the\r
208 certificates in the set that is passed in. For\r
209 example, gEfiCertX509Guid stands for DER-encoded\r
210 X.509 certificates, while gEfiCertSha256Guid stands\r
211 for SHA256 image hashes.\r
212\r
213 @param[in] ... A list of\r
214\r
215 IN CONST UINT8 *Cert,\r
216 IN UINTN CertSize,\r
217 IN CONST EFI_GUID *OwnerGuid\r
218\r
219 triplets. If the first component of a triplet is\r
220 NULL, then the other two components are not\r
221 accessed, and processing is terminated. The list of\r
222 certificates is enrolled in the variable specified,\r
223 overwriting it. The OwnerGuid component identifies\r
224 the agent installing the certificate.\r
225\r
226 @retval EFI_INVALID_PARAMETER The triplet list is empty (ie. the first Cert\r
227 value is NULL), or one of the CertSize values\r
228 is 0, or one of the CertSize values would\r
229 overflow the accumulated UINT32 data size.\r
230\r
231 @retval EFI_OUT_OF_RESOURCES Out of memory while formatting variable\r
232 payload.\r
233\r
234 @retval EFI_SUCCESS Enrollment successful; the variable has been\r
235 overwritten (or created).\r
236\r
237 @return Error codes from gRT->GetTime() and\r
238 gRT->SetVariable().\r
239**/\r
240STATIC\r
241EFI_STATUS\r
242EFIAPI\r
243EnrollListOfCerts (\r
244 IN CHAR16 *VariableName,\r
245 IN EFI_GUID *VendorGuid,\r
246 IN EFI_GUID *CertType,\r
247 ...\r
248 )\r
249{\r
250 UINTN DataSize;\r
251 SINGLE_HEADER *SingleHeader;\r
252 REPEATING_HEADER *RepeatingHeader;\r
253 VA_LIST Marker;\r
254 CONST UINT8 *Cert;\r
255 EFI_STATUS Status;\r
256 UINT8 *Data;\r
257 UINT8 *Position;\r
258\r
259 Status = EFI_SUCCESS;\r
260\r
261 //\r
262 // compute total size first, for UINT32 range check, and allocation\r
263 //\r
264 DataSize = sizeof *SingleHeader;\r
265 VA_START (Marker, CertType);\r
266 for (Cert = VA_ARG (Marker, CONST UINT8 *);\r
267 Cert != NULL;\r
268 Cert = VA_ARG (Marker, CONST UINT8 *)) {\r
269 UINTN CertSize;\r
270\r
271 CertSize = VA_ARG (Marker, UINTN);\r
272 (VOID)VA_ARG (Marker, CONST EFI_GUID *);\r
273\r
274 if (CertSize == 0 ||\r
275 CertSize > MAX_UINT32 - sizeof *RepeatingHeader ||\r
276 DataSize > MAX_UINT32 - sizeof *RepeatingHeader - CertSize) {\r
277 Status = EFI_INVALID_PARAMETER;\r
278 break;\r
279 }\r
280 DataSize += sizeof *RepeatingHeader + CertSize;\r
281 }\r
282 VA_END (Marker);\r
283\r
284 if (DataSize == sizeof *SingleHeader) {\r
285 Status = EFI_INVALID_PARAMETER;\r
286 }\r
287 if (EFI_ERROR (Status)) {\r
288 goto Out;\r
289 }\r
290\r
291 Data = AllocatePool (DataSize);\r
292 if (Data == NULL) {\r
293 Status = EFI_OUT_OF_RESOURCES;\r
294 goto Out;\r
295 }\r
296\r
297 Position = Data;\r
298\r
299 SingleHeader = (SINGLE_HEADER *)Position;\r
300 Status = gRT->GetTime (&SingleHeader->TimeStamp, NULL);\r
301 if (EFI_ERROR (Status)) {\r
302 goto FreeData;\r
303 }\r
304 SingleHeader->TimeStamp.Pad1 = 0;\r
305 SingleHeader->TimeStamp.Nanosecond = 0;\r
306 SingleHeader->TimeStamp.TimeZone = 0;\r
307 SingleHeader->TimeStamp.Daylight = 0;\r
308 SingleHeader->TimeStamp.Pad2 = 0;\r
309#if 0\r
310 SingleHeader->dwLength = DataSize - sizeof SingleHeader->TimeStamp;\r
311#else\r
312 //\r
313 // This looks like a bug in edk2. According to the UEFI specification,\r
314 // dwLength is "The length of the entire certificate, including the length of\r
315 // the header, in bytes". That shouldn't stop right after CertType -- it\r
316 // should include everything below it.\r
317 //\r
318 SingleHeader->dwLength = sizeof *SingleHeader\r
319 - sizeof SingleHeader->TimeStamp;\r
320#endif\r
321 SingleHeader->wRevision = 0x0200;\r
322 SingleHeader->wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
323 CopyGuid (&SingleHeader->CertType, &gEfiCertPkcs7Guid);\r
324 Position += sizeof *SingleHeader;\r
325\r
326 VA_START (Marker, CertType);\r
327 for (Cert = VA_ARG (Marker, CONST UINT8 *);\r
328 Cert != NULL;\r
329 Cert = VA_ARG (Marker, CONST UINT8 *)) {\r
330 UINTN CertSize;\r
331 CONST EFI_GUID *OwnerGuid;\r
332\r
333 CertSize = VA_ARG (Marker, UINTN);\r
334 OwnerGuid = VA_ARG (Marker, CONST EFI_GUID *);\r
335\r
336 RepeatingHeader = (REPEATING_HEADER *)Position;\r
337 CopyGuid (&RepeatingHeader->SignatureType, CertType);\r
338 RepeatingHeader->SignatureListSize =\r
339 (UINT32)(sizeof *RepeatingHeader + CertSize);\r
340 RepeatingHeader->SignatureHeaderSize = 0;\r
341 RepeatingHeader->SignatureSize =\r
342 (UINT32)(sizeof RepeatingHeader->SignatureOwner + CertSize);\r
343 CopyGuid (&RepeatingHeader->SignatureOwner, OwnerGuid);\r
344 Position += sizeof *RepeatingHeader;\r
345\r
346 CopyMem (Position, Cert, CertSize);\r
347 Position += CertSize;\r
348 }\r
349 VA_END (Marker);\r
350\r
351 ASSERT (Data + DataSize == Position);\r
352\r
353 Status = gRT->SetVariable (VariableName, VendorGuid,\r
354 (EFI_VARIABLE_NON_VOLATILE |\r
355 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
356 EFI_VARIABLE_RUNTIME_ACCESS |\r
357 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),\r
358 DataSize, Data);\r
359\r
360FreeData:\r
361 FreePool (Data);\r
362\r
363Out:\r
364 if (EFI_ERROR (Status)) {\r
365 AsciiPrint ("error: %a(\"%s\", %g): %r\n", __FUNCTION__, VariableName,\r
366 VendorGuid, Status);\r
367 }\r
368 return Status;\r
369}\r
370\r
371\r
86bf2672
LE
372/**\r
373 Read a UEFI variable into a caller-allocated buffer, enforcing an exact size.\r
374\r
375 @param[in] VariableName The name of the variable to read; passed to\r
376 gRT->GetVariable().\r
377\r
378 @param[in] VendorGuid The vendor (namespace) GUID of the variable to read;\r
379 passed to gRT->GetVariable().\r
380\r
381 @param[out] Data The caller-allocated buffer that is supposed to\r
382 receive the variable's contents. On error, the\r
383 contents of Data are indeterminate.\r
384\r
385 @param[in] DataSize The size in bytes that the caller requires the UEFI\r
386 variable to have. The caller is responsible for\r
387 providing room for DataSize bytes in Data.\r
388\r
389 @param[in] AllowMissing If FALSE, the variable is required to exist. If\r
390 TRUE, the variable is permitted to be missing.\r
391\r
392 @retval EFI_SUCCESS The UEFI variable exists, has the required size\r
393 (DataSize), and has been read into Data.\r
394\r
395 @retval EFI_SUCCESS The UEFI variable doesn't exist, and\r
396 AllowMissing is TRUE. DataSize bytes in Data\r
397 have been zeroed out.\r
398\r
399 @retval EFI_NOT_FOUND The UEFI variable doesn't exist, and\r
400 AllowMissing is FALSE.\r
401\r
402 @retval EFI_BUFFER_TOO_SMALL The UEFI variable exists, but its size is\r
403 greater than DataSize.\r
404\r
405 @retval EFI_PROTOCOL_ERROR The UEFI variable exists, but its size is\r
406 smaller than DataSize.\r
407\r
408 @return Error codes propagated from gRT->GetVariable().\r
409**/\r
b1163623
LE
410STATIC\r
411EFI_STATUS\r
b1163623
LE
412GetExact (\r
413 IN CHAR16 *VariableName,\r
414 IN EFI_GUID *VendorGuid,\r
415 OUT VOID *Data,\r
416 IN UINTN DataSize,\r
417 IN BOOLEAN AllowMissing\r
418 )\r
419{\r
420 UINTN Size;\r
421 EFI_STATUS Status;\r
422\r
423 Size = DataSize;\r
424 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &Size, Data);\r
425 if (EFI_ERROR (Status)) {\r
426 if (Status == EFI_NOT_FOUND && AllowMissing) {\r
427 ZeroMem (Data, DataSize);\r
428 return EFI_SUCCESS;\r
429 }\r
430\r
431 AsciiPrint ("error: GetVariable(\"%s\", %g): %r\n", VariableName,\r
432 VendorGuid, Status);\r
433 return Status;\r
434 }\r
435\r
436 if (Size != DataSize) {\r
437 AsciiPrint ("error: GetVariable(\"%s\", %g): expected size 0x%Lx, "\r
438 "got 0x%Lx\n", VariableName, VendorGuid, (UINT64)DataSize, (UINT64)Size);\r
439 return EFI_PROTOCOL_ERROR;\r
440 }\r
441\r
442 return EFI_SUCCESS;\r
443}\r
444\r
86bf2672
LE
445\r
446/**\r
447 Populate a SETTINGS structure from the underlying UEFI variables.\r
448\r
449 The following UEFI variables are standard variables:\r
450 - L"SetupMode" (EFI_SETUP_MODE_NAME)\r
451 - L"SecureBoot" (EFI_SECURE_BOOT_MODE_NAME)\r
452 - L"VendorKeys" (EFI_VENDOR_KEYS_VARIABLE_NAME)\r
453\r
454 The following UEFI variables are edk2 extensions:\r
455 - L"SecureBootEnable" (EFI_SECURE_BOOT_ENABLE_NAME)\r
456 - L"CustomMode" (EFI_CUSTOM_MODE_NAME)\r
457\r
458 The L"SecureBootEnable" UEFI variable is permitted to be missing, in which\r
459 case the corresponding field in the SETTINGS object will be zeroed out. The\r
460 rest of the covered UEFI variables are required to exist; otherwise, the\r
461 function will fail.\r
462\r
463 @param[out] Settings The SETTINGS object to fill.\r
464\r
465 @retval EFI_SUCCESS Settings has been populated.\r
466\r
467 @return Error codes propagated from the GetExact() function. The\r
468 contents of Settings are indeterminate.\r
469**/\r
b1163623
LE
470STATIC\r
471EFI_STATUS\r
b1163623
LE
472GetSettings (\r
473 OUT SETTINGS *Settings\r
474 )\r
475{\r
476 EFI_STATUS Status;\r
477\r
478 Status = GetExact (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid,\r
479 &Settings->SetupMode, sizeof Settings->SetupMode, FALSE);\r
480 if (EFI_ERROR (Status)) {\r
481 return Status;\r
482 }\r
483\r
484 Status = GetExact (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid,\r
485 &Settings->SecureBoot, sizeof Settings->SecureBoot, FALSE);\r
486 if (EFI_ERROR (Status)) {\r
487 return Status;\r
488 }\r
489\r
490 Status = GetExact (EFI_SECURE_BOOT_ENABLE_NAME,\r
491 &gEfiSecureBootEnableDisableGuid, &Settings->SecureBootEnable,\r
492 sizeof Settings->SecureBootEnable, TRUE);\r
493 if (EFI_ERROR (Status)) {\r
494 return Status;\r
495 }\r
496\r
497 Status = GetExact (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
498 &Settings->CustomMode, sizeof Settings->CustomMode, FALSE);\r
499 if (EFI_ERROR (Status)) {\r
500 return Status;\r
501 }\r
502\r
503 Status = GetExact (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid,\r
504 &Settings->VendorKeys, sizeof Settings->VendorKeys, FALSE);\r
505 return Status;\r
506}\r
507\r
86bf2672
LE
508\r
509/**\r
510 Print the contents of a SETTINGS structure to the UEFI console.\r
511\r
512 @param[in] Settings The SETTINGS object to print the contents of.\r
513**/\r
b1163623
LE
514STATIC\r
515VOID\r
b1163623
LE
516PrintSettings (\r
517 IN CONST SETTINGS *Settings\r
518 )\r
519{\r
520 AsciiPrint ("info: SetupMode=%d SecureBoot=%d SecureBootEnable=%d "\r
521 "CustomMode=%d VendorKeys=%d\n", Settings->SetupMode, Settings->SecureBoot,\r
522 Settings->SecureBootEnable, Settings->CustomMode, Settings->VendorKeys);\r
523}\r
524\r
525\r
86bf2672
LE
526/**\r
527 Entry point function of this shell application.\r
528**/\r
b1163623
LE
529INTN\r
530EFIAPI\r
531ShellAppMain (\r
532 IN UINTN Argc,\r
533 IN CHAR16 **Argv\r
534 )\r
535{\r
be9470b3 536 INTN RetVal;\r
b1163623
LE
537 EFI_STATUS Status;\r
538 SETTINGS Settings;\r
be9470b3
LE
539 UINT8 *PkKek1;\r
540 UINTN SizeOfPkKek1;\r
89d7c543
GL
541 BOOLEAN NoDefault;\r
542\r
543 if (Argc == 2 && StrCmp (Argv[1], L"--no-default") == 0) {\r
544 NoDefault = TRUE;\r
545 } else {\r
546 NoDefault = FALSE;\r
547 }\r
be9470b3
LE
548\r
549 //\r
550 // Prepare for failure.\r
551 //\r
552 RetVal = 1;\r
b1163623 553\r
c9727ff1
LE
554 //\r
555 // If we're not in Setup Mode, we can't do anything.\r
556 //\r
b1163623
LE
557 Status = GetSettings (&Settings);\r
558 if (EFI_ERROR (Status)) {\r
be9470b3 559 return RetVal;\r
b1163623
LE
560 }\r
561 PrintSettings (&Settings);\r
562\r
563 if (Settings.SetupMode != 1) {\r
564 AsciiPrint ("error: already in User Mode\n");\r
be9470b3
LE
565 return RetVal;\r
566 }\r
567\r
727d7eba
LE
568 //\r
569 // Set PkKek1 and SizeOfPkKek1 to suppress incorrect compiler/analyzer\r
570 // warnings.\r
571 //\r
572 PkKek1 = NULL;\r
573 SizeOfPkKek1 = 0;\r
574\r
be9470b3
LE
575 //\r
576 // Fetch the X509 certificate (to be used as Platform Key and first Key\r
577 // Exchange Key) from SMBIOS.\r
578 //\r
579 Status = GetPkKek1 (&PkKek1, &SizeOfPkKek1);\r
580 if (EFI_ERROR (Status)) {\r
581 return RetVal;\r
b1163623
LE
582 }\r
583\r
c9727ff1
LE
584 //\r
585 // Enter Custom Mode so we can enroll PK, KEK, db, and dbx without signature\r
586 // checks on those variable writes.\r
587 //\r
b1163623
LE
588 if (Settings.CustomMode != CUSTOM_SECURE_BOOT_MODE) {\r
589 Settings.CustomMode = CUSTOM_SECURE_BOOT_MODE;\r
590 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
591 (EFI_VARIABLE_NON_VOLATILE |\r
592 EFI_VARIABLE_BOOTSERVICE_ACCESS),\r
593 sizeof Settings.CustomMode, &Settings.CustomMode);\r
594 if (EFI_ERROR (Status)) {\r
595 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,\r
596 &gEfiCustomModeEnableGuid, Status);\r
be9470b3 597 goto FreePkKek1;\r
b1163623
LE
598 }\r
599 }\r
600\r
c9727ff1
LE
601 //\r
602 // Enroll db.\r
603 //\r
89d7c543
GL
604 if (NoDefault) {\r
605 Status = EnrollListOfCerts (\r
606 EFI_IMAGE_SECURITY_DATABASE,\r
607 &gEfiImageSecurityDatabaseGuid,\r
608 &gEfiCertX509Guid,\r
609 PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,\r
610 NULL);\r
611 } else {\r
612 Status = EnrollListOfCerts (\r
613 EFI_IMAGE_SECURITY_DATABASE,\r
614 &gEfiImageSecurityDatabaseGuid,\r
615 &gEfiCertX509Guid,\r
616 mMicrosoftPca, mSizeOfMicrosoftPca, &gMicrosoftVendorGuid,\r
617 mMicrosoftUefiCa, mSizeOfMicrosoftUefiCa, &gMicrosoftVendorGuid,\r
618 NULL);\r
619 }\r
b1163623 620 if (EFI_ERROR (Status)) {\r
be9470b3 621 goto FreePkKek1;\r
b1163623
LE
622 }\r
623\r
c9727ff1
LE
624 //\r
625 // Enroll dbx.\r
626 //\r
b1163623
LE
627 Status = EnrollListOfCerts (\r
628 EFI_IMAGE_SECURITY_DATABASE1,\r
629 &gEfiImageSecurityDatabaseGuid,\r
630 &gEfiCertSha256Guid,\r
a79b115a 631 mSha256OfDevNull, mSizeOfSha256OfDevNull, &gEfiCallerIdGuid,\r
b1163623
LE
632 NULL);\r
633 if (EFI_ERROR (Status)) {\r
be9470b3 634 goto FreePkKek1;\r
b1163623
LE
635 }\r
636\r
c9727ff1
LE
637 //\r
638 // Enroll KEK.\r
639 //\r
89d7c543
GL
640 if (NoDefault) {\r
641 Status = EnrollListOfCerts (\r
642 EFI_KEY_EXCHANGE_KEY_NAME,\r
643 &gEfiGlobalVariableGuid,\r
644 &gEfiCertX509Guid,\r
645 PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,\r
646 NULL);\r
647 } else {\r
648 Status = EnrollListOfCerts (\r
649 EFI_KEY_EXCHANGE_KEY_NAME,\r
650 &gEfiGlobalVariableGuid,\r
651 &gEfiCertX509Guid,\r
652 PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,\r
653 mMicrosoftKek, mSizeOfMicrosoftKek, &gMicrosoftVendorGuid,\r
654 NULL);\r
655 }\r
b1163623 656 if (EFI_ERROR (Status)) {\r
be9470b3 657 goto FreePkKek1;\r
b1163623
LE
658 }\r
659\r
c9727ff1
LE
660 //\r
661 // Enroll PK, leaving Setup Mode (entering User Mode) at once.\r
662 //\r
b1163623
LE
663 Status = EnrollListOfCerts (\r
664 EFI_PLATFORM_KEY_NAME,\r
665 &gEfiGlobalVariableGuid,\r
666 &gEfiCertX509Guid,\r
be9470b3 667 PkKek1, SizeOfPkKek1, &gEfiGlobalVariableGuid,\r
b1163623
LE
668 NULL);\r
669 if (EFI_ERROR (Status)) {\r
be9470b3 670 goto FreePkKek1;\r
b1163623
LE
671 }\r
672\r
c9727ff1
LE
673 //\r
674 // Leave Custom Mode, so that updates to PK, KEK, db, and dbx require valid\r
675 // signatures.\r
676 //\r
b1163623
LE
677 Settings.CustomMode = STANDARD_SECURE_BOOT_MODE;\r
678 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
679 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
680 sizeof Settings.CustomMode, &Settings.CustomMode);\r
681 if (EFI_ERROR (Status)) {\r
682 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,\r
683 &gEfiCustomModeEnableGuid, Status);\r
be9470b3 684 goto FreePkKek1;\r
b1163623
LE
685 }\r
686\r
c9727ff1
LE
687 //\r
688 // Final sanity check:\r
689 //\r
690 // [SetupMode]\r
691 // (read-only, standardized by UEFI)\r
692 // / \_\r
693 // 0 1, default\r
694 // / \_\r
695 // PK enrolled no PK enrolled yet,\r
696 // (this is called "User Mode") PK enrollment possible\r
697 // |\r
698 // |\r
699 // [SecureBootEnable]\r
700 // (read-write, edk2-specific, boot service only)\r
701 // / \_\r
702 // 0 1, default\r
703 // / \_\r
704 // [SecureBoot]=0 [SecureBoot]=1\r
705 // (read-only, standardized by UEFI) (read-only, standardized by UEFI)\r
706 // images are not verified images are verified, platform is\r
707 // operating in Secure Boot mode\r
708 // |\r
709 // |\r
710 // [CustomMode]\r
711 // (read-write, edk2-specific, boot service only)\r
712 // / \_\r
713 // 0, default 1\r
714 // / \_\r
715 // PK, KEK, db, dbx PK, KEK, db, dbx\r
716 // updates are verified updates are not verified\r
717 //\r
b1163623
LE
718 Status = GetSettings (&Settings);\r
719 if (EFI_ERROR (Status)) {\r
be9470b3 720 goto FreePkKek1;\r
b1163623
LE
721 }\r
722 PrintSettings (&Settings);\r
723\r
724 if (Settings.SetupMode != 0 || Settings.SecureBoot != 1 ||\r
725 Settings.SecureBootEnable != 1 || Settings.CustomMode != 0 ||\r
726 Settings.VendorKeys != 0) {\r
727 AsciiPrint ("error: unexpected\n");\r
be9470b3 728 goto FreePkKek1;\r
b1163623
LE
729 }\r
730\r
731 AsciiPrint ("info: success\n");\r
be9470b3
LE
732 RetVal = 0;\r
733\r
734FreePkKek1:\r
735 FreePool (PkKek1);\r
736\r
737 return RetVal;\r
b1163623 738}\r