From 4349d01744e26a4b26365df946443a0b9bb5ac0b Mon Sep 17 00:00:00 2001 From: David Alexander Bjerremose Date: Fri, 4 Apr 2025 11:17:38 +0200 Subject: [PATCH] feat: added fixed signature script option --- scripts/imgtool/image.py | 16 ++++++++++++++-- scripts/imgtool/main.py | 15 +++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/scripts/imgtool/image.py b/scripts/imgtool/image.py index 3e2c11073f..38f462bd63 100644 --- a/scripts/imgtool/image.py +++ b/scripts/imgtool/image.py @@ -27,6 +27,8 @@ from enum import Enum import array from intelhex import IntelHex +import subprocess +import base64 import hashlib import array import os.path @@ -461,7 +463,8 @@ def create(self, key, public_key_format, enckey, dependencies=None, sw_type=None, custom_tlvs=None, compression_tlvs=None, compression_type=None, encrypt_keylen=128, clear=False, fixed_sig=None, pub_key=None, vector_to_sign=None, - user_sha='auto', is_pure=False, keep_comp_size=False, dont_encrypt=False): + user_sha='auto', is_pure=False, keep_comp_size=False, dont_encrypt=False, + fixed_sig_script=None): self.enckey = enckey # key decides on sha, then pub_key; of both are none default is used @@ -638,7 +641,16 @@ def create(self, key, public_key_format, enckey, dependencies=None, else: tlv.add('PUBKEY', pub) - if key is not None and fixed_sig is None: + if fixed_sig_script is not None: + # Call fixed signature script with payload and digest to get signature + # The script should return the signature in binary format + digest_base64 = base64.b64encode(digest).decode('ascii') + print(os.path.basename(__file__) + ": call fixed signature script with digest and input file") + result = subprocess.run([fixed_sig_script, digest_base64], stdout=subprocess.PIPE, check=True, input=self.payload) + stdout = result.stdout + self.signature = base64.b64decode(stdout.decode('ascii')) + tlv.add(pub_key.sig_tlv(), self.signature) + elif key is not None and fixed_sig is None: # `sign` expects the full image payload (hashing done # internally), while `sign_digest` expects only the digest # of the payload diff --git a/scripts/imgtool/main.py b/scripts/imgtool/main.py index 1cdb792a54..61189399c3 100755 --- a/scripts/imgtool/main.py +++ b/scripts/imgtool/main.py @@ -427,6 +427,8 @@ def convert(self, value, param, ctx): 'the signature calculated using the public key') @click.option('--fix-sig-pubkey', metavar='filename', help='public key relevant to fixed signature') +@click.option('--fix-sig-script', metavar='filename', + help='script to generate fixed signature') @click.option('--pure', 'is_pure', is_flag=True, default=False, show_default=True, help='Expected Pure variant of signature; the Pure variant is ' 'expected to be signature done over an image rather than hash of ' @@ -449,8 +451,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, endian, encrypt_keylen, encrypt, compression, infile, outfile, dependencies, load_addr, hex_addr, erased_val, save_enctlv, security_counter, boot_record, custom_tlv, rom_fixed, max_align, - clear, fix_sig, fix_sig_pubkey, sig_out, user_sha, is_pure, - vector_to_sign, non_bootable): + clear, fix_sig, fix_sig_pubkey, fix_sig_script, sig_out, user_sha, + is_pure, vector_to_sign, non_bootable): if confirm: # Confirmed but non-padded images don't make much sense, because @@ -506,16 +508,17 @@ def sign(key, public_key_format, align, version, pad_sig, header_size, baked_signature = None pub_key = None - if raw_signature is not None: + if raw_signature is not None or fix_sig_script is not None: if fix_sig_pubkey is None: raise click.UsageError( 'public key of the fixed signature is not specified') pub_key = load_key(fix_sig_pubkey) - baked_signature = { - 'value': raw_signature - } + if raw_signature is not None: + baked_signature = { + 'value': raw_signature + } if is_pure and user_sha != 'auto': raise click.UsageError(