Skip to content

Commit cf47a56

Browse files
committed
Unsupported algorithm or recipient type
CDOC-3 Signed-off-by: Raul Metsma <[email protected]>
1 parent 67e6996 commit cf47a56

25 files changed

+217
-120
lines changed

client/CDoc1.cpp

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ const QString CDoc1::AES128GCM_MTH = QStringLiteral("http://www.w3.org/2009/xmle
4141
const QString CDoc1::AES192GCM_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#aes192-gcm");
4242
const QString CDoc1::AES256GCM_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#aes256-gcm");
4343
const QString CDoc1::RSA_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#rsa-1_5");
44-
const QString CDoc1::KWAES128_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#kw-aes128");
45-
const QString CDoc1::KWAES192_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#kw-aes192");
4644
const QString CDoc1::KWAES256_MTH = QStringLiteral("http://www.w3.org/2001/04/xmlenc#kw-aes256");
4745
const QString CDoc1::CONCATKDF_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#ConcatKDF");
4846
const QString CDoc1::AGREEMENT_MTH = QStringLiteral("http://www.w3.org/2009/xmlenc11#ECDH-ES");
@@ -66,7 +64,6 @@ const QHash<QString, const EVP_CIPHER*> CDoc1::ENC_MTH{
6664
const QHash<QString, QCryptographicHash::Algorithm> CDoc1::SHA_MTH{
6765
{SHA256_MTH, QCryptographicHash::Sha256}, {SHA384_MTH, QCryptographicHash::Sha384}, {SHA512_MTH, QCryptographicHash::Sha512}
6866
};
69-
const QHash<QString, quint32> CDoc1::KWAES_SIZE{{KWAES128_MTH, 16}, {KWAES192_MTH, 24}, {KWAES256_MTH, 32}};
7067

7168
CDoc1::CDoc1(const QString &path)
7269
: QFile(path)
@@ -108,7 +105,6 @@ CDoc1::CDoc1(const QString &path)
108105
return;
109106

110107
CKey key;
111-
key.id = xml.attributes().value(QLatin1String("Id")).toString();
112108
key.recipient = xml.attributes().value(QLatin1String("Recipient")).toString();
113109
while(!xml.atEnd())
114110
{
@@ -117,18 +113,17 @@ CDoc1::CDoc1(const QString &path)
117113
break;
118114
if(!xml.isStartElement())
119115
continue;
120-
// EncryptedData/KeyInfo/KeyName
121-
if(xml.name() == QLatin1String("KeyName"))
122-
key.name = xml.readElementText();
123-
// EncryptedData/KeyInfo/EncryptedKey/EncryptionMethod
124-
else if(xml.name() == QLatin1String("EncryptionMethod"))
125-
key.method = xml.attributes().value(QLatin1String("Algorithm")).toString();
116+
if(xml.name() == QLatin1String("EncryptionMethod"))
117+
{
118+
auto method = xml.attributes().value(QLatin1String("Algorithm"));
119+
key.unsupported = std::max(key.unsupported, method != KWAES256_MTH && method != RSA_MTH);
120+
}
126121
// EncryptedData/KeyInfo/EncryptedKey/KeyInfo/AgreementMethod
127122
else if(xml.name() == QLatin1String("AgreementMethod"))
128-
key.agreement = xml.attributes().value(QLatin1String("Algorithm")).toString();
123+
key.unsupported = std::max(key.unsupported, xml.attributes().value(QLatin1String("Algorithm")) != AGREEMENT_MTH);
129124
// EncryptedData/KeyInfo/EncryptedKey/KeyInfo/AgreementMethod/KeyDerivationMethod
130125
else if(xml.name() == QLatin1String("KeyDerivationMethod"))
131-
key.derive = xml.attributes().value(QLatin1String("Algorithm")).toString();
126+
key.unsupported = std::max(key.unsupported, xml.attributes().value(QLatin1String("Algorithm")) != CONCATKDF_MTH);
132127
// EncryptedData/KeyInfo/EncryptedKey/KeyInfo/AgreementMethod/KeyDerivationMethod/ConcatKDFParams
133128
else if(xml.name() == QLatin1String("ConcatKDFParams"))
134129
{
@@ -273,16 +268,13 @@ CKey CDoc1::canDecrypt(const QSslCertificate &cert) const
273268
{
274269
if(!ENC_MTH.contains(method) ||
275270
k.cert != cert ||
276-
k.cipher.isEmpty())
271+
k.cipher.isEmpty() ||
272+
k.unsupported)
277273
continue;
278-
if(cert.publicKey().algorithm() == QSsl::Rsa &&
279-
k.method == RSA_MTH)
274+
if(cert.publicKey().algorithm() == QSsl::Rsa)
280275
return k;
281276
if(cert.publicKey().algorithm() == QSsl::Ec &&
282-
!k.publicKey.isEmpty() &&
283-
KWAES_SIZE.contains(k.method) &&
284-
k.derive == CONCATKDF_MTH &&
285-
k.agreement == AGREEMENT_MTH)
277+
!k.publicKey.isEmpty())
286278
return k;
287279
}
288280
return {};
@@ -432,8 +424,6 @@ bool CDoc1::save(const QString &path)
432424
for(const CKey &k: qAsConst(keys))
433425
{
434426
writeElement(w, DENC, QStringLiteral("EncryptedKey"), [&]{
435-
if(!k.id.isEmpty())
436-
w.writeAttribute(QStringLiteral("Id"), k.id);
437427
if(!k.recipient.isEmpty())
438428
w.writeAttribute(QStringLiteral("Recipient"), k.recipient);
439429
QByteArray cipher;
@@ -446,8 +436,6 @@ bool CDoc1::save(const QString &path)
446436
{QStringLiteral("Algorithm"), RSA_MTH},
447437
});
448438
writeElement(w, DS, QStringLiteral("KeyInfo"), [&]{
449-
if(!k.name.isEmpty())
450-
w.writeTextElement(DS, QStringLiteral("KeyName"), k.name);
451439
writeElement(w, DS, QStringLiteral("X509Data"), [&]{
452440
writeBase64Element(w, DS, QStringLiteral("X509Certificate"), k.cert.toDer());
453441
});
@@ -464,14 +452,13 @@ bool CDoc1::save(const QString &path)
464452
QByteArray oid = Crypto::curve_oid(peerPKey);
465453
QByteArray SsDer = Crypto::toPublicKeyDer(priv.get());
466454

467-
const QString encryptionMethod = KWAES256_MTH;
468455
QString concatDigest = SHA384_MTH;
469456
switch((SsDer.size() - 1) / 2) {
470457
case 32: concatDigest = SHA256_MTH; break;
471458
case 48: concatDigest = SHA384_MTH; break;
472459
default: concatDigest = SHA512_MTH; break;
473460
}
474-
QByteArray encryptionKey = Crypto::concatKDF(SHA_MTH[concatDigest], KWAES_SIZE[encryptionMethod],
461+
QByteArray encryptionKey = Crypto::concatKDF(SHA_MTH[concatDigest],
475462
sharedSecret, props.value(QStringLiteral("DocumentFormat")).toUtf8() + SsDer + k.cert.toDer());
476463
#ifndef NDEBUG
477464
qDebug() << "ENC Ss" << SsDer.toHex();
@@ -484,7 +471,7 @@ bool CDoc1::save(const QString &path)
484471
return;
485472

486473
writeElement(w, DENC, QStringLiteral("EncryptionMethod"), {
487-
{QStringLiteral("Algorithm"), encryptionMethod},
474+
{QStringLiteral("Algorithm"), KWAES256_MTH},
488475
});
489476
writeElement(w, DS, QStringLiteral("KeyInfo"), [&]{
490477
writeElement(w, DENC, QStringLiteral("AgreementMethod"), {
@@ -553,7 +540,7 @@ QByteArray CDoc1::transportKey(const CKey &key)
553540
if(key.isRSA)
554541
return backend->decrypt(key.cipher, false);
555542
return backend->deriveConcatKDF(key.publicKey, SHA_MTH[key.concatDigest],
556-
int(KWAES_SIZE[key.method]), key.AlgorithmID, key.PartyUInfo, key.PartyVInfo);
543+
key.AlgorithmID, key.PartyUInfo, key.PartyVInfo);
557544
});
558545
if(decryptedKey.isEmpty())
559546
{

client/CDoc1.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,10 @@ class CDoc1 final: public CDoc, private QFile
5757
static const QString
5858
AES128CBC_MTH, AES192CBC_MTH, AES256CBC_MTH,
5959
AES128GCM_MTH, AES192GCM_MTH, AES256GCM_MTH,
60-
KWAES128_MTH, KWAES192_MTH, KWAES256_MTH,
6160
SHA256_MTH, SHA384_MTH, SHA512_MTH,
62-
RSA_MTH, CONCATKDF_MTH, AGREEMENT_MTH;
61+
RSA_MTH, CONCATKDF_MTH, AGREEMENT_MTH, KWAES256_MTH;
6362
static const QString DS, DENC, DSIG11, XENC11;
6463
static const QString MIME_ZLIB, MIME_DDOC, MIME_DDOC_OLD;
6564
static const QHash<QString, const EVP_CIPHER*> ENC_MTH;
6665
static const QHash<QString, QCryptographicHash::Algorithm> SHA_MTH;
67-
static const QHash<QString, quint32> KWAES_SIZE;
6866
};

client/CDoc2.cpp

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -432,26 +432,23 @@ CDoc2::CDoc2(const QString &path)
432432
for(const auto *recipient: *recipients){
433433
if(recipient->fmk_encryption_method() != FMKEncryptionMethod::XOR)
434434
{
435+
keys.append(CKey::Unsupported);
435436
qWarning() << "Unsupported FMK encryption method: skipping";
436437
continue;
437438
}
438-
auto fillRecipient = [&] (auto key, bool isRSA) {
439+
auto fillRecipient = [&] (auto key, bool isRSA, bool unsupported = false) {
439440
CKey k(toByteArray(key->recipient_public_key()), isRSA);
440441
k.recipient = toString(recipient->key_label());
441442
k.cipher = toByteArray(recipient->encrypted_fmk());
443+
k.unsupported = unsupported;
442444
return k;
443445
};
444446
switch(recipient->capsule_type())
445447
{
446448
case Capsule::ECCPublicKeyCapsule:
447449
if(const auto *key = recipient->capsule_as_ECCPublicKeyCapsule())
448450
{
449-
if(key->curve() != EllipticCurve::secp384r1)
450-
{
451-
qWarning() << "Unsupported ECC curve: skipping";
452-
continue;
453-
}
454-
CKey k = fillRecipient(key, false);
451+
CKey k = fillRecipient(key, false, key->curve() != EllipticCurve::secp384r1);
455452
k.publicKey = toByteArray(key->sender_public_key());
456453
keys.append(std::move(k));
457454
}
@@ -467,8 +464,8 @@ CDoc2::CDoc2(const QString &path)
467464
case Capsule::KeyServerCapsule:
468465
if(const auto *server = recipient->capsule_as_KeyServerCapsule())
469466
{
470-
auto fillKeyServer = [&] (auto key, bool isRSA) {
471-
CKey k = fillRecipient(key, isRSA);
467+
auto fillKeyServer = [&] (auto key, bool isRSA, bool unsupported = false) {
468+
CKey k = fillRecipient(key, isRSA, unsupported);
472469
k.keyserver_id = toString(server->keyserver_id());
473470
k.transaction_id = toString(server->transaction_id());
474471
return k;
@@ -477,21 +474,20 @@ CDoc2::CDoc2(const QString &path)
477474
{
478475
case ServerDetailsUnion::ServerEccDetails:
479476
if(const auto *eccDetails = server->recipient_key_details_as_ServerEccDetails())
480-
{
481-
if(eccDetails->curve() == EllipticCurve::secp384r1)
482-
keys.append(fillKeyServer(eccDetails, false));
483-
}
477+
keys.append(fillKeyServer(eccDetails, false, eccDetails->curve() != EllipticCurve::secp384r1));
484478
break;
485479
case ServerDetailsUnion::ServerRsaDetails:
486480
if(const auto *rsaDetails = server->recipient_key_details_as_ServerRsaDetails())
487481
keys.append(fillKeyServer(rsaDetails, true));
488482
break;
489483
default:
484+
keys.append(CKey::Unsupported);
490485
qWarning() << "Unsupported Key Server Details: skipping";
491486
}
492487
}
493488
break;
494489
default:
490+
keys.append(CKey::Unsupported);
495491
qWarning() << "Unsupported Key Details: skipping";
496492
}
497493
}

client/Crypto.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,11 @@ QByteArray Crypto::cipher(const EVP_CIPHER *cipher, const QByteArray &key, QByte
144144
return data;
145145
}
146146

147-
QByteArray Crypto::concatKDF(QCryptographicHash::Algorithm hashAlg, quint32 keyDataLen, const QByteArray &z, const QByteArray &otherInfo)
147+
QByteArray Crypto::concatKDF(QCryptographicHash::Algorithm hashAlg, const QByteArray &z, const QByteArray &otherInfo)
148148
{
149149
if(z.isEmpty())
150150
return z;
151+
quint32 keyDataLen = 32;
151152
auto hashLen = quint32(QCryptographicHash::hashLength(hashAlg));
152153
auto reps = quint32(std::ceil(double(keyDataLen) / double(hashLen)));
153154
QCryptographicHash md(hashAlg);

client/Crypto.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ class Crypto
5353
static QByteArray aes_wrap(const QByteArray &key, const QByteArray &data, bool encrypt);
5454
static QByteArray cipher(const EVP_CIPHER *cipher, const QByteArray &key, QByteArray &data, bool encrypt);
5555
static QByteArray curve_oid(EVP_PKEY *key);
56-
static QByteArray concatKDF(QCryptographicHash::Algorithm digestMethod,
57-
quint32 keyDataLen, const QByteArray &z, const QByteArray &otherInfo);
56+
static QByteArray concatKDF(QCryptographicHash::Algorithm digestMethod, const QByteArray &z, const QByteArray &otherInfo);
5857
static QByteArray derive(EVP_PKEY *priv, EVP_PKEY *pub);
5958
static QByteArray encrypt(EVP_PKEY *pub, int padding, const QByteArray &data);
6059
static QByteArray expand(const QByteArray &key, const QByteArray &info, int len = 32);

client/CryptoDoc.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,10 @@ QString CDocumentModel::save(int row, const QString &path) const
217217
return fileName;
218218
}
219219

220+
CKey::CKey(Tag)
221+
: unsupported(true)
222+
{}
223+
220224
CKey::CKey(const QSslCertificate &c)
221225
{
222226
setCert(c);
@@ -247,6 +251,7 @@ void CKey::setCert(const QSslCertificate &c)
247251
}
248252

249253

254+
250255
CryptoDoc::CryptoDoc( QObject *parent )
251256
: QObject(parent)
252257
, d(new Private)

client/CryptoDoc.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,12 @@ class QSslKey;
3232
class CKey
3333
{
3434
public:
35+
enum Tag
36+
{
37+
Unsupported,
38+
};
3539
CKey() = default;
40+
CKey(Tag);
3641
CKey(QByteArray _key, bool _isRSA): key(std::move(_key)), isRSA(_isRSA) {}
3742
CKey(const QSslCertificate &cert);
3843
bool operator==(const CKey &other) const { return other.key == key; }
@@ -41,10 +46,10 @@ class CKey
4146

4247
QByteArray key, cipher, publicKey;
4348
QSslCertificate cert;
44-
bool isRSA = false;
49+
bool isRSA = false, unsupported = false;
4550
QString recipient;
4651
// CDoc1
47-
QString agreement, concatDigest, derive, method, id, name;
52+
QString concatDigest;
4853
QByteArray AlgorithmID, PartyUInfo, PartyVInfo;
4954
// CDoc2
5055
QByteArray encrypted_kek;

client/MainWindow.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,17 @@ MainWindow::MainWindow( QWidget *parent )
115115
// Refresh ID card info in card widget
116116
connect(qApp->signer(), &QSigner::cacheChanged, this, &MainWindow::updateSelector);
117117
connect(&QPCSC::instance(), &QPCSC::statusChanged, this, &MainWindow::updateSelector);
118-
connect(qApp->signer(), &QSigner::signDataChanged, this, [=](const TokenData &token){
118+
connect(qApp->signer(), &QSigner::signDataChanged, this, [this](const TokenData &token) {
119119
updateSelectorData(token);
120120
updateMyEID(token);
121121
ui->signContainerPage->cardChanged(token.cert());
122122
});
123-
connect(qApp->signer(), &QSigner::authDataChanged, this, [=](const TokenData &token){
123+
connect(qApp->signer(), &QSigner::authDataChanged, this, [this](const TokenData &token) {
124124
updateSelectorData(token);
125125
updateMyEID(token);
126126
ui->cryptoContainerPage->cardChanged(token.cert());
127127
if(cryptoDoc)
128-
ui->cryptoContainerPage->update(cryptoDoc->canDecrypt(token.cert()), cryptoDoc);
128+
ui->cryptoContainerPage->update(cryptoDoc, token.cert());
129129
});
130130
QPCSC::instance().start();
131131

@@ -143,7 +143,7 @@ MainWindow::MainWindow( QWidget *parent )
143143
connect(ui->signContainerPage, &ContainerPage::addFiles, this, [this](const QStringList &files) { openFiles(files, true); } );
144144
connect(ui->signContainerPage, &ContainerPage::fileRemoved, this, &MainWindow::removeSignatureFile);
145145
connect(ui->signContainerPage, &ContainerPage::removed, this, &MainWindow::removeSignature);
146-
connect(ui->signContainerPage, &ContainerPage::warning, this, [this](const WarningText &warningText) {
146+
connect(ui->signContainerPage, &ContainerPage::warning, this, [this](WarningText warningText) {
147147
ui->warnings->showWarning(warningText);
148148
ui->signature->warningIcon(true);
149149
});
@@ -153,6 +153,10 @@ MainWindow::MainWindow( QWidget *parent )
153153
connect(ui->cryptoContainerPage, &ContainerPage::fileRemoved, this, &MainWindow::removeCryptoFile);
154154
connect(ui->cryptoContainerPage, &ContainerPage::keysSelected, this, &MainWindow::updateKeys);
155155
connect(ui->cryptoContainerPage, &ContainerPage::removed, this, &MainWindow::removeAddress);
156+
connect(ui->cryptoContainerPage, &ContainerPage::warning, this, [this](WarningText warningText) {
157+
ui->warnings->showWarning(warningText);
158+
ui->crypto->warningIcon(true);
159+
});
156160

157161
connect(ui->accordion, &Accordion::changePin1Clicked, this, &MainWindow::changePin1Clicked);
158162
connect(ui->accordion, &Accordion::changePin2Clicked, this, &MainWindow::changePin2Clicked);
@@ -547,6 +551,10 @@ void MainWindow::onCryptoAction(int action, const QString &/*id*/, const QString
547551
cryptoDoc->saveCopy(target);
548552
break;
549553
}
554+
case ClearCryptoWarning:
555+
ui->crypto->warningIcon(false);
556+
ui->warnings->closeWarnings(CryptoDetails);
557+
break;
550558
case ContainerEmail:
551559
if( cryptoDoc )
552560
containerToEmail( cryptoDoc->fileName() );
@@ -682,6 +690,7 @@ void MainWindow::openContainer(bool signature)
682690

683691
void MainWindow::resetCryptoDoc(CryptoDoc *doc)
684692
{
693+
ui->crypto->warningIcon(false);
685694
ui->cryptoContainerPage->clear();
686695
delete cryptoDoc;
687696
cryptoDoc = doc;
@@ -882,7 +891,7 @@ void MainWindow::removeAddress(int index)
882891
if(cryptoDoc)
883892
{
884893
cryptoDoc->removeKey(index);
885-
ui->cryptoContainerPage->transition(cryptoDoc, qApp->signer()->tokenauth().cert());
894+
ui->cryptoContainerPage->update(cryptoDoc, qApp->signer()->tokenauth().cert());
886895
}
887896
}
888897

@@ -1077,7 +1086,7 @@ void MainWindow::updateKeys(const QList<CKey> &keys)
10771086
cryptoDoc->removeKey(i);
10781087
for(const auto &key: keys)
10791088
cryptoDoc->addKey(key);
1080-
ui->cryptoContainerPage->update(cryptoDoc->canDecrypt(qApp->signer()->tokenauth().cert()), cryptoDoc);
1089+
ui->cryptoContainerPage->update(cryptoDoc, qApp->signer()->tokenauth().cert());
10811090
}
10821091

10831092
void MainWindow::containerSummary()
@@ -1094,7 +1103,7 @@ void MainWindow::containerSummary()
10941103
dialog->printer()->setPageSize( QPageSize( QPageSize::A4 ) );
10951104
dialog->printer()->setPageOrientation( QPageLayout::Portrait );
10961105
dialog->setMinimumHeight( 700 );
1097-
connect(dialog, &QPrintPreviewDialog::paintRequested, digiDoc, [=](QPrinter *printer){
1106+
connect(dialog, &QPrintPreviewDialog::paintRequested, digiDoc, [this](QPrinter *printer) {
10981107
PrintSheet(digiDoc, printer);
10991108
});
11001109
dialog->exec();

client/QCNG.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ QByteArray QCNG::derive(const QByteArray &publicKey, F &&func) const
100100
});
101101
}
102102

103-
QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, int keySize,
103+
QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest,
104104
const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const
105105
{
106106
return derive(publicKey, [&](NCRYPT_SECRET_HANDLE sharedSecret, QByteArray &derived) {
@@ -126,7 +126,7 @@ QByteArray QCNG::deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash
126126
return err;
127127
derived.resize(int(size));
128128
if(SUCCEEDED(err = NCryptDeriveKey(sharedSecret, BCRYPT_KDF_SP80056A_CONCAT, &params, PBYTE(derived.data()), size, &size, 0)))
129-
derived.resize(keySize);
129+
derived.resize(32);
130130
return err;
131131
});
132132
}

client/QCNG.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class QCNG final: public QCryptoBackend
3333

3434
QList<TokenData> tokens() const final;
3535
QByteArray decrypt(const QByteArray &data, bool oaep) const final;
36-
QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest, int keySize,
36+
QByteArray deriveConcatKDF(const QByteArray &publicKey, QCryptographicHash::Algorithm digest,
3737
const QByteArray &algorithmID, const QByteArray &partyUInfo, const QByteArray &partyVInfo) const final;
3838
QByteArray deriveHMACExtract(const QByteArray &publicKey, const QByteArray &salt, int keySize) const final;
3939
PinStatus lastError() const final;

0 commit comments

Comments
 (0)