diff --git a/Pdf4QtLibCore/CMakeLists.txt b/Pdf4QtLibCore/CMakeLists.txt index 31731b7..e060d8d 100644 --- a/Pdf4QtLibCore/CMakeLists.txt +++ b/Pdf4QtLibCore/CMakeLists.txt @@ -144,6 +144,8 @@ add_library(Pdf4QtLibCore SHARED sources/pdfwidgetsnapshot.cpp sources/pdfwidgetsnapshot.h cmaps.qrc + sources/pdfcertificatestore.h + sources/pdfcertificatestore.cpp ) include(GenerateExportHeader) diff --git a/Pdf4QtLibCore/sources/pdfcertificatemanager.cpp b/Pdf4QtLibCore/sources/pdfcertificatemanager.cpp index 7024719..1cc5fa2 100644 --- a/Pdf4QtLibCore/sources/pdfcertificatemanager.cpp +++ b/Pdf4QtLibCore/sources/pdfcertificatemanager.cpp @@ -144,10 +144,57 @@ void PDFCertificateManager::createCertificate(const NewCertificateInfo& info) } } -QFileInfoList PDFCertificateManager::getCertificates() +PDFCertificateEntries PDFCertificateManager::getCertificates() { + PDFCertificateEntries entries = PDFCertificateStore::getPersonalCertificates(); + QDir directory(getCertificateDirectory()); - return directory.entryInfoList(QStringList() << "*.pfx", QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name); + QFileInfoList pfxFiles = directory.entryInfoList(QStringList() << "*.pfx", QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name); + + for (const QFileInfo& fileInfo : pfxFiles) + { + QFile file(fileInfo.absoluteFilePath()); + if (file.open(QFile::ReadOnly)) + { + QByteArray data = file.readAll(); + + openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); + BIO_write(pksBuffer.get(), data.constData(), data.length()); + + openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); + if (pkcs12) + { + X509* certificatePtr = nullptr; + + PDFCertificateEntry entry; + + // Parse PKCS12 with password + bool isParsed = PKCS12_parse(pkcs12.get(), nullptr, nullptr, &certificatePtr, nullptr) == 1; + if (isParsed) + { + std::optional info = PDFCertificateInfo::getCertificateInfo(certificatePtr); + if (info) + { + entry.type = PDFCertificateEntry::EntryType::System; + entry.info = qMove(*info); + } + } + + if (certificatePtr) + { + X509_free(certificatePtr); + } + + entry.pkcs12 = data; + entry.pkcs12fileName = fileInfo.fileName(); + entries.emplace_back(qMove(entry)); + } + + file.close(); + } + } + + return entries; } QString PDFCertificateManager::getCertificateDirectory() @@ -175,46 +222,42 @@ QString PDFCertificateManager::generateCertificateFileName() return QString(); } -bool PDFCertificateManager::isCertificateValid(QString fileName, QString password) +bool PDFCertificateManager::isCertificateValid(const PDFCertificateEntry& certificateEntry, QString password) { - QFile file(fileName); - if (file.open(QFile::ReadOnly)) + QByteArray pkcs12data = certificateEntry.pkcs12; + + openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); + BIO_write(pksBuffer.get(), pkcs12data.constData(), pkcs12data.length()); + + openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); + if (pkcs12) { - QByteArray data = file.readAll(); - file.close(); - - openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); - BIO_write(pksBuffer.get(), data.constData(), data.length()); - - openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); - if (pkcs12) + const char* passwordPointer = nullptr; + QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8(); + if (!passwordByteArray.isEmpty()) { - const char* passwordPointer = nullptr; - QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8(); - if (!passwordByteArray.isEmpty()) - { - passwordPointer = passwordByteArray.constData(); - } - - return PKCS12_parse(pkcs12.get(), passwordPointer, nullptr, nullptr, nullptr) == 1; + passwordPointer = passwordByteArray.constData(); } + + return PKCS12_parse(pkcs12.get(), passwordPointer, nullptr, nullptr, nullptr) == 1; } - return false; + return pkcs12data.isEmpty(); } -bool PDFSignatureFactory::sign(QString certificateName, QString password, QByteArray data, QByteArray& result) +bool PDFSignatureFactory::sign(const PDFCertificateEntry& certificateEntry, + QString password, + QByteArray data, + QByteArray& result) { - QFile file(certificateName); - if (file.open(QFile::ReadOnly)) + QByteArray pkcs12Data = certificateEntry.pkcs12; + + if (!pkcs12Data.isEmpty()) { - QByteArray certificateData = file.readAll(); - file.close(); + openssl_ptr pkcs12Buffer(BIO_new(BIO_s_mem()), &BIO_free_all); + BIO_write(pkcs12Buffer.get(), pkcs12Data.constData(), pkcs12Data.length()); - openssl_ptr certificateBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); - BIO_write(certificateBuffer.get(), certificateData.constData(), certificateData.length()); - - openssl_ptr pkcs12(d2i_PKCS12_bio(certificateBuffer.get(), nullptr), &PKCS12_free); + openssl_ptr pkcs12(d2i_PKCS12_bio(pkcs12Buffer.get(), nullptr), &PKCS12_free); if (pkcs12) { const char* passwordPointer = nullptr; @@ -256,12 +299,119 @@ bool PDFSignatureFactory::sign(QString certificateName, QString password, QByteA } } } +#ifdef Q_OS_WIN + else + { + return signImpl_Win(certificateEntry, password, data, result); + } +#endif return false; } } // namespace pdf +#ifdef Q_OS_WIN +#include +#include +#include +#if defined(PDF4QT_USE_PRAGMA_LIB) +#pragma comment(lib, "crypt32.lib") +#endif +#endif + +bool pdf::PDFSignatureFactory::signImpl_Win(const pdf::PDFCertificateEntry& certificateEntry, QString password, QByteArray data, QByteArray& result) +{ + bool success = false; + +#ifdef Q_OS_WIN + Q_UNUSED(password); + + HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"); + if (certStore) + { + PCCERT_CONTEXT pCertContext = nullptr; + + while (pCertContext = CertEnumCertificatesInStore(certStore, pCertContext)) + { + const unsigned char* pointer = pCertContext->pbCertEncoded; + QByteArray testData(reinterpret_cast(pointer), pCertContext->cbCertEncoded); + + if (testData == certificateEntry.info.getCertificateData()) + { + break; + } + } + + if (pCertContext) + { + CRYPT_SIGN_MESSAGE_PARA SignParams{}; + BYTE* pbSignedBlob = nullptr; + DWORD cbSignedBlob = 0; + PCCERT_CONTEXT pCertContextArray[1] = { pCertContext }; + + const BYTE* pbDataToBeSigned = (const BYTE*)data.constData(); + DWORD cbDataToBeSigned = (DWORD)data.size(); + + // Nastavení parametrů pro podpis + SignParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA); + SignParams.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; + SignParams.pSigningCert = pCertContext; + SignParams.HashAlgorithm.pszObjId = (LPSTR)szOID_RSA_SHA256RSA; + SignParams.HashAlgorithm.Parameters.cbData = 0; + SignParams.HashAlgorithm.Parameters.pbData = NULL; + SignParams.cMsgCert = 1; + SignParams.rgpMsgCert = pCertContextArray; + pCertContextArray[0] = pCertContext; + + const BYTE* rgpbToBeSigned[1] = {pbDataToBeSigned}; + DWORD rgcbToBeSigned[1] = {cbDataToBeSigned}; + + // Retrieve signed message size + CryptSignMessage( + &SignParams, + TRUE, + 1, + rgpbToBeSigned, + rgcbToBeSigned, + NULL, + &cbSignedBlob + ); + + pbSignedBlob = new BYTE[cbSignedBlob]; + + // Create digital signature + if (CryptSignMessage( + &SignParams, + TRUE, + 1, + rgpbToBeSigned, + rgcbToBeSigned, + pbSignedBlob, + &cbSignedBlob + )) + { + result = QByteArray((const char*)pbSignedBlob, cbSignedBlob); + success = true; + } + + delete[] pbSignedBlob; + + CertFreeCertificateContext(pCertContext); + } + + CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG); + } +#else + Q_UNUSED(certificateEntry); + Q_UNUSED(password); + Q_UNUSED(data); + Q_UNUSED(result); +#endif + + return success; +} + #if defined(PDF4QT_COMPILER_MINGW) || defined(PDF4QT_COMPILER_GCC) #pragma GCC diagnostic pop #endif diff --git a/Pdf4QtLibCore/sources/pdfcertificatemanager.h b/Pdf4QtLibCore/sources/pdfcertificatemanager.h index 083faed..c463737 100644 --- a/Pdf4QtLibCore/sources/pdfcertificatemanager.h +++ b/Pdf4QtLibCore/sources/pdfcertificatemanager.h @@ -1,4 +1,4 @@ -// Copyright (C) 2022 Jakub Melka +// Copyright (C) 2022-2023 Jakub Melka // // This file is part of PDF4QT. // @@ -19,6 +19,7 @@ #define PDFCERTIFICATEMANAGER_H #include "pdfglobal.h" +#include "pdfcertificatestore.h" #include #include @@ -49,16 +50,25 @@ public: void createCertificate(const NewCertificateInfo& info); - static QFileInfoList getCertificates(); + static PDFCertificateEntries getCertificates(); static QString getCertificateDirectory(); static QString generateCertificateFileName(); - static bool isCertificateValid(QString fileName, QString password); + static bool isCertificateValid(const PDFCertificateEntry& certificateEntry, QString password); }; class PDF4QTLIBCORESHARED_EXPORT PDFSignatureFactory { public: - static bool sign(QString certificateName, QString password, QByteArray data, QByteArray& result); + static bool sign(const PDFCertificateEntry& certificateEntry, + QString password, + QByteArray data, + QByteArray& result); + +private: + static bool signImpl_Win(const PDFCertificateEntry& certificateEntry, + QString password, + QByteArray data, + QByteArray& result); }; } // namespace pdf diff --git a/Pdf4QtLibCore/sources/pdfcertificatestore.cpp b/Pdf4QtLibCore/sources/pdfcertificatestore.cpp new file mode 100644 index 0000000..0a30253 --- /dev/null +++ b/Pdf4QtLibCore/sources/pdfcertificatestore.cpp @@ -0,0 +1,547 @@ +// Copyright (C) 2022-2023 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 . + +#include "pdfcertificatestore.h" +#include "pdfutils.h" + +#if defined(PDF4QT_COMPILER_MINGW) || defined(PDF4QT_COMPILER_GCC) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +#if defined(PDF4QT_COMPILER_MSVC) +#pragma warning(push) +#pragma warning(disable: 4996) +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "pdfdbgheap.h" + +#include +#ifdef Q_OS_UNIX +#include +#endif + +namespace pdf +{ + +QRecursiveMutex PDFOpenSSLGlobalLock::s_globalOpenSSLMutex; + +PDFOpenSSLGlobalLock::PDFOpenSSLGlobalLock() : + m_mutexLocker(&s_globalOpenSSLMutex) +{ + +} + +void PDFCertificateEntry::serialize(QDataStream& stream) const +{ + stream << persist_version; + stream << type; + stream << info; +} + +void PDFCertificateEntry::deserialize(QDataStream& stream) +{ + int persistVersionDeserialized = 0; + stream >> persistVersionDeserialized; + stream >> type; + stream >> info; +} + + +void PDFCertificateInfo::serialize(QDataStream& stream) const +{ + stream << persist_version; + stream << m_version; + stream << m_keySize; + stream << m_publicKey; + stream << m_nameEntries; + stream << m_notValidBefore; + stream << m_notValidAfter; + stream << m_keyUsage; + stream << m_certificateData; +} + +void PDFCertificateInfo::deserialize(QDataStream& stream) +{ + int persistVersionDeserialized = 0; + stream >> persistVersionDeserialized; + stream >> m_version; + stream >> m_keySize; + stream >> m_publicKey; + stream >> m_nameEntries; + stream >> m_notValidBefore; + stream >> m_notValidAfter; + stream >> m_keyUsage; + stream >> m_certificateData; +} + +QDateTime PDFCertificateInfo::getNotValidBefore() const +{ + return m_notValidBefore; +} + +void PDFCertificateInfo::setNotValidBefore(const QDateTime& notValidBefore) +{ + m_notValidBefore = notValidBefore; +} + +QDateTime PDFCertificateInfo::getNotValidAfter() const +{ + return m_notValidAfter; +} + +void PDFCertificateInfo::setNotValidAfter(const QDateTime& notValidAfter) +{ + m_notValidAfter = notValidAfter; +} + +int32_t PDFCertificateInfo::getVersion() const +{ + return m_version; +} + +void PDFCertificateInfo::setVersion(int32_t version) +{ + m_version = version; +} + +PDFCertificateInfo::PublicKey PDFCertificateInfo::getPublicKey() const +{ + return m_publicKey; +} + +void PDFCertificateInfo::setPublicKey(const PublicKey& publicKey) +{ + m_publicKey = publicKey; +} + +int PDFCertificateInfo::getKeySize() const +{ + return m_keySize; +} + +void PDFCertificateInfo::setKeySize(int keySize) +{ + m_keySize = keySize; +} + +PDFCertificateInfo::KeyUsageFlags PDFCertificateInfo::getKeyUsage() const +{ + return m_keyUsage; +} + +void PDFCertificateInfo::setKeyUsage(KeyUsageFlags keyUsage) +{ + m_keyUsage = keyUsage; +} + +std::optional PDFCertificateInfo::getCertificateInfo(const QByteArray& certificateData) +{ + std::optional result; + + PDFOpenSSLGlobalLock lock; + const unsigned char* data = convertByteArrayToUcharPtr(certificateData); + if (X509* certificate = d2i_X509(nullptr, &data, certificateData.length())) + { + result = getCertificateInfo(certificate); + X509_free(certificate); + } + + return result; +} + +PDFCertificateInfo PDFCertificateInfo::getCertificateInfo(x509_st* certificate) +{ + PDFCertificateInfo info; + + auto getStringFromASN1_STRING = [](ASN1_STRING* string) -> QString + { + QString result; + + if (string) + { + // Jakub Melka: we must convert entry to UTF8 encoding using function ASN1_STRING_to_UTF8 + unsigned char* utf8Buffer = nullptr; + int errorCodeOrLength = ASN1_STRING_to_UTF8(&utf8Buffer, string); + if (errorCodeOrLength > 0) + { + result = QString::fromUtf8(reinterpret_cast(utf8Buffer), errorCodeOrLength); + } + OPENSSL_free(utf8Buffer); + } + + return result; + }; + + auto getStringFromX509Name = [&getStringFromASN1_STRING](X509_NAME* name, int nid) -> QString + { + QString result; + + const int stringLocation = X509_NAME_get_index_by_NID(name, nid, -1); + X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, stringLocation); + return getStringFromASN1_STRING(X509_NAME_ENTRY_get_data(entry)); + }; + + auto getDateTimeFromASN = [](const ASN1_TIME* time) -> QDateTime + { + QDateTime result; + + if (time) + { + tm internalTime = { }; + if (ASN1_TIME_to_tm(time, &internalTime) > 0) + { +#if defined(Q_OS_WIN) + time_t localTime = _mkgmtime(&internalTime); +#elif defined(Q_OS_UNIX) + time_t localTime = timegm(&internalTime); +#else + static_assert(false, "Implement this for another OS!"); +#endif + result = QDateTime::fromSecsSinceEpoch(localTime, Qt::UTC); + } + } + + return result; + }; + + if (X509_NAME* subjectName = X509_get_subject_name(certificate)) + { + // List of these properties are in RFC 5280, section 4.1.2.4, these attributes + // are standard and all implementations must be prepared to process them. + QString countryName = getStringFromX509Name(subjectName, NID_countryName); + QString organizationName = getStringFromX509Name(subjectName, NID_organizationName); + QString organizationalUnitName = getStringFromX509Name(subjectName, NID_organizationalUnitName); + QString distinguishedName = getStringFromX509Name(subjectName, NID_distinguishedName); + QString stateOrProvinceName = getStringFromX509Name(subjectName, NID_stateOrProvinceName); + QString commonName = getStringFromX509Name(subjectName, NID_commonName); + QString serialNumber = getStringFromX509Name(subjectName, NID_serialNumber); + + // These attributes are defined also in section 4.1.2.4, they are not mandatory, + // but application should be able to process them. + QString localityName = getStringFromX509Name(subjectName, NID_localityName); + QString title = getStringFromX509Name(subjectName, NID_title); + QString surname = getStringFromX509Name(subjectName, NID_surname); + QString givenName = getStringFromX509Name(subjectName, NID_givenName); + QString initials = getStringFromX509Name(subjectName, NID_initials); + QString pseudonym = getStringFromX509Name(subjectName, NID_pseudonym); + QString generationQualifier = getStringFromX509Name(subjectName, NID_generationQualifier); + + // This entry is not defined in section 4.1.2.4, but is commonly used + QString email = getStringFromX509Name(subjectName, NID_pkcs9_emailAddress); + + info.setName(PDFCertificateInfo::CountryName, qMove(countryName)); + info.setName(PDFCertificateInfo::OrganizationName, qMove(organizationName)); + info.setName(PDFCertificateInfo::OrganizationalUnitName, qMove(organizationalUnitName)); + info.setName(PDFCertificateInfo::DistinguishedName, qMove(distinguishedName)); + info.setName(PDFCertificateInfo::StateOrProvinceName, qMove(stateOrProvinceName)); + info.setName(PDFCertificateInfo::CommonName, qMove(commonName)); + info.setName(PDFCertificateInfo::SerialNumber, qMove(serialNumber)); + + info.setName(PDFCertificateInfo::LocalityName, qMove(localityName)); + info.setName(PDFCertificateInfo::Title, qMove(title)); + info.setName(PDFCertificateInfo::Surname, qMove(surname)); + info.setName(PDFCertificateInfo::GivenName, qMove(givenName)); + info.setName(PDFCertificateInfo::Initials, qMove(initials)); + info.setName(PDFCertificateInfo::Pseudonym, qMove(pseudonym)); + info.setName(PDFCertificateInfo::GenerationalQualifier, qMove(generationQualifier)); + + info.setName(PDFCertificateInfo::Email, qMove(email)); + + const long version = X509_get_version(certificate); + info.setVersion(version); + + const ASN1_TIME* notBeforeTime = X509_get0_notBefore(certificate); + const ASN1_TIME* notAfterTime = X509_get0_notAfter(certificate); + + info.setNotValidBefore(getDateTimeFromASN(notBeforeTime)); + info.setNotValidAfter(getDateTimeFromASN(notAfterTime)); + + X509_PUBKEY* publicKey = X509_get_X509_PUBKEY(certificate); + EVP_PKEY* evpKey = X509_PUBKEY_get(publicKey); + const int keyType = EVP_PKEY_type(EVP_PKEY_base_id(evpKey)); + + PDFCertificateInfo::PublicKey key = PDFCertificateInfo::KeyUnknown; + switch (keyType) + { + case EVP_PKEY_RSA: + key = PDFCertificateInfo::KeyRSA; + break; + + case EVP_PKEY_DSA: + key = PDFCertificateInfo::KeyDSA; + break; + + case EVP_PKEY_DH: + key = PDFCertificateInfo::KeyDH; + break; + + case EVP_PKEY_EC: + key = PDFCertificateInfo::KeyEC; + break; + + default: + break; + } + info.setPublicKey(key); + + const int bits = EVP_PKEY_bits(evpKey); + info.setKeySize(bits); + + uint32_t keyUsage = X509_get_key_usage(certificate); + if (keyUsage != UINT32_MAX) + { + static_assert(PDFCertificateInfo::KeyUsageDigitalSignature == KU_DIGITAL_SIGNATURE, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageNonRepudiation == KU_NON_REPUDIATION, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageKeyEncipherment == KU_KEY_ENCIPHERMENT, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageDataEncipherment == KU_DATA_ENCIPHERMENT, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageAgreement == KU_KEY_AGREEMENT, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageCertSign == KU_KEY_CERT_SIGN, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageCrlSign == KU_CRL_SIGN, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageEncipherOnly == KU_ENCIPHER_ONLY, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageDecipherOnly == KU_DECIPHER_ONLY, "Fix this code!"); + + if (X509_get_extension_flags(certificate) & EXFLAG_XKUSAGE) + { + const uint32_t extendedKeyUsage = X509_get_extended_key_usage(certificate); + Q_ASSERT(extendedKeyUsage != UINT32_MAX); + + static_assert(PDFCertificateInfo::KeyUsageExtended_SSL_SERVER >> 16 == XKU_SSL_SERVER, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_SSL_CLIENT >> 16 == XKU_SSL_CLIENT, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_SMIME >> 16 == XKU_SMIME, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_CODE_SIGN >> 16 == XKU_CODE_SIGN, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_SGC >> 16 == XKU_SGC, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_OCSP_SIGN >> 16 == XKU_OCSP_SIGN, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_TIMESTAMP >> 16 == XKU_TIMESTAMP, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_DVCS >> 16 == XKU_DVCS, "Fix this code!"); + static_assert(PDFCertificateInfo::KeyUsageExtended_ANYEKU >> 16 == XKU_ANYEKU, "Fix this code!"); + + keyUsage = keyUsage | (extendedKeyUsage << 16); + } + + info.setKeyUsage(static_cast(keyUsage)); + } + + unsigned char* buffer = nullptr; + int length = i2d_X509(certificate, &buffer); + if (length >= 0) + { + Q_ASSERT(buffer); + info.setCertificateData(QByteArray(reinterpret_cast(buffer), length)); + OPENSSL_free(buffer); + } + } + + return info; +} + +QByteArray PDFCertificateInfo::getCertificateData() const +{ + return m_certificateData; +} + +void PDFCertificateInfo::setCertificateData(const QByteArray& certificateData) +{ + m_certificateData = certificateData; +} + + +void PDFCertificateStore::serialize(QDataStream& stream) const +{ + stream << persist_version; + stream << m_certificates; +} + +void PDFCertificateStore::deserialize(QDataStream& stream) +{ + int persistVersionDeserialized = 0; + stream >> persistVersionDeserialized; + stream >> m_certificates; +} + +bool PDFCertificateStore::add(PDFCertificateEntry::EntryType type, const QByteArray& certificate) +{ + if (auto certificateInfo = PDFCertificateInfo::getCertificateInfo(certificate)) + { + return add(type, qMove(*certificateInfo)); + } + + return false; +} + +bool PDFCertificateStore::add(PDFCertificateEntry::EntryType type, PDFCertificateInfo info) +{ + auto it = std::find_if(m_certificates.cbegin(), m_certificates.cend(), [&info](const auto& entry) { return entry.info == info; }); + if (it == m_certificates.cend()) + { + m_certificates.push_back({ type, qMove(info) }); + } + + return true; +} + +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(); +} + +QString PDFCertificateStore::getDefaultCertificateStoreFileName() const +{ + return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/TrustedCertStorage.bin"; +} + +void PDFCertificateStore::loadDefaultUserCertificates() +{ + createDirectoryForDefaultUserCertificatesStore(); + QString trustedCertificateStoreFileName = getDefaultCertificateStoreFileName(); + QString trustedCertificateStoreLockFileName = trustedCertificateStoreFileName + ".lock"; + + QLockFile lockFile(trustedCertificateStoreLockFileName); + if (lockFile.lock()) + { + QFile trustedCertificateStoreFile(trustedCertificateStoreFileName); + if (trustedCertificateStoreFile.open(QFile::ReadOnly)) + { + QDataStream stream(&trustedCertificateStoreFile); + deserialize(stream); + trustedCertificateStoreFile.close(); + } + lockFile.unlock(); + } +} + +void PDFCertificateStore::saveDefaultUserCertificates() +{ + createDirectoryForDefaultUserCertificatesStore(); + QString trustedCertificateStoreFileName = getDefaultCertificateStoreFileName(); + QString trustedCertificateStoreLockFileName = trustedCertificateStoreFileName + ".lock"; + + QFileInfo fileInfo(trustedCertificateStoreFileName); + QDir dir = fileInfo.dir(); + dir.mkpath(dir.path()); + + QLockFile lockFile(trustedCertificateStoreLockFileName); + if (lockFile.lock()) + { + QFile trustedCertificateStoreFile(trustedCertificateStoreFileName); + if (trustedCertificateStoreFile.open(QFile::WriteOnly | QFile::Truncate)) + { + QDataStream stream(&trustedCertificateStoreFile); + serialize(stream); + trustedCertificateStoreFile.close(); + } + lockFile.unlock(); + } +} + +void PDFCertificateStore::createDirectoryForDefaultUserCertificatesStore() +{ + QFileInfo fileInfo(getDefaultCertificateStoreFileName()); + QString path = fileInfo.path(); + QDir().mkpath(path); +} + +} // namespace pdf + +#ifdef Q_OS_WIN +#include +#include +#if defined(PDF4QT_USE_PRAGMA_LIB) +#pragma comment(lib, "crypt32.lib") +#endif +#endif + +pdf::PDFCertificateEntries pdf::PDFCertificateStore::getSystemCertificates() +{ + PDFCertificateEntries result; + +#ifdef Q_OS_WIN + HCERTSTORE certStore = CertOpenSystemStore(0, 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) + { + PDFCertificateEntry entry; + entry.type = PDFCertificateEntry::EntryType::System; + entry.info = qMove(*info); + result.emplace_back(qMove(entry)); + } + } + + CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG); + } +#endif + + return result; +} + +pdf::PDFCertificateEntries pdf::PDFCertificateStore::getPersonalCertificates() +{ + PDFCertificateEntries result; + +#ifdef Q_OS_WIN + HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"); + 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) + { + PDFCertificateEntry entry; + entry.type = PDFCertificateEntry::EntryType::System; + entry.info = qMove(*info); + result.emplace_back(qMove(entry)); + } + } + + CertCloseStore(certStore, CERT_CLOSE_STORE_FORCE_FLAG); + } +#endif + + return result; +} + +#if defined(PDF4QT_COMPILER_MINGW) || defined(PDF4QT_COMPILER_GCC) +#pragma GCC diagnostic pop +#endif + +#if defined(PDF4QT_COMPILER_MSVC) +#pragma warning(pop) +#endif diff --git a/Pdf4QtLibCore/sources/pdfcertificatestore.h b/Pdf4QtLibCore/sources/pdfcertificatestore.h new file mode 100644 index 0000000..f8d3116 --- /dev/null +++ b/Pdf4QtLibCore/sources/pdfcertificatestore.h @@ -0,0 +1,255 @@ +// Copyright (C) 2023 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 . + +#ifndef PDFCERTIFICATESTORE_H +#define PDFCERTIFICATESTORE_H + +#include "pdfglobal.h" + +#include +#include +#include +#include + +class QDataStream; +struct x509_st; + +namespace pdf +{ + +/// OpenSSL is not thread safe. +class PDF4QTLIBCORESHARED_EXPORT PDFOpenSSLGlobalLock +{ +public: + explicit PDFOpenSSLGlobalLock(); + inline ~PDFOpenSSLGlobalLock() = default; + +private: + QMutexLocker m_mutexLocker; + static QRecursiveMutex s_globalOpenSSLMutex; +}; + +/// Info about certificate, various details etc. +class PDF4QTLIBCORESHARED_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 getCertificateInfo(const QByteArray& certificateData); + + /// Creates certificate info from certificate + static PDFCertificateInfo getCertificateInfo(x509_st* certificate); + +private: + static constexpr int persist_version = 1; + + int32_t m_version = 0; + int m_keySize = 0; + PublicKey m_publicKey = KeyUnknown; + std::array m_nameEntries; + QDateTime m_notValidBefore; + QDateTime m_notValidAfter; + KeyUsageFlags m_keyUsage; + QByteArray m_certificateData; +}; + +using PDFCertificateInfos = std::vector; + +struct PDFCertificateEntry +{ + enum class EntryType : int + { + User, ///< Certificate has been added manually by the user + System, ///< System certificate + }; + + void serialize(QDataStream& stream) const; + void deserialize(QDataStream& stream); + + friend inline QDataStream& operator<<(QDataStream& stream, const PDFCertificateEntry& entry) { entry.serialize(stream); return stream; } + friend inline QDataStream& operator>>(QDataStream& stream, PDFCertificateEntry& entry) { entry.deserialize(stream); return stream; } + + static constexpr int persist_version = 1; + EntryType type = EntryType::User; + PDFCertificateInfo info; + QByteArray pkcs12; + QString pkcs12fileName; +}; + +using PDFCertificateEntries = std::vector; + +/// Trusted certificate store. Contains list of trusted certificates. Store +/// can be persisted to the persistent storage trough serialization/deserialization. +/// Persisting method is versioned. +class PDF4QTLIBCORESHARED_EXPORT PDFCertificateStore +{ +public: + explicit inline PDFCertificateStore() = default; + + void serialize(QDataStream& stream) const; + void deserialize(QDataStream& stream); + + /// 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(PDFCertificateEntry::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(PDFCertificateEntry::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 PDFCertificateEntries& getCertificates() const { return m_certificates; } + + /// Set certificates + void setCertificates(PDFCertificateEntries 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 PDFCertificateEntries getSystemCertificates(); + + /// Returns a list of personal certificates (usually used for signing documents) + static PDFCertificateEntries getPersonalCertificates(); + +private: + static constexpr int persist_version = 1; + + PDFCertificateEntries m_certificates; +}; + +} // namespace pdf + +#endif // PDFCERTIFICATESTORE_H diff --git a/Pdf4QtLibCore/sources/pdfsecurityhandler.cpp b/Pdf4QtLibCore/sources/pdfsecurityhandler.cpp index 2d98baa..492f93b 100644 --- a/Pdf4QtLibCore/sources/pdfsecurityhandler.cpp +++ b/Pdf4QtLibCore/sources/pdfsecurityhandler.cpp @@ -1979,62 +1979,57 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_PrintHighResolution; } - QFile file(settings.certificateFileName); - if (file.open(QFile::ReadOnly)) + QByteArray data = settings.certificate.pkcs12; + + openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); + BIO_write(pksBuffer.get(), data.constData(), data.length()); + + openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); + if (pkcs12) { - QByteArray data = file.readAll(); - file.close(); - - openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); - BIO_write(pksBuffer.get(), data.constData(), data.length()); - - openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); - if (pkcs12) + QByteArray password = PDFStandardOrPublicSecurityHandler::adjustPassword(settings.userPassword, 0); + const char* passwordPointer = nullptr; + if (!password.isEmpty()) { - QByteArray password = PDFStandardOrPublicSecurityHandler::adjustPassword(settings.userPassword, 0); - const char* passwordPointer = nullptr; - if (!password.isEmpty()) + passwordPointer = password.constData(); + } + + EVP_PKEY* keyPtr = nullptr; + X509* certificatePtr = nullptr; + STACK_OF(X509)* certificatesPtr = nullptr; + + // Parse PKCS12 with password + bool isParsed = PKCS12_parse(pkcs12.get(), passwordPointer, &keyPtr, &certificatePtr, &certificatesPtr) == 1; + + if (isParsed) + { + openssl_ptr key(keyPtr, EVP_PKEY_free); + openssl_ptr certificate(certificatePtr, X509_free); + openssl_ptr certificates(certificatesPtr, sk_x509_free_impl); + openssl_ptr dataToBeSigned(BIO_new(BIO_s_mem()), BIO_free_all); + + uint32_t permissions = qToLittleEndian(publicKeyHandler->m_permissions); + QRandomGenerator generator = QRandomGenerator::securelySeeded(); + QByteArray randomKey = generateRandomByteArray(generator, 20); + BIO_write(dataToBeSigned.get(), randomKey.data(), randomKey.length()); + BIO_write(dataToBeSigned.get(), &permissions, sizeof(permissions)); + + openssl_ptr recipientCertificates(sk_X509_new_null(), sk_x509_free_impl); + sk_X509_push(recipientCertificates.get(), certificate.get()); + + openssl_ptr pkcs7(PKCS7_encrypt(recipientCertificates.get(), dataToBeSigned.get(), EVP_aes_256_cbc(), PKCS7_BINARY), PKCS7_free); + + if (pkcs7) { - passwordPointer = password.constData(); - } + openssl_ptr storedData(BIO_new(BIO_s_mem()), BIO_free_all); - EVP_PKEY* keyPtr = nullptr; - X509* certificatePtr = nullptr; - STACK_OF(X509)* certificatesPtr = nullptr; - - // Parse PKCS12 with password - bool isParsed = PKCS12_parse(pkcs12.get(), passwordPointer, &keyPtr, &certificatePtr, &certificatesPtr) == 1; - - if (isParsed) - { - openssl_ptr key(keyPtr, EVP_PKEY_free); - openssl_ptr certificate(certificatePtr, X509_free); - openssl_ptr certificates(certificatesPtr, sk_x509_free_impl); - openssl_ptr dataToBeSigned(BIO_new(BIO_s_mem()), BIO_free_all); - - uint32_t permissions = qToLittleEndian(publicKeyHandler->m_permissions); - QRandomGenerator generator = QRandomGenerator::securelySeeded(); - QByteArray randomKey = generateRandomByteArray(generator, 20); - BIO_write(dataToBeSigned.get(), randomKey.data(), randomKey.length()); - BIO_write(dataToBeSigned.get(), &permissions, sizeof(permissions)); - - openssl_ptr recipientCertificates(sk_X509_new_null(), sk_x509_free_impl); - sk_X509_push(recipientCertificates.get(), certificate.get()); - - openssl_ptr pkcs7(PKCS7_encrypt(recipientCertificates.get(), dataToBeSigned.get(), EVP_aes_256_cbc(), PKCS7_BINARY), PKCS7_free); - - if (pkcs7) + if (i2d_PKCS7_bio(storedData.get(), pkcs7.get())) { - openssl_ptr storedData(BIO_new(BIO_s_mem()), BIO_free_all); + BUF_MEM* memoryBuffer = nullptr; + BIO_get_mem_ptr(storedData.get(), &memoryBuffer); - if (i2d_PKCS7_bio(storedData.get(), pkcs7.get())) - { - BUF_MEM* memoryBuffer = nullptr; - BIO_get_mem_ptr(storedData.get(), &memoryBuffer); - - QByteArray recipient(memoryBuffer->data, int(memoryBuffer->length)); - publicKeyHandler->m_filterDefault.recipients << recipient; - } + QByteArray recipient(memoryBuffer->data, int(memoryBuffer->length)); + publicKeyHandler->m_filterDefault.recipients << recipient; } } } @@ -2354,7 +2349,7 @@ bool PDFSecurityHandlerFactory::validate(const SecuritySettings& settings, QStri case pdf::PDFSecurityHandlerFactory::Certificate: { - if (!pdf::PDFCertificateManager::isCertificateValid(settings.certificateFileName, settings.userPassword)) + if (!pdf::PDFCertificateManager::isCertificateValid(settings.certificate, settings.userPassword)) { *errorMessage = tr("Invalid certificate or password."); return false; @@ -2401,8 +2396,8 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat constexpr int revision = 0; QByteArray password = adjustPassword(getPasswordCallback(&passwordObtained), revision); - QFileInfoList certificates = PDFCertificateManager::getCertificates(); - if (certificates.isEmpty()) + PDFCertificateEntries certificates = PDFCertificateManager::getCertificates(); + if (certificates.empty()) { return AuthorizationResult::Failed; } @@ -2421,114 +2416,109 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat while (passwordObtained) { // We will iterate trough all certificates - for (const QFileInfo& certificateFileInfo : certificates) + for (const PDFCertificateEntry& certificateEntry : certificates) { - if (!PDFCertificateManager::isCertificateValid(certificateFileInfo.absoluteFilePath(), password)) + if (!PDFCertificateManager::isCertificateValid(certificateEntry, password)) { continue; } - QFile file(certificateFileInfo.absoluteFilePath()); - if (file.open(QFile::ReadOnly)) + QByteArray data = certificateEntry.info.getCertificateData(); + + openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); + BIO_write(pksBuffer.get(), data.constData(), data.length()); + + openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); + if (pkcs12) { - QByteArray data = file.readAll(); - file.close(); - - openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); - BIO_write(pksBuffer.get(), data.constData(), data.length()); - - openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); - if (pkcs12) + const char* passwordPointer = nullptr; + if (!password.isEmpty()) { - const char* passwordPointer = nullptr; - if (!password.isEmpty()) + passwordPointer = password.constData(); + } + + EVP_PKEY* keyPtr = nullptr; + X509* certificatePtr = nullptr; + STACK_OF(X509)* certificatesPtr = nullptr; + + // Parse PKCS12 with password + bool isParsed = PKCS12_parse(pkcs12.get(), passwordPointer, &keyPtr, &certificatePtr, &certificatesPtr) == 1; + + if (!isParsed) + { + continue; + } + + openssl_ptr key(keyPtr, EVP_PKEY_free); + openssl_ptr certificate(certificatePtr, X509_free); + openssl_ptr certificates2(certificatesPtr, sk_x509_free_impl); + + for (const auto& recipientItem : recipients) + { + PKCS7* pkcs7 = recipientItem.get(); + + openssl_ptr dataBuffer(BIO_new(BIO_s_mem()), BIO_free_all); + if (PKCS7_decrypt(pkcs7, keyPtr, certificatePtr, dataBuffer.get(), PKCS7_BINARY) == 1) { - passwordPointer = password.constData(); - } + BUF_MEM* memoryBuffer = nullptr; + BIO_get_mem_ptr(dataBuffer.get(), &memoryBuffer); - EVP_PKEY* keyPtr = nullptr; - X509* certificatePtr = nullptr; - STACK_OF(X509)* certificatesPtr = nullptr; + // Acc. to chapter 7.6.5.3 - decrypted data + QByteArray decryptedData(memoryBuffer->data, int(memoryBuffer->length)); - // Parse PKCS12 with password - bool isParsed = PKCS12_parse(pkcs12.get(), passwordPointer, &keyPtr, &certificatePtr, &certificatesPtr) == 1; + // Calculate file encryption key + EVP_MD_CTX* context = EVP_MD_CTX_new(); + Q_ASSERT(context); - if (!isParsed) - { - continue; - } - - openssl_ptr key(keyPtr, EVP_PKEY_free); - openssl_ptr certificate(certificatePtr, X509_free); - openssl_ptr certificates2(certificatesPtr, sk_x509_free_impl); - - for (const auto& recipientItem : recipients) - { - PKCS7* pkcs7 = recipientItem.get(); - - openssl_ptr dataBuffer(BIO_new(BIO_s_mem()), BIO_free_all); - if (PKCS7_decrypt(pkcs7, keyPtr, certificatePtr, dataBuffer.get(), PKCS7_BINARY) == 1) + switch (m_keyLength) { - BUF_MEM* memoryBuffer = nullptr; - BIO_get_mem_ptr(dataBuffer.get(), &memoryBuffer); + case 128: + EVP_DigestInit(context, EVP_sha1()); + break; - // Acc. to chapter 7.6.5.3 - decrypted data - QByteArray decryptedData(memoryBuffer->data, int(memoryBuffer->length)); + case 256: + EVP_DigestInit(context, EVP_sha256()); + break; - // Calculate file encryption key - EVP_MD_CTX* context = EVP_MD_CTX_new(); - Q_ASSERT(context); - - switch (m_keyLength) - { - case 128: - EVP_DigestInit(context, EVP_sha1()); - break; - - case 256: - EVP_DigestInit(context, EVP_sha256()); - break; - - default: - Q_ASSERT(false); - EVP_DigestInit(context, EVP_sha256()); - break; - } - - QByteArray seed = decryptedData.left(20); - - // 7.6.5.3 a) - EVP_DigestUpdate(context, seed.constData(), seed.size()); - - // 7.6.5.3 b) - for (const QByteArray& recipient : m_filterDefault.recipients) - { - EVP_DigestUpdate(context, recipient.constData(), recipient.size()); - } - - // 7.6.5.3 c) - if (!isMetadataEncrypted()) - { - constexpr uint32_t value = 0xFFFFFFFF; - EVP_DigestUpdate(context, &value, sizeof(value)); - } - - unsigned int size = EVP_MD_size(EVP_MD_CTX_md(context)); - QByteArray digestBuffer(size, char()); - - EVP_DigestFinal_ex(context, convertByteArrayToUcharPtr(digestBuffer), &size); - EVP_MD_CTX_free(context); - - if (decryptedData.size() == 20 + sizeof(uint32_t)) - { - // We shall set permissions - m_permissions = qFromLittleEndian(decryptedData.data() + 20); - } - - m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8); - m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized; - return AuthorizationResult::UserAuthorized; + default: + Q_ASSERT(false); + EVP_DigestInit(context, EVP_sha256()); + break; } + + QByteArray seed = decryptedData.left(20); + + // 7.6.5.3 a) + EVP_DigestUpdate(context, seed.constData(), seed.size()); + + // 7.6.5.3 b) + for (const QByteArray& recipient : m_filterDefault.recipients) + { + EVP_DigestUpdate(context, recipient.constData(), recipient.size()); + } + + // 7.6.5.3 c) + if (!isMetadataEncrypted()) + { + constexpr uint32_t value = 0xFFFFFFFF; + EVP_DigestUpdate(context, &value, sizeof(value)); + } + + unsigned int size = EVP_MD_size(EVP_MD_CTX_md(context)); + QByteArray digestBuffer(size, char()); + + EVP_DigestFinal_ex(context, convertByteArrayToUcharPtr(digestBuffer), &size); + EVP_MD_CTX_free(context); + + if (decryptedData.size() == 20 + sizeof(uint32_t)) + { + // We shall set permissions + m_permissions = qFromLittleEndian(decryptedData.data() + 20); + } + + m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8); + m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized; + return AuthorizationResult::UserAuthorized; } } } diff --git a/Pdf4QtLibCore/sources/pdfsecurityhandler.h b/Pdf4QtLibCore/sources/pdfsecurityhandler.h index f55a8a6..14895d0 100644 --- a/Pdf4QtLibCore/sources/pdfsecurityhandler.h +++ b/Pdf4QtLibCore/sources/pdfsecurityhandler.h @@ -20,6 +20,7 @@ #include "pdfglobal.h" #include "pdfobject.h" +#include "pdfcertificatestore.h" #include #include @@ -477,7 +478,7 @@ public: QString ownerPassword; uint32_t permissions = 0; QByteArray id; - QString certificateFileName; + PDFCertificateEntry certificate; }; /// Creates security handler based on given settings. If security handler cannot @@ -514,5 +515,4 @@ public: } // namespace pdf - #endif // PDFSECURITYHANDLER_H diff --git a/Pdf4QtLibCore/sources/pdfsignaturehandler.cpp b/Pdf4QtLibCore/sources/pdfsignaturehandler.cpp index 2500ae7..d211c46 100644 --- a/Pdf4QtLibCore/sources/pdfsignaturehandler.cpp +++ b/Pdf4QtLibCore/sources/pdfsignaturehandler.cpp @@ -60,19 +60,6 @@ namespace pdf template using openssl_ptr = std::unique_ptr; -static QRecursiveMutex s_globalOpenSSLMutex; - -/// OpenSSL is not thread safe. -class PDFOpenSSLGlobalLock -{ -public: - explicit inline PDFOpenSSLGlobalLock() : m_mutexLocker(&s_globalOpenSSLMutex) { } - inline ~PDFOpenSSLGlobalLock() = default; - -private: - QMutexLocker m_mutexLocker; -}; - PDFSignatureReference PDFSignatureReference::parse(const PDFObjectStorage* storage, PDFObject object) { PDFSignatureReference result; @@ -1569,263 +1556,7 @@ BIO* PDFSignatureHandler_adbe_pkcs7_sha1::getSignedDataBuffer(PDFSignatureVerifi PDFCertificateInfo PDFPublicKeySignatureHandler::getCertificateInfo(X509* certificate) { - PDFCertificateInfo info; - - if (X509_NAME* subjectName = X509_get_subject_name(certificate)) - { - // List of these properties are in RFC 5280, section 4.1.2.4, these attributes - // are standard and all implementations must be prepared to process them. - QString countryName = getStringFromX509Name(subjectName, NID_countryName); - QString organizationName = getStringFromX509Name(subjectName, NID_organizationName); - QString organizationalUnitName = getStringFromX509Name(subjectName, NID_organizationalUnitName); - QString distinguishedName = getStringFromX509Name(subjectName, NID_distinguishedName); - QString stateOrProvinceName = getStringFromX509Name(subjectName, NID_stateOrProvinceName); - QString commonName = getStringFromX509Name(subjectName, NID_commonName); - QString serialNumber = getStringFromX509Name(subjectName, NID_serialNumber); - - // These attributes are defined also in section 4.1.2.4, they are not mandatory, - // but application should be able to process them. - QString localityName = getStringFromX509Name(subjectName, NID_localityName); - QString title = getStringFromX509Name(subjectName, NID_title); - QString surname = getStringFromX509Name(subjectName, NID_surname); - QString givenName = getStringFromX509Name(subjectName, NID_givenName); - QString initials = getStringFromX509Name(subjectName, NID_initials); - QString pseudonym = getStringFromX509Name(subjectName, NID_pseudonym); - QString generationQualifier = getStringFromX509Name(subjectName, NID_generationQualifier); - - // This entry is not defined in section 4.1.2.4, but is commonly used - QString email = getStringFromX509Name(subjectName, NID_pkcs9_emailAddress); - - info.setName(PDFCertificateInfo::CountryName, qMove(countryName)); - info.setName(PDFCertificateInfo::OrganizationName, qMove(organizationName)); - info.setName(PDFCertificateInfo::OrganizationalUnitName, qMove(organizationalUnitName)); - info.setName(PDFCertificateInfo::DistinguishedName, qMove(distinguishedName)); - info.setName(PDFCertificateInfo::StateOrProvinceName, qMove(stateOrProvinceName)); - info.setName(PDFCertificateInfo::CommonName, qMove(commonName)); - info.setName(PDFCertificateInfo::SerialNumber, qMove(serialNumber)); - - info.setName(PDFCertificateInfo::LocalityName, qMove(localityName)); - info.setName(PDFCertificateInfo::Title, qMove(title)); - info.setName(PDFCertificateInfo::Surname, qMove(surname)); - info.setName(PDFCertificateInfo::GivenName, qMove(givenName)); - info.setName(PDFCertificateInfo::Initials, qMove(initials)); - info.setName(PDFCertificateInfo::Pseudonym, qMove(pseudonym)); - info.setName(PDFCertificateInfo::GenerationalQualifier, qMove(generationQualifier)); - - info.setName(PDFCertificateInfo::Email, qMove(email)); - - const long version = X509_get_version(certificate); - info.setVersion(version); - - const ASN1_TIME* notBeforeTime = X509_get0_notBefore(certificate); - const ASN1_TIME* notAfterTime = X509_get0_notAfter(certificate); - - info.setNotValidBefore(getDateTimeFromASN(notBeforeTime)); - info.setNotValidAfter(getDateTimeFromASN(notAfterTime)); - - X509_PUBKEY* publicKey = X509_get_X509_PUBKEY(certificate); - EVP_PKEY* evpKey = X509_PUBKEY_get(publicKey); - const int keyType = EVP_PKEY_type(EVP_PKEY_base_id(evpKey)); - - PDFCertificateInfo::PublicKey key = PDFCertificateInfo::KeyUnknown; - switch (keyType) - { - case EVP_PKEY_RSA: - key = PDFCertificateInfo::KeyRSA; - break; - - case EVP_PKEY_DSA: - key = PDFCertificateInfo::KeyDSA; - break; - - case EVP_PKEY_DH: - key = PDFCertificateInfo::KeyDH; - break; - - case EVP_PKEY_EC: - key = PDFCertificateInfo::KeyEC; - break; - - default: - break; - } - info.setPublicKey(key); - - const int bits = EVP_PKEY_bits(evpKey); - info.setKeySize(bits); - - uint32_t keyUsage = X509_get_key_usage(certificate); - if (keyUsage != UINT32_MAX) - { - static_assert(PDFCertificateInfo::KeyUsageDigitalSignature == KU_DIGITAL_SIGNATURE, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageNonRepudiation == KU_NON_REPUDIATION, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageKeyEncipherment == KU_KEY_ENCIPHERMENT, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageDataEncipherment == KU_DATA_ENCIPHERMENT, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageAgreement == KU_KEY_AGREEMENT, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageCertSign == KU_KEY_CERT_SIGN, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageCrlSign == KU_CRL_SIGN, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageEncipherOnly == KU_ENCIPHER_ONLY, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageDecipherOnly == KU_DECIPHER_ONLY, "Fix this code!"); - - if (X509_get_extension_flags(certificate) & EXFLAG_XKUSAGE) - { - const uint32_t extendedKeyUsage = X509_get_extended_key_usage(certificate); - Q_ASSERT(extendedKeyUsage != UINT32_MAX); - - static_assert(PDFCertificateInfo::KeyUsageExtended_SSL_SERVER >> 16 == XKU_SSL_SERVER, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_SSL_CLIENT >> 16 == XKU_SSL_CLIENT, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_SMIME >> 16 == XKU_SMIME, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_CODE_SIGN >> 16 == XKU_CODE_SIGN, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_SGC >> 16 == XKU_SGC, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_OCSP_SIGN >> 16 == XKU_OCSP_SIGN, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_TIMESTAMP >> 16 == XKU_TIMESTAMP, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_DVCS >> 16 == XKU_DVCS, "Fix this code!"); - static_assert(PDFCertificateInfo::KeyUsageExtended_ANYEKU >> 16 == XKU_ANYEKU, "Fix this code!"); - - keyUsage = keyUsage | (extendedKeyUsage << 16); - } - - info.setKeyUsage(static_cast(keyUsage)); - } - - unsigned char* buffer = nullptr; - int length = i2d_X509(certificate, &buffer); - if (length >= 0) - { - Q_ASSERT(buffer); - info.setCertificateData(QByteArray(reinterpret_cast(buffer), length)); - OPENSSL_free(buffer); - } - } - - return info; -} - -void PDFCertificateInfo::serialize(QDataStream& stream) const -{ - stream << persist_version; - stream << m_version; - stream << m_keySize; - stream << m_publicKey; - stream << m_nameEntries; - stream << m_notValidBefore; - stream << m_notValidAfter; - stream << m_keyUsage; - stream << m_certificateData; -} - -void PDFCertificateInfo::deserialize(QDataStream& stream) -{ - int persistVersionDeserialized = 0; - stream >> persistVersionDeserialized; - stream >> m_version; - stream >> m_keySize; - stream >> m_publicKey; - stream >> m_nameEntries; - stream >> m_notValidBefore; - stream >> m_notValidAfter; - stream >> m_keyUsage; - stream >> m_certificateData; -} - -QDateTime PDFCertificateInfo::getNotValidBefore() const -{ - return m_notValidBefore; -} - -void PDFCertificateInfo::setNotValidBefore(const QDateTime& notValidBefore) -{ - m_notValidBefore = notValidBefore; -} - -QDateTime PDFCertificateInfo::getNotValidAfter() const -{ - return m_notValidAfter; -} - -void PDFCertificateInfo::setNotValidAfter(const QDateTime& notValidAfter) -{ - m_notValidAfter = notValidAfter; -} - -int32_t PDFCertificateInfo::getVersion() const -{ - return m_version; -} - -void PDFCertificateInfo::setVersion(int32_t version) -{ - m_version = version; -} - -PDFCertificateInfo::PublicKey PDFCertificateInfo::getPublicKey() const -{ - return m_publicKey; -} - -void PDFCertificateInfo::setPublicKey(const PublicKey& publicKey) -{ - m_publicKey = publicKey; -} - -int PDFCertificateInfo::getKeySize() const -{ - return m_keySize; -} - -void PDFCertificateInfo::setKeySize(int keySize) -{ - m_keySize = keySize; -} - -PDFCertificateInfo::KeyUsageFlags PDFCertificateInfo::getKeyUsage() const -{ - return m_keyUsage; -} - -void PDFCertificateInfo::setKeyUsage(KeyUsageFlags keyUsage) -{ - m_keyUsage = keyUsage; -} - -std::optional PDFCertificateInfo::getCertificateInfo(const QByteArray& certificateData) -{ - std::optional result; - - PDFOpenSSLGlobalLock lock; - const unsigned char* data = convertByteArrayToUcharPtr(certificateData); - if (X509* certificate = d2i_X509(nullptr, &data, certificateData.length())) - { - result = PDFPublicKeySignatureHandler::getCertificateInfo(certificate); - X509_free(certificate); - } - - return result; -} - -QByteArray PDFCertificateInfo::getCertificateData() const -{ - return m_certificateData; -} - -void PDFCertificateInfo::setCertificateData(const QByteArray& certificateData) -{ - m_certificateData = certificateData; -} - -void PDFCertificateStore::CertificateEntry::serialize(QDataStream& stream) const -{ - stream << persist_version; - stream << type; - stream << info; -} - -void PDFCertificateStore::CertificateEntry::deserialize(QDataStream& stream) -{ - int persistVersionDeserialized = 0; - stream >> persistVersionDeserialized; - stream >> type; - stream >> info; + return PDFCertificateInfo::getCertificateInfo(certificate); } QString PDFPublicKeySignatureHandler::getStringFromX509Name(X509_NAME* name, int nid) @@ -1938,100 +1669,6 @@ void PDFPublicKeySignatureHandler::addSignatureDateFromSignerInfoStack(STACK_OF( } } -void PDFCertificateStore::serialize(QDataStream& stream) const -{ - stream << persist_version; - stream << m_certificates; -} - -void PDFCertificateStore::deserialize(QDataStream& stream) -{ - int persistVersionDeserialized = 0; - stream >> persistVersionDeserialized; - stream >> m_certificates; -} - -bool PDFCertificateStore::add(EntryType type, const QByteArray& certificate) -{ - if (auto certificateInfo = PDFCertificateInfo::getCertificateInfo(certificate)) - { - return add(type, qMove(*certificateInfo)); - } - - return false; -} - -bool PDFCertificateStore::add(EntryType type, PDFCertificateInfo info) -{ - auto it = std::find_if(m_certificates.cbegin(), m_certificates.cend(), [&info](const auto& entry) { return entry.info == info; }); - if (it == m_certificates.cend()) - { - m_certificates.push_back({ type, qMove(info) }); - } - - return true; -} - -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(); -} - -QString PDFCertificateStore::getDefaultCertificateStoreFileName() const -{ - return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/TrustedCertStorage.bin"; -} - -void PDFCertificateStore::loadDefaultUserCertificates() -{ - createDirectoryForDefaultUserCertificatesStore(); - QString trustedCertificateStoreFileName = getDefaultCertificateStoreFileName(); - QString trustedCertificateStoreLockFileName = trustedCertificateStoreFileName + ".lock"; - - QLockFile lockFile(trustedCertificateStoreLockFileName); - if (lockFile.lock()) - { - QFile trustedCertificateStoreFile(trustedCertificateStoreFileName); - if (trustedCertificateStoreFile.open(QFile::ReadOnly)) - { - QDataStream stream(&trustedCertificateStoreFile); - deserialize(stream); - trustedCertificateStoreFile.close(); - } - lockFile.unlock(); - } -} - -void PDFCertificateStore::saveDefaultUserCertificates() -{ - createDirectoryForDefaultUserCertificatesStore(); - QString trustedCertificateStoreFileName = getDefaultCertificateStoreFileName(); - QString trustedCertificateStoreLockFileName = trustedCertificateStoreFileName + ".lock"; - - QFileInfo fileInfo(trustedCertificateStoreFileName); - QDir dir = fileInfo.dir(); - dir.mkpath(dir.path()); - - QLockFile lockFile(trustedCertificateStoreLockFileName); - if (lockFile.lock()) - { - QFile trustedCertificateStoreFile(trustedCertificateStoreFileName); - if (trustedCertificateStoreFile.open(QFile::WriteOnly | QFile::Truncate)) - { - QDataStream stream(&trustedCertificateStoreFile); - serialize(stream); - trustedCertificateStoreFile.close(); - } - lockFile.unlock(); - } -} - -void PDFCertificateStore::createDirectoryForDefaultUserCertificatesStore() -{ - QFileInfo fileInfo(getDefaultCertificateStoreFileName()); - QString path = fileInfo.path(); - QDir().mkpath(path); -} } // namespace pdf @@ -2047,7 +1684,7 @@ void pdf::PDFPublicKeySignatureHandler::addTrustedCertificates(X509_STORE* store { if (m_parameters.store) { - const PDFCertificateStore::CertificateEntries& certificates = m_parameters.store->getCertificates(); + const PDFCertificateEntries& certificates = m_parameters.store->getCertificates(); for (const auto& entry : certificates) { QByteArray certificateData = entry.info.getCertificateData(); @@ -2085,36 +1722,6 @@ void pdf::PDFPublicKeySignatureHandler::addTrustedCertificates(X509_STORE* store #endif } -pdf::PDFCertificateStore::CertificateEntries pdf::PDFCertificateStore::getSystemCertificates() -{ - CertificateEntries result; - -#ifdef Q_OS_WIN - HCERTSTORE certStore = CertOpenSystemStore(0, 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; -} - #if defined(PDF4QT_COMPILER_MINGW) || defined(PDF4QT_COMPILER_GCC) #pragma GCC diagnostic pop #endif diff --git a/Pdf4QtLibCore/sources/pdfsignaturehandler.h b/Pdf4QtLibCore/sources/pdfsignaturehandler.h index 388e424..32f071a 100644 --- a/Pdf4QtLibCore/sources/pdfsignaturehandler.h +++ b/Pdf4QtLibCore/sources/pdfsignaturehandler.h @@ -21,6 +21,7 @@ #include "pdfglobal.h" #include "pdfobject.h" #include "pdfutils.h" +#include "pdfcertificatestore.h" #include #include @@ -152,124 +153,6 @@ private: AuthentificationType m_propType = AuthentificationType::Invalid; }; -/// Info about certificate, various details etc. -class PDF4QTLIBCORESHARED_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 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 m_nameEntries; - QDateTime m_notValidBefore; - QDateTime m_notValidAfter; - KeyUsageFlags m_keyUsage; - QByteArray m_certificateData; -}; - -using PDFCertificateInfos = std::vector; - class PDF4QTLIBCORESHARED_EXPORT PDFSignatureVerificationResult { public: @@ -462,88 +345,6 @@ private: 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 PDF4QTLIBCORESHARED_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; - - /// 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 diff --git a/Pdf4QtLibCore/sources/pdfutils.cpp b/Pdf4QtLibCore/sources/pdfutils.cpp index df7ffed..3e53300 100644 --- a/Pdf4QtLibCore/sources/pdfutils.cpp +++ b/Pdf4QtLibCore/sources/pdfutils.cpp @@ -36,6 +36,7 @@ #include #if defined(PDF4QT_USE_PRAGMA_LIB) #pragma comment(lib, "Secur32.lib") +#pragma comment(lib, "Ncrypt.lib") #endif #endif diff --git a/Pdf4QtLibWidgets/CMakeLists.txt b/Pdf4QtLibWidgets/CMakeLists.txt index 4541cc9..e8e620b 100644 --- a/Pdf4QtLibWidgets/CMakeLists.txt +++ b/Pdf4QtLibWidgets/CMakeLists.txt @@ -63,6 +63,8 @@ add_library(Pdf4QtLibWidgets SHARED sources/pdfcompiler.h sources/pdfdocumentdrawinterface.h sources/pdfwidgetsglobal.h + sources/pdfcertificatelisthelper.h + sources/pdfcertificatelisthelper.cpp ) include(GenerateExportHeader) diff --git a/Pdf4QtLibWidgets/sources/pdfcertificatelisthelper.cpp b/Pdf4QtLibWidgets/sources/pdfcertificatelisthelper.cpp new file mode 100644 index 0000000..593ef14 --- /dev/null +++ b/Pdf4QtLibWidgets/sources/pdfcertificatelisthelper.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2023 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 . + +#include "pdfcertificatelisthelper.h" +#include "pdfwidgetutils.h" + +#include +#include +#include +#include + +namespace pdf +{ + +void PDFCertificateListHelper::initComboBox(QComboBox* comboBox) +{ + QStandardItemModel* model = new QStandardItemModel(comboBox); + model->setColumnCount(COLUMN_COUNT); + model->setRowCount(0); + comboBox->setModel(model); + + QTableView* tableView = new QTableView(comboBox); + + tableView->verticalHeader()->setVisible(false); + tableView->horizontalHeader()->setVisible(false); + + tableView->setVerticalScrollMode(QTableView::ScrollPerPixel); + tableView->setAlternatingRowColors(true); + tableView->setAutoScroll(false); + tableView->setShowGrid(false); + tableView->setSortingEnabled(false); + tableView->setColumnWidth(0, PDFWidgetUtils::scaleDPI_x(tableView, 150)); + tableView->setColumnWidth(1, PDFWidgetUtils::scaleDPI_x(tableView, 150)); + tableView->setColumnWidth(2, PDFWidgetUtils::scaleDPI_x(tableView, 75)); + tableView->setColumnWidth(3, PDFWidgetUtils::scaleDPI_x(tableView, 75)); + tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + + comboBox->setView(tableView); +} + +void PDFCertificateListHelper::fillComboBox(QComboBox* comboBox, const PDFCertificateEntries& entries) +{ + QString currentText = comboBox->currentText(); + + const bool updatesEnabled = comboBox->updatesEnabled(); + comboBox->setUpdatesEnabled(false); + + QStandardItemModel* model = qobject_cast(comboBox->model()); + model->setRowCount(int(entries.size())); + for (int i = 0; i < entries.size(); ++i) + { + const PDFCertificateEntry& entry = entries[i]; + + QString secondInfoEntry = entry.info.getName(PDFCertificateInfo::NameEntry::OrganizationName); + if (secondInfoEntry.isEmpty()) + { + secondInfoEntry = entry.info.getName(PDFCertificateInfo::NameEntry::Email); + } + + if (entry.pkcs12fileName.isEmpty()) + { + model->setItem(i, 0, new QStandardItem(entry.info.getName(PDFCertificateInfo::NameEntry::CommonName))); + model->setItem(i, 1, new QStandardItem(secondInfoEntry)); + model->setItem(i, 2, new QStandardItem(entry.info.getNotValidBefore().toLocalTime().toString())); + model->setItem(i, 3, new QStandardItem(entry.info.getNotValidAfter().toLocalTime().toString())); + } + else + { + model->setItem(i, 0, new QStandardItem(entry.pkcs12fileName)); + model->setItem(i, 1, new QStandardItem(tr("Password protected"))); + model->setItem(i, 2, new QStandardItem(QString())); + model->setItem(i, 3, new QStandardItem(QString())); + } + } + + comboBox->setUpdatesEnabled(updatesEnabled); + + int newCurrentIndex = comboBox->findText(currentText); + + if (newCurrentIndex < 0) + { + newCurrentIndex = 0; + } + + comboBox->setCurrentIndex(newCurrentIndex); + + QTableView* tableView = qobject_cast(comboBox->view()); + tableView->resizeColumnsToContents(); +} + +} // namespace pdf diff --git a/Pdf4QtLibWidgets/sources/pdfcertificatelisthelper.h b/Pdf4QtLibWidgets/sources/pdfcertificatelisthelper.h new file mode 100644 index 0000000..301b4c5 --- /dev/null +++ b/Pdf4QtLibWidgets/sources/pdfcertificatelisthelper.h @@ -0,0 +1,45 @@ +// Copyright (C) 2023 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 . + +#ifndef PDFCERTIFICATELISTHELPER_H +#define PDFCERTIFICATELISTHELPER_H + +#include "pdfwidgetsglobal.h" +#include "pdfcertificatestore.h" + +class QComboBox; + +namespace pdf +{ + +class PDF4QTLIBWIDGETSSHARED_EXPORT PDFCertificateListHelper +{ + Q_DECLARE_TR_FUNCTIONS(pdf::PDFCertificateListHelper) + +public: + PDFCertificateListHelper() = delete; + + static void initComboBox(QComboBox* comboBox); + static void fillComboBox(QComboBox* comboBox, const PDFCertificateEntries& entries); + +private: + static constexpr int COLUMN_COUNT = 4; +}; + +} // namespace pdf + +#endif // PDFCERTIFICATELISTHELPER_H diff --git a/Pdf4QtViewer/pdfencryptionsettingsdialog.cpp b/Pdf4QtViewer/pdfencryptionsettingsdialog.cpp index d020719..493c78d 100644 --- a/Pdf4QtViewer/pdfencryptionsettingsdialog.cpp +++ b/Pdf4QtViewer/pdfencryptionsettingsdialog.cpp @@ -23,6 +23,7 @@ #include "pdfwidgetutils.h" #include "pdfsecurityhandler.h" #include "pdfcertificatemanager.h" +#include "pdfcertificatelisthelper.h" #include @@ -84,6 +85,8 @@ PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QByteArray documentId, m_checkBoxToPermission[ui->permAssembleCheckBox] = pdf::PDFSecurityHandler::Permission::Assemble; m_checkBoxToPermission[ui->permPrintHighResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintHighResolution; + pdf::PDFCertificateListHelper::initComboBox(ui->certificateComboBox); + updateCertificates(); updateUi(); updatePasswordScore(); @@ -194,17 +197,8 @@ void PDFEncryptionSettingsDialog::updateUi() void PDFEncryptionSettingsDialog::updateCertificates() { - QFileInfoList certificates = pdf::PDFCertificateManager::getCertificates(); - - QVariant currentCertificate = ui->certificateComboBox->currentData(); - - ui->certificateComboBox->clear(); - for (const QFileInfo& certificateItem : certificates) - { - ui->certificateComboBox->addItem(certificateItem.fileName(), certificateItem.absoluteFilePath()); - } - - ui->certificateComboBox->setCurrentIndex(ui->certificateComboBox->findData(currentCertificate)); + m_certificates = pdf::PDFCertificateManager::getCertificates(); + pdf::PDFCertificateListHelper::fillComboBox(ui->certificateComboBox, m_certificates); } void PDFEncryptionSettingsDialog::updatePasswordScore() @@ -237,7 +231,12 @@ void PDFEncryptionSettingsDialog::accept() settings.userPassword = ui->userPasswordEdit->text(); settings.ownerPassword = ui->ownerPasswordEdit->text(); settings.permissions = 0; - settings.certificateFileName = ui->certificateComboBox->currentData().toString(); + + const int currentCertificateIndex = ui->certificateComboBox->currentIndex(); + if (currentCertificateIndex >= 0 && currentCertificateIndex < m_certificates.size()) + { + settings.certificate = m_certificates.at(currentCertificateIndex); + } for (auto item : m_checkBoxToPermission) { diff --git a/Pdf4QtViewer/pdfencryptionsettingsdialog.h b/Pdf4QtViewer/pdfencryptionsettingsdialog.h index 0870d3f..76915f9 100644 --- a/Pdf4QtViewer/pdfencryptionsettingsdialog.h +++ b/Pdf4QtViewer/pdfencryptionsettingsdialog.h @@ -20,6 +20,7 @@ #include "pdfviewerglobal.h" #include "pdfsecurityhandler.h" +#include "pdfcertificatestore.h" #include @@ -61,6 +62,7 @@ private: PDFEncryptionStrengthHintWidget* m_userPasswordStrengthHintWidget; PDFEncryptionStrengthHintWidget* m_ownerPasswordStrengthHintWidget; PDFEncryptionStrengthHintWidget* m_algorithmHintWidget; + pdf::PDFCertificateEntries m_certificates; }; } // namespace pdfviewer diff --git a/Pdf4QtViewer/pdfsidebarwidget.cpp b/Pdf4QtViewer/pdfsidebarwidget.cpp index a869410..e71f03d 100644 --- a/Pdf4QtViewer/pdfsidebarwidget.cpp +++ b/Pdf4QtViewer/pdfsidebarwidget.cpp @@ -767,7 +767,7 @@ void PDFSidebarWidget::onSignatureCustomContextMenuRequested(const QPoint& pos) { if (QMessageBox::question(this, tr("Add to Trusted Certificate Store"), tr("Are you sure want to add '%1' to the trusted certificate store?").arg(info.getName(pdf::PDFCertificateInfo::CommonName))) == QMessageBox::Yes) { - if (!m_certificateStore->add(pdf::PDFCertificateStore::EntryType::User, info)) + if (!m_certificateStore->add(pdf::PDFCertificateEntry::EntryType::User, info)) { QMessageBox::critical(this, tr("Trusted Certificate Store Error"), tr("Failed to add certificate to the trusted certificate store.")); } diff --git a/Pdf4QtViewer/pdfviewersettingsdialog.cpp b/Pdf4QtViewer/pdfviewersettingsdialog.cpp index e454019..d2d54b4 100644 --- a/Pdf4QtViewer/pdfviewersettingsdialog.cpp +++ b/Pdf4QtViewer/pdfviewersettingsdialog.cpp @@ -675,7 +675,7 @@ void PDFViewerSettingsDialog::updateTrustedCertificatesTable() ui->trustedCertificateStoreTableWidget->setUpdatesEnabled(false); ui->trustedCertificateStoreTableWidget->clear(); - const pdf::PDFCertificateStore::CertificateEntries& certificates = m_certificateStore.getCertificates(); + const pdf::PDFCertificateEntries& certificates = m_certificateStore.getCertificates(); ui->trustedCertificateStoreTableWidget->setRowCount(int(certificates.size())); ui->trustedCertificateStoreTableWidget->setColumnCount(5); ui->trustedCertificateStoreTableWidget->verticalHeader()->setVisible(true); @@ -688,15 +688,11 @@ void PDFViewerSettingsDialog::updateTrustedCertificatesTable() QString type; switch (certificates[i].type) { - case pdf::PDFCertificateStore::EntryType::User: + case pdf::PDFCertificateEntry::EntryType::User: type = tr("User"); break; - case pdf::PDFCertificateStore::EntryType::EUTL: - type = tr("EUTL"); - break; - - case pdf::PDFCertificateStore::EntryType::System: + case pdf::PDFCertificateEntry::EntryType::System: type = tr("System"); break; @@ -920,8 +916,8 @@ void PDFViewerSettingsDialog::on_removeCertificateButton_clicked() rows.insert(index.row()); } - pdf::PDFCertificateStore::CertificateEntries newEntries; - const pdf::PDFCertificateStore::CertificateEntries& certificates = m_certificateStore.getCertificates(); + pdf::PDFCertificateEntries newEntries; + const pdf::PDFCertificateEntries& certificates = m_certificateStore.getCertificates(); for (int i = 0; i < int(certificates.size()); ++i) { if (!rows.count(i)) diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp index 8bd8246..86e7e94 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp @@ -315,11 +315,11 @@ void SignaturePlugin::onSignDigitally() // Jakub Melka: do we have certificates? If not, // open certificate dialog, so the user can create // a new one. - if (pdf::PDFCertificateManager::getCertificates().isEmpty()) + if (pdf::PDFCertificateManager::getCertificates().empty()) { onOpenCertificatesManager(); - if (pdf::PDFCertificateManager::getCertificates().isEmpty()) + if (pdf::PDFCertificateManager::getCertificates().empty()) { return; } @@ -328,9 +328,12 @@ void SignaturePlugin::onSignDigitally() SignDialog dialog(m_dataExchangeInterface->getMainWindow(), m_scene.isEmpty()); if (dialog.exec() == SignDialog::Accepted) { + const pdf::PDFCertificateEntry* certificate = dialog.getCertificate(); + Q_ASSERT(certificate); + QByteArray data = "SampleDataToBeSigned" + QByteArray::number(QDateTime::currentMSecsSinceEpoch()); QByteArray signature; - if (!pdf::PDFSignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), data, signature)) + if (!pdf::PDFSignatureFactory::sign(*certificate, dialog.getPassword(), data, signature)) { QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature.")); return; @@ -459,7 +462,7 @@ void SignaturePlugin::onSignDigitally() buffer.seek(i3); dataToBeSigned.append(buffer.read(i4)); - if (!pdf::PDFSignatureFactory::sign(dialog.getCertificatePath(), dialog.getPassword(), dataToBeSigned, signature)) + if (!pdf::PDFSignatureFactory::sign(*certificate, dialog.getPassword(), dataToBeSigned, signature)) { QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature.")); buffer.close(); diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h index ea1cd86..2f6d3c4 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h @@ -108,6 +108,8 @@ private: void setActive(bool active); + pdf::PDFWidgetTool* getActiveTool(); + void updateActions(); void updateGraphics(); void updateDockWidget(); @@ -120,7 +122,6 @@ private: pdf::PDFPageContentScene m_scene; bool m_sceneSelectionChangeEnabled; - pdf::PDFWidgetTool* getActiveTool(); }; } // namespace pdfplugin diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp index b098f0d..7ab2876 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp @@ -19,6 +19,7 @@ #include "ui_signdialog.h" #include "pdfcertificatemanager.h" +#include "pdfcertificatelisthelper.h" #include @@ -41,11 +42,10 @@ SignDialog::SignDialog(QWidget* parent, bool isSceneEmpty) : ui->methodCombo->addItem(tr("Sign digitally (invisible signature)"), SignDigitallyInvisible); ui->methodCombo->setCurrentIndex(0); - QFileInfoList certificates = pdf::PDFCertificateManager::getCertificates(); - for (const QFileInfo& certificateFileInfo : certificates) - { - ui->certificateCombo->addItem(certificateFileInfo.fileName(), certificateFileInfo.absoluteFilePath()); - } + m_certificates = pdf::PDFCertificateManager::getCertificates(); + + pdf::PDFCertificateListHelper::initComboBox(ui->certificateCombo); + pdf::PDFCertificateListHelper::fillComboBox(ui->certificateCombo, m_certificates); } SignDialog::~SignDialog() @@ -58,11 +58,6 @@ SignDialog::SignMethod SignDialog::getSignMethod() const return static_cast(ui->methodCombo->currentData().toInt()); } -QString SignDialog::getCertificatePath() const -{ - return ui->certificateCombo->currentData().toString(); -} - QString SignDialog::getPassword() const { return ui->certificatePasswordEdit->text(); @@ -78,10 +73,23 @@ QString SignDialog::getContactInfoText() const return ui->contactInfoEdit->text(); } +const pdf::PDFCertificateEntry* SignDialog::getCertificate() const +{ + const int index = ui->certificateCombo->currentIndex(); + if (index >= 0 && index < m_certificates.size()) + { + return &m_certificates.at(index); + } + + return nullptr; +} + void SignDialog::accept() { + const pdf::PDFCertificateEntry* certificate = getCertificate(); + // Check certificate - if (!QFile::exists(getCertificatePath())) + if (!certificate) { QMessageBox::critical(this, tr("Error"), tr("Certificate does not exist.")); ui->certificateCombo->setFocus(); @@ -89,7 +97,7 @@ void SignDialog::accept() } // Check we can access the certificate - if (!pdf::PDFCertificateManager::isCertificateValid(getCertificatePath(), ui->certificatePasswordEdit->text())) + if (!pdf::PDFCertificateManager::isCertificateValid(*certificate, ui->certificatePasswordEdit->text())) { QMessageBox::critical(this, tr("Error"), tr("Password to open certificate is invalid.")); ui->certificatePasswordEdit->setFocus(); diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h index 6546b58..e6734dd 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h @@ -18,6 +18,8 @@ #ifndef SIGNDIALOG_H #define SIGNDIALOG_H +#include "pdfcertificatemanager.h" + #include namespace Ui @@ -45,13 +47,14 @@ public: }; SignMethod getSignMethod() const; - QString getCertificatePath() const; QString getPassword() const; QString getReasonText() const; QString getContactInfoText() const; + const pdf::PDFCertificateEntry* getCertificate() const; private: Ui::SignDialog* ui; + pdf::PDFCertificateEntries m_certificates; }; } // namespace pdfplugin diff --git a/PdfTool/pdftoolcertstore.cpp b/PdfTool/pdftoolcertstore.cpp index b001b79..875393d 100644 --- a/PdfTool/pdftoolcertstore.cpp +++ b/PdfTool/pdftoolcertstore.cpp @@ -58,10 +58,10 @@ int PDFToolCertStore::execute(const PDFToolOptions& options) certificateStore.loadDefaultUserCertificates(); } - pdf::PDFCertificateStore::CertificateEntries certificates = certificateStore.getCertificates(); + pdf::PDFCertificateEntries certificates = certificateStore.getCertificates(); if (options.certStoreEnumerateSystemCertificates) { - pdf::PDFCertificateStore::CertificateEntries systemCertificates = pdf::PDFCertificateStore::getSystemCertificates(); + pdf::PDFCertificateEntries systemCertificates = pdf::PDFCertificateStore::getSystemCertificates(); certificates.insert(certificates.end(), std::make_move_iterator(systemCertificates.begin()), std::make_move_iterator(systemCertificates.end())); } @@ -83,20 +83,16 @@ int PDFToolCertStore::execute(const PDFToolOptions& options) int ref = 1; QLocale locale; - for (const pdf::PDFCertificateStore::CertificateEntry& entry : certificates) + for (const pdf::PDFCertificateEntry& entry : certificates) { QString type; switch (entry.type) { - case pdf::PDFCertificateStore::EntryType::User: + case pdf::PDFCertificateEntry::EntryType::User: type = PDFToolTranslationContext::tr("User"); break; - case pdf::PDFCertificateStore::EntryType::EUTL: - type = PDFToolTranslationContext::tr("EUTL"); - break; - - case pdf::PDFCertificateStore::EntryType::System: + case pdf::PDFCertificateEntry::EntryType::System: type = PDFToolTranslationContext::tr("System"); break; @@ -185,7 +181,7 @@ int PDFToolCertStoreInstallCertificate::execute(const PDFToolOptions& options) pdf::PDFCertificateStore certificateStore; certificateStore.loadDefaultUserCertificates(); - if (certificateStore.add(pdf::PDFCertificateStore::EntryType::User, certificateData)) + if (certificateStore.add(pdf::PDFCertificateEntry::EntryType::User, certificateData)) { certificateStore.saveDefaultUserCertificates(); }