1e8ef5353SArnaud Pouliquen#!/usr/bin/env python3 2e8ef5353SArnaud Pouliquen# SPDX-License-Identifier: BSD-2-Clause 3e8ef5353SArnaud Pouliquen# 4e8ef5353SArnaud Pouliquen# Copyright (C) 2023, STMicroelectronics 5e8ef5353SArnaud Pouliquen# 6e8ef5353SArnaud Pouliquen 7e8ef5353SArnaud Pouliquentry: 8e8ef5353SArnaud Pouliquen from elftools.elf.elffile import ELFFile 9e8ef5353SArnaud Pouliquen from elftools.elf.sections import SymbolTableSection 10e8ef5353SArnaud Pouliquen from elftools.elf.enums import ENUM_P_TYPE_ARM 11e8ef5353SArnaud Pouliquen from elftools.elf.enums import * 12e8ef5353SArnaud Pouliquenexcept ImportError: 13e8ef5353SArnaud Pouliquen print(""" 14e8ef5353SArnaud Pouliquen*** 15e8ef5353SArnaud PouliquenERROR: "pyelftools" python module is not installed or version < 0.25. 16e8ef5353SArnaud Pouliquen*** 17e8ef5353SArnaud Pouliquen""") 18e8ef5353SArnaud Pouliquen raise 19e8ef5353SArnaud Pouliquen 20e8ef5353SArnaud Pouliquentry: 21e8ef5353SArnaud Pouliquen from Cryptodome.Hash import SHA256 22e8ef5353SArnaud Pouliquen from Cryptodome.Signature import pkcs1_15 23e8ef5353SArnaud Pouliquen from Cryptodome.PublicKey import RSA 24e8ef5353SArnaud Pouliquen from Cryptodome.Signature import DSS 25e8ef5353SArnaud Pouliquen from Cryptodome.PublicKey import ECC 26e8ef5353SArnaud Pouliquenexcept ImportError: 27e8ef5353SArnaud Pouliquen print(""" 28e8ef5353SArnaud Pouliquen *** 29e8ef5353SArnaud Pouliquen ERROR: "pycryptodomex" python module should be installed. 30e8ef5353SArnaud Pouliquen *** 31e8ef5353SArnaud Pouliquen """) 32e8ef5353SArnaud Pouliquen raise 33e8ef5353SArnaud Pouliquen 34e8ef5353SArnaud Pouliquenimport os 35e8ef5353SArnaud Pouliquenimport sys 36e8ef5353SArnaud Pouliquenimport struct 37e8ef5353SArnaud Pouliquenimport logging 38e8ef5353SArnaud Pouliquenimport binascii 39e8ef5353SArnaud Pouliquen 40e8ef5353SArnaud Pouliquen# Generated file structure: 41e8ef5353SArnaud Pouliquen# 42e8ef5353SArnaud Pouliquen# -----+-------------+ 43e8ef5353SArnaud Pouliquen# / | Magic | 32-bit word, magic value equal to 44e8ef5353SArnaud Pouliquen# / +-------------+ 0x3543A468 45e8ef5353SArnaud Pouliquen# / +-------------+ 46e8ef5353SArnaud Pouliquen# / | version | 32-bit word, version of the format 47e8ef5353SArnaud Pouliquen# / +-------------+ 48e8ef5353SArnaud Pouliquen# +-----------+ +-------------+ 49e8ef5353SArnaud Pouliquen# | Header | | TLV size | 32-bit word, size of the TLV 50e8ef5353SArnaud Pouliquen# +-----------+ +-------------+ (aligned on 64-bit), in bytes. 51e8ef5353SArnaud Pouliquen# \ +-------------+ 52e8ef5353SArnaud Pouliquen# \ | sign size | 32-bit word, size of the signature 53e8ef5353SArnaud Pouliquen# \ +-------------+ (aligned on 64-bit), in bytes. 54e8ef5353SArnaud Pouliquen# \ +-------------+ 55e8ef5353SArnaud Pouliquen# \ | images size | 32-bit word, size of the images to 56e8ef5353SArnaud Pouliquen# -----+-------------+ load (aligned on 64-bit), in bytes. 57e8ef5353SArnaud Pouliquen# 58e8ef5353SArnaud Pouliquen# +-------------+ Information used to authenticate the 59e8ef5353SArnaud Pouliquen# | TLV | images and boot the remote processor, 60e8ef5353SArnaud Pouliquen# | | stored in Type-Length-Value format. 61e8ef5353SArnaud Pouliquen# +-------------+ 'Type' and 'Length' are 32-bit words. 62e8ef5353SArnaud Pouliquen# 63e8ef5353SArnaud Pouliquen# +-------------+ 64e8ef5353SArnaud Pouliquen# | Signature | Signature of the header and the TLV. 65e8ef5353SArnaud Pouliquen# +-------------+ 66e8ef5353SArnaud Pouliquen# 67e8ef5353SArnaud Pouliquen# +-------------+ 68e8ef5353SArnaud Pouliquen# | Firmware | 69e8ef5353SArnaud Pouliquen# | image 1 | 70e8ef5353SArnaud Pouliquen# +-------------+ 71e8ef5353SArnaud Pouliquen# ... 72e8ef5353SArnaud Pouliquen# +-------------+ 73e8ef5353SArnaud Pouliquen# | Firmware | 74e8ef5353SArnaud Pouliquen# | image n | 75e8ef5353SArnaud Pouliquen# +-------------+ 76e8ef5353SArnaud Pouliquen 77e8ef5353SArnaud Pouliquen# Generic type definitions 78e8ef5353SArnaud PouliquenTLV_TYPES = { 79e8ef5353SArnaud Pouliquen 'SIGNTYPE': 0x00000001, # algorithm used for signature 80e8ef5353SArnaud Pouliquen 'HASHTYPE': 0x00000002, # algorithm used for computing segment's hash 81e8ef5353SArnaud Pouliquen 'NUM_IMG': 0x00000003, # number of images to load 82e8ef5353SArnaud Pouliquen 'IMGTYPE': 0x00000004, # array of type of images to load 83e8ef5353SArnaud Pouliquen 'IMGSIZE': 0x00000005, # array of the size of the images to load 84e8ef5353SArnaud Pouliquen 'HASHTABLE': 0x000000010, # segment hash table for authentication 85e8ef5353SArnaud Pouliquen 'PKEYINFO': 0x0000000011, # information to retrieve signature key 86e8ef5353SArnaud Pouliquen} 87e8ef5353SArnaud Pouliquen 88e8ef5353SArnaud PouliquenGENERIC_TLV_TYPE_RANGE = range(0x00000000, 0x00010000) 89e8ef5353SArnaud PouliquenPLATFORM_TLV_TYPE_RANGE = range(0x00010000, 0x00020000) 90e8ef5353SArnaud Pouliquen 91e8ef5353SArnaud PouliquenHEADER_MAGIC = 0x3543A468 92e8ef5353SArnaud Pouliquen 93e8ef5353SArnaud Pouliquenlogging.basicConfig(stream=sys.stderr, level=logging.INFO) 94e8ef5353SArnaud Pouliquen 95e8ef5353SArnaud PouliquenENUM_HASH_TYPE = dict( 96e8ef5353SArnaud Pouliquen SHA256=1, 97e8ef5353SArnaud Pouliquen) 98e8ef5353SArnaud Pouliquen 99e8ef5353SArnaud PouliquenENUM_SIGNATURE_TYPE = dict( 100e8ef5353SArnaud Pouliquen RSA=1, 101e8ef5353SArnaud Pouliquen ECC=2, 102e8ef5353SArnaud Pouliquen) 103e8ef5353SArnaud Pouliquen 104e8ef5353SArnaud PouliquenENUM_BINARY_TYPE = dict( 105e8ef5353SArnaud Pouliquen ELF=1, 106e8ef5353SArnaud Pouliquen) 107e8ef5353SArnaud Pouliquen 108e8ef5353SArnaud Pouliquen 109e8ef5353SArnaud Pouliquendef dump_buffer(buf, step=16, name="", logger=logging.debug, indent=""): 110e8ef5353SArnaud Pouliquen logger("%s%s:" % (indent, name)) 111e8ef5353SArnaud Pouliquen for i in range(0, len(buf), step): 112e8ef5353SArnaud Pouliquen logger("%s " % (indent) + " ". 113e8ef5353SArnaud Pouliquen join(["%02X" % c for c in buf[i:i+step]])) 114e8ef5353SArnaud Pouliquen logger("\n") 115e8ef5353SArnaud Pouliquen 116e8ef5353SArnaud Pouliquen 117e8ef5353SArnaud Pouliquenclass TLV(): 118e8ef5353SArnaud Pouliquen def __init__(self): 119e8ef5353SArnaud Pouliquen self.buf = bytearray() 120e8ef5353SArnaud Pouliquen self.tlvs = {} 121e8ef5353SArnaud Pouliquen 122e8ef5353SArnaud Pouliquen def add(self, kind, payload): 123e8ef5353SArnaud Pouliquen """ 124e8ef5353SArnaud Pouliquen Add a TLV record. Argument type is either the type scalar ID or a 125e8ef5353SArnaud Pouliquen matching string defined in TLV_TYPES. 126e8ef5353SArnaud Pouliquen """ 127e8ef5353SArnaud Pouliquen if isinstance(kind, int): 128e8ef5353SArnaud Pouliquen buf = struct.pack('II', kind, len(payload)) 129e8ef5353SArnaud Pouliquen else: 130e8ef5353SArnaud Pouliquen buf = struct.pack('II', TLV_TYPES[kind], len(payload)) 131e8ef5353SArnaud Pouliquen 132e8ef5353SArnaud Pouliquen # Ensure that each TLV is 64-bit aligned 133e8ef5353SArnaud Pouliquen align_64b = (len(payload) + len(buf)) % 8 134e8ef5353SArnaud Pouliquen self.buf += buf 135e8ef5353SArnaud Pouliquen self.buf += payload 136e8ef5353SArnaud Pouliquen if align_64b: 137e8ef5353SArnaud Pouliquen self.buf += bytearray(8 - align_64b) 138e8ef5353SArnaud Pouliquen 139e8ef5353SArnaud Pouliquen def add_plat_tlv(self, cust_tlv): 140e8ef5353SArnaud Pouliquen # Get list of custom protected TLVs from the command-line 141e8ef5353SArnaud Pouliquen for tlv in cust_tlv: 142e8ef5353SArnaud Pouliquen type_id = int(tlv[0], 0) 143e8ef5353SArnaud Pouliquen 144e8ef5353SArnaud Pouliquen if type_id not in PLATFORM_TLV_TYPE_RANGE: 145e8ef5353SArnaud Pouliquen raise Exception('TLV %s not in range' % hex(type_id)) 146e8ef5353SArnaud Pouliquen 147e8ef5353SArnaud Pouliquen value = tlv[1] 148e8ef5353SArnaud Pouliquen if value.startswith('0x'): 149e8ef5353SArnaud Pouliquen int_val = int(value[2:], 16) 150e8ef5353SArnaud Pouliquen self.tlvs[type_id] = int_val.to_bytes(4, 'little') 151e8ef5353SArnaud Pouliquen else: 152e8ef5353SArnaud Pouliquen self.tlvs[type_id] = value.encode('utf-8') 153e8ef5353SArnaud Pouliquen 154e8ef5353SArnaud Pouliquen if self.tlvs is not None: 155e8ef5353SArnaud Pouliquen for type_id, value in self.tlvs.items(): 156e8ef5353SArnaud Pouliquen self.add(type_id, value) 157e8ef5353SArnaud Pouliquen 158e8ef5353SArnaud Pouliquen def get(self): 159e8ef5353SArnaud Pouliquen """ 160e8ef5353SArnaud Pouliquen Get a byte-array that concatenates all the TLV added. 161e8ef5353SArnaud Pouliquen """ 162e8ef5353SArnaud Pouliquen if len(self.buf) == 0: 163e8ef5353SArnaud Pouliquen return bytes() 164e8ef5353SArnaud Pouliquen return bytes(self.buf) 165e8ef5353SArnaud Pouliquen 166e8ef5353SArnaud Pouliquen 167e8ef5353SArnaud Pouliquenclass RSA_Signature(object): 168e8ef5353SArnaud Pouliquen 169e8ef5353SArnaud Pouliquen def __init__(self, key): 170e8ef5353SArnaud Pouliquen self._hasher = SHA256.new() 171e8ef5353SArnaud Pouliquen self.signer = pkcs1_15.new(key) 172e8ef5353SArnaud Pouliquen 173e8ef5353SArnaud Pouliquen def hash_compute(self, segment): 174e8ef5353SArnaud Pouliquen self._hasher.update(segment) 175e8ef5353SArnaud Pouliquen 176e8ef5353SArnaud Pouliquen def sign(self): 177e8ef5353SArnaud Pouliquen return self.signer.sign(self._hasher) 178e8ef5353SArnaud Pouliquen 179e8ef5353SArnaud Pouliquen 180e8ef5353SArnaud Pouliquenclass ECC_Signature(object): 181e8ef5353SArnaud Pouliquen 182e8ef5353SArnaud Pouliquen def __init__(self, key): 183e8ef5353SArnaud Pouliquen self._hasher = SHA256.new() 184e8ef5353SArnaud Pouliquen self.signer = DSS.new(key, 'fips-186-3') 185e8ef5353SArnaud Pouliquen 186e8ef5353SArnaud Pouliquen def hash_compute(self, segment): 187e8ef5353SArnaud Pouliquen self._hasher.update(segment) 188e8ef5353SArnaud Pouliquen 189e8ef5353SArnaud Pouliquen def sign(self): 190e8ef5353SArnaud Pouliquen return self.signer.sign(self._hasher) 191e8ef5353SArnaud Pouliquen 192e8ef5353SArnaud Pouliquen 193e8ef5353SArnaud PouliquenSignature = { 194e8ef5353SArnaud Pouliquen 1: RSA_Signature, 195e8ef5353SArnaud Pouliquen 2: ECC_Signature, 196e8ef5353SArnaud Pouliquen} 197e8ef5353SArnaud Pouliquen 198e8ef5353SArnaud Pouliquen 199e8ef5353SArnaud Pouliquenclass SegmentHashStruct: 200e8ef5353SArnaud Pouliquen pass 201e8ef5353SArnaud Pouliquen 202e8ef5353SArnaud Pouliquen 203e8ef5353SArnaud Pouliquenclass SegmentHash(object): 204e8ef5353SArnaud Pouliquen ''' 205e8ef5353SArnaud Pouliquen Hash table based on Elf program segments 206e8ef5353SArnaud Pouliquen ''' 207e8ef5353SArnaud Pouliquen def __init__(self, img): 208e8ef5353SArnaud Pouliquen self._num_segments = img.num_segments() 209e8ef5353SArnaud Pouliquen self._pack_fmt = '<%dL' % 8 210e8ef5353SArnaud Pouliquen self.img = img 211e8ef5353SArnaud Pouliquen self.hashProgTable = bytes() 212e8ef5353SArnaud Pouliquen self._offset = 0 213e8ef5353SArnaud Pouliquen 214e8ef5353SArnaud Pouliquen def get_table(self): 215e8ef5353SArnaud Pouliquen ''' 216e8ef5353SArnaud Pouliquen Create a segment hash table containing for each segment: 217e8ef5353SArnaud Pouliquen - the segments header 218e8ef5353SArnaud Pouliquen - a hash of the segment 219e8ef5353SArnaud Pouliquen ''' 220e8ef5353SArnaud Pouliquen h = SHA256.new() 221e8ef5353SArnaud Pouliquen seg = SegmentHashStruct() 222e8ef5353SArnaud Pouliquen self.size = (h.digest_size + 32) * self._num_segments 223e8ef5353SArnaud Pouliquen logging.debug("hash section size %d" % self.size) 224e8ef5353SArnaud Pouliquen del h 225e8ef5353SArnaud Pouliquen self.buf = bytearray(self.size) 226e8ef5353SArnaud Pouliquen self._bufview_ = memoryview(self.buf) 227e8ef5353SArnaud Pouliquen 228e8ef5353SArnaud Pouliquen for i in range(self._num_segments): 229e8ef5353SArnaud Pouliquen h = SHA256.new() 230e8ef5353SArnaud Pouliquen segment = self.img.get_segment(i) 231e8ef5353SArnaud Pouliquen seg.header = self.img.get_segment(i).header 232e8ef5353SArnaud Pouliquen logging.debug("compute hash for segment offset %s" % seg.header) 233e8ef5353SArnaud Pouliquen h.update(segment.data()) 234e8ef5353SArnaud Pouliquen seg.hash = h.digest() 235e8ef5353SArnaud Pouliquen logging.debug("hash computed: %s" % seg.hash) 236e8ef5353SArnaud Pouliquen del h 237e8ef5353SArnaud Pouliquen struct.pack_into('<I', self._bufview_, self._offset, 238e8ef5353SArnaud Pouliquen ENUM_P_TYPE_ARM[seg.header.p_type]) 239e8ef5353SArnaud Pouliquen self._offset += 4 240e8ef5353SArnaud Pouliquen struct.pack_into('<7I', self._bufview_, self._offset, 241e8ef5353SArnaud Pouliquen seg.header.p_offset, seg.header.p_vaddr, 242e8ef5353SArnaud Pouliquen seg.header.p_paddr, seg.header.p_filesz, 243e8ef5353SArnaud Pouliquen seg.header.p_memsz, seg.header.p_flags, 244e8ef5353SArnaud Pouliquen seg.header.p_align) 245e8ef5353SArnaud Pouliquen self._offset += 28 246e8ef5353SArnaud Pouliquen struct.pack_into('<32B', self._bufview_, self._offset, *seg.hash) 247e8ef5353SArnaud Pouliquen self._offset += 32 248e8ef5353SArnaud Pouliquen dump_buffer(self.buf, name='hash table', indent="\t") 249e8ef5353SArnaud Pouliquen return self.buf 250e8ef5353SArnaud Pouliquen 251e8ef5353SArnaud Pouliquen 252e8ef5353SArnaud Pouliquenclass ImageHeader(object): 253e8ef5353SArnaud Pouliquen ''' 254e8ef5353SArnaud Pouliquen Image header 255e8ef5353SArnaud Pouliquen ''' 256e8ef5353SArnaud Pouliquen 257e8ef5353SArnaud Pouliquen magic = 'HELF' # SHDR_MAGIC 258e8ef5353SArnaud Pouliquen version = 1 259e8ef5353SArnaud Pouliquen 260e8ef5353SArnaud Pouliquen MAGIC_OFFSET = 0 261e8ef5353SArnaud Pouliquen VERSION_OFFSET = 4 262e8ef5353SArnaud Pouliquen SIGN_LEN_OFFSET = 8 263e8ef5353SArnaud Pouliquen IMG_LEN_OFFSET = 12 264e8ef5353SArnaud Pouliquen TLV_LEN_OFFSET = 16 265e8ef5353SArnaud Pouliquen PTLV_LEN_OFFSET = 20 266e8ef5353SArnaud Pouliquen 267e8ef5353SArnaud Pouliquen def __init__(self): 268e8ef5353SArnaud Pouliquen self.size = 56 269e8ef5353SArnaud Pouliquen 270e8ef5353SArnaud Pouliquen self.magic = HEADER_MAGIC 271e8ef5353SArnaud Pouliquen self.version = 1 272e8ef5353SArnaud Pouliquen self.tlv_length = 0 273e8ef5353SArnaud Pouliquen self.sign_length = 0 274e8ef5353SArnaud Pouliquen self.img_length = 0 275e8ef5353SArnaud Pouliquen 276e8ef5353SArnaud Pouliquen self.shdr = struct.pack('<IIIII', 277e8ef5353SArnaud Pouliquen self.magic, self.version, 278e8ef5353SArnaud Pouliquen self.tlv_length, self.sign_length, 279e8ef5353SArnaud Pouliquen self.img_length) 280e8ef5353SArnaud Pouliquen 281e8ef5353SArnaud Pouliquen def dump(self): 282e8ef5353SArnaud Pouliquen logging.debug("\tMAGIC\t\t= %08X" % (self.magic)) 283e8ef5353SArnaud Pouliquen logging.debug("\tHEADER_VERSION\t= %08X" % (self.version)) 284e8ef5353SArnaud Pouliquen logging.debug("\tTLV_LENGTH\t= %08X" % (self.tlv_length)) 285e8ef5353SArnaud Pouliquen logging.debug("\tSIGN_LENGTH\t= %08X" % (self.sign_length)) 286e8ef5353SArnaud Pouliquen logging.debug("\tIMAGE_LENGTH\t= %08X" % (self.img_length)) 287e8ef5353SArnaud Pouliquen 288e8ef5353SArnaud Pouliquen def get_packed(self): 289e8ef5353SArnaud Pouliquen return struct.pack('<IIIII', 290e8ef5353SArnaud Pouliquen self.magic, self.version, 291e8ef5353SArnaud Pouliquen self.tlv_length, self.sign_length, self.img_length) 292e8ef5353SArnaud Pouliquen 293e8ef5353SArnaud Pouliquen 294e8ef5353SArnaud Pouliquendef get_args(logger): 295e8ef5353SArnaud Pouliquen from argparse import ArgumentParser, RawDescriptionHelpFormatter 296e8ef5353SArnaud Pouliquen import textwrap 297e8ef5353SArnaud Pouliquen 298e8ef5353SArnaud Pouliquen parser = ArgumentParser( 299e8ef5353SArnaud Pouliquen description='Sign a remote processor firmware loadable by OP-TEE.', 300e8ef5353SArnaud Pouliquen usage='\n %(prog)s [ arguments ]\n\n' 301e8ef5353SArnaud Pouliquen ' Generate signed loadable binary \n' + 302e8ef5353SArnaud Pouliquen ' Takes arguments --in, --out --key\n' + 303e8ef5353SArnaud Pouliquen ' %(prog)s --help show available arguments\n\n') 304e8ef5353SArnaud Pouliquen parser.add_argument('--in', required=True, dest='in_file', 305e8ef5353SArnaud Pouliquen help='Name of firmware input file ' + 306e8ef5353SArnaud Pouliquen '(can be used multiple times)', action='append') 307e8ef5353SArnaud Pouliquen parser.add_argument('--out', required=True, dest='out_file', 308e8ef5353SArnaud Pouliquen help='Name of the signed firmware output file') 309e8ef5353SArnaud Pouliquen parser.add_argument('--key', required=True, 310e8ef5353SArnaud Pouliquen help='Name of signing key file', 311e8ef5353SArnaud Pouliquen dest='key_file') 312e8ef5353SArnaud Pouliquen parser.add_argument('--key_info', required=False, 313e8ef5353SArnaud Pouliquen help='Name file containing extra key information', 314e8ef5353SArnaud Pouliquen dest='key_info') 315e8ef5353SArnaud Pouliquen parser.add_argument('--key_type', required=False, 316e8ef5353SArnaud Pouliquen help='Type of signing key: should be RSA or ECC', 317e8ef5353SArnaud Pouliquen default='RSA', 318e8ef5353SArnaud Pouliquen dest='key_type') 319*39a4a0eeSArnaud Pouliquen parser.add_argument('--key_pwd', required=False, 320*39a4a0eeSArnaud Pouliquen help='passphrase for the private key decryption', 321*39a4a0eeSArnaud Pouliquen dest='key_pwd') 322e8ef5353SArnaud Pouliquen parser.add_argument('--plat-tlv', required=False, nargs=2, 323e8ef5353SArnaud Pouliquen metavar=("ID", "value"), action='append', 324e8ef5353SArnaud Pouliquen help='Platform TLV that will be placed into image ' 325e8ef5353SArnaud Pouliquen 'plat_tlv area. Add "0x" prefix to interpret ' 326e8ef5353SArnaud Pouliquen 'the value as an integer, otherwise it will be ' 327e8ef5353SArnaud Pouliquen 'interpreted as a string. Option can be used ' 328e8ef5353SArnaud Pouliquen 'multiple times to add multiple TLVs.', 329e8ef5353SArnaud Pouliquen default=[], dest='plat_tlv') 330e8ef5353SArnaud Pouliquen 331e8ef5353SArnaud Pouliquen parsed = parser.parse_args() 332e8ef5353SArnaud Pouliquen 333e8ef5353SArnaud Pouliquen # Set defaults for optional arguments. 334e8ef5353SArnaud Pouliquen 335e8ef5353SArnaud Pouliquen if parsed.out_file is None: 336e8ef5353SArnaud Pouliquen parsed.out_file = str(parsed.in_file)+'.sig' 337e8ef5353SArnaud Pouliquen 338e8ef5353SArnaud Pouliquen return parsed 339e8ef5353SArnaud Pouliquen 340e8ef5353SArnaud Pouliquen 341*39a4a0eeSArnaud Pouliquendef rsa_key(key_file, key_pwd): 342*39a4a0eeSArnaud Pouliquen return RSA.importKey(open(key_file).read(), key_pwd) 343e8ef5353SArnaud Pouliquen 344e8ef5353SArnaud Pouliquen 345*39a4a0eeSArnaud Pouliquendef ecc_key(key_file, key_pwd): 346*39a4a0eeSArnaud Pouliquen return ECC.import_key(open(key_file).read(), key_pwd) 347e8ef5353SArnaud Pouliquen 348e8ef5353SArnaud Pouliquen 349e8ef5353SArnaud Pouliquenkey_type = { 350e8ef5353SArnaud Pouliquen 1: rsa_key, 351e8ef5353SArnaud Pouliquen 2: ecc_key, 352e8ef5353SArnaud Pouliquen} 353e8ef5353SArnaud Pouliquen 354e8ef5353SArnaud Pouliquen 355e8ef5353SArnaud Pouliquendef rsa_sig_size(key): 356e8ef5353SArnaud Pouliquen return key.size_in_bytes() 357e8ef5353SArnaud Pouliquen 358e8ef5353SArnaud Pouliquen 359e8ef5353SArnaud Pouliquendef ecc_sig_size(key): 360e8ef5353SArnaud Pouliquen # to be improve... 361e8ef5353SArnaud Pouliquen # DSA size is N/4 so 64 for DSA (L,N) = (2048, 256) 362e8ef5353SArnaud Pouliquen return 64 363e8ef5353SArnaud Pouliquen 364e8ef5353SArnaud Pouliquen 365e8ef5353SArnaud Pouliquensig_size_type = { 366e8ef5353SArnaud Pouliquen 1: rsa_sig_size, 367e8ef5353SArnaud Pouliquen 2: ecc_sig_size, 368e8ef5353SArnaud Pouliquen} 369e8ef5353SArnaud Pouliquen 370e8ef5353SArnaud Pouliquen 371e8ef5353SArnaud Pouliquendef main(): 372e8ef5353SArnaud Pouliquen from Cryptodome.Signature import pss 373e8ef5353SArnaud Pouliquen from Cryptodome.Hash import SHA256 374e8ef5353SArnaud Pouliquen from Cryptodome.PublicKey import RSA 375e8ef5353SArnaud Pouliquen import base64 376e8ef5353SArnaud Pouliquen import logging 377e8ef5353SArnaud Pouliquen import struct 378e8ef5353SArnaud Pouliquen 379e8ef5353SArnaud Pouliquen logging.basicConfig() 380e8ef5353SArnaud Pouliquen logger = logging.getLogger(os.path.basename(__file__)) 381e8ef5353SArnaud Pouliquen 382e8ef5353SArnaud Pouliquen args = get_args(logger) 383e8ef5353SArnaud Pouliquen 384e8ef5353SArnaud Pouliquen # Initialise the header */ 385e8ef5353SArnaud Pouliquen s_header = ImageHeader() 386e8ef5353SArnaud Pouliquen tlv = TLV() 387e8ef5353SArnaud Pouliquen 388e8ef5353SArnaud Pouliquen sign_type = ENUM_SIGNATURE_TYPE[args.key_type] 389e8ef5353SArnaud Pouliquen get_key = key_type.get(sign_type, lambda: "Invalid sign type") 390e8ef5353SArnaud Pouliquen 391*39a4a0eeSArnaud Pouliquen key = get_key(args.key_file, args.key_pwd) 392e8ef5353SArnaud Pouliquen 393e8ef5353SArnaud Pouliquen if not key.has_private(): 394e8ef5353SArnaud Pouliquen logger.error('Provided key cannot be used for signing, ') 395e8ef5353SArnaud Pouliquen sys.exit(1) 396e8ef5353SArnaud Pouliquen 397e8ef5353SArnaud Pouliquen tlv.add('SIGNTYPE', sign_type.to_bytes(1, 'little')) 398e8ef5353SArnaud Pouliquen 399e8ef5353SArnaud Pouliquen images_type = [] 400e8ef5353SArnaud Pouliquen hash_tlv = bytearray() 401e8ef5353SArnaud Pouliquen images_size = [] 402e8ef5353SArnaud Pouliquen 403e8ef5353SArnaud Pouliquen # Firmware image 404e8ef5353SArnaud Pouliquen for inputf in args.in_file: 405e8ef5353SArnaud Pouliquen logging.debug("image %s" % inputf) 406e8ef5353SArnaud Pouliquen input_file = open(inputf, 'rb') 407e8ef5353SArnaud Pouliquen img = ELFFile(input_file) 408e8ef5353SArnaud Pouliquen 409e8ef5353SArnaud Pouliquen # Only ARM machine has been tested and well supported yet. 410e8ef5353SArnaud Pouliquen # Indeed this script uses of ENUM_P_TYPE_ARM dic 411e8ef5353SArnaud Pouliquen assert img.get_machine_arch() in ["ARM"] 412e8ef5353SArnaud Pouliquen 413e8ef5353SArnaud Pouliquen # Need to reopen the file to get the raw data 414e8ef5353SArnaud Pouliquen with open(inputf, 'rb') as f: 415e8ef5353SArnaud Pouliquen bin_img = f.read() 416e8ef5353SArnaud Pouliquen size = len(bin_img) 417e8ef5353SArnaud Pouliquen align_64b = size % 8 418e8ef5353SArnaud Pouliquen if align_64b: 419e8ef5353SArnaud Pouliquen size += 8 - align_64b 420e8ef5353SArnaud Pouliquen 421e8ef5353SArnaud Pouliquen images_size.extend(size.to_bytes(4, 'little')) 422e8ef5353SArnaud Pouliquen s_header.img_length += size 423e8ef5353SArnaud Pouliquen f.close() 424e8ef5353SArnaud Pouliquen 425e8ef5353SArnaud Pouliquen # Store image type information 426e8ef5353SArnaud Pouliquen bin_type = ENUM_BINARY_TYPE['ELF'] 427e8ef5353SArnaud Pouliquen images_type += bin_type.to_bytes(1, 'little') 428e8ef5353SArnaud Pouliquen 429e8ef5353SArnaud Pouliquen # Compute the hash table and add it to TLV blob 430e8ef5353SArnaud Pouliquen hash_table = SegmentHash(img) 431e8ef5353SArnaud Pouliquen hash_tlv.extend(hash_table.get_table()) 432e8ef5353SArnaud Pouliquen 433e8ef5353SArnaud Pouliquen # Add image information 434e8ef5353SArnaud Pouliquen # The 'IMGTYPE' contains a byte array of the image type (ENUM_BINARY_TYPE). 435e8ef5353SArnaud Pouliquen # The 'IMGSIZE' contains a byte array of the size (32-bit) of each image. 436e8ef5353SArnaud Pouliquen tlv.add('NUM_IMG', len(args.in_file).to_bytes(1, 'little')) 437e8ef5353SArnaud Pouliquen tlv.add('IMGTYPE', bytearray(images_type)) 438e8ef5353SArnaud Pouliquen tlv.add('IMGSIZE', bytearray(images_size)) 439e8ef5353SArnaud Pouliquen 440e8ef5353SArnaud Pouliquen # Add hash type information in TLV blob 441e8ef5353SArnaud Pouliquen # The 'HASHTYPE' TLV contains a byte associated to ENUM_HASH_TYPE. 442e8ef5353SArnaud Pouliquen hash_type = ENUM_HASH_TYPE['SHA256'] 443e8ef5353SArnaud Pouliquen tlv.add('HASHTYPE', hash_type.to_bytes(1, 'little')) 444e8ef5353SArnaud Pouliquen 445e8ef5353SArnaud Pouliquen # Add hash table information in TLV blob 446e8ef5353SArnaud Pouliquen # The HASHTABLE TLV contains a byte array containing all the ELF segment 447e8ef5353SArnaud Pouliquen # with associated hash. 448e8ef5353SArnaud Pouliquen tlv.add('HASHTABLE', hash_tlv) 449e8ef5353SArnaud Pouliquen 450e8ef5353SArnaud Pouliquen # Add optional key information to TLV 451e8ef5353SArnaud Pouliquen if args.key_info: 452e8ef5353SArnaud Pouliquen with open(args.key_info, 'rb') as f: 453e8ef5353SArnaud Pouliquen key_info = f.read() 454e8ef5353SArnaud Pouliquen tlv.add('PKEYINFO', key_info) 455e8ef5353SArnaud Pouliquen 456e8ef5353SArnaud Pouliquen # Compute custom TLV that will be passed to the platform PTA 457e8ef5353SArnaud Pouliquen # Get list of custom protected TLVs from the command-line 458e8ef5353SArnaud Pouliquen if args.plat_tlv: 459e8ef5353SArnaud Pouliquen tlv.add_plat_tlv(args.plat_tlv) 460e8ef5353SArnaud Pouliquen 461e8ef5353SArnaud Pouliquen # Get the TLV area and compute its size (with 64 bit alignment) 462e8ef5353SArnaud Pouliquen tlvs_buff = tlv.get() 463e8ef5353SArnaud Pouliquen s_header.tlv_length = len(tlvs_buff) 464e8ef5353SArnaud Pouliquen 465e8ef5353SArnaud Pouliquen align_64b = 8 - (s_header.tlv_length % 8) 466e8ef5353SArnaud Pouliquen if align_64b: 467e8ef5353SArnaud Pouliquen s_header.tlv_length += 8 - align_64b 468e8ef5353SArnaud Pouliquen tlvs_buff += bytearray(8 - align_64b) 469e8ef5353SArnaud Pouliquen 470e8ef5353SArnaud Pouliquen dump_buffer(tlvs_buff, name='TLVS', indent="\t") 471e8ef5353SArnaud Pouliquen 472e8ef5353SArnaud Pouliquen # Signature chunk 473e8ef5353SArnaud Pouliquen sign_size = sig_size_type.get(ENUM_SIGNATURE_TYPE[args.key_type], 474e8ef5353SArnaud Pouliquen lambda: "Invalid sign type")(key) 475e8ef5353SArnaud Pouliquen s_header.sign_length = sign_size 476e8ef5353SArnaud Pouliquen 477e8ef5353SArnaud Pouliquen # Construct the Header 478e8ef5353SArnaud Pouliquen header = s_header.get_packed() 479e8ef5353SArnaud Pouliquen 480e8ef5353SArnaud Pouliquen # Generate signature 481e8ef5353SArnaud Pouliquen signer = Signature.get(ENUM_SIGNATURE_TYPE[args.key_type])(key) 482e8ef5353SArnaud Pouliquen 483e8ef5353SArnaud Pouliquen signer.hash_compute(header) 484e8ef5353SArnaud Pouliquen signer.hash_compute(tlvs_buff) 485e8ef5353SArnaud Pouliquen signature = signer.sign() 486e8ef5353SArnaud Pouliquen if len(signature) != sign_size: 487e8ef5353SArnaud Pouliquen raise Exception(("Actual signature length is not equal to ", 488e8ef5353SArnaud Pouliquen "the computed one: {} != {}". 489e8ef5353SArnaud Pouliquen format(len(signature), sign_size))) 490e8ef5353SArnaud Pouliquen 491e8ef5353SArnaud Pouliquen s_header.dump() 492e8ef5353SArnaud Pouliquen 493e8ef5353SArnaud Pouliquen with open(args.out_file, 'wb') as f: 494e8ef5353SArnaud Pouliquen f.write(header) 495e8ef5353SArnaud Pouliquen f.write(tlvs_buff) 496e8ef5353SArnaud Pouliquen f.write(signature) 497e8ef5353SArnaud Pouliquen align_64b = sign_size % 8 498e8ef5353SArnaud Pouliquen if align_64b: 499e8ef5353SArnaud Pouliquen f.write(bytearray(8 - align_64b)) 500e8ef5353SArnaud Pouliquen for inputf in args.in_file: 501e8ef5353SArnaud Pouliquen with open(inputf, 'rb') as fin: 502e8ef5353SArnaud Pouliquen bin_img = fin.read() 503e8ef5353SArnaud Pouliquen f.write(bin_img) 504e8ef5353SArnaud Pouliquen fin.close() 505e8ef5353SArnaud Pouliquen align_64b = len(bin_img) % 8 506e8ef5353SArnaud Pouliquen if align_64b: 507e8ef5353SArnaud Pouliquen f.write(bytearray(8 - align_64b)) 508e8ef5353SArnaud Pouliquen 509e8ef5353SArnaud Pouliquen 510e8ef5353SArnaud Pouliquenif __name__ == "__main__": 511e8ef5353SArnaud Pouliquen main() 512