예제 #1
0
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
예제 #2
0
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()
예제 #3
0
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)
예제 #4
0
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')
예제 #5
0
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)