Yubico / python-fido2

Provides library functionality for FIDO 2.0, including communication with a device over USB.
BSD 2-Clause "Simplified" License
432 stars 109 forks source link

Waits forever while calling hid.list_devices() #140

Open mralinp opened 2 years ago

mralinp commented 2 years ago

There is a problem with the method list_devices() inside fido2/hid/__init__.py. It opens a connection to the fido security key HID device, and after a successful connection, it yields the device as the next found device. If the HID device has a problem and does not answer the open_connection() request, it waits forever. What I did to solve the problem was add a timeout to the open_connection() function call:

class CtapHidDevice(CtapDevice):
    ...
    @classmethod
    def open_test_connection(cls, d):
        # TODO: change proces to thread
        cls(d, open_connection(d))

    @classmethod
    def is_device_connected(cls, d):
        process = multiprocessing.Process(target=cls.open_test_connection, args=(d,))
        process.start()
        process.join(1)
        if process.is_alive():
            process.terminate()
            return False
        return True

    @classmethod
    def list_devices(cls):
        for d in list_descriptors():
            if cls.is_device_connected(d):
                yield cls(d, open_connection(d))

I'm using the PyPI installed version of the library: fido2==0.9.3

dainnilsson commented 2 years ago

Hi.

What OS are you running?

Do you know what circumstances cause the problem of a device hanging to occur?

Also, can you test the latest pre-release, 1.0.0rc1 and see if you have the same issue there?

mralinp commented 2 years ago

Hi, I'm using windows and, I've tested the pre-release 1.0.0rc1. Yes the issue is still unresolved. The problem occurs when it tries to open the connection to a HID device while the HID device is not answering to the connection request. I am using a virtual HID driver to regenerate the issue. If you want, I can check my USB bus logs for more details.

dainnilsson commented 2 years ago

Is this only occurring with a virtual HID driver, as in not an actual device? I'm trying to figure out here is this is something that actually happen unexpectedly or if you have to explicitly provoke it with a fake device.

mralinp commented 2 years ago

I've seen this issue with my device once about two months ago. Then I tried to make a test scenario with this fake virtual HID device. I was expecting that the library should do something when the connected HID device is not responding (As the windows hello webauthn.dll handles this situation somehow). For example, the security key is crashed (For some unknown or unreal reason), its driver failed, or something unexpected happens.

dainnilsson commented 2 years ago

Could you try modifying your fido2/hid/windows.py WinCtapHidConnection.init method to the following, and see if that makes a difference?

from threading import Timer

class WinCtapHidConnection(CtapHidConnection):
    def __init__(self, descriptor):
        self.descriptor = descriptor

        timer = Timer(1.0, kernel32.CancelSynchronousIo, [kernel32.GetCurrentThread()])
        timer.start()

        self.handle = kernel32.CreateFileA(
            descriptor.path,
            GENERIC_WRITE | GENERIC_READ,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            None,
            OPEN_EXISTING,
            0,
            None,
        )

        timer.cancel()

        if self.handle == INVALID_HANDLE_VALUE:
            raise WinError()
mralinp commented 2 years ago

No, it didn't help.

dainnilsson commented 2 years ago

Is there anything you can share with me that would help me be able to reproduce this on my end? Maybe I could set up the virtual HID device myself?