def _find_and_open_usb_bitbox02(
        use_cache: bool) -> Tuple[devices.DeviceInfo, TransportLayer]:
    """
    Connects to a BitBox02 bootloader over USB.
    If the BitBox02 is currently running a firmware, it will
    be rebooted and this function will connect to the bootloader
    when it shows up.
    """
    bootloader_device = None
    try:
        bootloader_device = devices.get_any_bitbox02_bootloader()
    except TooManyFoundException:
        eprint(
            "Found multiple bb02 bootloader standard editions. Only one supported."
        )
        sys.exit(1)
    except NoneFoundException:
        pass

    if bootloader_device is None:
        try:
            bootloader_device = _get_bitbox_and_reboot(use_cache)
        except TooManyFoundException:
            eprint("Found multiple bitboxes. Only one supported.")
            sys.exit(1)
        except NoneFoundException:
            eprint("Neither bootloader nor bitbox found.")
            sys.exit(1)

    pprint.pprint(bootloader_device)

    hid_device = hid.device()
    hid_device.open_path(bootloader_device["path"])
    return bootloader_device, u2fhid.U2FHid(hid_device)
def _get_bitbox_and_reboot(use_cache: bool) -> devices.DeviceInfo:
    """Search for a bitbox and then reboot it into bootloader"""
    device = devices.get_any_bitbox02()

    class NoiseConfig(util.NoiseConfigUserCache):
        """NoiseConfig extends NoiseConfigUserCache"""
        def __init__(self) -> None:
            super().__init__("shift/load_firmware")

        def show_pairing(self, code: str,
                         device_response: Callable[[], bool]) -> bool:
            print(
                "Please compare and confirm the pairing code on your BitBox02:"
            )
            print(code)
            return device_response()

    class NoiseConfigNoCache(bitbox_api_protocol.BitBoxNoiseConfig):
        """NoiseConfig extends BitBoxNoiseConfig"""
        def show_pairing(self, code: str,
                         device_response: Callable[[], bool]) -> bool:
            print(
                "Please compare and confirm the pairing code on your BitBox02:"
            )
            print(code)
            return device_response()

    if use_cache:
        config: bitbox_api_protocol.BitBoxNoiseConfig = NoiseConfig()
    else:
        config = NoiseConfigNoCache()

    hid_device = hid.device()
    hid_device.open_path(device["path"])
    bitbox = BitBox02(transport=u2fhid.U2FHid(hid_device),
                      device_info=device,
                      noise_config=config)
    if not bitbox.reboot():
        raise RuntimeError("User aborted")

    # wait for it to reboot
    while True:
        try:
            bootloader_device = devices.get_any_bitbox02_bootloader()
        except NoneFoundException:
            sys.stdout.write(".")
            sys.stdout.flush()
            sleep(1)
            continue
        return bootloader_device
Example #3
0
def connect_to_usb_bitbox(debug: bool, use_cache: bool) -> int:
    """
    Connects and runs the main menu on a BitBox02 connected
    over USB.
    """
    try:
        bitbox = devices.get_any_bitbox02()
    except devices.TooManyFoundException:
        print("Multiple bitboxes detected. Only one supported")
        return 1
    except devices.NoneFoundException:
        try:
            bootloader = devices.get_any_bitbox02_bootloader()
        except devices.TooManyFoundException:
            print("Multiple bitbox bootloaders detected. Only one supported")
            return 1
        except devices.NoneFoundException:
            print("Neither bitbox nor bootloader found.")
            return 1
        else:
            hid_device = hid.device()
            hid_device.open_path(bootloader["path"])
            bootloader_connection = bitbox02.Bootloader(
                u2fhid.U2FHid(hid_device), bootloader)
            boot_app = SendMessageBootloader(bootloader_connection)
            return boot_app.run()
    else:

        def show_pairing(code: str, device_response: Callable[[],
                                                              bool]) -> bool:
            print(
                "Please compare and confirm the pairing code on your BitBox02:"
            )
            print(code)
            if not device_response():
                return False
            return input("Accept pairing? [y]/n: ").strip() != "n"

        class NoiseConfig(util.NoiseConfigUserCache):
            """NoiseConfig extends NoiseConfigUserCache"""
            def __init__(self) -> None:
                super().__init__("shift/send_message")

            def show_pairing(self, code: str,
                             device_response: Callable[[], bool]) -> bool:
                return show_pairing(code, device_response)

            def attestation_check(self, result: bool) -> None:
                if result:
                    print("Device attestation PASSED")
                else:
                    print("Device attestation FAILED")

        class NoiseConfigNoCache(bitbox_api_protocol.BitBoxNoiseConfig):
            """NoiseConfig extends BitBoxNoiseConfig"""
            def show_pairing(self, code: str,
                             device_response: Callable[[], bool]) -> bool:
                return show_pairing(code, device_response)

            def attestation_check(self, result: bool) -> None:
                if result:
                    print("Device attestation PASSED")
                else:
                    print("Device attestation FAILED")

        if use_cache:
            config: bitbox_api_protocol.BitBoxNoiseConfig = NoiseConfig()
        else:
            config = NoiseConfigNoCache()

        hid_device = hid.device()
        hid_device.open_path(bitbox["path"])
        bitbox_connection = bitbox02.BitBox02(
            transport=u2fhid.U2FHid(hid_device),
            device_info=bitbox,
            noise_config=config)
        try:
            bitbox_connection.check_min_version()
        except FirmwareVersionOutdatedException as exc:
            print("WARNING: ", exc)

        if debug:
            print("Device Info:")
            pprint.pprint(bitbox)
        return SendMessage(bitbox_connection, debug).run()