yubikey-personalization icon indicating copy to clipboard operation
yubikey-personalization copied to clipboard

YubiKey index is not stable

Open antelle opened this issue 4 years ago • 6 comments

Hi! I'm trying to use the library to enumerate connected YubiKeys to offer a way of selecting which YubiKey to use in the product, here's a piece of code I'm using to test it (on macOS):

    for (int i = 0; i < 100; i++) {
        YK_KEY *yk = nullptr;

        if (!(yk = yk_open_key(0))) {
            throwYubiKeyError(env, "yk_open_key");
            return result;
        }

        unsigned int serial;
        if (!yk_get_serial(yk, 1, 0, &serial)) {
            throwYubiKeyError(env, "yk_get_serial");
            return result;
        }
        std::cout << serial << "\n";

        yk_close_key(yk);
    }

When two YubiKeys are connected, the output contains two of YubiKeys in random order. Similarly, ykinfo -sn1 gives a random serial.

What would be the proper way to get the list of YubiKeys?

The issue seems to be here, where a set is converted to an array, which is supposed to give results in random order indeed.

I tried to figure out how you do it in ykman and came across this hack, which is actually how the proper yubikey is selected. Perhaps something like yk_open_all_keys would make more sense rather than doing it this way?

antelle avatar May 28 '20 08:05 antelle

Was there any resolution to this issue? I have a similar problem. I am creating an MacOS utility to program multiple keys via a USB hub. When more than one key is connected to the system, the index associated with each of the keys changes in an apparent random order. By that I mean if I have three keys inserted at once... and I enumerate the list of keys.. the key at any given index will change randomly when trying to open a key at a specific index.

I was hoping there was a way to save the USB device path.. and then access the key using that path reference, so as to open a specific key, but there appears to be no method in the personalization library to do that. Any advice would be most appreciated.

Another option would be to receive a list of key serial numbers and then open a specific key with the matching serial.

Ken-CA avatar Jun 26 '20 16:06 Ken-CA

@Ken-CA I ended up in retrying a number of times until we get the right YubiKey.

Additionally if VID and PID are provided, it's possible to use yk_open_key_vid_pid method, which opens a random YubiKey but with specified parameters, this narrows down the list a bit. However it would be very nice to have a proper solution instead of this hack.

antelle avatar Jun 26 '20 17:06 antelle

@antelle, agreed. It would be nice to have a more deterministic way to open a key... either with a USB identifier or the serial number. I looked at the code and found the same thing you mention... with the conversion from a CFSetRef to an array. Since this is not ordered, the function support provided via an index is rather useless.

The open function appears to return a void pointer to a device. I wonder if it would be more helpful to return a set of pointers to all of the devices matching the vid/pid? Then, we could just hold on to that and then enumerate the set.

Doing so still creates the additional problem that if a key is removed or added.. the set of pointers needs to be expanded or reduced. This is become quite problematic...lol. There has to be a better way to reference keys by something unique in the USB subsystem?

Two questions come to mind... If I open each key and hold on to the device pointer...

  1. will that device pointer remain valid as long as the key is inserted and
  2. what happens to that device pointer if the user removes the key

Ken-CA avatar Jun 26 '20 17:06 Ken-CA

No word from YubiCo yet. This is a real problem as it makes all of the CLI tools the take an index parameter rather useless. If I can't depend that the index value points to a specific key, then CLI tools like ykpersonalize may end up programing the wrong key. A better implementation would be to allow a serial number to be passed in as a parameter. Another option is to offer a function that returns the set of keys...rather than an array.

Ken-CA avatar Jun 29 '20 11:06 Ken-CA

@antelle Not sure if this will help you in your situation, but the way I got around this was to use the HIDManager (MacOS) to list devices based on vid/pid, filter that list for devices with usagePage=1 and usage=6. This return one device handle per YubiKey. I then save a reference to that device handle. I also rewrote the YubiCo open key function to take a device handle rather than an index. I can then guarantee that I am opening the correct key.

Ken-CA avatar Jul 02 '20 15:07 Ken-CA

I came over here to report a similar issue trying to use the tool, querying ykpersonalize -N0 -d repeatedly results in the output device and firmware version changing every couple of calls when multiple Yubikeys are plugged in.

I'm guessing it also isn't safe to assume that the "show serial in USB descriptor" is consistently enabled on large batches of Yubikeys if they are a mix of the Neo/YK4/YK5.

dragon788 avatar Nov 23 '20 17:11 dragon788