Skip to content

Commit 2646a7a

Browse files
authored
Show improved AddressItem widget (#1306)
* Icon * Unsupported algorithm or recipient type CDOC-3 Signed-off-by: Raul Metsma <[email protected]> * Update AddressItem UI Signed-off-by: Raul Metsma <[email protected]> * Update to new UI Signed-off-by: Raul Metsma <[email protected]> --------- Signed-off-by: Raul Metsma <[email protected]>
1 parent 86eb82d commit 2646a7a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+547
-477
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: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ namespace cdoc20 {
274274
io->skip(padding(f.size));
275275
if(!readHeader() || h.isNull() || !h.verify())
276276
return {};
277+
if(f.name.startsWith(QLatin1String("./PaxHeaders.X")))
278+
f.name = QString::fromUtf8(h.name.data(), std::min<int>(h.name.size(), int(strlen(h.name.data()))));
277279
f.size = fromOctal(h.size);
278280
for(const QByteArray &data: paxData.split('\n'))
279281
{
@@ -432,26 +434,23 @@ CDoc2::CDoc2(const QString &path)
432434
for(const auto *recipient: *recipients){
433435
if(recipient->fmk_encryption_method() != FMKEncryptionMethod::XOR)
434436
{
437+
keys.append(CKey::Unsupported);
435438
qWarning() << "Unsupported FMK encryption method: skipping";
436439
continue;
437440
}
438-
auto fillRecipient = [&] (auto key, bool isRSA) {
441+
auto fillRecipient = [&] (auto key, bool isRSA, bool unsupported = false) {
439442
CKey k(toByteArray(key->recipient_public_key()), isRSA);
440443
k.recipient = toString(recipient->key_label());
441444
k.cipher = toByteArray(recipient->encrypted_fmk());
445+
k.unsupported = unsupported;
442446
return k;
443447
};
444448
switch(recipient->capsule_type())
445449
{
446450
case Capsule::ECCPublicKeyCapsule:
447451
if(const auto *key = recipient->capsule_as_ECCPublicKeyCapsule())
448452
{
449-
if(key->curve() != EllipticCurve::secp384r1)
450-
{
451-
qWarning() << "Unsupported ECC curve: skipping";
452-
continue;
453-
}
454-
CKey k = fillRecipient(key, false);
453+
CKey k = fillRecipient(key, false, key->curve() != EllipticCurve::secp384r1);
455454
k.publicKey = toByteArray(key->sender_public_key());
456455
keys.append(std::move(k));
457456
}
@@ -467,8 +466,8 @@ CDoc2::CDoc2(const QString &path)
467466
case Capsule::KeyServerCapsule:
468467
if(const auto *server = recipient->capsule_as_KeyServerCapsule())
469468
{
470-
auto fillKeyServer = [&] (auto key, bool isRSA) {
471-
CKey k = fillRecipient(key, isRSA);
469+
auto fillKeyServer = [&] (auto key, bool isRSA, bool unsupported = false) {
470+
CKey k = fillRecipient(key, isRSA, unsupported);
472471
k.keyserver_id = toString(server->keyserver_id());
473472
k.transaction_id = toString(server->transaction_id());
474473
return k;
@@ -477,29 +476,31 @@ CDoc2::CDoc2(const QString &path)
477476
{
478477
case ServerDetailsUnion::ServerEccDetails:
479478
if(const auto *eccDetails = server->recipient_key_details_as_ServerEccDetails())
480-
{
481-
if(eccDetails->curve() == EllipticCurve::secp384r1)
482-
keys.append(fillKeyServer(eccDetails, false));
483-
}
479+
keys.append(fillKeyServer(eccDetails, false, eccDetails->curve() != EllipticCurve::secp384r1));
484480
break;
485481
case ServerDetailsUnion::ServerRsaDetails:
486482
if(const auto *rsaDetails = server->recipient_key_details_as_ServerRsaDetails())
487483
keys.append(fillKeyServer(rsaDetails, true));
488484
break;
489485
default:
486+
keys.append(CKey::Unsupported);
490487
qWarning() << "Unsupported Key Server Details: skipping";
491488
}
492489
}
493490
break;
494491
default:
492+
keys.append(CKey::Unsupported);
495493
qWarning() << "Unsupported Key Details: skipping";
496494
}
497495
}
498496
}
499497

500498
CKey CDoc2::canDecrypt(const QSslCertificate &cert) const
501499
{
502-
return keys.value(keys.indexOf(CKey(cert)));
500+
auto key = keys.value(keys.indexOf(CKey(cert)));
501+
if(key.unsupported || (!key.transaction_id.isEmpty() && cert.expiryDate() <= QDateTime::currentDateTimeUtc()))
502+
return {};
503+
return key;
503504
}
504505

505506
bool CDoc2::decryptPayload(const QByteArray &fmk)
@@ -562,6 +563,7 @@ bool CDoc2::save(const QString &path)
562563
if(!cdoc20::checkConnection())
563564
return false;
564565
QScopedPointer<QNetworkAccessManager,QScopedPointerDeleteLater> nam(CheckConnection::setupNAM(req, Settings::CDOC2_POST_CERT));
566+
req.setRawHeader("x-expiry-time", QDateTime::currentDateTimeUtc().addMonths(6).toString(Qt::ISODate).toLatin1());
565567
QEventLoop e;
566568
QNetworkReply *reply = nam->post(req, QJsonDocument({
567569
{QLatin1String("recipient_id"), QLatin1String(recipient_id.toBase64())},
@@ -602,7 +604,7 @@ bool CDoc2::save(const QString &path)
602604
toVector(key.key), toVector(encrytpedKek));
603605
recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder,
604606
cdoc20::Recipients::Capsule::RSAPublicKeyCapsule, rsaPublicKey.Union(),
605-
toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
607+
toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
606608
continue;
607609
}
608610

@@ -614,7 +616,7 @@ bool CDoc2::save(const QString &path)
614616
rsaKeyServer.Union(), toString(key.keyserver_id), toString(key.transaction_id));
615617
recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder,
616618
cdoc20::Recipients::Capsule::KeyServerCapsule, keyServer.Union(),
617-
toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
619+
toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
618620
continue;
619621
}
620622

@@ -642,7 +644,7 @@ bool CDoc2::save(const QString &path)
642644
cdoc20::Recipients::EllipticCurve::secp384r1, toVector(key.key), toVector(ephPublicKeyDer));
643645
recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder,
644646
cdoc20::Recipients::Capsule::ECCPublicKeyCapsule, eccPublicKey.Union(),
645-
toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
647+
toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
646648
continue;
647649
}
648650

@@ -655,7 +657,7 @@ bool CDoc2::save(const QString &path)
655657
eccKeyServer.Union(), toString(key.keyserver_id), toString(key.transaction_id));
656658
recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder,
657659
cdoc20::Recipients::Capsule::KeyServerCapsule, keyServer.Union(),
658-
toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
660+
toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR));
659661
}
660662

661663
auto offset = cdoc20::Header::CreateHeader(builder, builder.CreateVector(recipients),

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: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <QtCore/QRegularExpression>
3939
#include <QtCore/QThread>
4040
#include <QtCore/QUrl>
41+
#include <QtCore/QUrlQuery>
4142
#include <QtGui/QDesktopServices>
4243
#include <QtNetwork/QSslKey>
4344
#include <QtWidgets/QMessageBox>
@@ -217,6 +218,10 @@ QString CDocumentModel::save(int row, const QString &path) const
217218
return fileName;
218219
}
219220

221+
CKey::CKey(Tag)
222+
: unsupported(true)
223+
{}
224+
220225
CKey::CKey(const QSslCertificate &c)
221226
{
222227
setCert(c);
@@ -246,6 +251,61 @@ void CKey::setCert(const QSslCertificate &c)
246251
isRSA = k.algorithm() == QSsl::Rsa;
247252
}
248253

254+
QHash<QString, QString> CKey::fromKeyLabel() const
255+
{
256+
QHash<QString,QString> result;
257+
if(!recipient.startsWith(QLatin1String("data:"), Qt::CaseInsensitive))
258+
return result;
259+
QString payload = recipient.mid(5);
260+
QString mimeType;
261+
QString encoding;
262+
if(auto pos = payload.indexOf(','); pos != -1)
263+
{
264+
mimeType = payload.left(pos);
265+
payload = payload.mid(pos + 1);
266+
if(auto header = mimeType.split(';'); header.size() == 2)
267+
{
268+
mimeType = header.value(0);
269+
encoding = header.value(1);
270+
}
271+
}
272+
if(!mimeType.isEmpty() && mimeType != QLatin1String("application/x-www-form-urlencoded"))
273+
return result;
274+
if(encoding == QLatin1String("base64"))
275+
payload = QByteArray::fromBase64(payload.toLatin1());
276+
;
277+
for(const auto &[key,value]: QUrlQuery(payload).queryItems(QUrl::FullyDecoded))
278+
result[key.toLower()] = value;
279+
if(!result.contains(QStringLiteral("type")) || !result.contains(QStringLiteral("v")))
280+
result.clear();
281+
return result;
282+
}
283+
284+
QString CKey::toKeyLabel() const
285+
{
286+
if(cert.isNull())
287+
return recipient;
288+
QDateTime exp = cert.expiryDate();
289+
if(Settings::CDOC2_USE_KEYSERVER)
290+
exp = std::min(exp, QDateTime::currentDateTimeUtc().addMonths(6));
291+
auto escape = [](QString data) { return data.replace(',', QLatin1String("%2C")); };
292+
QString type = QStringLiteral("ID-card");
293+
if(auto t = SslCertificate(cert).type(); t & SslCertificate::EResidentSubType)
294+
type = QStringLiteral("Digi-ID E-RESIDENT");
295+
else if(t & SslCertificate::DigiIDType)
296+
type = QStringLiteral("Digi-ID");
297+
QUrlQuery q;
298+
q.setQueryItems({
299+
{QStringLiteral("v"), QString::number(1)},
300+
{QStringLiteral("type"), type},
301+
{QStringLiteral("serial_number"), escape(cert.subjectInfo("serialNumber").join(','))},
302+
{QStringLiteral("cn"), escape(cert.subjectInfo("CN").join(','))},
303+
{QStringLiteral("server_exp"), QString::number(exp.toSecsSinceEpoch())},
304+
});
305+
return "data:" + q.query(QUrl::FullyEncoded);
306+
}
307+
308+
249309

250310
CryptoDoc::CryptoDoc( QObject *parent )
251311
: QObject(parent)

0 commit comments

Comments
 (0)