Improve Yubikey USB API
* Allow for multiple vendor ID's to be checked at once. This allows for the use of one tracking index, streamlining KPXC code. * Remove support for libusb 0.x on Linux * Better handling of USB errors during initial key query. Output warnings to console.
This commit is contained in:
@@ -31,27 +31,22 @@ namespace
|
||||
{
|
||||
constexpr int MAX_KEYS = 4;
|
||||
|
||||
YK_KEY* openKey(int ykIndex, int okIndex, bool* onlyKey = nullptr)
|
||||
YK_KEY* openKey(int index)
|
||||
{
|
||||
YK_KEY* key = nullptr;
|
||||
if (onlyKey) {
|
||||
*onlyKey = false;
|
||||
}
|
||||
// Only allow for the first found key to be used
|
||||
if (ykIndex == 0) {
|
||||
key = yk_open_first_key();
|
||||
}
|
||||
static const int vids[] = {YUBICO_VID, ONLYKEY_VID};
|
||||
static const int pids[] = {YUBIKEY_PID,
|
||||
NEO_OTP_PID,
|
||||
NEO_OTP_CCID_PID,
|
||||
NEO_OTP_U2F_PID,
|
||||
NEO_OTP_U2F_CCID_PID,
|
||||
YK4_OTP_PID,
|
||||
YK4_OTP_U2F_PID,
|
||||
YK4_OTP_CCID_PID,
|
||||
YK4_OTP_U2F_CCID_PID,
|
||||
PLUS_U2F_OTP_PID,
|
||||
ONLYKEY_PID};
|
||||
|
||||
// New fuction available in yubikey-personalization version >= 1.20.0 that allows
|
||||
// selecting device VID/PID (yk_open_key_vid_pid)
|
||||
if (!key) {
|
||||
static const int device_pids[] = {0x60fc}; // OnlyKey PID
|
||||
key = yk_open_key_vid_pid(0x1d50, device_pids, 1, okIndex);
|
||||
if (onlyKey) {
|
||||
*onlyKey = true;
|
||||
}
|
||||
}
|
||||
return key;
|
||||
return yk_open_key_vid_pid(vids, sizeof(vids) / sizeof(vids[0]), pids, sizeof(pids) / sizeof(pids[0]), index);
|
||||
}
|
||||
|
||||
void closeKey(YK_KEY* key)
|
||||
@@ -68,19 +63,21 @@ namespace
|
||||
|
||||
YK_KEY* openKeySerial(unsigned int serial)
|
||||
{
|
||||
bool onlykey;
|
||||
for (int i = 0, j = 0; i + j < MAX_KEYS;) {
|
||||
auto* yk_key = openKey(i, j, &onlykey);
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
auto* yk_key = openKey(i);
|
||||
if (yk_key) {
|
||||
onlykey ? ++j : ++i;
|
||||
// If the provided serial number is 0, or the key matches the serial, return it
|
||||
if (serial == 0 || getSerial(yk_key) == serial) {
|
||||
return yk_key;
|
||||
}
|
||||
closeKey(yk_key);
|
||||
} else {
|
||||
} else if (yk_errno == YK_ENOKEY) {
|
||||
// No more connected keys
|
||||
break;
|
||||
} else if (yk_errno == YK_EUSBERR) {
|
||||
qWarning("Hardware key USB error: %s", yk_usb_strerror());
|
||||
} else {
|
||||
qWarning("Hardware key error: %s", yk_strerror(yk_errno));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -143,12 +140,9 @@ void YubiKey::findValidKeys()
|
||||
m_foundKeys.clear();
|
||||
|
||||
// Try to detect up to 4 connected hardware keys
|
||||
for (int i = 0, j = 0; i + j < MAX_KEYS;) {
|
||||
bool onlyKey = false;
|
||||
auto yk_key = openKey(i, j, &onlyKey);
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
auto yk_key = openKey(i);
|
||||
if (yk_key) {
|
||||
onlyKey ? ++j : ++i;
|
||||
auto vender = onlyKey ? QStringLiteral("OnlyKey") : QStringLiteral("YubiKey");
|
||||
auto serial = getSerial(yk_key);
|
||||
if (serial == 0) {
|
||||
closeKey(yk_key);
|
||||
@@ -160,6 +154,8 @@ void YubiKey::findValidKeys()
|
||||
int vid, pid;
|
||||
yk_get_key_vid_pid(yk_key, &vid, &pid);
|
||||
|
||||
auto vendor = vid == 0x1d50 ? QStringLiteral("OnlyKey") : QStringLiteral("YubiKey");
|
||||
|
||||
bool wouldBlock;
|
||||
QList<QPair<int, QString>> ykSlots;
|
||||
for (int slot = 1; slot <= 2; ++slot) {
|
||||
@@ -172,12 +168,12 @@ void YubiKey::findValidKeys()
|
||||
// if it is enabled for the slot resulting in failed detection
|
||||
if (pid <= NEO_OTP_U2F_CCID_PID) {
|
||||
auto display = tr("%1 [%2] Configured Slot - %3")
|
||||
.arg(vender, QString::number(serial), QString::number(slot));
|
||||
.arg(vendor, QString::number(serial), QString::number(slot));
|
||||
ykSlots.append({slot, display});
|
||||
} else if (performTestChallenge(yk_key, slot, &wouldBlock)) {
|
||||
auto display =
|
||||
tr("%1 [%2] Challenge-Response - Slot %3 - %4")
|
||||
.arg(vender,
|
||||
.arg(vendor,
|
||||
QString::number(serial),
|
||||
QString::number(slot),
|
||||
wouldBlock ? tr("Press", "Challenge-Response Key interaction request")
|
||||
@@ -194,9 +190,13 @@ void YubiKey::findValidKeys()
|
||||
closeKey(yk_key);
|
||||
|
||||
Tools::wait(100);
|
||||
} else {
|
||||
} else if (yk_errno == YK_ENOKEY) {
|
||||
// No more keys are connected
|
||||
break;
|
||||
} else if (yk_errno == YK_EUSBERR) {
|
||||
qWarning("Hardware key USB error: %s", yk_usb_strerror());
|
||||
} else {
|
||||
qWarning("Hardware key error: %s", yk_strerror(yk_errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user