Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions client/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ class Application::Private
#ifdef Q_OS_WIN
QStringList tempFiles;
#endif // Q_OS_WIN

~Private() {
delete signer;
}
};

Application::Application( int &argc, char **argv )
Expand Down Expand Up @@ -429,6 +433,7 @@ Application::Application( int &argc, char **argv )
// Clear obsolete registriy settings
#ifndef Q_OS_DARWIN
Settings::DEFAULT_DIR.clear();
Settings::CDOC2_NOTIFICATION.clear();
#endif

// Actions
Expand Down
124 changes: 79 additions & 45 deletions client/CDocSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,60 +93,80 @@ CDocSupport::getCDocFileList(const QString &filename)
}

static libcdoc::result_t
getDecryptStatus(const std::vector<uint8_t>& result, QCryptoBackend::PinStatus pin_status)
getDecryptStatus(QCryptoBackend::Status pin_status)
{
switch (pin_status) {
case QCryptoBackend::PinOK:
return (result.empty()) ? DDCryptoBackend::BACKEND_ERROR : libcdoc::OK;
return libcdoc::OK;
case QCryptoBackend::PinCanceled:
return DDCryptoBackend::PIN_CANCELED;
case QCryptoBackend::PinIncorrect:
return DDCryptoBackend::PIN_INCORRECT;
case QCryptoBackend::PinLocked:
return DDCryptoBackend::PIN_LOCKED;
case QCryptoBackend::InProgress:
return DDCryptoBackend::IN_PROGRESS;
default:
return DDCryptoBackend::BACKEND_ERROR;
}
}

static libcdoc::result_t
getDecryptResultStatus(const std::vector<uint8_t> &result, std::unique_ptr<QCryptoBackend> backend)
{
if (!result.empty())
return libcdoc::OK;
libcdoc::result_t mapped = getDecryptStatus(backend->status);
return mapped == libcdoc::OK ? DDCryptoBackend::BACKEND_ERROR : mapped;
}

libcdoc::result_t
DDCryptoBackend::decryptRSA(std::vector<uint8_t>& result, const std::vector<uint8_t> &data, bool oaep, unsigned int idx)
DDCryptoBackend::decryptRSA(std::vector<uint8_t>& dst, const std::vector<uint8_t> &data, bool oaep, unsigned int idx)
{
QCryptoBackend::PinStatus pin_status = QCryptoBackend::PinOK;
QByteArray qkek = qApp->signer()->decrypt([qdata = toByteArray(data), &oaep](QCryptoBackend *backend) {
return backend->decrypt(qdata, oaep);
}, pin_status);
result.assign(qkek.cbegin(), qkek.cend());
return getDecryptStatus(result, pin_status);
if (!backend) {
auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth());
if (!val)
return getDecryptStatus(val.error());
backend.reset(val.value());
}
QByteArray decryptedKey = backend->decrypt(toByteArray(data), oaep);
dst.assign(decryptedKey.cbegin(), decryptedKey.cend());
return getDecryptResultStatus(dst, std::move(backend));
}

libcdoc::result_t
DDCryptoBackend::deriveConcatKDF(std::vector<uint8_t>& dst, const std::vector<uint8_t> &publicKey, const std::string &digest,
const std::vector<uint8_t> &algorithmID, const std::vector<uint8_t> &partyUInfo, const std::vector<uint8_t> &partyVInfo, unsigned int idx)
{
QCryptoBackend::PinStatus pin_status = QCryptoBackend::PinOK;
QByteArray decryptedKey = qApp->signer()->decrypt([&publicKey, &digest, &algorithmID, &partyUInfo, &partyVInfo](QCryptoBackend *backend) {
static const QHash<std::string_view, QCryptographicHash::Algorithm> SHA_MTH{
{"http://www.w3.org/2001/04/xmlenc#sha256", QCryptographicHash::Sha256},
{"http://www.w3.org/2001/04/xmlenc#sha384", QCryptographicHash::Sha384},
{"http://www.w3.org/2001/04/xmlenc#sha512", QCryptographicHash::Sha512}
};
return backend->deriveConcatKDF(toByteArray(publicKey), SHA_MTH.value(digest),
toByteArray(algorithmID), toByteArray(partyUInfo), toByteArray(partyVInfo));
}, pin_status);
static const QHash<std::string_view, QCryptographicHash::Algorithm> SHA_MTH{
{"http://www.w3.org/2001/04/xmlenc#sha256", QCryptographicHash::Sha256},
{"http://www.w3.org/2001/04/xmlenc#sha384", QCryptographicHash::Sha384},
{"http://www.w3.org/2001/04/xmlenc#sha512", QCryptographicHash::Sha512}
};
if (!backend) {
auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth());
if (!val)
return getDecryptStatus(val.error());
backend.reset(val.value());
}
QByteArray decryptedKey = backend->deriveConcatKDF(toByteArray(publicKey), SHA_MTH.value(digest),
toByteArray(algorithmID), toByteArray(partyUInfo), toByteArray(partyVInfo));
dst.assign(decryptedKey.cbegin(), decryptedKey.cend());
return getDecryptStatus(dst, pin_status);
return getDecryptResultStatus(dst, std::move(backend));
}

libcdoc::result_t
DDCryptoBackend::deriveHMACExtract(std::vector<uint8_t>& dst, const std::vector<uint8_t> &key_material, const std::vector<uint8_t> &salt, unsigned int idx)
{
QCryptoBackend::PinStatus pin_status = QCryptoBackend::PinOK;
QByteArray qkekpm = qApp->signer()->decrypt([qkey_material = toByteArray(key_material), qsalt = toByteArray(salt)](QCryptoBackend *backend) {
return backend->deriveHMACExtract(qkey_material, qsalt, ECC_KEY_LEN);
}, pin_status);
dst = std::vector<uint8_t>(qkekpm.cbegin(), qkekpm.cend());
return getDecryptStatus(dst, pin_status);
if (!backend) {
auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth());
if (!val)
return getDecryptStatus(val.error());
backend.reset(val.value());
}
QByteArray decryptedKey = backend->deriveHMACExtract(toByteArray(key_material), toByteArray(salt), ECC_KEY_LEN);
dst.assign(decryptedKey.cbegin(), decryptedKey.cend());
return getDecryptResultStatus(dst, std::move(backend));
}

libcdoc::result_t
Expand All @@ -166,6 +186,8 @@ DDCryptoBackend::getLastErrorStr(libcdoc::result_t code) const
return "PIN incorrect";
case PIN_LOCKED:
return "PIN locked";
case IN_PROGRESS:
return "Signing/decrypting is already in progress another window.";
case BACKEND_ERROR:
return qApp->signer()->getLastErrorStr().toStdString();
}
Expand All @@ -188,26 +210,33 @@ checkConnection()
std::string
DDConfiguration::getValue(std::string_view domain, std::string_view param) const
{
std::string def = Settings::CDOC2_DEFAULT_KEYSERVER;
if (param == libcdoc::Configuration::KEYSERVER_SEND_URL) {
#ifdef CONFIG_URL
QJsonObject list = Application::confValue(QLatin1String("CDOC2-CONF")).toObject();
if (list.isEmpty()) return {};
QJsonObject data = list.value(QLatin1String(domain.data(), domain.size())).toObject();
QString url = data.value(QLatin1String("POST")).toString(Settings::CDOC2_POST);
if (data.isEmpty()) return {};
QString url = data.value(QLatin1String("POST")).toString();
return url.toStdString();
#else
QString url = Settings::CDOC2_POST;
return url.toStdString();
if (domain == Settings::CDOC2_DEFAULT_KEYSERVER) {
QString url = Settings::CDOC2_POST;
return url.toStdString();
}
#endif
} else if (param == libcdoc::Configuration::KEYSERVER_FETCH_URL) {
#ifdef CONFIG_URL
QJsonObject list = Application::confValue(QLatin1String("CDOC2-CONF")).toObject();
if (list.isEmpty()) return {};
QJsonObject data = list.value(QLatin1String(domain.data(), domain.size())).toObject();
QString url = data.value(QLatin1String("FETCH")).toString(Settings::CDOC2_GET);
if (data.isEmpty()) return {};
QString url = data.value(QLatin1String("FETCH")).toString();
return url.toStdString();
#else
QString url = Settings::CDOC2_GET;
return url.toStdString();
if (domain == Settings::CDOC2_DEFAULT_KEYSERVER) {
QString url = Settings::CDOC2_GET;
return url.toStdString();
}
#endif
}
return {};
Expand All @@ -223,6 +252,8 @@ DDNetworkBackend::getLastErrorStr(libcdoc::result_t code) const
return "PIN incorrect";
case DDCryptoBackend::PIN_LOCKED:
return "PIN locked";
case DDCryptoBackend::IN_PROGRESS:
return "Signing/decrypting is already in progress another window.";
case BACKEND_ERROR:
case DDCryptoBackend::BACKEND_ERROR:
return last_error;
Expand Down Expand Up @@ -281,32 +312,32 @@ libcdoc::result_t DDNetworkBackend::sendKey(
};

libcdoc::result_t
DDNetworkBackend::fetchKey(std::vector<uint8_t> &result,
const std::string &url,
const std::string &transaction_id) {
DDNetworkBackend::fetchKey(std::vector<uint8_t> &result, const std::string &url, const std::string &transaction_id)
{
QNetworkRequest req(QStringLiteral("%1/key-capsules/%2").arg(QString::fromStdString(url), QLatin1String(transaction_id.c_str())));
req.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));
if(!checkConnection()) {
last_error = "No connection";
return BACKEND_ERROR;
}
QCryptoBackend::PinStatus pin_status = QCryptoBackend::PinOK;
auto authKey = dispatchToMain([&] {
return qApp->signer()->key(pin_status);
});

TokenData auth = qApp->signer()->tokenauth();
auto val = QCryptoBackend::getBackend(qApp->signer()->tokenauth());
if (!val)
return getDecryptStatus(val.error());
std::unique_ptr<QCryptoBackend> backend(val.value());

auto authKey = backend->getKey();
if (!authKey.handle()) {
last_error = qApp->signer()->getLastErrorStr().toStdString();
return getDecryptStatus(result, pin_status);
last_error = "Cannot create authentication key";
return BACKEND_ERROR;
}
QScopedPointer<QNetworkAccessManager,QScopedPointerDeleteLater> nam(
CheckConnection::setupNAM(req, qApp->signer()->tokenauth().cert(), authKey, Settings::CDOC2_GET_CERT));
QEventLoop e;
QNetworkReply *reply = nam->get(req);
connect(reply, &QNetworkReply::finished, &e, &QEventLoop::quit);
e.exec();
if(authKey.handle()) {
qApp->signer()->logout();
}

if(reply->error() != QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 201) {
last_error = reply->errorString().toStdString();
Expand All @@ -315,6 +346,9 @@ DDNetworkBackend::fetchKey(std::vector<uint8_t> &result,
QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object();
QByteArray key_material = QByteArray::fromBase64(json.value(QLatin1String("ephemeral_key_material")).toString().toLatin1());
result.assign(key_material.cbegin(), key_material.cend());

crypto.setBackend(std::move(backend));

return libcdoc::OK;
}

Expand Down
13 changes: 11 additions & 2 deletions client/CDocSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#pragma once

#include "QCryptoBackend.h"

#include <QtCore/QObject>
#include <QtCore/QIODevice>
#include <QtCore/QFile>
Expand Down Expand Up @@ -58,6 +60,7 @@ struct DDCryptoBackend final : public libcdoc::CryptoBackend {
static constexpr int PIN_CANCELED = -504;
static constexpr int PIN_INCORRECT = -505;
static constexpr int PIN_LOCKED = -506;
static constexpr int IN_PROGRESS = -507;
libcdoc::result_t decryptRSA(std::vector<uint8_t> &result,
const std::vector<uint8_t> &data, bool oaep,
unsigned int idx) final;
Expand All @@ -76,9 +79,14 @@ struct DDCryptoBackend final : public libcdoc::CryptoBackend {
unsigned int idx) final;
std::string getLastErrorStr(libcdoc::result_t code) const final;

std::unique_ptr<QCryptoBackend> backend;
std::vector<uint8_t> secret;

explicit DDCryptoBackend() = default;

void setBackend(std::unique_ptr<QCryptoBackend> &&backend) {
this->backend = std::move(backend);
}
};

//
Expand Down Expand Up @@ -110,8 +118,9 @@ struct DDNetworkBackend final : public libcdoc::NetworkBackend, private QObject
return libcdoc::NOT_IMPLEMENTED;
}

explicit DDNetworkBackend() = default;
explicit DDNetworkBackend(DDCryptoBackend &_crypto) : crypto(_crypto) {}

DDCryptoBackend &crypto;
std::string last_error;
};

Expand Down Expand Up @@ -177,4 +186,4 @@ struct StreamListSource final : public libcdoc::MultiDataSource {

const std::vector<IOEntry> &_files;
int64_t _current = -1;
};
};
33 changes: 7 additions & 26 deletions client/CryptoDoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ struct CryptoDoc::Private
std::vector<IOEntry> files;
std::vector<CKey> keys;

explicit Private() : network(crypto) {}
bool isEncryptedWarning(const QString &title) const;

bool isEncrypted() const {
Expand Down Expand Up @@ -320,28 +321,6 @@ bool CryptoDoc::decrypt(const libcdoc::Lock *lock, const QByteArray& secret)
return false;
}

if (d->reader->version == 2 &&
(lock->type == libcdoc::Lock::Type::SERVER) &&
!Settings::CDOC2_NOTIFICATION.isSet()) {
auto *dlg = WarningDialog::create()
->withTitle(tr("You must enter your PIN code twice in order to decrypt the CDOC2 container"))
->withText(tr(
"The first PIN entry is required for authentication to the key server referenced in the CDOC2 container. "
"Second PIN entry is required to decrypt the CDOC2 container."))
->setCancelText(WarningDialog::Cancel)
->addButton(WarningDialog::OK, QMessageBox::Ok)
->addButton(tr("Don't show again"), QMessageBox::Ignore);
switch (dlg->exec())
{
case QMessageBox::Ok: break;
case QMessageBox::Ignore:
Settings::CDOC2_NOTIFICATION = true;
break;
default:
return false;
}
}

d->crypto.secret.assign(secret.cbegin(), secret.cend());

TempListConsumer cons;
Expand Down Expand Up @@ -374,13 +353,15 @@ bool CryptoDoc::decrypt(const libcdoc::Lock *lock, const QByteArray& secret)
str = tr("Cannot read file.");
break;
case DDCryptoBackend::PIN_CANCELED:
str = QCryptoBackend::tr("PIN Canceled");
break;
return false;
case DDCryptoBackend::PIN_INCORRECT:
str = QCryptoBackend::tr("PIN Incorrect");
str = QCryptoBackend::errorString(QCryptoBackend::Status::PinIncorrect);
break;
case DDCryptoBackend::PIN_LOCKED:
str = QCryptoBackend::tr("PIN locked");
str = QCryptoBackend::errorString(QCryptoBackend::Status::PinLocked);
break;
case DDCryptoBackend::IN_PROGRESS:
str = QCryptoBackend::errorString(QCryptoBackend::Status::InProgress);
break;
default:
str = tr("Please check your internet connection and network settings.");
Expand Down
5 changes: 3 additions & 2 deletions client/DigiDoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "CheckConnection.h"
#include "Common.h"
#include "MainWindow.h"
#include "QCryptoBackend.h"
#include "QSigner.h"
#include "Settings.h"
#include "TokenData.h"
Expand Down Expand Up @@ -749,7 +750,7 @@ void DigiDoc::setLastError(const QString &title, const Exception &e)
case Exception::PINFailed:
dlg->withText(tr("PIN Login failed")); break;
case Exception::PINIncorrect:
dlg->withText(QCryptoBackend::tr("PIN Incorrect")); break;
dlg->withText(QCryptoBackend::errorString(QCryptoBackend::PinIncorrect)); break;
case Exception::PINLocked:
dlg->withText(tr("PIN Locked. Unblock to reuse PIN.")); break;
case Exception::NetworkError:
Expand Down Expand Up @@ -798,7 +799,7 @@ bool DigiDoc::sign(const QString &city, const QString &state, const QString &zip
case Exception::PINIncorrect:
WarningDialog::create()
->withTitle(tr("Failed to sign container"))
->withText(QCryptoBackend::tr("PIN Incorrect"))
->withText(QCryptoBackend::errorString(QCryptoBackend::PinIncorrect))
->exec();
return sign(city, state, zip, country, role, signer);
case Exception::InvalidUrl:
Expand Down
Loading
Loading