From c252cbfa59fb662e5e259678ca6e225eee6b889a Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Wed, 18 Jan 2023 14:59:11 +0200 Subject: [PATCH] Add option to modify TSA Pinning certificate (#1133) IB-7392 Signed-off-by: Raul Metsma Signed-off-by: Raul Metsma --- .github/workflows/build.yml | 2 + CMakeLists.txt | 2 +- client/Application.cpp | 162 +++--- client/dialogs/SettingsDialog.cpp | 96 ++-- client/dialogs/SettingsDialog.h | 5 + client/dialogs/SettingsDialog.ui | 789 +++++++++++++++++------------- client/translations/en.ts | 8 + client/translations/et.ts | 8 + client/translations/ru.ts | 8 + 9 files changed, 609 insertions(+), 471 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 315d77847..393fb6f2f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,8 @@ jobs: path: libdigidocpp-pkg repo: open-eid/libdigidocpp - name: Install dependencies + env: + HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: YES run: | brew install ninja HASH=($(shasum prepare_osx_build_environment.sh)) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6c2fac2e..6d3b3e7c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ include( GNUInstallDirs ) include( VersionInfo ) find_package( PKCS11 ) -find_package(LibDigiDocpp 3.14.11 REQUIRED) +find_package(LibDigiDocpp 3.15.0 REQUIRED) find_package( LDAP REQUIRED ) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) find_package(Qt${QT_VERSION_MAJOR} 5.12.0 REQUIRED COMPONENTS Core Widgets Network PrintSupport Svg LinguistTools) diff --git a/client/Application.cpp b/client/Application.cpp index 47e779f2b..95b5d8df0 100644 --- a/client/Application.cpp +++ b/client/Application.cpp @@ -118,42 +118,26 @@ class DigidocConf final: public digidoc::XmlConfCurrent std::string proxyHost() const final { - switch(s.value(QStringLiteral("ProxyConfig")).toUInt()) - { - case 0: return {}; - case 1: return systemProxy().hostName().toStdString(); - default: return s.value(QStringLiteral("ProxyHost"), QString::fromStdString(digidoc::XmlConfCurrent::proxyHost()) ).toString().toStdString(); - } + return proxyConf(&QNetworkProxy::hostName, + QStringLiteral("ProxyHost"), [this] { return digidoc::XmlConfCurrent::proxyHost(); }); } std::string proxyPort() const final { - switch(s.value(QStringLiteral("ProxyConfig")).toUInt()) - { - case 0: return {}; - case 1: return QString::number(systemProxy().port()).toStdString(); - default: return s.value(QStringLiteral("ProxyPort"), QString::fromStdString(digidoc::XmlConfCurrent::proxyPort()) ).toString().toStdString(); - } + return proxyConf([](const QNetworkProxy &systemProxy) { return QString::number(systemProxy.port()); }, + QStringLiteral("ProxyPort"), [this] { return digidoc::XmlConfCurrent::proxyPort(); }); } std::string proxyUser() const final { - switch(s.value(QStringLiteral("ProxyConfig")).toUInt()) - { - case 0: return {}; - case 1: return systemProxy().user().toStdString(); - default: return s.value(QStringLiteral("ProxyUser"), QString::fromStdString(digidoc::XmlConfCurrent::proxyUser()) ).toString().toStdString(); - } + return proxyConf(&QNetworkProxy::user, + QStringLiteral("ProxyUser"), [this] { return digidoc::XmlConfCurrent::proxyUser(); }); } std::string proxyPass() const final { - switch(s.value(QStringLiteral("ProxyConfig")).toUInt()) - { - case 0: return {}; - case 1: return systemProxy().password().toStdString(); - default: return s.value(QStringLiteral("ProxyPass"), QString::fromStdString(digidoc::XmlConfCurrent::proxyPass())).toString().toStdString(); - } + return proxyConf(&QNetworkProxy::password, + QStringLiteral("ProxyPass"), [this] { return digidoc::XmlConfCurrent::proxyPass(); }); } #ifdef Q_OS_MAC @@ -167,13 +151,13 @@ class DigidocConf final: public digidoc::XmlConfCurrent { return s.value(QStringLiteral("TSLOnlineDigest"), digidoc::XmlConfCurrent::TSLOnlineDigest()).toBool(); } void setProxyHost( const std::string &host ) final - { SettingsDialog::setValueEx(QStringLiteral("ProxyHost"), QString::fromStdString( host )); } + { SettingsDialog::setValueEx(QStringLiteral("ProxyHost"), fromStdString(host)); } void setProxyPort( const std::string &port ) final - { SettingsDialog::setValueEx(QStringLiteral("ProxyPort"), QString::fromStdString( port )); } + { SettingsDialog::setValueEx(QStringLiteral("ProxyPort"), fromStdString(port)); } void setProxyUser( const std::string &user ) final - { SettingsDialog::setValueEx(QStringLiteral("ProxyUser"), QString::fromStdString( user )); } + { SettingsDialog::setValueEx(QStringLiteral("ProxyUser"), fromStdString(user)); } void setProxyPass( const std::string &pass ) final - { SettingsDialog::setValueEx(QStringLiteral("ProxyPass"), QString::fromStdString( pass )); } + { SettingsDialog::setValueEx(QStringLiteral("ProxyPass"), fromStdString(pass)); } void setProxyTunnelSSL( bool enable ) final { SettingsDialog::setValueEx(QStringLiteral("ProxyTunnelSSL"), enable, digidoc::XmlConfCurrent::proxyTunnelSSL()); } void setPKCS12Cert( const std::string & /*cert*/) final {} @@ -184,6 +168,14 @@ class DigidocConf final: public digidoc::XmlConfCurrent { SettingsDialog::setValueEx(QStringLiteral("TSLOnlineDigest"), enable, digidoc::XmlConfCurrent::TSLOnlineDigest()); } #endif + std::vector TSCerts() const final + { + std::vector list = toCerts(QStringLiteral("CERT-BUNDLE")); + if(digidoc::X509Cert cert = toCert(fromBase64(s.value(QStringLiteral("TSA-CERT"))))) + list.push_back(cert); + return list; + } + std::string TSUrl() const final { if(s.value(QStringLiteral("TSA-URL-CUSTOM"), s.contains(QStringLiteral("TSA-URL"))).toBool()) @@ -191,36 +183,27 @@ class DigidocConf final: public digidoc::XmlConfCurrent return valueSystemScope(QStringLiteral("TSA-URL"), digidoc::XmlConfCurrent::TSUrl()); } void setTSUrl(const std::string &url) final - { SettingsDialog::setValueEx(QStringLiteral("TSA-URL"), QString::fromStdString(url)); } + { SettingsDialog::setValueEx(QStringLiteral("TSA-URL"), fromStdString(url)); } std::string TSLUrl() const final { return valueSystemScope(QStringLiteral("TSL-URL"), digidoc::XmlConfCurrent::TSLUrl()); } std::vector TSLCerts() const final { - std::vector tslcerts; - for(const QJsonValue &val: obj.value(QStringLiteral("TSL-CERTS")).toArray()) - { - QByteArray cert = QByteArray::fromBase64(val.toString().toLatin1()); - tslcerts.emplace_back((const unsigned char*)cert.constData(), size_t(cert.size())); - } + std::vector tslcerts = toCerts(QStringLiteral("TSL-CERTS")); return tslcerts.empty() ? digidoc::XmlConfCurrent::TSLCerts() : tslcerts; } digidoc::X509Cert verifyServiceCert() const final { - QByteArray cert = QByteArray::fromBase64(obj.value(QStringLiteral("SIVA-CERT")).toString().toLatin1()); + QByteArray cert = fromBase64(obj.value(QStringLiteral("SIVA-CERT"))); if(cert.isEmpty()) return digidoc::XmlConfCurrent::verifyServiceCert(); - return digidoc::X509Cert((const unsigned char*)cert.constData(), size_t(cert.size())); + return toCert(cert); } std::vector verifyServiceCerts() const final { - std::vector list; - list.push_back(verifyServiceCert()); - for(const QJsonValue &cert: obj.value(QStringLiteral("CERT-BUNDLE")).toArray()) - { - QByteArray der = QByteArray::fromBase64(cert.toString().toLatin1()); - list.emplace_back((const unsigned char*)der.constData(), size_t(der.size())); - } + std::vector list = toCerts(QStringLiteral("CERT-BUNDLE")); + if(digidoc::X509Cert cert = verifyServiceCert()) + list.push_back(cert); return list; } std::string verifyServiceUri() const final @@ -240,7 +223,7 @@ class DigidocConf final: public digidoc::XmlConfCurrent if(issuer == i.key().toStdString()) return i.value().toString().toStdString(); } - return obj.value(QStringLiteral("OCSP-URL")).toString(QString::fromStdString(digidoc::XmlConfCurrent::ocsp(issuer))).toStdString(); + return obj.value(QStringLiteral("OCSP-URL")).toString(fromStdString(digidoc::XmlConfCurrent::ocsp(issuer))).toStdString(); } bool TSLAllowExpired() const final @@ -267,36 +250,67 @@ class DigidocConf final: public digidoc::XmlConfCurrent if(s.value(QStringLiteral("TSA-URL")) == obj.value(QStringLiteral("TSA-URL"))) s.remove(QStringLiteral("TSA-URL")); // Cleanup user conf if it is default url QList list; - for(const QJsonValue &cert: obj.value(QStringLiteral("CERT-BUNDLE")).toArray()) - list.append(QSslCertificate(QByteArray::fromBase64(cert.toString().toLatin1()), QSsl::Der)); + for(const auto &cert: obj.value(QStringLiteral("CERT-BUNDLE")).toArray()) + list.append(QSslCertificate(fromBase64(cert), QSsl::Der)); QSslConfiguration ssl = QSslConfiguration::defaultConfiguration(); ssl.setCaCertificates(list); QSslConfiguration::setDefaultConfiguration(ssl); } #endif - QNetworkProxy systemProxy() const + std::string valueSystemScope(const QString &key, const std::string &defaultValue) const { - for(const QNetworkProxy &proxy: QNetworkProxyFactory::systemProxyForQuery()) + return obj.value(key).toString(fromStdString(defaultValue)).toStdString(); + } + + std::string valueUserScope(const QString &key, const std::string &defaultValue) const + { + return s.value(key, obj.value(key).toString(fromStdString(defaultValue))).toString().toStdString(); + } + + template + std::string proxyConf(System &&system, const QString &key, Config &&config) const + { + switch(s.value(QStringLiteral("ProxyConfig")).toUInt()) { - if(proxy.type() == QNetworkProxy::HttpProxy) - return proxy; + case 0: return {}; + case 1: return std::invoke(system, [] { + for(const QNetworkProxy &proxy: QNetworkProxyFactory::systemProxyForQuery()) + { + if(proxy.type() == QNetworkProxy::HttpProxy) + return proxy; + } + return QNetworkProxy{}; + }()).toStdString(); + default: return s.contains(key) ? s.value(key).toString().toStdString() : config(); } - return {}; } - std::string valueSystemScope(const QString &key, const std::string &defaultValue) const + template + static QByteArray fromBase64(const T &data) { - return obj.value(key).toString(QString::fromStdString(defaultValue)).toStdString(); + return QByteArray::fromBase64(data.toString().toLatin1()); } - std::string valueUserScope(const QString &key, const std::string &defaultValue) const + static digidoc::X509Cert toCert(const QByteArray &der) { - return s.value(key, obj.value(key).toString(QString::fromStdString(defaultValue))).toString().toStdString(); + return digidoc::X509Cert((const unsigned char*)der.constData(), size_t(der.size())); } + std::vector toCerts(const QString &key) const + { + std::vector certs; + for(const auto &cert: obj.value(key).toArray()) + { + QByteArray der = fromBase64(cert); + certs.emplace_back((const unsigned char*)der.constData(), size_t(der.size())); + } + return certs; + } + + static constexpr auto fromStdString = &QString::fromStdString; QSettings s; - bool debug = false; + bool debug = false; public: QJsonObject obj; }; @@ -588,7 +602,7 @@ void Application::closeWindow() #endif if( QDialog *d = qobject_cast(activeWindow()) ) d->reject(); - else if( QWidget *w = qobject_cast(activeWindow()) ) + else if(QWidget *w = activeWindow()) w->close(); } @@ -621,8 +635,7 @@ QVariant Application::confValue( ConfParameter parameter, const QVariant &value QList list; for(const digidoc::X509Cert &cert: i->TSLCerts()) { - std::vector v = cert; - if(!v.empty()) + if(std::vector v = cert; !v.empty()) list.append(QSslCertificate(QByteArray::fromRawData((const char*)v.data(), int(v.size())), QSsl::Der)); } return QVariant::fromValue(list); @@ -694,11 +707,11 @@ void Application::mailTo( const QUrl &url ) QString filePath = QDir::toNativeSeparators( file ); QString fileName = QFileInfo( file ).fileName(); QString subject = q.queryItemValue( "subject", QUrl::FullyDecoded ); - MapiFileDescW doc = {}; + MapiFileDescW doc {}; doc.nPosition = -1; doc.lpszPathName = PWSTR(filePath.utf16()); doc.lpszFileName = PWSTR(fileName.utf16()); - MapiMessageW message = {}; + MapiMessageW message {}; message.lpszSubject = PWSTR(subject.utf16()); message.lpszNoteText = PWSTR(L""); message.nFileCount = 1; @@ -712,29 +725,6 @@ void Application::mailTo( const QUrl &url ) default: break; } } - else if( LPMAPISENDMAIL mapi = LPMAPISENDMAIL(lib.resolve("MAPISendMail")) ) - { - QByteArray filePath = QDir::toNativeSeparators( file ).toLocal8Bit(); - QByteArray fileName = QFileInfo( file ).fileName().toLocal8Bit(); - QByteArray subject = q.queryItemValue( "subject", QUrl::FullyDecoded ).toLocal8Bit(); - MapiFileDesc doc = {}; - doc.nPosition = -1; - doc.lpszPathName = LPSTR(filePath.constData()); - doc.lpszFileName = LPSTR(fileName.constData()); - MapiMessage message = {}; - message.lpszSubject = LPSTR(subject.constData()); - message.lpszNoteText = LPSTR(""); - message.nFileCount = 1; - message.lpFiles = lpMapiFileDesc(&doc); - switch( mapi( NULL, 0, &message, MAPI_LOGON_UI|MAPI_DIALOG, 0 ) ) - { - case SUCCESS_SUCCESS: - case MAPI_E_USER_ABORT: - case MAPI_E_LOGIN_FAILURE: - return; - default: break; - } - } #elif defined(Q_OS_UNIX) QByteArray thunderbird; QProcess p; @@ -1081,7 +1071,7 @@ void Application::showSettings() void Application::showClient(const QStringList ¶ms, bool crypto, bool sign, bool newWindow) { if(sign) - sign = !(params.size() == 1 && CONTAINER_EXT.contains(QFileInfo(params.value(0)).suffix(), Qt::CaseInsensitive)); + sign = params.size() != 1 || !CONTAINER_EXT.contains(QFileInfo(params.value(0)).suffix(), Qt::CaseInsensitive); QWidget *w = nullptr; if(!newWindow && params.isEmpty()) { diff --git a/client/dialogs/SettingsDialog.cpp b/client/dialogs/SettingsDialog.cpp index 7ea88a463..48efd4562 100644 --- a/client/dialogs/SettingsDialog.cpp +++ b/client/dialogs/SettingsDialog.cpp @@ -17,7 +17,6 @@ * */ - #include "SettingsDialog.h" #include "ui_SettingsDialog.h" @@ -123,6 +122,14 @@ SettingsDialog::SettingsDialog(QWidget *parent) ui->rdTimeStampDefault->setFont(regularFont); ui->rdTimeStampCustom->setFont(regularFont); ui->txtTimeStamp->setFont(regularFont); + ui->lblTSACert->setFont(regularFont); + ui->txtTSACert->setFont(regularFont); + ui->btInstallTSACert->setFont(condensed12); + ui->btShowTSACert->setFont(condensed12); +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) + ui->btInstallTSACert->setStyleSheet("background-color: #d3d3d3"); + ui->btShowTSACert->setStyleSheet("background-color: #d3d3d3"); +#endif ui->lblMID->setFont(headerFont); ui->rdMIDUUIDDefault->setFont(regularFont); ui->rdMIDUUIDCustom->setFont(regularFont); @@ -133,11 +140,11 @@ SettingsDialog::SettingsDialog(QWidget *parent) // pageValidation ui->lblSiVa->setFont(headerFont); - ui->lblSiVaCert->setFont(regularFont); ui->txtSiVa->setFont(regularFont); - ui->txtSiVaCert->setFont(regularFont); ui->rdSiVaDefault->setFont(regularFont); ui->rdSiVaCustom->setFont(regularFont); + ui->lblSiVaCert->setFont(regularFont); + ui->txtSiVaCert->setFont(regularFont); ui->btInstallSiVaCert->setFont(condensed12); ui->btShowSiVaCert->setFont(condensed12); #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) @@ -229,7 +236,6 @@ SettingsDialog::SettingsDialog(QWidget *parent) QFile::copy(":/TSL/" + file, target); QFile::setPermissions(target, QFile::Permissions(0x6444)); } - } }); connect( ui->btnNavUseByDefault, &QPushButton::clicked, this, &SettingsDialog::useDefaultSettings ); @@ -267,7 +273,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) ui->pageGroup->setId(ui->btnMenuProxy, NetworkSettings); ui->pageGroup->setId(ui->btnMenuDiagnostics, DiagnosticsSettings); ui->pageGroup->setId(ui->btnMenuInfo, LicenseSettings); - connect(ui->pageGroup, QOverload::of(&QButtonGroup::buttonClicked), this, &SettingsDialog::changePage); + connect(ui->pageGroup, qOverload(&QButtonGroup::buttonClicked), this, &SettingsDialog::changePage); initFunctionality(); updateVersion(); @@ -289,7 +295,7 @@ SettingsDialog::~SettingsDialog() QString SettingsDialog::certInfo(const SslCertificate &c) { return tr("Issued to: %1
Valid to: %2 %3").arg( - c.subjectInfo(QSslCertificate::CommonName), + CertificateDetails::decodeCN(c.subjectInfo(QSslCertificate::CommonName)), c.expiryDate().toString(QStringLiteral("dd.MM.yyyy")), !c.isValid() ? QStringLiteral("(%1)").arg(tr("expired")) : QString()); } @@ -302,7 +308,7 @@ void SettingsDialog::checkConnection() if(!connection.check(QStringLiteral("https://id.eesti.ee/config.json"))) { Application::restoreOverrideCursor(); - FadeInNotification* notification = new FadeInNotification(this, + FadeInNotification* notification = new FadeInNotification(this, ria::qdigidoc4::colors::MOJO, ria::qdigidoc4::colors::MARZIPAN, 0, 120); QString error; QString details = connection.errorDetails(); @@ -315,7 +321,7 @@ void SettingsDialog::checkConnection() else { Application::restoreOverrideCursor(); - FadeInNotification* notification = new FadeInNotification(this, + FadeInNotification* notification = new FadeInNotification(this, ria::qdigidoc4::colors::WHITE, ria::qdigidoc4::colors::MANTIS, 0, 120); notification->start(tr("The connection to certificate status service is successful!"), 750, 3000, 1200); } @@ -338,7 +344,7 @@ void SettingsDialog::initFunctionality() // pageGeneral selectLanguage(); - connect(ui->langGroup, QOverload::of(&QButtonGroup::buttonClicked), this, + connect(ui->langGroup, qOverload(&QButtonGroup::buttonClicked), this, [this](QAbstractButton *button){ retranslate(button->property("lang").toString()); }); ui->chkGeneralTslRefresh->setChecked(qApp->confValue(Application::TSLOnlineDigest).toBool()); @@ -417,22 +423,38 @@ void SettingsDialog::initFunctionality() }); // pageServices - TimeStamp - connect(ui->rdTimeStampCustom, &QRadioButton::toggled, ui->txtTimeStamp, [=](bool checked) { + connect(ui->rdTimeStampCustom, &QRadioButton::toggled, ui->txtTimeStamp, [this](bool checked) { ui->txtTimeStamp->setEnabled(checked); + ui->wgtTSACert->setVisible(checked); setValueEx(QStringLiteral("TSA-URL-CUSTOM"), checked, QSettings().contains(QStringLiteral("TSA-URL"))); }); ui->rdTimeStampCustom->setChecked(s.value(QStringLiteral("TSA-URL-CUSTOM"), s.contains(QStringLiteral("TSA-URL"))).toBool()); + ui->wgtTSACert->setVisible(ui->rdTimeStampCustom->isChecked()); #ifdef CONFIG_URL ui->txtTimeStamp->setPlaceholderText(qApp->conf()->object().value(QStringLiteral("TSA-URL")).toString()); #endif QString TSA_URL = s.value(QStringLiteral("TSA-URL"), qApp->confValue(Application::TSAUrl)).toString(); ui->txtTimeStamp->setText(ui->txtTimeStamp->placeholderText() == TSA_URL ? QString() : TSA_URL); - connect(ui->txtTimeStamp, &QLineEdit::textChanged, this, [](const QString &url) { + connect(ui->txtTimeStamp, &QLineEdit::textChanged, this, [this](const QString &url) { qApp->setConfValue(Application::TSAUrl, url); + if(url.isEmpty()) + { + QSettings().remove(QStringLiteral("TSA-CERT")); + updateTSACert(QSslCertificate()); + } }); connect(ui->helpTimeStamp, &QToolButton::clicked, this, []{ QDesktopServices::openUrl(tr("https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/")); }); + connect(ui->btInstallTSACert, &QPushButton::clicked, this, [this] { + QSslCertificate cert = selectCert(tr("Select Time-Stamping server certificate"), + QStringLiteral("%1 (*.crt *.cer *.pem)").arg(tr("Time-Stamping service SSL certificate"))); + if(cert.isNull()) + return; + QSettings().setValue(QStringLiteral("TSA-CERT"), cert.toDer().toBase64()); + updateTSACert(cert); + }); + updateTSACert(QSslCertificate(QByteArray::fromBase64(s.value(QStringLiteral("TSA-CERT")).toByteArray()), QSsl::Der)); // pageServices - MID connect(ui->rdMIDUUIDCustom, &QRadioButton::toggled, ui->txtMIDUUID, [=](bool checked) { @@ -475,16 +497,8 @@ void SettingsDialog::initFunctionality() QDesktopServices::openUrl(tr("https://www.id.ee/en/article/configuring-the-siva-validation-service-in-the-digidoc4-client/")); }); connect(ui->btInstallSiVaCert, &QPushButton::clicked, this, [this] { - QFile file(FileDialog::getOpenFileName(this, tr("Select SiVa server certificate"), {}, - QStringLiteral("%1 (*.crt *.cer *.pem)")).arg(tr("Digital Signature Validation Service SiVa SSL certificate"))); - if(!file.open(QFile::ReadOnly)) - return; - QSslCertificate cert(&file, QSsl::Pem); - if(cert.isNull()) - { - file.seek(0); - cert = QSslCertificate(&file, QSsl::Der); - } + QSslCertificate cert = selectCert(tr("Select SiVa server certificate"), + QStringLiteral("%1 (*.crt *.cer *.pem)").arg(tr("Digital Signature Validation Service SiVa SSL certificate"))); if(cert.isNull()) return; QSettings().setValue(QStringLiteral("SIVA-CERT"), cert.toDer().toBase64()); @@ -531,19 +545,41 @@ void SettingsDialog::updateCert() ui->btShowCertificate->setDisabled(c.isNull()); } -void SettingsDialog::updateSiVaCert(const QSslCertificate &c) +void SettingsDialog::updateCert(const QSslCertificate &c, QPushButton *btn, CertLabel *lbl) { - disconnect(ui->btShowSiVaCert, &QPushButton::clicked, nullptr, nullptr); - ui->btShowSiVaCert->setHidden(c.isNull()); - ui->txtSiVaCert->setHidden(c.isNull()); + disconnect(btn, &QPushButton::clicked, nullptr, nullptr); + btn->setHidden(c.isNull()); + lbl->setHidden(c.isNull()); if(c.isNull()) return; - ui->txtSiVaCert->setCert(c); - connect(ui->btShowSiVaCert, &QPushButton::clicked, this, [this, c] { + lbl->setCert(c); + connect(btn, &QPushButton::clicked, this, [this, c] { CertificateDetails::showCertificate(c, this); }); } +void SettingsDialog::updateSiVaCert(const QSslCertificate &c) +{ + updateCert(c, ui->btShowSiVaCert, ui->txtSiVaCert); +} + +void SettingsDialog::updateTSACert(const QSslCertificate &c) +{ + updateCert(c, ui->btShowTSACert, ui->txtTSACert); +} + +QSslCertificate SettingsDialog::selectCert(const QString &label, const QString &format) +{ + QFile file(FileDialog::getOpenFileName(this, label, {}, format)); + if(!file.open(QFile::ReadOnly)) + return QSslCertificate(); + QSslCertificate cert(&file, QSsl::Pem); + if(!cert.isNull()) + return cert; + file.seek(0); + return QSslCertificate(&file, QSsl::Der); +} + void SettingsDialog::selectLanguage() { const QList list = ui->langGroup->buttons(); @@ -646,16 +682,12 @@ void SettingsDialog::installCert() { QFile file(FileDialog::getOpenFileName(this, tr("Select server access certificate"), {}, tr("Server access certificates (*.p12 *.p12d *.pfx)") ) ); - if(!file.exists()) + if(!file.open(QFile::ReadOnly)) return; QString pass = QInputDialog::getText( this, tr("Password"), tr("Enter server access certificate password."), QLineEdit::Password ); if(pass.isEmpty()) return; - - if(!file.open(QFile::ReadOnly)) - return; - PKCS12Certificate p12(&file, pass); switch(p12.error()) { diff --git a/client/dialogs/SettingsDialog.h b/client/dialogs/SettingsDialog.h index 426134bd1..0649a60f3 100644 --- a/client/dialogs/SettingsDialog.h +++ b/client/dialogs/SettingsDialog.h @@ -30,7 +30,9 @@ namespace Ui { class SettingsDialog; } +class CertLabel; class QAbstractButton; +class QLabel; class QSslCertificate; class SslCertificate; @@ -70,10 +72,13 @@ class SettingsDialog final: public QDialog void saveFile(const QString &name, const QString &path); void saveFile(const QString &name, const QByteArray &content); void saveProxy(); + QSslCertificate selectCert(const QString &label, const QString &format); void selectLanguage(); void setProxyEnabled(); void updateCert(); + void updateCert(const QSslCertificate &c, QPushButton *btn, CertLabel *lbl); void updateSiVaCert(const QSslCertificate &c); + void updateTSACert(const QSslCertificate &c); void updateProxy(); void updateVersion(); void updateDiagnostics(); diff --git a/client/dialogs/SettingsDialog.ui b/client/dialogs/SettingsDialog.ui index 1ead127db..0c8e71a9c 100644 --- a/client/dialogs/SettingsDialog.ui +++ b/client/dialogs/SettingsDialog.ui @@ -478,363 +478,448 @@ QRadioButton::indicator::checked { - - - QToolButton { border: none; } -QPushButton { - padding: 1px; - text-align: middle; - min-height: 30px; - min-width: 150px; -} + + + QFrame::NoFrame - - - 5 - - - 20 + + true + + + + + 0 + 0 + 789 + 527 + - - 20 + + QToolButton { border: none; } + QPushButton { + padding: 1px; + text-align: middle; + min-height: 30px; + min-width: 150px; + } - - 20 - - - 20 - - - - - - - Qt::TabFocus - - - Access to validity confirmation service - - - - - - - PointingHandCursor - - - Help - - - - :/images/icon_Abi.svg - :/images/icon_Abi_hover.svg - - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::TabFocus - - - Server access certificate - - - - - - - Qt::TabFocus - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - true - - - Qt::TextBrowserInteraction - - - - - - - - - PointingHandCursor - - - INSTALL MANUALLY - - - false - - - - - - - PointingHandCursor - - - SHOW CERTIFICATE - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Ignore server access certificate (IP based access) - - - - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 20 - 20 - - - - - - - - - - Qt::TabFocus - - - Access to Time-Stamping service - - - txtTimeStamp - - - - - - - PointingHandCursor - - - Help - - - - :/images/icon_Abi.svg - :/images/icon_Abi_hover.svg - - - - - 20 - 20 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Use default access - - - true - - - rdTimeStamp - - - - - - - Use manually configured access - - - rdTimeStamp - - - - - - - false - - - true - - - - - - - - - Qt::TabFocus - - - Access to mobile-ID and Smart-ID service - - - - - - - PointingHandCursor - - - Help + + + 5 + + + 20 + + + 20 + + + 20 + + + 20 + + + + + + + Qt::TabFocus + + + Access to validity confirmation service + + + + + + + PointingHandCursor + + + Help + + + + :/images/icon_Abi.svg + :/images/icon_Abi_hover.svg + + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::TabFocus + + + Server access certificate + + + + + + + Qt::TabFocus + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + Qt::TextBrowserInteraction + + + + + + + + + PointingHandCursor + + + INSTALL MANUALLY + + + + + + + PointingHandCursor + + + SHOW CERTIFICATE + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Ignore server access certificate (IP based access) + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + + + Qt::TabFocus + + + Access to Time-Stamping service + + + txtTimeStamp + + + + + + + PointingHandCursor + + + Help + + + + :/images/icon_Abi.svg + :/images/icon_Abi_hover.svg + + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Use default access + + + true + + + rdTimeStamp + + + + + + + Use manually configured access + + + rdTimeStamp + + + + + + + false + + + true + + + + + + + + 5 - - - :/images/icon_Abi.svg - :/images/icon_Abi_hover.svg - + + 0 - - - 20 - 20 - + + 10 - - - - - - Qt::Horizontal + + 0 - - - 40 - 20 - + + 0 - - - - - - - - Use default access - - - true - - - rdMIDUUID - - - - - - - Use manually configured access - - - rdMIDUUID - - - - - - - false - - - QLineEdit::Password - - - 00000000-0000-0000-0000-000000000000 - - - true - - - - - - - Qt::Vertical - - - - 20 - 20 - - - - - + + + + Qt::TabFocus + + + Time-Stamping service SSL certificate + + + + + + + Qt::TabFocus + + + + + + + + + PointingHandCursor + + + ADD CERTIFICATE + + + + + + + PointingHandCursor + + + SHOW CERTIFICATE + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + + + + + + + Qt::TabFocus + + + Access to mobile-ID and Smart-ID service + + + + + + + PointingHandCursor + + + Help + + + + :/images/icon_Abi.svg + :/images/icon_Abi_hover.svg + + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Use default access + + + true + + + rdMIDUUID + + + + + + + Use manually configured access + + + rdMIDUUID + + + + + + + false + + + QLineEdit::Password + + + 00000000-0000-0000-0000-000000000000 + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + @@ -1517,14 +1602,14 @@ QPushButton:disabled { - 0 - 30 + 132 + 25 16777215 - 30 + 25 diff --git a/client/translations/en.ts b/client/translations/en.ts index 382dfe9a2..34128d9df 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -2769,6 +2769,14 @@ Additional licenses and components ADD CERTIFICATE ADD CERTIFICATE + + Select Time-Stamping server certificate + + + + Time-Stamping service SSL certificate + Time-Stamping Service SSL certificate + SHOW CERTIFICATE accessCert diff --git a/client/translations/et.ts b/client/translations/et.ts index 3c595e5b5..7951c40b0 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -2769,6 +2769,14 @@ Täiendavad litsentsid ja komponendid ADD CERTIFICATE LISA SERTIFIKAAT + + Select Time-Stamping server certificate + + + + Time-Stamping service SSL certificate + Ajatempliteenuse SSL sertifikaat + SHOW CERTIFICATE accessCert diff --git a/client/translations/ru.ts b/client/translations/ru.ts index c51c7e91e..25f43c54f 100644 --- a/client/translations/ru.ts +++ b/client/translations/ru.ts @@ -2772,6 +2772,14 @@ Additional licenses and components ADD CERTIFICATE ДОБАВИТЬ СЕРТИФИКАТ + + Select Time-Stamping server certificate + + + + Time-Stamping service SSL certificate + SSL сертификат службы отметок времени + SHOW CERTIFICATE accessCert