mbed-os/targets/TARGET_Cypress/TARGET_PSOC6/sb-tools/encrypted_image_runner.py

216 lines
8.3 KiB
Python

# Copyright 2019 Cypress Semiconductor Corporation
# 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
import sys
import click
import subprocess
import binascii
from pathlib import Path, PurePath
from intelhex import IntelHex, hex2bin, bin2hex
from intelhex.compat import asbytes
HEADER_SIZE = 0x400
AES_HEADER="aes_header.txt" # near the script file
def check_file_exist(file):
if not Path(file).exists():
print("ERROR: File %s not found. Check script arguments."% file)
return False
else:
return True
def get_final_hex_name(file):
"""
Determine if script is called from mbed-os build system
for Secure Boot target processing or directly
"""
for part in PurePath(file).parts:
if "_unsigned.hex" in part:
# suppose file came from mbed-os build execution
return file[:-13] + "_enc_upgrade.hex"
# suppose stand alone script execution
return file[:-4] + "_enc_upgrade.hex"
def manage_output(process, input_f, output_f):
"""
Function takes care of subprocess
"""
stderr = process.communicate()[1]
rc = process.wait()
if rc != 0:
print("ERROR: Encryption script ended with error!")
print("ERROR: " + stderr.decode("utf-8"))
raise Exception("imgtool finished execution with errors!")
if check_file_exist(output_f):
os.remove(input_f)
@click.command()
@click.option('--sdk-path', 'sdk_path',
default=Path("."),
type=click.STRING,
help='Path to Secure Boot tools in case running script from outside')
@click.option('--hex-file', 'hex_file',
default=None,
type=click.STRING,
help='Hex file to process')
@click.option('--key-priv', 'key_priv',
default=None,
type=click.STRING,
help='Private key file to use for signing BOOT or UPGRADE image')
@click.option('--key-pub', 'key_pub',
default=None,
type=click.STRING,
help='Path to device public key - obtained from device on provisioning stage')
@click.option('--key-aes', 'key_aes',
default=None,
type=click.STRING,
help='Path to encryption key')
@click.option('--ver', 'version',
default=None,
type=click.STRING,
help='Version')
@click.option('--img-id', 'img_id',
default=None,
type=click.STRING,
help='Image ID - should correspond to values, used in policy file')
@click.option('--rlb-count', 'rlb_count',
default=None,
type=click.STRING,
help='Rollback counter value')
@click.option('--slot-size', 'slot_size',
default=None,
type=click.STRING,
help='Size of slot available for BOOT or UPGRADE image')
@click.option('--pad', 'pad',
default=False,
is_flag=True,
help='Add padding to image - required for UPGRADE image')
@click.option('--img-offset', 'img_offset',
default=None,
type=click.STRING,
help='Offset of hex file for UPGRADE image')
def main(sdk_path,
hex_file,
key_priv,
key_pub,
key_aes,
version,
img_id,
rlb_count,
slot_size,
pad,
img_offset):
"""
Function consequentially performs operations with provided hex file
and produces an encrypted and signed hex file for UPGRADE
"""
check_file_exist(key_priv)
check_file_exist(key_pub)
check_file_exist(key_aes)
check_file_exist(hex_file)
in_f = hex_file[:-4] + "_i.bin"
out_f = hex_file[:-4] + "_o.bin"
hex_file_final = get_final_hex_name(hex_file)
print("Image UPGRADE:" + hex_file_final)
# ih = IntelHex(hex_file)
# img_start_addr = ih.start_addr['EIP']
hex2bin(hex_file, in_f) #bin_file)
# $PYTHON $IMGTOOL sign --key $KEY --header-size $HEADER_SIZE --pad-header --align 8 --version $VERSION --image-id $ID --rollback_counter $ROLLBACK_COUNTER --slot-size $SLOT_SIZE --overwrite-only $binFileName $signedFileName is_file_created $signedFileName
# call imgtool for signature
process = subprocess.Popen([sys.executable, sdk_path + "/imgtool/imgtool.py", "sign",
"--key", key_priv,
"--header-size", str(hex(HEADER_SIZE)),
"--pad-header",
"--align", "8",
"--version", version,
"--image-id", img_id,
"--rollback_counter", rlb_count,
"--slot-size", slot_size,
"--overwrite-only",
in_f,
out_f],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
manage_output(process, in_f, out_f)
# AES
# $PYTHON $(dirname "${IMGTOOL}")"/create_aesHeader.py" -k $KEY -p $KEY_DEV --key_to_encrypt "$KEY_AES" $AES_HEADER
# call aesHeader for crypto header generation
process = subprocess.Popen([sys.executable, sdk_path + "/imgtool/create_aesHeader.py",
"-k", key_priv,
"-p", key_pub,
"--key_to_encrypt", key_aes,
AES_HEADER],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# catch stderr outputs
stderr = process.communicate()
rc = process.wait()
check_file_exist(AES_HEADER)
# aes_cipher.py script file should be in the same folder as imgtool.py
# $PYTHON $(dirname "${IMGTOOL}")"/aes_cipher.py" -k $KEY_AES $signedFileName $aes_encryptedFileName
# is_file_created $aes_encryptedFileName
# encrypt signed image
process = subprocess.Popen([sys.executable, sdk_path + "/imgtool/aes_cipher.py",
"-k", key_aes,
out_f,
in_f],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
manage_output(process, out_f, in_f)
# second part - obtain signed image from encrypted file - with padding - for staging area
# $PYTHON $IMGTOOL sign --key $KEY --header-size $HEADER_SIZE --pad-header --align 8 --version $VERSION --image-id $ID --rollback_counter $ROLLBACK_COUNTER --slot-size $SLOT_SIZE --overwrite-only $PAD -a $AES_HEADER $aes_encryptedFileName $signedEncFileName
# is_file_created $signedEncFileName
# call imgtool for signature
process = subprocess.Popen([sys.executable, sdk_path + "/imgtool/imgtool.py", "sign",
"--key", key_priv,
"--header-size", str(hex(HEADER_SIZE)),
"--pad-header",
"--align", "8",
"--version", version,
"--image-id", img_id,
"--rollback_counter", rlb_count,
"--slot-size", slot_size,
"--overwrite-only",
"--pad",
"-a", AES_HEADER,
in_f,
out_f],
#bin_sig_enc,
#bin_sig_enc_sig],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
manage_output(process, in_f, out_f)
bin2hex(out_f, hex_file_final, int(img_offset))
os.remove(out_f)
os.remove(AES_HEADER)
if __name__ == "__main__":
main()