From ee847f140f37518aa52a96b8c2aca7a272ea285f Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Thu, 13 Feb 2025 11:44:54 +0200 Subject: [PATCH] Add ECC signature support to central configuration IB-8381 Signed-off-by: Raul Metsma --- CMakeLists.txt | 14 ++++++------ Configuration.cpp | 56 +++++++++++++++++++---------------------------- 2 files changed, 30 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d2c3d71..920a2da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,19 +35,19 @@ if( CONFIG_URL ) set_source_files_properties(Configuration.cpp PROPERTIES COMPILE_DEFINITIONS LAST_CHECK_DAYS=${LAST_CHECK_DAYS}) endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/config.json AND - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/config.rsa AND - EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/config.pub) + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/config.ecc AND + EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/config.ecpub) set(CONFIG_DIR ${CMAKE_CURRENT_SOURCE_DIR}) else() file(DOWNLOAD ${CONFIG_URL} ${CMAKE_CURRENT_BINARY_DIR}/config.json) - string(REPLACE ".json" ".rsa" RSA_URL ${CONFIG_URL} ) - file(DOWNLOAD ${RSA_URL} ${CMAKE_CURRENT_BINARY_DIR}/config.rsa) - string(REPLACE ".json" ".pub" PUB_URL ${CONFIG_URL} ) - file(DOWNLOAD ${PUB_URL} ${CMAKE_CURRENT_BINARY_DIR}/config.pub) + string(REPLACE ".json" ".ecc" ECC_URL ${CONFIG_URL}) + file(DOWNLOAD ${ECC_URL} ${CMAKE_CURRENT_BINARY_DIR}/config.ecc) + string(REPLACE ".json" ".ecpub" PUB_URL ${CONFIG_URL}) + file(DOWNLOAD ${PUB_URL} ${CMAKE_CURRENT_BINARY_DIR}/config.ecpub) set(CONFIG_DIR ${CMAKE_CURRENT_BINARY_DIR}) endif() qt_add_resources(qdigidoccommon config BASE ${CONFIG_DIR} PREFIX / FILES - ${CONFIG_DIR}/config.json ${CONFIG_DIR}/config.rsa ${CONFIG_DIR}/config.pub + ${CONFIG_DIR}/config.json ${CONFIG_DIR}/config.ecc ${CONFIG_DIR}/config.ecpub ) target_compile_definitions(qdigidoccommon PUBLIC CONFIG_URL="${CONFIG_URL}") target_sources(qdigidoccommon PRIVATE Configuration.cpp) diff --git a/Configuration.cpp b/Configuration.cpp index 5ab8ec7..1855724 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -21,20 +21,19 @@ #include "Common.h" #include -#include #include #include #include #include #include #include +#include #include #include -#include #include #include -#include #include +#include #include #include @@ -76,7 +75,7 @@ class Configuration::Private #endif QByteArray data, signature; QJsonObject dataobject; - QUrl rsaurl, url = QUrl(QStringLiteral(CONFIG_URL)); + QUrl eccurl, url = QUrl(QStringLiteral(CONFIG_URL)); std::unique_ptr> publicKey; QNetworkRequest req; QNetworkAccessManager *net = nullptr; @@ -100,10 +99,10 @@ void Configuration::Private::initCache(bool clear) return f.open(QFile::ReadOnly) ? f.readAll() : QByteArray(); }; setData(readAll(url, QStringLiteral(":/config.json")), - readAll(rsaurl, QStringLiteral(":/config.rsa"))); + readAll(eccurl, QStringLiteral(":/config.ecc"))); #else setData(readFile(QStringLiteral(":/config.json")), - readFile(QStringLiteral(":/config.rsa"))); + readFile(QStringLiteral(":/config.ecc"))); #endif } @@ -135,30 +134,21 @@ bool Configuration::Private::validate(const QByteArray &data, const QByteArray & return false; QByteArray sig = QByteArray::fromBase64(signature); - size_t size = 0; - auto ctx = std::unique_ptr>(EVP_PKEY_CTX_new(publicKey.get(), nullptr)); - if(!ctx || EVP_PKEY_verify_recover_init(ctx.get()) < 1 || - EVP_PKEY_verify_recover(ctx.get(), nullptr, &size, - (const unsigned char*)sig.constData(), size_t(sig.size())) < 1) - return false; - QByteArray digest(qsizetype(size), '\0'); - if(EVP_PKEY_verify_recover(ctx.get(), (unsigned char*)digest.data(), &size, - (const unsigned char*)sig.constData(), size_t(sig.size())) < 1) + const EVP_MD *md = [&]{ + switch(EVP_PKEY_bits(publicKey.get())) + { + case SHA256_DIGEST_LENGTH * 8: return EVP_sha256(); + case SHA384_DIGEST_LENGTH * 8: return EVP_sha384(); + default: return EVP_sha512(); + } + }(); + if(std::unique_ptr> ctx(EVP_MD_CTX_new()); + !ctx || + EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, publicKey.get()) < 1 || + EVP_DigestVerify(ctx.get(), (const unsigned char*)sig.constData(), size_t(sig.size()), + (const unsigned char*)data.constData(), size_t(data.size())) < 1) return false; - digest.resize(qsizetype(size)); - using item = std::pair; - static const std::array list { - item{QCryptographicHash::Sha1, QByteArray::fromHex("3021300906052b0e03021a05000414")}, - item{QCryptographicHash::Sha224, QByteArray::fromHex("302d300d06096086480165030402040500041c")}, - item{QCryptographicHash::Sha256, QByteArray::fromHex("3031300d060960864801650304020105000420")}, - item{QCryptographicHash::Sha384, QByteArray::fromHex("3041300d060960864801650304020205000430")}, - item{QCryptographicHash::Sha512, QByteArray::fromHex("3051300d060960864801650304020305000440")}, - }; - if(std::none_of(list.cbegin(), list.cend(), [&](const auto &item) { - return digest == item.second + QCryptographicHash::hash(data, item.first); - })) - return false; QString date = headerValue(toObject(data), QLatin1String("DATE")).toString(); return QDateTime::currentDateTimeUtc() > QDateTime::fromString(date, QStringLiteral("yyyyMMddHHmmss'Z'")); } @@ -172,7 +162,7 @@ Configuration::Configuration(QObject *parent) #ifndef NO_CACHE QDir().mkpath(d->cache); #endif - d->rsaurl = QStringLiteral("%1%2.rsa").arg( + d->eccurl = QStringLiteral("%1%2.ecc").arg( d->url.adjusted(QUrl::RemoveFilename).toString(), QFileInfo(d->url.fileName()).baseName()); d->req.setRawHeader("User-Agent", QStringLiteral("%1/%2 (%3) Lang: %4 Devices: %5") @@ -191,7 +181,7 @@ Configuration::Configuration(QObject *parent) Q_EMIT finished(false, reply->errorString()); return; } - if(reply->url() == d->rsaurl) + if(reply->url() == d->eccurl) { QByteArray signature = reply->readAll(); if(d->validate(d->data, signature)) @@ -234,7 +224,7 @@ Configuration::Configuration(QObject *parent) f.write(data); }; writeAll(d->url.fileName(), d->data); - writeAll(d->rsaurl.fileName(), d->signature); + writeAll(d->eccurl.fileName(), d->signature); #endif #ifdef LAST_CHECK_DAYS d->s.setValue(QStringLiteral("LastCheck"), QDate::currentDate().toString(QStringLiteral("yyyyMMdd"))); @@ -243,7 +233,7 @@ Configuration::Configuration(QObject *parent) } }); - QByteArray key = readFile(QStringLiteral(":/config.pub")); + QByteArray key = readFile(QStringLiteral(":/config.ecpub")); BIO *bio = BIO_new_mem_buf(key.constData(), int(key.size())); if(!bio) { @@ -303,7 +293,7 @@ QJsonObject Configuration::object() const void Configuration::update(bool force) { d->initCache(force); - d->req.setUrl(d->rsaurl); + d->req.setUrl(d->eccurl); d->net->get(d->req); QSettings().setValue(QStringLiteral("LastVersion"), QCoreApplication::applicationVersion()); }