예제 #1
0
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)
예제 #2
0
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
예제 #3
0
    def __init__(self, path: str, password: str = "", expert: bool = False) -> None:
        """
        Initializes a new BitBox02 client instance.
        """
        super().__init__(path, password=password, expert=expert)
        if password:
            raise BadArgumentError(
                "The BitBox02 does not accept a passphrase from the host. Please enable the passphrase option and enter the passphrase on the device during unlock."
            )

        hid_device = hid.device()
        hid_device.open_path(path.encode())
        self.transport = u2fhid.U2FHid(hid_device)
        self.device_path = path

        # use self.init() to access self.bb02.
        self.bb02: Optional[bitbox02.BitBox02] = None

        self.noise_config: BitBoxNoiseConfig = CLINoiseConfig()
예제 #4
0
파일: bitbox02.py 프로젝트: sysbot/electrum
    def pairing_dialog(self):
        def pairing_step(code: str, device_response: Callable[[], bool]) -> bool:
            msg = "Please compare and confirm the pairing code on your BitBox02:\n" + code
            self.handler.show_message(msg)
            try:
                res = device_response()
            except:
                # Close the hid device on exception
                with self.device_manager().hid_lock:
                    hid_device.close()
                raise
            finally:
                self.handler.finished()
            return res

        def exists_remote_static_pubkey(pubkey: bytes) -> bool:
            bitbox02_config = self.config.get("bitbox02")
            noise_keys = bitbox02_config.get("remote_static_noise_keys")
            if noise_keys is not None:
                if pubkey.hex() in [noise_key for noise_key in noise_keys]:
                    return True
            return False

        def set_remote_static_pubkey(pubkey: bytes) -> None:
            if not exists_remote_static_pubkey(pubkey):
                bitbox02_config = self.config.get("bitbox02")
                if bitbox02_config.get("remote_static_noise_keys") is not None:
                    bitbox02_config["remote_static_noise_keys"].append(pubkey.hex())
                else:
                    bitbox02_config["remote_static_noise_keys"] = [pubkey.hex()]
                self.config.set_key("bitbox02", bitbox02_config)

        def get_noise_privkey() -> Optional[bytes]:
            bitbox02_config = self.config.get("bitbox02")
            privkey = bitbox02_config.get("noise_privkey")
            if privkey is not None:
                return bytes.fromhex(privkey)
            return None

        def set_noise_privkey(privkey: bytes) -> None:
            bitbox02_config = self.config.get("bitbox02")
            bitbox02_config["noise_privkey"] = privkey.hex()
            self.config.set_key("bitbox02", bitbox02_config)

        def attestation_warning() -> None:
            self.handler.show_error(
                "The BitBox02 attestation failed.\nTry reconnecting the BitBox02.\nWarning: The device might not be genuine, if the\n problem persists please contact Shift support.",
                blocking=True
            )

        class NoiseConfig(bitbox_api_protocol.BitBoxNoiseConfig):
            """NoiseConfig extends BitBoxNoiseConfig"""

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

            def attestation_check(self, result: bool) -> None:
                if not result:
                    attestation_warning()

            def contains_device_static_pubkey(self, pubkey: bytes) -> bool:
                return exists_remote_static_pubkey(pubkey)

            def add_device_static_pubkey(self, pubkey: bytes) -> None:
                return set_remote_static_pubkey(pubkey)

            def get_app_static_privkey(self) -> Optional[bytes]:
                return get_noise_privkey()

            def set_app_static_privkey(self, privkey: bytes) -> None:
                return set_noise_privkey(privkey)

        if self.bitbox02_device is None:
            with self.device_manager().hid_lock:
                hid_device = hid.device()
                hid_device.open_path(self.bitbox_hid_info["path"])


            bitbox02_device = bitbox02.BitBox02(
                transport=u2fhid.U2FHid(hid_device),
                device_info=self.bitbox_hid_info,
                noise_config=NoiseConfig(),
            )
            try:
                bitbox02_device.check_min_version()
            except FirmwareVersionOutdatedException:
                raise
            self.bitbox02_device = bitbox02_device

        self.fail_if_not_initialized()
예제 #5
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()