feat(core): support checking generated vendor headers as part of make gen_check

[no changelog]
pull/3215/head
matejcik 9 months ago committed by matejcik
parent ec06cc5c40
commit df84d96244

@ -130,6 +130,12 @@ ci_docs: ## generate CI documentation
ci_docs_check: ## check that generated CI documentation is up to date
./tools/generate_ci_docs.py --check
gen: mocks icons templates protobuf ci_docs ## regenerate auto-generated files from sources
vendorheader: ## generate vendor header
./core/embed/vendorheader/generate.sh --quiet
gen_check: mocks_check icons_check templates_check protobuf_check ci_docs_check ## check validity of auto-generated files
vendorheader_check: ## check that vendor header is up to date
./core/embed/vendorheader/generate.sh --quiet --check
gen: mocks icons templates protobuf ci_docs vendorheader ## regenerate auto-generated files from sources
gen_check: mocks_check icons_check templates_check protobuf_check ci_docs_check vendorheader_check ## check validity of auto-generated files

@ -1,10 +1,21 @@
#!/usr/bin/env bash
set -e
cd $(dirname $0)
BUILDVH=$(realpath ../../tools/build_vendorheader)
BINCTL=$(realpath ../../tools/headertool.py)
for arg in "$@"; do
if [ "$arg" == "--check" ]; then
CHECK="--check"
fi
if [ "$arg" == "--quiet" ]; then
QUIET="--quiet"
fi
done
MODELS=(T2T1 T2B1 D001)
for MODEL in ${MODELS[@]}; do
@ -12,13 +23,24 @@ for MODEL in ${MODELS[@]}; do
# construct all vendor headers
for fn in *.json; do
name=$(echo $fn | sed 's/vendor_\(.*\)\.json/\1/')
$BUILDVH vendor_${name}.json vendor_${name}.toif vendorheader_${name}_unsigned.bin
$BUILDVH $QUIET $CHECK vendor_${name}.json vendor_${name}.toif vendorheader_${name}_unsigned.bin
done
TMPDIR=$(mktemp -d)
trap "rm -rf $TMPDIR" EXIT
# sign dev and QA vendor header
for name in unsafe qa_DO_NOT_SIGN; do
cp -a vendorheader_${name}_unsigned.bin vendorheader_${name}_signed_dev.bin
$BINCTL -D vendorheader_${name}_signed_dev.bin
SRC_NAME="vendorheader_${name}_unsigned.bin"
DEST_NAME="vendorheader_${name}_signed_dev.bin"
if [ ! -f "$SRC_NAME" ]; then
continue
fi
cp -a vendorheader_${name}_unsigned.bin "$TMPDIR/$DEST_NAME"
$BINCTL $QUIET -D "$TMPDIR/$DEST_NAME"
if [ -n "$CHECK" ]; then
diff "$DEST_NAME" "$TMPDIR/$DEST_NAME"
fi
cp -a "$TMPDIR/$DEST_NAME" "$DEST_NAME"
done
cd ..
done

@ -1,5 +1,6 @@
#!/usr/bin/env python3
import json
from pathlib import Path
import click
@ -20,8 +21,15 @@ def minimum_header_len(spec):
@click.command()
@click.argument("specfile", type=click.File("r"))
@click.argument("image", type=click.File("rb"))
@click.argument("outfile", type=click.File("wb"))
def build_vendorheader(specfile, image, outfile):
@click.argument("outfile", type=click.Path(dir_okay=False, writable=True, path_type=Path))
@click.option("-c", "--check", is_flag=True, help="Check but do not write header.")
@click.option("-q", "--quiet", is_flag=True, help="Do not print anything.")
def build_vendorheader(specfile, image, outfile, check: bool, quiet: bool):
if quiet:
echo = lambda *args, **kwargs: None
else:
echo = click.echo
spec = json.load(specfile)
spec["pubkeys"] = [bytes.fromhex(k) for k in spec["pubkeys"]]
spec["image"] = toif.ToifStruct.parse(image.read())
@ -41,16 +49,26 @@ def build_vendorheader(specfile, image, outfile):
f"Minimum allowable value is {min_length}."
)
elif spec["header_len"] == min_length:
click.echo(f"{specfile.name}: Header has correct length.")
echo(f"{specfile.name}: Header has correct length.")
else:
click.echo(
echo(
f"{specfile.name}: Extending header ({min_length} bytes) to {spec['header_len']} bytes."
)
if spec["header_len"] % 512 != 0:
raise click.ClickException("Invalid header_len: must be a multiple of 512")
outfile.write(firmware.VendorHeader.SUBCON.build(spec))
vh_bytes = firmware.VendorHeader.SUBCON.build(spec)
if check:
if not outfile.exists():
raise click.ClickException(f"Header file {outfile.name} does not exist.")
outfile_bytes = outfile.read_bytes()
if outfile_bytes != vh_bytes:
raise click.ClickException(
f"Header file {outfile.name} differs from expected header."
)
else:
outfile.write_bytes(firmware.VendorHeader.SUBCON.build(spec))
if __name__ == "__main__":

@ -100,6 +100,7 @@ def do_replace_vendorheader(fw, vh_file) -> None:
is_flag=True,
help="Only output header digest for signing and exit.",
)
@click.option("-q", "--quiet", is_flag=True, help="Do not print anything.")
@click.argument("firmware_file", type=click.File("rb+"))
def cli(
firmware_file,
@ -111,6 +112,7 @@ def cli(
insert_signature,
replace_vendor_header,
print_digest,
quiet,
):
"""Manage firmware headers.
@ -160,6 +162,11 @@ def cli(
click.echo(digest.hex())
return
if quiet:
echo = lambda *args, **kwargs: None
else:
echo = click.echo
if replace_vendor_header:
do_replace_vendorheader(fw, replace_vendor_header)
@ -174,11 +181,11 @@ def cli(
signature = None
if privkeys:
click.echo("Signing with local private keys...", err=True)
echo("Signing with local private keys...", err=True)
signature = sign_with_privkeys(digest, privkeys)
if insert_signature:
click.echo("Inserting external signature...", err=True)
echo("Inserting external signature...", err=True)
sigmask_str, signature = insert_signature
signature = bytes.fromhex(signature)
sigmask = 0
@ -193,14 +200,14 @@ def cli(
if signature or rehash:
do_rehash(fw)
click.echo(f"Detected image type: {fw.NAME}")
click.echo(fw.format(verbose))
echo(f"Detected image type: {fw.NAME}")
echo(fw.format(verbose))
updated_data = fw.build()
if updated_data == firmware_data:
click.echo("No changes made", err=True)
echo("No changes made", err=True)
elif dry_run:
click.echo("Not saving changes", err=True)
echo("Not saving changes", err=True)
else:
firmware_file.seek(0)
firmware_file.truncate(0)

Loading…
Cancel
Save