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

Commits on Oct 7, 2024

  1. preinstall: Add checks for PCR7

    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.
    chrisccoulson committed Oct 7, 2024
    Configuration menu
    Copy the full SHA
    ba42909 View commit details
    Browse the repository at this point in the history

Commits on Oct 13, 2024

  1. Configuration menu
    Copy the full SHA
    90036c5 View commit details
    Browse the repository at this point in the history
  2. preinstall: Reduce some code duplication

    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 committed Oct 13, 2024
    Configuration menu
    Copy the full SHA
    5e42dd0 View commit details
    Browse the repository at this point in the history

Commits on Oct 15, 2024

  1. Configuration menu
    Copy the full SHA
    942ebac View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    5655f3f View commit details
    Browse the repository at this point in the history

Commits on Nov 12, 2024

  1. preinstall: Refactor the PCR7 checks

    Hopefully this will address any outstanding review comments.
    chrisccoulson committed Nov 12, 2024
    Configuration menu
    Copy the full SHA
    c281620 View commit details
    Browse the repository at this point in the history

Commits on Nov 13, 2024

  1. preinstall: Add CheckResult and WithAutoTCGPCRProfile APIs

    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 committed Nov 13, 2024
    Configuration menu
    Copy the full SHA
    42dfed0 View commit details
    Browse the repository at this point in the history