diff options
author | louib <L0U13@protonmail.com> | 2019-09-21 19:31:44 +0300 |
---|---|---|
committer | Jonathan White <support@dmapps.us> | 2019-09-23 01:11:40 +0300 |
commit | 964478e78f94b00f79983f97480eb0183dae413f (patch) | |
tree | b6a36544cf490627bb12f9a5a2c268b823bb2704 /tests | |
parent | 77fcde875e78fa44fc664b92e77db14f41b92c0b (diff) |
CLI: Add Yubikey unlock support
Diffstat (limited to 'tests')
-rw-r--r-- | tests/TestCli.cpp | 114 | ||||
-rw-r--r-- | tests/TestCli.h | 3 | ||||
-rw-r--r-- | tests/TestYkChallengeResponseKey.cpp | 2 | ||||
-rw-r--r-- | tests/data/YubiKeyProtectedPasswords.kdbx | bin | 0 -> 1653 bytes |
4 files changed, 97 insertions, 22 deletions
diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index d1ae3992d..d0fe75702 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -89,6 +89,11 @@ void TestCli::initTestCase() QVERIFY(sourceDbFile4.open(QIODevice::ReadOnly)); QVERIFY(Tools::readAllFromDevice(&sourceDbFile4, m_keyFileProtectedNoPasswordDbData)); sourceDbFile4.close(); + + QFile sourceDbFileYubiKeyProtected(QString(KEEPASSX_TEST_DATA_DIR).append("/YubiKeyProtectedPasswords.kdbx")); + QVERIFY(sourceDbFileYubiKeyProtected.open(QIODevice::ReadOnly)); + QVERIFY(Tools::readAllFromDevice(&sourceDbFileYubiKeyProtected, m_yubiKeyProtectedDbData)); + sourceDbFileYubiKeyProtected.close(); } void TestCli::init() @@ -113,6 +118,11 @@ void TestCli::init() m_keyFileProtectedNoPasswordDbFile->write(m_keyFileProtectedNoPasswordDbData); m_keyFileProtectedNoPasswordDbFile->close(); + m_yubiKeyProtectedDbFile.reset(new TemporaryFile()); + m_yubiKeyProtectedDbFile->open(); + m_yubiKeyProtectedDbFile->write(m_yubiKeyProtectedDbData); + m_yubiKeyProtectedDbFile->close(); + m_stdinFile.reset(new TemporaryFile()); m_stdinFile->open(); m_stdinHandle = fdopen(m_stdinFile->handle(), "r+"); @@ -155,7 +165,7 @@ void TestCli::cleanupTestCase() QSharedPointer<Database> TestCli::readTestDatabase() const { Utils::Test::setNextPassword("a"); - auto db = QSharedPointer<Database>(Utils::unlockDatabase(m_dbFile->fileName(), true, "", m_stdoutHandle)); + auto db = QSharedPointer<Database>(Utils::unlockDatabase(m_dbFile->fileName(), true, "", "", m_stdoutHandle)); m_stdoutFile->seek(ftell(m_stdoutHandle)); // re-synchronize handles return db; } @@ -226,14 +236,8 @@ void TestCli::testAdd() Utils::Test::setNextPassword("a"); Utils::Test::setNextPassword("newpassword"); - addCmd.execute({"add", - "-u", - "newuser2", - "--url", - "https://example.net/", - "-p", - m_dbFile->fileName(), - "/newuser-entry2"}); + addCmd.execute( + {"add", "-u", "newuser2", "--url", "https://example.net/", "-p", m_dbFile->fileName(), "/newuser-entry2"}); db = readTestDatabase(); entry = db->rootGroup()->findEntryByPath("/newuser-entry2"); @@ -246,14 +250,7 @@ void TestCli::testAdd() pos = m_stdoutFile->pos(); posErr = m_stderrFile->pos(); Utils::Test::setNextPassword("a"); - addCmd.execute({"add", - "-u", - "newuser3", - "-g", - "-L", - "34", - m_dbFile->fileName(), - "/newuser-entry3"}); + addCmd.execute({"add", "-u", "newuser3", "-g", "-L", "34", m_dbFile->fileName(), "/newuser-entry3"}); m_stdoutFile->seek(pos); m_stderrFile->seek(posErr); m_stdoutFile->readLine(); // skip password prompt @@ -433,7 +430,7 @@ void TestCli::testCreate() QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n")); Utils::Test::setNextPassword("a"); - auto db = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename, true, "", Utils::DEVNULL)); + auto db = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename, true, "", "", Utils::DEVNULL)); QVERIFY(db); // Should refuse to create the database if it already exists. @@ -462,7 +459,8 @@ void TestCli::testCreate() QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n")); Utils::Test::setNextPassword("a"); - auto db2 = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename2, true, keyfilePath, Utils::DEVNULL)); + auto db2 = + QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename2, true, keyfilePath, "", Utils::DEVNULL)); QVERIFY(db2); // Testing with existing keyfile @@ -479,7 +477,8 @@ void TestCli::testCreate() QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n")); Utils::Test::setNextPassword("a"); - auto db3 = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename3, true, keyfilePath, Utils::DEVNULL)); + auto db3 = + QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename3, true, keyfilePath, "", Utils::DEVNULL)); QVERIFY(db3); } @@ -1471,5 +1470,78 @@ void TestCli::testInvalidDbFiles() m_stderrFile->seek(pos); QCOMPARE(QString(m_stderrFile->readAll()), QObject::tr("Failed to open database file %1: not readable").arg(path) + "\n"); -#endif // Q_OS_WIN +#endif // Q_OS_WIN +} + +/** + * Secret key for the YubiKey slot used by the unit test is + * 1c e3 0f d7 8d 20 dc fa 40 b5 0c 18 77 9a fb 0f 02 28 8d b7 + * This secret should be configured at slot 2, and the slot + * should be configured as passive. + */ +void TestCli::testYubiKeyOption() +{ + if (!YubiKey::instance()->init()) { + QSKIP("Unable to connect to YubiKey"); + } + + QString errorMessage; + bool isBlocking = YubiKey::instance()->checkSlotIsBlocking(2, errorMessage); + if (isBlocking && errorMessage.isEmpty()) { + QSKIP("Skipping YubiKey in press mode."); + } + + QByteArray challenge("CLITest"); + QByteArray response; + YubiKey::instance()->challenge(2, false, challenge, response); + QByteArray expected("\xA2\x3B\x94\x00\xBE\x47\x9A\x30\xA9\xEB\x50\x9B\x85\x56\x5B\x6B\x30\x25\xB4\x8E", 20); + QVERIFY2(response == expected, "YubiKey Slot 2 is not configured with correct secret key."); + + List listCmd; + Add addCmd; + + Utils::Test::setNextPassword("a"); + listCmd.execute({"ls", "-y", "2", m_yubiKeyProtectedDbFile->fileName()}); + m_stdoutFile->reset(); + m_stderrFile->reset(); + m_stdoutFile->readLine(); // skip password prompt + QCOMPARE(m_stdoutFile->readAll(), + QByteArray("entry1\n" + "entry2\n")); + + // Should raise an error with no yubikey slot. + qint64 pos = m_stdoutFile->pos(); + qint64 posErr = m_stderrFile->pos(); + Utils::Test::setNextPassword("a"); + listCmd.execute({"ls", m_yubiKeyProtectedDbFile->fileName()}); + m_stdoutFile->seek(pos); + m_stdoutFile->readLine(); // skip password prompt + m_stderrFile->seek(posErr); + QCOMPARE(m_stdoutFile->readAll(), QByteArray("")); + QCOMPARE(m_stderrFile->readLine(), + QByteArray("Error while reading the database: Invalid credentials were provided, please try again.\n")); + QCOMPARE(m_stderrFile->readLine(), + QByteArray("If this reoccurs, then your database file may be corrupt. (HMAC mismatch)\n")); + + // Should raise an error if yubikey slot is not a string + pos = m_stdoutFile->pos(); + posErr = m_stderrFile->pos(); + Utils::Test::setNextPassword("a"); + listCmd.execute({"ls", "-y", "invalidslot", m_yubiKeyProtectedDbFile->fileName()}); + m_stdoutFile->seek(pos); + m_stdoutFile->readLine(); // skip password prompt + m_stderrFile->seek(posErr); + QCOMPARE(m_stdoutFile->readAll(), QByteArray("")); + QCOMPARE(m_stderrFile->readAll().split(':').at(0), QByteArray("Invalid YubiKey slot invalidslot\n")); + + // Should raise an error if yubikey slot is invalid. + pos = m_stdoutFile->pos(); + posErr = m_stderrFile->pos(); + Utils::Test::setNextPassword("a"); + listCmd.execute({"ls", "-y", "3", m_yubiKeyProtectedDbFile->fileName()}); + m_stdoutFile->seek(pos); + m_stdoutFile->readLine(); // skip password prompt + m_stderrFile->seek(posErr); + QCOMPARE(m_stdoutFile->readAll(), QByteArray("")); + QCOMPARE(m_stderrFile->readAll().split(':').at(0), QByteArray("Invalid YubiKey slot 3\n")); } diff --git a/tests/TestCli.h b/tests/TestCli.h index 09c55e0ed..c2d72effa 100644 --- a/tests/TestCli.h +++ b/tests/TestCli.h @@ -64,16 +64,19 @@ private slots: void testRemoveQuiet(); void testShow(); void testInvalidDbFiles(); + void testYubiKeyOption(); private: QByteArray m_dbData; QByteArray m_dbData2; + QByteArray m_yubiKeyProtectedDbData; QByteArray m_keyFileProtectedDbData; QByteArray m_keyFileProtectedNoPasswordDbData; QScopedPointer<TemporaryFile> m_dbFile; QScopedPointer<TemporaryFile> m_dbFile2; QScopedPointer<TemporaryFile> m_keyFileProtectedDbFile; QScopedPointer<TemporaryFile> m_keyFileProtectedNoPasswordDbFile; + QScopedPointer<TemporaryFile> m_yubiKeyProtectedDbFile; QScopedPointer<TemporaryFile> m_stdoutFile; QScopedPointer<TemporaryFile> m_stderrFile; QScopedPointer<TemporaryFile> m_stdinFile; diff --git a/tests/TestYkChallengeResponseKey.cpp b/tests/TestYkChallengeResponseKey.cpp index 126d00315..0d6f9b5c3 100644 --- a/tests/TestYkChallengeResponseKey.cpp +++ b/tests/TestYkChallengeResponseKey.cpp @@ -74,7 +74,7 @@ void TestYubiKeyChalResp::keyIssueChallenge() /* TODO Determine if it's reasonable to provide a fixed secret key for * verification testing. Obviously simple technically, but annoying * if devs need to re-program their yubikeys or have a spare test key - * for unit tests to past. + * for unit tests to pass. * * Might be worth it for integrity verification though. */ diff --git a/tests/data/YubiKeyProtectedPasswords.kdbx b/tests/data/YubiKeyProtectedPasswords.kdbx Binary files differnew file mode 100644 index 000000000..c6c6d1324 --- /dev/null +++ b/tests/data/YubiKeyProtectedPasswords.kdbx |