From 3bc8a79b9bca9dfc77d32846e8d5e344347bdca4 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 7 Oct 2017 21:25:42 -0400 Subject: [PATCH] Both slots on Yubikey are now polled for challenge/response --- src/gui/DatabaseOpenWidget.cpp | 29 +++++++++++++++++++------ src/gui/DatabaseOpenWidget.h | 2 ++ src/keys/drivers/YubiKey.cpp | 39 +++++++++++++++++++++++----------- src/keys/drivers/YubiKey.h | 5 +++++ 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 7d59f16c..b8f8feb1 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -70,9 +70,6 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) connect(m_ui->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey())); connect(m_ui->comboChallengeResponse, SIGNAL(activated(int)), SLOT(activateChallengeResponse())); - - connect(YubiKey::instance(), SIGNAL(detected(int,bool)), SLOT(yubikeyDetected(int,bool)), Qt::QueuedConnection); - connect(YubiKey::instance(), SIGNAL(notFound()), SLOT(noYubikeyFound()), Qt::QueuedConnection); #else m_ui->checkChallengeResponse->setVisible(false); m_ui->buttonRedetectYubikey->setVisible(false); @@ -98,10 +95,24 @@ void DatabaseOpenWidget::showEvent(QShowEvent* event) m_ui->editPassword->setFocus(); #ifdef WITH_XC_YUBIKEY + connect(YubiKey::instance(), SIGNAL(detected(int,bool)), SLOT(yubikeyDetected(int,bool)), Qt::QueuedConnection); + connect(YubiKey::instance(), SIGNAL(detectComplete()), SLOT(yubikeyDetectComplete()), Qt::QueuedConnection); + connect(YubiKey::instance(), SIGNAL(notFound()), SLOT(noYubikeyFound()), Qt::QueuedConnection); + pollYubikey(); #endif } +void DatabaseOpenWidget::hideEvent(QHideEvent* event) +{ + DialogyWidget::hideEvent(event); + +#ifdef WITH_XC_YUBIKEY + // Don't listen to any Yubikey events if we are hidden + disconnect(YubiKey::instance(), 0, this, 0); +#endif +} + void DatabaseOpenWidget::load(const QString& filename) { m_filename = filename; @@ -283,10 +294,6 @@ void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) YkChallengeResponseKey yk(slot, blocking); // add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant((slot << 1) | blocking)); - m_ui->comboChallengeResponse->setEnabled(true); - m_ui->checkChallengeResponse->setEnabled(true); - m_ui->buttonRedetectYubikey->setEnabled(true); - m_ui->yubikeyProgress->setVisible(false); if (config()->get("RememberLastKeyFiles").toBool()) { QHash lastChallengeResponse = config()->get("LastChallengeResponse").toHash(); @@ -296,6 +303,14 @@ void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) } } +void DatabaseOpenWidget::yubikeyDetectComplete() +{ + m_ui->comboChallengeResponse->setEnabled(true); + m_ui->checkChallengeResponse->setEnabled(true); + m_ui->buttonRedetectYubikey->setEnabled(true); + m_ui->yubikeyProgress->setVisible(false); +} + void DatabaseOpenWidget::noYubikeyFound() { m_ui->buttonRedetectYubikey->setEnabled(true); diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h index 441e6418..d4b47364 100644 --- a/src/gui/DatabaseOpenWidget.h +++ b/src/gui/DatabaseOpenWidget.h @@ -51,6 +51,7 @@ signals: protected: void showEvent(QShowEvent* event) override; + void hideEvent(QHideEvent* event) override; CompositeKey databaseKey(); protected slots: @@ -63,6 +64,7 @@ private slots: void activateChallengeResponse(); void browseKeyFile(); void yubikeyDetected(int slot, bool blocking); + void yubikeyDetectComplete(); void noYubikeyFound(); protected: diff --git a/src/keys/drivers/YubiKey.cpp b/src/keys/drivers/YubiKey.cpp index b6f0d309..4b98a6e4 100644 --- a/src/keys/drivers/YubiKey.cpp +++ b/src/keys/drivers/YubiKey.cpp @@ -25,6 +25,7 @@ #include #include +#include "core/Tools.h" #include "core/Global.h" #include "crypto/Random.h" @@ -112,23 +113,36 @@ bool YubiKey::deinit() void YubiKey::detect() { - if (init()) { - for (int i = 1; i < 3; i++) { - YubiKey::ChallengeResult result; - QByteArray rand = randomGen()->randomArray(1); - QByteArray resp; + bool found = false; + if (init()) { + YubiKey::ChallengeResult result; + QByteArray rand = randomGen()->randomArray(1); + QByteArray resp; + + // Check slot 1 and 2 for Challenge-Response HMAC capability + for (int i = 1; i <= 2; ++i) { result = challenge(i, false, rand, resp); - if (result == YubiKey::ALREADY_RUNNING) { - emit alreadyRunning(); - return; - } else if (result != YubiKey::ERROR) { - emit detected(i, result == YubiKey::WOULDBLOCK); - return; + if (result == ALREADY_RUNNING) { + // Try this slot again after waiting + Tools::sleep(300); + result = challenge(i, false, rand, resp); } + + if (result != ALREADY_RUNNING && result != ERROR) { + emit detected(i, result == WOULDBLOCK); + found = true; + } + // Wait between slots to let the yubikey settle + Tools::sleep(150); } } - emit notFound(); + + if (!found) { + emit notFound(); + } else { + emit detectComplete(); + } } bool YubiKey::getSerial(unsigned int& serial) @@ -160,6 +174,7 @@ YubiKey::ChallengeResult YubiKey::challenge(int slot, bool mayBlock, const QByte } // yk_challenge_response() insists on 64 byte response buffer */ + response.clear(); response.resize(64); /* The challenge sent to the yubikey should always be 64 bytes for diff --git a/src/keys/drivers/YubiKey.h b/src/keys/drivers/YubiKey.h index 1467b9fd..328688f0 100644 --- a/src/keys/drivers/YubiKey.h +++ b/src/keys/drivers/YubiKey.h @@ -87,6 +87,11 @@ signals: */ void detected(int slot, bool blocking); + /** + * Emitted when detection is complete + */ + void detectComplete(); + /** * Emitted when the YubiKey was challenged and has returned a response. */