]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
BaseTools:Fixed an issue where the order of GuidS changed in guid.xref
[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
541\r
542 //\r
543 // Prepare for failure.\r
544 //\r
545 RetVal = 1;\r
b1163623 546\r
c9727ff1
LE
547 //\r
548 // If we're not in Setup Mode, we can't do anything.\r
549 //\r
b1163623
LE
550 Status = GetSettings (&Settings);\r
551 if (EFI_ERROR (Status)) {\r
be9470b3 552 return RetVal;\r
b1163623
LE
553 }\r
554 PrintSettings (&Settings);\r
555\r
556 if (Settings.SetupMode != 1) {\r
557 AsciiPrint ("error: already in User Mode\n");\r
be9470b3
LE
558 return RetVal;\r
559 }\r
560\r
561 //\r
562 // Fetch the X509 certificate (to be used as Platform Key and first Key\r
563 // Exchange Key) from SMBIOS.\r
564 //\r
565 Status = GetPkKek1 (&PkKek1, &SizeOfPkKek1);\r
566 if (EFI_ERROR (Status)) {\r
567 return RetVal;\r
b1163623
LE
568 }\r
569\r
c9727ff1
LE
570 //\r
571 // Enter Custom Mode so we can enroll PK, KEK, db, and dbx without signature\r
572 // checks on those variable writes.\r
573 //\r
b1163623
LE
574 if (Settings.CustomMode != CUSTOM_SECURE_BOOT_MODE) {\r
575 Settings.CustomMode = CUSTOM_SECURE_BOOT_MODE;\r
576 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
577 (EFI_VARIABLE_NON_VOLATILE |\r
578 EFI_VARIABLE_BOOTSERVICE_ACCESS),\r
579 sizeof Settings.CustomMode, &Settings.CustomMode);\r
580 if (EFI_ERROR (Status)) {\r
581 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,\r
582 &gEfiCustomModeEnableGuid, Status);\r
be9470b3 583 goto FreePkKek1;\r
b1163623
LE
584 }\r
585 }\r
586\r
c9727ff1
LE
587 //\r
588 // Enroll db.\r
589 //\r
b1163623
LE
590 Status = EnrollListOfCerts (\r
591 EFI_IMAGE_SECURITY_DATABASE,\r
592 &gEfiImageSecurityDatabaseGuid,\r
593 &gEfiCertX509Guid,\r
7eeaa758
LE
594 mMicrosoftPca, mSizeOfMicrosoftPca, &gMicrosoftVendorGuid,\r
595 mMicrosoftUefiCa, mSizeOfMicrosoftUefiCa, &gMicrosoftVendorGuid,\r
b1163623
LE
596 NULL);\r
597 if (EFI_ERROR (Status)) {\r
be9470b3 598 goto FreePkKek1;\r
b1163623
LE
599 }\r
600\r
c9727ff1
LE
601 //\r
602 // Enroll dbx.\r
603 //\r
b1163623
LE
604 Status = EnrollListOfCerts (\r
605 EFI_IMAGE_SECURITY_DATABASE1,\r
606 &gEfiImageSecurityDatabaseGuid,\r
607 &gEfiCertSha256Guid,\r
a79b115a 608 mSha256OfDevNull, mSizeOfSha256OfDevNull, &gEfiCallerIdGuid,\r
b1163623
LE
609 NULL);\r
610 if (EFI_ERROR (Status)) {\r
be9470b3 611 goto FreePkKek1;\r
b1163623
LE
612 }\r
613\r
c9727ff1
LE
614 //\r
615 // Enroll KEK.\r
616 //\r
b1163623
LE
617 Status = EnrollListOfCerts (\r
618 EFI_KEY_EXCHANGE_KEY_NAME,\r
619 &gEfiGlobalVariableGuid,\r
620 &gEfiCertX509Guid,\r
be9470b3 621 PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,\r
7eeaa758 622 mMicrosoftKek, mSizeOfMicrosoftKek, &gMicrosoftVendorGuid,\r
b1163623
LE
623 NULL);\r
624 if (EFI_ERROR (Status)) {\r
be9470b3 625 goto FreePkKek1;\r
b1163623
LE
626 }\r
627\r
c9727ff1
LE
628 //\r
629 // Enroll PK, leaving Setup Mode (entering User Mode) at once.\r
630 //\r
b1163623
LE
631 Status = EnrollListOfCerts (\r
632 EFI_PLATFORM_KEY_NAME,\r
633 &gEfiGlobalVariableGuid,\r
634 &gEfiCertX509Guid,\r
be9470b3 635 PkKek1, SizeOfPkKek1, &gEfiGlobalVariableGuid,\r
b1163623
LE
636 NULL);\r
637 if (EFI_ERROR (Status)) {\r
be9470b3 638 goto FreePkKek1;\r
b1163623
LE
639 }\r
640\r
c9727ff1
LE
641 //\r
642 // Leave Custom Mode, so that updates to PK, KEK, db, and dbx require valid\r
643 // signatures.\r
644 //\r
b1163623
LE
645 Settings.CustomMode = STANDARD_SECURE_BOOT_MODE;\r
646 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
647 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
648 sizeof Settings.CustomMode, &Settings.CustomMode);\r
649 if (EFI_ERROR (Status)) {\r
650 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,\r
651 &gEfiCustomModeEnableGuid, Status);\r
be9470b3 652 goto FreePkKek1;\r
b1163623
LE
653 }\r
654\r
c9727ff1
LE
655 //\r
656 // Final sanity check:\r
657 //\r
658 // [SetupMode]\r
659 // (read-only, standardized by UEFI)\r
660 // / \_\r
661 // 0 1, default\r
662 // / \_\r
663 // PK enrolled no PK enrolled yet,\r
664 // (this is called "User Mode") PK enrollment possible\r
665 // |\r
666 // |\r
667 // [SecureBootEnable]\r
668 // (read-write, edk2-specific, boot service only)\r
669 // / \_\r
670 // 0 1, default\r
671 // / \_\r
672 // [SecureBoot]=0 [SecureBoot]=1\r
673 // (read-only, standardized by UEFI) (read-only, standardized by UEFI)\r
674 // images are not verified images are verified, platform is\r
675 // operating in Secure Boot mode\r
676 // |\r
677 // |\r
678 // [CustomMode]\r
679 // (read-write, edk2-specific, boot service only)\r
680 // / \_\r
681 // 0, default 1\r
682 // / \_\r
683 // PK, KEK, db, dbx PK, KEK, db, dbx\r
684 // updates are verified updates are not verified\r
685 //\r
b1163623
LE
686 Status = GetSettings (&Settings);\r
687 if (EFI_ERROR (Status)) {\r
be9470b3 688 goto FreePkKek1;\r
b1163623
LE
689 }\r
690 PrintSettings (&Settings);\r
691\r
692 if (Settings.SetupMode != 0 || Settings.SecureBoot != 1 ||\r
693 Settings.SecureBootEnable != 1 || Settings.CustomMode != 0 ||\r
694 Settings.VendorKeys != 0) {\r
695 AsciiPrint ("error: unexpected\n");\r
be9470b3 696 goto FreePkKek1;\r
b1163623
LE
697 }\r
698\r
699 AsciiPrint ("info: success\n");\r
be9470b3
LE
700 RetVal = 0;\r
701\r
702FreePkKek1:\r
703 FreePool (PkKek1);\r
704\r
705 return RetVal;\r
b1163623 706}\r