mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Digital signatures verification tool (first part)
This commit is contained in:
@@ -15,8 +15,6 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
QT -= gui
|
||||
|
||||
CONFIG += c++11 console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
@@ -43,7 +41,8 @@ LIBS += -lPDFForQtLib
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
pdfoutputformatter.cpp \
|
||||
pdftoolabstractapplication.cpp
|
||||
pdftoolabstractapplication.cpp \
|
||||
pdftoolverifysignatures.cpp
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
@@ -56,4 +55,5 @@ INSTALLS += application
|
||||
|
||||
HEADERS += \
|
||||
pdfoutputformatter.h \
|
||||
pdftoolabstractapplication.h
|
||||
pdftoolabstractapplication.h \
|
||||
pdftoolverifysignatures.h
|
||||
|
@@ -630,4 +630,13 @@ void PDFConsole::writeText(QString text)
|
||||
#endif
|
||||
}
|
||||
|
||||
void PDFConsole::writeError(QString text)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), text.utf16(), text.size(), nullptr, nullptr);
|
||||
#else
|
||||
QTextStream(stdout) << text;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // pdftool
|
||||
|
@@ -95,6 +95,9 @@ public:
|
||||
/// Writes text to the console
|
||||
static void writeText(QString text);
|
||||
|
||||
/// Writes error to the console
|
||||
static void writeError(QString text);
|
||||
|
||||
private:
|
||||
explicit PDFConsole() = delete;
|
||||
};
|
||||
|
@@ -130,12 +130,30 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser*
|
||||
{
|
||||
parser->addOption(QCommandLineOption("console-format", "Console output text format (valid values: text|xml|html).", "console-format", "text"));
|
||||
}
|
||||
|
||||
if (optionFlags.testFlag(OpenDocument))
|
||||
{
|
||||
parser->addOption(QCommandLineOption("pswd", "Password for encrypted document.", "password"));
|
||||
parser->addPositionalArgument("document", "Processed document.");
|
||||
parser->addOption(QCommandLineOption("no-permissive-reading", "Do not attempt to fix damaged documents."));
|
||||
}
|
||||
|
||||
if (optionFlags.testFlag(SignatureVerification))
|
||||
{
|
||||
parser->addOption(QCommandLineOption("ver-no-user-cert", "Disable user certificate store."));
|
||||
parser->addOption(QCommandLineOption("ver-no-sys-cert", "Disable system certificate store."));
|
||||
parser->addOption(QCommandLineOption("ver-no-cert-check", "Disable certificate validation."));
|
||||
parser->addOption(QCommandLineOption("ver-cert-details", "Print certificate details (including chain, if found)."));
|
||||
parser->addOption(QCommandLineOption("ver-ignore-exp-date", "Ignore certificate expiration date."));
|
||||
}
|
||||
}
|
||||
|
||||
PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser) const
|
||||
{
|
||||
PDFToolOptions options;
|
||||
|
||||
QStringList positionalArguments = parser->positionalArguments();
|
||||
|
||||
Options optionFlags = getOptionsFlags();
|
||||
if (optionFlags.testFlag(ConsoleFormat))
|
||||
{
|
||||
@@ -154,10 +172,31 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!consoleFormat.isEmpty())
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("Unknown console format '%1'. Defaulting to text console format.").arg(consoleFormat));
|
||||
}
|
||||
|
||||
options.outputStyle = PDFOutputFormatter::Style::Text;
|
||||
}
|
||||
}
|
||||
|
||||
if (optionFlags.testFlag(OpenDocument))
|
||||
{
|
||||
options.document = positionalArguments.isEmpty() ? QString() : positionalArguments.front();
|
||||
options.password = parser->value("password");
|
||||
options.permissiveReading = !parser->isSet("no-permissive-reading");
|
||||
}
|
||||
|
||||
if (optionFlags.testFlag(SignatureVerification))
|
||||
{
|
||||
options.verificationUseUserCertificates = !parser->isSet("ver-no-user-cert");
|
||||
options.verificationUseSystemCertificates = !parser->isSet("ver-no-sys-cert");
|
||||
options.verificationOmitCertificateCheck = parser->isSet("ver-no-cert-check");
|
||||
options.verificationPrintCertificateDetails = parser->isSet("ver-cert-details");
|
||||
options.verificationIgnoreExpirationDate = parser->isSet("ver-ignore-exp-date");
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@@ -38,9 +38,20 @@ struct PDFToolTranslationContext
|
||||
|
||||
struct PDFToolOptions
|
||||
{
|
||||
// For option 'ConsoleFormat'
|
||||
PDFOutputFormatter::Style outputStyle = PDFOutputFormatter::Style::Text;
|
||||
|
||||
// For option 'OpenDocument'
|
||||
QString document;
|
||||
QString password;
|
||||
PDFOutputFormatter::Style outputStyle = PDFOutputFormatter::Style::Text;
|
||||
bool permissiveReading = true;
|
||||
|
||||
// For option 'SignatureVerification'
|
||||
bool verificationUseUserCertificates = true;
|
||||
bool verificationUseSystemCertificates = true;
|
||||
bool verificationOmitCertificateCheck = false;
|
||||
bool verificationPrintCertificateDetails = false;
|
||||
bool verificationIgnoreExpirationDate = false;
|
||||
};
|
||||
|
||||
/// Base class for all applications
|
||||
@@ -52,7 +63,9 @@ public:
|
||||
|
||||
enum ExitCodes
|
||||
{
|
||||
ExitSuccess = EXIT_SUCCESS
|
||||
ExitSuccess = EXIT_SUCCESS,
|
||||
ErrorNoDocumentSpecified,
|
||||
ErrorDocumentReading
|
||||
};
|
||||
|
||||
enum StandardString
|
||||
@@ -64,7 +77,9 @@ public:
|
||||
|
||||
enum Option
|
||||
{
|
||||
ConsoleFormat = 0x0001, ///< Set format of console output (text, xml or html)
|
||||
ConsoleFormat = 0x0001, ///< Set format of console output (text, xml or html)
|
||||
OpenDocument = 0x0002, ///< Flags for document reading
|
||||
SignatureVerification = 0x0004, ///< Flags for signature verification
|
||||
};
|
||||
Q_DECLARE_FLAGS(Options, Option)
|
||||
|
||||
|
118
PdfTool/pdftoolverifysignatures.cpp
Normal file
118
PdfTool/pdftoolverifysignatures.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt 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
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "pdftoolverifysignatures.h"
|
||||
|
||||
#include "pdfdocumentreader.h"
|
||||
#include "pdfsignaturehandler.h"
|
||||
#include "pdfform.h"
|
||||
|
||||
namespace pdftool
|
||||
{
|
||||
|
||||
static PDFToolVerifySignaturesApplication s_verifySignaturesApplication;
|
||||
|
||||
QString PDFToolVerifySignaturesApplication::getStandardString(StandardString standardString) const
|
||||
{
|
||||
switch (standardString)
|
||||
{
|
||||
case Command:
|
||||
return "verify-signatures";
|
||||
|
||||
case Name:
|
||||
return PDFToolTranslationContext::tr("Signature verification");
|
||||
|
||||
case Description:
|
||||
return PDFToolTranslationContext::tr("Verify signatures and timestamps in pdf document.");
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
int PDFToolVerifySignaturesApplication::execute(const PDFToolOptions& options)
|
||||
{
|
||||
// No document specified?
|
||||
if (options.document.isEmpty())
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("No document specified."));
|
||||
return ErrorNoDocumentSpecified;
|
||||
}
|
||||
|
||||
bool isFirstPasswordAttempt = true;
|
||||
auto passwordCallback = [&options, &isFirstPasswordAttempt](bool* ok) -> QString
|
||||
{
|
||||
*ok = isFirstPasswordAttempt;
|
||||
isFirstPasswordAttempt = false;
|
||||
return options.password;
|
||||
};
|
||||
pdf::PDFDocumentReader reader(nullptr, passwordCallback, options.permissiveReading);
|
||||
pdf::PDFDocument document = reader.readFromFile(options.document);
|
||||
|
||||
switch (reader.getReadingResult())
|
||||
{
|
||||
case pdf::PDFDocumentReader::Result::OK:
|
||||
break;
|
||||
|
||||
case pdf::PDFDocumentReader::Result::Cancelled:
|
||||
return ExitSuccess;
|
||||
|
||||
case pdf::PDFDocumentReader::Result::Failed:
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("Error occured during document reading. %1").arg(reader.getErrorMessage()));
|
||||
return ErrorDocumentReading;
|
||||
}
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return ErrorDocumentReading;
|
||||
}
|
||||
|
||||
for (const QString& warning : reader.getWarnings())
|
||||
{
|
||||
PDFConsole::writeError(PDFToolTranslationContext::tr("Warning: %1").arg(warning));
|
||||
}
|
||||
|
||||
// Verify signatures
|
||||
pdf::PDFCertificateStore certificateStore;
|
||||
if (options.verificationUseUserCertificates)
|
||||
{
|
||||
certificateStore.loadDefaultUserCertificates();
|
||||
}
|
||||
|
||||
pdf::PDFSignatureHandler::Parameters parameters;
|
||||
parameters.store = &certificateStore;
|
||||
parameters.dss = &document.getCatalog()->getDocumentSecurityStore();
|
||||
parameters.enableVerification = true;
|
||||
parameters.ignoreExpirationDate = options.verificationIgnoreExpirationDate;
|
||||
parameters.useSystemCertificateStore = options.verificationUseSystemCertificates;
|
||||
|
||||
pdf::PDFForm form = pdf::PDFForm::parse(&document, document.getCatalog()->getFormObject());
|
||||
std::vector<pdf::PDFSignatureVerificationResult> signatures = pdf::PDFSignatureHandler::verifySignatures(form, reader.getSource(), parameters);
|
||||
|
||||
return ExitSuccess;
|
||||
}
|
||||
|
||||
PDFToolAbstractApplication::Options PDFToolVerifySignaturesApplication::getOptionsFlags() const
|
||||
{
|
||||
return PDFToolAbstractApplication::ConsoleFormat | PDFToolAbstractApplication::OpenDocument | PDFToolAbstractApplication::SignatureVerification;
|
||||
}
|
||||
|
||||
} // namespace pdftool
|
36
PdfTool/pdftoolverifysignatures.h
Normal file
36
PdfTool/pdftoolverifysignatures.h
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2020 Jakub Melka
|
||||
//
|
||||
// This file is part of PdfForQt.
|
||||
//
|
||||
// PdfForQt 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
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PdfForQt 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 PDFForQt. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef PDFTOOLVERIFYSIGNATURES_H
|
||||
#define PDFTOOLVERIFYSIGNATURES_H
|
||||
|
||||
#include "pdftoolabstractapplication.h"
|
||||
|
||||
namespace pdftool
|
||||
{
|
||||
|
||||
class PDFToolVerifySignaturesApplication : public PDFToolAbstractApplication
|
||||
{
|
||||
public:
|
||||
virtual QString getStandardString(StandardString standardString) const override;
|
||||
virtual int execute(const PDFToolOptions& options) override;
|
||||
virtual Options getOptionsFlags() const override;
|
||||
};
|
||||
|
||||
} // namespace pdftool
|
||||
|
||||
#endif // PDFTOOLVERIFYSIGNATURES_H
|
Reference in New Issue
Block a user