hack: bypass password challenge verification

Needed to support automatic migration of old Keysmith storage format.

This is unfortunate, but we have users and we cannot simply break
backwards compatibility with the old storage format (yet).
master
Johan Ouwerkerk 2021-02-01 19:22:29 +01:00
parent 464e001caf
commit 82ebbdf4f9
3 changed files with 62 additions and 10 deletions

View File

@ -1,6 +1,6 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
* SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
*/
#include "actions_p.h"
#include "validation.h"
@ -347,6 +347,8 @@ namespace accounts
quint64 cpuCost = 0ULL;
quint64 keyLength = 0ULL;
size_t memoryCost = 0ULL;
// HACK: disables challenge verification, remove at some point!
bool challengeAvailable = settings.contains(QStringLiteral("challenge"));
int algorithm = settings.value(QStringLiteral("algorithm")).toInt(&ok);
if (ok) {
ok = false;
@ -365,12 +367,15 @@ namespace accounts
salt = QByteArray::fromBase64(encodedSalt, QByteArray::Base64Encoding);
ok = !salt.isEmpty() && secrets::SecureMasterKey::validate(salt);
}
if (ok) {
// HACK: disables challenge verification, remove at some point!
if (challengeAvailable && ok) {
QByteArray encodedChallenge = settings.value(QStringLiteral("challenge")).toString().toUtf8();
challenge = QByteArray::fromBase64(encodedChallenge, QByteArray::Base64Encoding);
ok = !challenge.isEmpty();
}
if (ok) {
// HACK: disables challenge verification, remove at some point!
if (challengeAvailable && ok) {
QByteArray encodedNonce = settings.value(QStringLiteral("nonce")).toString().toUtf8();
nonce = QByteArray::fromBase64(encodedNonce, QByteArray::Base64Encoding);
ok = !nonce.isEmpty();
@ -379,13 +384,17 @@ namespace accounts
const auto params = secrets::KeyDerivationParameters::create(keyLength, algorithm, memoryCost, cpuCost);
const auto encryptedChallenge = secrets::EncryptedSecret::from(challenge, nonce);
if (!ok || !params || !secrets::SecureMasterKey::validate(*params) || !encryptedChallenge) {
// HACK: disables challenge verification, remove at some point!
if (!ok || !params || !secrets::SecureMasterKey::validate(*params) || (challengeAvailable && !encryptedChallenge)) {
qCDebug(logger) << "Unable to request 'existing' password: invalid challenge, nonce, salt or key derivation parameters";
return;
}
qCInfo(logger) << "Requesting 'existing' password for accounts";
ok = m_secret->requestExistingPassword(*encryptedChallenge, salt, *params);
ok = challengeAvailable
? m_secret->requestExistingPassword(*encryptedChallenge, salt, *params)
: m_secret->requestExistingPassword(salt, *params); // HACK: disables challenge verification, remove at some point!
});
if (!ok) {

View File

@ -1,6 +1,6 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
* SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
*/
#include "keys.h"
@ -13,8 +13,10 @@ KEYSMITH_LOGGER(logger, ".accounts.keys")
namespace accounts
{
AccountSecret::AccountSecret(const secrets::SecureRandom &random, QObject *parent) :
QObject(parent), m_stillAlive(true), m_newPassword(false), m_passwordRequested(false), m_random(random),
m_salt(std::nullopt), m_challenge(std::nullopt), m_key(nullptr), m_password(nullptr), m_keyParams(std::nullopt)
QObject(parent), m_stillAlive(true), m_newPassword(false), m_passwordRequested(false),
m_hackWithoutChallenge(false), // HACK: disables challenge verification, remove at some point!
m_random(random), m_salt(std::nullopt), m_challenge(std::nullopt), m_key(nullptr), m_password(nullptr),
m_keyParams(std::nullopt)
{
}
@ -81,6 +83,41 @@ namespace accounts
return true;
}
// HACK: disables challenge verification, remove at some point!
bool AccountSecret::requestExistingPassword(const QByteArray& salt, const secrets::KeyDerivationParameters &keyParams)
{
qCWarning(logger) << "HACK: running a 'silent' migration for legacy account setups without password challenge";
if (!m_stillAlive) {
qCDebug(logger) << "Ignoring request for 'existing' password: account secret is marked for death";
return false;
}
if (m_passwordRequested) {
qCDebug(logger) << "Ignoring request for 'existing' password: conflicting or duplicate request";
return false;
}
if (!secrets::SecureMasterKey::validate(keyParams)) {
qCDebug(logger) << "Unable to request 'existing' password: invalid key derivation parameters";
return false;
}
if (!secrets::SecureMasterKey::validate(salt)) {
qCDebug(logger) << "Unable to request 'existing' password: invalid salt";
return false;
}
qCDebug(logger) << "Emitting request for 'existing' password";
m_passwordRequested = true;
m_newPassword = false;
m_keyParams.emplace(keyParams);
m_salt.emplace(salt);
m_hackWithoutChallenge = true;
Q_EMIT existingPasswordNeeded();
return true;
}
bool AccountSecret::acceptPassword(QString &password, bool answerMatchesRequest)
{
QByteArray passwordBytes;
@ -132,7 +169,9 @@ namespace accounts
bool AccountSecret::answerExistingPassword(QString &password)
{
bool result = acceptPassword(password, m_keyParams && m_salt && m_challenge);
// HACK: disables challenge verification, remove at some point!
bool challengeOk = (m_challenge || m_hackWithoutChallenge);
bool result = acceptPassword(password, m_keyParams && m_salt && challengeOk);
if (result) {
Q_EMIT passwordAvailable();
}

View File

@ -1,6 +1,6 @@
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
* SPDX-FileCopyrightText: 2020-2021 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
*/
#ifndef ACCOUNTS_KEYS_H
#define ACCOUNTS_KEYS_H
@ -29,6 +29,9 @@ namespace accounts
bool requestExistingPassword(const secrets::EncryptedSecret &challenge,
const QByteArray& salt, const secrets::KeyDerivationParameters &keyParams);
// HACK: disables challenge verification, remove at some point!
bool requestExistingPassword(const QByteArray& salt, const secrets::KeyDerivationParameters &keyParams);
bool answerExistingPassword(QString &password);
bool answerNewPassword(QString &password, const secrets::KeyDerivationParameters &keyParams);
@ -50,6 +53,7 @@ namespace accounts
bool m_stillAlive;
bool m_newPassword;
bool m_passwordRequested;
bool m_hackWithoutChallenge; // HACK: disables challenge verification, remove at some point!
const secrets::SecureRandom m_random;
std::optional<QByteArray> m_salt;
std::optional<secrets::EncryptedSecret> m_challenge;