imgtool: Added support for providing the signature by 3rd party
The sign command was extended so it now allow to provide the signature as base64 formatted RAW file using --fix-sig along with the relevant public key --fix-sig-pubkey. This patch is added for support the case where the party which produces the image dose not have access to the signing image key but must request third party for the signature. Signed-off-by: Andrzej Puzdrowski <andrzej.puzdrowski@nordicsemi.no>
This commit is contained in:
parent
ee1b7b9d6e
commit
160303c202
|
@ -305,7 +305,7 @@ class Image():
|
||||||
return cipherkey, ciphermac, pubk
|
return cipherkey, ciphermac, pubk
|
||||||
|
|
||||||
def create(self, key, public_key_format, enckey, dependencies=None,
|
def create(self, key, public_key_format, enckey, dependencies=None,
|
||||||
sw_type=None, custom_tlvs=None, encrypt_keylen=128, clear=False):
|
sw_type=None, custom_tlvs=None, encrypt_keylen=128, clear=False, fixed_sig=None, pub_key=None):
|
||||||
self.enckey = enckey
|
self.enckey = enckey
|
||||||
|
|
||||||
# Calculate the hash of the public key
|
# Calculate the hash of the public key
|
||||||
|
@ -314,6 +314,11 @@ class Image():
|
||||||
sha = hashlib.sha256()
|
sha = hashlib.sha256()
|
||||||
sha.update(pub)
|
sha.update(pub)
|
||||||
pubbytes = sha.digest()
|
pubbytes = sha.digest()
|
||||||
|
elif pub_key is not None:
|
||||||
|
pub = pub_key.get_public_bytes()
|
||||||
|
sha = hashlib.sha256()
|
||||||
|
sha.update(pub)
|
||||||
|
pubbytes = sha.digest()
|
||||||
else:
|
else:
|
||||||
pubbytes = bytes(hashlib.sha256().digest_size)
|
pubbytes = bytes(hashlib.sha256().digest_size)
|
||||||
|
|
||||||
|
@ -428,7 +433,7 @@ class Image():
|
||||||
|
|
||||||
tlv.add('SHA256', digest)
|
tlv.add('SHA256', digest)
|
||||||
|
|
||||||
if key is not None:
|
if key is not None and fixed_sig is None:
|
||||||
if public_key_format == 'hash':
|
if public_key_format == 'hash':
|
||||||
tlv.add('KEYHASH', pubbytes)
|
tlv.add('KEYHASH', pubbytes)
|
||||||
else:
|
else:
|
||||||
|
@ -442,6 +447,14 @@ class Image():
|
||||||
else:
|
else:
|
||||||
sig = key.sign_digest(digest)
|
sig = key.sign_digest(digest)
|
||||||
tlv.add(key.sig_tlv(), sig)
|
tlv.add(key.sig_tlv(), sig)
|
||||||
|
elif fixed_sig is not None and key is None:
|
||||||
|
if public_key_format == 'hash':
|
||||||
|
tlv.add('KEYHASH', pubbytes)
|
||||||
|
else:
|
||||||
|
tlv.add('PUBKEY', pub)
|
||||||
|
tlv.add(pub_key.sig_tlv(), fixed_sig['value'])
|
||||||
|
else:
|
||||||
|
raise click.UsageError("Can not sign using key and provide fixed-signature at the same time")
|
||||||
|
|
||||||
# At this point the image was hashed + signed, we can remove the
|
# At this point the image was hashed + signed, we can remove the
|
||||||
# protected TLVs from the payload (will be re-added later)
|
# protected TLVs from the payload (will be re-added later)
|
||||||
|
@ -486,6 +499,9 @@ class Image():
|
||||||
|
|
||||||
self.check_trailer()
|
self.check_trailer()
|
||||||
|
|
||||||
|
def get_signature(self):
|
||||||
|
return self.signature
|
||||||
|
|
||||||
def add_header(self, enckey, protected_tlv_size, aes_length=128):
|
def add_header(self, enckey, protected_tlv_size, aes_length=128):
|
||||||
"""Install the image header."""
|
"""Install the image header."""
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import click
|
||||||
import getpass
|
import getpass
|
||||||
import imgtool.keys as keys
|
import imgtool.keys as keys
|
||||||
import sys
|
import sys
|
||||||
|
import base64
|
||||||
from imgtool import image, imgtool_version
|
from imgtool import image, imgtool_version
|
||||||
from imgtool.version import decode_version
|
from imgtool.version import decode_version
|
||||||
from .keys import (
|
from .keys import (
|
||||||
|
@ -68,6 +69,10 @@ keygens = {
|
||||||
'x25519': gen_x25519,
|
'x25519': gen_x25519,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def load_signature(sigfile):
|
||||||
|
with open(sigfile, 'rb') as f:
|
||||||
|
signature = base64.b64decode(f.read())
|
||||||
|
return signature
|
||||||
|
|
||||||
def load_key(keyfile):
|
def load_key(keyfile):
|
||||||
# TODO: better handling of invalid pass-phrase
|
# TODO: better handling of invalid pass-phrase
|
||||||
|
@ -303,6 +308,11 @@ class BasedIntParamType(click.ParamType):
|
||||||
default='hash', help='In what format to add the public key to '
|
default='hash', help='In what format to add the public key to '
|
||||||
'the image manifest: full key or hash of the key.')
|
'the image manifest: full key or hash of the key.')
|
||||||
@click.option('-k', '--key', metavar='filename')
|
@click.option('-k', '--key', metavar='filename')
|
||||||
|
@click.option('--fix-sig', metavar='filename',
|
||||||
|
help='fixed signature for the image. It will be used instead of'
|
||||||
|
'the signature calculated using the public key')
|
||||||
|
@click.option('--fix-sig-pubkey', metavar='filename',
|
||||||
|
help='public key relevant to fixed signature')
|
||||||
@click.command(help='''Create a signed or unsigned image\n
|
@click.command(help='''Create a signed or unsigned image\n
|
||||||
INFILE and OUTFILE are parsed as Intel HEX if the params have
|
INFILE and OUTFILE are parsed as Intel HEX if the params have
|
||||||
.hex extension, otherwise binary format is used''')
|
.hex extension, otherwise binary format is used''')
|
||||||
|
@ -310,7 +320,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size,
|
||||||
pad_header, slot_size, pad, confirm, max_sectors, overwrite_only,
|
pad_header, slot_size, pad, confirm, max_sectors, overwrite_only,
|
||||||
endian, encrypt_keylen, encrypt, infile, outfile, dependencies,
|
endian, encrypt_keylen, encrypt, infile, outfile, dependencies,
|
||||||
load_addr, hex_addr, erased_val, save_enctlv, security_counter,
|
load_addr, hex_addr, erased_val, save_enctlv, security_counter,
|
||||||
boot_record, custom_tlv, rom_fixed, max_align, clear):
|
boot_record, custom_tlv, rom_fixed, max_align, clear, fix_sig,
|
||||||
|
fix_sig_pubkey):
|
||||||
|
|
||||||
if confirm:
|
if confirm:
|
||||||
# Confirmed but non-padded images don't make much sense, because
|
# Confirmed but non-padded images don't make much sense, because
|
||||||
|
@ -356,8 +367,25 @@ def sign(key, public_key_format, align, version, pad_sig, header_size,
|
||||||
else:
|
else:
|
||||||
custom_tlvs[tag] = value.encode('utf-8')
|
custom_tlvs[tag] = value.encode('utf-8')
|
||||||
|
|
||||||
|
# Allow signature calculated externally.
|
||||||
|
raw_signature = load_signature(fix_sig) if fix_sig else None
|
||||||
|
|
||||||
|
baked_signature = None
|
||||||
|
pub_key = None
|
||||||
|
|
||||||
|
if raw_signature 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
|
||||||
|
}
|
||||||
|
|
||||||
img.create(key, public_key_format, enckey, dependencies, boot_record,
|
img.create(key, public_key_format, enckey, dependencies, boot_record,
|
||||||
custom_tlvs, int(encrypt_keylen), clear)
|
custom_tlvs, int(encrypt_keylen), clear, baked_signature, pub_key)
|
||||||
img.save(outfile, hex_addr)
|
img.save(outfile, hex_addr)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue