Show message when user needs to touch their YubiKey (still buggy when using multiple databases)

This commit is contained in:
Janek Bevendorff 2017-02-24 03:25:08 +01:00
parent 44ac7d152b
commit d6c48a5cf1
No known key found for this signature in database
GPG Key ID: CFEC2F6850BFFA53
11 changed files with 75 additions and 16 deletions

View File

@ -87,6 +87,11 @@ Application::Application(int& argc, char** argv)
#endif #endif
} }
QWidget* Application::mainWindow() const
{
return m_mainWindow;
}
void Application::setMainWindow(QWidget* mainWindow) void Application::setMainWindow(QWidget* mainWindow)
{ {
m_mainWindow = mainWindow; m_mainWindow = mainWindow;

View File

@ -29,6 +29,7 @@ class Application : public QApplication
public: public:
Application(int& argc, char** argv); Application(int& argc, char** argv);
QWidget* mainWindow() const;
void setMainWindow(QWidget* mainWindow); void setMainWindow(QWidget* mainWindow);
bool event(QEvent* event) override; bool event(QEvent* event) override;

View File

@ -25,6 +25,7 @@
#include "gui/FileDialog.h" #include "gui/FileDialog.h"
#include "gui/MessageBox.h" #include "gui/MessageBox.h"
#include "crypto/Random.h" #include "crypto/Random.h"
#include "MainWindow.h"
#include "config-keepassx.h" #include "config-keepassx.h"
@ -176,6 +177,8 @@ void ChangeMasterKeyWidget::generateKey()
bool blocking = i & true; bool blocking = i & true;
int slot = i >> 1; int slot = i >> 1;
auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking)); auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
connect(key.data(), SIGNAL(userInteractionRequired()), SLOT(showYubiKeyPopup()));
connect(key.data(), SIGNAL(userConfirmed()), SLOT(hideYubiKeyPopup()));
m_key.addChallengeResponseKey(key); m_key.addChallengeResponseKey(key);
} }
#endif #endif
@ -238,3 +241,15 @@ void ChangeMasterKeyWidget::setCancelEnabled(bool enabled)
{ {
m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(enabled); m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(enabled);
} }
void ChangeMasterKeyWidget::showYubiKeyPopup()
{
KEEPASSXC_MAIN_WINDOW->displayGlobalMessage(tr("Please touch the button on your YubiKey!"), MessageWidget::Information);
KEEPASSXC_MAIN_WINDOW->setEnabled(false);
}
void ChangeMasterKeyWidget::hideYubiKeyPopup()
{
KEEPASSXC_MAIN_WINDOW->hideGlobalMessage();
KEEPASSXC_MAIN_WINDOW->setEnabled(true);
}

View File

@ -55,6 +55,8 @@ private slots:
void noYubikeyFound(); void noYubikeyFound();
void challengeResponseGroupToggled(bool checked); void challengeResponseGroupToggled(bool checked);
void pollYubikey(); void pollYubikey();
void showYubiKeyPopup();
void hideYubiKeyPopup();
private: private:
const QScopedPointer<Ui::ChangeMasterKeyWidget> m_ui; const QScopedPointer<Ui::ChangeMasterKeyWidget> m_ui;

View File

@ -214,6 +214,8 @@ CompositeKey DatabaseOpenWidget::databaseKey()
bool blocking = i & true; bool blocking = i & true;
int slot = i >> 1; int slot = i >> 1;
auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking)); auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
connect(key.data(), SIGNAL(userInteractionRequired()), SLOT(showYubiKeyPopup()));
connect(key.data(), SIGNAL(userConfirmed()), SLOT(hideYubiKeyPopup()));
masterKey.addChallengeResponseKey(key); masterKey.addChallengeResponseKey(key);
} }
#endif #endif
@ -264,6 +266,18 @@ void DatabaseOpenWidget::pollYubikey()
QtConcurrent::run(YubiKey::instance(), &YubiKey::detect); QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
} }
void DatabaseOpenWidget::showYubiKeyPopup()
{
m_ui->messageWidget->showMessage(tr("Please touch the button on your YubiKey!"), MessageWidget::Information);
KEEPASSXC_MAIN_WINDOW->setEnabled(false);
}
void DatabaseOpenWidget::hideYubiKeyPopup()
{
m_ui->messageWidget->hideMessage();
KEEPASSXC_MAIN_WINDOW->setEnabled(true);
}
void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking)
{ {
YkChallengeResponseKey yk(slot, blocking); YkChallengeResponseKey yk(slot, blocking);

View File

@ -53,6 +53,8 @@ protected:
protected slots: protected slots:
virtual void openDatabase(); virtual void openDatabase();
void showYubiKeyPopup();
void hideYubiKeyPopup();
void reject(); void reject();
private slots: private slots:

View File

@ -24,6 +24,7 @@
#include "core/SignalMultiplexer.h" #include "core/SignalMultiplexer.h"
#include "gui/DatabaseWidget.h" #include "gui/DatabaseWidget.h"
#include "gui/Application.h"
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -43,6 +44,9 @@ public Q_SLOTS:
void openDatabase(const QString& fileName, const QString& pw = QString(), void openDatabase(const QString& fileName, const QString& pw = QString(),
const QString& keyFile = QString()); const QString& keyFile = QString());
void appExit(); void appExit();
void displayGlobalMessage(const QString& text, MessageWidget::MessageType type);
void displayTabMessage(const QString& text, MessageWidget::MessageType type);
void hideGlobalMessage();
protected: protected:
void closeEvent(QCloseEvent* event) override; void closeEvent(QCloseEvent* event) override;
@ -75,9 +79,6 @@ private Q_SLOTS:
void toggleWindow(); void toggleWindow();
void lockDatabasesAfterInactivity(); void lockDatabasesAfterInactivity();
void repairDatabase(); void repairDatabase();
void displayGlobalMessage(const QString& text, MessageWidget::MessageType type);
void displayTabMessage(const QString& text, MessageWidget::MessageType type);
void hideGlobalMessage();
void hideTabMessage(); void hideTabMessage();
private: private:
@ -106,4 +107,6 @@ private:
bool appExitCalled; bool appExitCalled;
}; };
#define KEEPASSXC_MAIN_WINDOW qobject_cast<MainWindow*>(qobject_cast<Application*>(qApp)->mainWindow())
#endif // KEEPASSX_MAINWINDOW_H #endif // KEEPASSX_MAINWINDOW_H

View File

@ -14,16 +14,19 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "keys/YkChallengeResponseKey.h"
#include <QFile> #include "keys/drivers/YubiKey.h"
#include <QXmlStreamReader>
#include "core/Tools.h" #include "core/Tools.h"
#include "crypto/CryptoHash.h" #include "crypto/CryptoHash.h"
#include "crypto/Random.h" #include "crypto/Random.h"
#include "keys/YkChallengeResponseKey.h" #include <QFile>
#include "keys/drivers/YubiKey.h" #include <QXmlStreamReader>
#include <QtConcurrent>
#include <QApplication>
#include <QEventLoop>
#include <QFutureWatcher>
YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking) YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking)
: m_slot(slot), : m_slot(slot),
@ -39,12 +42,12 @@ QByteArray YkChallengeResponseKey::rawKey() const
/** /**
* Assumes yubikey()->init() was called * Assumes yubikey()->init() was called
*/ */
bool YkChallengeResponseKey::challenge(const QByteArray& chal) bool YkChallengeResponseKey::challenge(const QByteArray& challenge)
{ {
return challenge(chal, 1); return this->challenge(challenge, 1);
} }
#include <QDebug>
bool YkChallengeResponseKey::challenge(const QByteArray& chal, unsigned retries) bool YkChallengeResponseKey::challenge(const QByteArray& challenge, unsigned retries)
{ {
Q_ASSERT(retries > 0); Q_ASSERT(retries > 0);
@ -55,13 +58,21 @@ bool YkChallengeResponseKey::challenge(const QByteArray& chal, unsigned retries)
emit userInteractionRequired(); emit userInteractionRequired();
} }
auto result = YubiKey::instance()->challenge(m_slot, true, chal, m_key); QFuture<YubiKey::ChallengeResult> future = QtConcurrent::run([this, challenge]() {
return YubiKey::instance()->challenge(m_slot, true, challenge, m_key);
});
QEventLoop loop;
QFutureWatcher<YubiKey::ChallengeResult> watcher;
watcher.setFuture(future);
connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
if (m_blocking) { if (m_blocking) {
emit userConfirmed(); emit userConfirmed();
} }
if (result != YubiKey::ERROR) { if (future.result() != YubiKey::ERROR) {
return true; return true;
} }

View File

@ -33,8 +33,8 @@ public:
YkChallengeResponseKey(int slot = -1, bool blocking = false); YkChallengeResponseKey(int slot = -1, bool blocking = false);
QByteArray rawKey() const; QByteArray rawKey() const;
bool challenge(const QByteArray& chal); bool challenge(const QByteArray& challenge);
bool challenge(const QByteArray& chal, unsigned retries); bool challenge(const QByteArray& challenge, unsigned retries);
QString getName() const; QString getName() const;
bool isBlocking() const; bool isBlocking() const;

View File

@ -182,6 +182,7 @@ YubiKey::ChallengeResult YubiKey::challenge(int slot, bool mayBlock, const QByte
#endif #endif
int ret = yk_challenge_response(m_yk, yk_cmd, mayBlock, paddedChallenge.size(), c, response.size(), r); int ret = yk_challenge_response(m_yk, yk_cmd, mayBlock, paddedChallenge.size(), c, response.size(), r);
emit challenged();
m_mutex.unlock(); m_mutex.unlock();

View File

@ -86,6 +86,11 @@ Q_SIGNALS:
*/ */
void detected(int slot, bool blocking); void detected(int slot, bool blocking);
/**
* Emitted when the YubiKey was challenged and has returned a response.
*/
void challenged();
/** /**
* Emitted when no Yubikey could be found. * Emitted when no Yubikey could be found.
*/ */