Skip to content

Commit

Permalink
Unsupported algorithm or recipient type
Browse files Browse the repository at this point in the history
CDOC-3

Signed-off-by: Raul Metsma <raul@metsma.ee>
  • Loading branch information
metsma committed Dec 2, 2024
1 parent e2b6cfd commit 23da6ba
Show file tree
Hide file tree
Showing 25 changed files with 216 additions and 120 deletions.
41 changes: 14 additions & 27 deletions client/CDoc1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -66,7 +64,6 @@ const QHash<QString, const EVP_CIPHER*> CDoc1::ENC_MTH{
const QHash<QString, QCryptographicHash::Algorithm> CDoc1::SHA_MTH{
{SHA256_MTH, QCryptographicHash::Sha256}, {SHA384_MTH, QCryptographicHash::Sha384}, {SHA512_MTH, QCryptographicHash::Sha512}
};
const QHash<QString, quint32> CDoc1::KWAES_SIZE{{KWAES128_MTH, 16}, {KWAES192_MTH, 24}, {KWAES256_MTH, 32}};

CDoc1::CDoc1(const QString &path)
: QFile(path)
Expand Down Expand Up @@ -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())
{
Expand All @@ -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"))
{
Expand Down Expand Up @@ -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 {};
Expand Down Expand Up @@ -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;
Expand All @@ -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());
});
Expand All @@ -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();
Expand All @@ -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"), {
Expand Down Expand Up @@ -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())
{
Expand Down
4 changes: 1 addition & 3 deletions client/CDoc1.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<QString, const EVP_CIPHER*> ENC_MTH;
static const QHash<QString, QCryptographicHash::Algorithm> SHA_MTH;
static const QHash<QString, quint32> KWAES_SIZE;
};
22 changes: 9 additions & 13 deletions client/CDoc2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,26 +432,23 @@ 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())
{
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));
}
Expand All @@ -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;
Expand All @@ -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";
}
}
Expand Down
3 changes: 2 additions & 1 deletion client/Crypto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 1 addition & 2 deletions client/Crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions client/CryptoDoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -247,6 +251,7 @@ void CKey::setCert(const QSslCertificate &c)
}



CryptoDoc::CryptoDoc( QObject *parent )
: QObject(parent)
, d(new Private)
Expand Down
9 changes: 7 additions & 2 deletions client/CryptoDoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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;
Expand Down
22 changes: 15 additions & 7 deletions client/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
});
Expand All @@ -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);
Expand Down Expand Up @@ -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() );
Expand Down Expand Up @@ -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());
}
}

Expand Down Expand Up @@ -1077,7 +1085,7 @@ void MainWindow::updateKeys(const QList<CKey> &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()
Expand All @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions client/QCNG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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, &params, PBYTE(derived.data()), size, &size, 0)))
derived.resize(keySize);
derived.resize(32);
return err;
});
}
Expand Down
2 changes: 1 addition & 1 deletion client/QCNG.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class QCNG final: public QCryptoBackend

QList<TokenData> 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;
Expand Down
4 changes: 2 additions & 2 deletions client/QCryptoBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class QCryptoBackend: public QObject
{
Q_OBJECT
public:
enum PinStatus
enum PinStatus : quint8
{
PinOK,
PinCanceled,
Expand All @@ -43,7 +43,7 @@ class QCryptoBackend: public QObject

virtual QList<TokenData> 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; }
Expand Down
Loading

0 comments on commit 23da6ba

Please sign in to comment.