1#! /usr/bin/env python3 2# 3# ----------------------------------------------------------------------------- 4# Copyright (c) 2020-2022, Arm Limited. All rights reserved. 5# 6# SPDX-License-Identifier: BSD-3-Clause 7# 8# ----------------------------------------------------------------------------- 9 10import re 11import os 12import sys 13import click 14 15# Add the cwd to the path so that if there is a version of imgtool in there then 16# it gets used over the system imgtool. Used so that imgtool from upstream 17# mcuboot is preferred over system imgtool 18cwd = os.getcwd() 19sys.path = [cwd] + sys.path 20import imgtool 21import imgtool.main 22 23parser_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../')) 24sys.path.append(parser_path) 25import macro_parser 26 27sign_bin_size_re = re.compile(r"^\s*RE_SIGN_BIN_SIZE\s*=\s*(.*)") 28load_addr_re = re.compile(r"^\s*RE_IMAGE_LOAD_ADDRESS\s*=\s*(.*)") 29rom_fixed_re = re.compile(r"^\s*RE_IMAGE_ROM_FIXED\s*=\s*(.*)") 30 31#This works around Python 2 and Python 3 handling character encodings 32#differently. More information about this issue at 33#https://click.palletsprojects.com/en/5.x/python3 34os.environ['LC_ALL'] = 'C.UTF-8' 35os.environ['LANG'] = 'C.UTF-8' 36 37@click.argument('outfile') 38@click.argument('infile') 39@click.option('-R', '--erased-val', type=click.Choice(['0', '0xff']), 40 required=False, help='The value that is read back from erased ' 41 'flash.') 42@click.option('-x', '--hex-addr', type=imgtool.main.BasedIntParamType(), 43 required=False, help='Adjust address in hex output file.') 44@click.option('--measured-boot-record', default=False, is_flag=True, help='Add ' 45 'CBOR encoded measured boot record to the image manifest.') 46@click.option('--save-enctlv', default=False, is_flag=True, 47 help='When upgrading, save encrypted key TLVs instead of plain ' 48 'keys. Enable when BOOT_SWAP_SAVE_ENCTLV config option ' 49 'was set.') 50@click.option('-E', '--encrypt', metavar='filename', 51 help='Encrypt image using the provided public key') 52@click.option('-e', '--endian', type=click.Choice(['little', 'big']), 53 default='little', help="Select little or big endian") 54@click.option('--overwrite-only', default=False, is_flag=True, 55 help='Use overwrite-only instead of swap upgrades') 56@click.option('-M', '--max-sectors', type=int, 57 help='When padding allow for this amount of sectors (defaults ' 58 'to 128)') 59@click.option('--confirm', default=False, is_flag=True, 60 help='When padding the image, mark it as confirmed') 61@click.option('--pad', default=False, is_flag=True, 62 help='Pad image to the size determined by --layout, adding ' 63 'trailer magic') 64@click.option('-l', '--layout', help='The file containing the macros of the ' 65 'slot sizes') 66@click.option('--pad-header', default=False, is_flag=True, 67 help='Adds --erased-val (defaults to 0xff) --header-size times ' 68 'at the beginning of the image') 69@click.option('-H', '--header-size', 70 callback=imgtool.main.validate_header_size, 71 type=imgtool.main.BasedIntParamType(), required=True) 72@click.option('-d', '--dependencies', callback=imgtool.main.get_dependencies, 73 required=False, help='''Add dependence on another image, format: 74 "(<image_ID>,<image_version>), ... "''') 75@click.option('-s', '--security-counter', 76 callback=imgtool.main.validate_security_counter, 77 help='Specify the value of security counter. Use the `auto` ' 78 'keyword to automatically generate it from the image version.') 79@click.option('-L', '--encrypt-keylen', type=click.Choice(['128', '256']), 80 default='128', 81 help='Specify the value of encrypt key length. Default 128.') 82@click.option('-v', '--version', callback=imgtool.main.validate_version, 83 required=True) 84@click.option('--align', type=click.Choice(['1', '2', '4', '8', '16', '32']), 85 required=True) 86@click.option('--public-key-format', type=click.Choice(['hash', 'full']), 87 default='hash', help='In what format to add the public key to ' 88 'the image manifest: full key or hash of the key.') 89@click.option('-k', '--key', metavar='filename') 90@click.command(help='''Create a signed or unsigned image\n 91 INFILE and OUTFILE are parsed as Intel HEX if the params have 92 .hex extension, otherwise binary format is used''') 93def wrap(key, align, version, header_size, pad_header, layout, pad, confirm, 94 max_sectors, overwrite_only, endian, encrypt, infile, outfile, 95 dependencies, hex_addr, erased_val, save_enctlv, public_key_format, 96 security_counter, encrypt_keylen, measured_boot_record): 97 98 slot_size = macro_parser.evaluate_macro(layout, sign_bin_size_re, 0, 1) 99 load_addr = macro_parser.evaluate_macro(layout, load_addr_re, 0, 1) 100 rom_fixed = macro_parser.evaluate_macro(layout, rom_fixed_re, 0, 1) 101 102 if measured_boot_record: 103 if "_s" in layout: 104 record_sw_type = "SPE" 105 elif "_ns" in layout: 106 record_sw_type = "NSPE" 107 else: 108 record_sw_type = "NSPE_SPE" 109 else: 110 record_sw_type = None 111 112 if int(align) <= 8 : 113 #default behaviour for max_align 114 max_align=8 115 else: 116 #max_align must be set to align 117 max_align=align 118 119 img = imgtool.image.Image(version=imgtool.version.decode_version(version), 120 header_size=header_size, pad_header=pad_header, 121 pad=pad, confirm=confirm, align=int(align), 122 slot_size=slot_size, max_sectors=max_sectors, 123 overwrite_only=overwrite_only, endian=endian, 124 load_addr=load_addr, rom_fixed=rom_fixed, 125 erased_val=erased_val, 126 save_enctlv=save_enctlv, 127 security_counter=security_counter, 128 max_align=max_align) 129 130 img.load(infile) 131 key = imgtool.main.load_key(key) if key else None 132 enckey = imgtool.main.load_key(encrypt) if encrypt else None 133 if enckey and key: 134 if (isinstance(key, imgtool.keys.RSA) and 135 not isinstance(enckey, imgtool.keys.RSAPublic)): 136 # FIXME 137 raise click.UsageError("Signing and encryption must use the same " 138 "type of key") 139 img.create(key, public_key_format, enckey, dependencies, record_sw_type, 140 None, encrypt_keylen=int(encrypt_keylen)) 141 img.save(outfile, hex_addr) 142 143 144if __name__ == '__main__': 145 wrap() 146