Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 18 additions & 29 deletions client/SslCertificate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "SslCertificate.h"

#include "Common.h"
#include "Utils.h"

#include <digidocpp/Exception.h>
#include <digidocpp/crypto/X509Cert.h>
Expand All @@ -35,18 +36,6 @@
#include <openssl/ocsp.h>
#include <openssl/x509v3.h>

#include <memory>

template<auto D>
struct free_deleter
{
template<class T>
void operator()(T *p) const noexcept
{
D(p);
}
};

template<typename> struct free_argument;
template<class T, class R>
struct free_argument<R (*)(T *)>
Expand All @@ -59,13 +48,6 @@ struct free_argument<R (&)(T *)>
using type = T;
};

template<auto F, typename T>
[[nodiscard]]
constexpr auto make_unique_ptr(T *t) noexcept
{
return std::unique_ptr<T, free_deleter<F>>(t);
}

template<class T>
static auto toQByteArray(T &x)
{
Expand Down Expand Up @@ -356,38 +338,42 @@ SslCertificate::Validity SslCertificate::validateOnline() const
if(urls.isEmpty())
return Error;

QEventLoop e;
QNetworkAccessManager m;
QNetworkAccessManager::connect(&m, &QNetworkAccessManager::finished, &e, &QEventLoop::quit);
QNetworkAccessManager::connect(&m, &QNetworkAccessManager::sslErrors, &m,
[](QNetworkReply *reply, const QList<QSslError> &errors){
reply->ignoreSslErrors(errors);
});

// Get issuer
QNetworkRequest r(urls.values(SslCertificate::ad_CAIssuers).first());
r.setRawHeader("User-Agent", QStringLiteral("%1/%2 (%3)")
.arg(QCoreApplication::applicationName(), QCoreApplication::applicationVersion(), Common::applicationOs()).toUtf8());
r.setTransferTimeout(15000);
QNetworkReply *repl = m.get(r);
e.exec();
waitForSignal(&m, &QNetworkAccessManager::finished);
QSslCertificate issuer(repl->readAll(), QSsl::Der);
repl->deleteLater();
if(issuer.isNull())
return Error;

// Verify cert
auto *cert = static_cast<X509 *>(handle());
auto *issuerCert = static_cast<X509 *>(issuer.handle());
if(EVP_PKEY *issuerKey = X509_get0_pubkey(issuerCert);
!issuerKey ||
X509_check_issued(issuerCert, cert) != X509_V_OK ||
X509_verify(cert, issuerKey) != 1)
return Invalid;

// Build request
auto ocspReq = make_unique_ptr<OCSP_REQUEST_free>(OCSP_REQUEST_new());
if(!ocspReq)
return Error;
OCSP_CERTID *certId = OCSP_cert_to_id(nullptr, (X509*)handle(), (X509*)issuer.handle());
OCSP_CERTID *certId = OCSP_cert_to_id(nullptr, cert, issuerCert);
if(!OCSP_request_add0_id(ocspReq.get(), certId))
return Error;

// Send request
r.setUrl(urls.values(SslCertificate::ad_OCSP).first());
r.setHeader(QNetworkRequest::ContentTypeHeader, "application/ocsp-request");
repl = m.post(r, i2dDer<i2d_OCSP_REQUEST>(ocspReq.get()));
e.exec();
waitForSignal(&m, &QNetworkAccessManager::finished);

// Parse response
QByteArray respData = repl->readAll();
Expand All @@ -401,7 +387,10 @@ SslCertificate::Validity SslCertificate::validateOnline() const
auto basic = make_unique_ptr<OCSP_BASICRESP_free>(OCSP_response_get1_basic(resp.get()));
if(!basic)
return Error;
if(OCSP_basic_verify(basic.get(), nullptr, nullptr, OCSP_NOVERIFY) <= 0)
auto store = make_unique_ptr<X509_STORE_free>(X509_STORE_new());
if(!store || !X509_STORE_add_cert(store.get(), issuerCert))
return Error;
if(OCSP_basic_verify(basic.get(), nullptr, store.get(), OCSP_PARTIAL_CHAIN) <= 0)
return Invalid;
int status = -1;
if(OCSP_resp_find_status(basic.get(), certId, &status, nullptr, nullptr, nullptr, nullptr) <= 0)
Expand Down
51 changes: 38 additions & 13 deletions client/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,52 @@
#include <QTimer>

#include <exception>
#include <future>
#include <limits>
#include <memory>
#include <thread>

namespace {
template<auto D>
struct free_deleter
{
template<class T>
void operator()(T *p) const noexcept
{
D(p);
}
};

template<auto F, typename T>
[[nodiscard]]
constexpr auto make_unique_ptr(T *t) noexcept
{
return std::unique_ptr<T, free_deleter<F>>(t);
}

template <typename F, class... Args>
inline auto waitFor(F&& function, Args&& ...args) {
std::exception_ptr exception;
std::invoke_result_t<F,Args...> result{};
QEventLoop l;
std::thread([&, function = std::forward<F>(function), ...args = std::forward<Args>(args)]{
try {
result = std::invoke(function, args...);
} catch(...) {
exception = std::current_exception();
}
l.exit();
}).detach();
using result_t = std::invoke_result_t<F, Args...>;
std::packaged_task<result_t()> task(
[function = std::forward<F>(function),
...args = std::forward<Args>(args)]() mutable -> result_t {
return std::invoke(function, args...);
});
auto future = task.get_future();
std::jthread worker([&l, task = std::move(task)]() mutable {
task();
QMetaObject::invokeMethod(&l, &QEventLoop::quit, Qt::QueuedConnection);
});
l.exec();
return future.get();
}

template <typename Sender, typename Signal>
inline void waitForSignal(Sender *sender, Signal signal) {
QEventLoop l;
QObject::connect(sender, signal, &l, &QEventLoop::quit);
l.exec();
if(exception)
std::rethrow_exception(std::move(exception));
return result;
}

template <typename F, class... Args>
Expand Down
Loading