Compare commits

...

18 Commits

Author SHA1 Message Date
Tim Gover
1bb6edeff5 pieeprom-2025-05-08: 2711: Promote to the default release 2025-05-13 19:45:02 +01:00
Tim Gover
ce78b31476 pieeprom-2025-05-08: 2712: Promote to the default release 2025-05-13 19:45:02 +01:00
Tim Gover
cd4048df1d pieeprom-2025-05-08: 2711: Implement TCP window for net boot (latest)
Fixup the previous commit to include the 2711 firmware signed
with the secure-boot key.
2025-05-08 16:25:13 +01:00
Tim Gover
96af2e81c7 pieeprom-2025-02-24: 2711: Implement TCP window for net boot (latest)
* Signed boot and HTTP boot mode
  HTTP boot mode is supposed to be disabled if signed boot is enabled and
  a host is not specified. The code is checking the http_secure flag to
  enforce this. But this is valid now we support custom CA certs.
  Only disable HTTP mode if we're using the default HOST.
* Implement TCP window for net boot
  The minimal IP stack used for https booting lacks the ability to cache
  packets received out of order, which can lead to severe slowdown when
  it happens. The problem seems to affect some ISPs more than others.
  The receive window implemented here copes with packet losses of 10%.
* netboot: Correct the TCP MSS
* Correct msecs in debug timestamps
  The fractional part of timestamps in UART debug output was showing the
  100ths and 1000ths of a second, rather than 10ths and 100ths, causing
  strange sequences that appear to jump backwards.
2025-05-08 16:10:16 +01:00
Tim Gover
d584a84891 pieeprom-2025-05-08: 2712: Implement TCP window for net boot (latest)
* arm_loader: Correct some mailbox response lengths
  The GET_GENCMD_RESULT mailbox handler was setting the wrong response
  length, and GET_FIRMWARE_COMMIT_HASH and GET_FIRMWARE_VARIANT were not
  setting any length.
  See: https://github.com/raspberrypi/firmware/issues/1968
* Signed boot and HTTP boot mode
  HTTP boot mode is supposed to be disabled if signed boot is enabled and
  a host is not specified. The code is checking the http_secure flag to
  enforce this. But this is valid now we support custom CA certs.
  Only disable HTTP mode if we're using the default HOST.
* Implement TCP window for net boot
  The minimal IP stack used for https booting lacks the ability to cache
  packets received out of order, which can lead to severe slowdown when
  it happens. The problem seems to affect some ISPs more than others.
  The receive window implemented here copes with packet losses of 10%.
* netboot: Correct the TCP MSS
* rp1_net: Overwrite the length field
  Although concise, ORing in the packet length runs the risk of leaving
  some unwanted bits set. Ensure the length field is cleared before
  ORing in the required value.
* Correct msecs in debug timestamps
  The fractional part of timestamps in UART debug output was showing the
  100ths and 1000ths of a second, rather than 10ths and 100ths, causing
  strange sequences that appear to jump backwards.
* Implement GET_BOARD_MAC_ADDRESS on Pi5
  The Pi 5 EEPROM implements a subset of the original mailbox properties.
  Add GET_BOARD_MAC_ADDRESS to the subset.
  See: https://github.com/raspberrypi/rpi-eeprom/issues/698
* Ensure the initramfs matches the kernel
  As far as is possible, both the kernel and initramfs are matched to the
  device. However, where multiple kernel variants can run on a device, the
  initramfs must be matched to the chosen kernel. Make that the sole rule
  for initramfs selection, rather than duplicating the device matching
  logic.
  See: https://github.com/raspberrypi/firmware/issues/1965
* Enable logging messages from OS loader
  Pi 5 EEPROM builds were missing the output from the main OS loading
  function, including some important diagnostics. Enabling the logging
  output from this loader code results in some near-duplicates, but is
  more user friendly and is available via "sudo vclog -m".
2025-05-08 15:26:30 +01:00
Tim Gover
816bf7c594 test: Add a README 2025-04-08 10:22:17 +01:00
Tim Gover
f087342b26 test: Add github workflow for test-rpi-eeprom-config 2025-04-08 09:35:58 +01:00
Tim Gover
17a9f162c9 pieeprom-2025-04-07: 2712: Revert to using the max fan speed (latest)
* arm_dt: Revert to using the max fan speed
  It has been reported that the presence of a cooling fan at boot time
  can lead to a maximum observed fan speed of ~300 but a current speed
  of 0. The absence of a fan results in 0s for both metrics.
  See: https://github.com/raspberrypi/rpi-eeprom/issues/690
2025-04-08 08:07:22 +01:00
Tim Gover
914dd0f73f rpi-sign-bootcode: Add optional callout to HSM wrapper script from PKCS#1 v1.5 signature 2025-04-07 09:51:17 +01:00
Tim Gover
7f66ffe483 pieeprom-2025-03-27: 2712: os_check: cm5: Check for CM5 specific DTBs (latest)
* os_check: cm5: Check for CM5 specific dtbs
  Check for BCM2712 support in bcm2712-rpi-cm5-cm5io.dtb
  or bcm2712-rpi-cm5l-cm5io.dtb on CM5 instead of bcm2712-rpi-5-b.dtb.
  This avoids needing to put os_check=1 or specifying device_tree
  in config.txt in minimal images for CM5.
  See: https://github.com/raspberrypi/rpi-eeprom/issues/682
2025-03-27 11:52:01 +00:00
Nicolai Buchwitz
1bd0a1052b bug_report template: Add missing CM5 + pi500
Signed-off-by: Nicolai Buchwitz <n.buchwitz@kunbus.com>
2025-03-21 13:24:58 +00:00
Tim Gover
6c2e2d6833 pieeprom-2025-03-19: 2712: Log the fan speed at boot (latest)
* Log the fan speed at boot
  Record the fan RPM (and the maximum seen) during boot, so that it is
  accessible using "sudo vclog -m".
  See: https://github.com/raspberrypi/rpi-eeprom/issues/678
* Add current_supply to HAT+ support
  Refactor the HAT library to make it more self-contained, and combine
  the I2C address detection and the reading of the EEPROM contents.
  Use it to allow the earlier boot stages to check for a current_supply
  setting in the EEPROM of a normal (non-stackable) HAT+.
2025-03-19 17:06:49 +00:00
Tim Gover
78d08e9763 firmware: 2712: Archive old '2712' 'latest' firmware
Following the update of the 'default' release to 2025-03-10
archive the older firmware releases to reduce the size of the APT
package.
2025-03-12 14:07:48 +00:00
Tim Gover
92488a202f pieeprom-2025-03-10-12: Promote 2025-10-03 to the default release 2025-03-12 14:07:48 +00:00
Tim Gover
d50b2b32f1 pieeprom-2025-03-10: 2712: Add [boot_partition] filter plus SDRAM init fixes (latest)
* Update SDRAM init timings to intermittent 8-flash SDRAM init errors
  on some boards.
  See: https://github.com/raspberrypi/rpi-eeprom/issues/67
* config: Fix missing initialisation of selected_expr to 1 in config.txt
  Without an [all] section the new expression filter might default to
  false. This impacts the bootloader early parsing of config.txt
  for things like boot_ramdisk rather than the later config.txt pass
  for device-tree parsing.
* config_loader: Add support [boot_partition=N] as an expression filter
  The boot_partition tests whether the partition number N matches
  the number that the system is booting from. This expression is
  only supported in config.txt and is designed to make it easier
  to have common boot.img ramdisks in an A/B system where the
  conditional loads a different cmdline.txt file depending on
  which partition boot.img is loaded from.
2025-03-10 17:24:25 +00:00
Rasmus Villemoes
3a16bd016f rpi-eeprom-digest: support specifying keys via PKCS#11 URI
In production setups, it is quite normal that the private key does not
exist as a file in the file system, but is kept inside some HSM,
remote signing service or similar, and only accessed via some pkcs#11
interface; moreover, by design, the private key _cannot_ be extracted
from the HSM or signing service.

In such a case, the user will have set OPENSSL_CONF to some
configuration file setting up the appropriate engine, and the "key" is
simply the pkcs#11 URI, e.g. "pkcs11:model=foo;object=bar".

In order to support this use case, automatically infer the appropriate
options to pass to openssl-dgst if "${KEY}" begins with
"pkcs11:". Doing this at the top level avoids duplicating the logic in
both writeSig and verifySig. While here, this also adds a sanity check
that -v can only be used while also providing a (public) key to check
against.

This drops the -keyform argument in the non-pkcs#11 case, as openssl
automatically infers the type, and this then in fact allows one to use
a private key in e.g. DER format.

Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
2025-03-06 16:04:38 +00:00
Tim Gover
28a2c0242c pieeprom-2025-03-03: 2712: Fix bootloader pull configuration on BCM2712D0 (latest)
* Fix pull configuration on 2712D0
  2712D0 uses a horrendously sparse set of pad control registers. Make
  the pull-setting code sufficiently complex to cope.
  See: https://github.com/raspberrypi/rpi-eeprom/issues/672
* Disable UARTA for CM5s without WiFi
  Just as CM5s without WiFI don't need the SDIO interface, the Bluetooth
  UART is unconnected. Disable the DT node to avoid kernel warnings and
  save some cycles.
2025-03-03 15:18:20 +00:00
Tim Gover
8eef29aed9 image: Update 2711 plus 2712 images and enable boot-menu on 2711 2025-02-18 12:19:00 +00:00
41 changed files with 292 additions and 53 deletions

View File

@@ -40,8 +40,11 @@ body:
multiple: true
options:
- Raspberry Pi 5
- Raspberry Pi 500
- Raspberry Pi 4 Mod. B
- Raspberry Pi 400
- Raspberry Pi CM5
- Raspberry Pi CM5 Lite
- Raspberry Pi CM4
- Raspberry Pi CM4 Lite
- Raspberry Pi CM4-S

31
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Test EEPROM Config
on:
pull_request:
branches: [ 'master' ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Create and activate virtual environment
run: |
python -m venv venv
source venv/bin/activate
- name: Install dependencies
run: |
pip install pycryptodomex
- name: Run EEPROM Config Tests
run: |
cd test
chmod +x test-rpi-eeprom-config
./test-rpi-eeprom-config

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,24 @@
# Raspberry Pi4 bootloader EEPROM release notes
## 2025-05-13: Promote 2025-05-08 to the default release (default)
## 2025-05-08: Implement TCP window for net boot (latest)
* Signed boot and HTTP boot mode
HTTP boot mode is supposed to be disabled if signed boot is enabled and
a host is not specified. The code is checking the http_secure flag to
enforce this. But this is valid now we support custom CA certs.
Only disable HTTP mode if we're using the default HOST.
* Implement TCP window for net boot
The minimal IP stack used for https booting lacks the ability to cache
packets received out of order, which can lead to severe slowdown when
it happens. The problem seems to affect some ISPs more than others.
The receive window implemented here copes with packet losses of 10%.
* netboot: Correct the TCP MSS
* Correct msecs in debug timestamps
The fractional part of timestamps in UART debug output was showing the
100ths and 1000ths of a second, rather than 10ths and 100ths, causing
strange sequences that appear to jump backwards.
## 2025-02-17: Promote 2025-02-11 to default release (default)
## 2025-02-11: recovery: Walk partitions to delete recovery.bin (latest)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,110 @@
# Raspberry Pi5 bootloader EEPROM release notes
## 2025-05-13: Promote 2025-05-08 to the default release (default)
## 2025-05-08: Implement TCP window for net boot (latest)
* arm_loader: Correct some mailbox response lengths
The GET_GENCMD_RESULT mailbox handler was setting the wrong response
length, and GET_FIRMWARE_COMMIT_HASH and GET_FIRMWARE_VARIANT were not
setting any length.
See: https://github.com/raspberrypi/firmware/issues/1968
* Signed boot and HTTP boot mode
HTTP boot mode is supposed to be disabled if signed boot is enabled and
a host is not specified. The code is checking the http_secure flag to
enforce this. But this is valid now we support custom CA certs.
Only disable HTTP mode if we're using the default HOST.
* Implement TCP window for net boot
The minimal IP stack used for https booting lacks the ability to cache
packets received out of order, which can lead to severe slowdown when
it happens. The problem seems to affect some ISPs more than others.
The receive window implemented here copes with packet losses of 10%.
* netboot: Correct the TCP MSS
* rp1_net: Overwrite the length field
Although concise, ORing in the packet length runs the risk of leaving
some unwanted bits set. Ensure the length field is cleared before
ORing in the required value.
* Correct msecs in debug timestamps
The fractional part of timestamps in UART debug output was showing the
100ths and 1000ths of a second, rather than 10ths and 100ths, causing
strange sequences that appear to jump backwards.
* Implement GET_BOARD_MAC_ADDRESS on Pi5
The Pi 5 EEPROM implements a subset of the original mailbox properties.
Add GET_BOARD_MAC_ADDRESS to the subset.
See: https://github.com/raspberrypi/rpi-eeprom/issues/698
* Ensure the initramfs matches the kernel
As far as is possible, both the kernel and initramfs are matched to the
device. However, where multiple kernel variants can run on a device, the
initramfs must be matched to the chosen kernel. Make that the sole rule
for initramfs selection, rather than duplicating the device matching
logic.
See: https://github.com/raspberrypi/firmware/issues/1965
* Enable logging messages from OS loader
Pi 5 EEPROM builds were missing the output from the main OS loading
function, including some important diagnostics. Enabling the logging
output from this loader code results in some near-duplicates, but is
more user friendly and is available via "sudo vclog -m".
## 2025-04-07: arm_dt: Revert to using the max fan speed (latest)
* arm_dt: Revert to using the max fan speed
It has been reported that the presence of a cooling fan at boot time
can lead to a maximum observed fan speed of ~300 but a current speed
of 0. The absence of a fan results in 0s for both metrics.
See: https://github.com/raspberrypi/rpi-eeprom/issues/690
## 2025-03-27: os_check: cm5: Check for CM5 specific dtbs (latest)
* os_check: cm5: Check for CM5 specific dtbs
Check for BCM2712 support in bcm2712-rpi-cm5-cm5io.dtb
or bcm2712-rpi-cm5l-cm5io.dtb on CM5 instead of bcm2712-rpi-5-b.dtb.
This avoids needing to put os_check=1 or specifying device_tree
in config.txt in minimal images for CM5.
See: https://github.com/raspberrypi/rpi-eeprom/issues/682
## 2025-03-19: Log the fan speed at boot (latest)
* Log the fan speed at boot
Record the fan RPM (and the maximum seen) during boot, so that it is
accessible using "sudo vclog -m".
See: https://github.com/raspberrypi/rpi-eeprom/issues/678
* Add current_supply to HAT+ support
Refactor the HAT library to make it more self-contained, and combine
the I2C address detection and the reading of the EEPROM contents.
Use it to allow the earlier boot stages to check for a current_supply
setting in the EEPROM of a normal (non-stackable) HAT+.
## 2025-03-10: Promote 2025-03-10 release to default (default)
## 2025-03-10: Add [boot_partition] filter plus SDRAM init fixes (latest)
* Update SDRAM init timings to intermittent 8-flash SDRAM init errors
on some boards.
See: https://github.com/raspberrypi/rpi-eeprom/issues/67
* config: Fix missing initialisation of selected_expr to 1 in config.txt
Without an [all] section the new expression filter might default to
false. This impacts the bootloader early parsing of config.txt
for things like boot_ramdisk rather than the later config.txt pass
for device-tree parsing.
* config_loader: Add support [boot_partition=N] as an expression filter
The boot_partition tests whether the partition number N matches
the number that the system is booting from. This expression is
only supported in config.txt and is designed to make it easier
to have common boot.img ramdisks in an A/B system where the
conditional loads a different cmdline.txt file depending on
which partition boot.img is loaded from.
## 2025-03-03: Fix bootloader pull configuration on 2712D0 (latest)
* Fix pull configuration on 2712D0
2712D0 uses a horrendously sparse set of pad control registers. Make
the pull-setting code sufficiently complex to cope.
See: https://github.com/raspberrypi/rpi-eeprom/issues/672
* Disable UARTA for CM5s without WiFi
Just as CM5s without WiFI don't need the SDIO interface, the Bluetooth
UART is unconnected. Disable the DT node to avoid kernel warnings and
save some cycles.
## 2025-02-17: Promote 2025-02-12 to the default release (default)
## 2025-02-12: Fixup change to disable 3.7V PMIC output on CM5 no-wifi (latest)

View File

@@ -3,4 +3,5 @@ BOOT_UART=0
WAKE_ON_GPIO=1
ENABLE_SELF_UPDATE=1
BOOT_ORDER=0xf21
NET_INSTALL_AT_POWER_ON=1

View File

@@ -3,4 +3,4 @@ BOOT_UART=0
WAKE_ON_GPIO=1
ENABLE_SELF_UPDATE=1
BOOT_ORDER=0xf41
NET_INSTALL_AT_POWER_ON=1

View File

@@ -3,4 +3,5 @@ BOOT_UART=0
WAKE_ON_GPIO=1
ENABLE_SELF_UPDATE=1
BOOT_ORDER=0xf14
NET_INSTALL_AT_POWER_ON=1

View File

@@ -5,7 +5,7 @@ set -e
script_dir=$(cd "$(dirname "$0")" && pwd)
# Pi4, Pi400, CM4, CM4-S
${script_dir}/make-release critical 2023-01-11 000138c0 "${script_dir}/2711-config" release-2711 rpi-boot-eeprom-recovery 2711
${script_dir}/make-release critical 2025-02-11 000138c0 "${script_dir}/2711-config" release-2711 rpi-boot-eeprom-recovery 2711
# Pi5
${script_dir}/make-release critical 2025-01-22 "" "${script_dir}/2712-config" release-2712 rpi-boot-eeprom-recovery 2712
${script_dir}/make-release critical 2025-02-12 "" "${script_dir}/2712-config" release-2712 rpi-boot-eeprom-recovery 2712

View File

@@ -6,8 +6,12 @@
# a hard dependency on OpenSSL.
set -e
set -u
OPENSSL=${OPENSSL:-openssl}
KEY=""
SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-""}
HSM_WRAPPER=""
die() {
echo "$@" >&2
@@ -46,28 +50,30 @@ RSA signature. Typically this tool is used by rpi-eeprom-update to
generate a hash to guard against file-system corruption for EEPROM updates
OR for signing OS images (boot.img) for secure-boot.
This tool CANNOT be used directly to sign an bootloader EEPROM image
for secure-boot because the signed data is bootloader configuration file
This tool CANNOT be used directly to sign a bootloader EEPROM image
for secure-boot because the signed data is the bootloader configuration file
rather than the entire flash image.
To create signed bootloader images please see
To create signed bootloader images, please see
https://github.com/raspberrypi/usbboot/tree/master/secure-boot-recovery/README.md
Options:
-i The source image e.g. boot.img
-o The name of the digest/signature file.
-k Optional RSA private key.
-i The source image, e.g., boot.img
-o The name of the digest/signature file
-k Optional RSA private key
-H The name of the HSM wrapper script to invoke - default ""
RSA signing
If a private key in PEM format is supplied then the RSA signature of the
sha256 digest is included in the .sig file. Currently, the bootloader only
supports sha256 digests signed with a 2048bit RSA key.
The bootloader only verifies RSA signatures in signed boot mode
and only for the EEPROM config file and the signed image.
RSA signing:
If a private key in PEM format or a PKCS#11 URI is supplied, then the
RSA signature of the SHA256 digest is included in the .sig
file. Currently, the bootloader only supports SHA256 digests signed
with a 2048-bit RSA key. The bootloader only verifies RSA signatures
in signed boot mode and only for the EEPROM config file and the signed
image.
Examples:
# Generate the normal sha256 hash to guard against file-system corruption
# Generate the normal SHA256 hash to guard against file-system corruption
rpi-eeprom-digest -i pieeprom.bin -o pieeprom.sig
rpi-eeprom-digest -i vl805.bin -o vl805.sig
@@ -76,7 +82,15 @@ rpi-eeprom-digest -k private.pem -i boot.img -o boot.sig
# Generate RSA signature for the EEPROM config file
# As used by update-pieeprom.sh in usbboot/secure-boot-recovery
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
# Generate RSA signature for the EEPROM config file and delegate
# the signing process to a HSM wrapper script instead of using the private key directly.
rpi-eeprom-digest -H hsm-wrapper -i bootconf.txt -o bootconf.sig
# Similarly, but specifying the key with a PKCS#11 URI
# (Deprecated - use HSM wrapper instead)
rpi-eeprom-digest -k pkcs11:token=deadbeef;object=bl-key;type=private;pin-value=1234 -i bootconf.txt -o bootconf.sig
# To verify the signature of an existing .sig file using the public key.
# N.B The key file must be the PUBLIC key in PEM format.
@@ -98,9 +112,10 @@ writeSig() {
echo "ts: $(date -u +%s)" >> "${OUTPUT}"
fi
if [ -n "${KEY}" ]; then
[ -f "${KEY}" ] || die "RSA private \"${KEY}\" not found"
"${OPENSSL}" dgst -sign "${KEY}" -keyform PEM -sha256 -out "${SIG_TMP}" "${IMAGE}"
if [ -n "${HSM_WRAPPER}" ]; then
echo "rsa2048: $("${HSM_WRAPPER}" -a rsa2048-sha256 "${IMAGE}")" >> "${OUTPUT}"
elif [ -n "${KEY}" ]; then
"${OPENSSL}" dgst ${ENGINE_OPTS} -sign "${KEY}" -sha256 -out "${SIG_TMP}" "${IMAGE}"
echo "rsa2048: $(xxd -c 4096 -p < "${SIG_TMP}")" >> "${OUTPUT}"
fi
}
@@ -112,18 +127,20 @@ verifySig() {
sig_hex="$(grep rsa2048 "${sig_file}" | cut -f 2 -d ' ')"
[ -n "${sig_hex}" ] || die "No RSA signature in ${sig_file}"
echo ${sig_hex} | xxd -c 4096 -p -r > "${TMP_DIR}/sig.bin"
"${OPENSSL}" dgst -verify "${KEY}" -signature "${TMP_DIR}/sig.bin" "${IMAGE}" || die "${IMAGE} not verified"
echo "${sig_hex}" | xxd -c 4096 -p -r > "${TMP_DIR}/sig.bin"
"${OPENSSL}" dgst ${ENGINE_OPTS} -verify "${KEY}" -signature "${TMP_DIR}/sig.bin" "${IMAGE}" || die "${IMAGE} not verified"
}
OUTPUT=""
VERIFY=0
while getopts i:k:ho:v: option; do
while getopts i:H:k:ho:v: option; do
case "${option}" in
i) IMAGE="${OPTARG}"
;;
k) KEY="${OPTARG}"
;;
H) HSM_WRAPPER="${OPTARG}"
;;
o) OUTPUT="${OPTARG}"
;;
v) SIGNATURE="${OPTARG}"
@@ -142,6 +159,18 @@ checkDependencies
[ -n "${IMAGE}" ] || usage
[ -f "${IMAGE}" ] || die "Source image \"${IMAGE}\" not found"
[ "${VERIFY}" != 1 ] || [ -n "${KEY}" ] || die "Option -v also requires passing public key via -k"
if [ -n "${KEY}" ] ; then
if [ -f "${KEY}" ] ; then
ENGINE_OPTS=
elif echo "${KEY}" | grep -q "^pkcs11:" ; then
ENGINE_OPTS="-engine pkcs11 -keyform engine"
else
die "RSA key \"${KEY}\" not found"
fi
fi
if [ "${VERIFY}" = 1 ]; then
verifySig "${SIGNATURE}"
else

14
test/README.md Normal file
View File

@@ -0,0 +1,14 @@
# rpi-eeprom - unit tests
## test-rpi-eeprom-config
Unit test for rpi-eeprom-config which verifies:
* rpi-eeprom-config is compatible with all EEPROM binaries
* unit tests for modifying the boot.conf file
* simple code signing test
To run on Linux:
```
cd test
./test-rpi-eeprom-config
```

View File

@@ -2,8 +2,11 @@
import argparse
import base64
import os
import struct
import subprocess
import sys
import tempfile
# python3 -m pip install pycryptodomex
from Cryptodome.Hash import HMAC, SHA1, SHA256
@@ -105,6 +108,30 @@ class ImageFile:
debug("%08x %20s: [%6d] %s" % (self.pos(), 'RSA', len(arr), pem_file))
self.append(arr)
h = SHA256.new()
h.update(key.n.to_bytes(256, byteorder='little'))
h.update(key.e.to_bytes(8, byteorder='little'))
d = h.hexdigest()
pub_str = ""
for i in range(int(len(d)/8)):
pub_str += "0x%s%s%s%s, " % (d[i*8+6:i*8+8], d[i*8+4:i*8+6], d[i*8+2:i*8+4], d[i*8+0:i*8+2])
debug("Public key SHA256(N,e) = %s" % pub_str)
def append_rsa_signature_pkcs11(self, hsm_wrapper):
temp = tempfile.NamedTemporaryFile(delete=False)
temp.write(self._bytes)
temp.close() # close and flush before spawning PKCS#11 wrapper
res = subprocess.run([hsm_wrapper, "-a", "rsa2048-sha256", temp.name], capture_output=True)
debug(res.stderr)
if res.returncode != 0:
os.unlink(temp.name)
raise Exception(f"HSM wrapper failed with exit code {res.returncode}: {res.stderr.decode()}")
signature = res.stdout.decode()
os.unlink(temp.name)
self.append(bytearray.fromhex(signature))
debug("PKCS11 %08x %20s: [%6d] signature %s" % (self.pos(), 'RSA2048 - SHA256', len(signature), signature))
def append_rsa_signature(self, digest_alg, private_pem):
"""
Append a RSA 2048 signature of the SHA256 of the data so far
@@ -132,19 +159,13 @@ class ImageFile:
if len(hmac_key) != expected_keylen:
raise Exception("Bad key length %d expected %d" % (len(hmac_key), expected_keylen))
if digest_alg == 'hmac-sha256':
digest = HMAC.new(base64.b16decode(hmac_key, True), self._bytes, digestmod=SHA256)
elif digest_alg == 'hmac-sha1':
digest = HMAC.new(base64.b16decode(hmac_key, True), self._bytes, digestmod=SHA1)
elif digest_alg == 'sha256':
digest = SHA256.new(self._bytes)
elif digest_alg == 'sha1':
digest = SHA1.new(self._bytes)
if digest_alg == 'hmac-sha1':
h = HMAC.new(base64.b16decode(hmac_key, True), self._bytes, digestmod=SHA1)
else:
raise Exception("Digest not supported %s" % (digest_alg))
debug("%08x %20s: [%6d] %s" % (self.pos(), digest_alg, len(digest.digest()), digest.hexdigest()))
self.append(digest.digest())
debug("%08x %20s: [%6d] %s" % (self.pos(), digest_alg, len(h.digest()), h.hexdigest()))
self.append(h.digest())
def pos(self):
return len(self._bytes)
@@ -161,7 +182,7 @@ class ImageFile:
def close(self):
self._of.close()
def create_2711_image(output, bootcode, private_key, private_keynum, hmac):
def create_2711_image(output, bootcode, private_key=None, private_keynum=0, hmac=None, hsm_wrapper=None):
"""
Create a 2711 C0 secure-boot compatible seconds stage signed binary.
"""
@@ -169,22 +190,31 @@ def create_2711_image(output, bootcode, private_key, private_keynum, hmac):
image.append_file(bootcode)
image.append_length()
image.append_keynum(private_keynum)
image.append_rsa_signature('sha1', private_key)
if hsm_wrapper:
image.append_rsa_signature_pkcs11(hsm_wrapper)
else:
image.append_rsa_signature('sha1', private_key)
image.append_digest('hmac-sha1', hmac)
image.write()
image.close()
def create_2712_image(output, bootcode, private_key, private_keynum, private_version):
def create_2712_image(output, bootcode, private_version=0, public_key=None, private_key=None, private_keynum=0, hsm_wrapper=None):
"""
Create 2712 signed bootloader. The HMAC is removed and the full public key is appended.
Create a prototype 2712 signed bootloader. The HMAC is removed and the
full public key is appended.
"""
image = ImageFile(output, MAX_BIN_SIZE)
image.append_file(bootcode)
image.append_length()
image.append_keynum(private_keynum)
image.append_version(private_version)
image.append_rsa_signature('sha256', private_key)
image.append_public_key(private_key)
if hsm_wrapper is not None:
debug(f"Call HSM wrapper {hsm_wrapper}")
image.append_rsa_signature_pkcs11(hsm_wrapper)
image.append_public_key(public_key)
else:
image.append_rsa_signature('sha256', private_key)
image.append_public_key(private_key)
image.write()
image.close()
@@ -193,37 +223,43 @@ def main():
Signs a second stage bootloader image.
Examples:
2711 mode:
rpi-sign-bootcode --debug -c 2711 -i bootcode.bin.clr -o bootcode.bin -k 2711_rsa_priv_0.pem -n 0 -m bootcode-production.key
2712 C1 and D0 mode:
* HMAC not included on 2712
* RSA public key included - ROM just contains the hashes of the RPi public keys.
Customer counter-signed signed:
Customer counter-signed:
* Exactly the same as Raspberry Pi signing but the input is the Raspberry Pi signed bootcode.bin
* The key number will probably always be 16 to indicate a customer signing
rpi-sign-bootcode --debug -c 2712 -i bootcode.bin.sign2 -o bootcode.bin -k customer.pem
PKCS#1 v1.5 - HSM wrapper:
* hsm-wrapper takes a single argument which is a temporary filename containing the data to sign
* hsm-wrapper outputs the PKCS#1 v1.5 signature in hex format
* hsm-wrapper must return a non-zero exit code if signing fails
* hsm-wrapper requires the -a rsa2048-sha256 parameter to specify the algorithm
* There is no facility to pass the private key or custom HSM arguments - the caller should generate a dedicated wrapper script
* The public key in PEM format MUST be specified with the -p option
rpi-sign-bootcode --debug -c 2712 -i bootcode.bin.sign2 -o bootcode.bin -p public.pem -H hsm-wrapper
"""
parser = argparse.ArgumentParser(help_text)
parser.add_argument('-o', '--output', required=False, help='Output filename . If not specified the signed images is written to stdout in base64 format')
parser.add_argument('-o', '--output', required=False, help='Output filename. If not specified, the signed image is written to stdout in base64 format')
parser.add_argument('-c', '--chip', required=True, type=int, help='Chip number')
parser.add_argument('-i', '--input', required=False, help='Path of the unsigned bootcode.bin file OR RPi signed bootcode file sign with the customer key. If NULLL the binary is read from stdin in base64 format')
parser.add_argument('-i', '--input', required=False, help='Path of the unsigned bootcode.bin file OR RPi signed bootcode file to be signed with the customer key. If NULL, the binary is read from stdin in base64 format')
parser.add_argument('-m', '--hmac', required=False, help='Path of the HMAC key file')
parser.add_argument('-k', '--private-key', dest='private_key', required=True, help='Path of RSA private key (PEM format)')
parser.add_argument('-k', '--private-key', dest='private_key', required=False, default=None, help='Path of RSA private key (PEM format)')
parser.add_argument('-p', '--public-key', dest='public_key', required=False, default=None, help='Path of RSA public key (PEM format)')
parser.add_argument('-n', '--private-keynum', dest='private_keynum', required=False, default=0, type=int, help='ROM key index for RPi signing stage')
parser.add_argument('-H', '--hsm-wrapper', default=None, required=False, help='Filename of HSM wrapper script which generates a PKCSv1.1 signature as hex')
parser.add_argument('-d', '--debug', action='store_true')
parser.add_argument('-v', '--private-version', dest='private_version', required=True, type=int, help='Version of firmware, stops firmware rollback, only valid 0-31')
parser.add_argument('-v', '--private-version', dest='private_version', required=False, default=0, type=int, help='Version of firmware, stops firmware rollback, only valid 0-31')
args = parser.parse_args()
_CONFIG['DEBUG'] = args.debug
if args.chip == 2711:
if args.hmac is None:
raise Exception("HMAC key requried for 2711")
create_2711_image(args.output, args.input, args.private_key, args.private_keynum, args.hmac)
create_2711_image(args.output, args.input, private_key=args.private_key, private_keynum=args.private_keynum, hmac=args.hmac, hsm_wrapper=args.hsm_wrapper)
elif args.chip == 2712:
create_2712_image(args.output, args.input, args.private_key, args.private_keynum, args.private_version)
create_2712_image(args.output, args.input, private_version=args.private_version, public_key=args.public_key, private_key=args.private_key, private_keynum=args.private_keynum, hsm_wrapper=args.hsm_wrapper)
if __name__ == '__main__':
main()