Bug 1010477

Summary: Using own certificates/keys with SecureBoot isn't documented enough
Product: [Fedora] Fedora Documentation Reporter: Bruno Cornec <bruno.cornec>
Component: uefi-secure-boot-guideAssignee: Peter Jones <pjones>
Status: CLOSED EOL QA Contact: Fedora Docs QA <docs-qa>
Severity: high Docs Contact:
Priority: unspecified    
Version: develCC: bruno.cornec, nicolasoliver03
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-11-07 15:29:59 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Bruno Cornec 2013-09-20 20:45:33 UTC
Description of problem:
http://docs.fedoraproject.org/en-US/Fedora/18/html-single/UEFI_Secure_Boot_Guide/index.html#chap-UEFI_Secure_Boot_Guide-Implementation_of_UEFI_Secure_Boot doesn't have descriptions for the chapter 5 which is very useful if you want to use your own keys/certificates.

Using what is at http://en.opensuse.org/openSUSE:UEFI could serve as an example.

Comment 1 Eric Christensen 2013-10-01 15:29:34 UTC
Peter, can you can help out here. I suspect you're the only person with enough knowledge to start documenting this.

Comment 2 nicolasoliver03 2019-10-18 22:06:10 UTC
I have some documentation in this area that could serve as a base to solve this (posted in markdown format below).
I have tested them in Fedora 30 and 31 (regularly).

This snippet documents how to sign a custom kernel with a Machine Owner Key for Secure Boot.

        ## Secure Boot with custom Linux Kernels

        In the case that a custom Linux Kernel is used, it is possible to use the Machine Owner Keys (MOK) infrastructure to
        save a public key to verify a custom Linux Kernel signed with the associated private key.

        ### MOK Key Generation

        To start, create an OpenSSL configuration file as follow. Replace the `countryName`, `stateOrProvinceName`,
        `localityName`, and `0.organizationName` with the correct values, if needed:

        **NOTE:** There is a 64 character limit for each of the following string values.

        cat > openssl.cnf << EOF
        [ req ]
        distinguished_name      = req_distinguished_name
        x509_extensions         = v3
        string_mask             = utf8only
        prompt                  = no
        [ req_distinguished_name ]
        countryName             = Country
        stateOrProvinceName     = Province
        localityName            = City
        0.organizationName      = Organization
        commonName              = Secure Boot Signing
        emailAddress            = test@domain.com
        [ v3 ]
        subjectKeyIdentifier    = hash
        authorityKeyIdentifier  = keyid:always,issuer
        basicConstraints        = critical,CA:FALSE
        extendedKeyUsage        = codeSigning,
        nsComment               = "OpenSSL Generated Certificate"

        Create a private key and the associated public key in DER format:

        openssl req -config ./openssl.cnf \
                -new -x509 -newkey rsa:2048 \
                -nodes -days 3650 -outform DER \
                -keyout MOK.key \
                -out MOK.der

        Additionally, generate the same associated public key in PEM format. DER format will be used to save the certificate
        in the MOK infrastructure, and the PEM format will be used to sign the custom Linux Kernel.

        openssl x509 -in MOK.der -inform DER -outform PEM -out MOK.pem

        ### Signing custom Linux Kernel

        You'll need to have the `pesign` and `sbsigntools` utilities:


        sudo dnf install pesign
        sudo dnf install sbsigntools


        In the case that the Linux Kernel to be signed contains additional unwanted signatures, use the `pesign` utility to
        remove them. Repeat this for each signature slot.

        To list the current signatures in the kernel (`vmlinuz` is used as an example Linux Kernel):

        sbverify --list vmlinuz

        To remove a signature from a slot:

        pesign --remove-signature \
            --in vmlinuz --out vmlinuz-unsigned \
            --signature-number 0 --force

        Then, we can sign the kernel with our private key generated previously:

        sbsign --key MOK.key --cert MOK.pem \
            --output vmlinuz-signed vmlinuz-unsigned

        Install the custom signed Linux Kernel following the distribution recommendations.

        ### Enrolling Signing Key into MOK

        Finally, we need to load the public key in DER format into the MOK infrastructure. A password needs to be added, that
        will be used once the system is rebooted to complete the MOK enrollment:

        sudo mokutil --import MOK.der

        Check the enrollment state:

        sudo mokutil --list-new

        Finally, reboot the system. The first stage bootloader will detect the new key being added, and request the password to
        complete the enrollment. Once this is done the custom signed Linux Kernel will be validated by the first stage boot
        loader on every boot.

And this snippet explain how to create Custom PK, KEK, DB, and DBX for Secure Boot, how to use them to sign a kernel, and enroll them in the BIOS

        ## Secure Boot with Custom Keys

        In the case that Standard Key usage is not desired, it is possible to generate custom PK, KEK, and DB artifacts to be
        used in the Secure Boot flow. Those artifacts will be then installed into the system using the BIOS Settings.

        ### Key Generation

        Generate Platform Key:

        openssl req -new -x509 -newkey rsa:2048 -subj "/CN=PK_Key/" \
                -keyout Private_PK_Key.key -out Public_PK_Cert.crt \
                -days 3650 -nodes -sha384

        Generate Key Exchange Key:

        openssl req -new -x509 -newkey rsa:2048 -subj "/CN=KEK_Key/" \
                -keyout Private_KEK_Key.key -out Public_KEK_Cert.crt \
                -days 3650 -nodes -sha384

        Generate DB Key:

        openssl req -new -x509 -newkey rsa:2048 -subj "/CN=DB_Key/" \
                -keyout Private_DB_Key.key -out Public_DB_Cert.crt \
                -days 3650 -nodes -sha384

        Convert all public parts in DER format

        openssl x509 -in Public_PK_Cert.crt -out Public_PK_Cert.der -outform DER
        openssl x509 -in Public_KEK_Cert.crt -out Public_KEK_Cert.der -outform DER
        openssl x509 -in Public_DB_Cert.crt -out Public_DB_Cert.der -outform DER

        The public parts in DER format need to be saved into a USB drive (FAT) to be loaded into the BIOS later.

        ### Signing EFI binaries with custom keys

        The artifacts to be signed are:

        1. First Stage bootloader (Shim)
        2. Second Stage bootloader (Grub 2)
        3. Linux Kernel

        In this example, we use `shimx64.efi`, `grubx64.efi` and `vmlinuz` as example artifacts to be signed.

        In the case that the artifacts to be signed contains additional unwanted signatures, use the `pesign` utility to remove
        them. Repeat this for each signature slot.

        To list the current signatures:

        sbverify --list shimx64.efi
        sbverify --list grubx64.efi
        sbverify --list vmlinuz

        To remove a signature from a slot:

        pesign --remove-signature --in shimx64.efi \
            --out shimx64-unsigned.efi --signature-number 0 \

        pesign --remove-signature --in grubx64.efi \
            --out grubx64-unsigned.efi --signature-number 0 \

        pesign --remove-signature --in vmlinuz \
            --out vmlinuz-unsigned --signature-number 0 \

        Now, sign the artifacts with the previously generated DB private key:

        sbsign  --key Private_DB_Key.key \
                --cert Public_DB_Cert.crt \
                --output shimx64-signed.efi \

        sbsign  --key Private_DB_Key.key \
                --cert Public_DB_Cert.crt \
                --output grubx64-signed.efi \

        sbsign  --key Private_DB_Key.key \
                --cert Public_DB_Cert.crt \
                --output vmlinuz-signed \

        Finally, install the signed first stage bootloader, second stage bootloader, and Linux Kernel following the recommended
        procedure by the Linux Distribution.

        ### Enabling Custom Keys in the BIOS

        Restart your system and access the BIOS Configuration. Navigate to the `Security` -> `Secure Boot` screen. Set the
        Secure Boot mode to `Custom` and open the `Key Management` page.

        Set the `Default Key Provision` to `Disabled`. Finally, install the new Platform, Key Exchange, and DB keys using each
        of the corresponding options.

        **NOTE:** While platform key can only be replaced in the set of keys, the Key Exchange and DB keys can be added to the
        system. Use the `Append` option to install new keys while keeping the original ones, so you can secure boot to both
        the new custom kernel and the original ones.

I have no instructions on how to sign kernel modules, but this could be taken from the comments of this bug https://bugzilla.redhat.com/show_bug.cgi?id=1615744

Could you please review this instructions?

Comment 3 Petr Bokoc 2019-11-07 15:29:59 UTC
I'm closing this bug as part of a Bugzilla cleanup effort. The most likely reason is that the bug has been opened either against a component we no longer publish, or against Release Notes for an EOL release.

Comment 4 nicolasoliver03 2019-11-07 19:10:50 UTC

This is still current. The Fedora documentation of secure boot is incomplete and dated (the current one is a draft for Fedora 18)
There are some instructions on how to sign kernel modules, but it is also inaccurate per https://bugzilla.redhat.com/show_bug.cgi?id=1615744
Public information found by web search usually recommends nuking PK,KEK,DB,DBX and creating your owns, which is something extreme if the only thing you want to do is to boot a custom kernel. (e.g. http://kroah.com/log/blog/2013/09/02/booting-a-self-signed-linux-kernel/ from 2013). This also invalidates any existing signed kernel and makes you have to sign them with your custom keys. 
It is not explained how to append a KEK and DB.
It is also not clear how kernel modules reacts to secure boot, given that the functionality to force modules to be signed in secure boot mode comes and goes (https://bugzilla.redhat.com/show_bug.cgi?id=1696671)