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