challenge: Propagate failed challenge to caller

* If a removed Yubikey is to blame, re-inserting the Yubikey won't
  resolve the issue.  Hot plug isn't supported at this point.
* The caller should detect the error and cancel the database write.

Signed-off-by: Kyle Manna <kyle@kylemanna.com>
This commit is contained in:
Kyle Manna 2014-09-06 17:49:39 -07:00
parent ba8fd25604
commit faa055010f
6 changed files with 26 additions and 10 deletions

View File

@ -176,9 +176,9 @@ QByteArray Database::transformedMasterKey() const
return m_data.transformedMasterKey; return m_data.transformedMasterKey;
} }
QByteArray Database::challengeMasterSeed(const QByteArray& masterSeed) const bool Database::challengeMasterSeed(const QByteArray& masterSeed, QByteArray& result) const
{ {
return m_data.key.challenge(masterSeed); return m_data.key.challenge(masterSeed, result);
} }
void Database::setCipher(const Uuid& cipher) void Database::setCipher(const Uuid& cipher)

View File

@ -89,7 +89,7 @@ public:
quint64 transformRounds() const; quint64 transformRounds() const;
QByteArray transformedMasterKey() const; QByteArray transformedMasterKey() const;
const CompositeKey & key() const; const CompositeKey & key() const;
QByteArray challengeMasterSeed(const QByteArray& masterSeed) const; bool challengeMasterSeed(const QByteArray& masterSeed, QByteArray& result) const;
void setCipher(const Uuid& cipher); void setCipher(const Uuid& cipher);
void setCompressionAlgo(Database::CompressionAlgorithm algo); void setCompressionAlgo(Database::CompressionAlgorithm algo);

View File

@ -113,9 +113,15 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
return nullptr; return nullptr;
} }
QByteArray challengeResult;
if (m_db->challengeMasterSeed(m_masterSeed, challengeResult) == false) {
raiseError(tr("Unable to issue challenge-response."));
return Q_NULLPTR;
}
CryptoHash hash(CryptoHash::Sha256); CryptoHash hash(CryptoHash::Sha256);
hash.addData(m_masterSeed); hash.addData(m_masterSeed);
hash.addData(m_db->challengeMasterSeed(m_masterSeed)); hash.addData(challengeResult);
hash.addData(m_db->transformedMasterKey()); hash.addData(m_db->transformedMasterKey());
QByteArray finalKey = hash.result(); QByteArray finalKey = hash.result();

View File

@ -51,9 +51,15 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db)
QByteArray startBytes = randomGen()->randomArray(32); QByteArray startBytes = randomGen()->randomArray(32);
QByteArray endOfHeader = "\r\n\r\n"; QByteArray endOfHeader = "\r\n\r\n";
QByteArray challengeResult;
if (db->challengeMasterSeed(masterSeed, challengeResult) == false) {
raiseError("Unable to issue challenge-response.");
return;
}
CryptoHash hash(CryptoHash::Sha256); CryptoHash hash(CryptoHash::Sha256);
hash.addData(masterSeed); hash.addData(masterSeed);
hash.addData(db->challengeMasterSeed(masterSeed)); hash.addData(challengeResult);
Q_ASSERT(!db->transformedMasterKey().isEmpty()); Q_ASSERT(!db->transformedMasterKey().isEmpty());
hash.addData(db->transformedMasterKey()); hash.addData(db->transformedMasterKey());
QByteArray finalKey = hash.result(); QByteArray finalKey = hash.result();

View File

@ -146,23 +146,27 @@ QByteArray CompositeKey::transformKeyRaw(const QByteArray& key, const QByteArray
return result; return result;
} }
QByteArray CompositeKey::challenge(const QByteArray& seed) const bool CompositeKey::challenge(const QByteArray& seed, QByteArray& result) const
{ {
/* If no challenge response was requested, return nothing to /* If no challenge response was requested, return nothing to
* maintain backwards compatability with regular databases. * maintain backwards compatability with regular databases.
*/ */
if (m_challengeResponseKeys.length() == 0) { if (m_challengeResponseKeys.length() == 0) {
return QByteArray(); return true;
} }
CryptoHash cryptoHash(CryptoHash::Sha256); CryptoHash cryptoHash(CryptoHash::Sha256);
Q_FOREACH (ChallengeResponseKey* key, m_challengeResponseKeys) { Q_FOREACH (ChallengeResponseKey* key, m_challengeResponseKeys) {
key->challenge(seed); /* If the device isn't present or fails, return an error */
if (key->challenge(seed) == false) {
return false;
}
cryptoHash.addData(key->rawKey()); cryptoHash.addData(key->rawKey());
} }
return cryptoHash.result(); result = cryptoHash.result();
return true;
} }
void CompositeKey::addKey(const Key& key) void CompositeKey::addKey(const Key& key)

View File

@ -37,7 +37,7 @@ public:
QByteArray rawKey() const; QByteArray rawKey() const;
QByteArray transform(const QByteArray& seed, quint64 rounds, QByteArray transform(const QByteArray& seed, quint64 rounds,
bool* ok, QString* errorString) const; bool* ok, QString* errorString) const;
QByteArray challenge(const QByteArray& seed) const; bool challenge(const QByteArray& seed, QByteArray &result) const;
void addKey(const Key& key); void addKey(const Key& key);
void addChallengeResponseKey(const ChallengeResponseKey& key); void addChallengeResponseKey(const ChallengeResponseKey& key);