diff --git a/build_library/sbsign_util.sh b/build_library/sbsign_util.sh index b8017224d6..6eb82ea14d 100644 --- a/build_library/sbsign_util.sh +++ b/build_library/sbsign_util.sh @@ -10,9 +10,10 @@ else SBSIGN_CERT="/usr/share/sb_keys/official/signing.pem" fi -PKCS11_MODULE_PATH="/usr/$(get_sdk_libdir)/pkcs11/azure-keyvault-pkcs11.so" +PKCS11_MODULE_PATH="$(pkg-config p11-kit-1 --variable p11_module_path)/azure-keyvault-pkcs11.so" PKCS11_ENV=( + AZURE_CORE_COLLECT_TELEMETRY=no AZURE_KEYVAULT_URL="https://flatcar-sb-dev-kv.vault.azure.net/" PKCS11_MODULE_PATH="${PKCS11_MODULE_PATH}" AZURE_KEYVAULT_PKCS11_DEBUG=1 @@ -31,3 +32,25 @@ do_sbsign() { --cert "${SBSIGN_CERT}" \ "${@}" } + +setup_gnupghome() { + export GNUPGHOME + GNUPGHOME=$(mktemp -d) + trap 'gpgconf --kill gpg-agent; rm -r -- "${GNUPGHOME}"' EXIT + + # Unofficial builds simply use a local private key. + [[ ${COREOS_OFFICIAL:-0} -ne 1 ]] && return + + cat < "${GNUPGHOME}"/gpg-agent.conf +scdaemon-program $(type -P gnupg-pkcs11-scd) +EOF + + cat < "${GNUPGHOME}"/gnupg-pkcs11-scd.conf +providers kms +provider-kms-library ${PKCS11_MODULE_PATH} +log-file /dev/null +EOF + + # This fetches the private keys from AKV. + gpg --card-status +} diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md index 77f406af6f..0f4a53af23 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/README.md @@ -1,15 +1,31 @@ ## Keys & Certificates -- DB (Signature Database): The signature database is used to validate signed EFI binaries. -- Shim Certificates: Our set of certificates +### X.509 signature database - DB.key, DB.pem +The signature database is used by the UEFI firmware to validate signed EFI binaries (e.g. the shim). In this case, `DB.key` and `DB.pem` are only used for testing with QEMU. Real deployments use the database provided by the bare metal host or hypervisor. + +### X.509 shim vendor certificates - shim.key, shim-*.pem + +Unofficial builds: `shim-*.pem` are the current and historical self-signed signing certificates used to sign the bootloader and kernel. `shim.key` is the private key for the current certificate. + +Official builds: `shim-*.pem` are the current and historical CA certificates that issue the signing certificates. The private key is only needed to issue new signing certificates so is kept offline. + +### X.509 signing certificate - signing.pem + +Unofficial builds: The current signing certificate is also the current shim vendor certificate above, so there is no separate `signing.pem`. + +Official builds: `signing.pem` is the current signing certificate used to sign the bootloader and kernel. It is copied from Azure Key Vault, where the private key is also stored. + +### GPG signing keys - signing*.gpg + +Unofficial builds: `signing.gpg` is the current private key used to sign the kernel load script. `signing-*.gpg` are the historical public keys used to verify them. They have no expiry date. + +Official builds: `signing.gpg` is the current public key used to sign the kernel load script. `signing-*.gpg` are the historical public keys used to verify them. These keys are created from their respective X.509 signing certificates. As such, the private keys are only stored in Azure Key Vault. The start and end dates of the keys also match the certificates. ## Generation of Keys & Certificates +Unofficial builds: Delete any of `DB.key`, `shim.key`, or `signing.gpg` to force recreation. -Generate the our shim certificates: +Official builds: Delete `signing.gpg` to force recreation. `shim-*.pem` must be updated manually. `signing.pem` is refreshed from Azure Key Vault using the details stored in `build_library/sbsign_util.sh`. Ensure [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) is in your `PATH`. -``` -openssl genrsa -out "shim.key" 2048 -openssl req -new -x509 -sha256 -subj "/CN=shim/" -key "shim.key" -out "shim.pem" -days 7300 -``` +Run the `refresh_keys` script without any arguments. Bump the coreos-sb-keys package with the changes. diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-2.0.0.ebuild b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-2.0.0.ebuild index 2a6ffb79d3..6baa9ed3a1 100644 --- a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-2.0.0.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/coreos-sb-keys-2.0.0.ebuild @@ -56,5 +56,14 @@ src_install() { doins -r unofficial official insinto /usr/share/sb_keys/unofficial - doins "${FILESDIR}"/unofficial/{DB.{key,pem},shim.key} + doins "${FILESDIR}"/unofficial/{DB.{key,pem},shim.key,signing*.gpg} + + insinto /usr/share/sb_keys/official + doins "${FILESDIR}"/official/signing-*.gpg + + # For unofficial builds, we install the GPG private key as signing.gpg to + # sign with. For official builds, we create a symlink to the newest public + # key instead because the private key is in Azure Key Vault. + local FILES=( "${FILESDIR}"/official/signing-*.gpg ) + dosym "${FILES[-1]##*/}" /usr/share/sb_keys/official/signing.gpg } diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/.gitignore b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/.gitignore new file mode 100644 index 0000000000..64d1ee2030 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/.gitignore @@ -0,0 +1,2 @@ +# azure-cli creates this, seemingly due to a bug. +/None/ diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/refresh_keys b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/refresh_keys new file mode 100755 index 0000000000..5f68c21f47 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/refresh_keys @@ -0,0 +1,67 @@ +#!/bin/bash + +set -euo pipefail +cd "${0%/*}" + +COREOS_OFFICIAL=1 +. ../../../../../../../../build_library/sbsign_util.sh +export "${PKCS11_ENV[@]}" + +echo "Fetching ${SBSIGN_KEY} from Azure" +CERT=$(p11-kit export-object --provider "${PKCS11_MODULE_PATH}" "${SBSIGN_KEY};type=cert") + +if [[ -f signing.pem && ${CERT} = "$(< signing.pem)" ]]; then + echo "signing.pem: Unchanged" +else + echo "signing.pem: Updating" + cat > signing.pem <<< "${CERT}" +fi + +CERT=signing.pem + +# Copy the X.509 dates to the GPG key. This isn't required, but it helps to +# identify the key, and not setting an expiry date is bad practise. +START=$(openssl x509 -noout -in "${CERT}" -startdate) +START=$(date -d "${START#*=}" -u +%Y%m%dT%H%M%S) +# +END=$(openssl x509 -noout -in "${CERT}" -enddate) +END=$(date -d "${END#*=}" -u +%Y%m%dT%H%M%S) + +# We also use the start date to name the GPG key. +OUTPUT=signing-${START%%T*}.gpg + +if [[ -f ${OUTPUT} ]]; then + echo "${OUTPUT}: Exists (remove to recreate)" + exit +fi + +setup_gnupghome + +# This isn't a great way to find the matching key from AKV, and it only works +# with RSA keys, but keygrips are internal to GPG, so there isn't much choice. +MODULUS=$(openssl x509 -in "${CERT}" -noout -modulus) +MODULUS=${MODULUS#*=} +# +for KEYGRIP in "${GNUPGHOME}"/private-keys-v1.d/*.key; do + if tr -d "\n " < "${KEYGRIP}" | grep -qF "${MODULUS}"; then + break + fi +done +# +KEYGRIP=${KEYGRIP##*/} +KEYGRIP=${KEYGRIP%.key} + +echo "${OUTPUT}: Creating" +gpg --batch --generate-key <<-EOF +Key-Type: RSA +Key-Grip: ${KEYGRIP} +Key-Usage: sign +Name-Real: Flatcar Secure Boot official +Name-Email: maintainers@flatcar-linux.org +Creation-Date: ${START} +Expire-Date: ${END} +%commit +EOF + +# Only write the public key to a file. The private key remains in AKV. +gpg --export --output "${OUTPUT}" diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/signing-20250320.gpg b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/signing-20250320.gpg new file mode 100644 index 0000000000..9e98573fe8 Binary files /dev/null and b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/official/signing-20250320.gpg differ diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/refresh_keys b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/refresh_keys new file mode 100755 index 0000000000..cf9dbd9058 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/refresh_keys @@ -0,0 +1,56 @@ +#!/bin/bash + +set -euo pipefail +cd "${0%/*}" + +COREOS_OFFICIAL=0 +. ../../../../../../../../build_library/sbsign_util.sh + +BITS=2048 +DAYS=7300 +DATE=$(date +%Y%m%d) + +if [[ -f DB.key ]]; then + echo "DB.key: Exists (remove to recreate)" +else + echo "DB.key: Creating" + openssl genrsa -out DB.key "${BITS}" + echo "DB.pem: Creating" + openssl req -new -x509 -sha256 -days "${DAYS}" -subj "/CN=CoreOS test DB/" -key DB.key -out DB.pem +fi + +if [[ -f shim.key ]]; then + echo "shim.key: Exists (remove to recreate)" +else + echo "shim.key: Creating" + openssl genrsa -out shim.key "${BITS}" + echo "shim-${DATE}.pem: Creating" + openssl req -new -x509 -sha256 -days "${DAYS}" -subj "/CN=shim/" -key shim.key -out shim-"${DATE}".pem +fi + +if [[ -f signing.gpg ]]; then + echo "signing.gpg: Exists (remove to recreate)" + exit +fi + +setup_gnupghome + +echo "signing.gpg: Creating" +gpg --batch --generate-key <<-EOF +%no-protection +Key-Type: RSA +Key-Length: ${BITS} +Key-Usage: sign +Name-Real: Flatcar Secure Boot development +Name-Email: maintainers@flatcar-linux.org +Expire-Date: 0 +%commit +EOF + +# Write the private key to a file for signing. +gpg --export-secret-keys --output signing.gpg + +# Write the public key to a file for verification. +echo "signing-${DATE}.gpg: Creating" +rm -f signing-"${DATE}".gpg +gpg --export --output signing-"${DATE}".gpg diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/signing-20250604.gpg b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/signing-20250604.gpg new file mode 100644 index 0000000000..e0b3a1b9fe Binary files /dev/null and b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/signing-20250604.gpg differ diff --git a/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/signing.gpg b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/signing.gpg new file mode 100644 index 0000000000..ce520623a4 Binary files /dev/null and b/sdk_container/src/third_party/coreos-overlay/coreos-base/coreos-sb-keys/files/unofficial/signing.gpg differ