]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
OvmfPkg/EnrollDefaultKeys: describe functions with leading comment blocks
[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
b1163623
LE
12#include <Library/BaseMemoryLib.h> // CopyGuid()\r
13#include <Library/DebugLib.h> // ASSERT()\r
14#include <Library/MemoryAllocationLib.h> // FreePool()\r
15#include <Library/ShellCEntryLib.h> // ShellAppMain()\r
16#include <Library/UefiLib.h> // AsciiPrint()\r
17#include <Library/UefiRuntimeServicesTableLib.h> // gRT\r
18\r
1c9418fc
LE
19#include "EnrollDefaultKeys.h"\r
20\r
86bf2672 21\r
b1163623
LE
22/**\r
23 Enroll a set of certificates in a global variable, overwriting it.\r
24\r
25 The variable will be rewritten with NV+BS+RT+AT attributes.\r
26\r
27 @param[in] VariableName The name of the variable to overwrite.\r
28\r
29 @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable to\r
30 overwrite.\r
31\r
32 @param[in] CertType The GUID determining the type of all the\r
33 certificates in the set that is passed in. For\r
34 example, gEfiCertX509Guid stands for DER-encoded\r
35 X.509 certificates, while gEfiCertSha256Guid stands\r
36 for SHA256 image hashes.\r
37\r
38 @param[in] ... A list of\r
39\r
40 IN CONST UINT8 *Cert,\r
41 IN UINTN CertSize,\r
42 IN CONST EFI_GUID *OwnerGuid\r
43\r
44 triplets. If the first component of a triplet is\r
45 NULL, then the other two components are not\r
46 accessed, and processing is terminated. The list of\r
47 certificates is enrolled in the variable specified,\r
48 overwriting it. The OwnerGuid component identifies\r
49 the agent installing the certificate.\r
50\r
51 @retval EFI_INVALID_PARAMETER The triplet list is empty (ie. the first Cert\r
52 value is NULL), or one of the CertSize values\r
53 is 0, or one of the CertSize values would\r
54 overflow the accumulated UINT32 data size.\r
55\r
56 @retval EFI_OUT_OF_RESOURCES Out of memory while formatting variable\r
57 payload.\r
58\r
59 @retval EFI_SUCCESS Enrollment successful; the variable has been\r
60 overwritten (or created).\r
61\r
62 @return Error codes from gRT->GetTime() and\r
63 gRT->SetVariable().\r
64**/\r
65STATIC\r
66EFI_STATUS\r
67EFIAPI\r
68EnrollListOfCerts (\r
69 IN CHAR16 *VariableName,\r
70 IN EFI_GUID *VendorGuid,\r
71 IN EFI_GUID *CertType,\r
72 ...\r
73 )\r
74{\r
75 UINTN DataSize;\r
76 SINGLE_HEADER *SingleHeader;\r
77 REPEATING_HEADER *RepeatingHeader;\r
78 VA_LIST Marker;\r
79 CONST UINT8 *Cert;\r
80 EFI_STATUS Status;\r
81 UINT8 *Data;\r
82 UINT8 *Position;\r
83\r
84 Status = EFI_SUCCESS;\r
85\r
86 //\r
87 // compute total size first, for UINT32 range check, and allocation\r
88 //\r
89 DataSize = sizeof *SingleHeader;\r
90 VA_START (Marker, CertType);\r
91 for (Cert = VA_ARG (Marker, CONST UINT8 *);\r
92 Cert != NULL;\r
93 Cert = VA_ARG (Marker, CONST UINT8 *)) {\r
94 UINTN CertSize;\r
95\r
96 CertSize = VA_ARG (Marker, UINTN);\r
97 (VOID)VA_ARG (Marker, CONST EFI_GUID *);\r
98\r
99 if (CertSize == 0 ||\r
100 CertSize > MAX_UINT32 - sizeof *RepeatingHeader ||\r
101 DataSize > MAX_UINT32 - sizeof *RepeatingHeader - CertSize) {\r
102 Status = EFI_INVALID_PARAMETER;\r
103 break;\r
104 }\r
105 DataSize += sizeof *RepeatingHeader + CertSize;\r
106 }\r
107 VA_END (Marker);\r
108\r
109 if (DataSize == sizeof *SingleHeader) {\r
110 Status = EFI_INVALID_PARAMETER;\r
111 }\r
112 if (EFI_ERROR (Status)) {\r
113 goto Out;\r
114 }\r
115\r
116 Data = AllocatePool (DataSize);\r
117 if (Data == NULL) {\r
118 Status = EFI_OUT_OF_RESOURCES;\r
119 goto Out;\r
120 }\r
121\r
122 Position = Data;\r
123\r
124 SingleHeader = (SINGLE_HEADER *)Position;\r
125 Status = gRT->GetTime (&SingleHeader->TimeStamp, NULL);\r
126 if (EFI_ERROR (Status)) {\r
127 goto FreeData;\r
128 }\r
129 SingleHeader->TimeStamp.Pad1 = 0;\r
130 SingleHeader->TimeStamp.Nanosecond = 0;\r
131 SingleHeader->TimeStamp.TimeZone = 0;\r
132 SingleHeader->TimeStamp.Daylight = 0;\r
133 SingleHeader->TimeStamp.Pad2 = 0;\r
134#if 0\r
135 SingleHeader->dwLength = DataSize - sizeof SingleHeader->TimeStamp;\r
136#else\r
137 //\r
138 // This looks like a bug in edk2. According to the UEFI specification,\r
139 // dwLength is "The length of the entire certificate, including the length of\r
140 // the header, in bytes". That shouldn't stop right after CertType -- it\r
141 // should include everything below it.\r
142 //\r
143 SingleHeader->dwLength = sizeof *SingleHeader\r
144 - sizeof SingleHeader->TimeStamp;\r
145#endif\r
146 SingleHeader->wRevision = 0x0200;\r
147 SingleHeader->wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
148 CopyGuid (&SingleHeader->CertType, &gEfiCertPkcs7Guid);\r
149 Position += sizeof *SingleHeader;\r
150\r
151 VA_START (Marker, CertType);\r
152 for (Cert = VA_ARG (Marker, CONST UINT8 *);\r
153 Cert != NULL;\r
154 Cert = VA_ARG (Marker, CONST UINT8 *)) {\r
155 UINTN CertSize;\r
156 CONST EFI_GUID *OwnerGuid;\r
157\r
158 CertSize = VA_ARG (Marker, UINTN);\r
159 OwnerGuid = VA_ARG (Marker, CONST EFI_GUID *);\r
160\r
161 RepeatingHeader = (REPEATING_HEADER *)Position;\r
162 CopyGuid (&RepeatingHeader->SignatureType, CertType);\r
163 RepeatingHeader->SignatureListSize =\r
164 (UINT32)(sizeof *RepeatingHeader + CertSize);\r
165 RepeatingHeader->SignatureHeaderSize = 0;\r
166 RepeatingHeader->SignatureSize =\r
167 (UINT32)(sizeof RepeatingHeader->SignatureOwner + CertSize);\r
168 CopyGuid (&RepeatingHeader->SignatureOwner, OwnerGuid);\r
169 Position += sizeof *RepeatingHeader;\r
170\r
171 CopyMem (Position, Cert, CertSize);\r
172 Position += CertSize;\r
173 }\r
174 VA_END (Marker);\r
175\r
176 ASSERT (Data + DataSize == Position);\r
177\r
178 Status = gRT->SetVariable (VariableName, VendorGuid,\r
179 (EFI_VARIABLE_NON_VOLATILE |\r
180 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
181 EFI_VARIABLE_RUNTIME_ACCESS |\r
182 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),\r
183 DataSize, Data);\r
184\r
185FreeData:\r
186 FreePool (Data);\r
187\r
188Out:\r
189 if (EFI_ERROR (Status)) {\r
190 AsciiPrint ("error: %a(\"%s\", %g): %r\n", __FUNCTION__, VariableName,\r
191 VendorGuid, Status);\r
192 }\r
193 return Status;\r
194}\r
195\r
196\r
86bf2672
LE
197/**\r
198 Read a UEFI variable into a caller-allocated buffer, enforcing an exact size.\r
199\r
200 @param[in] VariableName The name of the variable to read; passed to\r
201 gRT->GetVariable().\r
202\r
203 @param[in] VendorGuid The vendor (namespace) GUID of the variable to read;\r
204 passed to gRT->GetVariable().\r
205\r
206 @param[out] Data The caller-allocated buffer that is supposed to\r
207 receive the variable's contents. On error, the\r
208 contents of Data are indeterminate.\r
209\r
210 @param[in] DataSize The size in bytes that the caller requires the UEFI\r
211 variable to have. The caller is responsible for\r
212 providing room for DataSize bytes in Data.\r
213\r
214 @param[in] AllowMissing If FALSE, the variable is required to exist. If\r
215 TRUE, the variable is permitted to be missing.\r
216\r
217 @retval EFI_SUCCESS The UEFI variable exists, has the required size\r
218 (DataSize), and has been read into Data.\r
219\r
220 @retval EFI_SUCCESS The UEFI variable doesn't exist, and\r
221 AllowMissing is TRUE. DataSize bytes in Data\r
222 have been zeroed out.\r
223\r
224 @retval EFI_NOT_FOUND The UEFI variable doesn't exist, and\r
225 AllowMissing is FALSE.\r
226\r
227 @retval EFI_BUFFER_TOO_SMALL The UEFI variable exists, but its size is\r
228 greater than DataSize.\r
229\r
230 @retval EFI_PROTOCOL_ERROR The UEFI variable exists, but its size is\r
231 smaller than DataSize.\r
232\r
233 @return Error codes propagated from gRT->GetVariable().\r
234**/\r
b1163623
LE
235STATIC\r
236EFI_STATUS\r
b1163623
LE
237GetExact (\r
238 IN CHAR16 *VariableName,\r
239 IN EFI_GUID *VendorGuid,\r
240 OUT VOID *Data,\r
241 IN UINTN DataSize,\r
242 IN BOOLEAN AllowMissing\r
243 )\r
244{\r
245 UINTN Size;\r
246 EFI_STATUS Status;\r
247\r
248 Size = DataSize;\r
249 Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &Size, Data);\r
250 if (EFI_ERROR (Status)) {\r
251 if (Status == EFI_NOT_FOUND && AllowMissing) {\r
252 ZeroMem (Data, DataSize);\r
253 return EFI_SUCCESS;\r
254 }\r
255\r
256 AsciiPrint ("error: GetVariable(\"%s\", %g): %r\n", VariableName,\r
257 VendorGuid, Status);\r
258 return Status;\r
259 }\r
260\r
261 if (Size != DataSize) {\r
262 AsciiPrint ("error: GetVariable(\"%s\", %g): expected size 0x%Lx, "\r
263 "got 0x%Lx\n", VariableName, VendorGuid, (UINT64)DataSize, (UINT64)Size);\r
264 return EFI_PROTOCOL_ERROR;\r
265 }\r
266\r
267 return EFI_SUCCESS;\r
268}\r
269\r
86bf2672
LE
270\r
271/**\r
272 Populate a SETTINGS structure from the underlying UEFI variables.\r
273\r
274 The following UEFI variables are standard variables:\r
275 - L"SetupMode" (EFI_SETUP_MODE_NAME)\r
276 - L"SecureBoot" (EFI_SECURE_BOOT_MODE_NAME)\r
277 - L"VendorKeys" (EFI_VENDOR_KEYS_VARIABLE_NAME)\r
278\r
279 The following UEFI variables are edk2 extensions:\r
280 - L"SecureBootEnable" (EFI_SECURE_BOOT_ENABLE_NAME)\r
281 - L"CustomMode" (EFI_CUSTOM_MODE_NAME)\r
282\r
283 The L"SecureBootEnable" UEFI variable is permitted to be missing, in which\r
284 case the corresponding field in the SETTINGS object will be zeroed out. The\r
285 rest of the covered UEFI variables are required to exist; otherwise, the\r
286 function will fail.\r
287\r
288 @param[out] Settings The SETTINGS object to fill.\r
289\r
290 @retval EFI_SUCCESS Settings has been populated.\r
291\r
292 @return Error codes propagated from the GetExact() function. The\r
293 contents of Settings are indeterminate.\r
294**/\r
b1163623
LE
295STATIC\r
296EFI_STATUS\r
b1163623
LE
297GetSettings (\r
298 OUT SETTINGS *Settings\r
299 )\r
300{\r
301 EFI_STATUS Status;\r
302\r
303 Status = GetExact (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid,\r
304 &Settings->SetupMode, sizeof Settings->SetupMode, FALSE);\r
305 if (EFI_ERROR (Status)) {\r
306 return Status;\r
307 }\r
308\r
309 Status = GetExact (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid,\r
310 &Settings->SecureBoot, sizeof Settings->SecureBoot, FALSE);\r
311 if (EFI_ERROR (Status)) {\r
312 return Status;\r
313 }\r
314\r
315 Status = GetExact (EFI_SECURE_BOOT_ENABLE_NAME,\r
316 &gEfiSecureBootEnableDisableGuid, &Settings->SecureBootEnable,\r
317 sizeof Settings->SecureBootEnable, TRUE);\r
318 if (EFI_ERROR (Status)) {\r
319 return Status;\r
320 }\r
321\r
322 Status = GetExact (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
323 &Settings->CustomMode, sizeof Settings->CustomMode, FALSE);\r
324 if (EFI_ERROR (Status)) {\r
325 return Status;\r
326 }\r
327\r
328 Status = GetExact (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid,\r
329 &Settings->VendorKeys, sizeof Settings->VendorKeys, FALSE);\r
330 return Status;\r
331}\r
332\r
86bf2672
LE
333\r
334/**\r
335 Print the contents of a SETTINGS structure to the UEFI console.\r
336\r
337 @param[in] Settings The SETTINGS object to print the contents of.\r
338**/\r
b1163623
LE
339STATIC\r
340VOID\r
b1163623
LE
341PrintSettings (\r
342 IN CONST SETTINGS *Settings\r
343 )\r
344{\r
345 AsciiPrint ("info: SetupMode=%d SecureBoot=%d SecureBootEnable=%d "\r
346 "CustomMode=%d VendorKeys=%d\n", Settings->SetupMode, Settings->SecureBoot,\r
347 Settings->SecureBootEnable, Settings->CustomMode, Settings->VendorKeys);\r
348}\r
349\r
350\r
86bf2672
LE
351/**\r
352 Entry point function of this shell application.\r
353**/\r
b1163623
LE
354INTN\r
355EFIAPI\r
356ShellAppMain (\r
357 IN UINTN Argc,\r
358 IN CHAR16 **Argv\r
359 )\r
360{\r
361 EFI_STATUS Status;\r
362 SETTINGS Settings;\r
363\r
364 Status = GetSettings (&Settings);\r
365 if (EFI_ERROR (Status)) {\r
366 return 1;\r
367 }\r
368 PrintSettings (&Settings);\r
369\r
370 if (Settings.SetupMode != 1) {\r
371 AsciiPrint ("error: already in User Mode\n");\r
372 return 1;\r
373 }\r
374\r
375 if (Settings.CustomMode != CUSTOM_SECURE_BOOT_MODE) {\r
376 Settings.CustomMode = CUSTOM_SECURE_BOOT_MODE;\r
377 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
378 (EFI_VARIABLE_NON_VOLATILE |\r
379 EFI_VARIABLE_BOOTSERVICE_ACCESS),\r
380 sizeof Settings.CustomMode, &Settings.CustomMode);\r
381 if (EFI_ERROR (Status)) {\r
382 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,\r
383 &gEfiCustomModeEnableGuid, Status);\r
384 return 1;\r
385 }\r
386 }\r
387\r
388 Status = EnrollListOfCerts (\r
389 EFI_IMAGE_SECURITY_DATABASE,\r
390 &gEfiImageSecurityDatabaseGuid,\r
391 &gEfiCertX509Guid,\r
7eeaa758
LE
392 mMicrosoftPca, mSizeOfMicrosoftPca, &gMicrosoftVendorGuid,\r
393 mMicrosoftUefiCa, mSizeOfMicrosoftUefiCa, &gMicrosoftVendorGuid,\r
b1163623
LE
394 NULL);\r
395 if (EFI_ERROR (Status)) {\r
396 return 1;\r
397 }\r
398\r
399 Status = EnrollListOfCerts (\r
400 EFI_IMAGE_SECURITY_DATABASE1,\r
401 &gEfiImageSecurityDatabaseGuid,\r
402 &gEfiCertSha256Guid,\r
a79b115a 403 mSha256OfDevNull, mSizeOfSha256OfDevNull, &gEfiCallerIdGuid,\r
b1163623
LE
404 NULL);\r
405 if (EFI_ERROR (Status)) {\r
406 return 1;\r
407 }\r
408\r
409 Status = EnrollListOfCerts (\r
410 EFI_KEY_EXCHANGE_KEY_NAME,\r
411 &gEfiGlobalVariableGuid,\r
412 &gEfiCertX509Guid,\r
a79b115a 413 mRedHatPkKek1, mSizeOfRedHatPkKek1, &gEfiCallerIdGuid,\r
7eeaa758 414 mMicrosoftKek, mSizeOfMicrosoftKek, &gMicrosoftVendorGuid,\r
b1163623
LE
415 NULL);\r
416 if (EFI_ERROR (Status)) {\r
417 return 1;\r
418 }\r
419\r
420 Status = EnrollListOfCerts (\r
421 EFI_PLATFORM_KEY_NAME,\r
422 &gEfiGlobalVariableGuid,\r
423 &gEfiCertX509Guid,\r
a79b115a 424 mRedHatPkKek1, mSizeOfRedHatPkKek1, &gEfiGlobalVariableGuid,\r
b1163623
LE
425 NULL);\r
426 if (EFI_ERROR (Status)) {\r
427 return 1;\r
428 }\r
429\r
430 Settings.CustomMode = STANDARD_SECURE_BOOT_MODE;\r
431 Status = gRT->SetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,\r
432 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
433 sizeof Settings.CustomMode, &Settings.CustomMode);\r
434 if (EFI_ERROR (Status)) {\r
435 AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,\r
436 &gEfiCustomModeEnableGuid, Status);\r
437 return 1;\r
438 }\r
439\r
440 Status = GetSettings (&Settings);\r
441 if (EFI_ERROR (Status)) {\r
442 return 1;\r
443 }\r
444 PrintSettings (&Settings);\r
445\r
446 if (Settings.SetupMode != 0 || Settings.SecureBoot != 1 ||\r
447 Settings.SecureBootEnable != 1 || Settings.CustomMode != 0 ||\r
448 Settings.VendorKeys != 0) {\r
449 AsciiPrint ("error: unexpected\n");\r
450 return 1;\r
451 }\r
452\r
453 AsciiPrint ("info: success\n");\r
454 return 0;\r
455}\r