From 8afbf0a6bf7c7502c373ed54516b7bca7c7a73c6 Mon Sep 17 00:00:00 2001 From: krygas-crane <94056625+krygas-crane@users.noreply.github.com> Date: Fri, 21 Mar 2025 08:41:49 +0100 Subject: [PATCH 1/2] Changes for Yubikey derivePublicKey() will generate the key for both PEM and PKCS11 get_signing_directives() is removed and ifs are placed where openssl call is made. This is because get_signing_directives was returning string that was incorrectly processed by the openssl command (single parameter rather than multiple parameters). There is likely a way to fix the get_signing_directives and avoid repeating the code but my bash skills are too limited to do it unfortunately. This version of the file was tested with Raspberry Pi 4 used as host (running standard PI OS 64 bit image) and it provisioned CM4 module correctly with the private key stored in the Yubikey 5. One thing that is worth noting is to store the key outside of the 9c slot (I have used 9a) to avoid script getting prompted for pin. --- service/rpi-sb-provisioner.sh | 124 +++++++++++++++++----------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/service/rpi-sb-provisioner.sh b/service/rpi-sb-provisioner.sh index eb5d891..7ddc9e6 100755 --- a/service/rpi-sb-provisioner.sh +++ b/service/rpi-sb-provisioner.sh @@ -47,24 +47,6 @@ read_config() { : "${RPI_DEVICE_STORAGE_CIPHER:=aes-xts-plain64}" -get_signing_directives() { - if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then - echo "${CUSTOMER_KEY_PKCS11_NAME} -engine pkcs11 -keyform engine" - else - if [ -n "${CUSTOMER_KEY_FILE_PEM}" ]; then - if [ -f "${CUSTOMER_KEY_FILE_PEM}" ]; then - echo "${CUSTOMER_KEY_FILE_PEM} -keyform PEM" - else - echo "RSA private key \"${CUSTOMER_KEY_FILE_PEM}\" not a file. Aborting." >&2 - exit 1 - fi - else - echo "Neither PKCS11 key name, or PEM key file specified. Aborting." >&2 - exit 1 - fi - fi -} - echo "${KEYWRITER_STARTED}" >> /var/log/rpi-sb-provisioner/"${TARGET_DEVICE_SERIAL}"/progress read_config @@ -126,7 +108,17 @@ timeout_fatal() { CUSTOMER_PUBLIC_KEY_FILE= derivePublicKey() { CUSTOMER_PUBLIC_KEY_FILE="$(mktemp)" - "${OPENSSL}" rsa -in "${CUSTOMER_KEY_FILE_PEM}" -pubout > "${CUSTOMER_PUBLIC_KEY_FILE}" + if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then + "${OPENSSL}" rsa -engine pkcs11 -inform engine -in "${CUSTOMER_KEY_PKCS11_NAME}" -pubout > "${CUSTOMER_PUBLIC_KEY_FILE}" + if [ $? -ne 0 ]; then + echo "Error: Failed to extract public key using PKCS#11 engine." + exit 1 + fi + else + # Existing method to derive public key + "${OPENSSL}" rsa -in "${CUSTOMER_KEY_FILE_PEM}" -pubout > "${CUSTOMER_PUBLIC_KEY_FILE}" + fi + } TMP_DIR="" @@ -139,12 +131,15 @@ writeSig() { # Include the update-timestamp echo "ts: $(date -u +%s)" >> "${OUTPUT}" - - if [ -n "$(get_signing_directives)" ]; then # shellcheck disable=SC2046 - "${OPENSSL}" dgst -sign $(get_signing_directives) -sha256 -out "${SIG_TMP}" "${IMAGE}" + + if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then + "${OPENSSL}" dgst -sign "${CUSTOMER_KEY_PKCS11_NAME}" -engine pkcs11 -keyform engine -sha256 -out "${SIG_TMP}" "${IMAGE}" + else + + "${OPENSSL}" dgst -sign ${CUSTOMER_KEY_FILE_PEM} -keyform PEM -sha256 -out "${SIG_TMP}" "${IMAGE}" + fi echo "rsa2048: $(xxd -c 4096 -p < "${SIG_TMP}")" >> "${OUTPUT}" - fi rm "${SIG_TMP}" } @@ -179,45 +174,43 @@ update_eeprom() { keywriter_log "update_eeprom() src_image: \"${src_image}\"" - if [ -n "${pem_file}" ]; then - if ! grep -q "SIGNED_BOOT=1" "${RPI_DEVICE_BOOTLOADER_CONFIG_FILE}"; then - # If the OTP bit to require secure boot are set then then - # SIGNED_BOOT=1 is implicitly set in the EEPROM config. - # For debug in signed-boot mode it's normally useful to set this - keywriter_log "Warning: SIGNED_BOOT=1 not found in \"${RPI_DEVICE_BOOTLOADER_CONFIG_FILE}\"" - fi + if ! grep -q "SIGNED_BOOT=1" "${RPI_DEVICE_BOOTLOADER_CONFIG_FILE}"; then + # If the OTP bit to require secure boot are set then then + # SIGNED_BOOT=1 is implicitly set in the EEPROM config. + # For debug in signed-boot mode it's normally useful to set this + keywriter_log "Warning: SIGNED_BOOT=1 not found in \"${RPI_DEVICE_BOOTLOADER_CONFIG_FILE}\"" + fi - #update_version=$(strings "${src_image}" | grep BUILD_TIMESTAMP | sed 's/.*=//g') + #update_version=$(strings "${src_image}" | grep BUILD_TIMESTAMP | sed 's/.*=//g') - TMP_CONFIG_SIG="$(mktemp)" - keywriter_log "Signing bootloader config" - writeSig "${RPI_DEVICE_BOOTLOADER_CONFIG_FILE}" "${TMP_CONFIG_SIG}" + TMP_CONFIG_SIG="$(mktemp)" + keywriter_log "Signing bootloader config" + writeSig "${RPI_DEVICE_BOOTLOADER_CONFIG_FILE}" "${TMP_CONFIG_SIG}" - # shellcheck disable=SC2086 - cat "${TMP_CONFIG_SIG}" ${DEBUG} - - # rpi-eeprom-config extracts the public key args from the specified - # PEM file. - sign_args="-d ${TMP_CONFIG_SIG} -p ${public_pem_file}" - - case ${RPI_DEVICE_FAMILY} in - 4) - # 2711 does _not_ require a signed bootcode binary - cp "${src_image}" "${dst_image}.intermediate" - ;; - 5) - customer_signed_bootcode_binary_workdir=$(mktemp -d) - cd "${customer_signed_bootcode_binary_workdir}" || return - rpi-eeprom-config -x "${src_image}" - rpi-sign-bootcode --debug -c 2712 -i bootcode.bin -o bootcode.bin.signed -k "${pem_file}" -v 0 -n 16 - rpi-eeprom-config \ - --out "${dst_image}.intermediate" --bootcode "${customer_signed_bootcode_binary_workdir}/bootcode.bin.signed" \ - "${src_image}" || die "Failed to update signed bootcode in the EEPROM image" - cd - > /dev/null || return - rm -rf "${customer_signed_bootcode_binary_workdir}" - ;; - esac - fi + # shellcheck disable=SC2086 + cat "${TMP_CONFIG_SIG}" ${DEBUG} + + # rpi-eeprom-config extracts the public key args from the specified + # PEM file. + sign_args="-d ${TMP_CONFIG_SIG} -p ${public_pem_file}" + + case ${RPI_DEVICE_FAMILY} in + 4) + # 2711 does _not_ require a signed bootcode binary + cp "${src_image}" "${dst_image}.intermediate" + ;; + 5) + customer_signed_bootcode_binary_workdir=$(mktemp -d) + cd "${customer_signed_bootcode_binary_workdir}" || return + rpi-eeprom-config -x "${src_image}" + rpi-sign-bootcode --debug -c 2712 -i bootcode.bin -o bootcode.bin.signed -k "${pem_file}" -v 0 -n 16 + rpi-eeprom-config \ + --out "${dst_image}.intermediate" --bootcode "${customer_signed_bootcode_binary_workdir}/bootcode.bin.signed" \ + "${src_image}" || die "Failed to update signed bootcode in the EEPROM image" + cd - > /dev/null || return + rm -rf "${customer_signed_bootcode_binary_workdir}" + ;; + esac rm -f "${dst_image}" set -x @@ -694,8 +687,11 @@ sha256sum "${RPI_SB_WORKDIR}"/boot.img | awk '{print $1}' > "${RPI_SB_WORKDIR}"/ printf 'rsa2048: ' >> "${RPI_SB_WORKDIR}"/boot.sig # Prefer PKCS11 over PEM keyfiles, if both are specified. # shellcheck disable=SC2046 -${OPENSSL} dgst -sign $(get_signing_directives) -sha256 "${RPI_SB_WORKDIR}"/boot.img | xxd -c 4096 -p >> "${RPI_SB_WORKDIR}"/boot.sig - +if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then + "${OPENSSL}" dgst -sign "${CUSTOMER_KEY_PKCS11_NAME}" -engine pkcs11 -keyform engine -sha256 "${RPI_SB_WORKDIR}"/boot.img | xxd -c 4096 -p >> "${RPI_SB_WORKDIR}"/boot.sig +else + "${OPENSSL}" dgst -sign ${CUSTOMER_KEY_FILE_PEM} -keyform PEM -sha256 "${RPI_SB_WORKDIR}"/boot.img | xxd -c 4096 -p >> "${RPI_SB_WORKDIR}"/boot.sig +fi announce_stop "Finding/generating fastboot image" announce_start "Starting fastboot" @@ -893,7 +889,11 @@ if [ ! -e "${RPI_SB_WORKDIR}/bootfs-temporary.img" ] || sha256sum "${TMP_DIR}"/boot.img | awk '{print $1}' > "${TMP_DIR}"/boot.sig printf 'rsa2048: ' >> "${TMP_DIR}"/boot.sig # shellcheck disable=SC2046 - ${OPENSSL} dgst -sign $(get_signing_directives) -sha256 "${TMP_DIR}"/boot.img | xxd -c 4096 -p >> "${TMP_DIR}"/boot.sig + if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then + "${OPENSSL}" dgst -sign "${CUSTOMER_KEY_PKCS11_NAME}" -engine pkcs11 -keyform engine -sha256 "${TMP_DIR}"/boot.img | xxd -c 4096 -p >> "${TMP_DIR}"/boot.sig + else + "${OPENSSL}" dgst -sign ${CUSTOMER_KEY_FILE_PEM} -keyform PEM -sha256 "${TMP_DIR}"/boot.img | xxd -c 4096 -p >> "${TMP_DIR}"/boot.sig + fi announce_stop "boot.img signing" announce_start "Boot Image partition extraction" From 30b4b2ad786d65ae46db22109eeb2f55d4bc105a Mon Sep 17 00:00:00 2001 From: krygas-crane <94056625+krygas-crane@users.noreply.github.com> Date: Mon, 14 Apr 2025 13:48:54 +0200 Subject: [PATCH 2/2] Changes to restore get_signing_directives() Following the advise given earlier, I've modified my config file and restored the get_signing_directives(). With the modified config, everything appears to be working now and the image was loaded correctly. The config used: CUSTOMER_KEY_FILE_PEM= CUSTOMER_KEY_PKCS11_NAME='pkcs11:object=PIV%20AUTH%20key;type=private;pin-value=123456' GOLD_MASTER_OS_FILE=/media/kamil/sandisk/bookworm_2025_02_03.img/myimg.img RPI_DEVICE_STORAGE_TYPE=emmc RPI_DEVICE_STORAGE_CIPHER=xchacha12,aes-adiantum-plain64 RPI_DEVICE_FAMILY=4 RPI_DEVICE_BOOTLOADER_CONFIG_FILE=/home/kamil/Desktop/config_cm4_bookworm.txt RPI_DEVICE_LOCK_JTAG=1 RPI_DEVICE_EEPROM_WP_SET= RPI_DEVICE_FETCH_METADATA=1 RPI_DEVICE_RETRIEVE_KEYPAIR=/home/kamil/Desktop/keys DEMO_MODE_ONLY= RPI_SB_WORKDIR= RPI_SB_PROVISONER_MANUFACTURING_DB=/home/kamil/Desktop/provisioning-db.db --- service/rpi-sb-provisioner.sh | 43 +++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/service/rpi-sb-provisioner.sh b/service/rpi-sb-provisioner.sh index 7ddc9e6..6469d0e 100755 --- a/service/rpi-sb-provisioner.sh +++ b/service/rpi-sb-provisioner.sh @@ -105,6 +105,25 @@ timeout_fatal() { set -e } +get_signing_directives() { + if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then + echo "${CUSTOMER_KEY_PKCS11_NAME} -engine pkcs11 -keyform engine" + else + if [ -n "${CUSTOMER_KEY_FILE_PEM}" ]; then + if [ -f "${CUSTOMER_KEY_FILE_PEM}" ]; then + echo "${CUSTOMER_KEY_FILE_PEM} -keyform PEM" + else + echo "RSA private key \"${CUSTOMER_KEY_FILE_PEM}\" not a file. Aborting." >&2 + exit 1 + fi + else + echo "Neither PKCS11 key name, or PEM key file specified. Aborting." >&2 + exit 1 + fi + fi +} + + CUSTOMER_PUBLIC_KEY_FILE= derivePublicKey() { CUSTOMER_PUBLIC_KEY_FILE="$(mktemp)" @@ -131,15 +150,9 @@ writeSig() { # Include the update-timestamp echo "ts: $(date -u +%s)" >> "${OUTPUT}" - # shellcheck disable=SC2046 - - if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then - "${OPENSSL}" dgst -sign "${CUSTOMER_KEY_PKCS11_NAME}" -engine pkcs11 -keyform engine -sha256 -out "${SIG_TMP}" "${IMAGE}" - else - - "${OPENSSL}" dgst -sign ${CUSTOMER_KEY_FILE_PEM} -keyform PEM -sha256 -out "${SIG_TMP}" "${IMAGE}" - fi - echo "rsa2048: $(xxd -c 4096 -p < "${SIG_TMP}")" >> "${OUTPUT}" + # shellcheck disable=SC2046 + "${OPENSSL}" dgst -sign $(get_signing_directives) -sha256 -out "${SIG_TMP}" "${IMAGE}" + echo "rsa2048: $(xxd -c 4096 -p < "${SIG_TMP}")" >> "${OUTPUT}" rm "${SIG_TMP}" } @@ -687,11 +700,7 @@ sha256sum "${RPI_SB_WORKDIR}"/boot.img | awk '{print $1}' > "${RPI_SB_WORKDIR}"/ printf 'rsa2048: ' >> "${RPI_SB_WORKDIR}"/boot.sig # Prefer PKCS11 over PEM keyfiles, if both are specified. # shellcheck disable=SC2046 -if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then - "${OPENSSL}" dgst -sign "${CUSTOMER_KEY_PKCS11_NAME}" -engine pkcs11 -keyform engine -sha256 "${RPI_SB_WORKDIR}"/boot.img | xxd -c 4096 -p >> "${RPI_SB_WORKDIR}"/boot.sig -else - "${OPENSSL}" dgst -sign ${CUSTOMER_KEY_FILE_PEM} -keyform PEM -sha256 "${RPI_SB_WORKDIR}"/boot.img | xxd -c 4096 -p >> "${RPI_SB_WORKDIR}"/boot.sig -fi +${OPENSSL} dgst -sign $(get_signing_directives) -sha256 "${RPI_SB_WORKDIR}"/boot.img | xxd -c 4096 -p >> "${RPI_SB_WORKDIR}"/boot.sig announce_stop "Finding/generating fastboot image" announce_start "Starting fastboot" @@ -889,11 +898,7 @@ if [ ! -e "${RPI_SB_WORKDIR}/bootfs-temporary.img" ] || sha256sum "${TMP_DIR}"/boot.img | awk '{print $1}' > "${TMP_DIR}"/boot.sig printf 'rsa2048: ' >> "${TMP_DIR}"/boot.sig # shellcheck disable=SC2046 - if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then - "${OPENSSL}" dgst -sign "${CUSTOMER_KEY_PKCS11_NAME}" -engine pkcs11 -keyform engine -sha256 "${TMP_DIR}"/boot.img | xxd -c 4096 -p >> "${TMP_DIR}"/boot.sig - else - "${OPENSSL}" dgst -sign ${CUSTOMER_KEY_FILE_PEM} -keyform PEM -sha256 "${TMP_DIR}"/boot.img | xxd -c 4096 -p >> "${TMP_DIR}"/boot.sig - fi + ${OPENSSL} dgst -sign $(get_signing_directives) -sha256 "${TMP_DIR}"/boot.img | xxd -c 4096 -p >> "${TMP_DIR}"/boot.sig announce_stop "boot.img signing" announce_start "Boot Image partition extraction"