From 23da6baa06deb53775968022fd869f0c1ad818e3 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Wed, 13 Nov 2024 13:48:24 +0200 Subject: [PATCH] Unsupported algorithm or recipient type CDOC-3 Signed-off-by: Raul Metsma --- client/CDoc1.cpp | 41 +++++++++++-------------------- client/CDoc1.h | 4 +-- client/CDoc2.cpp | 22 +++++++---------- client/Crypto.cpp | 3 ++- client/Crypto.h | 3 +-- client/CryptoDoc.cpp | 5 ++++ client/CryptoDoc.h | 9 +++++-- client/MainWindow.cpp | 22 +++++++++++------ client/QCNG.cpp | 4 +-- client/QCNG.h | 2 +- client/QCryptoBackend.h | 4 +-- client/QPKCS11.cpp | 4 +-- client/QPKCS11.h | 2 +- client/common_enums.h | 4 ++- client/dialogs/KeyDialog.cpp | 6 +---- client/translations/en.ts | 31 ++++++++++++++--------- client/translations/et.ts | 31 ++++++++++++++--------- client/translations/ru.ts | 31 ++++++++++++++--------- client/widgets/AddressItem.cpp | 4 +++ client/widgets/ContainerPage.cpp | 33 +++++++++++++++---------- client/widgets/ContainerPage.h | 2 +- client/widgets/FileList.cpp | 5 +++- client/widgets/Item.cpp | 42 ++++++++++++++++++++++++++++++++ client/widgets/Item.h | 16 ++++++++++++ client/widgets/WarningItem.cpp | 6 +++++ 25 files changed, 216 insertions(+), 120 deletions(-) diff --git a/client/CDoc1.cpp b/client/CDoc1.cpp index 78596edaa..338797151 100644 --- a/client/CDoc1.cpp +++ b/client/CDoc1.cpp @@ -41,8 +41,6 @@ const QString CDoc1::AES128GCM_MTH = QStringLiteral("http://www.w3.org/2009/xmle const QString CDoc1::AES192GCM_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#aes192-gcm"); const QString CDoc1::AES256GCM_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#aes256-gcm"); const QString CDoc1::RSA_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#rsa-1_5"); -const QString CDoc1::KWAES128_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#kw-aes128"); -const QString CDoc1::KWAES192_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#kw-aes192"); const QString CDoc1::KWAES256_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#kw-aes256"); const QString CDoc1::CONCATKDF_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#ConcatKDF"); const QString CDoc1::AGREEMENT_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#ECDH-ES"); @@ -66,7 +64,6 @@ const QHash CDoc1::ENC_MTH{ const QHash CDoc1::SHA_MTH{ {SHA256_MTH, QCryptographicHash::Sha256}, {SHA384_MTH, QCryptographicHash::Sha384}, {SHA512_MTH, QCryptographicHash::Sha512} }; -const QHash CDoc1::KWAES_SIZE{{KWAES128_MTH, 16}, {KWAES192_MTH, 24}, {KWAES256_MTH, 32}}; CDoc1::CDoc1(const QString &path) : QFile(path) @@ -108,7 +105,6 @@ CDoc1::CDoc1(const QString &path) return; CKey key; - key.id = xml.attributes().value(QLatin1String("Id")).toString(); key.recipient = xml.attributes().value(QLatin1String("Recipient")).toString(); while(!xml.atEnd()) { @@ -117,18 +113,17 @@ CDoc1::CDoc1(const QString &path) break; if(!xml.isStartElement()) continue; - // EncryptedData/KeyInfo/KeyName - if(xml.name() == QLatin1String("KeyName")) - key.name = xml.readElementText(); - // EncryptedData/KeyInfo/EncryptedKey/EncryptionMethod - else if(xml.name() == QLatin1String("EncryptionMethod")) - key.method = xml.attributes().value(QLatin1String("Algorithm")).toString(); + if(xml.name() == QLatin1String("EncryptionMethod")) + { + auto method = xml.attributes().value(QLatin1String("Algorithm")); + key.unsupported = std::max(key.unsupported, method != KWAES256_MTH && method != RSA_MTH); + } // EncryptedData/KeyInfo/EncryptedKey/KeyInfo/AgreementMethod else if(xml.name() == QLatin1String("AgreementMethod")) - key.agreement = xml.attributes().value(QLatin1String("Algorithm")).toString(); + key.unsupported = std::max(key.unsupported, xml.attributes().value(QLatin1String("Algorithm")) != AGREEMENT_MTH); // EncryptedData/KeyInfo/EncryptedKey/KeyInfo/AgreementMethod/KeyDerivationMethod else if(xml.name() == QLatin1String("KeyDerivationMethod")) - key.derive = xml.attributes().value(QLatin1String("Algorithm")).toString(); + key.unsupported = std::max(key.unsupported, xml.attributes().value(QLatin1String("Algorithm")) != CONCATKDF_MTH); // EncryptedData/KeyInfo/EncryptedKey/KeyInfo/AgreementMethod/KeyDerivationMethod/ConcatKDFParams else if(xml.name() == QLatin1String("ConcatKDFParams")) { @@ -273,16 +268,13 @@ CKey CDoc1::canDecrypt(const QSslCertificate &cert) const { if(!ENC_MTH.contains(method) || k.cert != cert || - k.cipher.isEmpty()) + k.cipher.isEmpty() || + k.unsupported) continue; - if(cert.publicKey().algorithm() == QSsl::Rsa && - k.method == RSA_MTH) + if(cert.publicKey().algorithm() == QSsl::Rsa) return k; if(cert.publicKey().algorithm() == QSsl::Ec && - !k.publicKey.isEmpty() && - KWAES_SIZE.contains(k.method) && - k.derive == CONCATKDF_MTH && - k.agreement == AGREEMENT_MTH) + !k.publicKey.isEmpty()) return k; } return {}; @@ -432,8 +424,6 @@ bool CDoc1::save(const QString &path) for(const CKey &k: qAsConst(keys)) { writeElement(w, DENC, QStringLiteral("EncryptedKey"), [&]{ - if(!k.id.isEmpty()) - w.writeAttribute(QStringLiteral("Id"), k.id); if(!k.recipient.isEmpty()) w.writeAttribute(QStringLiteral("Recipient"), k.recipient); QByteArray cipher; @@ -446,8 +436,6 @@ bool CDoc1::save(const QString &path) {QStringLiteral("Algorithm"), RSA_MTH}, }); writeElement(w, DS, QStringLiteral("KeyInfo"), [&]{ - if(!k.name.isEmpty()) - w.writeTextElement(DS, QStringLiteral("KeyName"), k.name); writeElement(w, DS, QStringLiteral("X509Data"), [&]{ writeBase64Element(w, DS, QStringLiteral("X509Certificate"), k.cert.toDer()); }); @@ -464,14 +452,13 @@ bool CDoc1::save(const QString &path) QByteArray oid = Crypto::curve_oid(peerPKey); QByteArray SsDer = Crypto::toPublicKeyDer(priv.get()); - const QString encryptionMethod = KWAES256_MTH; QString concatDigest = SHA384_MTH; switch((SsDer.size() - 1) / 2) { case 32: concatDigest = SHA256_MTH; break; case 48: concatDigest = SHA384_MTH; break; default: concatDigest = SHA512_MTH; break; } - QByteArray encryptionKey = Crypto::concatKDF(SHA_MTH[concatDigest], KWAES_SIZE[encryptionMethod], + QByteArray encryptionKey = Crypto::concatKDF(SHA_MTH[concatDigest], sharedSecret, props.value(QStringLiteral("DocumentFormat")).toUtf8() + SsDer + k.cert.toDer()); #ifndef NDEBUG qDebug() << "ENC Ss" << SsDer.toHex(); @@ -484,7 +471,7 @@ bool CDoc1::save(const QString &path) return; writeElement(w, DENC, QStringLiteral("EncryptionMethod"), { - {QStringLiteral("Algorithm"), encryptionMethod}, + {QStringLiteral("Algorithm"), KWAES256_MTH}, }); writeElement(w, DS, QStringLiteral("KeyInfo"), [&]{ writeElement(w, DENC, QStringLiteral("AgreementMethod"), { @@ -553,7 +540,7 @@ QByteArray CDoc1::transportKey(const CKey &key) if(key.isRSA) return backend->decrypt(key.cipher, false); return backend->deriveConcatKDF(key.publicKey, SHA_MTH[key.concatDigest], - int(KWAES_SIZE[key.method]), key.AlgorithmID, key.PartyUInfo, key.PartyVInfo); + key.AlgorithmID, key.PartyUInfo, key.PartyVInfo); }); if(decryptedKey.isEmpty()) { diff --git a/client/CDoc1.h b/client/CDoc1.h index 82d333c1d..5cf1f46a6 100644 --- a/client/CDoc1.h +++ b/client/CDoc1.h @@ -57,12 +57,10 @@ class CDoc1 final: public CDoc, private QFile static const QString AES128CBC_MTH, AES192CBC_MTH, AES256CBC_MTH, AES128GCM_MTH, AES192GCM_MTH, AES256GCM_MTH, - KWAES128_MTH, KWAES192_MTH, KWAES256_MTH, SHA256_MTH, SHA384_MTH, SHA512_MTH, - RSA_MTH, CONCATKDF_MTH, AGREEMENT_MTH; + RSA_MTH, CONCATKDF_MTH, AGREEMENT_MTH, KWAES256_MTH; static const QString DS, DENC, DSIG11, XENC11; static const QString MIME_ZLIB, MIME_DDOC, MIME_DDOC_OLD; static const QHash ENC_MTH; static const QHash SHA_MTH; - static const QHash KWAES_SIZE; }; diff --git a/client/CDoc2.cpp b/client/CDoc2.cpp index f0645e708..853af318d 100644 --- a/client/CDoc2.cpp +++ b/client/CDoc2.cpp @@ -432,13 +432,15 @@ CDoc2::CDoc2(const QString &path) for(const auto *recipient: *recipients){ if(recipient->fmk_encryption_method() != FMKEncryptionMethod::XOR) { + keys.append(CKey::Unsupported); qWarning() << "Unsupported FMK encryption method: skipping"; continue; } - auto fillRecipient = [&] (auto key, bool isRSA) { + auto fillRecipient = [&] (auto key, bool isRSA, bool unsupported = false) { CKey k(toByteArray(key->recipient_public_key()), isRSA); k.recipient = toString(recipient->key_label()); k.cipher = toByteArray(recipient->encrypted_fmk()); + k.unsupported = unsupported; return k; }; switch(recipient->capsule_type()) @@ -446,12 +448,7 @@ CDoc2::CDoc2(const QString &path) case Capsule::ECCPublicKeyCapsule: if(const auto *key = recipient->capsule_as_ECCPublicKeyCapsule()) { - if(key->curve() != EllipticCurve::secp384r1) - { - qWarning() << "Unsupported ECC curve: skipping"; - continue; - } - CKey k = fillRecipient(key, false); + CKey k = fillRecipient(key, false, key->curve() != EllipticCurve::secp384r1); k.publicKey = toByteArray(key->sender_public_key()); keys.append(std::move(k)); } @@ -467,8 +464,8 @@ CDoc2::CDoc2(const QString &path) case Capsule::KeyServerCapsule: if(const auto *server = recipient->capsule_as_KeyServerCapsule()) { - auto fillKeyServer = [&] (auto key, bool isRSA) { - CKey k = fillRecipient(key, isRSA); + auto fillKeyServer = [&] (auto key, bool isRSA, bool unsupported = false) { + CKey k = fillRecipient(key, isRSA, unsupported); k.keyserver_id = toString(server->keyserver_id()); k.transaction_id = toString(server->transaction_id()); return k; @@ -477,21 +474,20 @@ CDoc2::CDoc2(const QString &path) { case ServerDetailsUnion::ServerEccDetails: if(const auto *eccDetails = server->recipient_key_details_as_ServerEccDetails()) - { - if(eccDetails->curve() == EllipticCurve::secp384r1) - keys.append(fillKeyServer(eccDetails, false)); - } + keys.append(fillKeyServer(eccDetails, false, eccDetails->curve() != EllipticCurve::secp384r1)); break; case ServerDetailsUnion::ServerRsaDetails: if(const auto *rsaDetails = server->recipient_key_details_as_ServerRsaDetails()) keys.append(fillKeyServer(rsaDetails, true)); break; default: + keys.append(CKey::Unsupported); qWarning() << "Unsupported Key Server Details: skipping"; } } break; default: + keys.append(CKey::Unsupported); qWarning() << "Unsupported Key Details: skipping"; } } diff --git a/client/Crypto.cpp b/client/Crypto.cpp index 607e961ec..ac6b2ad73 100644 --- a/client/Crypto.cpp +++ b/client/Crypto.cpp @@ -144,10 +144,11 @@ QByteArray Crypto::cipher(const EVP_CIPHER *cipher, const QByteArray &key, QByte return data; } -QByteArray Crypto::concatKDF(QCryptographicHash::Algorithm hashAlg, quint32 keyDataLen, const QByteArray &z, const QByteArray &otherInfo) +QByteArray Crypto::concatKDF(QCryptographicHash::Algorithm hashAlg, const QByteArray &z, const QByteArray &otherInfo) { if(z.isEmpty()) return z; + quint32 keyDataLen = 32; auto hashLen = quint32(QCryptographicHash::hashLength(hashAlg)); auto reps = quint32(std::ceil(double(keyDataLen) / double(hashLen))); QCryptographicHash md(hashAlg); diff --git a/client/Crypto.h b/client/Crypto.h index 58e8972bd..7ed6d00ca 100644 --- a/client/Crypto.h +++ b/client/Crypto.h @@ -53,8 +53,7 @@ class Crypto static QByteArray aes_wrap(const QByteArray &key, const QByteArray &data, bool encrypt); static QByteArray cipher(const EVP_CIPHER *cipher, const QByteArray &key, QByteArray &data, bool encrypt); static QByteArray curve_oid(EVP_PKEY *key); - static QByteArray concatKDF(QCryptographicHash::Algorithm digestMethod, - quint32 keyDataLen, const QByteArray &z, const QByteArray &otherInfo); + static QByteArray concatKDF(QCryptographicHash::Algorithm digestMethod, const QByteArray &z, const QByteArray &otherInfo); static QByteArray derive(EVP_PKEY *priv, EVP_PKEY *pub); static QByteArray encrypt(EVP_PKEY *pub, int padding, const QByteArray &data); static QByteArray expand(const QByteArray &key, const QByteArray &info, int len = 32); diff --git a/client/CryptoDoc.cpp b/client/CryptoDoc.cpp index 2d04f1f25..442ebf6a8 100644 --- a/client/CryptoDoc.cpp +++ b/client/CryptoDoc.cpp @@ -217,6 +217,10 @@ QString CDocumentModel::save(int row, const QString &path) const return fileName; } +CKey::CKey(Tag) + : unsupported(true) +{} + CKey::CKey(const QSslCertificate &c) { setCert(c); @@ -247,6 +251,7 @@ void CKey::setCert(const QSslCertificate &c) } + CryptoDoc::CryptoDoc( QObject *parent ) : QObject(parent) , d(new Private) diff --git a/client/CryptoDoc.h b/client/CryptoDoc.h index 8929550ed..fc490392e 100644 --- a/client/CryptoDoc.h +++ b/client/CryptoDoc.h @@ -32,7 +32,12 @@ class QSslKey; class CKey { public: + enum Tag + { + Unsupported, + }; CKey() = default; + CKey(Tag); CKey(QByteArray _key, bool _isRSA): key(std::move(_key)), isRSA(_isRSA) {} CKey(const QSslCertificate &cert); bool operator==(const CKey &other) const { return other.key == key; } @@ -41,10 +46,10 @@ class CKey QByteArray key, cipher, publicKey; QSslCertificate cert; - bool isRSA = false; + bool isRSA = false, unsupported = false; QString recipient; // CDoc1 - QString agreement, concatDigest, derive, method, id, name; + QString concatDigest; QByteArray AlgorithmID, PartyUInfo, PartyVInfo; // CDoc2 QByteArray encrypted_kek; diff --git a/client/MainWindow.cpp b/client/MainWindow.cpp index cacd59833..f33acb23f 100644 --- a/client/MainWindow.cpp +++ b/client/MainWindow.cpp @@ -115,17 +115,17 @@ MainWindow::MainWindow( QWidget *parent ) // Refresh ID card info in card widget connect(qApp->signer(), &QSigner::cacheChanged, this, &MainWindow::updateSelector); connect(&QPCSC::instance(), &QPCSC::statusChanged, this, &MainWindow::updateSelector); - connect(qApp->signer(), &QSigner::signDataChanged, this, [=](const TokenData &token){ + connect(qApp->signer(), &QSigner::signDataChanged, this, [this](const TokenData &token) { updateSelectorData(token); updateMyEID(token); ui->signContainerPage->cardChanged(token.cert()); }); - connect(qApp->signer(), &QSigner::authDataChanged, this, [=](const TokenData &token){ + connect(qApp->signer(), &QSigner::authDataChanged, this, [this](const TokenData &token) { updateSelectorData(token); updateMyEID(token); ui->cryptoContainerPage->cardChanged(token.cert()); if(cryptoDoc) - ui->cryptoContainerPage->update(cryptoDoc->canDecrypt(token.cert()), cryptoDoc); + ui->cryptoContainerPage->update(cryptoDoc, token.cert()); }); QPCSC::instance().start(); @@ -143,7 +143,7 @@ MainWindow::MainWindow( QWidget *parent ) connect(ui->signContainerPage, &ContainerPage::addFiles, this, [this](const QStringList &files) { openFiles(files, true); } ); connect(ui->signContainerPage, &ContainerPage::fileRemoved, this, &MainWindow::removeSignatureFile); connect(ui->signContainerPage, &ContainerPage::removed, this, &MainWindow::removeSignature); - connect(ui->signContainerPage, &ContainerPage::warning, this, [this](const WarningText &warningText) { + connect(ui->signContainerPage, &ContainerPage::warning, this, [this](WarningText warningText) { ui->warnings->showWarning(warningText); ui->signature->warningIcon(true); }); @@ -153,6 +153,10 @@ MainWindow::MainWindow( QWidget *parent ) connect(ui->cryptoContainerPage, &ContainerPage::fileRemoved, this, &MainWindow::removeCryptoFile); connect(ui->cryptoContainerPage, &ContainerPage::keysSelected, this, &MainWindow::updateKeys); connect(ui->cryptoContainerPage, &ContainerPage::removed, this, &MainWindow::removeAddress); + connect(ui->cryptoContainerPage, &ContainerPage::warning, this, [this](WarningText warningText) { + ui->warnings->showWarning(warningText); + ui->crypto->warningIcon(true); + }); connect(ui->accordion, &Accordion::changePin1Clicked, this, &MainWindow::changePin1Clicked); connect(ui->accordion, &Accordion::changePin2Clicked, this, &MainWindow::changePin2Clicked); @@ -547,6 +551,10 @@ void MainWindow::onCryptoAction(int action, const QString &/*id*/, const QString cryptoDoc->saveCopy(target); break; } + case ClearCryptoWarning: + ui->crypto->warningIcon(false); + ui->warnings->closeWarnings(CryptoDetails); + break; case ContainerEmail: if( cryptoDoc ) containerToEmail( cryptoDoc->fileName() ); @@ -882,7 +890,7 @@ void MainWindow::removeAddress(int index) if(cryptoDoc) { cryptoDoc->removeKey(index); - ui->cryptoContainerPage->transition(cryptoDoc, qApp->signer()->tokenauth().cert()); + ui->cryptoContainerPage->update(cryptoDoc, qApp->signer()->tokenauth().cert()); } } @@ -1077,7 +1085,7 @@ void MainWindow::updateKeys(const QList &keys) cryptoDoc->removeKey(i); for(const auto &key: keys) cryptoDoc->addKey(key); - ui->cryptoContainerPage->update(cryptoDoc->canDecrypt(qApp->signer()->tokenauth().cert()), cryptoDoc); + ui->cryptoContainerPage->update(cryptoDoc, qApp->signer()->tokenauth().cert()); } void MainWindow::containerSummary() @@ -1094,7 +1102,7 @@ void MainWindow::containerSummary() dialog->printer()->setPageSize( QPageSize( QPageSize::A4 ) ); dialog->printer()->setPageOrientation( QPageLayout::Portrait ); dialog->setMinimumHeight( 700 ); - connect(dialog, &QPrintPreviewDialog::paintRequested, digiDoc, [=](QPrinter *printer){ + connect(dialog, &QPrintPreviewDialog::paintRequested, digiDoc, [this](QPrinter *printer) { PrintSheet(digiDoc, printer); }); dialog->exec(); diff --git a/client/QCNG.cpp b/client/QCNG.cpp index 2e2bb1324..a99d511de 100644 --- a/client/QCNG.cpp +++ b/client/QCNG.cpp @@ -100,7 +100,7 @@ QByteArray QCNG::derive(const QByteArray &publicKey, F &&func) const }); } -QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, int keySize, +QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const { return derive(publicKey, [&](NCRYPT_SECRET_HANDLE sharedSecret, QByteArray &derived) { @@ -126,7 +126,7 @@ QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash return err; derived.resize(int(size)); if(SUCCEEDED(err = NCryptDeriveKey(sharedSecret, BCRYPT_KDF_SP80056A_CONCAT, ¶ms, PBYTE(derived.data()), size, &size, 0))) - derived.resize(keySize); + derived.resize(32); return err; }); } diff --git a/client/QCNG.h b/client/QCNG.h index cf8c86616..279860ab5 100644 --- a/client/QCNG.h +++ b/client/QCNG.h @@ -33,7 +33,7 @@ class QCNG final: public QCryptoBackend QList tokens() const final; QByteArray decrypt(const QByteArray &data, bool oaep) const final; - QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, int keySize, + QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const final; QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const final; PinStatus lastError() const final; diff --git a/client/QCryptoBackend.h b/client/QCryptoBackend.h index 9a7035366..210826b96 100644 --- a/client/QCryptoBackend.h +++ b/client/QCryptoBackend.h @@ -28,7 +28,7 @@ class QCryptoBackend: public QObject { Q_OBJECT public: - enum PinStatus + enum PinStatus : quint8 { PinOK, PinCanceled, @@ -43,7 +43,7 @@ class QCryptoBackend: public QObject virtual QList tokens() const = 0; virtual QByteArray decrypt(const QByteArray &data, bool oaep) const = 0; - virtual QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, int keySize, + virtual QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const = 0; virtual QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const = 0; virtual PinStatus lastError() const { return PinOK; } diff --git a/client/QPKCS11.cpp b/client/QPKCS11.cpp index 709c13eba..b98c3bad2 100644 --- a/client/QPKCS11.cpp +++ b/client/QPKCS11.cpp @@ -140,9 +140,9 @@ QByteArray QPKCS11::derive(const QByteArray &publicKey) const } QByteArray QPKCS11::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, - int keySize, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const + const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const { - return Crypto::concatKDF(digest, quint32(keySize), derive(publicKey), algorithmID + partyUInfo + partyVInfo); + return Crypto::concatKDF(digest, derive(publicKey), algorithmID + partyUInfo + partyVInfo); } QByteArray QPKCS11::deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const diff --git a/client/QPKCS11.h b/client/QPKCS11.h index 300e5299c..468e7e23b 100644 --- a/client/QPKCS11.h +++ b/client/QPKCS11.h @@ -30,7 +30,7 @@ class QPKCS11 final: public QCryptoBackend QByteArray decrypt(const QByteArray &data, bool oaep) const final; QByteArray derive(const QByteArray &publicKey) const; - QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, int keySize, + QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const final; QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const final; bool isLoaded() const; diff --git a/client/common_enums.h b/client/common_enums.h index 69c1b1764..c9529e7cf 100644 --- a/client/common_enums.h +++ b/client/common_enums.h @@ -54,7 +54,8 @@ enum Actions { SignatureMobile, SignatureSmartID, SignatureToken, - ClearSignatureWarning + ClearSignatureWarning, + ClearCryptoWarning, }; enum ItemType { @@ -88,6 +89,7 @@ enum WarningType { UnsupportedAsicSWarning, UnsupportedAsicCadesWarning, UnsupportedDDocWarning, + UnsupportedCDocWarning, EmptyFileWarning, }; diff --git a/client/dialogs/KeyDialog.cpp b/client/dialogs/KeyDialog.cpp index b9b662ca3..1fdac3556 100644 --- a/client/dialogs/KeyDialog.cpp +++ b/client/dialogs/KeyDialog.cpp @@ -64,15 +64,11 @@ KeyDialog::KeyDialog( const CKey &k, QWidget *parent ) }; addItem(tr("Recipient"), k.recipient); - addItem(tr("Crypto method"), k.method); - addItem(tr("Agreement method"), k.agreement); - addItem(tr("Key derivation method"), k.derive); addItem(tr("ConcatKDF digest method"), k.concatDigest); addItem(tr("Key server ID"), k.keyserver_id); addItem(tr("Transaction ID"), k.transaction_id); addItem(tr("Expiry date"), k.cert.expiryDate().toLocalTime().toString(QStringLiteral("dd.MM.yyyy hh:mm:ss"))); addItem(tr("Issuer"), SslCertificate(k.cert).issuerInfo(QSslCertificate::CommonName)); d->view->resizeColumnToContents( 0 ); - if(!k.agreement.isEmpty()) - adjustSize(); + adjustSize(); } diff --git a/client/translations/en.ts b/client/translations/en.ts index da7b73f26..aa26b4f41 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -157,6 +157,10 @@ Expired on Expired on + + Unsupported cryptographic algorithm or recipient type + Unsupported cryptographic algorithm or recipient type + Application @@ -1291,18 +1295,6 @@ SHOW CERTIFICATE SHOW CERTIFICATE - - Crypto method - Crypto method - - - Agreement method - Agreement method - - - Key derivation method - Key derivation method - ConcatKDF digest method ConcatKDF digest method @@ -1338,6 +1330,13 @@ Transaction ID + + LabelItem + + The container must be decrypted in order to see the contents of an encrypted container. + The container must be decrypted in order to see the contents of an encrypted container. + + LdapSearch @@ -3146,5 +3145,13 @@ Additional licenses and components This container contains CAdES signature. You are not allowed to add or remove signatures to this container. This container contains CAdES signature. You are not allowed to add or remove signatures to this container. + + The encrypted container contains a cryptographic algorithm or recipient type that is not supported in this DigiDoc4 application version. Please make sure that you are using the latest DigiDoc4 application version. + The encrypted container contains a cryptographic algorithm or recipient type that is not supported in this DigiDoc4 application version. Please make sure that you are using the latest DigiDoc4 application version. + + + https://www.id.ee/en/article/install-id-software/ + https://www.id.ee/en/article/install-id-software/ + diff --git a/client/translations/et.ts b/client/translations/et.ts index 18c728135..0ffb8974b 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -157,6 +157,10 @@ Expired on Aegus + + Unsupported cryptographic algorithm or recipient type + Mittetoetatud krüptograafiline algoritm või adressaadi tüüp + Application @@ -1291,18 +1295,6 @@ SHOW CERTIFICATE NÄITA SERTIFIKAATI - - Crypto method - Krüpteerimismeetod - - - Agreement method - Aktsepteeritud meetod - - - Key derivation method - Võtme tuletamise meetod - ConcatKDF digest method ConcatKDF referaatmeetod @@ -1338,6 +1330,13 @@ Transaktsiooni identifikaator + + LabelItem + + The container must be decrypted in order to see the contents of an encrypted container. + Krüpteeritud ümbriku sisu nägemiseks tuleb ümbrik dekrüpteerida. + + LdapSearch @@ -3146,5 +3145,13 @@ Täiendavad litsentsid ja komponendid This container contains CAdES signature. You are not allowed to add or remove signatures to this container. Tegemist on CAdES allkirja sisaldava ümbrikuga. Sellele ümbrikule ei saa allkirja lisada ega eemaldada. + + The encrypted container contains a cryptographic algorithm or recipient type that is not supported in this DigiDoc4 application version. Please make sure that you are using the latest DigiDoc4 application version. + Krüpteeritud ümbrik sisaldab DigiDoc4 rakenduse käesolevas versioonis mittetoetatud krüptograafilist algoritmi või adressaadi tüüpi. Palun veendu, et kasutad uusimat DigiDoc4 rakenduse versiooni. + + + https://www.id.ee/en/article/install-id-software/ + https://www.id.ee/artikkel/paigalda-id-tarkvara/ + diff --git a/client/translations/ru.ts b/client/translations/ru.ts index c26df8cde..068d2b5e7 100644 --- a/client/translations/ru.ts +++ b/client/translations/ru.ts @@ -157,6 +157,10 @@ Expired on Истекший + + Unsupported cryptographic algorithm or recipient type + Неподдерживаемый криптографический алгоритм или тип получателя + Application @@ -1291,18 +1295,6 @@ SHOW CERTIFICATE ПОКАЗАТЬ СЕРТИФИКАТ - - Crypto method - Метод шифровки - - - Agreement method - Метод подтверждения - - - Key derivation method - Метод деривации ключа - ConcatKDF digest method Метод подсчета ConcatKDF @@ -1338,6 +1330,13 @@ Идентификатор транзакции + + LabelItem + + The container must be decrypted in order to see the contents of an encrypted container. + Контейнер должен быть расшифрован, чтобы увидеть его зашифрованное содержимое. + + LdapSearch @@ -3151,5 +3150,13 @@ Additional licenses and components This container contains CAdES signature. You are not allowed to add or remove signatures to this container. Этот контейнер содержит подпись CAdES. К данному контейнеру нельзя добавить или удалить из него подпись. + + The encrypted container contains a cryptographic algorithm or recipient type that is not supported in this DigiDoc4 application version. Please make sure that you are using the latest DigiDoc4 application version. + Зашифрованный конверт содержит криптографический алгоритм или тип получателя, не поддерживаемый в текущей версии приложения DigiDoc4. Пожалуйста, убедитесь, что вы используете последнюю версию приложения DigiDoc4. + + + https://www.id.ee/en/article/install-id-software/ + https://www.id.ee/ru/artikkel/ustanovite-id-programmu/ + diff --git a/client/widgets/AddressItem.cpp b/client/widgets/AddressItem.cpp index 4cc51efc8..48794f136 100644 --- a/client/widgets/AddressItem.cpp +++ b/client/widgets/AddressItem.cpp @@ -68,6 +68,8 @@ AddressItem::AddressItem(CKey k, QWidget *parent, bool showIcon) ui->label = ui->key.recipient.toHtmlEscaped(); setIdType(); showButton(AddressItem::Remove); + if(ui->key.unsupported) + ui->idType->setText(tr("Unsupported cryptographic algorithm or recipient type")); } AddressItem::~AddressItem() @@ -135,6 +137,8 @@ void AddressItem::setName() { ui->name->setText(QStringLiteral("%1 %2") .arg(ui->label, ui->yourself ? ui->code + tr(" (Yourself)") : ui->code)); + if(ui->name->text().isEmpty()) + ui->name->hide(); } void AddressItem::showButton(ShowToolButton show) diff --git a/client/widgets/ContainerPage.cpp b/client/widgets/ContainerPage.cpp index f20391814..f5a41b8f8 100644 --- a/client/widgets/ContainerPage.cpp +++ b/client/widgets/ContainerPage.cpp @@ -37,7 +37,6 @@ #include #include #include -#include using namespace ria::qdigidoc4; @@ -290,14 +289,20 @@ void ContainerPage::showSigningButton() void ContainerPage::transition(CryptoDoc *container, const QSslCertificate &cert) { clear(); - isSupported = container && (container->state() & UnencryptedContainer || container->canDecrypt(cert)); - if(!container) - return; + emit action(ClearCryptoWarning); + isSupported = container->state() & UnencryptedContainer || container->canDecrypt(cert); setHeader(container->fileName()); + bool hasUnsupported = false; + ui->rightPane->clear(); for(const CKey &key: container->keys()) + { + hasUnsupported = std::max(hasUnsupported, key.unsupported); ui->rightPane->addWidget(new AddressItem(key, ui->rightPane, true)); - ui->leftPane->setModel(container->documentModel()); + } + if(hasUnsupported) + emit warning({UnsupportedCDocWarning}); updatePanes(container->state()); + ui->leftPane->setModel(container->documentModel()); } void ContainerPage::transition(DigiDoc* container) @@ -358,19 +363,21 @@ void ContainerPage::transition(DigiDoc* container) updatePanes(container->state()); } -void ContainerPage::update(bool canDecrypt, CryptoDoc* container) +void ContainerPage::update(CryptoDoc* container, const QSslCertificate &cert) { - isSupported = canDecrypt || container->state() & UnencryptedContainer; - if(container && container->state() & EncryptedContainer) - updateDecryptionButton(); - - if(!container) - return; - + isSupported = container->canDecrypt(cert) || container->state() & UnencryptedContainer; hasEmptyFile = false; + bool hasUnsupported = false; ui->rightPane->clear(); for(const CKey &key: container->keys()) + { + hasUnsupported = std::max(hasUnsupported, key.unsupported); ui->rightPane->addWidget(new AddressItem(key, ui->rightPane, true)); + } + if(hasUnsupported) + emit warning({UnsupportedCDocWarning}); + if(container->state() & EncryptedContainer) + updateDecryptionButton(); if(container->state() & UnencryptedContainer) showMainAction({ EncryptContainer }); } diff --git a/client/widgets/ContainerPage.h b/client/widgets/ContainerPage.h index f035d2b69..c9370fc47 100644 --- a/client/widgets/ContainerPage.h +++ b/client/widgets/ContainerPage.h @@ -52,7 +52,7 @@ class ContainerPage final : public QWidget void togglePrinting(bool enable); void transition(CryptoDoc *container, const QSslCertificate &cert); void transition(DigiDoc* container); - void update(bool canDecrypt, CryptoDoc *container); + void update(CryptoDoc *container, const QSslCertificate &cert); signals: void action(int code, const QString &info1 = {}, const QString &info2 = {}); diff --git a/client/widgets/FileList.cpp b/client/widgets/FileList.cpp index 0fd246a80..d1068ca55 100644 --- a/client/widgets/FileList.cpp +++ b/client/widgets/FileList.cpp @@ -216,6 +216,9 @@ void FileList::setModel(DocumentModel *documentModel) auto count = documentModel->rowCount(); for(int i = 0; i < count; i++) addFile(documentModel->data(i)); + if(state == EncryptedContainer && count == 0) + addWidget(new LabelItem(QT_TRANSLATE_NOOP("LabelItem", + "The container must be decrypted in order to see the contents of an encrypted container."))); } void FileList::stateChange(ria::qdigidoc4::ContainerState state) @@ -226,7 +229,7 @@ void FileList::stateChange(ria::qdigidoc4::ContainerState state) void FileList::updateDownload() { - int c = findChildren().size(); + auto c = findChildren().size(); ui->download->setVisible(state & (UnsignedSavedContainer | SignedContainer | UnencryptedContainer) && c); ui->count->setVisible(state & (UnsignedSavedContainer | SignedContainer | UnencryptedContainer) && c); ui->count->setText(QString::number(c)); diff --git a/client/widgets/Item.cpp b/client/widgets/Item.cpp index d8d2a83f6..ae85f2655 100644 --- a/client/widgets/Item.cpp +++ b/client/widgets/Item.cpp @@ -19,6 +19,48 @@ #include "Item.h" +#include +#include +#include + void Item::idChanged(const SslCertificate & /* cert */) {} void Item::initTabOrder(QWidget * /* item */) {} QWidget* Item::lastTabWidget() { return this; } + +LabelItem::LabelItem(const char *text, QWidget *parent) + : Item(parent) + , _text(text) +{ + setObjectName(QStringLiteral("LabelItem")); + setStyleSheet(QStringLiteral(R"( +QWidget { +font-family: Roboto, Helvetica; +font-size: 14px; +} +#LabelItem { +border-bottom: 1px solid rgba(217, 217, 216, 0.45); +} +#label { +color: #07142A; +} +)")); + setLayout(new QVBoxLayout); + layout()->setContentsMargins(8, 16, 8, 16); + layout()->addWidget(label = new QLabel(tr(text), this)); + label->setObjectName("label"); + label->setFocusPolicy(Qt::TabFocus); + label->setWordWrap(true); +} + +void LabelItem::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::LanguageChange) + label->setText(tr(_text)); + Item::changeEvent(event); +} + +void LabelItem::initTabOrder(QWidget *item) +{ + setTabOrder(item, label); + setTabOrder(label, lastTabWidget()); +} diff --git a/client/widgets/Item.h b/client/widgets/Item.h index a35d4ce03..3c540e381 100644 --- a/client/widgets/Item.h +++ b/client/widgets/Item.h @@ -21,6 +21,7 @@ #include "widgets/StyledWidget.h" +class QLabel; class SslCertificate; class Item : public StyledWidget @@ -38,3 +39,18 @@ class Item : public StyledWidget void add(Item* item); void remove(Item* item); }; + + +class LabelItem : public Item +{ + Q_OBJECT + +public: + LabelItem(const char *text, QWidget *parent = nullptr); + void initTabOrder(QWidget *item) override; + +private: + void changeEvent(QEvent *event) override; + QLabel *label; + const char *_text; +}; diff --git a/client/widgets/WarningItem.cpp b/client/widgets/WarningItem.cpp index 971a4cf12..09795ba3f 100644 --- a/client/widgets/WarningItem.cpp +++ b/client/widgets/WarningItem.cpp @@ -138,6 +138,12 @@ void WarningItem::lookupWarning() url = tr("https://www.id.ee/en/article/digidoc-container-format-life-cycle-2/"); _page = SignDetails; break; + case UnsupportedCDocWarning: + ui->warningText->setText(tr("The encrypted container contains a cryptographic algorithm or recipient type that is not supported in this DigiDoc4 application version. " + "Please make sure that you are using the latest DigiDoc4 application version.")); + url = tr("https://www.id.ee/en/article/install-id-software/"); + _page = CryptoDetails; + break; case EmptyFileWarning: ui->warningText->setText(tr("An empty file is attached to the container. " "Remove the empty file from the container to sign."));