#!/usr/bin/env python3 import logging import sys import shutil from argparse import _MutuallyExclusiveGroup from genericpath import exists import click from click_option_group import optgroup,RequiredMutuallyExclusiveOptionGroup import json import struct from scripts import partition from scripts.partition import * from scripts.gen_partition import * from scripts.gen_ppc import * from scripts.gen_mpc import * from scripts.gen_security import * from scripts.gen_ota import * from scripts.gen_code import gen_code from scripts.bl1_sign import * from scripts.bl2_sign import * from scripts.pk_hash import * from scripts.pack import * from scripts.compress import * from scripts import crc from scripts import encrypt from scripts import xts_aes from scripts import generator from scripts.sign import * from scripts.steps import * from scripts.solution_generator import * from scripts.copy_json_data_csv import * def set_debug(debug): if debug: logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) stream_handler = logging.StreamHandler(sys.stdout) stream_handler.setLevel(logging.DEBUG) @click.group() @click.version_option(version='1.0.0.0') def cli(): """Beken security tools for generating code, signing, encrypting and packing""" pass @cli.group("gen") def gen(): """Generate code from security config files""" @cli.group("sign") def sign(): """BL1/BL2 signing commands""" @cli.group("pack") def pack(): """Merge partitions, CRC/AES and packing""" @cli.group("steps") def steps(): """Create downloadable bin step by step""" @cli.group("pipeline") def pipeline(): """security solutions pipeline""" @gen.command("partition") @click.option("--partition_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='partitions.csv', help="partition CSV file.") @click.option("--ota_type", type=click.Choice(['OVERWRITE', 'XIP']), default='OVERWRITE', required=True, help="The OTA type.") @click.option("--out_hdr_file", type=str, required=False, default='partition_gen.h', help="Output file") @click.option("--out_layout_file", type=str, required=False, default='partition_layout.h', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_partition_command(partition_csv, ota_type, out_hdr_file, out_layout_file, debug): """gen partition header and layout file.""" set_debug(debug) p = Partitions(partition_csv, ota_type) gen_partitions_hdr_file(p, out_hdr_file) gen_partitions_layout_file(p, out_layout_file) @gen.command("ppc") @click.option("--ppc_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='ppc.csv', help="PPC CSV file.") @click.option("--gpio_dev_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='gpio_dev.csv', help="GPIO map control config csv file.") @click.option("--outfile", type=str, required=False, default='_ppc.h', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_ppc_command(ppc_csv, gpio_dev_csv, outfile, debug): """gen ppc.h from ppc.csv and gpio_dev.csv.""" set_debug(debug) gen_ppc_config_file(ppc_csv, gpio_dev_csv, outfile) @gen.command("mpc") @click.option("--mpc_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='mpc.csv', help="MPC CSV file.") @click.option("--outfile", type=str, required=False, default='_mpc.h', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_mpc_command(mpc_csv, outfile, debug): """gen mpc.h from mpc.csv.""" set_debug(debug) gen_mpc_config_file(mpc_csv, outfile) @gen.command("security") @click.option("--security_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='security.csv', help="Security CSV file.") @click.option("--outfile", type=str, required=False, default='security.h', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_security_command(security_csv, outfile, debug): """gen security.h from security.csv.""" set_debug(debug) gen_security_config_file(security_csv, outfile) @gen.command("ota") @click.option("--ota_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='ota.csv', help="OTA CSV file.") @click.option("--outfile", type=str, required=False, default='_ota.h', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_ota_command(ota_csv, outfile, debug): """gen ota.h from ota.csv.""" set_debug(debug) gen_ota_config_file(ota_csv, outfile) @gen.command("otp") @click.option("--otp_csv", type=click.Path(exists=True, dir_okay=False), required=False, default='otp2.csv', help="OTP CSV file.") @click.option("--outfile", type=str, required=False, default='_otp.h', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_ota_command(otp_csv, outfile, debug): """gen otp.h from otp.csv.""" set_debug(debug) gen_otp_map_file() @gen.command("otp_efuse") @click.option("--flash_aes_type", type=click.Choice(['FIXED', 'RANDOM', 'NONE']), default='FIXED', required=True, help="Flash AES type.") @click.option("--flash_aes_key", type=str, required=False, default=None, help="flash AES key.") @click.option("--pubkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_pubkey.pem', help="PEM secure boot public key file.") @click.option("--secure_boot", is_flag=True, help="Enable secure boot") @click.option("--outfile", type=str, required=False, default='otp_efuse_config.json', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def gen_otp_efuse_command(flash_aes_type, flash_aes_key, pubkey_pem_file, secure_boot, outfile, debug): """gen otp_efuse_config.json from security csv files.""" set_debug(debug) gen_otp_efuse_config_file(flash_aes_type, flash_aes_key, pubkey_pem_file, secure_boot, outfile) @gen.command("all") @click.option("--debug", is_flag=True, help="Enable debug") def pack_command(debug): """generate all code from security csv files""" set_debug(debug) gen_code() @pack.command("compress") @click.option("--infile", type=click.Path(exists=True, dir_okay=False), required=False, default='primary_all_code_signed.bin', help="Binary to be compressed.") @click.option("--outfile", type=str, required=False, default='otp_efuse_config.json', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def compress_command(infile, outfile, debug): """compress OTA binary (overwrite only)""" set_debug(debug) compress_bin(infile, outfile) @pack.command("extract_pk_hash") @click.option("--bin", type=click.Path(exists=True, dir_okay=False), required=True, default='bootloader.bin', help="Binaries that contains public key hash.") @click.option("--outfile", type=str, required=False, default='pk_hash.json', help="Output public key hash json") @click.option("--debug", is_flag=True, help="Enable debug") def pk_hash_command(bin, outfile, debug): """extract public key hash from binary""" set_debug(debug) extract_pk_hash(bin, outfile) @pack.command("insert_pk_hash") @click.option("--bin", type=click.Path(exists=True, dir_okay=False), required=True, default='bootloader.bin', help="Binaries that contains public key hash.") @click.option("--pubkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_pubkey.pem', help="PEM public key file.") @click.option("--debug", is_flag=True, help="Enable debug") def pk_hash_command(bin, pubkey_pem_file, debug): """insert public key hash from binary""" set_debug(debug) insert_pk_hash(bin, pubkey_pem_file) @pack.command("get_pk_hash") @click.option("--pubkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_pubkey.pem', help="PEM public key file.") @click.option("--debug", is_flag=True, help="Enable debug") def pk_hash_command(pubkey_pem_file, debug): """insert public key hash from binary""" set_debug(debug) get_pk_hash(pubkey_pem_file) @steps.command("get_app_bin_hash") @click.option("--debug", is_flag=True, help="Enable debug") def get_bin_hash_command(debug): """Get binaries hash for signing""" set_debug(debug) get_app_bin_hash() @steps.command("sign_app_bin_hash") @click.option("--debug", is_flag=True, help="Enable debug") def sign_hash_command(debug): """Signing app binaries hash""" set_debug(debug) sign_app_bin_hash() @steps.command("sign_from_app_sig") @click.option("--debug", is_flag=True, help="Enable debug") def sign_from_sig_command(debug): """Create signed app bin based on signature""" set_debug(debug) sign_from_app_sig() @steps.command("get_ota_bin_hash") @click.option("--debug", is_flag=True, help="Enable debug") def get_ota_bin_hash_command(debug): """Get OTA binary hash""" set_debug(debug) get_ota_bin_hash() @steps.command("sign_ota_bin_hash") @click.option("--debug", is_flag=True, help="Enable debug") def sign_ota_bin_hash_command(debug): """Create signature of OTA bin hash""" set_debug(debug) sign_ota_bin_hash() @steps.command("sign_from_ota_sig") @click.option("--debug", is_flag=True, help="Enable debug") def sign_from_ota_sig_command(debug): """Create signed OTA bin from signature""" set_debug(debug) sign_from_ota_sig() @steps.command("pack") @click.option("--debug", is_flag=True, help="Enable debug") def pack_command(debug): """Pack download bin""" set_debug(debug) steps_pack() @pack.command("all") @click.option("--debug", is_flag=True, help="Enable debug") @click.option("--config_dir", type=click.Path(exists=True, dir_okay=True), required=False, default=None, help="configuration files dir") def pack_command(debug, config_dir): """Pack downloadable bin in a single command""" set_debug(debug) pack_all(config_dir) @sign.command("bl1_sign_hash") @click.option("--privkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_privkey.pem', help="PEM private key file.") @click.option("--hash", type=str, default=None, required=False, help="HASH value.") @click.option("--outfile", type=str, required=False, default='manifest_signature.json', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def bl1_sign_hash_command(privkey_pem_file, hash, outfile, debug): """sign the hash via beken bootrom signing tool.""" set_debug(debug) bl1_sign_hash(privkey_pem_file, hash, outfile) @sign.command("bl1_sign") @click.option("--action_type", type=click.Choice(['hash', 'sign', 'sign_from_sig']), default='sign', required=True, help="Sign action type.") @click.option("--key_type", type=click.Choice(['ec256']), default='ec256', required=False, help="Sign algorithm, currently only support ec256.") @click.option("--privkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_privkey.pem', help="PEM private key file.") @click.option("--pubkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_pubkey.pem', help="PEM public key file.") @click.option("--signature", type=str, required=False, default=None, help="Signature of manifest hash.") @click.option("--bin_file", type=click.Path(exists=True, dir_okay=False), required=False, default='bl2.bin', help="Binary file to be signed.") @click.option("--static_addr", type=str, required=True, default='0x0', help="BL2 static address.") @click.option("--load_addr", type=str, required=True, default='0x28040000', help="BL2 load address.") @click.option("--outfile", type=str, required=False, default='primary_manifest.bin', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def bl1_sign_command(action_type, key_type, privkey_pem_file, pubkey_pem_file, signature, bin_file, static_addr, load_addr, outfile, debug): """sign or calculate binary hash for bl1.""" set_debug(debug) bl1_sign(action_type, key_type, privkey_pem_file, pubkey_pem_file, signature, bin_file, static_addr, load_addr, outfile) @sign.command("bl2_sign_hash") @click.option("-k", "--privkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_privkey.pem', help="PEM private key file.") @click.option("-d", "--hash", type=str, default=None, required=False, help="HASH value.") @click.option("-o", "--outfile", type=str, required=False, default='manifest_signature.json', help="Output file") @click.option("--debug", is_flag=True, help="Enable debug") def bl2_sign_hash_command(privkey_pem_file, hash, outfile, debug): """sign the hash via mcuboot imgtools.""" set_debug(debug) bl2_sign_hash(privkey_pem_file, hash, outfile) @sign.command("bl2_sign") @click.option("--action_type", type=click.Choice(['hash', 'sign', 'sign_from_sig']), default='sign', required=True, help="Sign action type.") @click.option("--key_type", type=click.Choice(['ec256']), default='ec256', required=False, help="Sign algorithm, currently only support ec256.") @click.option("--privkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_privkey.pem', help="PEM private key file.") @click.option("--pubkey_pem_file", type=click.Path(exists=True, dir_okay=False), required=False, default='root_ec256_pubkey.pem', help="PEM public key file.") @click.option("--signature", type=str, required=False, default=None, help="Signature of manifest hash.") @click.option("--bin_file", type=click.Path(exists=True, dir_okay=False), required=False, default='bl2.bin', help="Binary file to be signed.") @click.option("--partition_size", type=int, required=True, default=0, help="Partition size.") @click.option("--version", type=str, required=True, default='0.0.1', help="Version.") @click.option("--security_counter", type=int, required=True, default=0, help="Version.") @click.option("--sign_outfile", type=str, required=False, default='signed.bin', help="Output signed bin") @click.option("--hash_outfile", type=str, required=False, default='bl2_hash.json', help="Output bl2 hash json file") @click.option("--debug", is_flag=True, help="Enable debug") def bl2_sign_command(action_type, key_type, privkey_pem_file, pubkey_pem_file, signature, bin_file, partition_size, version, security_counter, sign_outfile, hash_outfile, debug): """sign or calculate binary hash for bl2.""" set_debug(debug) bl2_sign(action_type, key_type, privkey_pem_file, pubkey_pem_file, signature, bin_file, partition_size, version, security_counter, sign_outfile, hash_outfile) @pipeline.command("mock") @click.option("--debug", is_flag=True, help="Enable debug") @click.option("--outfolder", type=str, required=False, default='./key_output', help="Output folder path") def mock_command(outfolder, debug): """generator mock data""" set_debug(debug) Mock(outfolder).generate_mock_data() @pipeline.command("server_keys") @click.option("--outfolder", type=str, required=False, default='./key_output', help="Output folder path") @click.option("--debug", is_flag=True, help="Enable debug") def server_keys_command(outfolder, debug): """generator a series keys and bin file""" set_debug(debug) generate_solution_files(outfolder) @pipeline.command("process_keys_data") @click.option("--srcfolder", type=str, required=False, default='./key_output', help="Output folder path") @click.option("--dstfolder", type=str, required=False, default='./pack', help="Output folder path") @click.option("--debug", is_flag=True, help="Enable debug") def server_keys_command(srcfolder, dstfolder, debug): """generator a series keys and bin file""" set_debug(debug) keys_data_post_processing(srcfolder, dstfolder) if __name__ == '__main__': logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) stream_handler = logging.StreamHandler(sys.stdout) stream_handler.setLevel(logging.DEBUG) cli()