2021-09-27 11:14:20 +02:00
|
|
|
// Copyright (C) 2020-2021 Jakub Melka
|
|
|
|
//
|
|
|
|
// This file is part of PDF4QT.
|
|
|
|
//
|
|
|
|
// PDF4QT is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// with the written consent of the copyright owner, any later version.
|
|
|
|
//
|
|
|
|
// PDF4QT is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#ifndef PDFSIGNATUREHANDLER_H
|
|
|
|
#define PDFSIGNATUREHANDLER_H
|
|
|
|
|
|
|
|
#include "pdfglobal.h"
|
|
|
|
#include "pdfobject.h"
|
|
|
|
#include "pdfutils.h"
|
|
|
|
|
|
|
|
#include <QString>
|
|
|
|
#include <QDateTime>
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
|
|
|
|
class QDataStream;
|
|
|
|
|
|
|
|
namespace pdf
|
|
|
|
{
|
|
|
|
class PDFForm;
|
|
|
|
class PDFObjectStorage;
|
|
|
|
class PDFCertificateStore;
|
|
|
|
class PDFFormFieldSignature;
|
|
|
|
class PDFDocumentSecurityStore;
|
|
|
|
|
|
|
|
/// Signature reference dictionary.
|
|
|
|
class PDFSignatureReference
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
enum class TransformMethod
|
|
|
|
{
|
|
|
|
Invalid,
|
|
|
|
DocMDP,
|
|
|
|
UR,
|
|
|
|
FieldMDP
|
|
|
|
};
|
|
|
|
|
|
|
|
TransformMethod getTransformMethod() const { return m_transformMethod; }
|
|
|
|
const PDFObject& getTransformParams() const { return m_transformParams; }
|
|
|
|
const PDFObject& getData() const { return m_data; }
|
|
|
|
const QByteArray& getDigestMethod() const { return m_digestMethod; }
|
|
|
|
|
|
|
|
/// Tries to parse the signature reference. No exception is thrown, in case of error,
|
|
|
|
/// invalid signature reference object is returned.
|
|
|
|
/// \param storage Object storage
|
|
|
|
/// \param object Object containing the signature
|
|
|
|
static PDFSignatureReference parse(const PDFObjectStorage* storage, PDFObject object);
|
|
|
|
|
|
|
|
private:
|
|
|
|
TransformMethod m_transformMethod = TransformMethod::Invalid;
|
|
|
|
PDFObject m_transformParams;
|
|
|
|
PDFObject m_data;
|
|
|
|
QByteArray m_digestMethod;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Signature dictionary. Contains digital signature. This signature can be validated by signature validator.
|
|
|
|
/// This object contains certificates, digital signatures, and other information about signature.
|
|
|
|
class PDFSignature
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
enum class Type
|
|
|
|
{
|
|
|
|
Invalid,
|
|
|
|
Sig,
|
|
|
|
DocTimeStamp
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ByteRange
|
|
|
|
{
|
|
|
|
PDFInteger offset = 0;
|
|
|
|
PDFInteger size = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
using ByteRanges = std::vector<ByteRange>;
|
|
|
|
|
|
|
|
struct Changes
|
|
|
|
{
|
|
|
|
PDFInteger pagesAltered = 0;
|
|
|
|
PDFInteger fieldsAltered = 0;
|
|
|
|
PDFInteger fieldsFilled = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class AuthentificationType
|
|
|
|
{
|
|
|
|
Invalid,
|
|
|
|
PIN,
|
|
|
|
Password,
|
|
|
|
Fingerprint
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Tries to parse the signature. No exception is thrown, in case of error,
|
|
|
|
/// invalid signature object is returned.
|
|
|
|
/// \param storage Object storage
|
|
|
|
/// \param object Object containing the signature
|
|
|
|
static PDFSignature parse(const PDFObjectStorage* storage, PDFObject object);
|
|
|
|
|
|
|
|
Type getType() const { return m_type; }
|
|
|
|
const QByteArray& getFilter() const { return m_filter; }
|
|
|
|
const QByteArray& getSubfilter() const { return m_subfilter; }
|
|
|
|
const QByteArray& getContents() const { return m_contents; }
|
|
|
|
const std::vector<QByteArray>* getCertificates() const { return m_certificates.has_value() ? &m_certificates.value() : nullptr; }
|
|
|
|
const ByteRanges& getByteRanges() const { return m_byteRanges; }
|
|
|
|
const std::vector<PDFSignatureReference>& getReferences() const { return m_references; }
|
|
|
|
const Changes* getChanges() const { return m_changes.has_value() ? &m_changes.value() : nullptr; }
|
|
|
|
|
|
|
|
const QString& getName() const { return m_name; }
|
|
|
|
const QDateTime& getSigningDateTime() const { return m_signingDateTime; }
|
|
|
|
const QString& getLocation() const { return m_location; }
|
|
|
|
const QString& getReason() const { return m_reason; }
|
|
|
|
const QString& getContactInfo() const { return m_contactInfo; }
|
|
|
|
PDFInteger getR() const { return m_R; }
|
|
|
|
PDFInteger getV() const { return m_V; }
|
|
|
|
const PDFObject& getPropBuild() const { return m_propBuild; }
|
|
|
|
PDFInteger getPropTime() const { return m_propTime; }
|
|
|
|
AuthentificationType getAuthentificationType() const { return m_propType; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Type m_type = Type::Invalid;
|
|
|
|
QByteArray m_filter; ///< Preferred signature handler name
|
|
|
|
QByteArray m_subfilter; ///< Describes encoding of signature
|
|
|
|
QByteArray m_contents;
|
|
|
|
std::optional<std::vector<QByteArray>> m_certificates; ///< Certificate chain (only for adbe.x509.rsa_sha1)
|
|
|
|
ByteRanges m_byteRanges;
|
|
|
|
std::vector<PDFSignatureReference> m_references;
|
|
|
|
std::optional<Changes> m_changes;
|
|
|
|
|
|
|
|
QString m_name; ///< Name of signer. Should rather be extracted from signature.
|
|
|
|
QDateTime m_signingDateTime; ///< Signing date and time. Should be extracted from signature, if possible.
|
|
|
|
QString m_location; ///< CPU hostname or physical location of signing
|
|
|
|
QString m_reason; ///< Reason for signing
|
|
|
|
QString m_contactInfo; ///< Contact info for verifying the signature
|
|
|
|
PDFInteger m_R; ///< Version of signature handler. Obsolete.
|
|
|
|
PDFInteger m_V; ///< Version of signature dictionary format. 1 if References should be used.
|
|
|
|
PDFObject m_propBuild;
|
|
|
|
PDFInteger m_propTime = 0;
|
|
|
|
AuthentificationType m_propType = AuthentificationType::Invalid;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Info about certificate, various details etc.
|
|
|
|
class PDF4QTLIBSHARED_EXPORT PDFCertificateInfo
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit inline PDFCertificateInfo() = default;
|
|
|
|
|
|
|
|
void serialize(QDataStream& stream) const;
|
|
|
|
void deserialize(QDataStream& stream);
|
|
|
|
|
|
|
|
friend inline QDataStream& operator<<(QDataStream& stream, const PDFCertificateInfo& info) { info.serialize(stream); return stream; }
|
|
|
|
friend inline QDataStream& operator>>(QDataStream& stream, PDFCertificateInfo& info) { info.deserialize(stream); return stream; }
|
|
|
|
|
|
|
|
bool operator ==(const PDFCertificateInfo&) const = default;
|
|
|
|
bool operator !=(const PDFCertificateInfo&) const = default;
|
|
|
|
|
|
|
|
/// These entries are taken from RFC 5280, section 4.1.2.4,
|
|
|
|
/// they are supported and loaded from the certificate, with
|
|
|
|
/// exception of Email entry.
|
|
|
|
enum NameEntry
|
|
|
|
{
|
|
|
|
CountryName,
|
|
|
|
OrganizationName,
|
|
|
|
OrganizationalUnitName,
|
|
|
|
DistinguishedName,
|
|
|
|
StateOrProvinceName,
|
|
|
|
CommonName,
|
|
|
|
SerialNumber,
|
|
|
|
LocalityName,
|
|
|
|
Title,
|
|
|
|
Surname,
|
|
|
|
GivenName,
|
|
|
|
Initials,
|
|
|
|
Pseudonym,
|
|
|
|
GenerationalQualifier,
|
|
|
|
Email,
|
|
|
|
NameEnd
|
|
|
|
};
|
|
|
|
|
|
|
|
enum PublicKey
|
|
|
|
{
|
|
|
|
KeyRSA,
|
|
|
|
KeyDSA,
|
|
|
|
KeyEC,
|
|
|
|
KeyDH,
|
|
|
|
KeyUnknown
|
|
|
|
};
|
|
|
|
|
|
|
|
// This enum is defined in RFC 5280, chapter 4.2.1.3, Key Usage. Second part,
|
|
|
|
// are defined in extended key usage entry, if it is defined.
|
|
|
|
enum KeyUsageFlag : uint32_t
|
|
|
|
{
|
|
|
|
KeyUsageNone = 0x00000000,
|
|
|
|
KeyUsageDigitalSignature = 0x00000080,
|
|
|
|
KeyUsageNonRepudiation = 0x00000040,
|
|
|
|
KeyUsageKeyEncipherment = 0x00000020,
|
|
|
|
KeyUsageDataEncipherment = 0x00000010,
|
|
|
|
KeyUsageAgreement = 0x00000008,
|
|
|
|
KeyUsageCertSign = 0x00000004,
|
|
|
|
KeyUsageCrlSign = 0x00000002,
|
|
|
|
KeyUsageEncipherOnly = 0x00000001,
|
|
|
|
KeyUsageDecipherOnly = 0x00008000,
|
|
|
|
|
|
|
|
KeyUsageExtended_SSL_SERVER = 0x1 << 16,
|
|
|
|
KeyUsageExtended_SSL_CLIENT = 0x2 << 16,
|
|
|
|
KeyUsageExtended_SMIME = 0x4 << 16,
|
|
|
|
KeyUsageExtended_CODE_SIGN = 0x8 << 16,
|
|
|
|
KeyUsageExtended_SGC = 0x10 << 16,
|
|
|
|
KeyUsageExtended_OCSP_SIGN = 0x20 << 16,
|
|
|
|
KeyUsageExtended_TIMESTAMP = 0x40 << 16,
|
|
|
|
KeyUsageExtended_DVCS = 0x80 << 16,
|
|
|
|
KeyUsageExtended_ANYEKU = 0x100 << 16,
|
|
|
|
};
|
|
|
|
Q_DECLARE_FLAGS(KeyUsageFlags, KeyUsageFlag)
|
|
|
|
|
|
|
|
const QString& getName(NameEntry name) const { return m_nameEntries[name]; }
|
|
|
|
void setName(NameEntry name, QString string) { m_nameEntries[name] = qMove(string); }
|
|
|
|
|
|
|
|
QDateTime getNotValidBefore() const;
|
|
|
|
void setNotValidBefore(const QDateTime& notValidBefore);
|
|
|
|
|
|
|
|
QDateTime getNotValidAfter() const;
|
|
|
|
void setNotValidAfter(const QDateTime& notValidAfter);
|
|
|
|
|
|
|
|
int32_t getVersion() const;
|
|
|
|
void setVersion(int32_t version);
|
|
|
|
|
|
|
|
PublicKey getPublicKey() const;
|
|
|
|
void setPublicKey(const PublicKey& publicKey);
|
|
|
|
|
|
|
|
int getKeySize() const;
|
|
|
|
void setKeySize(int keySize);
|
|
|
|
|
|
|
|
KeyUsageFlags getKeyUsage() const;
|
|
|
|
void setKeyUsage(KeyUsageFlags keyUsage);
|
|
|
|
|
|
|
|
QByteArray getCertificateData() const;
|
|
|
|
void setCertificateData(const QByteArray& certificateData);
|
|
|
|
|
|
|
|
/// Creates certificate info from binary data. Binary data must
|
|
|
|
/// contain DER-encoded certificate.
|
|
|
|
/// \param certificateData Data
|
|
|
|
static std::optional<PDFCertificateInfo> getCertificateInfo(const QByteArray& certificateData);
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr int persist_version = 1;
|
|
|
|
|
|
|
|
int32_t m_version = 0;
|
|
|
|
int m_keySize = 0;
|
|
|
|
PublicKey m_publicKey = KeyUnknown;
|
|
|
|
std::array<QString, NameEnd> m_nameEntries;
|
|
|
|
QDateTime m_notValidBefore;
|
|
|
|
QDateTime m_notValidAfter;
|
|
|
|
KeyUsageFlags m_keyUsage;
|
|
|
|
QByteArray m_certificateData;
|
|
|
|
};
|
|
|
|
|
|
|
|
using PDFCertificateInfos = std::vector<PDFCertificateInfo>;
|
|
|
|
|
|
|
|
class PDF4QTLIBSHARED_EXPORT PDFSignatureVerificationResult
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit PDFSignatureVerificationResult() = default;
|
|
|
|
explicit PDFSignatureVerificationResult(PDFSignature::Type type, PDFObjectReference signatureFieldReference, QString qualifiedName) :
|
|
|
|
m_type(type),
|
|
|
|
m_signatureFieldReference(signatureFieldReference),
|
|
|
|
m_signatureFieldQualifiedName(qualifiedName)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class Status
|
|
|
|
{
|
|
|
|
OK,
|
|
|
|
Warning,
|
|
|
|
Error
|
|
|
|
};
|
|
|
|
|
|
|
|
enum VerificationFlag
|
|
|
|
{
|
|
|
|
None = 0x00000000, ///< Used only for initialization
|
|
|
|
OK = 0x00000001, ///< Both certificate and signature is OK
|
|
|
|
Certificate_OK = 0x00000002, ///< Certificate is OK
|
|
|
|
Signature_OK = 0x00000004, ///< Signature is OK
|
|
|
|
Error_NoHandler = 0x00000008, ///< No signature handler for given signature
|
|
|
|
Error_Generic = 0x00000010, ///< Generic error (uknown general error)
|
|
|
|
|
|
|
|
Error_Certificate_Invalid = 0x00000020, ///< Certificate is invalid
|
|
|
|
Error_Certificate_NoSignatures = 0x00000040, ///< No signature found in certificate data
|
|
|
|
Error_Certificate_Missing = 0x00000080, ///< Certificate is missing
|
|
|
|
Error_Certificate_Generic = 0x00000100, ///< Generic error during certificate verification
|
|
|
|
Error_Certificate_Expired = 0x00000200, ///< Certificate has expired
|
|
|
|
Error_Certificate_SelfSigned = 0x00000400, ///< Self signed certificate
|
|
|
|
Error_Certificate_SelfSignedChain = 0x00000800, ///< Self signed certificate in chain
|
|
|
|
Error_Certificate_TrustedNotFound = 0x00001000, ///< No trusted certificate was found
|
|
|
|
Error_Certificate_Revoked = 0x00002000, ///< Certificate has been revoked
|
|
|
|
Error_Certificate_Other = 0x00004000, ///< Other certificate error. See OpenSSL code for details.
|
|
|
|
|
|
|
|
Error_Signature_Invalid = 0x00008000, ///< Signature is invalid for some reason
|
|
|
|
Error_Signature_SourceCertificateMissing = 0x00010000, ///< Source certificate of signature is missing
|
|
|
|
Error_Signature_NoSignaturesFound = 0x00020000, ///< No signatures found
|
|
|
|
Error_Signature_DigestFailure = 0x00040000, ///< Digest failure
|
|
|
|
Error_Signature_DataOther = 0x00080000, ///< Signed data were not verified
|
|
|
|
Error_Signature_DataCoveredBySignatureMissing = 0x00100000, ///< Data covered by signature are not present
|
|
|
|
|
|
|
|
Warning_Signature_NotCoveredBytes = 0x00200000, ///< Some bytes in source data are not covered by signature
|
|
|
|
Warning_Certificate_CRLValidityTimeExpired = 0x00400000, ///< Certificate revocation list was not checked, because it's validity expired
|
|
|
|
Warning_Certificate_QualifiedStatement = 0x00800000, ///< Qualified certificate statement not verified
|
|
|
|
|
|
|
|
Error_Certificates_Mask = Error_Certificate_Invalid | Error_Certificate_NoSignatures | Error_Certificate_Missing | Error_Certificate_Generic |
|
|
|
|
Error_Certificate_Expired | Error_Certificate_SelfSigned | Error_Certificate_SelfSignedChain | Error_Certificate_TrustedNotFound |
|
|
|
|
Error_Certificate_Revoked | Error_Certificate_Other,
|
|
|
|
|
|
|
|
Error_Signatures_Mask = Error_Signature_Invalid | Error_Signature_SourceCertificateMissing | Error_Signature_NoSignaturesFound |
|
|
|
|
Error_Signature_DigestFailure | Error_Signature_DataOther | Error_Signature_DataCoveredBySignatureMissing,
|
|
|
|
|
|
|
|
Warning_Certificates_Mask = Warning_Certificate_CRLValidityTimeExpired | Warning_Certificate_QualifiedStatement,
|
|
|
|
Warning_Signatures_Mask = Warning_Signature_NotCoveredBytes,
|
|
|
|
|
|
|
|
Warnings_Mask = Warning_Certificates_Mask | Warning_Signatures_Mask
|
|
|
|
};
|
|
|
|
Q_DECLARE_FLAGS(VerificationFlags, VerificationFlag)
|
|
|
|
|
|
|
|
PDFSignature::Type getType() const;
|
|
|
|
void setType(const PDFSignature::Type& type);
|
|
|
|
|
|
|
|
/// 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);
|
|
|
|
void addInvalidSignatureError();
|
|
|
|
void addSignatureNoSignaturesFoundError();
|
|
|
|
void addSignatureCertificateMissingError();
|
|
|
|
void addSignatureDigestFailureError();
|
|
|
|
void addSignatureDataOtherError();
|
|
|
|
void addSignatureDataCoveredBySignatureMissingError();
|
|
|
|
|
|
|
|
void addSignatureNotCoveredBytesWarning(PDFInteger count);
|
|
|
|
void addCertificateCRLValidityTimeExpiredWarning();
|
|
|
|
void addCertificateQualifiedStatementNotVerifiedWarning();
|
|
|
|
|
|
|
|
bool isValid() const { return hasFlag(OK); }
|
|
|
|
bool isCertificateValid() const { return hasFlag(Certificate_OK); }
|
|
|
|
bool isSignatureValid() const { return hasFlag(Signature_OK); }
|
|
|
|
bool hasError() const { return !isValid(); }
|
|
|
|
bool hasWarning() const { return m_flags & Warnings_Mask; }
|
|
|
|
bool hasCertificateError() const { return m_flags & Error_Certificates_Mask; }
|
|
|
|
bool hasSignatureError() const { return m_flags & Error_Signatures_Mask; }
|
|
|
|
bool hasCertificateWarning() const { return m_flags & Warning_Certificates_Mask; }
|
|
|
|
bool hasSignatureWarning() const { return m_flags & Warning_Signatures_Mask; }
|
|
|
|
bool hasFlag(VerificationFlag flag) const { return m_flags.testFlag(flag); }
|
|
|
|
void setFlag(VerificationFlag flag, bool value) { m_flags.setFlag(flag, value); }
|
|
|
|
|
|
|
|
PDFObjectReference getSignatureFieldReference() const { return m_signatureFieldReference; }
|
|
|
|
const QString& getSignatureFieldQualifiedName() const { return m_signatureFieldQualifiedName; }
|
|
|
|
const QStringList& getErrors() const { return m_errors; }
|
|
|
|
const QStringList& getWarnings() const { return m_warnings; }
|
|
|
|
const QStringList& getHashAlgorithms() const { return m_hashAlgorithms; }
|
|
|
|
const PDFCertificateInfos& getCertificateInfos() const { return m_certificateInfos; }
|
|
|
|
|
|
|
|
void setSignatureFieldQualifiedName(const QString& signatureFieldQualifiedName);
|
|
|
|
void setSignatureFieldReference(PDFObjectReference signatureFieldReference);
|
|
|
|
|
|
|
|
void addCertificateInfo(PDFCertificateInfo info) { m_certificateInfos.emplace_back(qMove(info)); }
|
|
|
|
void addHashAlgorithm(const QString& algorithm);
|
|
|
|
|
|
|
|
/// Adds OK flag, if both certificate and signature are valid
|
|
|
|
void validate();
|
|
|
|
|
|
|
|
QDateTime getSignatureDate() const;
|
|
|
|
void setSignatureDate(const QDateTime& signatureDate);
|
|
|
|
|
|
|
|
QDateTime getTimestampDate() const;
|
|
|
|
void setTimestampDate(const QDateTime& timestampDate);
|
|
|
|
|
|
|
|
QByteArray getSignatureHandler() const;
|
|
|
|
void setSignatureHandler(const QByteArray& signatureFilter);
|
|
|
|
|
|
|
|
Status getCertificateStatus() const;
|
|
|
|
Status getSignatureStatus() const;
|
|
|
|
|
|
|
|
QString getCertificateStatusText() const { return getStatusText(getCertificateStatus()); }
|
|
|
|
QString getSignatureStatusText() const { return getStatusText(getSignatureStatus()); }
|
|
|
|
|
|
|
|
static QString getStatusText(Status status);
|
|
|
|
|
|
|
|
const PDFClosedIntervalSet& getBytesCoveredBySignature() const;
|
|
|
|
void setBytesCoveredBySignature(const PDFClosedIntervalSet& bytesCoveredBySignature);
|
|
|
|
|
|
|
|
private:
|
|
|
|
PDFSignature::Type m_type = PDFSignature::Type::Invalid;
|
|
|
|
VerificationFlags m_flags = None;
|
|
|
|
PDFObjectReference m_signatureFieldReference;
|
|
|
|
QString m_signatureFieldQualifiedName;
|
|
|
|
QDateTime m_signatureDate;
|
|
|
|
QDateTime m_timestampDate;
|
|
|
|
QStringList m_errors;
|
|
|
|
QStringList m_warnings;
|
|
|
|
QStringList m_hashAlgorithms;
|
|
|
|
QByteArray m_signatureHandler;
|
|
|
|
PDFCertificateInfos m_certificateInfos;
|
|
|
|
PDFClosedIntervalSet m_bytesCoveredBySignature;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Signature handler. Can verify both certificate and signature validity.
|
|
|
|
class PDF4QTLIBSHARED_EXPORT PDFSignatureHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit PDFSignatureHandler() = default;
|
|
|
|
virtual ~PDFSignatureHandler() = default;
|
|
|
|
|
|
|
|
virtual PDFSignatureVerificationResult verify() const = 0;
|
|
|
|
|
|
|
|
struct Parameters
|
|
|
|
{
|
|
|
|
const PDFCertificateStore* store = nullptr;
|
|
|
|
const PDFDocumentSecurityStore* dss = nullptr;
|
|
|
|
bool enableVerification = true;
|
|
|
|
bool ignoreExpirationDate = false;
|
|
|
|
bool useSystemCertificateStore = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Tries to verify all signatures in the form. If form is invalid, then
|
|
|
|
/// empty vector is returned.
|
|
|
|
/// \param form Form
|
|
|
|
/// \param sourceData Source data
|
|
|
|
/// \param parameters Verification settings
|
|
|
|
static std::vector<PDFSignatureVerificationResult> verifySignatures(const PDFForm& form, const QByteArray& sourceData, const Parameters& parameters);
|
|
|
|
|
|
|
|
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
|
|
|
|
/// \param parameters Verification settings
|
|
|
|
static PDFSignatureHandler* createHandler(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters);
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Trusted certificate store. Contains list of trusted certificates. Store
|
|
|
|
/// can be persisted to the persistent storage trough serialization/deserialization.
|
|
|
|
/// Persisting method is versioned.
|
|
|
|
class PDF4QTLIBSHARED_EXPORT PDFCertificateStore
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit inline PDFCertificateStore() = default;
|
|
|
|
|
|
|
|
void serialize(QDataStream& stream) const;
|
|
|
|
void deserialize(QDataStream& stream);
|
|
|
|
|
|
|
|
enum class EntryType : int
|
|
|
|
{
|
|
|
|
User, ///< Certificate has been added manually by the user
|
|
|
|
EUTL, ///< Certificate comes EU trusted list
|
|
|
|
System, ///< System certificate
|
|
|
|
};
|
|
|
|
|
|
|
|
struct CertificateEntry
|
|
|
|
{
|
|
|
|
void serialize(QDataStream& stream) const;
|
|
|
|
void deserialize(QDataStream& stream);
|
|
|
|
|
|
|
|
friend inline QDataStream& operator<<(QDataStream& stream, const CertificateEntry& entry) { entry.serialize(stream); return stream; }
|
|
|
|
friend inline QDataStream& operator>>(QDataStream& stream, CertificateEntry& entry) { entry.deserialize(stream); return stream; }
|
|
|
|
|
|
|
|
static constexpr int persist_version = 1;
|
|
|
|
EntryType type = EntryType::User;
|
|
|
|
PDFCertificateInfo info;
|
|
|
|
};
|
|
|
|
|
|
|
|
using CertificateEntries = std::vector<CertificateEntry>;
|
|
|
|
|
|
|
|
/// Tries to add new certificate to the certificate store. If certificate
|
|
|
|
/// is already here, then nothing happens and function returns true.
|
|
|
|
/// Otherwise data are checked, if they really contains a certificate,
|
|
|
|
/// and if yes, then it is added. Function returns false if, and only if,
|
|
|
|
/// error occured and certificate was not added.
|
|
|
|
/// \param type Type
|
|
|
|
/// \param certificate Certificate
|
|
|
|
bool add(EntryType type, const QByteArray& certificate);
|
|
|
|
|
|
|
|
/// Tries to add new certificate to the certificate store. If certificate
|
|
|
|
/// is already here, then nothing happens and function returns true.
|
|
|
|
/// Otherwise data are checked, if they really contains a certificate,
|
|
|
|
/// and if yes, then it is added. Function returns false if, and only if,
|
|
|
|
/// error occured and certificate was not added.
|
|
|
|
/// \param type Type
|
|
|
|
/// \param info Certificate info
|
|
|
|
bool add(EntryType type, PDFCertificateInfo info);
|
|
|
|
|
|
|
|
/// Returns true, if storage contains given certificate
|
|
|
|
/// \param info Certificate info
|
|
|
|
bool contains(const PDFCertificateInfo& info);
|
|
|
|
|
|
|
|
/// Get certificates stored in the store
|
|
|
|
const CertificateEntries& getCertificates() const { return m_certificates; }
|
|
|
|
|
|
|
|
/// Set certificates
|
|
|
|
void setCertificates(CertificateEntries certificates) { m_certificates = qMove(certificates); }
|
|
|
|
|
|
|
|
/// Returns default certificate store file name
|
|
|
|
QString getDefaultCertificateStoreFileName() const;
|
|
|
|
|
|
|
|
/// Load from default user certificate storage
|
|
|
|
void loadDefaultUserCertificates();
|
|
|
|
|
|
|
|
/// Save to default user certificate storage
|
|
|
|
void saveDefaultUserCertificates();
|
|
|
|
|
|
|
|
/// Creates default directory for certificate store
|
|
|
|
void createDirectoryForDefaultUserCertificatesStore();
|
|
|
|
|
|
|
|
/// Returns a list of system certificates
|
|
|
|
static CertificateEntries getSystemCertificates();
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr int persist_version = 1;
|
|
|
|
|
|
|
|
CertificateEntries m_certificates;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace pdf
|
|
|
|
|
|
|
|
#endif // PDFSIGNATUREHANDLER_H
|