From 685019250859fba24a984cfdbde1f2dfd39a96be Mon Sep 17 00:00:00 2001 From: Robert Walton Date: Thu, 2 Sep 2021 13:58:09 +0100 Subject: [PATCH] tools: tfm: Update bin_utils --- tools/psa/tfm/bin_utils/imgtool/__init__.py | 2 +- tools/psa/tfm/bin_utils/imgtool/image.py | 59 ++++++++++++++----- .../psa/tfm/bin_utils/imgtool/keys/general.py | 2 +- tools/psa/tfm/bin_utils/imgtool/main.py | 19 ++++-- tools/psa/tfm/bin_utils/macro_parser.py | 5 +- tools/psa/tfm/bin_utils/wrapper.py | 8 ++- 6 files changed, 67 insertions(+), 28 deletions(-) diff --git a/tools/psa/tfm/bin_utils/imgtool/__init__.py b/tools/psa/tfm/bin_utils/imgtool/__init__.py index 3f67eed488..4f1939904d 100644 --- a/tools/psa/tfm/bin_utils/imgtool/__init__.py +++ b/tools/psa/tfm/bin_utils/imgtool/__init__.py @@ -14,4 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -imgtool_version = "1.7.0rc1" +imgtool_version = "1.7.0" diff --git a/tools/psa/tfm/bin_utils/imgtool/image.py b/tools/psa/tfm/bin_utils/imgtool/image.py index 7d7f2bac01..684c6b354a 100644 --- a/tools/psa/tfm/bin_utils/imgtool/image.py +++ b/tools/psa/tfm/bin_utils/imgtool/image.py @@ -1,6 +1,6 @@ # Copyright 2018 Nordic Semiconductor ASA # Copyright 2017-2020 Linaro Limited -# Copyright 2019-2020 Arm Limited +# Copyright 2019-2021 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # @@ -51,9 +51,11 @@ MAX_SW_TYPE_LENGTH = 12 # Bytes # Image header flags. IMAGE_F = { 'PIC': 0x0000001, + 'ENCRYPTED_AES128': 0x0000004, + 'ENCRYPTED_AES256': 0x0000008, 'NON_BOOTABLE': 0x0000010, 'RAM_LOAD': 0x0000020, - 'ENCRYPTED': 0x0000004, + 'ROM_FIXED': 0x0000100, } TLV_VALUES = { @@ -66,7 +68,7 @@ TLV_VALUES = { 'RSA3072': 0x23, 'ED25519': 0x24, 'ENCRSA2048': 0x30, - 'ENCKW128': 0x31, + 'ENCKW': 0x31, 'ENCEC256': 0x32, 'ENCX25519': 0x33, 'DEPENDENCY': 0x40, @@ -132,7 +134,12 @@ class Image(): pad_header=False, pad=False, confirm=False, align=1, slot_size=0, max_sectors=DEFAULT_MAX_SECTORS, 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.header_size = header_size self.pad_header = pad_header @@ -145,6 +152,7 @@ class Image(): self.endian = endian self.base_addr = None 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.payload = [] self.enckey = None @@ -281,7 +289,7 @@ class Image(): return cipherkey, ciphermac, pubk 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 # Calculate the hash of the public key @@ -347,10 +355,17 @@ class Image(): if self.enckey is not None: pad_len = len(self.payload) % 16 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 - 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) @@ -418,7 +433,10 @@ class Image(): self.payload = self.payload[:protected_tlv_off] 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): cipherkey = enckey._get_public().encrypt( @@ -451,16 +469,21 @@ class Image(): 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.""" flags = 0 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: # Indicates that this image should be loaded into RAM # instead of run directly from flash. flags |= IMAGE_F['RAM_LOAD'] + if self.rom_fixed: + flags |= IMAGE_F['ROM_FIXED'] e = STRUCT_ENDIAN_DICT[self.endian] fmt = (e + @@ -477,7 +500,7 @@ class Image(): assert struct.calcsize(fmt) == IMAGE_HEADER_SIZE header = struct.pack(fmt, IMAGE_MAGIC, - self.load_addr, + self.rom_fixed or self.load_addr, self.header_size, protected_tlv_size, # TLV Info header + Protected TLVs len(self.payload) - self.header_size, # ImageSz @@ -537,16 +560,22 @@ class Image(): if magic != IMAGE_MAGIC: 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) + 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: return VerifyResult.INVALID_TLV_INFO_MAGIC, None, None sha = hashlib.sha256() - sha.update(b[:header_size+img_size]) + prot_tlv_size = tlv_off + sha.update(b[:prot_tlv_size]) digest = sha.digest() - tlv_off = header_size + img_size tlv_end = tlv_off + tlv_tot tlv_off += TLV_INFO_SIZE # skip tlv info while tlv_off < tlv_end: @@ -562,7 +591,7 @@ class Image(): elif key is not None and tlv_type == TLV_VALUES[key.sig_tlv()]: off = tlv_off + TLV_SIZE tlv_sig = b[off:off+tlv_len] - payload = b[:header_size+img_size] + payload = b[:prot_tlv_size] try: if hasattr(key, 'verify'): key.verify(tlv_sig, payload) diff --git a/tools/psa/tfm/bin_utils/imgtool/keys/general.py b/tools/psa/tfm/bin_utils/imgtool/keys/general.py index 442b1eab8b..3fad3ddc10 100644 --- a/tools/psa/tfm/bin_utils/imgtool/keys/general.py +++ b/tools/psa/tfm/bin_utils/imgtool/keys/general.py @@ -46,7 +46,7 @@ class KeyClass(object): def emit_rust_public(self, file=sys.stdout): self._emit( - header="static {}_PUB_KEY: &'static [u8] = &[".format(self.shortname().upper()), + header="static {}_PUB_KEY: &[u8] = &[".format(self.shortname().upper()), trailer="];", encoded_bytes=self.get_public_bytes(), indent=" ", diff --git a/tools/psa/tfm/bin_utils/imgtool/main.py b/tools/psa/tfm/bin_utils/imgtool/main.py index 46be8a8271..dd6c0447b0 100755 --- a/tools/psa/tfm/bin_utils/imgtool/main.py +++ b/tools/psa/tfm/bin_utils/imgtool/main.py @@ -1,7 +1,7 @@ #! /usr/bin/env python3 # # Copyright 2017-2020 Linaro Limited -# Copyright 2019-2020 Arm Limited +# Copyright 2019-2021 Arm Limited # # SPDX-License-Identifier: Apache-2.0 # @@ -241,6 +241,8 @@ class BasedIntParamType(click.ParamType): help='Adjust address in hex output file.') @click.option('-L', '--load-addr', type=BasedIntParamType(), required=False, 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, help='When upgrading, save encrypted key TLVs instead of plain ' 'keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option ' @@ -248,6 +250,10 @@ class BasedIntParamType(click.ParamType): @click.option('-E', '--encrypt', metavar='filename', help='Encrypt image using the provided public key. ' '(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']), default='little', help="Select little or big endian") @click.option('--overwrite-only', default=False, is_flag=True, @@ -293,8 +299,9 @@ class BasedIntParamType(click.ParamType): .hex extension, otherwise binary format is used''') def sign(key, public_key_format, align, version, pad_sig, header_size, pad_header, slot_size, pad, confirm, max_sectors, overwrite_only, - endian, encrypt, infile, outfile, dependencies, load_addr, hex_addr, - erased_val, save_enctlv, security_counter, boot_record, custom_tlv): + endian, encrypt_keylen, encrypt, infile, outfile, dependencies, + load_addr, hex_addr, erased_val, save_enctlv, security_counter, + boot_record, custom_tlv, rom_fixed): if confirm: # 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, align=int(align), slot_size=slot_size, max_sectors=max_sectors, overwrite_only=overwrite_only, - endian=endian, load_addr=load_addr, erased_val=erased_val, - save_enctlv=save_enctlv, + endian=endian, load_addr=load_addr, rom_fixed=rom_fixed, + erased_val=erased_val, save_enctlv=save_enctlv, security_counter=security_counter) img.load(infile) 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') img.create(key, public_key_format, enckey, dependencies, boot_record, - custom_tlvs) + custom_tlvs, int(encrypt_keylen)) img.save(outfile, hex_addr) diff --git a/tools/psa/tfm/bin_utils/macro_parser.py b/tools/psa/tfm/bin_utils/macro_parser.py index 5d9418a4e8..12e8a92f1a 100644 --- a/tools/psa/tfm/bin_utils/macro_parser.py +++ b/tools/psa/tfm/bin_utils/macro_parser.py @@ -1,7 +1,7 @@ #! /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 # @@ -11,7 +11,8 @@ import re 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. # The expression might contain additions and subtractions amongst numbers that diff --git a/tools/psa/tfm/bin_utils/wrapper.py b/tools/psa/tfm/bin_utils/wrapper.py index 7799ce06da..247cb1042f 100755 --- a/tools/psa/tfm/bin_utils/wrapper.py +++ b/tools/psa/tfm/bin_utils/wrapper.py @@ -1,7 +1,7 @@ #! /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 # @@ -26,6 +26,7 @@ import macro_parser 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*(.*)") +rom_fixed_re = re.compile(r"^\s*RE_IMAGE_ROM_FIXED\s*=\s*(.*)") #This works around Python 2 and Python 3 handling character encodings #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) 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: boot_record = "SPE" 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), slot_size=slot_size, max_sectors=max_sectors, 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, security_counter=security_counter)