diff --git a/PdfForQtLib/sources/pdfsignaturehandler.cpp b/PdfForQtLib/sources/pdfsignaturehandler.cpp index af539eb..38b0c74 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler.cpp +++ b/PdfForQtLib/sources/pdfsignaturehandler.cpp @@ -2044,3 +2044,33 @@ void pdf::PDFPublicKeySignatureHandler::addTrustedCertificates(X509_STORE* store } #endif } + +pdf::PDFCertificateStore::CertificateEntries pdf::PDFCertificateStore::getSystemCertificates() +{ + CertificateEntries result; + +#ifdef Q_OS_WIN + HCERTSTORE certStore = CertOpenSystemStore(NULL, L"ROOT"); + PCCERT_CONTEXT context = nullptr; + if (certStore) + { + while (context = CertEnumCertificatesInStore(certStore, context)) + { + const unsigned char* pointer = context->pbCertEncoded; + QByteArray data(reinterpret_cast(pointer), context->cbCertEncoded); + std::optional info = PDFCertificateInfo::getCertificateInfo(data); + if (info) + { + CertificateEntry entry; + entry.type = EntryType::System; + entry.info = qMove(*info); + result.emplace_back(qMove(entry)); + } + } + + CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG); + } +#endif + + return result; +} diff --git a/PdfForQtLib/sources/pdfsignaturehandler.h b/PdfForQtLib/sources/pdfsignaturehandler.h index 47dde68..8f8d315 100644 --- a/PdfForQtLib/sources/pdfsignaturehandler.h +++ b/PdfForQtLib/sources/pdfsignaturehandler.h @@ -473,8 +473,9 @@ public: enum class EntryType : int { - User, ///< Certificate has been added manually by the user - EUTL ///< Certificate comes EU trusted list + User, ///< Certificate has been added manually by the user + EUTL, ///< Certificate comes EU trusted list + System, ///< System certificate }; struct CertificateEntry @@ -532,6 +533,9 @@ public: /// Creates default directory for certificate store void createDirectoryForDefaultUserCertificatesStore(); + /// Returns a list of system certificates + static CertificateEntries getSystemCertificates(); + private: static constexpr int persist_version = 1; diff --git a/PdfForQtViewer/pdfviewersettingsdialog.cpp b/PdfForQtViewer/pdfviewersettingsdialog.cpp index b98d000..c7cd3aa 100644 --- a/PdfForQtViewer/pdfviewersettingsdialog.cpp +++ b/PdfForQtViewer/pdfviewersettingsdialog.cpp @@ -587,6 +587,10 @@ void PDFViewerSettingsDialog::updateTrustedCertificatesTable() type = tr("EUTL"); break; + case pdf::PDFCertificateStore::EntryType::System: + type = tr("System"); + break; + default: Q_ASSERT(false); break; diff --git a/PdfTool/PdfTool.pro b/PdfTool/PdfTool.pro index be80390..e5ff631 100644 --- a/PdfTool/PdfTool.pro +++ b/PdfTool/PdfTool.pro @@ -44,6 +44,7 @@ SOURCES += \ pdftoolabstractapplication.cpp \ pdftoolattachments.cpp \ pdftoolaudiobook.cpp \ + pdftoolcertstore.cpp \ pdftoolcolorprofiles.cpp \ pdftoolfetchimages.cpp \ pdftoolfetchtext.cpp \ @@ -75,6 +76,7 @@ HEADERS += \ pdftoolabstractapplication.h \ pdftoolattachments.h \ pdftoolaudiobook.h \ + pdftoolcertstore.h \ pdftoolcolorprofiles.h \ pdftoolfetchimages.h \ pdftoolfetchtext.h \ diff --git a/PdfTool/pdftoolabstractapplication.cpp b/PdfTool/pdftoolabstractapplication.cpp index b8558e2..d43abde 100644 --- a/PdfTool/pdftoolabstractapplication.cpp +++ b/PdfTool/pdftoolabstractapplication.cpp @@ -311,6 +311,12 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser* parser->addOption(QCommandLineOption(info.option, info.description)); } } + + if (optionFlags.testFlag(CertStore)) + { + parser->addOption(QCommandLineOption("list-user-certs", "Show list of user certificates.", "bool", "1")); + parser->addOption(QCommandLineOption("list-system-certs", "Show list of system certificates.", "bool", "0")); + } } PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser) const @@ -840,6 +846,12 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser } } + if (optionFlags.testFlag(CertStore)) + { + options.certStoreEnumerateSystemCertificates = parser->value("list-system-certs").toInt(); + options.certStoreEnumerateUserCertificates = parser->value("list-user-certs").toInt(); + } + return options; } diff --git a/PdfTool/pdftoolabstractapplication.h b/PdfTool/pdftoolabstractapplication.h index 853eb5b..965d503 100644 --- a/PdfTool/pdftoolabstractapplication.h +++ b/PdfTool/pdftoolabstractapplication.h @@ -139,6 +139,10 @@ struct PDFToolOptions // For option 'Optimize' pdf::PDFOptimizer::OptimizationFlags optimizeFlags = pdf::PDFOptimizer::None; + // For option 'CertStore' + bool certStoreEnumerateSystemCertificates = false; + bool certStoreEnumerateUserCertificates = true; + /// Returns page range. If page range is invalid, then \p errorMessage is empty. /// \param pageCount Page count /// \param[out] errorMessage Error message @@ -217,7 +221,8 @@ public: RenderFlags = 0x00020000, ///< Render flags for page image rasterizer Separate = 0x00040000, ///< Settings for Separate tool Unite = 0x00080000, ///< Settings for Unite tool - Optimize = 0x00100000, ///< Settings for Optimize + Optimize = 0x00100000, ///< Settings for Optimize tool + CertStore = 0x00200000, ///< Settings for certificate store tool }; Q_DECLARE_FLAGS(Options, Option) diff --git a/PdfTool/pdftoolcertstore.cpp b/PdfTool/pdftoolcertstore.cpp new file mode 100644 index 0000000..24b830d --- /dev/null +++ b/PdfTool/pdftoolcertstore.cpp @@ -0,0 +1,146 @@ +// 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 . + +#include "pdftoolcertstore.h" +#include "pdfsignaturehandler.h" + +namespace pdftool +{ + +static PDFToolCertStore s_certStoreApplication; + +QString PDFToolCertStore::getStandardString(PDFToolAbstractApplication::StandardString standardString) const +{ + switch (standardString) + { + case Command: + return "cert-store"; + + case Name: + return PDFToolTranslationContext::tr("Certificate Store"); + + case Description: + return PDFToolTranslationContext::tr("Certificate store operations (list, add, remove certificates)."); + + default: + Q_ASSERT(false); + break; + } + + return QString(); +} + +int PDFToolCertStore::execute(const PDFToolOptions& options) +{ + // Certificate store + pdf::PDFCertificateStore certificateStore; + + + if (options.certStoreEnumerateUserCertificates) + { + certificateStore.loadDefaultUserCertificates(); + } + + pdf::PDFCertificateStore::CertificateEntries certificates = certificateStore.getCertificates(); + if (options.certStoreEnumerateSystemCertificates) + { + pdf::PDFCertificateStore::CertificateEntries systemCertificates = pdf::PDFCertificateStore::getSystemCertificates(); + certificates.insert(certificates.end(), std::make_move_iterator(systemCertificates.begin()), std::make_move_iterator(systemCertificates.end())); + } + + PDFOutputFormatter formatter(options.outputStyle, options.outputCodec); + formatter.beginDocument("cert-store", PDFToolTranslationContext::tr("Certificates used in signature verification")); + formatter.endl(); + + formatter.beginTable("certificate-list", PDFToolTranslationContext::tr("Certificates")); + + formatter.beginTableHeaderRow("header"); + formatter.writeTableHeaderColumn("no", PDFToolTranslationContext::tr("No.")); + formatter.writeTableHeaderColumn("type", PDFToolTranslationContext::tr("Type")); + formatter.writeTableHeaderColumn("certificate", PDFToolTranslationContext::tr("Certificate")); + formatter.writeTableHeaderColumn("organization", PDFToolTranslationContext::tr("Organization")); + formatter.writeTableHeaderColumn("valid-from", PDFToolTranslationContext::tr("Valid from")); + formatter.writeTableHeaderColumn("valid-to", PDFToolTranslationContext::tr("Valid to")); + formatter.endTableHeaderRow(); + + int ref = 1; + QLocale locale; + + for (const pdf::PDFCertificateStore::CertificateEntry& entry : certificates) + { + QString type; + switch (entry.type) + { + case pdf::PDFCertificateStore::EntryType::User: + type = PDFToolTranslationContext::tr("User"); + break; + + case pdf::PDFCertificateStore::EntryType::EUTL: + type = PDFToolTranslationContext::tr("EUTL"); + break; + + case pdf::PDFCertificateStore::EntryType::System: + type = PDFToolTranslationContext::tr("System"); + break; + + default: + Q_ASSERT(false); + break; + } + + QDateTime notValidBefore = entry.info.getNotValidBefore().toLocalTime(); + QDateTime notValidAfter = entry.info.getNotValidAfter().toLocalTime(); + + QString notValidBeforeText; + QString notValidAfterText; + + if (notValidBefore.isValid()) + { + notValidBeforeText = notValidBefore.toString(options.outputDateFormat); + } + + if (notValidAfter.isValid()) + { + notValidAfterText = notValidAfter.toString(options.outputDateFormat); + } + + formatter.beginTableRow("certificate", ref); + + formatter.writeTableColumn("no", locale.toString(ref++), Qt::AlignRight); + formatter.writeTableColumn("type", type); + formatter.writeTableColumn("certificate", entry.info.getName(pdf::PDFCertificateInfo::CommonName)); + formatter.writeTableColumn("organization", entry.info.getName(pdf::PDFCertificateInfo::OrganizationName)); + formatter.writeTableColumn("valid-from", notValidBeforeText); + formatter.writeTableColumn("valid-to", notValidAfterText); + + formatter.endTableRow(); + } + + formatter.endTable(); + + formatter.endDocument(); + PDFConsole::writeText(formatter.getString(), options.outputCodec); + + return ExitSuccess; +} + +PDFToolAbstractApplication::Options PDFToolCertStore::getOptionsFlags() const +{ + return ConsoleFormat | DateFormat | CertStore; +} + +} // namespace pdftool diff --git a/PdfTool/pdftoolcertstore.h b/PdfTool/pdftoolcertstore.h new file mode 100644 index 0000000..883f1a5 --- /dev/null +++ b/PdfTool/pdftoolcertstore.h @@ -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 . + +#ifndef PDFTOOLCERTSTORE_H +#define PDFTOOLCERTSTORE_H + +#include "pdftoolabstractapplication.h" + +namespace pdftool +{ + +class PDFToolCertStore : 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 // PDFTOOLCERTSTORE_H