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