diff --git a/PdfForQtLib/sources/pdfsignaturehandler.cpp b/PdfForQtLib/sources/pdfsignaturehandler.cpp index 6a6de86..af539eb 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler.cpp +++ b/PdfForQtLib/sources/pdfsignaturehandler.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -449,6 +450,16 @@ QString PDFSignatureVerificationResult::getStatusText(Status status) return QString(); } +const PDFClosedIntervalSet& PDFSignatureVerificationResult::getBytesCoveredBySignature() const +{ + return m_bytesCoveredBySignature; +} + +void PDFSignatureVerificationResult::setBytesCoveredBySignature(const PDFClosedIntervalSet& bytesCoveredBySignature) +{ + m_bytesCoveredBySignature = bytesCoveredBySignature; +} + PDFSignature::Type PDFSignatureVerificationResult::getType() const { return m_type; @@ -702,6 +713,8 @@ BIO* PDFPublicKeySignatureHandler::getSignedDataBuffer(pdf::PDFSignatureVerifica result.addSignatureNotCoveredBytesWarning(notCoveredBytes); } + result.setBytesCoveredBySignature(qMove(bytesCoveredBySignature)); + return BIO_new_mem_buf(outputBuffer.data(), outputBuffer.length()); } @@ -1933,6 +1946,7 @@ QString PDFCertificateStore::getDefaultCertificateStoreFileName() const void PDFCertificateStore::loadDefaultUserCertificates() { + createDirectoryForDefaultUserCertificatesStore(); QString trustedCertificateStoreFileName = getDefaultCertificateStoreFileName(); QString trustedCertificateStoreLockFileName = trustedCertificateStoreFileName + ".lock"; @@ -1952,6 +1966,7 @@ void PDFCertificateStore::loadDefaultUserCertificates() void PDFCertificateStore::saveDefaultUserCertificates() { + createDirectoryForDefaultUserCertificatesStore(); QString trustedCertificateStoreFileName = getDefaultCertificateStoreFileName(); QString trustedCertificateStoreLockFileName = trustedCertificateStoreFileName + ".lock"; @@ -1973,6 +1988,13 @@ void PDFCertificateStore::saveDefaultUserCertificates() } } +void PDFCertificateStore::createDirectoryForDefaultUserCertificatesStore() +{ + QFileInfo fileInfo(getDefaultCertificateStoreFileName()); + QString path = fileInfo.path(); + QDir().mkpath(path); +} + } // namespace pdf #ifdef Q_OS_WIN diff --git a/PdfForQtLib/sources/pdfsignaturehandler.h b/PdfForQtLib/sources/pdfsignaturehandler.h index 57fd842..47dde68 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler.h +++ b/PdfForQtLib/sources/pdfsignaturehandler.h @@ -20,6 +20,7 @@ #include "pdfglobal.h" #include "pdfobject.h" +#include "pdfutils.h" #include #include @@ -406,6 +407,9 @@ public: 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; @@ -418,6 +422,7 @@ private: QStringList m_hashAlgorithms; QByteArray m_signatureHandler; PDFCertificateInfos m_certificateInfos; + PDFClosedIntervalSet m_bytesCoveredBySignature; }; /// Signature handler. Can verify both certificate and signature validity. @@ -524,6 +529,9 @@ public: /// Save to default user certificate storage void saveDefaultUserCertificates(); + /// Creates default directory for certificate store + void createDirectoryForDefaultUserCertificatesStore(); + private: static constexpr int persist_version = 1; diff --git a/PdfForQtLib/sources/pdfutils.cpp b/PdfForQtLib/sources/pdfutils.cpp index 5dd07c1..9f7afbc 100644 --- a/PdfForQtLib/sources/pdfutils.cpp +++ b/PdfForQtLib/sources/pdfutils.cpp @@ -296,6 +296,18 @@ PDFInteger PDFClosedIntervalSet::getTotalLength() const return std::accumulate(m_intervals.cbegin(), m_intervals.cend(), 0, [](PDFInteger count, const auto& b) { return count + b.second - b.first + 1; }); } +QString PDFClosedIntervalSet::toText() const +{ + QStringList intervals; + + for (const ClosedInterval& interval : m_intervals) + { + intervals << QString("[%1 - %2]").arg(interval.first).arg(interval.second); + } + + return intervals.join(", "); +} + void PDFClosedIntervalSet::normalize() { // Algorithm: diff --git a/PdfForQtLib/sources/pdfutils.h b/PdfForQtLib/sources/pdfutils.h index 4b8c731..cf19300 100644 --- a/PdfForQtLib/sources/pdfutils.h +++ b/PdfForQtLib/sources/pdfutils.h @@ -583,7 +583,7 @@ private: }; /// Set of closed intervals -class PDFClosedIntervalSet +class PDFFORQTLIBSHARED_EXPORT PDFClosedIntervalSet { public: explicit inline PDFClosedIntervalSet() = default; @@ -611,6 +611,9 @@ public: /// Returns sum of interval lengths PDFInteger getTotalLength() const; + /// Transforms interval set to readable text + QString toText() const; + private: /// Normalizes interval ranges - merges adjacent intervals void normalize(); diff --git a/PdfTool/pdftoolverifysignatures.cpp b/PdfTool/pdftoolverifysignatures.cpp index 4aef4de..8b563ac 100644 --- a/PdfTool/pdftoolverifysignatures.cpp +++ b/PdfTool/pdftoolverifysignatures.cpp @@ -200,6 +200,32 @@ int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options) formatter.writeText("handler", PDFToolTranslationContext::tr("Handler: %1").arg(QString::fromLatin1(signature.getSignatureHandler()))); formatter.writeText("whole-signed", PDFToolTranslationContext::tr("Is whole document signed: %1").arg(signature.hasFlag(pdf::PDFSignatureVerificationResult::Warning_Signature_NotCoveredBytes) ? PDFToolTranslationContext::tr("No") : PDFToolTranslationContext::tr("Yes"))); + // Signature range + const pdf::PDFClosedIntervalSet& bytesCoveredBySignature = signature.getBytesCoveredBySignature(); + formatter.writeText("byte-range", PDFToolTranslationContext::tr("Byte range covered by signature: %1").arg(bytesCoveredBySignature.toText())); + + if (signature.hasError()) + { + formatter.endl(); + formatter.beginHeader("errors", PDFToolTranslationContext::tr("Errors:")); + for (const QString& error : signature.getErrors()) + { + formatter.writeText("error", error); + } + formatter.endHeader(); + } + + if (signature.hasWarning()) + { + formatter.endl(); + formatter.beginHeader("warnings", PDFToolTranslationContext::tr("Warnings:")); + for (const QString& warning : signature.getWarnings()) + { + formatter.writeText("warning", warning); + } + formatter.endHeader(); + } + formatter.endl(); if (!options.verificationOmitCertificateCheck)