2 Enroll default PK, KEK, db, dbx.
4 Copyright (C) 2014-2019, Red Hat, Inc.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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
19 #include "EnrollDefaultKeys.h"
23 Enroll a set of certificates in a global variable, overwriting it.
25 The variable will be rewritten with NV+BS+RT+AT attributes.
27 @param[in] VariableName The name of the variable to overwrite.
29 @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable to
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.
38 @param[in] ... A list of
42 IN CONST EFI_GUID *OwnerGuid
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.
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.
56 @retval EFI_OUT_OF_RESOURCES Out of memory while formatting variable
59 @retval EFI_SUCCESS Enrollment successful; the variable has been
60 overwritten (or created).
62 @return Error codes from gRT->GetTime() and
69 IN CHAR16
*VariableName
,
70 IN EFI_GUID
*VendorGuid
,
71 IN EFI_GUID
*CertType
,
76 SINGLE_HEADER
*SingleHeader
;
77 REPEATING_HEADER
*RepeatingHeader
;
87 // compute total size first, for UINT32 range check, and allocation
89 DataSize
= sizeof *SingleHeader
;
90 VA_START (Marker
, CertType
);
91 for (Cert
= VA_ARG (Marker
, CONST UINT8
*);
93 Cert
= VA_ARG (Marker
, CONST UINT8
*)) {
96 CertSize
= VA_ARG (Marker
, UINTN
);
97 (VOID
)VA_ARG (Marker
, CONST EFI_GUID
*);
100 CertSize
> MAX_UINT32
- sizeof *RepeatingHeader
||
101 DataSize
> MAX_UINT32
- sizeof *RepeatingHeader
- CertSize
) {
102 Status
= EFI_INVALID_PARAMETER
;
105 DataSize
+= sizeof *RepeatingHeader
+ CertSize
;
109 if (DataSize
== sizeof *SingleHeader
) {
110 Status
= EFI_INVALID_PARAMETER
;
112 if (EFI_ERROR (Status
)) {
116 Data
= AllocatePool (DataSize
);
118 Status
= EFI_OUT_OF_RESOURCES
;
124 SingleHeader
= (SINGLE_HEADER
*)Position
;
125 Status
= gRT
->GetTime (&SingleHeader
->TimeStamp
, NULL
);
126 if (EFI_ERROR (Status
)) {
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;
135 SingleHeader
->dwLength
= DataSize
- sizeof SingleHeader
->TimeStamp
;
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.
143 SingleHeader
->dwLength
= sizeof *SingleHeader
144 - sizeof SingleHeader
->TimeStamp
;
146 SingleHeader
->wRevision
= 0x0200;
147 SingleHeader
->wCertificateType
= WIN_CERT_TYPE_EFI_GUID
;
148 CopyGuid (&SingleHeader
->CertType
, &gEfiCertPkcs7Guid
);
149 Position
+= sizeof *SingleHeader
;
151 VA_START (Marker
, CertType
);
152 for (Cert
= VA_ARG (Marker
, CONST UINT8
*);
154 Cert
= VA_ARG (Marker
, CONST UINT8
*)) {
156 CONST EFI_GUID
*OwnerGuid
;
158 CertSize
= VA_ARG (Marker
, UINTN
);
159 OwnerGuid
= VA_ARG (Marker
, CONST EFI_GUID
*);
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
;
171 CopyMem (Position
, Cert
, CertSize
);
172 Position
+= CertSize
;
176 ASSERT (Data
+ DataSize
== Position
);
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
),
189 if (EFI_ERROR (Status
)) {
190 AsciiPrint ("error: %a(\"%s\", %g): %r\n", __FUNCTION__
, VariableName
,
198 Read a UEFI variable into a caller-allocated buffer, enforcing an exact size.
200 @param[in] VariableName The name of the variable to read; passed to
203 @param[in] VendorGuid The vendor (namespace) GUID of the variable to read;
204 passed to gRT->GetVariable().
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.
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.
214 @param[in] AllowMissing If FALSE, the variable is required to exist. If
215 TRUE, the variable is permitted to be missing.
217 @retval EFI_SUCCESS The UEFI variable exists, has the required size
218 (DataSize), and has been read into Data.
220 @retval EFI_SUCCESS The UEFI variable doesn't exist, and
221 AllowMissing is TRUE. DataSize bytes in Data
222 have been zeroed out.
224 @retval EFI_NOT_FOUND The UEFI variable doesn't exist, and
225 AllowMissing is FALSE.
227 @retval EFI_BUFFER_TOO_SMALL The UEFI variable exists, but its size is
228 greater than DataSize.
230 @retval EFI_PROTOCOL_ERROR The UEFI variable exists, but its size is
231 smaller than DataSize.
233 @return Error codes propagated from gRT->GetVariable().
238 IN CHAR16
*VariableName
,
239 IN EFI_GUID
*VendorGuid
,
242 IN BOOLEAN AllowMissing
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
);
256 AsciiPrint ("error: GetVariable(\"%s\", %g): %r\n", VariableName
,
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
;
272 Populate a SETTINGS structure from the underlying UEFI variables.
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)
279 The following UEFI variables are edk2 extensions:
280 - L"SecureBootEnable" (EFI_SECURE_BOOT_ENABLE_NAME)
281 - L"CustomMode" (EFI_CUSTOM_MODE_NAME)
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
288 @param[out] Settings The SETTINGS object to fill.
290 @retval EFI_SUCCESS Settings has been populated.
292 @return Error codes propagated from the GetExact() function. The
293 contents of Settings are indeterminate.
298 OUT SETTINGS
*Settings
303 Status
= GetExact (EFI_SETUP_MODE_NAME
, &gEfiGlobalVariableGuid
,
304 &Settings
->SetupMode
, sizeof Settings
->SetupMode
, FALSE
);
305 if (EFI_ERROR (Status
)) {
309 Status
= GetExact (EFI_SECURE_BOOT_MODE_NAME
, &gEfiGlobalVariableGuid
,
310 &Settings
->SecureBoot
, sizeof Settings
->SecureBoot
, FALSE
);
311 if (EFI_ERROR (Status
)) {
315 Status
= GetExact (EFI_SECURE_BOOT_ENABLE_NAME
,
316 &gEfiSecureBootEnableDisableGuid
, &Settings
->SecureBootEnable
,
317 sizeof Settings
->SecureBootEnable
, TRUE
);
318 if (EFI_ERROR (Status
)) {
322 Status
= GetExact (EFI_CUSTOM_MODE_NAME
, &gEfiCustomModeEnableGuid
,
323 &Settings
->CustomMode
, sizeof Settings
->CustomMode
, FALSE
);
324 if (EFI_ERROR (Status
)) {
328 Status
= GetExact (EFI_VENDOR_KEYS_VARIABLE_NAME
, &gEfiGlobalVariableGuid
,
329 &Settings
->VendorKeys
, sizeof Settings
->VendorKeys
, FALSE
);
335 Print the contents of a SETTINGS structure to the UEFI console.
337 @param[in] Settings The SETTINGS object to print the contents of.
342 IN CONST SETTINGS
*Settings
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
);
352 Entry point function of this shell application.
365 // If we're not in Setup Mode, we can't do anything.
367 Status
= GetSettings (&Settings
);
368 if (EFI_ERROR (Status
)) {
371 PrintSettings (&Settings
);
373 if (Settings
.SetupMode
!= 1) {
374 AsciiPrint ("error: already in User Mode\n");
379 // Enter Custom Mode so we can enroll PK, KEK, db, and dbx without signature
380 // checks on those variable writes.
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
);
398 Status
= EnrollListOfCerts (
399 EFI_IMAGE_SECURITY_DATABASE
,
400 &gEfiImageSecurityDatabaseGuid
,
402 mMicrosoftPca
, mSizeOfMicrosoftPca
, &gMicrosoftVendorGuid
,
403 mMicrosoftUefiCa
, mSizeOfMicrosoftUefiCa
, &gMicrosoftVendorGuid
,
405 if (EFI_ERROR (Status
)) {
412 Status
= EnrollListOfCerts (
413 EFI_IMAGE_SECURITY_DATABASE1
,
414 &gEfiImageSecurityDatabaseGuid
,
416 mSha256OfDevNull
, mSizeOfSha256OfDevNull
, &gEfiCallerIdGuid
,
418 if (EFI_ERROR (Status
)) {
425 Status
= EnrollListOfCerts (
426 EFI_KEY_EXCHANGE_KEY_NAME
,
427 &gEfiGlobalVariableGuid
,
429 mRedHatPkKek1
, mSizeOfRedHatPkKek1
, &gEfiCallerIdGuid
,
430 mMicrosoftKek
, mSizeOfMicrosoftKek
, &gMicrosoftVendorGuid
,
432 if (EFI_ERROR (Status
)) {
437 // Enroll PK, leaving Setup Mode (entering User Mode) at once.
439 Status
= EnrollListOfCerts (
440 EFI_PLATFORM_KEY_NAME
,
441 &gEfiGlobalVariableGuid
,
443 mRedHatPkKek1
, mSizeOfRedHatPkKek1
, &gEfiGlobalVariableGuid
,
445 if (EFI_ERROR (Status
)) {
450 // Leave Custom Mode, so that updates to PK, KEK, db, and dbx require valid
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
);
464 // Final sanity check:
467 // (read-only, standardized by UEFI)
471 // PK enrolled no PK enrolled yet,
472 // (this is called "User Mode") PK enrollment possible
475 // [SecureBootEnable]
476 // (read-write, edk2-specific, boot service only)
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
487 // (read-write, edk2-specific, boot service only)
491 // PK, KEK, db, dbx PK, KEK, db, dbx
492 // updates are verified updates are not verified
494 Status
= GetSettings (&Settings
);
495 if (EFI_ERROR (Status
)) {
498 PrintSettings (&Settings
);
500 if (Settings
.SetupMode
!= 0 || Settings
.SecureBoot
!= 1 ||
501 Settings
.SecureBootEnable
!= 1 || Settings
.CustomMode
!= 0 ||
502 Settings
.VendorKeys
!= 0) {
503 AsciiPrint ("error: unexpected\n");
507 AsciiPrint ("info: success\n");