mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-29 08:39:41 +01:00
Handling CAdES signatures
This commit is contained in:
parent
73cebb184e
commit
03dac20314
@ -20,6 +20,7 @@
|
|||||||
#include "pdfexception.h"
|
#include "pdfexception.h"
|
||||||
#include "pdfnumbertreeloader.h"
|
#include "pdfnumbertreeloader.h"
|
||||||
#include "pdfnametreeloader.h"
|
#include "pdfnametreeloader.h"
|
||||||
|
#include "pdfencoding.h"
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
@ -169,6 +170,7 @@ PDFCatalog PDFCatalog::parse(const PDFObject& catalog, const PDFDocument* docume
|
|||||||
}
|
}
|
||||||
|
|
||||||
catalogObject.m_formObject = catalogDictionary->get("AcroForm");
|
catalogObject.m_formObject = catalogDictionary->get("AcroForm");
|
||||||
|
catalogObject.m_documentSecurityStore = PDFDocumentSecurityStore::parse(catalogDictionary->get("DSS"), document);
|
||||||
|
|
||||||
return catalogObject;
|
return catalogObject;
|
||||||
}
|
}
|
||||||
@ -461,4 +463,80 @@ PDFPageLabel PDFPageLabel::parse(PDFInteger pageIndex, const PDFDocument* docume
|
|||||||
return PDFPageLabel();
|
return PDFPageLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PDFDocumentSecurityStore::SecurityStoreItem* PDFDocumentSecurityStore::getItem(const QByteArray& hash) const
|
||||||
|
{
|
||||||
|
auto it = m_VRI.find(hash);
|
||||||
|
if (it != m_VRI.cend())
|
||||||
|
{
|
||||||
|
return &it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getMasterItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFDocumentSecurityStore PDFDocumentSecurityStore::parse(const PDFObject& object, const PDFDocument* document)
|
||||||
|
{
|
||||||
|
PDFDocumentSecurityStore store;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (const PDFDictionary* dssDictionary = document->getDictionaryFromObject(object))
|
||||||
|
{
|
||||||
|
PDFDocumentDataLoaderDecorator loader(document);
|
||||||
|
|
||||||
|
auto getDecodedStreams = [document, &loader](const PDFObject& object) -> std::vector<QByteArray>
|
||||||
|
{
|
||||||
|
std::vector<QByteArray> result;
|
||||||
|
|
||||||
|
std::vector<PDFObjectReference> references = loader.readReferenceArray(object);
|
||||||
|
result.reserve(references.size());
|
||||||
|
for (const PDFObjectReference& reference : references)
|
||||||
|
{
|
||||||
|
PDFObject object = document->getObjectByReference(reference);
|
||||||
|
if (object.isStream())
|
||||||
|
{
|
||||||
|
result.emplace_back(document->getDecodedStream(object.getStream()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
store.m_master.Cert = getDecodedStreams(dssDictionary->get("Certs"));
|
||||||
|
store.m_master.OCSP = getDecodedStreams(dssDictionary->get("OCSPs"));
|
||||||
|
store.m_master.CRL = getDecodedStreams(dssDictionary->get("CRLs"));
|
||||||
|
|
||||||
|
if (const PDFDictionary* vriDictionary = document->getDictionaryFromObject(dssDictionary->get("VRI")))
|
||||||
|
{
|
||||||
|
for (size_t i = 0, count = vriDictionary->getCount(); i < count; ++i)
|
||||||
|
{
|
||||||
|
const PDFObject& vriItemObject = vriDictionary->getValue(i);
|
||||||
|
if (const PDFDictionary* vriItemDictionary = document->getDictionaryFromObject(vriItemObject))
|
||||||
|
{
|
||||||
|
QByteArray key = vriDictionary->getKey(i).getString();
|
||||||
|
|
||||||
|
SecurityStoreItem& item = store.m_VRI[key];
|
||||||
|
item.Cert = getDecodedStreams(vriItemDictionary->get("Cert"));
|
||||||
|
item.CRL = getDecodedStreams(vriItemDictionary->get("CRL"));
|
||||||
|
item.OCSP = getDecodedStreams(vriItemDictionary->get("OCSP"));
|
||||||
|
item.created = PDFEncoding::convertToDateTime(loader.readStringFromDictionary(vriDictionary, "TU"));
|
||||||
|
|
||||||
|
PDFObject timestampObject = document->getObject(vriItemDictionary->get("TS"));
|
||||||
|
if (timestampObject.isStream())
|
||||||
|
{
|
||||||
|
item.timestamp = document->getDecodedStream(timestampObject.getStream());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (PDFException)
|
||||||
|
{
|
||||||
|
return PDFDocumentSecurityStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -194,6 +194,37 @@ private:
|
|||||||
PDFInteger m_numberOfCopies = 1;
|
PDFInteger m_numberOfCopies = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Document security store. Contains certificates, CRLs, OCSPs, and
|
||||||
|
/// other data for signature validation.
|
||||||
|
class PDFFORQTLIBSHARED_EXPORT PDFDocumentSecurityStore
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline PDFDocumentSecurityStore() = default;
|
||||||
|
|
||||||
|
struct SecurityStoreItem
|
||||||
|
{
|
||||||
|
std::vector<QByteArray> Cert;
|
||||||
|
std::vector<QByteArray> CRL;
|
||||||
|
std::vector<QByteArray> OCSP;
|
||||||
|
QDateTime created;
|
||||||
|
QByteArray timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Returns master item. Return value is never nullptr.
|
||||||
|
const SecurityStoreItem* getMasterItem() const { return &m_master; }
|
||||||
|
|
||||||
|
/// Get item using hash. If item is not found, master item is returned.
|
||||||
|
const SecurityStoreItem* getItem(const QByteArray& hash) const;
|
||||||
|
|
||||||
|
/// Parses document security store from catalog dictionary. If object cannot be parsed, or error occurs,
|
||||||
|
/// then empty object is returned.
|
||||||
|
static PDFDocumentSecurityStore parse(const PDFObject& object, const PDFDocument* document);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SecurityStoreItem m_master;
|
||||||
|
std::map<QByteArray, SecurityStoreItem> m_VRI;
|
||||||
|
};
|
||||||
|
|
||||||
class PDFFORQTLIBSHARED_EXPORT PDFCatalog
|
class PDFFORQTLIBSHARED_EXPORT PDFCatalog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -236,6 +267,7 @@ public:
|
|||||||
const QByteArray& getBaseURI() const { return m_baseURI; }
|
const QByteArray& getBaseURI() const { return m_baseURI; }
|
||||||
const std::map<QByteArray, PDFFileSpecification>& getEmbeddedFiles() const { return m_embeddedFiles; }
|
const std::map<QByteArray, PDFFileSpecification>& getEmbeddedFiles() const { return m_embeddedFiles; }
|
||||||
const PDFObject& getFormObject() const { return m_formObject; }
|
const PDFObject& getFormObject() const { return m_formObject; }
|
||||||
|
const PDFDocumentSecurityStore& getDocumentSecurityStore() const { return m_documentSecurityStore; }
|
||||||
|
|
||||||
/// Returns destination using the key. If destination with the key is not found,
|
/// Returns destination using the key. If destination with the key is not found,
|
||||||
/// then nullptr is returned.
|
/// then nullptr is returned.
|
||||||
@ -259,6 +291,7 @@ private:
|
|||||||
PageMode m_pageMode = PageMode::UseNone;
|
PageMode m_pageMode = PageMode::UseNone;
|
||||||
QByteArray m_baseURI;
|
QByteArray m_baseURI;
|
||||||
PDFObject m_formObject;
|
PDFObject m_formObject;
|
||||||
|
PDFDocumentSecurityStore m_documentSecurityStore;
|
||||||
|
|
||||||
// Maps from Names dictionary
|
// Maps from Names dictionary
|
||||||
std::map<QByteArray, PDFDestination> m_destinations;
|
std::map<QByteArray, PDFDestination> m_destinations;
|
||||||
|
@ -160,6 +160,10 @@ PDFSignatureHandler* PDFSignatureHandler::createHandler(const PDFFormFieldSignat
|
|||||||
{
|
{
|
||||||
return new PDFSignatureHandler_adbe_pkcs7_rsa_sha1(signatureField, sourceData, parameters);
|
return new PDFSignatureHandler_adbe_pkcs7_rsa_sha1(signatureField, sourceData, parameters);
|
||||||
}
|
}
|
||||||
|
else if (subfilter == "ETSI.CAdES.detached")
|
||||||
|
{
|
||||||
|
return new PDFSignatureHandler_ETSI_CAdES_detached(signatureField, sourceData, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -369,7 +373,7 @@ void PDFPublicKeySignatureHandler::verifyCertificate(PDFSignatureVerificationRes
|
|||||||
|
|
||||||
// Jakub Melka: we will try to get pkcs7 from signature, then
|
// Jakub Melka: we will try to get pkcs7 from signature, then
|
||||||
// verify signer certificates.
|
// verify signer certificates.
|
||||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(content.data());
|
const unsigned char* data = convertByteArrayToUcharPtr(content);
|
||||||
if (PKCS7* pkcs7 = d2i_PKCS7(nullptr, &data, content.size()))
|
if (PKCS7* pkcs7 = d2i_PKCS7(nullptr, &data, content.size()))
|
||||||
{
|
{
|
||||||
X509_STORE* store = X509_STORE_new();
|
X509_STORE* store = X509_STORE_new();
|
||||||
@ -585,7 +589,7 @@ void PDFPublicKeySignatureHandler::verifySignature(PDFSignatureVerificationResul
|
|||||||
|
|
||||||
// Jakub Melka: we will try to get pkcs7 from signature, then
|
// Jakub Melka: we will try to get pkcs7 from signature, then
|
||||||
// verify signer certificates.
|
// verify signer certificates.
|
||||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(content.data());
|
const unsigned char* data = convertByteArrayToUcharPtr(content);
|
||||||
if (PKCS7* pkcs7 = d2i_PKCS7(nullptr, &data, content.size()))
|
if (PKCS7* pkcs7 = d2i_PKCS7(nullptr, &data, content.size()))
|
||||||
{
|
{
|
||||||
QByteArray buffer;
|
QByteArray buffer;
|
||||||
@ -680,6 +684,180 @@ PDFSignatureVerificationResult PDFSignatureHandler_adbe_pkcs7_detached::verify()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFSignatureVerificationResult PDFSignatureHandler_ETSI_CAdES_detached::verify() const
|
||||||
|
{
|
||||||
|
PDFSignatureVerificationResult result;
|
||||||
|
initializeResult(result);
|
||||||
|
verifyCertificateCAdES(result);
|
||||||
|
verifySignature(result);
|
||||||
|
result.validate();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFSignatureHandler_ETSI_CAdES_detached::verifyCertificateCAdES(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 = convertByteArrayToUcharPtr(content);
|
||||||
|
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);
|
||||||
|
|
||||||
|
addTrustedCertificates(store);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
STACK_OF(X509)* allCertificates = nullptr;
|
||||||
|
if (m_parameters.dss && !m_parameters.dss->getMasterItem()->Cert.empty())
|
||||||
|
{
|
||||||
|
allCertificates = sk_X509_new_null();
|
||||||
|
|
||||||
|
// First, add all certificates from pkcs7
|
||||||
|
for (int i = 0; i < sk_X509_num(certificates); ++i)
|
||||||
|
{
|
||||||
|
sk_X509_push(allCertificates, sk_X509_value(certificates, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second, add all certificates from document's security store
|
||||||
|
for (const QByteArray& certificateData : m_parameters.dss->getMasterItem()->Cert)
|
||||||
|
{
|
||||||
|
const unsigned char* certificateDataBuffer = convertByteArrayToUcharPtr(certificateData);
|
||||||
|
if (X509* certificate = d2i_X509(nullptr, &certificateDataBuffer, certificateData.size()))
|
||||||
|
{
|
||||||
|
sk_X509_push(allCertificates, certificate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STACK_OF(X509)* usedCertificates = allCertificates ? allCertificates : 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(usedCertificates, issuerAndSerial->issuer, issuerAndSerial->serial);
|
||||||
|
|
||||||
|
if (!signer)
|
||||||
|
{
|
||||||
|
result.addCertificateMissingError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!X509_STORE_CTX_init(context, store, signer, usedCertificates))
|
||||||
|
{
|
||||||
|
result.addCertificateGenericError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!X509_STORE_CTX_set_purpose(context, X509_PURPOSE_SMIME_SIGN))
|
||||||
|
{
|
||||||
|
result.addCertificateGenericError();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long flags = X509_V_FLAG_TRUSTED_FIRST;
|
||||||
|
if (m_parameters.ignoreExpirationDate)
|
||||||
|
{
|
||||||
|
flags |= X509_V_FLAG_NO_CHECK_TIME;
|
||||||
|
}
|
||||||
|
X509_STORE_CTX_set_flags(context, flags);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We will add certificate info for all certificates
|
||||||
|
const int count = sk_X509_num(usedCertificates);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
result.addCertificateInfo(getCertificateInfo(sk_X509_value(usedCertificates, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
STACK_OF(X509)* validChain = X509_STORE_CTX_get0_chain(context);
|
||||||
|
const int count = sk_X509_num(validChain);
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
result.addCertificateInfo(getCertificateInfo(sk_X509_value(validChain, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
X509_STORE_CTX_cleanup(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allCertificates)
|
||||||
|
{
|
||||||
|
sk_X509_free(allCertificates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.addNoSignaturesError();
|
||||||
|
}
|
||||||
|
|
||||||
|
X509_STORE_CTX_free(context);
|
||||||
|
X509_STORE_free(store);
|
||||||
|
|
||||||
|
PKCS7_free(pkcs7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.addInvalidCertificateError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.hasCertificateError())
|
||||||
|
{
|
||||||
|
result.setFlag(PDFSignatureVerificationResult::Certificate_OK, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PDFSignatureVerificationResult PDFSignatureHandler_adbe_pkcs7_rsa_sha1::verify() const
|
PDFSignatureVerificationResult PDFSignatureHandler_adbe_pkcs7_rsa_sha1::verify() const
|
||||||
{
|
{
|
||||||
PDFSignatureVerificationResult result;
|
PDFSignatureVerificationResult result;
|
||||||
@ -699,7 +877,7 @@ X509* PDFSignatureHandler_adbe_pkcs7_rsa_sha1::createCertificate(size_t index) c
|
|||||||
if (certificates && index < certificates->size())
|
if (certificates && index < certificates->size())
|
||||||
{
|
{
|
||||||
const QByteArray& certificateSize = (*certificates)[index];
|
const QByteArray& certificateSize = (*certificates)[index];
|
||||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(certificateSize.data());
|
const unsigned char* data = convertByteArrayToUcharPtr(certificateSize);
|
||||||
return d2i_X509(nullptr, &data, certificateSize.size());
|
return d2i_X509(nullptr, &data, certificateSize.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -727,7 +905,7 @@ bool PDFSignatureHandler_adbe_pkcs7_rsa_sha1::getMessageDigest(const QByteArray&
|
|||||||
|
|
||||||
EVP_DigestInit(context, md);
|
EVP_DigestInit(context, md);
|
||||||
EVP_DigestUpdate(context, message.constData(), message.size());
|
EVP_DigestUpdate(context, message.constData(), message.size());
|
||||||
EVP_DigestFinal(context, reinterpret_cast<unsigned char*>(digest.data()), &messageDigestSize);
|
EVP_DigestFinal(context, convertByteArrayToUcharPtr(digest), &messageDigestSize);
|
||||||
|
|
||||||
EVP_MD_CTX_free(context);
|
EVP_MD_CTX_free(context);
|
||||||
return true;
|
return true;
|
||||||
@ -782,7 +960,6 @@ void PDFSignatureHandler_adbe_pkcs7_rsa_sha1::verifyRSACertificate(PDFSignatureV
|
|||||||
if (X509* currentCertificate = createCertificate(i))
|
if (X509* currentCertificate = createCertificate(i))
|
||||||
{
|
{
|
||||||
sk_X509_push(certificates, currentCertificate);
|
sk_X509_push(certificates, currentCertificate);
|
||||||
X509_free(currentCertificate);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -880,7 +1057,6 @@ void PDFSignatureHandler_adbe_pkcs7_rsa_sha1::verifyRSACertificate(PDFSignatureV
|
|||||||
X509_STORE_free(store);
|
X509_STORE_free(store);
|
||||||
|
|
||||||
sk_X509_free(certificates);
|
sk_X509_free(certificates);
|
||||||
X509_free(certificate);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -925,7 +1101,7 @@ void PDFSignatureHandler_adbe_pkcs7_rsa_sha1::verifyRSASignature(PDFSignatureVer
|
|||||||
const PDFSignature& signature = m_signatureField->getSignature();
|
const PDFSignature& signature = m_signatureField->getSignature();
|
||||||
const QByteArray& signKey = signature.getContents();
|
const QByteArray& signKey = signature.getContents();
|
||||||
|
|
||||||
const unsigned char* encryptedSign = reinterpret_cast<const unsigned char*>(signKey.constData());
|
const unsigned char* encryptedSign = convertByteArrayToUcharPtr(signKey);
|
||||||
const unsigned int encryptedSignLength = signKey.length();
|
const unsigned int encryptedSignLength = signKey.length();
|
||||||
if (ASN1_OCTET_STRING* encryptedString = d2i_ASN1_OCTET_STRING(nullptr, &encryptedSign, encryptedSignLength))
|
if (ASN1_OCTET_STRING* encryptedString = d2i_ASN1_OCTET_STRING(nullptr, &encryptedSign, encryptedSignLength))
|
||||||
{
|
{
|
||||||
@ -940,7 +1116,7 @@ void PDFSignatureHandler_adbe_pkcs7_rsa_sha1::verifyRSASignature(PDFSignatureVer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char* digest = reinterpret_cast<const unsigned char*>(digestBuffer.constData());
|
const unsigned char* digest = convertByteArrayToUcharPtr(digestBuffer);
|
||||||
const unsigned int digestLength = digestBuffer.length();
|
const unsigned int digestLength = digestBuffer.length();
|
||||||
|
|
||||||
const int verifyValue = RSA_verify(algorithmNID, digest, digestLength, encryptedString->data, encryptedString->length, rsa);
|
const int verifyValue = RSA_verify(algorithmNID, digest, digestLength, encryptedString->data, encryptedString->length, rsa);
|
||||||
@ -996,7 +1172,7 @@ BIO* PDFSignatureHandler_adbe_pkcs7_sha1::getSignedDataBuffer(PDFSignatureVerifi
|
|||||||
{
|
{
|
||||||
// Calculate SHA1
|
// Calculate SHA1
|
||||||
outputBuffer.resize(SHA_DIGEST_LENGTH);
|
outputBuffer.resize(SHA_DIGEST_LENGTH);
|
||||||
SHA1(reinterpret_cast<const unsigned char*>(temporaryBuffer.data()), temporaryBuffer.length(), reinterpret_cast<unsigned char*>(outputBuffer.data()));
|
SHA1(convertByteArrayToUcharPtr(temporaryBuffer), temporaryBuffer.length(), convertByteArrayToUcharPtr(outputBuffer));
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
|
|
||||||
return BIO_new_mem_buf(outputBuffer.data(), outputBuffer.length());
|
return BIO_new_mem_buf(outputBuffer.data(), outputBuffer.length());
|
||||||
@ -1213,7 +1389,7 @@ std::optional<PDFCertificateInfo> PDFCertificateInfo::getCertificateInfo(const Q
|
|||||||
std::optional<PDFCertificateInfo> result;
|
std::optional<PDFCertificateInfo> result;
|
||||||
|
|
||||||
PDFOpenSSLGlobalLock lock;
|
PDFOpenSSLGlobalLock lock;
|
||||||
const unsigned char* data = reinterpret_cast<const unsigned char*>(certificateData.constData());
|
const unsigned char* data = convertByteArrayToUcharPtr(certificateData);
|
||||||
if (X509* certificate = d2i_X509(nullptr, &data, certificateData.length()))
|
if (X509* certificate = d2i_X509(nullptr, &data, certificateData.length()))
|
||||||
{
|
{
|
||||||
result = PDFPublicKeySignatureHandler::getCertificateInfo(certificate);
|
result = PDFPublicKeySignatureHandler::getCertificateInfo(certificate);
|
||||||
@ -1292,7 +1468,7 @@ void PDFCertificateStore::serialize(QDataStream& stream) const
|
|||||||
stream << m_certificates;
|
stream << m_certificates;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pdf::PDFCertificateStore::deserialize(QDataStream& stream)
|
void PDFCertificateStore::deserialize(QDataStream& stream)
|
||||||
{
|
{
|
||||||
int persist_version = 0;
|
int persist_version = 0;
|
||||||
stream >> persist_version;
|
stream >> persist_version;
|
||||||
@ -1320,7 +1496,7 @@ bool PDFCertificateStore::add(EntryType type, PDFCertificateInfo info)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pdf::PDFCertificateStore::contains(const pdf::PDFCertificateInfo& info)
|
bool PDFCertificateStore::contains(const PDFCertificateInfo& info)
|
||||||
{
|
{
|
||||||
return std::find_if(m_certificates.cbegin(), m_certificates.cend(), [&info](const auto& entry) { return entry.info == info; }) != m_certificates.cend();
|
return std::find_if(m_certificates.cbegin(), m_certificates.cend(), [&info](const auto& entry) { return entry.info == info; }) != m_certificates.cend();
|
||||||
}
|
}
|
||||||
@ -1341,7 +1517,7 @@ void pdf::PDFPublicKeySignatureHandler::addTrustedCertificates(X509_STORE* store
|
|||||||
for (const auto& entry : certificates)
|
for (const auto& entry : certificates)
|
||||||
{
|
{
|
||||||
QByteArray certificateData = entry.info.getCertificateData();
|
QByteArray certificateData = entry.info.getCertificateData();
|
||||||
const unsigned char* pointer = reinterpret_cast<const unsigned char*>(certificateData.constData());
|
const unsigned char* pointer = convertByteArrayToUcharPtr(certificateData);
|
||||||
X509* certificate = d2i_X509(nullptr, &pointer, certificateData.length());
|
X509* certificate = d2i_X509(nullptr, &pointer, certificateData.length());
|
||||||
if (certificate)
|
if (certificate)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,7 @@ class PDFForm;
|
|||||||
class PDFObjectStorage;
|
class PDFObjectStorage;
|
||||||
class PDFCertificateStore;
|
class PDFCertificateStore;
|
||||||
class PDFFormFieldSignature;
|
class PDFFormFieldSignature;
|
||||||
|
class PDFDocumentSecurityStore;
|
||||||
|
|
||||||
/// Signature reference dictionary.
|
/// Signature reference dictionary.
|
||||||
class PDFSignatureReference
|
class PDFSignatureReference
|
||||||
@ -375,6 +376,7 @@ public:
|
|||||||
struct Parameters
|
struct Parameters
|
||||||
{
|
{
|
||||||
const PDFCertificateStore* store = nullptr;
|
const PDFCertificateStore* store = nullptr;
|
||||||
|
const PDFDocumentSecurityStore* dss = nullptr;
|
||||||
bool enableVerification = true;
|
bool enableVerification = true;
|
||||||
bool ignoreExpirationDate = false;
|
bool ignoreExpirationDate = false;
|
||||||
bool useSystemCertificateStore = true;
|
bool useSystemCertificateStore = true;
|
||||||
|
@ -113,6 +113,21 @@ protected:
|
|||||||
virtual BIO* getSignedDataBuffer(PDFSignatureVerificationResult& result, QByteArray& outputBuffer) const override;
|
virtual BIO* getSignedDataBuffer(PDFSignatureVerificationResult& result, QByteArray& outputBuffer) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PDFSignatureHandler_ETSI_CAdES_detached : public PDFPublicKeySignatureHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFSignatureHandler_ETSI_CAdES_detached(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters) :
|
||||||
|
PDFPublicKeySignatureHandler(signatureField, sourceData, parameters)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual PDFSignatureVerificationResult verify() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void verifyCertificateCAdES(PDFSignatureVerificationResult& result) const;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
#endif // PDFSIGNATUREHANDLER_IMPL_H
|
||||||
|
@ -1007,6 +1007,7 @@ void PDFViewerMainWindow::openDocument(const QString& fileName)
|
|||||||
// Verify signatures
|
// Verify signatures
|
||||||
pdf::PDFSignatureHandler::Parameters parameters;
|
pdf::PDFSignatureHandler::Parameters parameters;
|
||||||
parameters.store = &m_certificateStore;
|
parameters.store = &m_certificateStore;
|
||||||
|
parameters.dss = &document.getCatalog()->getDocumentSecurityStore();
|
||||||
parameters.enableVerification = m_settings->getSettings().m_signatureVerificationEnabled;
|
parameters.enableVerification = m_settings->getSettings().m_signatureVerificationEnabled;
|
||||||
parameters.ignoreExpirationDate = m_settings->getSettings().m_signatureIgnoreCertificateValidityTime;
|
parameters.ignoreExpirationDate = m_settings->getSettings().m_signatureIgnoreCertificateValidityTime;
|
||||||
parameters.useSystemCertificateStore = m_settings->getSettings().m_signatureUseSystemStore;
|
parameters.useSystemCertificateStore = m_settings->getSettings().m_signatureUseSystemStore;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user