diff --git a/Makefile b/Makefile index 703dd1c63..49fb2fc3f 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/core/embed/vendorheader/generate.sh b/core/embed/vendorheader/generate.sh index fd04bcb71..e8d144447 100755 --- a/core/embed/vendorheader/generate.sh +++ b/core/embed/vendorheader/generate.sh @@ -1,10 +1,21 @@ #!/usr/bin/env bash +set -ex + 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 diff --git a/core/tools/build_vendorheader b/core/tools/build_vendorheader index f71f69b7f..963ae37b5 100755 --- a/core/tools/build_vendorheader +++ b/core/tools/build_vendorheader @@ -21,7 +21,14 @@ def minimum_header_len(spec): @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.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 +48,24 @@ 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: + outfile_bytes = outfile.read() + if outfile_bytes != vh_bytes: + raise click.ClickException( + f"Header file {outfile.name} differs from expected header." + ) + else: + outfile.write(firmware.VendorHeader.SUBCON.build(spec)) if __name__ == "__main__": diff --git a/core/tools/headertool.py b/core/tools/headertool.py index 425f0aeb9..c31071b09 100755 --- a/core/tools/headertool.py +++ b/core/tools/headertool.py @@ -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. @@ -144,6 +146,7 @@ def cli( """ firmware_data = firmware_file.read() + try: fw = firmware_headers.parse_image(firmware_data) except Exception as e: @@ -160,6 +163,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 +182,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 +201,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)