Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

preinstall: Add CheckResult and WithAutoPCRProfile APIs #338

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

chrisccoulson
Copy link
Collaborator

(Draft until #337 has landed)

@chrisccoulson chrisccoulson force-pushed the preinstall-add-profile-and-results branch 2 times, most recently from 33a77f7 to 27fef9d Compare October 4, 2024 19:44
This adds some checks for PCR7.

The caller supplies a context.Context to which an EFI variable backend
is attached, a internal_efi.HostEnvironment implementation, a TCG log, a
PCR digest algorith (the optimum for this is computed earlier by
another function that does a more general check of the TCG log) and the
image of the initial boot loader for the current boot.

As we're testing the firmware, this only checks the log up to the launch
of the initial boot loader. It ignores events after this, as these are
under the control of the OS and don't rely on any special firmware
features such as EFI_TCG2_PROTOCOL + PE_COFF_IMAGE vs EFI_TCG_PROTOCOL
in the same way that OS components measuring to PCR4 do.

This ensures that secure boot is enabled, else an error is returned, as
WithSecureBootPolicyProfile only generates profiles compatible with
secure boot being enabled.

If the version of UEFI is >= 2.5, it also makes sure that the secure
boot mode is "deployed mode". If the secure boot mode is "user mode",
then the "AuditMode" and "DeployedMode" values are measured to PCR7,
something that WithSecureBootPolicyProfile doesn't support today.
Support for "user mode" will be added in the future, although the public
RunChecks API will probably require a flag to opt in to supporting user
mode, as it is the less secure mode of the 2 (see the documentation for
SecureBootMode in github.com/canonical/go-efilib).

It also reads the "OsIndicationsSupported" variable to test for features
that are not supported by WithSecureBootPolicyProfile. These are
timestamp revocation (which requires an extra signature database -
"dbt") and OS recovery (which requires an extra signature database -
"dbr", used to control access to OsRecoveryOrder and OsRecover####
variables). Of the 2, it's likely that we might need to add support for
timestamp revocation at some point.

It reads the "BootCurrent" EFI variable and matches this to the
EFI_LOAD_OPTION associated with the current boot from the TCG log - it
uses the log as "BootXXXX" EFI variables can be updated at runtime and
might be out of data when this code runs. It uses this to detect the
launch of the initial boot loader, which might not necessarily be the
first EV_EFI_BOOT_SERVICES_APPLICATION event in the OS-present
environment in PCR4 (eg, if Absolute is active).

First of all, it iterates over the secure boot configuration in the log,
making sure that the configuration is measured in the correct order,
that the event data is valid, and that the measured digest is the tagged
hash of the event data. It makes sure that the value of "SecureBoot" in
the log is consistent with the "SecureBoot" variable (which is read-only
at runtime), and it verifies that all of the signature databases are
formatted correctly. It will return an error if any of these checks
fail.

If the pre-OS environment contains events other than
EV_EFI_VARIABLE_DRIVER_CONFIG, it will return an error. This can happen
if a firmware debugger is enabled, in which case PCR7 will begin with a
EV_EFI_ACTION "UEFI Debug Mode" event. This case is detected by earlier
firmware protection checks.

If not all of the expected secure boot configuration is measured, an
error is returned.

Once the secure boot configuration has been measured, it looks for
EV_EFI_VARIABLE_AUTHORITY events in PCR7, until it detects the launch of
the initial boot loader. It verifies that each of these come from db,
and if the log is in the OS-present environment, it ensures that the
measured digest is the tagged hash of the event data. It doesn't do this
for events in the pre-OS environment because WithSecureBootPolicyProfile
just copies these to the profile. It verifies that the firmware doesn't
measure a signature more than once. For each EV_EFI_VARIABLE_AUTHORITY
event, it also matches the measured signature to a EFI_SIGNATURE_LIST
structure in db. If the matched ESL is a X.509 certificate, it records
the use of this CA in the return value. If the CA is an RSA certificate
with a public modulus of <= 1024 bits, it sets a flag in the return
value indicating a weak algorithm. If the matched ESL is a Authenticode
digest, it sets a flag in the return value indicating that pre-OS
components were verified using digests rather than signatures. This
makes PCR7 fragile wrt firmware updates, because it means db needs to
be updated to reflect the new components each time. If the digest being
matched is SHA-1, it sets the flag in the return value indicating a weak
algorithm. If any of these checks fail, an error is returned. If an
event type other than EV_EFI_VARIABLE_AUTHORITY is detected, an error is
returned.

Upon detecting the launch of the initial boot loader in PCR4, it
extracts the authenticode signatures from the supplied image, and
matches these to a previously measured CA. If no match is found, an
error is returned. If a match is found, it ensures that the signing
certificate has an RSA public key with a modulus larger than 1024 bits,
else it sets a flag in the return value indicating a weak algorithm.
Once the event for the initial boot loader is complete, the function
returns.

If the end of the log is reached without encountering the launch of the
initial boot loader, an error is returned.
This moves the code to read the current boot load option from the log
into a helper function, as the same code was used both in the PCR4 and
PCR7 checks.
@chrisccoulson chrisccoulson force-pushed the preinstall-add-profile-and-results branch 5 times, most recently from 0bec84e to 878ee98 Compare October 17, 2024 10:11
Hopefully this will address any outstanding review comments.
@chrisccoulson chrisccoulson force-pushed the preinstall-add-profile-and-results branch from 878ee98 to 5b74975 Compare November 12, 2024 23:47
CheckResult is returned from RunChecks on successful completion. It is
JSON serializable and intended to be supplied later on to
WithAutoTCGPCRProfile along with some user customization flags (defined
by PCRProfileOptionsFlags) in order to generate an option that can be
supplied to secboot_efi.AddPCRProfile.

Note that some user options don't work yet because of missing PCR
support, although these limitations will be addressed later. Even so,
some options may still fail depending on the CheckResult flags.
@chrisccoulson chrisccoulson force-pushed the preinstall-add-profile-and-results branch from 5b74975 to 42dfed0 Compare November 13, 2024 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant