mirror of
https://github.com/raspberrypi/rpi-eeprom.git
synced 2026-01-20 21:13:36 +08:00
Merge branch 'master' into debian/buster
This commit is contained in:
BIN
firmware/beta/pieeprom-2021-11-22.bin
Executable file
BIN
firmware/beta/pieeprom-2021-11-22.bin
Executable file
Binary file not shown.
Binary file not shown.
@@ -3,6 +3,10 @@
|
||||
USB MSD boot also requires the firmware from Raspberry Pi OS 2020-08-20 or newer.
|
||||
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-4-bootloader-configuration
|
||||
|
||||
## 2021-11-22 - Fix for Sabrent rocket Nano NVMe reboot issue - BETA
|
||||
* Fixes issue with Sabrent rocket Nano NVMe disk after a reboot.
|
||||
Run pcie initialisation again if there's an error.
|
||||
|
||||
## 2021-10-27 - Secure boot improvements - BETA
|
||||
* Improve the error logging if a file is too large and truncated.
|
||||
* Increase the maximum size of the ramdisk to 96MB.
|
||||
|
||||
@@ -8,6 +8,7 @@ import argparse
|
||||
import atexit
|
||||
import os
|
||||
import subprocess
|
||||
import string
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -15,7 +16,12 @@ import time
|
||||
|
||||
IMAGE_SIZE = 512 * 1024
|
||||
|
||||
MAX_BOOTCONF_SIZE = 2024
|
||||
# Larger files won't with with "vcgencmd bootloader_config"
|
||||
MAX_FILE_SIZE = 2024
|
||||
ALIGN_SIZE = 4096
|
||||
BOOTCONF_TXT = 'bootconf.txt'
|
||||
BOOTCONF_SIG = 'bootconf.sig'
|
||||
PUBKEY_BIN = 'pubkey.bin'
|
||||
|
||||
# Each section starts with a magic number followed by a 32 bit offset to the
|
||||
# next section (big-endian).
|
||||
@@ -26,12 +32,18 @@ MAX_BOOTCONF_SIZE = 2024
|
||||
# The last 4KB of the EEPROM image is reserved for internal use by the
|
||||
# bootloader and may be overwritten during the update process.
|
||||
MAGIC = 0x55aaf00f
|
||||
PAD_MAGIC = 0x55aafeef
|
||||
MAGIC_MASK = 0xfffff00f
|
||||
FILE_MAGIC = 0x55aaf11f # id for modifiable file, currently only bootconf.txt
|
||||
FILE_MAGIC = 0x55aaf11f # id for modifiable files
|
||||
FILE_HDR_LEN = 20
|
||||
FILENAME_LEN = 12
|
||||
TEMP_DIR = None
|
||||
|
||||
DEBUG = False
|
||||
def debug(s):
|
||||
if DEBUG:
|
||||
sys.stderr.write(s + '\n')
|
||||
|
||||
def rpi4():
|
||||
compatible_path = "/sys/firmware/devicetree/base/compatible"
|
||||
if os.path.exists(compatible_path):
|
||||
@@ -59,6 +71,25 @@ def create_tempdir():
|
||||
if TEMP_DIR is None:
|
||||
TEMP_DIR = tempfile.mkdtemp()
|
||||
|
||||
def pemtobin(infile):
|
||||
"""
|
||||
Converts an RSA public key into the format expected by the bootloader.
|
||||
"""
|
||||
# Import the package here to make this a weak dependency.
|
||||
from Cryptodome.PublicKey import RSA
|
||||
|
||||
arr = bytearray()
|
||||
f = open(infile,'r')
|
||||
key = RSA.importKey(f.read())
|
||||
|
||||
if key.size_in_bits() != 2048:
|
||||
raise Exception("RSA key size must be 2048")
|
||||
|
||||
# Export N and E in little endian format
|
||||
arr.extend(key.n.to_bytes(256, byteorder='little'))
|
||||
arr.extend(key.e.to_bytes(8, byteorder='little'))
|
||||
return arr
|
||||
|
||||
def exit_error(msg):
|
||||
"""
|
||||
Trapped a fatal error, output message to stderr and exit with non-zero
|
||||
@@ -109,15 +140,21 @@ def apply_update(config, eeprom=None, config_src=None):
|
||||
else:
|
||||
eeprom_image = get_latest_eeprom()
|
||||
create_tempdir()
|
||||
|
||||
# Replace the contents of bootconf.txt with the contents of the config file
|
||||
tmp_update = os.path.join(TEMP_DIR, 'pieeprom.upd')
|
||||
image = BootloaderImage(eeprom_image, tmp_update)
|
||||
image.write(config)
|
||||
image.update_file(config, BOOTCONF_TXT)
|
||||
image.write()
|
||||
|
||||
config_str = open(config).read()
|
||||
if config_src is None:
|
||||
config_src = ''
|
||||
sys.stdout.write("Updating bootloader EEPROM\n image: %s\nconfig_src: %s\nconfig: %s\n%s\n%s\n%s\n" %
|
||||
(eeprom_image, config_src, config, '#' * 80, config_str, '#' * 80))
|
||||
|
||||
sys.stdout.write("\n*** To cancel this update run 'sudo rpi-eeprom-update -r' ***\n\n")
|
||||
|
||||
# Ignore APT package checksums so that this doesn't fail when used
|
||||
# with EEPROMs with configs delivered outside of APT.
|
||||
# The checksums are really just a safety check for automatic updates.
|
||||
@@ -143,7 +180,7 @@ def edit_config(eeprom=None):
|
||||
if os.path.exists(pending):
|
||||
config_src = pending
|
||||
image = BootloaderImage(pending)
|
||||
current_config = image.get_config().decode('utf-8')
|
||||
current_config = image.get_file(BOOTCONF_TXT).decode('utf-8')
|
||||
else:
|
||||
current_config, config_src = read_current_config()
|
||||
|
||||
@@ -178,6 +215,14 @@ def read_current_config():
|
||||
|
||||
return (shell_cmd(['vcgencmd', 'bootloader_config']), "vcgencmd bootloader_config")
|
||||
|
||||
class ImageSection:
|
||||
def __init__(self, magic, offset, length, filename=''):
|
||||
self.magic = magic
|
||||
self.offset = offset
|
||||
self.length = length
|
||||
self.filename = filename
|
||||
debug("ImageSection %x %x %x %s" % (magic, offset, length, filename))
|
||||
|
||||
class BootloaderImage(object):
|
||||
def __init__(self, filename, output=None):
|
||||
"""
|
||||
@@ -185,6 +230,7 @@ class BootloaderImage(object):
|
||||
and optionally an output filename.
|
||||
"""
|
||||
self._filename = filename
|
||||
self._sections = []
|
||||
try:
|
||||
self._bytes = bytearray(open(filename, 'rb').read())
|
||||
except IOError as err:
|
||||
@@ -196,47 +242,112 @@ class BootloaderImage(object):
|
||||
if len(self._bytes) != IMAGE_SIZE:
|
||||
exit_error("%s: Expected size %d bytes actual size %d bytes" %
|
||||
(filename, IMAGE_SIZE, len(self._bytes)))
|
||||
self.parse()
|
||||
|
||||
def find_config(self):
|
||||
def parse(self):
|
||||
"""
|
||||
Builds a table of offsets to the different sections in the EEPROM.
|
||||
"""
|
||||
offset = 0
|
||||
magic = 0
|
||||
found = False
|
||||
while offset < IMAGE_SIZE:
|
||||
magic, length = struct.unpack_from('>LL', self._bytes, offset)
|
||||
if (magic & MAGIC_MASK) != MAGIC:
|
||||
raise Exception('EEPROM is corrupted')
|
||||
if magic == 0x0 or magic == 0xffffffff:
|
||||
break # EOF
|
||||
elif (magic & MAGIC_MASK) != MAGIC:
|
||||
raise Exception('EEPROM is corrupted %x %x %x' % (magic, magic & MAGIC_MASK, MAGIC))
|
||||
|
||||
filename = ''
|
||||
if magic == FILE_MAGIC: # Found a file
|
||||
name = self._bytes[offset + 8: offset + FILE_HDR_LEN]
|
||||
if name.decode('utf-8') == 'bootconf.txt':
|
||||
return (offset, length)
|
||||
# Discard trailing null characters used to pad filename
|
||||
filename = self._bytes[offset + 8: offset + FILE_HDR_LEN].decode('utf-8').replace('\0', '')
|
||||
self._sections.append(ImageSection(magic, offset, length, filename))
|
||||
|
||||
offset += 8 + length # length + type
|
||||
offset = (offset + 7) & ~7
|
||||
|
||||
raise Exception('EEPROM parse error: Bootloader config not found')
|
||||
def find_file(self, filename):
|
||||
"""
|
||||
Returns the offset, length and whether this is the last section in the
|
||||
EEPROM for a modifiable file within the image.
|
||||
"""
|
||||
ret = (-1, -1, False)
|
||||
for i in range(0, len(self._sections)):
|
||||
s = self._sections[i]
|
||||
if s.magic == FILE_MAGIC and s.filename == filename:
|
||||
is_last = (i == len(self._sections) - 1)
|
||||
ret = (s.offset, s.length, is_last)
|
||||
break
|
||||
debug('%s offset %d length %d last %s' % (filename, ret[0], ret[1], ret[2]))
|
||||
return ret
|
||||
|
||||
def write(self, new_config):
|
||||
hdr_offset, length = self.find_config()
|
||||
new_config_bytes = open(new_config, 'rb').read()
|
||||
new_len = len(new_config_bytes) + FILENAME_LEN + 4
|
||||
if len(new_config_bytes) > MAX_BOOTCONF_SIZE:
|
||||
raise Exception("Config is too large (%d bytes). The maximum size is %d bytes."
|
||||
% (len(new_config_bytes), MAX_BOOTCONF_SIZE))
|
||||
if hdr_offset + len(new_config_bytes) + FILE_HDR_LEN > IMAGE_SIZE:
|
||||
def update(self, src_bytes, dst_filename):
|
||||
"""
|
||||
Replaces a modifiable file with specified byte array.
|
||||
"""
|
||||
hdr_offset, length, is_last = self.find_file(dst_filename)
|
||||
if hdr_offset < 0:
|
||||
raise Exception('Update target %s not found' % dst_filename)
|
||||
|
||||
if hdr_offset + len(src_bytes) + FILE_HDR_LEN > IMAGE_SIZE:
|
||||
raise Exception('EEPROM image size exceeded')
|
||||
|
||||
new_len = len(src_bytes) + FILENAME_LEN + 4
|
||||
struct.pack_into('>L', self._bytes, hdr_offset + 4, new_len)
|
||||
struct.pack_into(("%ds" % len(new_config_bytes)), self._bytes,
|
||||
hdr_offset + 4 + FILE_HDR_LEN, new_config_bytes)
|
||||
struct.pack_into(("%ds" % len(src_bytes)), self._bytes,
|
||||
hdr_offset + 4 + FILE_HDR_LEN, src_bytes)
|
||||
|
||||
# If the new config is smaller than the old config then set any old
|
||||
# If the new file is smaller than the old file then set any old
|
||||
# data which is now unused to all ones (erase value)
|
||||
pad_start = hdr_offset + 4 + FILE_HDR_LEN + len(new_config_bytes)
|
||||
pad_start = hdr_offset + 4 + FILE_HDR_LEN + len(src_bytes)
|
||||
|
||||
# Add padding up to 8-byte boundary
|
||||
while pad_start % 8 != 0:
|
||||
struct.pack_into('B', self._bytes, pad_start, 0xff)
|
||||
pad_start += 1
|
||||
|
||||
# Create a padding section unless the padding size is smaller than the
|
||||
# size of a section head. Padding is allowed in the last section but
|
||||
# by convention bootconf.txt is the last section and there's no need to
|
||||
# pad to the end of the sector. This also ensures that the loopback
|
||||
# config read/write tests produce identical binaries.
|
||||
pad_bytes = ALIGN_SIZE - (pad_start % ALIGN_SIZE)
|
||||
if pad_bytes > 8 and not is_last:
|
||||
pad_bytes -= 8
|
||||
struct.pack_into('>i', self._bytes, pad_start, PAD_MAGIC)
|
||||
pad_start += 4
|
||||
struct.pack_into('>i', self._bytes, pad_start, pad_bytes)
|
||||
pad_start += 4
|
||||
|
||||
debug("pad %d" % pad_bytes)
|
||||
pad = 0
|
||||
while pad < (length - len(new_config_bytes)):
|
||||
while pad < pad_bytes:
|
||||
struct.pack_into('B', self._bytes, pad_start + pad, 0xff)
|
||||
pad = pad + 1
|
||||
|
||||
def update_key(self, src_pem, dst_filename):
|
||||
"""
|
||||
Replaces the specified public key entry with the public key values extracted
|
||||
from the source PEM file.
|
||||
"""
|
||||
pubkey_bytes = pemtobin(src_pem)
|
||||
self.update(pubkey_bytes, dst_filename)
|
||||
|
||||
def update_file(self, src_filename, dst_filename):
|
||||
"""
|
||||
Replaces the contents of dst_filename in the EEPROM with the contents of src_file.
|
||||
"""
|
||||
src_bytes = open(src_filename, 'rb').read()
|
||||
if len(src_bytes) > MAX_FILE_SIZE:
|
||||
raise Exception("src file %s is too large (%d bytes). The maximum size is %d bytes."
|
||||
% (src_filename, len(src_bytes), MAX_FILE_SIZE))
|
||||
self.update(src_bytes, dst_filename)
|
||||
|
||||
def write(self):
|
||||
"""
|
||||
Writes the updated EEPROM image to stdout or the specified output file.
|
||||
"""
|
||||
if self._out is not None:
|
||||
self._out.write(self._bytes)
|
||||
self._out.close()
|
||||
@@ -246,14 +357,14 @@ class BootloaderImage(object):
|
||||
else:
|
||||
sys.stdout.write(self._bytes)
|
||||
|
||||
def get_config(self):
|
||||
hdr_offset, length = self.find_config()
|
||||
def get_file(self, filename):
|
||||
hdr_offset, length, is_last = self.find_file(filename)
|
||||
offset = hdr_offset + 4 + FILE_HDR_LEN
|
||||
config_bytes = self._bytes[offset:offset+length-FILENAME_LEN-4]
|
||||
return config_bytes
|
||||
|
||||
def read(self):
|
||||
config_bytes = self.get_config()
|
||||
config_bytes = self.get_file('bootconf.txt')
|
||||
if self._out is not None:
|
||||
self._out.write(config_bytes)
|
||||
self._out.close()
|
||||
@@ -320,8 +431,21 @@ Operating modes:
|
||||
The default text editor is nano and may be overridden by setting the 'EDITOR'
|
||||
environment variable and passing '-E' to 'sudo' to preserve the environment.
|
||||
|
||||
See 'rpi-eeprom-update -h' for more information about the available EEPROM
|
||||
images.
|
||||
6. Signing the bootloader config file.
|
||||
Updates an EEPROM binary with a signed config file (created by rpi-eeprom-digest) plus
|
||||
the corresponding RSA public key.
|
||||
|
||||
Requires Python Cryptodomex libraries and OpenSSL. To install on Raspberry Pi OS run:-
|
||||
sudo apt install openssl python-pip
|
||||
sudo python3 -m pip install cryptodomex
|
||||
|
||||
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
|
||||
rpi-eeprom-config --config bootconf.txt --digest bootconf.sig --pubkey public.pem --out pieeprom-signed.bin pieeprom.bin
|
||||
|
||||
Currently, the signing process is a separate step so can't be used with the --edit or --apply modes.
|
||||
|
||||
|
||||
See 'rpi-eeprom-update -h' for more information about the available EEPROM images.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=description)
|
||||
@@ -331,6 +455,8 @@ images.
|
||||
parser.add_argument('-c', '--config', help='Name of bootloader configuration file', required=False)
|
||||
parser.add_argument('-e', '--edit', action='store_true', default=False, help='Edit the current EEPROM config')
|
||||
parser.add_argument('-o', '--out', help='Name of output file', required=False)
|
||||
parser.add_argument('-d', '--digest', help='Signed boot only. The name of the .sig file generated by rpi-eeprom-dgst for config.txt ', required=False)
|
||||
parser.add_argument('-p', '--pubkey', help='Signed boot only. The name of the RSA public key file to store in the EEPROM', required=False)
|
||||
parser.add_argument('eeprom', nargs='?', help='Name of EEPROM file to use as input')
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -351,7 +477,12 @@ images.
|
||||
if args.config is not None:
|
||||
if not os.path.exists(args.config):
|
||||
exit_error("config file '%s' not found" % args.config)
|
||||
image.write(args.config)
|
||||
image.update_file(args.config, BOOTCONF_TXT)
|
||||
if args.digest is not None:
|
||||
image.update_file(args.digest, BOOTCONF_SIG)
|
||||
if args.pubkey is not None:
|
||||
image.update_key(args.pubkey, PUBKEY_BIN)
|
||||
image.write()
|
||||
else:
|
||||
image.read()
|
||||
elif args.config is None and args.eeprom is None:
|
||||
|
||||
108
rpi-eeprom-digest
Executable file
108
rpi-eeprom-digest
Executable file
@@ -0,0 +1,108 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Helper script to generate .sig files for use with the Raspberry Pi bootloader.
|
||||
|
||||
# This has been implemented in a separate script in order to have avoid having
|
||||
# a hard dependency on OpenSSL.
|
||||
|
||||
set -e
|
||||
|
||||
OPENSSL=${OPENSSl:-openssl}
|
||||
|
||||
die() {
|
||||
echo "$@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
TMP_DIR=""
|
||||
cleanup() {
|
||||
if [ -f "${TMP_DIR}" ]; then
|
||||
rm -rf "${TMP_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkDependencies() {
|
||||
if ! command -v sha256sum > /dev/null; then
|
||||
die "sha256sum not found. Try installing the coreutilities package."
|
||||
fi
|
||||
|
||||
if ! command -v openssl > /dev/null; then
|
||||
die "openssl not found. Try installing the openssl package."
|
||||
fi
|
||||
|
||||
if ! command -v xxd > /dev/null; then
|
||||
die "xxd not found. Try installing the xxd package."
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
rpi-eeprom-digest [-k RSA_KEY] -i IMAGE -o OUTPUT
|
||||
|
||||
Creates a .sig file containing the sha256 digest of the IMAGE and an optional
|
||||
RSA signature of that hash.
|
||||
|
||||
Options:
|
||||
-i The source image.
|
||||
-o The name of the digest/signature file.
|
||||
-k Optional RSA private key.
|
||||
|
||||
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
|
||||
(not available yet) and only for the EEPROM config file and the signed image.
|
||||
|
||||
Examples:
|
||||
|
||||
# Generate RSA signature for the EEPROM config file.
|
||||
rpi-eeprom-digest -k key.pem -i bootconf.txt -o bootconf.sig
|
||||
|
||||
# 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
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
OUTPUT=""
|
||||
while getopts i:k:ho: option; do
|
||||
case "${option}" in
|
||||
i) IMAGE="${OPTARG}"
|
||||
;;
|
||||
k) KEY="${OPTARG}"
|
||||
;;
|
||||
o) OUTPUT="${OPTARG}"
|
||||
;;
|
||||
h) usage
|
||||
;;
|
||||
*) echo "Unknown argument \"${option}\""
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ -n "${IMAGE}" ] || usage
|
||||
[ -n "${OUTPUT}" ] || usage
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
checkDependencies
|
||||
|
||||
[ -f "${IMAGE}" ] || die "Source image \"${IMAGE}\" not found"
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
SIG_TMP="${TMP_DIR}/tmp.sig"
|
||||
sha256sum "${IMAGE}" | awk '{print $1}' > "${OUTPUT}"
|
||||
|
||||
# Include the update-timestamp
|
||||
echo "ts: $(date -u +%s)" >> "${OUTPUT}"
|
||||
|
||||
if [ -n "${KEY}" ]; then
|
||||
[ -f "${KEY}" ] || die "RSA private \"${KEY}\" not found"
|
||||
|
||||
"${OPENSSL}" dgst -sign "${KEY}" -keyform PEM -sha256 -out "${SIG_TMP}" "${IMAGE}"
|
||||
echo "rsa2048: $(xxd -c 4096 -p < "${SIG_TMP}")" >> "${OUTPUT}"
|
||||
fi
|
||||
@@ -186,38 +186,15 @@ applyRecoveryUpdate()
|
||||
findBootFS
|
||||
echo " BOOTFS: ${BOOTFS}"
|
||||
|
||||
# A '.sig' file is created so that recovery.bin can check that the
|
||||
# EEPROM image has not been corrupted (e.g. SD card corruption).
|
||||
# Format of the .sig file.
|
||||
# --
|
||||
# SHA256\n
|
||||
# ts: UPDATE-TIMESTAMP\n
|
||||
# --
|
||||
# SHA256 is a 64 character hex string
|
||||
# UPDATE-TIMESTAMP is an unsigned decimal.
|
||||
#
|
||||
# The 'filename' output from sha256 MUST be omitted.
|
||||
if [ -n "${BOOTLOADER_UPDATE_IMAGE}" ]; then
|
||||
[ -f "${BOOTLOADER_UPDATE_IMAGE}" ] || die "${BOOTLOADER_UPDATE_IMAGE} not found"
|
||||
|
||||
TMP_EEPROM_IMAGE="$(mktemp)"
|
||||
prepareImage
|
||||
# If recovery.bin encounters pieeprom.upd then it will select it in
|
||||
# preference to pieeprom.bin. The .upd file also causes recovery.bin
|
||||
# to rename itself to recovery.000 and reboot if the update is successful.
|
||||
# The rename causes the ROM to ignore this file and use the newly flashed
|
||||
# EEPROM image instead.
|
||||
sha256sum "${TMP_EEPROM_IMAGE}" | awk '{print $1}' > "${BOOTFS}/pieeprom.sig" \
|
||||
|| die "Failed to create ${BOOTFS}/pieeprom.sig"
|
||||
|
||||
# Appends the update creation timestamp on a newline in pieeprom.sig
|
||||
# During a self-update mode the bootloader examines the update-timestamp
|
||||
# and will only update itself if it is newer than the current update
|
||||
# timestamp.
|
||||
#
|
||||
# The update-timestamp is independent of the bootloader version and
|
||||
# does not have to be timestamp.
|
||||
echo "ts: $(date -u +%s)" >> "${BOOTFS}/pieeprom.sig"
|
||||
# Generate a .sig file containing the sha256 hash of the EEPROM image
|
||||
# and the current timestamp.
|
||||
rpi-eeprom-digest -i "${TMP_EEPROM_IMAGE}" -o "${BOOTFS}/pieeprom.sig"
|
||||
|
||||
cp -f "${TMP_EEPROM_IMAGE}" "${BOOTFS}/pieeprom.upd" \
|
||||
|| die "Failed to copy ${TMP_EEPROM_IMAGE} to ${BOOTFS}"
|
||||
@@ -228,8 +205,7 @@ applyRecoveryUpdate()
|
||||
fi
|
||||
|
||||
if [ -n "${VL805_UPDATE_IMAGE}" ]; then
|
||||
sha256sum "${VL805_UPDATE_IMAGE}" | awk '{print $1}' > "${BOOTFS}/vl805.sig" \
|
||||
|| die "Failed to create ${BOOTFS}/vl805.sig"
|
||||
rpi-eeprom-digest -i "${VL805_UPDATE_IMAGE}" -o "${BOOTFS}/vl805.sig"
|
||||
|
||||
cp -f "${VL805_UPDATE_IMAGE}" "${BOOTFS}/vl805.bin" \
|
||||
|| die "Failed to copy ${VL805_UPDATE_IMAGE} to ${BOOTFS}/vl805.bin"
|
||||
@@ -342,6 +318,10 @@ checkDependencies() {
|
||||
HAVE_VL805_EEPROM=0
|
||||
fi
|
||||
|
||||
if ! command -v rpi-eeprom-digest > /dev/null; then
|
||||
die "rpi-eeprom-digest not found. Try re-installing the rpi-eeprom package"
|
||||
fi
|
||||
|
||||
if ! command -v lspci > /dev/null; then
|
||||
die "lspci not found. Try installing the pciutils package."
|
||||
fi
|
||||
|
||||
3
test/bootconf.sig
Normal file
3
test/bootconf.sig
Normal file
@@ -0,0 +1,3 @@
|
||||
b5b917dc53a59c23035a89d4c58606211a07d4fb6e16bd00d74457a93ea5a264
|
||||
ts: 1614092425
|
||||
rsa2048: 284d3ef8b960ef9dd0bf5f320eacccb527623890b11136801fcfaf950ef3fb32c9b86ee48337d2cd21e00665a62215ff4d811b15d89867fb55d71b6372a4fa4b79af60cdda84c8a7d9b52d5f2b3026d3b088345d9424842cc2eb73e23f4577e12c74bc3bc1890bfbb6509fc8702cd3a202929bb6f9e5162ea53ec6e8503e08dda7b0c86a90bc21d33bd49535554383fe88e7d1d8e46e27c2bce60cf15b69c56ee27ccdd81ff8f47a616a2796cc2d943e17c6c01ac191f9b7dcda440238062e6c49df01f4bb8b97ce380a46aa29a03bf3fcbede3d76c13d862fc8b60b472a4d1017d5535f5188858a6e1103db2666aa63264e7c1f752b917405527094ed0da737
|
||||
8
test/bootconf.txt
Normal file
8
test/bootconf.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
[all]
|
||||
BOOT_UART=1
|
||||
WAKE_ON_GPIO=1
|
||||
POWER_OFF_ON_HALT=0
|
||||
HDMI_DELAY=0
|
||||
# Load firmware and kernel from signed boot.img file
|
||||
SIGNED_BOOT=1
|
||||
|
||||
@@ -21,6 +21,7 @@ CONFIG="/etc/default/rpi-eeprom-update"
|
||||
|
||||
cp -rfv "${FIRMWARE_DIR}"/* /lib/firmware/raspberrypi/bootloader
|
||||
cp -fv "${script_dir}/../rpi-eeprom-config" /usr/bin
|
||||
cp -fv "${script_dir}/../rpi-eeprom-digest" /usr/bin
|
||||
cp -fv "${script_dir}/../rpi-eeprom-update" /usr/bin
|
||||
rm -f /usr/bin/vl805
|
||||
|
||||
|
||||
BIN
test/pieeprom-signed.bin
Normal file
BIN
test/pieeprom-signed.bin
Normal file
Binary file not shown.
27
test/private.pem
Normal file
27
test/private.pem
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA+l3E+h/QNjrIR1cG6NpzP0fBwp2UDpuQAafXDS5yryrfCPDY
|
||||
TO9DvzAfOk9Dz/putDfHV0RTOFXv1tmc4nqOgU6nKx7tTdsjTiY4CgG3vXRMuAmD
|
||||
GX5ssJFCVmljGuILt1INlCmtun7Ow35VTxOcRDDfrBDKnSitzOTf6KTR7xJhqFFh
|
||||
dMpIg8hW4bDBKMavyt38pRvDaO1o01qaQT/GgAPmJm27y5RKNAe6iVTqsm4TMAhK
|
||||
C6P4XyRAbe6OMdFZyEWEk7Asexuc7uZlVHsUI6pebSW/07O+5l/U7/3k6r//hO/H
|
||||
DFOBUUW55EjzzC1BhTlWHWfZNI+5+NdN8o323QIDAQABAoIBAByQGZKSkhG5w5MV
|
||||
++ERWQARaurNyPAgsb1qnUdw8t8GlFLkDT07t74mWo2vsNQXpU0Upv6O+jKNZVMc
|
||||
2P/ijQL2Cu7JtLeC5mR6Sj7kAscPr1f4p9b+/B3puIh8tfSBcOY9a3Spi5sg7+xQ
|
||||
K6HdoiCKdd4evUrQMwHS47OaKCQuuibm46LWbXO1nk9QkymUy6zyaT5IuNpfKYKD
|
||||
UdFqV1FNwZ9A2Yb89rweBgU4DWdbjgVqBc23vS9l913rqd2LHN/4+XDBOGrovu5r
|
||||
mJy4WsyXuT0twuqi7FzhtbCdN/zhLo2od1XK6uA65EKdA9rrRMkNeGvxts6q3fPE
|
||||
i6tj7OECgYEA/YbIR8n8Vvb5XPAav/aAon4qjXyhkUTjnJfVT0yA+6T1AJwvQ+O4
|
||||
AhYgN4ld7msKRDJLcJs0EU8CmWUKJRt5Ai+JsOCbPuBNo+VGEFSsdG0mrSjFZf2e
|
||||
Bjm41lnvAEWReGwr9MVIf/prDE2/3aUl9irkNdu5q6NpG9M0N7AhzGECgYEA/M8Y
|
||||
Ew9Nv+XqEVKvOzxKRZBa6yzlOUj5PQ3cD7jl1aUNK4rTucvr3sJZAsgm5j+0XG99
|
||||
AJ447zdDEdcQbsOSaBR69pccdHYEaRSiIxWaCAir2BBS5DxYtgB6BLrIfBd1cKHv
|
||||
qB6u4M6FRJ5BcQa6VYlizAfG2yXoJv0xFrlQ2/0CgYEAwq0Alb+QOOckzCzDHayX
|
||||
Ui83VbXiCr6vWMtuTJoeYR1l1LYZxTPTVCbRTlP5AN7I310PeMR00uWsxUVE6QGT
|
||||
hg4i2ONf0oRCmhuwFVIvqqc2D7lC+vIoqfcg69fbIoZJEgNeLXJgHYWZNbVuIzBx
|
||||
WfnNi13R0O6GA4vGiQyCp4ECgYB1ZTG3wBaJsxlDnBLVPgT7UrJ1nO6A8HsUt/fl
|
||||
sSXBVRjNjHUPRTutwLAW050EtLZrajYw8EheBVp20VjHJrg47rG/CqLjDd60cSlt
|
||||
g114t5YdCk+DvuYu9f+zbI0m2rnlaL1iY4UvzZcjKx4Wf1pN2DNxrXbRU0P/vvlp
|
||||
pPqAfQKBgDZnxWuvRsT9rztGrEottifchfrStZx7u/2+iBtjFeFXr7L4MI14fNm2
|
||||
HkoThCpfFXCJFpRxy+kYi6xbPK/Om/hFNs3J5xqheTW8hFx7KN/zPg7jc0MlZ2R/
|
||||
uuOgZU9kkzLOamDyP85Doah7kAyA2PnLUno2k4IirbNVoH3aV++G
|
||||
-----END RSA PRIVATE KEY-----
|
||||
9
test/public.pem
Normal file
9
test/public.pem
Normal file
@@ -0,0 +1,9 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+l3E+h/QNjrIR1cG6Npz
|
||||
P0fBwp2UDpuQAafXDS5yryrfCPDYTO9DvzAfOk9Dz/putDfHV0RTOFXv1tmc4nqO
|
||||
gU6nKx7tTdsjTiY4CgG3vXRMuAmDGX5ssJFCVmljGuILt1INlCmtun7Ow35VTxOc
|
||||
RDDfrBDKnSitzOTf6KTR7xJhqFFhdMpIg8hW4bDBKMavyt38pRvDaO1o01qaQT/G
|
||||
gAPmJm27y5RKNAe6iVTqsm4TMAhKC6P4XyRAbe6OMdFZyEWEk7Asexuc7uZlVHsU
|
||||
I6pebSW/07O+5l/U7/3k6r//hO/HDFOBUUW55EjzzC1BhTlWHWfZNI+5+NdN8o32
|
||||
3QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -59,6 +59,29 @@ check_reduce_size()
|
||||
|
||||
}
|
||||
|
||||
check_signed_loopback()
|
||||
{
|
||||
echo "check_signed $1 $2"
|
||||
|
||||
image="${script_dir}/$1"
|
||||
conf="${script_dir}/$2"
|
||||
digest="${script_dir}/$3"
|
||||
pubkey="${script_dir}/$4"
|
||||
|
||||
# Replace the config, config.sig and pubkey and verify that the output is the same
|
||||
TMP_EEPROM="$(mktemp)"
|
||||
"${script_dir}/../rpi-eeprom-config" \
|
||||
"${image}" \
|
||||
--config "${conf}" \
|
||||
--digest "${digest}" \
|
||||
--pubkey "${pubkey}" \
|
||||
--out "${TMP_EEPROM}"
|
||||
|
||||
expected_md5="$(md5sum "${image}" | awk '{print $1}')"
|
||||
actual_md5="$(md5sum "${TMP_EEPROM}" | awk '{print $1}')"
|
||||
[ "${actual_md5}" = "${expected_md5}" ] || die "EEPROM signed-loopback: checksum mismatch"
|
||||
}
|
||||
|
||||
check_loopback()
|
||||
{
|
||||
echo "check_loopback $1 $2"
|
||||
@@ -148,6 +171,11 @@ for ver in ${versions}; do
|
||||
cleanup
|
||||
done
|
||||
|
||||
echo "Test lookback with a signed EEPROM image"
|
||||
check_loopback pieeprom-signed.bin bootconf.txt
|
||||
check_signed_loopback pieeprom-signed.bin bootconf.txt bootconf.sig public.pem
|
||||
cleanup
|
||||
|
||||
check_update "../firmware/old/beta/pieeprom-2019-07-15.bin" "pieeprom-2019-07-15-freeze.bin" "bootconf-2019-07-15-freeze.txt"
|
||||
cleanup
|
||||
|
||||
|
||||
Reference in New Issue
Block a user