tools: tfm: Update bin_utils

pull/15050/head
Robert Walton 2021-09-02 13:58:09 +01:00
parent 3d17e1646c
commit 6850192508
6 changed files with 67 additions and 28 deletions

View File

@ -14,4 +14,4 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
imgtool_version = "1.7.0rc1" imgtool_version = "1.7.0"

View File

@ -1,6 +1,6 @@
# Copyright 2018 Nordic Semiconductor ASA # Copyright 2018 Nordic Semiconductor ASA
# Copyright 2017-2020 Linaro Limited # Copyright 2017-2020 Linaro Limited
# Copyright 2019-2020 Arm Limited # Copyright 2019-2021 Arm Limited
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -51,9 +51,11 @@ MAX_SW_TYPE_LENGTH = 12 # Bytes
# Image header flags. # Image header flags.
IMAGE_F = { IMAGE_F = {
'PIC': 0x0000001, 'PIC': 0x0000001,
'ENCRYPTED_AES128': 0x0000004,
'ENCRYPTED_AES256': 0x0000008,
'NON_BOOTABLE': 0x0000010, 'NON_BOOTABLE': 0x0000010,
'RAM_LOAD': 0x0000020, 'RAM_LOAD': 0x0000020,
'ENCRYPTED': 0x0000004, 'ROM_FIXED': 0x0000100,
} }
TLV_VALUES = { TLV_VALUES = {
@ -66,7 +68,7 @@ TLV_VALUES = {
'RSA3072': 0x23, 'RSA3072': 0x23,
'ED25519': 0x24, 'ED25519': 0x24,
'ENCRSA2048': 0x30, 'ENCRSA2048': 0x30,
'ENCKW128': 0x31, 'ENCKW': 0x31,
'ENCEC256': 0x32, 'ENCEC256': 0x32,
'ENCX25519': 0x33, 'ENCX25519': 0x33,
'DEPENDENCY': 0x40, 'DEPENDENCY': 0x40,
@ -132,7 +134,12 @@ class Image():
pad_header=False, pad=False, confirm=False, align=1, pad_header=False, pad=False, confirm=False, align=1,
slot_size=0, max_sectors=DEFAULT_MAX_SECTORS, slot_size=0, max_sectors=DEFAULT_MAX_SECTORS,
overwrite_only=False, endian="little", load_addr=0, overwrite_only=False, endian="little", load_addr=0,
erased_val=None, save_enctlv=False, security_counter=None): rom_fixed=None, erased_val=None, save_enctlv=False,
security_counter=None):
if load_addr and rom_fixed:
raise click.UsageError("Can not set rom_fixed and load_addr at the same time")
self.version = version or versmod.decode_version("0") self.version = version or versmod.decode_version("0")
self.header_size = header_size self.header_size = header_size
self.pad_header = pad_header self.pad_header = pad_header
@ -145,6 +152,7 @@ class Image():
self.endian = endian self.endian = endian
self.base_addr = None self.base_addr = None
self.load_addr = 0 if load_addr is None else load_addr self.load_addr = 0 if load_addr is None else load_addr
self.rom_fixed = rom_fixed
self.erased_val = 0xff if erased_val is None else int(erased_val, 0) self.erased_val = 0xff if erased_val is None else int(erased_val, 0)
self.payload = [] self.payload = []
self.enckey = None self.enckey = None
@ -281,7 +289,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): sw_type=None, custom_tlvs=None, encrypt_keylen=128):
self.enckey = enckey self.enckey = enckey
# Calculate the hash of the public key # Calculate the hash of the public key
@ -347,10 +355,17 @@ class Image():
if self.enckey is not None: if self.enckey is not None:
pad_len = len(self.payload) % 16 pad_len = len(self.payload) % 16
if pad_len > 0: if pad_len > 0:
self.payload += bytes(16 - pad_len) pad = bytes(16 - pad_len)
if isinstance(self.payload, bytes):
self.payload += pad
else:
self.payload.extend(pad)
# This adds the header to the payload as well # This adds the header to the payload as well
self.add_header(enckey, protected_tlv_size) if encrypt_keylen == 256:
self.add_header(enckey, protected_tlv_size, 256)
else:
self.add_header(enckey, protected_tlv_size)
prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC) prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC)
@ -418,7 +433,10 @@ class Image():
self.payload = self.payload[:protected_tlv_off] self.payload = self.payload[:protected_tlv_off]
if enckey is not None: if enckey is not None:
plainkey = os.urandom(16) if encrypt_keylen == 256:
plainkey = os.urandom(32)
else:
plainkey = os.urandom(16)
if isinstance(enckey, rsa.RSAPublic): if isinstance(enckey, rsa.RSAPublic):
cipherkey = enckey._get_public().encrypt( cipherkey = enckey._get_public().encrypt(
@ -451,16 +469,21 @@ class Image():
self.check_trailer() self.check_trailer()
def add_header(self, enckey, protected_tlv_size): def add_header(self, enckey, protected_tlv_size, aes_length=128):
"""Install the image header.""" """Install the image header."""
flags = 0 flags = 0
if enckey is not None: if enckey is not None:
flags |= IMAGE_F['ENCRYPTED'] if aes_length == 128:
flags |= IMAGE_F['ENCRYPTED_AES128']
else:
flags |= IMAGE_F['ENCRYPTED_AES256']
if self.load_addr != 0: if self.load_addr != 0:
# Indicates that this image should be loaded into RAM # Indicates that this image should be loaded into RAM
# instead of run directly from flash. # instead of run directly from flash.
flags |= IMAGE_F['RAM_LOAD'] flags |= IMAGE_F['RAM_LOAD']
if self.rom_fixed:
flags |= IMAGE_F['ROM_FIXED']
e = STRUCT_ENDIAN_DICT[self.endian] e = STRUCT_ENDIAN_DICT[self.endian]
fmt = (e + fmt = (e +
@ -477,7 +500,7 @@ class Image():
assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE
header = struct.pack(fmt, header = struct.pack(fmt,
IMAGE_MAGIC, IMAGE_MAGIC,
self.load_addr, self.rom_fixed or self.load_addr,
self.header_size, self.header_size,
protected_tlv_size, # TLV Info header + Protected TLVs protected_tlv_size, # TLV Info header + Protected TLVs
len(self.payload) - self.header_size, # ImageSz len(self.payload) - self.header_size, # ImageSz
@ -537,16 +560,22 @@ class Image():
if magic != IMAGE_MAGIC: if magic != IMAGE_MAGIC:
return VerifyResult.INVALID_MAGIC, None, None return VerifyResult.INVALID_MAGIC, None, None
tlv_info = b[header_size+img_size:header_size+img_size+TLV_INFO_SIZE] tlv_off = header_size + img_size
tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE]
magic, tlv_tot = struct.unpack('HH', tlv_info) magic, tlv_tot = struct.unpack('HH', tlv_info)
if magic == TLV_PROT_INFO_MAGIC:
tlv_off += tlv_tot
tlv_info = b[tlv_off:tlv_off+TLV_INFO_SIZE]
magic, tlv_tot = struct.unpack('HH', tlv_info)
if magic != TLV_INFO_MAGIC: if magic != TLV_INFO_MAGIC:
return VerifyResult.INVALID_TLV_INFO_MAGIC, None, None return VerifyResult.INVALID_TLV_INFO_MAGIC, None, None
sha = hashlib.sha256() sha = hashlib.sha256()
sha.update(b[:header_size+img_size]) prot_tlv_size = tlv_off
sha.update(b[:prot_tlv_size])
digest = sha.digest() digest = sha.digest()
tlv_off = header_size + img_size
tlv_end = tlv_off + tlv_tot tlv_end = tlv_off + tlv_tot
tlv_off += TLV_INFO_SIZE # skip tlv info tlv_off += TLV_INFO_SIZE # skip tlv info
while tlv_off < tlv_end: while tlv_off < tlv_end:
@ -562,7 +591,7 @@ class Image():
elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]: elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]:
off = tlv_off + TLV_SIZE off = tlv_off + TLV_SIZE
tlv_sig = b[off:off+tlv_len] tlv_sig = b[off:off+tlv_len]
payload = b[:header_size+img_size] payload = b[:prot_tlv_size]
try: try:
if hasattr(key, 'verify'): if hasattr(key, 'verify'):
key.verify(tlv_sig, payload) key.verify(tlv_sig, payload)

View File

@ -46,7 +46,7 @@ class KeyClass(object):
def emit_rust_public(self, file=sys.stdout): def emit_rust_public(self, file=sys.stdout):
self._emit( self._emit(
header="static {}_PUB_KEY: &'static [u8] = &[".format(self.shortname().upper()), header="static {}_PUB_KEY: &[u8] = &[".format(self.shortname().upper()),
trailer="];", trailer="];",
encoded_bytes=self.get_public_bytes(), encoded_bytes=self.get_public_bytes(),
indent=" ", indent=" ",

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# #
# Copyright 2017-2020 Linaro Limited # Copyright 2017-2020 Linaro Limited
# Copyright 2019-2020 Arm Limited # Copyright 2019-2021 Arm Limited
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -241,6 +241,8 @@ class BasedIntParamType(click.ParamType):
help='Adjust address in hex output file.') help='Adjust address in hex output file.')
@click.option('-L', '--load-addr', type=BasedIntParamType(), required=False, @click.option('-L', '--load-addr', type=BasedIntParamType(), required=False,
help='Load address for image when it should run from RAM.') help='Load address for image when it should run from RAM.')
@click.option('-F', '--rom-fixed', type=BasedIntParamType(), required=False,
help='Set flash address the image is built for.')
@click.option('--save-enctlv', default=False, is_flag=True, @click.option('--save-enctlv', default=False, is_flag=True,
help='When upgrading, save encrypted key TLVs instead of plain ' help='When upgrading, save encrypted key TLVs instead of plain '
'keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option ' 'keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option '
@ -248,6 +250,10 @@ class BasedIntParamType(click.ParamType):
@click.option('-E', '--encrypt', metavar='filename', @click.option('-E', '--encrypt', metavar='filename',
help='Encrypt image using the provided public key. ' help='Encrypt image using the provided public key. '
'(Not supported in direct-xip or ram-load mode.)') '(Not supported in direct-xip or ram-load mode.)')
@click.option('--encrypt-keylen', default='128',
type=click.Choice(['128','256']),
help='When encrypting the image using AES, select a 128 bit or '
'256 bit key len.')
@click.option('-e', '--endian', type=click.Choice(['little', 'big']), @click.option('-e', '--endian', type=click.Choice(['little', 'big']),
default='little', help="Select little or big endian") default='little', help="Select little or big endian")
@click.option('--overwrite-only', default=False, is_flag=True, @click.option('--overwrite-only', default=False, is_flag=True,
@ -293,8 +299,9 @@ class BasedIntParamType(click.ParamType):
.hex extension, otherwise binary format is used''') .hex extension, otherwise binary format is used''')
def sign(key, public_key_format, align, version, pad_sig, header_size, 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, infile, outfile, dependencies, load_addr, hex_addr, endian, encrypt_keylen, encrypt, infile, outfile, dependencies,
erased_val, save_enctlv, security_counter, boot_record, custom_tlv): load_addr, hex_addr, erased_val, save_enctlv, security_counter,
boot_record, custom_tlv, rom_fixed):
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
@ -304,8 +311,8 @@ def sign(key, public_key_format, align, version, pad_sig, header_size,
pad_header=pad_header, pad=pad, confirm=confirm, pad_header=pad_header, pad=pad, confirm=confirm,
align=int(align), slot_size=slot_size, align=int(align), slot_size=slot_size,
max_sectors=max_sectors, overwrite_only=overwrite_only, max_sectors=max_sectors, overwrite_only=overwrite_only,
endian=endian, load_addr=load_addr, erased_val=erased_val, endian=endian, load_addr=load_addr, rom_fixed=rom_fixed,
save_enctlv=save_enctlv, erased_val=erased_val, save_enctlv=save_enctlv,
security_counter=security_counter) security_counter=security_counter)
img.load(infile) img.load(infile)
key = load_key(key) if key else None key = load_key(key) if key else None
@ -341,7 +348,7 @@ def sign(key, public_key_format, align, version, pad_sig, header_size,
custom_tlvs[tag] = value.encode('utf-8') custom_tlvs[tag] = value.encode('utf-8')
img.create(key, public_key_format, enckey, dependencies, boot_record, img.create(key, public_key_format, enckey, dependencies, boot_record,
custom_tlvs) custom_tlvs, int(encrypt_keylen))
img.save(outfile, hex_addr) img.save(outfile, hex_addr)

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# #
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Copyright (c) 2019, Arm Limited. All rights reserved. # Copyright (c) 2019-2021, Arm Limited. All rights reserved.
# #
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
@ -11,7 +11,8 @@
import re import re
import os import os
expression_re = re.compile(r"[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?") # Match (((x) + (y))) mode and ((x) + (y)) mode. x, y can be HEX or DEC value.
expression_re = re.compile(r"([(]?[(]?[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?\s*([\+\-])\s*[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?[)]?[)]?)|([(]?[(]?[(]?(([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*([\+\-]\s*([(]?(((0x)[0-9a-fA-F]+)|([0-9]+))[)]?)\s*)*)[)]?[)]?[)]?)")
# Simple parser that takes a string and evaluates an expression from it. # Simple parser that takes a string and evaluates an expression from it.
# The expression might contain additions and subtractions amongst numbers that # The expression might contain additions and subtractions amongst numbers that

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python3 #! /usr/bin/env python3
# #
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Copyright (c) 2020, Arm Limited. All rights reserved. # Copyright (c) 2020-2021, Arm Limited. All rights reserved.
# #
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# #
@ -26,6 +26,7 @@ import macro_parser
sign_bin_size_re = re.compile(r"^\s*RE_SIGN_BIN_SIZE\s*=\s*(.*)") sign_bin_size_re = re.compile(r"^\s*RE_SIGN_BIN_SIZE\s*=\s*(.*)")
load_addr_re = re.compile(r"^\s*RE_IMAGE_LOAD_ADDRESS\s*=\s*(.*)") load_addr_re = re.compile(r"^\s*RE_IMAGE_LOAD_ADDRESS\s*=\s*(.*)")
rom_fixed_re = re.compile(r"^\s*RE_IMAGE_ROM_FIXED\s*=\s*(.*)")
#This works around Python 2 and Python 3 handling character encodings #This works around Python 2 and Python 3 handling character encodings
#differently. More information about this issue at #differently. More information about this issue at
@ -91,7 +92,7 @@ def wrap(key, align, version, header_size, pad_header, layout, pad, confirm,
slot_size = macro_parser.evaluate_macro(layout, sign_bin_size_re, 0, 1) slot_size = macro_parser.evaluate_macro(layout, sign_bin_size_re, 0, 1)
load_addr = macro_parser.evaluate_macro(layout, load_addr_re, 0, 1) load_addr = macro_parser.evaluate_macro(layout, load_addr_re, 0, 1)
rom_fixed = macro_parser.evaluate_macro(layout, rom_fixed_re, 0, 1)
if "_s" in layout: if "_s" in layout:
boot_record = "SPE" boot_record = "SPE"
elif "_ns" in layout: elif "_ns" in layout:
@ -104,7 +105,8 @@ def wrap(key, align, version, header_size, pad_header, layout, pad, confirm,
pad=pad, confirm=confirm, align=int(align), pad=pad, confirm=confirm, align=int(align),
slot_size=slot_size, max_sectors=max_sectors, slot_size=slot_size, max_sectors=max_sectors,
overwrite_only=overwrite_only, endian=endian, overwrite_only=overwrite_only, endian=endian,
load_addr=load_addr, erased_val=erased_val, load_addr=load_addr, rom_fixed=rom_fixed,
erased_val=erased_val,
save_enctlv=save_enctlv, save_enctlv=save_enctlv,
security_counter=security_counter) security_counter=security_counter)