def __init__(self, policy_file, memory_map): # Resolve paths self.policy_dir = os.path.dirname(Path(policy_file).absolute()) self.PKG_PATH = os.path.dirname(os.path.realpath(__file__)) self.IMG_TOOL_PATH = os.path.join(self.PKG_PATH, '../imgtool/imgtool.py') self.parser = PolicyParser(policy_file) self.policy = PolicyParser.get_json(policy_file) self.memory_map = memory_map
def read_cm0_permissions(tool, reg_map): logger.info('Checking cm0 AP permissions') passed, data = get_prov_details(tool, reg_map, FB_POLICY_JWT) if passed and len(data) > 0: policy = Crypto.readable_jwt(data) silicon_policy_parser = PolicyParser(policy['payload']) cm0_open = silicon_policy_parser.is_cmx_ap_enabled(True) logger.info(f'cm0 AP {"open" if cm0_open else "closed"}') else: logger.error('Failed to read policy from device while getting AP ' 'permission') logger.warning('Flash operations will be skipped') cm0_open = False return cm0_open
def get_policy_parser(self): from cysecuretools.targets.common.policy_parser import PolicyParser policy_parser = PolicyParser(self.__policy) self.__policy_parser = policy_parser return policy_parser
def get_policy_parser(self, policy): policy_parser = PolicyParser(policy) return policy_parser
class SignTool: def __init__(self, policy_file, memory_map): # Resolve paths self.policy_dir = os.path.dirname(Path(policy_file).absolute()) self.PKG_PATH = os.path.dirname(os.path.realpath(__file__)) self.IMG_TOOL_PATH = os.path.join(self.PKG_PATH, '../imgtool/imgtool.py') self.parser = PolicyParser(policy_file) self.policy = PolicyParser.get_json(policy_file) self.memory_map = memory_map def sign_image(self, hex_file, image_id): """ Signs hex file with the key specified in the policy file. Converts binary file of the signed image. Creates copy of unsigned hex file. Encrypts UPGRADE image if the policy file contains encryption key :param hex_file: The hex file to sign. :param image_id: The ID of the firmware in policy file. :return: Path to the signed files. One file per slot. """ result = [] slot = self.parser.get_slot(image_id) for image in slot['resources']: # Sign BOOT image and encrypt+sign UPGRADE image if 'encrypt' in slot and slot['encrypt'] and image[ 'type'] == ImageType.UPGRADE.name: hex_out = self.encrypt_image(slot, image['type'], unsigned_boot_hex) else: if image['type'] == ImageType.UPGRADE.name: if 'upgrade' not in slot or not slot['upgrade']: continue # skip generating hex file for UPGRADE slot if it is disabled # Preserve hex file for cm4 image if slot['id'] == self.memory_map.NSPE_IMAGE_ID: out_cm4_hex = '{0}_{2}{1}'.format( *os.path.splitext(hex_file) + ('cm4', )) copy2(hex_file, out_cm4_hex) # Sign image if image['type'] == ImageType.BOOT.name: unsigned_boot_hex = '{0}_{2}{1}'.format( *os.path.splitext(hex_file) + ('unsigned', )) copy2(hex_file, unsigned_boot_hex) hex_out = self.sign_single_hex(slot, image['type'], hex_file, hex_file) # Produce hex file for slot1 if image['type'] == ImageType.UPGRADE.name: output_name = '{0}_{2}{1}'.format( *os.path.splitext(hex_file) + ('upgrade', )) hex_out = self.sign_single_hex(slot, image['type'], unsigned_boot_hex, output_name) bin_out = '{0}.bin'.format(os.path.splitext(hex_out)[0]) hex2bin(hex_out, bin_out) bin2hex(bin_out, output_name, offset=int(image['address'])) os.remove(bin_out) logger.info(f'Image UPGRADE: {hex_out}\n') # Replace input hex file with the result.append(hex_out) os.remove(unsigned_boot_hex) result = tuple(result) if len(result) > 0 else None return result def sign_single_hex(self, slot, image_type, hex_in, hex_out=None): """ Signs single hex file with a single key using imgtool. :param slot: Slot data from policy file. :param image_type: The type of the image. :param hex_in: The hex file to sign. :param hex_out: The name of the output file. If not specified, the default name will be used. :return: The name of the signed hex file. """ # Find in policy data necessary for image signing address, size = self.parser.get_image_data(slot['id'], image_type) for key_pair in self.parser.get_keys(): if key_pair.image_type.name == image_type: key = key_pair break # Define signed hex file name if hex_out is None: hex_out = '{0}_{2}{1}'.format(*os.path.splitext(hex_in) + ('signed', )) args = [ sys.executable, self.IMG_TOOL_PATH, 'sign', '--key', key.pem_key_path, '--header-size', hex(self.memory_map.MCUBOOT_HEADER_SIZE), '--pad-header', '--align', '8', '--version', slot['version'], '--image-id', str(slot['id']), '--rollback_counter', str(slot['monotonic']), '--slot-size', hex(size), '--overwrite-only', hex_in, hex_out ] if image_type != ImageType.BOOT.name: args.append('--pad') logger.debug(f'Run imgtool with arguments: {args}') process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stderr = process.communicate()[1] # catch stderr outputs rc = process.wait() if rc != 0: logger.error('Signature is not added!') logger.error(f'Message from imgtool: {stderr.decode("utf-8")}') logger.error('imgtool finished execution with errors!') else: logger.info( f'SUCCESS: Image for slot {image_type} signed successfully!') return hex_out def encrypt_image(self, slot, image_type, hex_in): """ Signs image, encrypts image and signs it again. :param slot: Slot data from policy file. :param image_type: The type of the image. :param hex_in: The hex file to encrypt and sign. :return: Encrypted and signed file path. """ # Find in policy data necessary for image signing address, size = self.parser.get_image_data(slot['id'], image_type) for key_pair in self.parser.get_keys(): if key_pair.key_type == KeyType.signing and key_pair.image_type.name == image_type: sign_key = key_pair.pem_key_path elif key_pair.key_type == KeyType.encryption: encrypt_key = key_pair.json_key_path elif key_pair.key_type == KeyType.device_public: pub_key = key_pair.pem_key_path args = [ '--sdk-path', self.PKG_PATH, '--hex-file', hex_in, '--key-priv', sign_key, '--key-pub', pub_key, '--key-aes', encrypt_key, '--ver', slot['version'], '--img-id', str(slot['id']), '--rlb-count', str(slot['monotonic']), '--slot-size', hex(size), '--img-offset', address, '--pad', 1 ] logger.debug(f'Run encryption with arguments: {args}') try: encryptor.main(args) except SystemExit as e: if e.code != 0: logger.error('Image encryption failed.') else: hex_out = encryptor.get_final_hex_name(hex_in) return hex_out