mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Certificate validation
This commit is contained in:
@ -107,6 +107,8 @@ PDFDocument PDFDocumentReader::readFromBuffer(const QByteArray& buffer)
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
m_source = buffer;
|
||||||
|
|
||||||
// FOOTER CHECKING
|
// FOOTER CHECKING
|
||||||
// 1) Check, if EOF marking is present
|
// 1) Check, if EOF marking is present
|
||||||
// 2) Find start of cross reference table
|
// 2) Find start of cross reference table
|
||||||
|
@ -72,6 +72,9 @@ public:
|
|||||||
/// Returns error message, if document reading was unsuccessfull
|
/// Returns error message, if document reading was unsuccessfull
|
||||||
const QString& getErrorMessage() const { return m_errorMessage; }
|
const QString& getErrorMessage() const { return m_errorMessage; }
|
||||||
|
|
||||||
|
/// Get source data of the document
|
||||||
|
const QByteArray& getSource() const { return m_source; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const int FIND_NOT_FOUND_RESULT = -1;
|
static constexpr const int FIND_NOT_FOUND_RESULT = -1;
|
||||||
|
|
||||||
@ -109,6 +112,9 @@ private:
|
|||||||
|
|
||||||
/// Progress indicator
|
/// Progress indicator
|
||||||
PDFProgress* m_progress;
|
PDFProgress* m_progress;
|
||||||
|
|
||||||
|
/// Raw document data (byte array containing source data for created document)
|
||||||
|
QByteArray m_source;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -636,6 +636,14 @@ PDFFormField* PDFForm::getFormFieldForWidget(PDFObjectReference widget)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PDFForm::apply(const std::function<void (const PDFFormField*)>& functor) const
|
||||||
|
{
|
||||||
|
for (const PDFFormFieldPointer& childField : getFormFields())
|
||||||
|
{
|
||||||
|
childField->apply(functor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PDFFormField::fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping)
|
void PDFFormField::fillWidgetToFormFieldMapping(PDFWidgetToFormFieldMapping& mapping)
|
||||||
{
|
{
|
||||||
for (const auto& childField : m_childFields)
|
for (const auto& childField : m_childFields)
|
||||||
@ -1204,10 +1212,7 @@ PDFFormWidgets PDFFormManager::getWidgets() const
|
|||||||
|
|
||||||
void PDFFormManager::apply(const std::function<void (const PDFFormField*)>& functor) const
|
void PDFFormManager::apply(const std::function<void (const PDFFormField*)>& functor) const
|
||||||
{
|
{
|
||||||
for (const PDFFormFieldPointer& childField : m_form.getFormFields())
|
m_form.apply(functor);
|
||||||
{
|
|
||||||
childField->apply(functor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFFormManager::modify(const std::function<void (PDFFormField*)>& functor) const
|
void PDFFormManager::modify(const std::function<void (PDFFormField*)>& functor) const
|
||||||
|
@ -409,7 +409,7 @@ private:
|
|||||||
/// Fields forms tree-like structure, where leafs are usually widgets. Fields include
|
/// Fields forms tree-like structure, where leafs are usually widgets. Fields include
|
||||||
/// ordinary widgets, such as buttons, check boxes, combo boxes and text fields, and one
|
/// ordinary widgets, such as buttons, check boxes, combo boxes and text fields, and one
|
||||||
/// special - signature field, which represents digital signature.
|
/// special - signature field, which represents digital signature.
|
||||||
class PDFForm
|
class PDFFORQTLIBSHARED_EXPORT PDFForm
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit inline PDFForm() = default;
|
explicit inline PDFForm() = default;
|
||||||
@ -454,6 +454,12 @@ public:
|
|||||||
/// \param widget Widget annotation
|
/// \param widget Widget annotation
|
||||||
PDFFormField* getFormFieldForWidget(PDFObjectReference widget);
|
PDFFormField* getFormFieldForWidget(PDFObjectReference widget);
|
||||||
|
|
||||||
|
/// Applies function to all form fields present in the form,
|
||||||
|
/// in pre-order (first application is to the parent, following
|
||||||
|
/// calls to apply for children).
|
||||||
|
/// \param functor Functor to apply
|
||||||
|
void apply(const std::function<void(const PDFFormField*)>& functor) const;
|
||||||
|
|
||||||
/// Parses form from the object. If some error occurs
|
/// Parses form from the object. If some error occurs
|
||||||
/// then empty form is returned, no exception is thrown.
|
/// then empty form is returned, no exception is thrown.
|
||||||
/// \param document Document
|
/// \param document Document
|
||||||
|
@ -18,12 +18,30 @@
|
|||||||
#include "pdfsignaturehandler.h"
|
#include "pdfsignaturehandler.h"
|
||||||
#include "pdfdocument.h"
|
#include "pdfdocument.h"
|
||||||
#include "pdfencoding.h"
|
#include "pdfencoding.h"
|
||||||
|
#include "pdfform.h"
|
||||||
|
#include "pdfsignaturehandler_impl.h"
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static QMutex s_globalOpenSSLMutex(QMutex::Recursive);
|
||||||
|
|
||||||
|
/// OpenSSL is not thread safe.
|
||||||
|
class PDFOpenSSLGlobalLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFOpenSSLGlobalLock() : m_mutexLocker(&s_globalOpenSSLMutex) { }
|
||||||
|
inline ~PDFOpenSSLGlobalLock() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutexLocker m_mutexLocker;
|
||||||
|
};
|
||||||
|
|
||||||
PDFSignatureReference PDFSignatureReference::parse(const PDFObjectStorage* storage, PDFObject object)
|
PDFSignatureReference PDFSignatureReference::parse(const PDFObjectStorage* storage, PDFObject object)
|
||||||
{
|
{
|
||||||
PDFSignatureReference result;
|
PDFSignatureReference result;
|
||||||
@ -118,4 +136,281 @@ PDFSignature PDFSignature::parse(const PDFObjectStorage* storage, PDFObject obje
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFSignatureHandler* PDFSignatureHandler::createHandler(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData)
|
||||||
|
{
|
||||||
|
Q_ASSERT(signatureField);
|
||||||
|
|
||||||
|
const QByteArray& subfilter = signatureField->getSignature().getSubfilter();
|
||||||
|
if (subfilter == "adbe.pkcs7.detached")
|
||||||
|
{
|
||||||
|
return new PDFSignatureHandler_adbe_pkcs7_detached(signatureField, sourceData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PDFSignatureVerificationResult> PDFSignatureHandler::verifySignatures(const PDFForm& form, const QByteArray& sourceData)
|
||||||
|
{
|
||||||
|
std::vector<PDFSignatureVerificationResult> result;
|
||||||
|
|
||||||
|
if (form.isAcroForm() || form.isXFAForm())
|
||||||
|
{
|
||||||
|
std::vector<const PDFFormFieldSignature*> signatureFields;
|
||||||
|
auto getSignatureFields = [&signatureFields](const PDFFormField* field)
|
||||||
|
{
|
||||||
|
if (field->getFieldType() == PDFFormField::FieldType::Signature)
|
||||||
|
{
|
||||||
|
const PDFFormFieldSignature* signatureField = dynamic_cast<const PDFFormFieldSignature*>(field);
|
||||||
|
Q_ASSERT(signatureField);
|
||||||
|
signatureFields.push_back(signatureField);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
form.apply(getSignatureFields);
|
||||||
|
result.reserve(signatureFields.size());
|
||||||
|
|
||||||
|
for (const PDFFormFieldSignature* signatureField : signatureFields)
|
||||||
|
{
|
||||||
|
if (const PDFSignatureHandler* signatureHandler = createHandler(signatureField, sourceData))
|
||||||
|
{
|
||||||
|
result.emplace_back(signatureHandler->verify());
|
||||||
|
delete signatureHandler;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PDFObjectReference signatureFieldReference = signatureField->getSelfReference();
|
||||||
|
QString qualifiedName = signatureField->getName(PDFFormField::NameType::FullyQualified);
|
||||||
|
PDFSignatureVerificationResult verificationResult(signatureFieldReference, qMove(qualifiedName));
|
||||||
|
verificationResult.addNoHandlerError(signatureField->getSignature().getSubfilter());
|
||||||
|
result.emplace_back(qMove(verificationResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addNoHandlerError(const QByteArray& format)
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_NoHandler);
|
||||||
|
m_errors << PDFTranslationContext::tr("No signature handler for signature format '%1'.").arg(QString::fromLatin1(format));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addInvalidCertificateError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_Invalid);
|
||||||
|
m_errors << PDFTranslationContext::tr("Certificate format is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addNoSignaturesError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_NoSignatures);
|
||||||
|
m_errors << PDFTranslationContext::tr("No signatures in certificate data.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateMissingError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_Missing);
|
||||||
|
m_errors << PDFTranslationContext::tr("Certificate is missing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateGenericError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_Generic);
|
||||||
|
m_errors << PDFTranslationContext::tr("Generic error occured during certificate validation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateExpiredError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_Expired);
|
||||||
|
m_errors << PDFTranslationContext::tr("Certificate has expired.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateSelfSignedError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_SelfSigned);
|
||||||
|
m_errors << PDFTranslationContext::tr("Certificate is self-signed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateSelfSignedInChainError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_SelfSignedChain);
|
||||||
|
m_errors << PDFTranslationContext::tr("Self-signed certificate in chain.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateTrustedNotFoundError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_TrustedNotFound);
|
||||||
|
m_errors << PDFTranslationContext::tr("Trusted certificate not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateRevokedError()
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_Revoked);
|
||||||
|
m_errors << PDFTranslationContext::tr("Certificate has been revoked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::addCertificateOtherError(int error)
|
||||||
|
{
|
||||||
|
m_flags.setFlag(Error_Certificate_Other);
|
||||||
|
m_errors << PDFTranslationContext::tr("Certificate validation failed with code %1.").arg(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::setSignatureFieldQualifiedName(const QString& signatureFieldQualifiedName)
|
||||||
|
{
|
||||||
|
m_signatureFieldQualifiedName = signatureFieldQualifiedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureVerificationResult::setSignatureFieldReference(PDFObjectReference signatureFieldReference)
|
||||||
|
{
|
||||||
|
m_signatureFieldReference = signatureFieldReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPublicKeySignatureHandler::initializeResult(PDFSignatureVerificationResult& result) const
|
||||||
|
{
|
||||||
|
PDFObjectReference signatureFieldReference = m_signatureField->getSelfReference();
|
||||||
|
QString signatureFieldQualifiedName = m_signatureField->getName(PDFFormField::NameType::FullyQualified);
|
||||||
|
result.setSignatureFieldReference(signatureFieldReference);
|
||||||
|
result.setSignatureFieldQualifiedName(signatureFieldQualifiedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
STACK_OF(X509)* PDFPublicKeySignatureHandler::getCertificates(PKCS7* pkcs7)
|
||||||
|
{
|
||||||
|
if (!pkcs7)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PKCS7_type_is_signed(pkcs7))
|
||||||
|
{
|
||||||
|
return pkcs7->d.sign->cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PKCS7_type_is_signedAndEnveloped(pkcs7))
|
||||||
|
{
|
||||||
|
return pkcs7->d.signed_and_enveloped->cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPublicKeySignatureHandler::verifyCertificate(PDFSignatureVerificationResult& result) const
|
||||||
|
{
|
||||||
|
PDFOpenSSLGlobalLock lock;
|
||||||
|
|
||||||
|
OpenSSL_add_all_algorithms();
|
||||||
|
|
||||||
|
const PDFSignature& signature = m_signatureField->getSignature();
|
||||||
|
const QByteArray& content = signature.getContents();
|
||||||
|
|
||||||
|
// Jakub Melka: we will try to get pkcs7 from signature, then
|
||||||
|
// verify signer certificates.
|
||||||
|
const unsigned char* data = reinterpret_cast<const unsigned char*>(content.data());
|
||||||
|
if (PKCS7* pkcs7 = d2i_PKCS7(nullptr, &data, content.size()))
|
||||||
|
{
|
||||||
|
X509_STORE* store = X509_STORE_new();
|
||||||
|
X509_STORE_CTX* context = X509_STORE_CTX_new();
|
||||||
|
|
||||||
|
// Above functions can fail only if not enough memory. But in this
|
||||||
|
// case, this library will crash anyway.
|
||||||
|
Q_ASSERT(store);
|
||||||
|
Q_ASSERT(context);
|
||||||
|
|
||||||
|
STACK_OF(PKCS7_SIGNER_INFO)* signerInfo = PKCS7_get_signer_info(pkcs7);
|
||||||
|
const int signerInfoCount = sk_PKCS7_SIGNER_INFO_num(signerInfo);
|
||||||
|
STACK_OF(X509)* certificates = getCertificates(pkcs7);
|
||||||
|
if (signerInfo && signerInfoCount > 0 && certificates)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < signerInfoCount; ++i)
|
||||||
|
{
|
||||||
|
PKCS7_SIGNER_INFO* signerInfoValue = sk_PKCS7_SIGNER_INFO_value(signerInfo, i);
|
||||||
|
PKCS7_ISSUER_AND_SERIAL* issuerAndSerial = signerInfoValue->issuer_and_serial;
|
||||||
|
X509* signer = X509_find_by_issuer_and_serial(certificates, issuerAndSerial->issuer, issuerAndSerial->serial);
|
||||||
|
|
||||||
|
if (!signer)
|
||||||
|
{
|
||||||
|
result.addCertificateMissingError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!X509_STORE_CTX_init(context, store, signer, nullptr))
|
||||||
|
{
|
||||||
|
result.addCertificateGenericError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!X509_STORE_CTX_set_purpose(context, X509_PURPOSE_SMIME_SIGN))
|
||||||
|
{
|
||||||
|
result.addCertificateGenericError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int verificationResult = X509_verify_cert(context);
|
||||||
|
if (verificationResult <= 0)
|
||||||
|
{
|
||||||
|
int error = X509_STORE_CTX_get_error(context);
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case X509_V_OK:
|
||||||
|
// Strange, this should not occur... when X509_verify_cert fails
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||||
|
result.addCertificateExpiredError();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||||
|
result.addCertificateSelfSignedError();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
|
||||||
|
result.addCertificateSelfSignedInChainError();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
|
||||||
|
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
|
||||||
|
result.addCertificateTrustedNotFoundError();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case X509_V_ERR_CERT_REVOKED:
|
||||||
|
result.addCertificateRevokedError();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
result.addCertificateOtherError(error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
X509_STORE_CTX_cleanup(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.addNoSignaturesError();
|
||||||
|
}
|
||||||
|
|
||||||
|
X509_STORE_CTX_free(context);
|
||||||
|
X509_STORE_free(store);
|
||||||
|
|
||||||
|
PKCS7_free(pkcs7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.addInvalidCertificateError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFPublicKeySignatureHandler::verifySignature(PDFSignatureVerificationResult& result) const
|
||||||
|
{
|
||||||
|
PDFOpenSSLGlobalLock lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFSignatureVerificationResult PDFSignatureHandler_adbe_pkcs7_detached::verify() const
|
||||||
|
{
|
||||||
|
PDFSignatureVerificationResult result;
|
||||||
|
initializeResult(result);
|
||||||
|
verifyCertificate(result);
|
||||||
|
verifySignature(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
class PDFForm;
|
||||||
class PDFObjectStorage;
|
class PDFObjectStorage;
|
||||||
|
class PDFFormFieldSignature;
|
||||||
|
|
||||||
/// Signature reference dictionary.
|
/// Signature reference dictionary.
|
||||||
class PDFSignatureReference
|
class PDFSignatureReference
|
||||||
@ -142,10 +144,92 @@ private:
|
|||||||
AuthentificationType m_propType = AuthentificationType::Invalid;
|
AuthentificationType m_propType = AuthentificationType::Invalid;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PDFSignatureHandler
|
class PDFFORQTLIBSHARED_EXPORT PDFSignatureVerificationResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PDFSignatureHandler();
|
explicit PDFSignatureVerificationResult() = default;
|
||||||
|
explicit PDFSignatureVerificationResult(PDFObjectReference signatureFieldReference, QString qualifiedName) :
|
||||||
|
m_signatureFieldReference(signatureFieldReference),
|
||||||
|
m_signatureFieldQualifiedName(qualifiedName)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
enum VerificationFlag
|
||||||
|
{
|
||||||
|
None = 0x00000, ///< Used only for initialization
|
||||||
|
OK = 0x00001, ///< Both certificate and signature is OK
|
||||||
|
Error_NoHandler = 0x00002, ///< No signature handler for given signature
|
||||||
|
Error_Generic = 0x00004, ///< Generic error (uknown general error)
|
||||||
|
|
||||||
|
Error_Certificate_Invalid = 0x00008, ///< Certificate is invalid
|
||||||
|
Error_Certificate_NoSignatures = 0x00010, ///< No signature found in certificate data
|
||||||
|
Error_Certificate_Missing = 0x00020, ///< Certificate is missing
|
||||||
|
Error_Certificate_Generic = 0x00040, ///< Generic error during certificate verification
|
||||||
|
Error_Certificate_Expired = 0x00080, ///< Certificate has expired
|
||||||
|
Error_Certificate_SelfSigned = 0x00100, ///< Self signed certificate
|
||||||
|
Error_Certificate_SelfSignedChain = 0x00200, ///< Self signed certificate in chain
|
||||||
|
Error_Certificate_TrustedNotFound = 0x00400, ///< No trusted certificate was found
|
||||||
|
Error_Certificate_Revoked = 0x00800, ///< Certificate has been revoked
|
||||||
|
Error_Certificate_Other = 0x01000, ///< Other certificate error. See OpenSSL code for details.
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(VerificationFlags, VerificationFlag)
|
||||||
|
|
||||||
|
/// Adds no handler error for given signature format
|
||||||
|
/// \param format Signature format
|
||||||
|
void addNoHandlerError(const QByteArray& format);
|
||||||
|
|
||||||
|
void addInvalidCertificateError();
|
||||||
|
void addNoSignaturesError();
|
||||||
|
void addCertificateMissingError();
|
||||||
|
void addCertificateGenericError();
|
||||||
|
void addCertificateExpiredError();
|
||||||
|
void addCertificateSelfSignedError();
|
||||||
|
void addCertificateSelfSignedInChainError();
|
||||||
|
void addCertificateTrustedNotFoundError();
|
||||||
|
void addCertificateRevokedError();
|
||||||
|
void addCertificateOtherError(int error);
|
||||||
|
|
||||||
|
bool isValid() const { return hasFlag(OK); }
|
||||||
|
bool hasError() const { return !isValid(); }
|
||||||
|
bool hasFlag(VerificationFlag flag) const { return m_flags.testFlag(flag); }
|
||||||
|
|
||||||
|
PDFObjectReference getSignatureFieldReference() const { return m_signatureFieldReference; }
|
||||||
|
const QString& getSignatureFieldQualifiedName() const { return m_signatureFieldQualifiedName; }
|
||||||
|
const QStringList& getErrors() const { return m_errors; }
|
||||||
|
|
||||||
|
void setSignatureFieldQualifiedName(const QString& signatureFieldQualifiedName);
|
||||||
|
void setSignatureFieldReference(PDFObjectReference signatureFieldReference);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VerificationFlags m_flags = None;
|
||||||
|
PDFObjectReference m_signatureFieldReference;
|
||||||
|
QString m_signatureFieldQualifiedName;
|
||||||
|
QStringList m_errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Signature handler. Can verify both certificate and signature validity.
|
||||||
|
class PDFFORQTLIBSHARED_EXPORT PDFSignatureHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFSignatureHandler() = default;
|
||||||
|
virtual ~PDFSignatureHandler() = default;
|
||||||
|
|
||||||
|
virtual PDFSignatureVerificationResult verify() const = 0;
|
||||||
|
|
||||||
|
/// Tries to verify all signatures in the form. If form is invalid, then
|
||||||
|
/// empty vector is returned.
|
||||||
|
/// \param form Form
|
||||||
|
/// \param sourceData Source data
|
||||||
|
static std::vector<PDFSignatureVerificationResult> verifySignatures(const PDFForm& form, const QByteArray& sourceData);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/// Creates signature handler using format specified by signature in signature field.
|
||||||
|
/// If signature format is unknown, then nullptr is returned.
|
||||||
|
/// \param signatureField Signature field
|
||||||
|
/// \param sourceData
|
||||||
|
static PDFSignatureHandler* createHandler(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -18,9 +18,50 @@
|
|||||||
#ifndef PDFSIGNATUREHANDLER_IMPL_H
|
#ifndef PDFSIGNATUREHANDLER_IMPL_H
|
||||||
#define PDFSIGNATUREHANDLER_IMPL_H
|
#define PDFSIGNATUREHANDLER_IMPL_H
|
||||||
|
|
||||||
|
#include "pdfsignaturehandler.h"
|
||||||
|
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
#include <openssl/pkcs7.h>
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// PKCS7 public key signature handler
|
||||||
|
class PDFPublicKeySignatureHandler : public PDFSignatureHandler
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
explicit PDFPublicKeySignatureHandler(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData) :
|
||||||
|
m_signatureField(signatureField),
|
||||||
|
m_sourceData(sourceData)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void initializeResult(PDFSignatureVerificationResult& result) const;
|
||||||
|
void verifyCertificate(PDFSignatureVerificationResult& result) const;
|
||||||
|
void verifySignature(PDFSignatureVerificationResult& result) const;
|
||||||
|
|
||||||
|
/// Return a list of certificates from PKCS7 object
|
||||||
|
static STACK_OF(X509)* getCertificates(PKCS7* pkcs7);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const PDFFormFieldSignature* m_signatureField;
|
||||||
|
QByteArray m_sourceData;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PDFSignatureHandler_adbe_pkcs7_detached : public PDFPublicKeySignatureHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFSignatureHandler_adbe_pkcs7_detached(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData) :
|
||||||
|
PDFPublicKeySignatureHandler(signatureField, sourceData)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual PDFSignatureVerificationResult verify() const override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "pdfexecutionpolicy.h"
|
#include "pdfexecutionpolicy.h"
|
||||||
#include "pdfwidgetutils.h"
|
#include "pdfwidgetutils.h"
|
||||||
#include "pdfdocumentwriter.h"
|
#include "pdfdocumentwriter.h"
|
||||||
|
#include "pdfsignaturehandler.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
@ -964,6 +965,10 @@ void PDFViewerMainWindow::openDocument(const QString& fileName)
|
|||||||
result.result = reader.getReadingResult();
|
result.result = reader.getReadingResult();
|
||||||
if (result.result == pdf::PDFDocumentReader::Result::OK)
|
if (result.result == pdf::PDFDocumentReader::Result::OK)
|
||||||
{
|
{
|
||||||
|
// Verify signatures
|
||||||
|
pdf::PDFForm form = pdf::PDFForm::parse(&document, document.getCatalog()->getFormObject());
|
||||||
|
std::vector<pdf::PDFSignatureVerificationResult> signaturesVerifications = pdf::PDFSignatureHandler::verifySignatures(form, reader.getSource());
|
||||||
|
|
||||||
result.document.reset(new pdf::PDFDocument(qMove(document)));
|
result.document.reset(new pdf::PDFDocument(qMove(document)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user