Use async signature validation

Also, show information about the validity of the certificate used for
the signature

BUG: 446298
This commit is contained in:
Sune Vuorela 2023-06-24 20:33:00 +02:00
parent e5900f9a4f
commit 0bd2c9cfa0
8 changed files with 89 additions and 9 deletions

View File

@ -485,6 +485,32 @@ public:
*/
virtual bool sign(const NewSignatureData &data, const QString &newPath) const = 0;
using SubscriptionHandle = uint64_t;
/**
* Subscribes to updates to signatureInfo
*
* Especially certificate validation can be a slow task and the
* underlying infrastructure might offload it to a background job.
*
* Whenever those background jobs finished, the callback(s) will be invoked
*
* @return handle to be able to be put back into \ref unsubscribeUpdates
*
* @since 24.08
*/
virtual SubscriptionHandle subscribeUpdates(const std::function<void()> &callback) const = 0;
/**
* Unsubscribes a handle for updates. Handle must be acquired by
* the \ref subscribeUpdates function
*
* @return true if subscription succeeded and false if failed.
* The most likely reason for for failure is if the handle was
* already unsubscribed or for other reasons not existing
*
* @since 24.08
*/
virtual bool unsubscribeUpdates(const SubscriptionHandle &) const = 0;
protected:
FormFieldSignature();

View File

@ -333,14 +333,15 @@ public:
* The verification result of the certificate.
*/
enum CertificateStatus {
CertificateStatusUnknown, ///< The certificate status is unknown for some reason.
CertificateTrusted, ///< The certificate is considered trusted.
CertificateUntrustedIssuer, ///< The issuer of this certificate has been marked as untrusted by the user.
CertificateUnknownIssuer, ///< The certificate trust chain has not finished in a trusted root certificate.
CertificateRevoked, ///< The certificate was revoked by the issuing certificate authority.
CertificateExpired, ///< The signing time is outside the validity bounds of this certificate.
CertificateGenericError, ///< The certificate could not be verified.
CertificateNotVerified ///< The certificate is not yet verified.
CertificateStatusUnknown, ///< The certificate status is unknown for some reason.
CertificateTrusted, ///< The certificate is considered trusted.
CertificateUntrustedIssuer, ///< The issuer of this certificate has been marked as untrusted by the user.
CertificateUnknownIssuer, ///< The certificate trust chain has not finished in a trusted root certificate.
CertificateRevoked, ///< The certificate was revoked by the issuing certificate authority.
CertificateExpired, ///< The signing time is outside the validity bounds of this certificate.
CertificateGenericError, ///< The certificate could not be verified.
CertificateNotVerified, ///< The certificate is not yet verified.
CertificateVerificationInProgress, ///< The certification is not yet verified, but in progress \since 24.08
};
/**

View File

@ -397,12 +397,39 @@ PopplerFormFieldSignature::PopplerFormFieldSignature(std::unique_ptr<Poppler::Fo
if (!PDFSettings::checkOCSPServers()) {
validateOptions = validateOptions | Poppler::FormFieldSignature::ValidateWithoutOCSPRevocationCheck;
}
#if POPPLER_VERSION_MACRO > QT_VERSION_CHECK(24, 4, 0)
auto result = m_field->validateAsync(static_cast<Poppler::FormFieldSignature::ValidateOptions>(validateOptions));
m_info = fromPoppler(result.first);
m_asyncObject = result.second;
QObject::connect(m_asyncObject.get(), &Poppler::AsyncObject::done, m_asyncObject.get(), [this]() {
m_info.setCertificateStatus(fromPoppler(m_field->validateResult()));
for (auto [_, callback] : m_updateSubscriptions) {
callback();
}
});
#else
m_info = fromPoppler(m_field->validate(static_cast<Poppler::FormFieldSignature::ValidateOptions>(validateOptions)));
#endif
SET_ACTIONS
}
PopplerFormFieldSignature::~PopplerFormFieldSignature() = default;
static Okular::FormFieldSignature::SubscriptionHandle globalHandle = 0;
Okular::FormFieldSignature::SubscriptionHandle PopplerFormFieldSignature::subscribeUpdates(const std::function<void()> &callback) const
{
auto handle = (globalHandle++);
m_updateSubscriptions.emplace(handle, callback);
return handle;
}
bool PopplerFormFieldSignature::unsubscribeUpdates(const SubscriptionHandle &handle) const
{
return m_updateSubscriptions.erase(handle) == 1;
}
Okular::NormalizedRect PopplerFormFieldSignature::rect() const
{
return m_rect;

View File

@ -10,6 +10,9 @@
#include "core/form.h"
#include <poppler-form.h>
#include <poppler-version.h>
#include <unordered_map>
#define POPPLER_VERSION_MACRO ((POPPLER_VERSION_MAJOR << 16) | (POPPLER_VERSION_MINOR << 8) | (POPPLER_VERSION_MICRO))
class PopplerFormFieldButton : public Okular::FormFieldButton
{
@ -140,11 +143,18 @@ public:
Okular::SignatureInfo signatureInfo() const override;
bool sign(const Okular::NewSignatureData &oData, const QString &newPath) const override;
SubscriptionHandle subscribeUpdates(const std::function<void()> &callback) const final;
bool unsubscribeUpdates(const SubscriptionHandle &handle) const final;
private:
std::unique_ptr<Poppler::FormFieldSignature> m_field;
Okular::SignatureInfo m_info;
Okular::NormalizedRect m_rect;
int m_id;
#if POPPLER_VERSION_MACRO > QT_VERSION_CHECK(24, 4, 0)
std::shared_ptr<Poppler::AsyncObject> m_asyncObject;
#endif
mutable std::unordered_map<SubscriptionHandle, std::function<void()>> m_updateSubscriptions;
};
#endif

View File

@ -137,6 +137,10 @@ Okular::SignatureInfo::CertificateStatus fromPoppler(Poppler::SignatureValidatio
return Okular::SignatureInfo::CertificateGenericError;
case Poppler::SignatureValidationInfo::CertificateNotVerified:
return Okular::SignatureInfo::CertificateNotVerified;
#if POPPLER_VERSION_MACRO > QT_VERSION_CHECK(24, 04, 0)
case Poppler::SignatureValidationInfo::CertificateVerificationInProgress:
return Okular::SignatureInfo::CertificateVerificationInProgress;
#endif
default:
return Okular::SignatureInfo::CertificateStatusUnknown;
}

View File

@ -15,6 +15,7 @@
Okular::SignatureInfo fromPoppler(const Poppler::SignatureValidationInfo &info);
Okular::CertificateInfo fromPoppler(const Poppler::CertificateInfo &info);
Okular::SignatureInfo::CertificateStatus fromPoppler(Poppler::SignatureValidationInfo::CertificateStatus status);
class PopplerCertificateStore : public Okular::CertificateStore
{

View File

@ -68,6 +68,8 @@ QString getReadableCertStatus(Okular::SignatureInfo::CertificateStatus certStatu
return i18n("Certificate has Expired.");
case Okular::SignatureInfo::CertificateNotVerified:
return i18n("Certificate has not yet been verified.");
case Okular::SignatureInfo::CertificateVerificationInProgress:
return i18n("Certificate validation in progress");
default:
return i18n("Unknown issue with Certificate or corrupted data.");
}

View File

@ -23,7 +23,7 @@
#include "core/signatureutils.h"
struct SignatureItem {
enum DataType { Root, RevisionInfo, ValidityStatus, SigningTime, Reason, Location, FieldInfo };
enum DataType { Root, RevisionInfo, ValidityStatus, CertificateStatus, SigningTime, Reason, Location, FieldInfo };
SignatureItem();
SignatureItem(SignatureItem *parent, const Okular::FormFieldSignature *form, DataType type, int page);
@ -154,6 +154,15 @@ void SignatureModelPrivate::notifySetup(const QVector<Okular::Page *> &pages, in
auto childItem1 = new SignatureItem(parentItem, nullptr, SignatureItem::ValidityStatus, pageNumber);
childItem1->displayString = SignatureGuiUtils::getReadableSignatureStatus(info.signatureStatus());
auto childItem1a = new SignatureItem(parentItem, nullptr, SignatureItem::CertificateStatus, pageNumber);
childItem1a->displayString = SignatureGuiUtils::getReadableCertStatus(info.certificateStatus());
sf->subscribeUpdates([childItem1a, sf, this]() {
const Okular::SignatureInfo &info = sf->signatureInfo();
childItem1a->displayString = SignatureGuiUtils::getReadableCertStatus(info.certificateStatus());
auto index = indexForItem(childItem1a);
q->dataChanged(index, index);
});
auto childItem2 = new SignatureItem(parentItem, nullptr, SignatureItem::SigningTime, pageNumber);
childItem2->displayString = i18n("Signing Time: %1", QLocale().toString(info.signingTime(), QLocale::LongFormat));