Beispiel #1
0
def open_mboot() -> McuBoot:
    """Open USB communication with RT5xx boot-loader

    :return: McuBoot instance
    :raises ConnectionError: if device not connected
    """
    assert not TEST_IMG_CONTENT

    devs = []
    for _ in range(
            5
    ):  # try three times to find USB device (wait until shadows registers are ready)
        devs = scan_usb("RT5xx")
        if len(devs) == 1:
            break

        sleep(1)

    if len(devs) != 1:
        raise ConnectionError(
            "RT5xx not connected via USB, "
            "ensure BOOT CONFIG SW7 is ON,OFF,ON and connect USB cable via J38"
        )

    mboot = McuBoot(devs[0], True)
    mboot.open()
    assert mboot.is_opened

    # test connection
    # blhost -u 0x1FC9,0x20 get-property 1
    res = mboot.get_property(PropertyTag.CURRENT_VERSION)
    assert res is not None

    return mboot
Beispiel #2
0
def burn_srk_fuses(mboot: McuBoot, srk_table: SrkTable, enable_and_close_hab: bool) -> None:
    """Program SRK fuses into the processor; Not tested on hardware

    :param mboot: result of `init_flashloader()`
    :param srk_table: Table of SRK root keys used to provide fuses value
    :param enable_and_close_hab: optional parameter to enable and close HAB
    """
    assert mboot.get_property(PropertyTag.CURRENT_VERSION)
    for index, srk_index in enumerate(SRK_FUSES_INDEX):
        mboot.efuse_program_once(srk_index, srk_table.get_fuse(index))

    if enable_and_close_hab:
        # enable and close HAB
        mboot.efuse_program_once(ENABLE_HAB_FUSE_INDEX, ENABLE_HAB_FUSE_MASK)
Beispiel #3
0
def verify_srk_fuses(mboot: McuBoot, srk_table: SrkTable) -> bool:
    """Verify fuses in the processor

    :param mboot: result of `init_flashloader()`
    :param srk_table: Table of SRK root keys used to provide fuses value
    :return: True if matches, False if does not match
    """
    assert mboot.get_property(PropertyTag.CURRENT_VERSION)
    for index, srk_index in enumerate(SRK_FUSES_INDEX):
        val = mboot.efuse_read_once(srk_index)
        exp_val = srk_table.get_fuse(index)
        if val != exp_val:
            return False
    return True
Beispiel #4
0
def hab_audit_xip_app(cpu_data: CpuData, mboot: McuBoot,
                      read_log_only: bool) -> Optional[bytes]:
    """Authenticate the application in external FLASH.

    The function loads application into RAM and invokes its function, that authenticates the application and read the
    HAB log. Then the HAB log is downloaded and parsed and printed to stdout.
    :param cpu_data: target cpu data
    :param mboot: running flashloader
    :param read_log_only: true to read HAB log without invoking authentication; False to authenticate and read-log
        It is recommended to call the function firstly with parameter `True` and second time with parameter False to
        see the difference.
    :return: bytes contains result of the hab log, otherwise returns None when an error occurred
    """
    # check if the flashloader is running (not None)
    assert mboot, "Flashloader is not running"

    # get CPU data dir, hab_audit_base and hab_audit_start
    assert cpu_data, "Can not read the log, because given cpu data were not provided."
    cpu_data_bin_dir = cpu_data.bin
    evk_exec_hab_audit_base = cpu_data.base_address
    evk_exec_hab_audit_start = cpu_data.start_address

    # get main directory in absolute format
    main_dir_absolute = os.path.dirname(__file__)
    # get hab_audit_executable bin file directory
    exec_hab_audit_path = os.path.join(os.path.dirname(main_dir_absolute),
                                       "data", "cpu_data", cpu_data_bin_dir)
    if not os.path.isfile(exec_hab_audit_path):
        print('\nHAB logger not supported for the processor')
        return None

    # get executable file, that will be loaded into RAM
    exec_hab_audit_code = load_binary(exec_hab_audit_path)
    # find address of the buffer in RAM, where the HAB LOG will be stored
    log_addr = evk_exec_hab_audit_base + exec_hab_audit_code.find(
        b'\xA5\x5A\x11\x22\x33\x44\x55\x66')
    assert log_addr > evk_exec_hab_audit_base
    # check if the executable binary is in collision with reserved region
    reserved_regions = mboot.get_property(PropertyTag.RESERVED_REGIONS)

    # check conflict between hab log address and any of reserved regions
    # we need 2 values (min and max) - that is why %2 is used
    assert check_reserved_regions(log_addr, reserved_regions), \
        f"Log address is in conflict with reserved regions"
    assert mboot.write_memory(evk_exec_hab_audit_base, exec_hab_audit_code, 0)
    assert mboot.call(evk_exec_hab_audit_start | 1, 0 if read_log_only else 1)

    log = mboot.read_memory(log_addr, 100, 0)
    return log
Beispiel #5
0
class Nitrokey3Bootloader(Nitrokey3Base):
    """A Nitrokey 3 device running the bootloader."""
    def __init__(self, device: RawHid):
        from . import PID_NITROKEY3_BOOTLOADER, VID_NITROKEY

        if (device.vid, device.pid) != (VID_NITROKEY,
                                        PID_NITROKEY3_BOOTLOADER):
            raise ValueError("Not a Nitrokey 3 device: expected VID:PID "
                             f"{VID_NITROKEY:x}:{PID_NITROKEY3_BOOTLOADER:x}, "
                             f"got {device.vid:x}:{device.pid:x}")
        self._path = device.path
        self.device = McuBoot(device)

    def __enter__(self) -> "Nitrokey3Bootloader":
        self.device.open()
        return self

    @property
    def path(self) -> str:
        if isinstance(self._path, bytes):
            return self._path.decode("UTF-8")
        return self._path

    @property
    def name(self) -> str:
        return "Nitrokey 3 Bootloader"

    @property
    def status(self) -> Tuple[int, str]:
        code = self.device.status_code
        message = StatusCode.desc(code)
        return (code, message)

    def close(self) -> None:
        self.device.close()

    def reboot(self) -> None:
        if not self.device.reset(reopen=False):
            # On Windows, this function returns false even if the reset was successful
            if platform.system() == "Windows":
                logger.warning("Failed to reboot Nitrokey 3 bootloader")
            else:
                raise Exception("Failed to reboot Nitrokey 3 bootloader")

    def uuid(self) -> Optional[int]:
        uuid = self.device.get_property(
            PropertyTag.UNIQUE_DEVICE_IDENT)  # type: ignore[arg-type]
        if not uuid:
            raise ValueError("Missing response for UUID property query")
        if len(uuid) != UUID_LEN:
            raise ValueError(f"UUID response has invalid length {len(uuid)}")

        # See GetProperties::device_uuid in the lpc55 crate:
        # https://github.com/lpc55/lpc55-host/blob/main/src/bootloader/property.rs#L222
        wrong_endian = (uuid[3] << 96) + (uuid[2] << 64) + (
            uuid[1] << 32) + uuid[0]
        right_endian = wrong_endian.to_bytes(16, byteorder="little")
        return int.from_bytes(right_endian, byteorder="big")

    def update(
        self,
        image: bytes,
        callback: Optional[Callable[[int, int], None]] = None,
        check_errors: bool = False,
    ) -> bool:
        return self.device.receive_sb_file(
            image,
            progress_callback=callback,
            check_errors=check_errors,
        )

    @staticmethod
    def list() -> List["Nitrokey3Bootloader"]:
        from . import PID_NITROKEY3_BOOTLOADER, VID_NITROKEY

        device_filter = USBDeviceFilter(
            f"0x{VID_NITROKEY:x}:0x{PID_NITROKEY3_BOOTLOADER:x}")
        devices = []
        for device in RawHid.enumerate(device_filter):
            # TODO: remove assert if https://github.com/NXPmicro/spsdk/issues/32 is fixed
            assert isinstance(device, RawHid)
            try:
                devices.append(Nitrokey3Bootloader(device))
            except ValueError:
                logger.warn(
                    f"Invalid Nitrokey 3 bootloader returned by enumeration: {device}"
                )
        return devices

    @staticmethod
    def open(path: str) -> Optional["Nitrokey3Bootloader"]:
        device_filter = USBDeviceFilter(path)
        devices = RawHid.enumerate(device_filter)
        if len(devices) == 0:
            logger.warn(f"No HID device at {path}")
            return None
        if len(devices) > 1:
            logger.warn(f"Multiple HID devices at {path}: {devices}")
            return None

        try:
            # TODO: remove assert if https://github.com/NXPmicro/spsdk/issues/32 is fixed
            assert isinstance(devices[0], RawHid)
            return Nitrokey3Bootloader(devices[0])
        except ValueError:
            logger.warn(f"No Nitrokey 3 bootloader at path {path}",
                        exc_info=sys.exc_info())
            return None