Boot: Use the MCUBoot version of the imgtool.

Uses the MCUBoot version of the imgtool. Adds a Python wrapper script
to work around its altered interface.

Change-Id: I9dc98f254f26de8d379e544a2c59fa6f08d42341
Signed-off-by: Balint Matyi <Balint.Matyi@arm.com>
diff --git a/bl2/ext/mcuboot/MCUBoot.cmake b/bl2/ext/mcuboot/MCUBoot.cmake
index e344e3e..71ed6e9 100644
--- a/bl2/ext/mcuboot/MCUBoot.cmake
+++ b/bl2/ext/mcuboot/MCUBoot.cmake
@@ -92,12 +92,12 @@
 	if (SECURITY_COUNTER_S)
 		set(ADD_SECURITY_COUNTER_S "-s ${SECURITY_COUNTER_S}")
 	else()
-		set(ADD_SECURITY_COUNTER_S "")
+		set(ADD_SECURITY_COUNTER_S '-sauto')
 	endif()
 	if (SECURITY_COUNTER_NS)
 		set(ADD_SECURITY_COUNTER_NS "-s ${SECURITY_COUNTER_NS}")
 	else()
-		set(ADD_SECURITY_COUNTER_NS "")
+		set(ADD_SECURITY_COUNTER_NS '-sauto')
 	endif()
 	if (DEFINED SECURITY_COUNTER)
 		message(WARNING "In case of multiple updatable images the security counter value can be specified"
@@ -130,6 +130,12 @@
 		set(ADD_NS_IMAGE_MIN_VER "")
 	endif()
 
+	if (${MCUBOOT_UPGRADE_STRATEGY} STREQUAL "OVERWRITE_ONLY")
+		set(OVERWRITE "--overwrite-only")
+	else()
+		set(OVERWRITE "")
+	endif()
+
 	set(FILE_TO_PREPROCESS ${CMAKE_BINARY_DIR}/image_macros_to_preprocess)
 	set(PREPROCESSED_FILE ${CMAKE_BINARY_DIR}/image_macros_preprocessed)
 
@@ -160,29 +166,33 @@
 						POST_BUILD
 
 						#Sign secure binary image with default public key in mcuboot folder
-						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/imgtool.py
-						ARGS sign
-							 --layout ${PREPROCESSED_FILE}_s.c
-							 -k ${KEY_FILE_S}
+						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/wrapper.py
+						ARGS -k ${KEY_FILE_S}
 							 --public-key-format ${PUBLIC_KEY_FORMAT}
 							 --align 1
+							 ${OVERWRITE}
 							 -v ${IMAGE_VERSION_S}
 							 ${ADD_NS_IMAGE_MIN_VER}
 							 ${ADD_SECURITY_COUNTER_S}
+							 -l ${PREPROCESSED_FILE}_s.c
+							 --pad
+							 --pad-header
 							 -H 0x400
 							 $<TARGET_FILE_DIR:${_MY_PARAMS_S_BIN}>/${_MY_PARAMS_S_BIN}.bin
 							 ${CMAKE_BINARY_DIR}/${_MY_PARAMS_S_BIN}_signed.bin
 
 						#Sign non-secure binary image with default public key in mcuboot folder
-						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/imgtool.py
-						ARGS sign
-							 --layout ${PREPROCESSED_FILE}_ns.c
-							 -k ${KEY_FILE_NS}
+						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/wrapper.py
+						ARGS -k ${KEY_FILE_NS}
 							 --public-key-format ${PUBLIC_KEY_FORMAT}
 							 --align 1
+							 ${OVERWRITE}
 							 -v ${IMAGE_VERSION_NS}
 							 ${ADD_S_IMAGE_MIN_VER}
 							 ${ADD_SECURITY_COUNTER_NS}
+							 -l ${PREPROCESSED_FILE}_ns.c
+							 --pad
+							 --pad-header
 							 -H 0x400
 							 $<TARGET_FILE_DIR:${_MY_PARAMS_NS_BIN}>/${_MY_PARAMS_NS_BIN}.bin
 							 ${CMAKE_BINARY_DIR}/${_MY_PARAMS_NS_BIN}_signed.bin
@@ -198,7 +208,7 @@
 	if (SECURITY_COUNTER)
 		set(ADD_SECURITY_COUNTER "-s ${SECURITY_COUNTER}")
 	else()
-		set(ADD_SECURITY_COUNTER "")
+		set(ADD_SECURITY_COUNTER "-sauto")
 	endif()
 	if (DEFINED SECURITY_COUNTER_S OR
 		DEFINED SECURITY_COUNTER_NS)
@@ -253,17 +263,20 @@
 							 -o ${CMAKE_BINARY_DIR}/${_MY_PARAMS_FULL_BIN}.bin
 
 						#Sign concatenated binary image with default public key in mcuboot folder
-						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/imgtool.py
-						ARGS sign
-							 --layout ${PREPROCESSED_FILE}
-							 -k ${KEY_FILE}
+						COMMAND ${PYTHON_EXECUTABLE} ${MCUBOOT_DIR}/scripts/wrapper.py
+						ARGS -k ${KEY_FILE}
 							 --public-key-format ${PUBLIC_KEY_FORMAT}
 							 --align 1
+							 ${OVERWRITE}
 							 -v ${IMAGE_VERSION}
 							 ${ADD_SECURITY_COUNTER}
+							 -l ${PREPROCESSED_FILE}
+							 --pad
+							 --pad-header
 							 -H 0x400
 							 ${CMAKE_BINARY_DIR}/${_MY_PARAMS_FULL_BIN}.bin
 							 ${CMAKE_BINARY_DIR}/${_MY_PARAMS_SIGN_BIN}.bin)
+
 endif()
 
 	#Collect executables to common location: build/install/outputs/
diff --git a/bl2/ext/mcuboot/scripts/requirements.txt b/bl2/ext/mcuboot/scripts/requirements.txt
index 3cc2ef4..d3c54b4 100644
--- a/bl2/ext/mcuboot/scripts/requirements.txt
+++ b/bl2/ext/mcuboot/scripts/requirements.txt
@@ -2,3 +2,4 @@
 pyasn1
 pyyaml
 cbor>=1.0.0
+click
\ No newline at end of file
diff --git a/bl2/ext/mcuboot/scripts/wrapper.py b/bl2/ext/mcuboot/scripts/wrapper.py
new file mode 100644
index 0000000..14ad07a
--- /dev/null
+++ b/bl2/ext/mcuboot/scripts/wrapper.py
@@ -0,0 +1,121 @@
+#! /usr/bin/env python3
+#
+# -----------------------------------------------------------------------------
+# Copyright (c) 2020, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# -----------------------------------------------------------------------------
+
+import re
+import os
+import sys
+import click
+import macro_parser
+# Import the external MCUBoot repo's imgtool script
+scripts_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                            '../../../../../mcuboot/scripts'))
+sys.path.insert(0, scripts_path)
+import imgtool
+import imgtool.main
+
+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*(.*)")
+
+#This works around Python 2 and Python 3 handling character encodings
+#differently. More information about this issue at
+#https://click.palletsprojects.com/en/5.x/python3
+os.environ['LC_ALL'] = 'C.UTF-8'
+os.environ['LANG'] = 'C.UTF-8'
+
+@click.argument('outfile')
+@click.argument('infile')
+@click.option('-R', '--erased-val', type=click.Choice(['0', '0xff']),
+              required=False, help='The value that is read back from erased '
+                                   'flash.')
+@click.option('-x', '--hex-addr', type=imgtool.main.BasedIntParamType(),
+              required=False, help='Adjust address in hex output file.')
+@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 '
+                   'was set.')
+@click.option('-E', '--encrypt', metavar='filename',
+              help='Encrypt image using the provided public key')
+@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,
+              help='Use overwrite-only instead of swap upgrades')
+@click.option('-M', '--max-sectors', type=int,
+              help='When padding allow for this amount of sectors (defaults '
+                   'to 128)')
+@click.option('--confirm', default=False, is_flag=True,
+              help='When padding the image, mark it as confirmed')
+@click.option('--pad', default=False, is_flag=True,
+              help='Pad image to the size determined by --layout, adding '
+                   'trailer magic')
+@click.option('-l', '--layout', help='The file containing the macros of the '
+                                     'slot sizes')
+@click.option('--pad-header', default=False, is_flag=True,
+              help='Adds --erased-val (defaults to 0xff) --header-size times '
+                   'at the beginning of the image')
+@click.option('-H', '--header-size',
+              callback=imgtool.main.validate_header_size,
+              type=imgtool.main.BasedIntParamType(), required=True)
+@click.option('-d', '--dependencies', callback=imgtool.main.get_dependencies,
+              required=False, help='''Add dependence on another image, format:
+                                   "(<image_ID>,<image_version>), ... "''')
+@click.option('-s', '--security-counter',
+              callback=imgtool.main.validate_security_counter,
+              help='Specify the value of security counter. Use the `auto` '
+              'keyword to automatically generate it from the image version.')
+@click.option('-v', '--version', callback=imgtool.main.validate_version,
+              required=True)
+@click.option('--align', type=click.Choice(['1', '2', '4', '8']),
+              required=True)
+@click.option('--public-key-format', type=click.Choice(['hash', 'full']),
+              default='hash', help='In what format to add the public key to '
+              'the image manifest: full key or hash of the key.')
+@click.option('-k', '--key', metavar='filename')
+@click.command(help='''Create a signed or unsigned image\n
+               INFILE and OUTFILE are parsed as Intel HEX if the params have
+               .hex extension, otherwise binary format is used''')
+def wrap(key, align, version, header_size, pad_header, layout, pad, confirm,
+         max_sectors, overwrite_only, endian, encrypt, infile, outfile,
+         dependencies, hex_addr, erased_val, save_enctlv, public_key_format,
+         security_counter):
+
+    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)
+
+    if "_s.c" in layout:
+        boot_record = "SPE"
+    elif "_ns.c" in layout:
+        boot_record = "NSPE"
+    else:
+        boot_record = "NSPE_SPE"
+
+    img = imgtool.image.Image(version=imgtool.version.decode_version(version),
+                              header_size=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,
+                              security_counter=security_counter)
+
+    img.load(infile)
+    key = imgtool.main.load_key(key) if key else None
+    enckey = imgtool.main.load_key(encrypt) if encrypt else None
+    if enckey and key:
+        if (isinstance(key, imgtool.keys.RSA) and
+           not isinstance(enckey, imgtool.keys.RSAPublic)):
+            # FIXME
+            raise click.UsageError("Signing and encryption must use the same "
+                                   "type of key")
+
+    img.create(key, public_key_format, enckey, dependencies, boot_record)
+    img.save(outfile, hex_addr)
+
+
+if __name__ == '__main__':
+    wrap()
diff --git a/docs/getting_started/tfm_sw_requirement.rst b/docs/getting_started/tfm_sw_requirement.rst
index a2518d8..9b3e09b 100644
--- a/docs/getting_started/tfm_sw_requirement.rst
+++ b/docs/getting_started/tfm_sw_requirement.rst
@@ -170,11 +170,11 @@
 - CMake (see the "Supported CMake versions" chapter)
 - GNU Make (see the "Supported make versions" chapter)
 - Python3 and the pip package manager (from Python 3.4 it's included)
-- Python3 packages: *cryptography, pyasn1, yaml, jinja2 v2.10, cbor v1.0.0*
+- Python3 packages: *cryptography, pyasn1, yaml, jinja2 v2.10, cbor v1.0.0, click*
 
   .. code-block:: bash
 
-    pip3 install --user cryptography pyasn1 pyyaml jinja2 cbor
+    pip3 install --user cryptography pyasn1 pyyaml jinja2 cbor click
 
 - SRecord v1.58 (for Musca test chip boards)
 
@@ -230,11 +230,11 @@
   installation.
 - Python3 `(native Windows version) <https://www.python.org/downloads/>`__ and
   the pip package manager (from Python 3.4 it's included)
-- Python3 packages: *cryptography, pyasn1, yaml, jinja2 v2.10, cbor v1.0.0*
+- Python3 packages: *cryptography, pyasn1, yaml, jinja2 v2.10, cbor v1.0.0, click*
 
   .. code-block:: bash
 
-    pip3 install --user cryptography pyasn1 pyyaml jinja2 cbor
+    pip3 install --user cryptography pyasn1 pyyaml jinja2 cbor click
 
 - `SRecord v1.63 <https://sourceforge.net/projects/srecord/>`__ (for Musca test
   chip boards)
@@ -492,6 +492,7 @@
    "jinja2",,"Firmware"
    "cryptography",,"Firmware"
    "cbor",,"Firmware"
+   "click",,"Firmware"
    "Doxygen",">1.8","Reference manual"
    "Sphinx",">1.4","User Guide"
    "sphinxcontrib-plantuml",,"User Guide"
@@ -542,11 +543,13 @@
     fw --> yaml
     fw --> jinja2
     fw --> cbor
+    fw --> click
     cryptography --> Python3
     pyasn1 --> Python3
     yaml --> Python3
     jinja2 --> Python3
     cbor --> Python3
+    click --> Python3
 
     [*] --> u_guide
     u_guide --> Sphinx