mirror of https://github.com/ARMmbed/mbed-os.git
241 lines
7.8 KiB
Python
241 lines
7.8 KiB
Python
#!/usr/bin/python
|
|
# Copyright (c) 2017-2021 Arm Limited
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import os
|
|
from os.path import abspath, basename, dirname, splitext, isdir
|
|
from os.path import join as path_join
|
|
import re
|
|
import subprocess
|
|
import shutil
|
|
import argparse
|
|
from intelhex import IntelHex
|
|
|
|
SCRIPT_DIR = dirname(abspath(__file__))
|
|
MBED_OS_ROOT = abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir, os.pardir))
|
|
|
|
def tfm_sign_image_tgt(tfm_import_path, signing_key, non_secure_bin):
|
|
|
|
SECURE_ROOT = abspath(tfm_import_path)
|
|
|
|
secure_bin = path_join(SECURE_ROOT, 'tfm_s.bin')
|
|
assert os.path.isfile(secure_bin)
|
|
|
|
non_secure_bin = abspath(non_secure_bin)
|
|
assert os.path.isfile(non_secure_bin)
|
|
|
|
build_dir = dirname(non_secure_bin)
|
|
tempdir = path_join(build_dir, 'temp')
|
|
if not isdir(tempdir):
|
|
os.makedirs(tempdir)
|
|
|
|
flash_layout = path_join(SECURE_ROOT, 'partition', 'flash_layout.h')
|
|
|
|
bl2_bin = path_join(SECURE_ROOT, 'bl2.bin')
|
|
image_macros_s_ns = path_join(SECURE_ROOT, 'partition', 'signing_layout_preprocessed.h')
|
|
ns_bin_basename = splitext(basename(non_secure_bin))[0]
|
|
concatenated_bin = abspath(path_join(tempdir, 'tfm_' + ns_bin_basename + ".bin"))
|
|
signed_bin = abspath(path_join(tempdir, 'tfm_' + ns_bin_basename + '_signed' + ".bin"))
|
|
signed_nopad_bin = abspath(path_join(tempdir, 'tfm_' + ns_bin_basename + '_signed_nopad' + ".bin"))
|
|
|
|
assert os.path.isfile(image_macros_s_ns)
|
|
|
|
signing_key = path_join(SECURE_ROOT, 'signing_key', signing_key)
|
|
assert os.path.isfile(signing_key)
|
|
|
|
# Find Python 3 command name across platforms
|
|
python3_cmd = "python3" if shutil.which("python3") is not None else "python"
|
|
|
|
#1. Concatenate secure TFM and non-secure mbed binaries
|
|
cmd = [
|
|
python3_cmd,
|
|
path_join(MBED_OS_ROOT, "tools", "psa", "tfm", "bin_utils", "assemble.py"),
|
|
"--layout",
|
|
image_macros_s_ns,
|
|
"-s",
|
|
secure_bin,
|
|
"-n",
|
|
non_secure_bin,
|
|
"-o",
|
|
concatenated_bin,
|
|
]
|
|
|
|
retcode = run_cmd(cmd, MBED_OS_ROOT)
|
|
if retcode:
|
|
raise Exception("Unable to concatenate " + "TF-M Secure/Mbed Non-secure" +
|
|
" binaries, Error code: " + str(retcode))
|
|
return
|
|
|
|
#2.1 Run wrapper to sign the concatenated binary with padding ("--pad"), so upgradeable by mcuboot
|
|
cmd = [
|
|
python3_cmd,
|
|
path_join(MBED_OS_ROOT, "tools", "psa","tfm", "bin_utils", "wrapper.py"),
|
|
"-v",
|
|
'1.2.0',
|
|
"-k",
|
|
signing_key,
|
|
"--layout",
|
|
image_macros_s_ns,
|
|
"--public-key-format",
|
|
'full',
|
|
"--align",
|
|
'1',
|
|
"--pad",
|
|
"--pad-header",
|
|
"-H",
|
|
'0x400',
|
|
"--overwrite-only",
|
|
"-s",
|
|
'auto',
|
|
"-d",
|
|
'(0,0.0.0+0)',
|
|
concatenated_bin,
|
|
signed_bin,
|
|
]
|
|
|
|
retcode = run_cmd(cmd, MBED_OS_ROOT)
|
|
if retcode:
|
|
raise Exception("Unable to sign " + "concatenated" +
|
|
" binary, Error code: " + str(retcode))
|
|
return
|
|
|
|
#2.2. Re-run above but without padding ("--pad"), so non-upgradeable by mcuboot
|
|
cmd.remove("--pad")
|
|
cmd.pop()
|
|
cmd.append(signed_nopad_bin)
|
|
|
|
retcode = run_cmd(cmd, MBED_OS_ROOT)
|
|
if retcode:
|
|
raise Exception("Unable to sign " + "concatenated" +
|
|
" binary, Error code: " + str(retcode))
|
|
return
|
|
|
|
#3. Concatenate mcuboot and signed binary and overwrite mbed built bin/hex file
|
|
flash_area_0_offset = find_flash_area_0_offset(flash_layout)
|
|
out_ih = IntelHex()
|
|
out_ih.loadbin(bl2_bin)
|
|
out_ih.loadbin(signed_nopad_bin, flash_area_0_offset)
|
|
out_ih.tofile(splitext(non_secure_bin)[0] + ".hex", 'hex')
|
|
out_ih.tobinfile(non_secure_bin)
|
|
|
|
def find_flash_area_0_offset(configFile):
|
|
# Compiled regular expressions
|
|
flash_area_bl2_offset_re = re.compile(r"^#define\s+FLASH_AREA_BL2_OFFSET\s+\({0,1}(0x[0-9a-fA-F]+)\){0,1}")
|
|
flash_area_bl2_size_re = re.compile(r"^#define\s+FLASH_AREA_BL2_SIZE\s+\({0,1}(0x[0-9a-fA-F]+)\){0,1}")
|
|
rsvd_stor_size_re = re.compile(r"^#define\s+FLASH_AREA_0_OFFSET\s+\(FLASH_AREA_BL2_OFFSET\s+\+\s+FLASH_AREA_BL2_SIZE\s+\+\s+\({0,1}(0x[0-9a-fA-F]+)\){0,1}\)")
|
|
|
|
# Match values
|
|
flash_area_bl2_offset = None
|
|
flash_area_bl2_size = None
|
|
rsvd_stor_size = None
|
|
flash_area_0_offset = None
|
|
|
|
with open(configFile, 'r') as configFile_:
|
|
for line in configFile_:
|
|
# Seek "#define FLASH_AREA_BL2_OFFSET..."
|
|
if flash_area_bl2_offset is None:
|
|
m = flash_area_bl2_offset_re.match(line)
|
|
if m is not None:
|
|
flash_area_bl2_offset = int(m.group(1), 0)
|
|
continue
|
|
|
|
# Seek "#define FLASH_AREA_BL2_SIZE..."
|
|
if flash_area_bl2_size is None:
|
|
m = flash_area_bl2_size_re.match(line)
|
|
if m is not None:
|
|
flash_area_bl2_size = int(m.group(1), 0)
|
|
continue
|
|
|
|
# Seek "#define FLASH_AREA_0_OFFSET..."
|
|
if rsvd_stor_size is None:
|
|
m = rsvd_stor_size_re.match(line)
|
|
if m is not None:
|
|
rsvd_stor_size = int(m.group(1), 0)
|
|
continue
|
|
|
|
# FLASH_AREA_0_OFFSET = FLASH_AREA_BL2_OFFSET + FLASH_AREA_BL2_SIZE + Reserved storage area size
|
|
if flash_area_bl2_offset is not None and \
|
|
flash_area_bl2_size is not None and \
|
|
rsvd_stor_size is not None:
|
|
flash_area_0_offset = flash_area_bl2_offset + flash_area_bl2_size + rsvd_stor_size
|
|
break
|
|
|
|
return flash_area_0_offset
|
|
|
|
def run_cmd(cmd, directory):
|
|
|
|
# Redirect stdout/stderr to pipe, text mode
|
|
POPEN_INSTANCE = subprocess.Popen(
|
|
cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
cwd=directory,
|
|
universal_newlines=True
|
|
)
|
|
|
|
# Command line
|
|
print("COMMAND: {}".format(POPEN_INSTANCE.args))
|
|
|
|
stdout_data, stderr_data = POPEN_INSTANCE.communicate()
|
|
|
|
# stdout/stderr messages
|
|
if (stdout_data):
|
|
print(stdout_data)
|
|
if (stderr_data):
|
|
print(stderr_data)
|
|
|
|
# Return code
|
|
return POPEN_INSTANCE.returncode
|
|
|
|
def parse_args():
|
|
"""Parse the command line arguments."""
|
|
parser = argparse.ArgumentParser(
|
|
description="Nuvoton post build command"
|
|
)
|
|
|
|
subparsers = parser.add_subparsers(description="The action to perform")
|
|
|
|
parser_tfm_sign_image_tgt = subparsers.add_parser(
|
|
"tfm_sign_image_tgt",
|
|
help="Sign secure and non-secure images together"
|
|
)
|
|
|
|
parser_tfm_sign_image_tgt.add_argument(
|
|
"--tfm-import-path",
|
|
help="Path containing the TF-M bootloader, layouts and signing keys",
|
|
required=True
|
|
)
|
|
|
|
parser_tfm_sign_image_tgt.add_argument(
|
|
"--signing_key",
|
|
help="File name of key for signing secure binary or secure/non-secure binaries together",
|
|
required=True
|
|
)
|
|
|
|
parser_tfm_sign_image_tgt.add_argument(
|
|
"--non-secure-bin",
|
|
help="Path to the non-secure binary",
|
|
required=True
|
|
)
|
|
|
|
parser_tfm_sign_image_tgt.set_defaults(func=tfm_sign_image_tgt)
|
|
|
|
return parser.parse_args()
|
|
|
|
if __name__ == "__main__":
|
|
args = parse_args()
|
|
args.func(args.tfm_import_path, args.signing_key, args.non_secure_bin)
|