Use UEFI Secure Boot

Secure Boot is supported in UEFI installations only. It is not used when booting StarlingX as a legacy boot target.

StarlingX currently does not support switching from legacy to UEFI mode after a system has been installed. Doing so requires a reinstallation of the system. This also means that upgrading from a legacy install to a secure boot install (UEFI) is not supported.

When upgrading a StarlingX system from a version which does not support secure boot to a version that does, do not enable secure boot in UEFI firmware until the upgrade is complete.

For each node that is going to use secure boot, you must populate the StarlingX public certificate/key in the UEFI Secure Boot authorized database in accordance with the board manufacturer’s process. This must be done for each node before starting installation.

You may need to work with your hardware vendor to have the certificate installed.

There is often an option in the UEFI setup utility which allows a user to browse to a file containing a certificate to be loaded in the authorized database. This option may be hidden in the UEFI setup utility unless UEFI mode is enabled, and secure boot is enabled.

Many motherboards ship with Microsoft secure boot certificates pre-programmed in the UEFI certificate database. These certificates may be required to boot UEFI drivers for video cards, RAID controllers, or NICs (for example, the PXE boot software for a NIC may have been signed by a Microsoft certificate). While certificates can usually be removed from the certificate database (again, this is UEFI implementation specific) it may be required that you keep the Microsoft certificates to allow for complete system operation.

Mixed combinations of secure boot and non-secure boot nodes are supported. For example, a controller node may secure boot, while a worker node may not. Secure boot must be enabled in the UEFI firmware of each node for that node to be protected.

Build considerations for signing packages for UEFI Secure Boot

The StarlingX build environment has provisions for calling out to a signing server for purposes of creating a secure boot load. At this time StarlingX does not include an implementation of the signing server. The following describes how the signing process is intended to work in the context of a CentOS build. You may find it helpful in implementing your own signing server.

The following environmental variables should be defined before attempting to request a secure boot signing:

export SIGNING_SERVER=<signing-host>
export SIGNING_USER=<signing-user>
export SIGNING_SERVER_SCRIPT=<path-to-signing-script>

build-pkgs further requires that $USER be set to “jenkins”, and export FORMAL_BUILD=1`.

If the above criteria is met, it calls into sign-secure-boot.

This is an example of the call sequence:

# 1. Set up the server side directory for files transfers.
UPLOAD_PATH=`ssh $SIGNING_USER@$SIGNING_SERVER sudo $SIGNING_SCRIPT -r`

# 2. upload the original package
scp -q $FILE $SIGNING_USER@$SIGNING_SERVER:$UPLOAD_PATH

# 3. Request that the package be signed
ssh $SIGNING_USER@$SIGNING_SERVER sudo $SIGNING_SCRIPT -v -i $UPLOAD_PATH/$(basename $FILE) $UNSIGNED_OPTION -t $TYPE > $TMPFILE

# 4. Download the file from the signing server
DOWNLOAD_FILENAME=$(basename $OUTPUT_FILE)
scp -q $SIGNING_USER@$SIGNING_SERVER:$OUTPUT_FILE $(dirname $FILE)

Within the signing server there are two keys used for signing, known as the boot key and the shim key. The public boot key file must be manually added to the secure boot keychain in the firmware. The boot key signs the first executable loaded, contained in the shim package. The first executable must then install the public shim key file (automatically) before passing control to the grub, and ultimately the kernel, both of which are signed by the private shim key.

Three packages need to be passed to the signing server. The RPMs need to be unpacked, the relevant binaries signed with the correct keys, and the RPMs reassembled.

Package

Key

Files to sign

shim

boot shim

BOOTX64, shim, shimx64 MokManager, fallback, mmx64, fbx64

grub

shim

grubx64.efi, gcdx64.efi

kernel

shim

Note

shim files that are required to be signed might might include a .efi or .EFI suffix.

Some files may be absent in newer packages.

Example:

sbsign --key $KEYPATH/$KEYNAME.key --cert $KEYPATH/$KEYNAME.crt  --output $SIGNEDFILE $UNSIGNEDFILE

Keys and certificates:

  • boot.crt - Certificate to boot (to be programmed in firmware)

  • boot.key - Private key with which to sign shim

  • shim.crt - Certificated embedded within shim used to validate kernel, grub

  • shim.key - Private key with which to sign kernel/grub

Key generation:

openssl req -new -x509 -newkey rsa:2048 -keyout $KEY.key -out $KEY.pem -days 3650
openssl x509 -in $KEY.pem -out $KEY.crt -outform DER

Note

boot.crt should be copied to cgcs-root/build-tools/certificates/TiBoot.crt for inclusion during the build-iso step.

Build considerations for signing packages for UEFI Secure Boot – Debian build

The StarlingX build environment has provisions for calling out to a signing server for purposes of creating a secure boot load. At this time StarlingX does not include an implementation of the signing server. The following describes how the signing process is intended to work in the context of a Debian build. You may find it helpful in implementing your own signing server.

The secure boot verification sequence of StarlingX Debian is:

  1. UEFI firmware verify shim image

  2. shim verify grub image

  3. grub verify kernel image and initramfs image

The bootloader shim will enroll the public key to verify grub image.

The bootloader grub-efi will enroll the public key to verify kernel and initramfs image.

The following process should be followed to request a secure boot signing:

......
stx control keys-add --key-type=signing-server --key=[key file]
stx shell
downloader
build-pkgs
export SIGNING_SERVER="signing_user@signing_server_ip"
sign-secure-boot_debian
build-image

The “key file” is the private key generated by ssh-keygen -t rsa and used to setup signing server access without password.

The signing script sign-secure-boot_debian does secure boot signing for StarlingX Debian as follows:

  1. Sign shim / grub images

    The shim/grub efi images are obtained from extracted shim/grub packages, and they are sent to signing server and signed there and copied back. Then the shim/grub packages are repacked with the signed efi images.

  2. Sign kernel images and LockDown.efi

    The file sign_rootfs-post-scripts is inserted to where the hook script “rootfs-post-scripts” is defined in the LAT config file base-bullseye.yaml. This will sign kernel images and LockDown.efi on signing server in the LAT build process. The “rootfs-post-scripts” is the hook in LAT tool running after rootfs is created.

  3. Sign initramfs and mini initrd

    The file`` sign_initramfs-sign-script`` is inserted to where the hook script initramfs-sign-script is defined in the LAT config file base-bullseye.yaml. This will sign initramfs and mini initrd on signing server in the LAT build process. The initramfs-sign-script is the hook in LAT tool running after initramfs is created.

2 and 3 above prepare the signing codes in the LAT config file. After build-image is triggered, the signing codes inserted into the LAT config files will run on the LAT container in the correct sequence.

Here is an example for signing an image file in sign-secure-boot_debian:

# Request upload path from signing server.
REQUEST=$(ssh ${SSH_OPTION_NOCHECKING} ${SIGNING_SERVER} sudo /opt/signing/sign-debian.sh -r)
UPLOAD_PATH=${REQUEST#*Upload: }

# Copy shimx64.efi to signing server
scp ${SSH_OPTION_NOCHECKING} shimx64.efi ${SIGNING_SERVER}:${UPLOAD_PATH}
# Sign shimx64.efi
ssh ${SSH_OPTION_NOCHECKING} ${SIGNING_SERVER} sudo /opt/signing/sign-debian.sh -i ${UPLOAD_PATH}/shimx64.efi -t shim
# Copy back signed shimx64.efi which is renamed as bootx64.efi
sudo scp ${SSH_OPTION_NOCHECKING} ${SIGNING_SERVER}:${UPLOAD_PATH}/bootx64.efi ./

sign-debian.sh, above, is the script running on signing server whose interface is defined as below:

Usage:
sign-debian.sh [options]

[-i <file>] - input unsigned file
[-t <type>] - type of signing to do
[-r]        - request an upload path

Types of signing:
-t shim     - signs a shim EFI binary with the boot key
-t grub     - signs a GRUB EFI binary with the shim key
-t shimtool - signs a shim tool EFI binary with the shim key
-t grub-gpg - signs a kernel/initrd/grub.cfg with the grub gpg key

Keys management:

Upstream stx public keys repo: https://opendev.org/starlingx/public-keys

The keys under cgcs-root/public-keys are the public keys used in the verification process of secure boot process for StarlingX Debian.

Keys Introduction:

tis-boot.crt: The public key flashed into UEFI to verify

bootx64.efi (signed shim image shimx64.efi)

tis-shim.der: The public key used by shim to verify

grubx64.efi (signed grub image) and mmx64.efi (signed shim tool image);

boot_pub_key: it is the public key used by grub to verify signed

kernel image and initramfs image and efitools image and so on.

TiBoot.crt: it is the same pub key with tis-boot.crt (pem) as a

der format. It is installed as /CERTS/TiBoot.crt in the efi.img which is in the iso image.

The following methods can be used to create substitute keys:

  1. Example to create tis-boot.crt/TiBoot.crt.

    openssl req -new -x509 -newkey rsa:2048 -keyout BOOT.priv -outform DER -out BOOT.der -days 36500 -subj "/CN=My Boot/" -nodes
    openssl x509 -inform der -in BOOT.der -out BOOT.pem
    cp BOOT.pem tis-boot.crt
    cp BOOT.priv tis-boot.key
    cp BOOT.der TiBoot.crt
    

    The tis-boot.crt and tis-boot.key are used to sign images mentioned above (shim image).

    The tis-shim.crt/tis-shim.der/tis-shim.key can be created in the same way, and used to sign images mentioned above (grub image and shim tool image).

  2. Example to create boot_pub_key.

    #!/bin/bash
    key_dir="./"
    priv_key="${key_dir}/BOOT-GPG-PRIVKEY-SecureBootCore"
    pub_key="${key_dir}/BOOT-GPG-KEY-SecureBootCore"
    name_real="SecureBootCore"
    pw="PASSWORD"
    USE_PW="Passphrase: PASSWORD"
    cat >"${key_dir}/gen_keyring" <<EOF
    Key-Type: RSA
    Key-Length: 4096
    Name-Real: ${name_real}
    Name-Comment: EXAMPLE
    Name-Email: a@b.com
    Expire-Date: 0
    ${USE_PW}
    %commit
    %echo keyring ${name_real} created
    EOF
    
    gpg --homedir "${key_dir}" --batch --yes --gen-key "${key_dir}/gen_keyring"
    gpg --homedir "${key_dir}" -k
    gpg --homedir "${key_dir}" --export --armor "${name_real}" > "${pub_key}"
    gpg --homedir "${key_dir}" --export-secret-keys --pinentry-mode=loopback --passphrase "${pw}" --armor "${name_real}" > "${priv_key}"
    gpg --homedir "${key_dir}" --export "${name_real}" > ${key_dir}/boot_pub_key
    

    The BOOT-GPG-PRIVKEY-SecureBootCore is used to sign images mentioned above (kernel image, initramfs image and efitools image and so on).

  3. Signing commands to sign image files:

    • Signing command to sign type shim/grub/shimtool image files:

      sbsign --key $KEYPATH/$KEYNAME.key \
             --cert $KEYPATH/$KEYNAME.crt \
             --output $SIGNEDFILE \
             $UNSIGNEDFILE
      
      • for -t shim, the output file name is bootx64.efi

      • for -t grub, the output file name is grubx64.efi

      • for -t shimtool, the output file name is ${UNSIGNEDFILE}.signed

    • Signing command to sign type grub-gpg files:

      gpg2 --batch \
          --homedir ${GPGHOME} \
          --passphrase PASSWORD \
          --import ${KEYPATH}/${BOOT_GPG_PRI_KEY}
      echo 'PASSWORD' | \
      gpg2 --pinentry-mode loopback \
          --batch \
          --homedir ${GPGHOME} \
          -u SecureBootCore \
          --detach-sign \
          --passphrase-fd 0 \
              ${FILEIN}
      

      Refer to Key management to determine the keys they should use.