def handle_qspi_config(header_config_path, flash_config_path): qspi_config = ProgramQspiConfig(config_path=header_config_path) if qspi_config.is_valid(): if flash_config_path is not None: if not qspi_config.check_flash_config(flash_config_path): if ui.ask(text="Current flash config isn't listed on supported flash config list " "({})\n Do you want to run configurator?\n" .format(flash_config_path), confirmation='Run', denial='Ignore'): program_qspi_config(header_config_path=header_config_path, flash_config_path=flash_config_path) else: # invalid qspi config if header_config_path is None: if ui.ask(text='Invalid configuration file: {}\n Do you want to run configurator?\n' .format(header_config_path), confirmation='Run', denial='Abort'): program_qspi_config(header_config_path=header_config_path, flash_config_path=flash_config_path) qspi_config.load() else: ui.print_message("Aborted.\n") raise ExecutionCanceled() if not qspi_config.is_valid(): raise RuntimeError("QSPI config is invalid.\nExecution aborted.\n") return qspi_config
def generate_keys(output_file=None, elliptic_curve=None, prod_id=None): if not output_file: output_file = DEFAULT_PRODUCT_KEYS_FILE # Use Enum objects instead of string try: product_id = ProductId(prod_id) except ValueError: raise RuntimeError( 'Invalid or no Product ID passed. Execution aborted.') if product_id == ProductId.DA14681_01: raise RuntimeError('Secure boot feature is not supported by ' + str(product_id.value)) if not os.path.exists(MKIMAGE_BIN): raise RuntimeError( 'Can not find mkimage. Please install it and run this script again.' ) if os.path.exists(output_file): if ui.ask(text='Product keys file already exists.\n' 'Would you like to move it to "' + output_file + '.old" and make new file?'): os.replace(output_file, output_file + '.old') else: ui.print_message('Aborting key generation') return product_keys = ProductKeys(output_file) if product_id == ProductId.DA1469x_00: # DA1469x devices support only one signature generation algorithm - Ed25519. if elliptic_curve and elliptic_curve != EllipticCurve.EDWARDS25519.value: raise RuntimeError( 'Only {} curve could be used for DA1469x ({} passed). Execution ' 'aborted.'.format(EllipticCurve.EDWARDS25519.value, elliptic_curve)) elliptic_curve = EllipticCurve.EDWARDS25519.value elif not elliptic_curve: elliptic_curve = ui.select_item( text='Select elliptic curve used for asymmetric keys', item_list=[c.value for c in ALLOWED_ELLIPTIC_CURVES]) # Use Enum objects instead of string try: elliptic_curve = EllipticCurve(elliptic_curve) except ValueError: raise RuntimeError('Invalid Elliptic Curve passed. Execution aborted.') ui.print_message('Writing keys to {}'.format(output_file)) if SYMMETRIC_KEYS_NUM[product_id] and SYMMETRIC_KEYS_LEN[product_id]: for key in generate_symmetric_keys(SYMMETRIC_KEYS_NUM[product_id], SYMMETRIC_KEYS_LEN[product_id]): product_keys.add_symmetric_key(key=key) if ASYMMETRIC_KEYS_NUM[product_id] and elliptic_curve: for private, public in generate_asymmetric_keys( ASYMMETRIC_KEYS_NUM[product_id], elliptic_curve): product_keys.add_asymmetric_key(private=private, public=public, elliptic_curve=elliptic_curve) if SYMMETRIC_FW_DEC_KEYS_NUM[product_id] and SYMMETRIC_FW_DEC_KEYS_LEN[ product_id]: for key in generate_symmetric_keys( SYMMETRIC_FW_DEC_KEYS_NUM[product_id], SYMMETRIC_FW_DEC_KEYS_LEN[product_id]): product_keys.add_symmetric_fw_dec_key(key=key) if not product_keys.is_valid(product_id): raise RuntimeError('Generated keys are invalid - cannot save file.') product_keys.save()
def secure_keys_cfg(configuration_file=None, keys_file=None, prod_id=None, pub_key_idx=None, elliptic_curve=None, hash_method=None, key_revocations=None, min_version=None, sym_key_idx=None, nonce=None, enable_secure_boot=None): supported_prod_id = [ProductId.DA14683_00.value, ProductId.DA1469x_00.value] if configuration_file is None: configuration_file = DEFAULT_CONFIGURATION_FILE if keys_file is None: keys_file = DEFAULT_PRODUCT_KEYS_FILE if not os.path.exists(keys_file): if ui.ask(text='Would you like to create product keys file?'): if not prod_id: prod_id = ui.select_item(text='Select Product ID', item_list=supported_prod_id) if not prod_id: raise ExecutionCanceled() generate_keys(keys_file, elliptic_curve=elliptic_curve, prod_id=prod_id) else: return ui.print_message('Using product keys file: ' + os.path.normpath(keys_file)) security_config = SecurityConfig(configuration_file) product_keys = ProductKeys(keys_file) if os.path.exists(configuration_file) and security_config.is_valid(): configuration_str = prepare_configuration_str(security_config, product_keys) if not ui.ask(text='Would you like to change existing configuration?\n' + configuration_str, confirmation='Change', denial='Keep'): return # Could be passed or already selected if not prod_id: prod_id = ui.select_item(text='Select Product ID', item_list=supported_prod_id) if not prod_id: raise ExecutionCanceled() # Use Enum object instead of string try: product_id = ProductId(prod_id) except ValueError: raise RuntimeError('Invalid Product ID passed. Execution aborted.') if not product_keys.is_valid(product_id): raise RuntimeError('Invalid product keys file. Execution aborted.') if product_id == ProductId.DA1469x_00: if enable_secure_boot is None: enable_secure_boot = ui.ask(text='Would you like to enable secure boot in CS?') elif enable_secure_boot == 'enable': enable_secure_boot = True elif enable_secure_boot == 'disable': enable_secure_boot = False else: raise RuntimeError('No valid option for secure boot enabling in CS. Execution aborted.') # Set public key index if not passed if pub_key_idx is None: items = ['{0: <3} | {1: <15} | {2}'.format(str(index), key.elliptic_curve.value, key.private) for index, key in enumerate(product_keys.asymmetric_keys)] selected = ui.select_item(item_list=items, text='Select public key index') if not selected: raise ExecutionCanceled() pub_key_idx = next((e.strip() for e in selected.split('|'))) if product_id == ProductId.DA1469x_00: if not nonce and ui.ask(text='Would you like to add nonce?'): nonce = ui.ask_value(value_name='nonce', regex='[A-Fa-f0-9]{16}') if sym_key_idx is None: items = ['{0: <3} | {1}'.format(str(index), str(key)) for index, key in enumerate(product_keys.symmetric_fw_dec_keys)] selected = ui.select_item(item_list=items, text='Select index of the FW decryption symmetric key') if not selected: raise ExecutionCanceled() sym_key_idx = next((e.strip() for e in selected.split('|'))) if product_id == ProductId.DA14683_00: if not hash_method: hash_method = ui.select_item(item_list=[e.value for e in ALLOWED_HASH_METHODS], text='Select hash method', default=DEFAULT_HASH_METHOD_IDX) if not hash_method: raise ExecutionCanceled() hash_method = HashMethod(hash_method) if key_revocations is None and ui.ask(text='Would you like to add key revocations?'): asym_key_rev_list = list(range(4)) if product_id == ProductId.DA14683_00 else list(range(8)) sym_key_rev_list = list(range(8)) sym_fw_dec_rev_list = [] if product_id == ProductId.DA14683_00 else list(range(8)) # Remove indexes of keys which will be used in image's signature verification/decryption asym_key_rev_list = list(filter(lambda x: x != int(str(pub_key_idx), 0), asym_key_rev_list)) sym_fw_dec_rev_list = list(filter(lambda x: x != int(sym_key_idx), sym_fw_dec_rev_list)) # Ask for key revocation in each group key_revocations = dict() key_revocations[SecurityConfig.KEY_REV_PUB_TAG] = \ ask_key_rev(asym_key_rev_list, 'Select public key indexes which should be revoked.', product_keys.asymmetric_keys) if sym_fw_dec_rev_list: key_revocations[SecurityConfig.KEY_REV_SYM_FW_DEC_TAG] = \ ask_key_rev(sym_fw_dec_rev_list, 'Select FW decryption key indexes which should be ' 'revoked.', product_keys.symmetric_fw_dec_keys) key_revocations[SecurityConfig.KEY_REV_SYM_USER_DATA_TAG] = \ ask_key_rev(sym_key_rev_list, 'Select user data decryption key indexes which should be ' 'revoked.', product_keys.symmetric_keys) elif key_revocations is not None: # Don't remove public key and FW decryption key indexes which will be used for creating # image - leave all values which were given in command line call key_revocations = SecurityConfig.parse_revocation_list(key_revocations) security_config.product_id = product_id if product_id == ProductId.DA14683_00: if not min_version and ui.ask(text='Would you like to add minimal version?'): min_version = ui.ask_value(value_name='minimal version') if not min_version: raise ExecutionCanceled() security_config.security_pub_key_idx = pub_key_idx if key_revocations: security_config.adm_key_revocations = key_revocations else: # Keep empty dictionary of lists. This one from constructor could have been altered. security_config.adm_key_revocations = { SecurityConfig.KEY_REV_PUB_TAG : [], SecurityConfig.KEY_REV_SYM_USER_DATA_TAG : [], SecurityConfig.KEY_REV_SYM_FW_DEC_TAG : [] } # Set only required field for specified product - rest will stay as None if product_id == ProductId.DA14683_00: security_config.security_hash_method = hash_method security_config.adm_minimal_version = min_version elif product_id == ProductId.DA1469x_00: security_config.cs_enable_secure_boot = enable_secure_boot security_config.security_sym_key_idx = sym_key_idx security_config.security_nonce = nonce security_config.save() ui.print_message('Configuration saved to ' + configuration_file)
def confirm_configuration_change(configuration): return ui.ask(text="Existing Configuration:\n\n" + configuration.get_config_info() + "\nDo you want to change this configuration?", confirmation='Change', denial='Keep')
def erase_qspi_jtag(cli_programmer=None, serial=None): if ui.ask(text='Are you sure you want to completely erase QSPI?') is False: raise ExecutionCanceled() cli_programmer.chip_erase_qspi(serial_port=serial, silent=False)