mirror of https://github.com/JakubMelka/PDF4QT.git
Merge remote-tracking branch 'remotes/origin/branches/issue55'
This commit is contained in:
commit
94b392c108
|
@ -144,6 +144,8 @@ add_library(Pdf4QtLibCore SHARED
|
||||||
sources/pdfwidgetsnapshot.cpp
|
sources/pdfwidgetsnapshot.cpp
|
||||||
sources/pdfwidgetsnapshot.h
|
sources/pdfwidgetsnapshot.h
|
||||||
cmaps.qrc
|
cmaps.qrc
|
||||||
|
sources/pdfcertificatestore.h
|
||||||
|
sources/pdfcertificatestore.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
|
|
@ -144,10 +144,57 @@ void PDFCertificateManager::createCertificate(const NewCertificateInfo& info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QFileInfoList PDFCertificateManager::getCertificates()
|
PDFCertificateEntries PDFCertificateManager::getCertificates()
|
||||||
{
|
{
|
||||||
|
PDFCertificateEntries entries = PDFCertificateStore::getPersonalCertificates();
|
||||||
|
|
||||||
QDir directory(getCertificateDirectory());
|
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<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> 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<PDFCertificateInfo> 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()
|
QString PDFCertificateManager::getCertificateDirectory()
|
||||||
|
@ -175,46 +222,42 @@ QString PDFCertificateManager::generateCertificateFileName()
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PDFCertificateManager::isCertificateValid(QString fileName, QString password)
|
bool PDFCertificateManager::isCertificateValid(const PDFCertificateEntry& certificateEntry, QString password)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QByteArray pkcs12data = certificateEntry.pkcs12;
|
||||||
if (file.open(QFile::ReadOnly))
|
|
||||||
|
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(pksBuffer.get(), pkcs12data.constData(), pkcs12data.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
||||||
|
if (pkcs12)
|
||||||
{
|
{
|
||||||
QByteArray data = file.readAll();
|
const char* passwordPointer = nullptr;
|
||||||
file.close();
|
QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8();
|
||||||
|
if (!passwordByteArray.isEmpty())
|
||||||
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
|
||||||
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
|
||||||
|
|
||||||
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
|
||||||
if (pkcs12)
|
|
||||||
{
|
{
|
||||||
const char* passwordPointer = nullptr;
|
passwordPointer = passwordByteArray.constData();
|
||||||
QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8();
|
|
||||||
if (!passwordByteArray.isEmpty())
|
|
||||||
{
|
|
||||||
passwordPointer = passwordByteArray.constData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return PKCS12_parse(pkcs12.get(), passwordPointer, nullptr, nullptr, nullptr) == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
QByteArray pkcs12Data = certificateEntry.pkcs12;
|
||||||
if (file.open(QFile::ReadOnly))
|
|
||||||
|
if (!pkcs12Data.isEmpty())
|
||||||
{
|
{
|
||||||
QByteArray certificateData = file.readAll();
|
openssl_ptr<BIO> pkcs12Buffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
file.close();
|
BIO_write(pkcs12Buffer.get(), pkcs12Data.constData(), pkcs12Data.length());
|
||||||
|
|
||||||
openssl_ptr<BIO> certificateBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pkcs12Buffer.get(), nullptr), &PKCS12_free);
|
||||||
BIO_write(certificateBuffer.get(), certificateData.constData(), certificateData.length());
|
|
||||||
|
|
||||||
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(certificateBuffer.get(), nullptr), &PKCS12_free);
|
|
||||||
if (pkcs12)
|
if (pkcs12)
|
||||||
{
|
{
|
||||||
const char* passwordPointer = nullptr;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#include <ncrypt.h>
|
||||||
|
#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<const char*>(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)
|
#if defined(PDF4QT_COMPILER_MINGW) || defined(PDF4QT_COMPILER_GCC)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2022 Jakub Melka
|
// Copyright (C) 2022-2023 Jakub Melka
|
||||||
//
|
//
|
||||||
// This file is part of PDF4QT.
|
// This file is part of PDF4QT.
|
||||||
//
|
//
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#define PDFCERTIFICATEMANAGER_H
|
#define PDFCERTIFICATEMANAGER_H
|
||||||
|
|
||||||
#include "pdfglobal.h"
|
#include "pdfglobal.h"
|
||||||
|
#include "pdfcertificatestore.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QFileInfoList>
|
#include <QFileInfoList>
|
||||||
|
@ -49,16 +50,25 @@ public:
|
||||||
|
|
||||||
void createCertificate(const NewCertificateInfo& info);
|
void createCertificate(const NewCertificateInfo& info);
|
||||||
|
|
||||||
static QFileInfoList getCertificates();
|
static PDFCertificateEntries getCertificates();
|
||||||
static QString getCertificateDirectory();
|
static QString getCertificateDirectory();
|
||||||
static QString generateCertificateFileName();
|
static QString generateCertificateFileName();
|
||||||
static bool isCertificateValid(QString fileName, QString password);
|
static bool isCertificateValid(const PDFCertificateEntry& certificateEntry, QString password);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureFactory
|
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureFactory
|
||||||
{
|
{
|
||||||
public:
|
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
|
} // namespace pdf
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#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 <openssl/err.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/rsaerr.h>
|
||||||
|
#include <openssl/ts.h>
|
||||||
|
#include <openssl/tserr.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QLockFile>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#include "pdfdbgheap.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
#include <time.h>
|
||||||
|
#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> PDFCertificateInfo::getCertificateInfo(const QByteArray& certificateData)
|
||||||
|
{
|
||||||
|
std::optional<PDFCertificateInfo> 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<const char*>(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<PDFCertificateInfo::KeyUsageFlags>(keyUsage));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* buffer = nullptr;
|
||||||
|
int length = i2d_X509(certificate, &buffer);
|
||||||
|
if (length >= 0)
|
||||||
|
{
|
||||||
|
Q_ASSERT(buffer);
|
||||||
|
info.setCertificateData(QByteArray(reinterpret_cast<const char*>(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 <Windows.h>
|
||||||
|
#include <wincrypt.h>
|
||||||
|
#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<const char*>(pointer), context->cbCertEncoded);
|
||||||
|
std::optional<PDFCertificateInfo> 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<const char*>(pointer), context->cbCertEncoded);
|
||||||
|
std::optional<PDFCertificateInfo> 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
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef PDFCERTIFICATESTORE_H
|
||||||
|
#define PDFCERTIFICATESTORE_H
|
||||||
|
|
||||||
|
#include "pdfglobal.h"
|
||||||
|
|
||||||
|
#include <QFlags>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QRecursiveMutex>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
|
||||||
|
class QDataStream;
|
||||||
|
struct x509_st;
|
||||||
|
|
||||||
|
namespace pdf
|
||||||
|
{
|
||||||
|
|
||||||
|
/// OpenSSL is not thread safe.
|
||||||
|
class PDF4QTLIBCORESHARED_EXPORT PDFOpenSSLGlobalLock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit PDFOpenSSLGlobalLock();
|
||||||
|
inline ~PDFOpenSSLGlobalLock() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutexLocker<QRecursiveMutex> 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<PDFCertificateInfo> 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<QString, NameEnd> m_nameEntries;
|
||||||
|
QDateTime m_notValidBefore;
|
||||||
|
QDateTime m_notValidAfter;
|
||||||
|
KeyUsageFlags m_keyUsage;
|
||||||
|
QByteArray m_certificateData;
|
||||||
|
};
|
||||||
|
|
||||||
|
using PDFCertificateInfos = std::vector<PDFCertificateInfo>;
|
||||||
|
|
||||||
|
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<PDFCertificateEntry>;
|
||||||
|
|
||||||
|
/// 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
|
|
@ -1979,62 +1979,57 @@ PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const
|
||||||
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_PrintHighResolution;
|
publicKeyHandler->m_permissions = publicKeyHandler->m_permissions | PDFPublicKeySecurityHandler::PKSH_PrintHighResolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile file(settings.certificateFileName);
|
QByteArray data = settings.certificate.pkcs12;
|
||||||
if (file.open(QFile::ReadOnly))
|
|
||||||
|
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
||||||
|
if (pkcs12)
|
||||||
{
|
{
|
||||||
QByteArray data = file.readAll();
|
QByteArray password = PDFStandardOrPublicSecurityHandler::adjustPassword(settings.userPassword, 0);
|
||||||
file.close();
|
const char* passwordPointer = nullptr;
|
||||||
|
if (!password.isEmpty())
|
||||||
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
|
||||||
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
|
||||||
|
|
||||||
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
|
||||||
if (pkcs12)
|
|
||||||
{
|
{
|
||||||
QByteArray password = PDFStandardOrPublicSecurityHandler::adjustPassword(settings.userPassword, 0);
|
passwordPointer = password.constData();
|
||||||
const char* passwordPointer = nullptr;
|
}
|
||||||
if (!password.isEmpty())
|
|
||||||
|
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<EVP_PKEY> key(keyPtr, EVP_PKEY_free);
|
||||||
|
openssl_ptr<X509> certificate(certificatePtr, X509_free);
|
||||||
|
openssl_ptr<STACK_OF(X509)> certificates(certificatesPtr, sk_x509_free_impl);
|
||||||
|
openssl_ptr<BIO> 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<STACK_OF(X509)> recipientCertificates(sk_X509_new_null(), sk_x509_free_impl);
|
||||||
|
sk_X509_push(recipientCertificates.get(), certificate.get());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS7> pkcs7(PKCS7_encrypt(recipientCertificates.get(), dataToBeSigned.get(), EVP_aes_256_cbc(), PKCS7_BINARY), PKCS7_free);
|
||||||
|
|
||||||
|
if (pkcs7)
|
||||||
{
|
{
|
||||||
passwordPointer = password.constData();
|
openssl_ptr<BIO> storedData(BIO_new(BIO_s_mem()), BIO_free_all);
|
||||||
}
|
|
||||||
|
|
||||||
EVP_PKEY* keyPtr = nullptr;
|
if (i2d_PKCS7_bio(storedData.get(), pkcs7.get()))
|
||||||
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<EVP_PKEY> key(keyPtr, EVP_PKEY_free);
|
|
||||||
openssl_ptr<X509> certificate(certificatePtr, X509_free);
|
|
||||||
openssl_ptr<STACK_OF(X509)> certificates(certificatesPtr, sk_x509_free_impl);
|
|
||||||
openssl_ptr<BIO> 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<STACK_OF(X509)> recipientCertificates(sk_X509_new_null(), sk_x509_free_impl);
|
|
||||||
sk_X509_push(recipientCertificates.get(), certificate.get());
|
|
||||||
|
|
||||||
openssl_ptr<PKCS7> pkcs7(PKCS7_encrypt(recipientCertificates.get(), dataToBeSigned.get(), EVP_aes_256_cbc(), PKCS7_BINARY), PKCS7_free);
|
|
||||||
|
|
||||||
if (pkcs7)
|
|
||||||
{
|
{
|
||||||
openssl_ptr<BIO> 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()))
|
QByteArray recipient(memoryBuffer->data, int(memoryBuffer->length));
|
||||||
{
|
publicKeyHandler->m_filterDefault.recipients << recipient;
|
||||||
BUF_MEM* memoryBuffer = nullptr;
|
|
||||||
BIO_get_mem_ptr(storedData.get(), &memoryBuffer);
|
|
||||||
|
|
||||||
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:
|
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.");
|
*errorMessage = tr("Invalid certificate or password.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -2401,8 +2396,8 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat
|
||||||
constexpr int revision = 0;
|
constexpr int revision = 0;
|
||||||
QByteArray password = adjustPassword(getPasswordCallback(&passwordObtained), revision);
|
QByteArray password = adjustPassword(getPasswordCallback(&passwordObtained), revision);
|
||||||
|
|
||||||
QFileInfoList certificates = PDFCertificateManager::getCertificates();
|
PDFCertificateEntries certificates = PDFCertificateManager::getCertificates();
|
||||||
if (certificates.isEmpty())
|
if (certificates.empty())
|
||||||
{
|
{
|
||||||
return AuthorizationResult::Failed;
|
return AuthorizationResult::Failed;
|
||||||
}
|
}
|
||||||
|
@ -2421,114 +2416,109 @@ PDFSecurityHandler::AuthorizationResult PDFPublicKeySecurityHandler::authenticat
|
||||||
while (passwordObtained)
|
while (passwordObtained)
|
||||||
{
|
{
|
||||||
// We will iterate trough all certificates
|
// 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile file(certificateFileInfo.absoluteFilePath());
|
QByteArray data = certificateEntry.info.getCertificateData();
|
||||||
if (file.open(QFile::ReadOnly))
|
|
||||||
|
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
||||||
|
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
||||||
|
|
||||||
|
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
||||||
|
if (pkcs12)
|
||||||
{
|
{
|
||||||
QByteArray data = file.readAll();
|
const char* passwordPointer = nullptr;
|
||||||
file.close();
|
if (!password.isEmpty())
|
||||||
|
|
||||||
openssl_ptr<BIO> pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all);
|
|
||||||
BIO_write(pksBuffer.get(), data.constData(), data.length());
|
|
||||||
|
|
||||||
openssl_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free);
|
|
||||||
if (pkcs12)
|
|
||||||
{
|
{
|
||||||
const char* passwordPointer = nullptr;
|
passwordPointer = password.constData();
|
||||||
if (!password.isEmpty())
|
}
|
||||||
|
|
||||||
|
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<EVP_PKEY> key(keyPtr, EVP_PKEY_free);
|
||||||
|
openssl_ptr<X509> certificate(certificatePtr, X509_free);
|
||||||
|
openssl_ptr<STACK_OF(X509)> certificates2(certificatesPtr, sk_x509_free_impl);
|
||||||
|
|
||||||
|
for (const auto& recipientItem : recipients)
|
||||||
|
{
|
||||||
|
PKCS7* pkcs7 = recipientItem.get();
|
||||||
|
|
||||||
|
openssl_ptr<BIO> 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;
|
// Acc. to chapter 7.6.5.3 - decrypted data
|
||||||
X509* certificatePtr = nullptr;
|
QByteArray decryptedData(memoryBuffer->data, int(memoryBuffer->length));
|
||||||
STACK_OF(X509)* certificatesPtr = nullptr;
|
|
||||||
|
|
||||||
// Parse PKCS12 with password
|
// Calculate file encryption key
|
||||||
bool isParsed = PKCS12_parse(pkcs12.get(), passwordPointer, &keyPtr, &certificatePtr, &certificatesPtr) == 1;
|
EVP_MD_CTX* context = EVP_MD_CTX_new();
|
||||||
|
Q_ASSERT(context);
|
||||||
|
|
||||||
if (!isParsed)
|
switch (m_keyLength)
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
openssl_ptr<EVP_PKEY> key(keyPtr, EVP_PKEY_free);
|
|
||||||
openssl_ptr<X509> certificate(certificatePtr, X509_free);
|
|
||||||
openssl_ptr<STACK_OF(X509)> certificates2(certificatesPtr, sk_x509_free_impl);
|
|
||||||
|
|
||||||
for (const auto& recipientItem : recipients)
|
|
||||||
{
|
|
||||||
PKCS7* pkcs7 = recipientItem.get();
|
|
||||||
|
|
||||||
openssl_ptr<BIO> dataBuffer(BIO_new(BIO_s_mem()), BIO_free_all);
|
|
||||||
if (PKCS7_decrypt(pkcs7, keyPtr, certificatePtr, dataBuffer.get(), PKCS7_BINARY) == 1)
|
|
||||||
{
|
{
|
||||||
BUF_MEM* memoryBuffer = nullptr;
|
case 128:
|
||||||
BIO_get_mem_ptr(dataBuffer.get(), &memoryBuffer);
|
EVP_DigestInit(context, EVP_sha1());
|
||||||
|
break;
|
||||||
|
|
||||||
// Acc. to chapter 7.6.5.3 - decrypted data
|
case 256:
|
||||||
QByteArray decryptedData(memoryBuffer->data, int(memoryBuffer->length));
|
EVP_DigestInit(context, EVP_sha256());
|
||||||
|
break;
|
||||||
|
|
||||||
// Calculate file encryption key
|
default:
|
||||||
EVP_MD_CTX* context = EVP_MD_CTX_new();
|
Q_ASSERT(false);
|
||||||
Q_ASSERT(context);
|
EVP_DigestInit(context, EVP_sha256());
|
||||||
|
break;
|
||||||
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<uint32_t>(decryptedData.data() + 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8);
|
|
||||||
m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized;
|
|
||||||
return AuthorizationResult::UserAuthorized;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<uint32_t>(decryptedData.data() + 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_authorizationData.fileEncryptionKey = digestBuffer.left(m_keyLength / 8);
|
||||||
|
m_authorizationData.authorizationResult = AuthorizationResult::UserAuthorized;
|
||||||
|
return AuthorizationResult::UserAuthorized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "pdfglobal.h"
|
#include "pdfglobal.h"
|
||||||
#include "pdfobject.h"
|
#include "pdfobject.h"
|
||||||
|
#include "pdfcertificatestore.h"
|
||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
|
@ -477,7 +478,7 @@ public:
|
||||||
QString ownerPassword;
|
QString ownerPassword;
|
||||||
uint32_t permissions = 0;
|
uint32_t permissions = 0;
|
||||||
QByteArray id;
|
QByteArray id;
|
||||||
QString certificateFileName;
|
PDFCertificateEntry certificate;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creates security handler based on given settings. If security handler cannot
|
/// Creates security handler based on given settings. If security handler cannot
|
||||||
|
@ -514,5 +515,4 @@ public:
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
|
|
||||||
#endif // PDFSECURITYHANDLER_H
|
#endif // PDFSECURITYHANDLER_H
|
||||||
|
|
|
@ -60,19 +60,6 @@ namespace pdf
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using openssl_ptr = std::unique_ptr<T, void(*)(T*)>;
|
using openssl_ptr = std::unique_ptr<T, void(*)(T*)>;
|
||||||
|
|
||||||
static QRecursiveMutex s_globalOpenSSLMutex;
|
|
||||||
|
|
||||||
/// OpenSSL is not thread safe.
|
|
||||||
class PDFOpenSSLGlobalLock
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit inline PDFOpenSSLGlobalLock() : m_mutexLocker(&s_globalOpenSSLMutex) { }
|
|
||||||
inline ~PDFOpenSSLGlobalLock() = default;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QMutexLocker<QRecursiveMutex> m_mutexLocker;
|
|
||||||
};
|
|
||||||
|
|
||||||
PDFSignatureReference PDFSignatureReference::parse(const PDFObjectStorage* storage, PDFObject object)
|
PDFSignatureReference PDFSignatureReference::parse(const PDFObjectStorage* storage, PDFObject object)
|
||||||
{
|
{
|
||||||
PDFSignatureReference result;
|
PDFSignatureReference result;
|
||||||
|
@ -1569,263 +1556,7 @@ BIO* PDFSignatureHandler_adbe_pkcs7_sha1::getSignedDataBuffer(PDFSignatureVerifi
|
||||||
|
|
||||||
PDFCertificateInfo PDFPublicKeySignatureHandler::getCertificateInfo(X509* certificate)
|
PDFCertificateInfo PDFPublicKeySignatureHandler::getCertificateInfo(X509* certificate)
|
||||||
{
|
{
|
||||||
PDFCertificateInfo info;
|
return PDFCertificateInfo::getCertificateInfo(certificate);
|
||||||
|
|
||||||
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<PDFCertificateInfo::KeyUsageFlags>(keyUsage));
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char* buffer = nullptr;
|
|
||||||
int length = i2d_X509(certificate, &buffer);
|
|
||||||
if (length >= 0)
|
|
||||||
{
|
|
||||||
Q_ASSERT(buffer);
|
|
||||||
info.setCertificateData(QByteArray(reinterpret_cast<const char*>(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> PDFCertificateInfo::getCertificateInfo(const QByteArray& certificateData)
|
|
||||||
{
|
|
||||||
std::optional<PDFCertificateInfo> 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PDFPublicKeySignatureHandler::getStringFromX509Name(X509_NAME* name, int nid)
|
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
|
} // namespace pdf
|
||||||
|
|
||||||
|
@ -2047,7 +1684,7 @@ void pdf::PDFPublicKeySignatureHandler::addTrustedCertificates(X509_STORE* store
|
||||||
{
|
{
|
||||||
if (m_parameters.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)
|
for (const auto& entry : certificates)
|
||||||
{
|
{
|
||||||
QByteArray certificateData = entry.info.getCertificateData();
|
QByteArray certificateData = entry.info.getCertificateData();
|
||||||
|
@ -2085,36 +1722,6 @@ void pdf::PDFPublicKeySignatureHandler::addTrustedCertificates(X509_STORE* store
|
||||||
#endif
|
#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<const char*>(pointer), context->cbCertEncoded);
|
|
||||||
std::optional<PDFCertificateInfo> 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)
|
#if defined(PDF4QT_COMPILER_MINGW) || defined(PDF4QT_COMPILER_GCC)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "pdfglobal.h"
|
#include "pdfglobal.h"
|
||||||
#include "pdfobject.h"
|
#include "pdfobject.h"
|
||||||
#include "pdfutils.h"
|
#include "pdfutils.h"
|
||||||
|
#include "pdfcertificatestore.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
@ -152,124 +153,6 @@ private:
|
||||||
AuthentificationType m_propType = AuthentificationType::Invalid;
|
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<PDFCertificateInfo> getCertificateInfo(const QByteArray& certificateData);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr int persist_version = 1;
|
|
||||||
|
|
||||||
int32_t m_version = 0;
|
|
||||||
int m_keySize = 0;
|
|
||||||
PublicKey m_publicKey = KeyUnknown;
|
|
||||||
std::array<QString, NameEnd> m_nameEntries;
|
|
||||||
QDateTime m_notValidBefore;
|
|
||||||
QDateTime m_notValidAfter;
|
|
||||||
KeyUsageFlags m_keyUsage;
|
|
||||||
QByteArray m_certificateData;
|
|
||||||
};
|
|
||||||
|
|
||||||
using PDFCertificateInfos = std::vector<PDFCertificateInfo>;
|
|
||||||
|
|
||||||
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureVerificationResult
|
class PDF4QTLIBCORESHARED_EXPORT PDFSignatureVerificationResult
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -462,88 +345,6 @@ private:
|
||||||
static PDFSignatureHandler* createHandler(const PDFFormFieldSignature* signatureField, const QByteArray& sourceData, const Parameters& parameters);
|
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<CertificateEntry>;
|
|
||||||
|
|
||||||
/// Tries to add new certificate to the certificate store. If certificate
|
|
||||||
/// is already here, then nothing happens and function returns true.
|
|
||||||
/// Otherwise data are checked, if they really contains a certificate,
|
|
||||||
/// and if yes, then it is added. Function returns false if, and only if,
|
|
||||||
/// error occured and certificate was not added.
|
|
||||||
/// \param type Type
|
|
||||||
/// \param certificate Certificate
|
|
||||||
bool add(EntryType type, const QByteArray& certificate);
|
|
||||||
|
|
||||||
/// Tries to add new certificate to the certificate store. If certificate
|
|
||||||
/// is already here, then nothing happens and function returns true.
|
|
||||||
/// Otherwise data are checked, if they really contains a certificate,
|
|
||||||
/// and if yes, then it is added. Function returns false if, and only if,
|
|
||||||
/// error occured and certificate was not added.
|
|
||||||
/// \param type Type
|
|
||||||
/// \param info Certificate info
|
|
||||||
bool add(EntryType type, PDFCertificateInfo info);
|
|
||||||
|
|
||||||
/// Returns true, if storage contains given certificate
|
|
||||||
/// \param info Certificate info
|
|
||||||
bool contains(const PDFCertificateInfo& info);
|
|
||||||
|
|
||||||
/// Get certificates stored in the store
|
|
||||||
const CertificateEntries& getCertificates() const { return m_certificates; }
|
|
||||||
|
|
||||||
/// Set certificates
|
|
||||||
void setCertificates(CertificateEntries certificates) { m_certificates = qMove(certificates); }
|
|
||||||
|
|
||||||
/// Returns default certificate store file name
|
|
||||||
QString getDefaultCertificateStoreFileName() const;
|
|
||||||
|
|
||||||
/// Load from default user certificate storage
|
|
||||||
void loadDefaultUserCertificates();
|
|
||||||
|
|
||||||
/// Save to default user certificate storage
|
|
||||||
void saveDefaultUserCertificates();
|
|
||||||
|
|
||||||
/// Creates default directory for certificate store
|
|
||||||
void createDirectoryForDefaultUserCertificatesStore();
|
|
||||||
|
|
||||||
/// Returns a list of system certificates
|
|
||||||
static CertificateEntries getSystemCertificates();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr int persist_version = 1;
|
|
||||||
|
|
||||||
CertificateEntries m_certificates;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
#endif // PDFSIGNATUREHANDLER_H
|
#endif // PDFSIGNATUREHANDLER_H
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include <security.h>
|
#include <security.h>
|
||||||
#if defined(PDF4QT_USE_PRAGMA_LIB)
|
#if defined(PDF4QT_USE_PRAGMA_LIB)
|
||||||
#pragma comment(lib, "Secur32.lib")
|
#pragma comment(lib, "Secur32.lib")
|
||||||
|
#pragma comment(lib, "Ncrypt.lib")
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,8 @@ add_library(Pdf4QtLibWidgets SHARED
|
||||||
sources/pdfcompiler.h
|
sources/pdfcompiler.h
|
||||||
sources/pdfdocumentdrawinterface.h
|
sources/pdfdocumentdrawinterface.h
|
||||||
sources/pdfwidgetsglobal.h
|
sources/pdfwidgetsglobal.h
|
||||||
|
sources/pdfcertificatelisthelper.h
|
||||||
|
sources/pdfcertificatelisthelper.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "pdfcertificatelisthelper.h"
|
||||||
|
#include "pdfwidgetutils.h"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include <QHeaderView>
|
||||||
|
|
||||||
|
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<QStandardItemModel*>(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<QTableView*>(comboBox->view());
|
||||||
|
tableView->resizeColumnsToContents();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace pdf
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#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
|
|
@ -23,6 +23,7 @@
|
||||||
#include "pdfwidgetutils.h"
|
#include "pdfwidgetutils.h"
|
||||||
#include "pdfsecurityhandler.h"
|
#include "pdfsecurityhandler.h"
|
||||||
#include "pdfcertificatemanager.h"
|
#include "pdfcertificatemanager.h"
|
||||||
|
#include "pdfcertificatelisthelper.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
@ -84,6 +85,8 @@ PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QByteArray documentId,
|
||||||
m_checkBoxToPermission[ui->permAssembleCheckBox] = pdf::PDFSecurityHandler::Permission::Assemble;
|
m_checkBoxToPermission[ui->permAssembleCheckBox] = pdf::PDFSecurityHandler::Permission::Assemble;
|
||||||
m_checkBoxToPermission[ui->permPrintHighResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintHighResolution;
|
m_checkBoxToPermission[ui->permPrintHighResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintHighResolution;
|
||||||
|
|
||||||
|
pdf::PDFCertificateListHelper::initComboBox(ui->certificateComboBox);
|
||||||
|
|
||||||
updateCertificates();
|
updateCertificates();
|
||||||
updateUi();
|
updateUi();
|
||||||
updatePasswordScore();
|
updatePasswordScore();
|
||||||
|
@ -194,17 +197,8 @@ void PDFEncryptionSettingsDialog::updateUi()
|
||||||
|
|
||||||
void PDFEncryptionSettingsDialog::updateCertificates()
|
void PDFEncryptionSettingsDialog::updateCertificates()
|
||||||
{
|
{
|
||||||
QFileInfoList certificates = pdf::PDFCertificateManager::getCertificates();
|
m_certificates = pdf::PDFCertificateManager::getCertificates();
|
||||||
|
pdf::PDFCertificateListHelper::fillComboBox(ui->certificateComboBox, m_certificates);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PDFEncryptionSettingsDialog::updatePasswordScore()
|
void PDFEncryptionSettingsDialog::updatePasswordScore()
|
||||||
|
@ -237,7 +231,12 @@ void PDFEncryptionSettingsDialog::accept()
|
||||||
settings.userPassword = ui->userPasswordEdit->text();
|
settings.userPassword = ui->userPasswordEdit->text();
|
||||||
settings.ownerPassword = ui->ownerPasswordEdit->text();
|
settings.ownerPassword = ui->ownerPasswordEdit->text();
|
||||||
settings.permissions = 0;
|
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)
|
for (auto item : m_checkBoxToPermission)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "pdfviewerglobal.h"
|
#include "pdfviewerglobal.h"
|
||||||
#include "pdfsecurityhandler.h"
|
#include "pdfsecurityhandler.h"
|
||||||
|
#include "pdfcertificatestore.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ private:
|
||||||
PDFEncryptionStrengthHintWidget* m_userPasswordStrengthHintWidget;
|
PDFEncryptionStrengthHintWidget* m_userPasswordStrengthHintWidget;
|
||||||
PDFEncryptionStrengthHintWidget* m_ownerPasswordStrengthHintWidget;
|
PDFEncryptionStrengthHintWidget* m_ownerPasswordStrengthHintWidget;
|
||||||
PDFEncryptionStrengthHintWidget* m_algorithmHintWidget;
|
PDFEncryptionStrengthHintWidget* m_algorithmHintWidget;
|
||||||
|
pdf::PDFCertificateEntries m_certificates;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
|
|
@ -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 (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."));
|
QMessageBox::critical(this, tr("Trusted Certificate Store Error"), tr("Failed to add certificate to the trusted certificate store."));
|
||||||
}
|
}
|
||||||
|
|
|
@ -675,7 +675,7 @@ void PDFViewerSettingsDialog::updateTrustedCertificatesTable()
|
||||||
ui->trustedCertificateStoreTableWidget->setUpdatesEnabled(false);
|
ui->trustedCertificateStoreTableWidget->setUpdatesEnabled(false);
|
||||||
ui->trustedCertificateStoreTableWidget->clear();
|
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->setRowCount(int(certificates.size()));
|
||||||
ui->trustedCertificateStoreTableWidget->setColumnCount(5);
|
ui->trustedCertificateStoreTableWidget->setColumnCount(5);
|
||||||
ui->trustedCertificateStoreTableWidget->verticalHeader()->setVisible(true);
|
ui->trustedCertificateStoreTableWidget->verticalHeader()->setVisible(true);
|
||||||
|
@ -688,15 +688,11 @@ void PDFViewerSettingsDialog::updateTrustedCertificatesTable()
|
||||||
QString type;
|
QString type;
|
||||||
switch (certificates[i].type)
|
switch (certificates[i].type)
|
||||||
{
|
{
|
||||||
case pdf::PDFCertificateStore::EntryType::User:
|
case pdf::PDFCertificateEntry::EntryType::User:
|
||||||
type = tr("User");
|
type = tr("User");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pdf::PDFCertificateStore::EntryType::EUTL:
|
case pdf::PDFCertificateEntry::EntryType::System:
|
||||||
type = tr("EUTL");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case pdf::PDFCertificateStore::EntryType::System:
|
|
||||||
type = tr("System");
|
type = tr("System");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -920,8 +916,8 @@ void PDFViewerSettingsDialog::on_removeCertificateButton_clicked()
|
||||||
rows.insert(index.row());
|
rows.insert(index.row());
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf::PDFCertificateStore::CertificateEntries newEntries;
|
pdf::PDFCertificateEntries newEntries;
|
||||||
const pdf::PDFCertificateStore::CertificateEntries& certificates = m_certificateStore.getCertificates();
|
const pdf::PDFCertificateEntries& certificates = m_certificateStore.getCertificates();
|
||||||
for (int i = 0; i < int(certificates.size()); ++i)
|
for (int i = 0; i < int(certificates.size()); ++i)
|
||||||
{
|
{
|
||||||
if (!rows.count(i))
|
if (!rows.count(i))
|
||||||
|
|
|
@ -315,11 +315,11 @@ void SignaturePlugin::onSignDigitally()
|
||||||
// Jakub Melka: do we have certificates? If not,
|
// Jakub Melka: do we have certificates? If not,
|
||||||
// open certificate dialog, so the user can create
|
// open certificate dialog, so the user can create
|
||||||
// a new one.
|
// a new one.
|
||||||
if (pdf::PDFCertificateManager::getCertificates().isEmpty())
|
if (pdf::PDFCertificateManager::getCertificates().empty())
|
||||||
{
|
{
|
||||||
onOpenCertificatesManager();
|
onOpenCertificatesManager();
|
||||||
|
|
||||||
if (pdf::PDFCertificateManager::getCertificates().isEmpty())
|
if (pdf::PDFCertificateManager::getCertificates().empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -328,9 +328,12 @@ void SignaturePlugin::onSignDigitally()
|
||||||
SignDialog dialog(m_dataExchangeInterface->getMainWindow(), m_scene.isEmpty());
|
SignDialog dialog(m_dataExchangeInterface->getMainWindow(), m_scene.isEmpty());
|
||||||
if (dialog.exec() == SignDialog::Accepted)
|
if (dialog.exec() == SignDialog::Accepted)
|
||||||
{
|
{
|
||||||
|
const pdf::PDFCertificateEntry* certificate = dialog.getCertificate();
|
||||||
|
Q_ASSERT(certificate);
|
||||||
|
|
||||||
QByteArray data = "SampleDataToBeSigned" + QByteArray::number(QDateTime::currentMSecsSinceEpoch());
|
QByteArray data = "SampleDataToBeSigned" + QByteArray::number(QDateTime::currentMSecsSinceEpoch());
|
||||||
QByteArray signature;
|
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."));
|
QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature."));
|
||||||
return;
|
return;
|
||||||
|
@ -459,7 +462,7 @@ void SignaturePlugin::onSignDigitally()
|
||||||
buffer.seek(i3);
|
buffer.seek(i3);
|
||||||
dataToBeSigned.append(buffer.read(i4));
|
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."));
|
QMessageBox::critical(m_widget, tr("Error"), tr("Failed to create digital signature."));
|
||||||
buffer.close();
|
buffer.close();
|
||||||
|
|
|
@ -108,6 +108,8 @@ private:
|
||||||
|
|
||||||
void setActive(bool active);
|
void setActive(bool active);
|
||||||
|
|
||||||
|
pdf::PDFWidgetTool* getActiveTool();
|
||||||
|
|
||||||
void updateActions();
|
void updateActions();
|
||||||
void updateGraphics();
|
void updateGraphics();
|
||||||
void updateDockWidget();
|
void updateDockWidget();
|
||||||
|
@ -120,7 +122,6 @@ private:
|
||||||
|
|
||||||
pdf::PDFPageContentScene m_scene;
|
pdf::PDFPageContentScene m_scene;
|
||||||
bool m_sceneSelectionChangeEnabled;
|
bool m_sceneSelectionChangeEnabled;
|
||||||
pdf::PDFWidgetTool* getActiveTool();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfplugin
|
} // namespace pdfplugin
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "ui_signdialog.h"
|
#include "ui_signdialog.h"
|
||||||
|
|
||||||
#include "pdfcertificatemanager.h"
|
#include "pdfcertificatemanager.h"
|
||||||
|
#include "pdfcertificatelisthelper.h"
|
||||||
|
|
||||||
#include <openssl/pkcs7.h>
|
#include <openssl/pkcs7.h>
|
||||||
|
|
||||||
|
@ -41,11 +42,10 @@ SignDialog::SignDialog(QWidget* parent, bool isSceneEmpty) :
|
||||||
ui->methodCombo->addItem(tr("Sign digitally (invisible signature)"), SignDigitallyInvisible);
|
ui->methodCombo->addItem(tr("Sign digitally (invisible signature)"), SignDigitallyInvisible);
|
||||||
ui->methodCombo->setCurrentIndex(0);
|
ui->methodCombo->setCurrentIndex(0);
|
||||||
|
|
||||||
QFileInfoList certificates = pdf::PDFCertificateManager::getCertificates();
|
m_certificates = pdf::PDFCertificateManager::getCertificates();
|
||||||
for (const QFileInfo& certificateFileInfo : certificates)
|
|
||||||
{
|
pdf::PDFCertificateListHelper::initComboBox(ui->certificateCombo);
|
||||||
ui->certificateCombo->addItem(certificateFileInfo.fileName(), certificateFileInfo.absoluteFilePath());
|
pdf::PDFCertificateListHelper::fillComboBox(ui->certificateCombo, m_certificates);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SignDialog::~SignDialog()
|
SignDialog::~SignDialog()
|
||||||
|
@ -58,11 +58,6 @@ SignDialog::SignMethod SignDialog::getSignMethod() const
|
||||||
return static_cast<SignMethod>(ui->methodCombo->currentData().toInt());
|
return static_cast<SignMethod>(ui->methodCombo->currentData().toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SignDialog::getCertificatePath() const
|
|
||||||
{
|
|
||||||
return ui->certificateCombo->currentData().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SignDialog::getPassword() const
|
QString SignDialog::getPassword() const
|
||||||
{
|
{
|
||||||
return ui->certificatePasswordEdit->text();
|
return ui->certificatePasswordEdit->text();
|
||||||
|
@ -78,10 +73,23 @@ QString SignDialog::getContactInfoText() const
|
||||||
return ui->contactInfoEdit->text();
|
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()
|
void SignDialog::accept()
|
||||||
{
|
{
|
||||||
|
const pdf::PDFCertificateEntry* certificate = getCertificate();
|
||||||
|
|
||||||
// Check certificate
|
// Check certificate
|
||||||
if (!QFile::exists(getCertificatePath()))
|
if (!certificate)
|
||||||
{
|
{
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Certificate does not exist."));
|
QMessageBox::critical(this, tr("Error"), tr("Certificate does not exist."));
|
||||||
ui->certificateCombo->setFocus();
|
ui->certificateCombo->setFocus();
|
||||||
|
@ -89,7 +97,7 @@ void SignDialog::accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check we can access the certificate
|
// 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."));
|
QMessageBox::critical(this, tr("Error"), tr("Password to open certificate is invalid."));
|
||||||
ui->certificatePasswordEdit->setFocus();
|
ui->certificatePasswordEdit->setFocus();
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#ifndef SIGNDIALOG_H
|
#ifndef SIGNDIALOG_H
|
||||||
#define SIGNDIALOG_H
|
#define SIGNDIALOG_H
|
||||||
|
|
||||||
|
#include "pdfcertificatemanager.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
|
@ -45,13 +47,14 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
SignMethod getSignMethod() const;
|
SignMethod getSignMethod() const;
|
||||||
QString getCertificatePath() const;
|
|
||||||
QString getPassword() const;
|
QString getPassword() const;
|
||||||
QString getReasonText() const;
|
QString getReasonText() const;
|
||||||
QString getContactInfoText() const;
|
QString getContactInfoText() const;
|
||||||
|
const pdf::PDFCertificateEntry* getCertificate() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::SignDialog* ui;
|
Ui::SignDialog* ui;
|
||||||
|
pdf::PDFCertificateEntries m_certificates;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfplugin
|
} // namespace pdfplugin
|
||||||
|
|
|
@ -58,10 +58,10 @@ int PDFToolCertStore::execute(const PDFToolOptions& options)
|
||||||
certificateStore.loadDefaultUserCertificates();
|
certificateStore.loadDefaultUserCertificates();
|
||||||
}
|
}
|
||||||
|
|
||||||
pdf::PDFCertificateStore::CertificateEntries certificates = certificateStore.getCertificates();
|
pdf::PDFCertificateEntries certificates = certificateStore.getCertificates();
|
||||||
if (options.certStoreEnumerateSystemCertificates)
|
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()));
|
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;
|
int ref = 1;
|
||||||
QLocale locale;
|
QLocale locale;
|
||||||
|
|
||||||
for (const pdf::PDFCertificateStore::CertificateEntry& entry : certificates)
|
for (const pdf::PDFCertificateEntry& entry : certificates)
|
||||||
{
|
{
|
||||||
QString type;
|
QString type;
|
||||||
switch (entry.type)
|
switch (entry.type)
|
||||||
{
|
{
|
||||||
case pdf::PDFCertificateStore::EntryType::User:
|
case pdf::PDFCertificateEntry::EntryType::User:
|
||||||
type = PDFToolTranslationContext::tr("User");
|
type = PDFToolTranslationContext::tr("User");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case pdf::PDFCertificateStore::EntryType::EUTL:
|
case pdf::PDFCertificateEntry::EntryType::System:
|
||||||
type = PDFToolTranslationContext::tr("EUTL");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case pdf::PDFCertificateStore::EntryType::System:
|
|
||||||
type = PDFToolTranslationContext::tr("System");
|
type = PDFToolTranslationContext::tr("System");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -185,7 +181,7 @@ int PDFToolCertStoreInstallCertificate::execute(const PDFToolOptions& options)
|
||||||
pdf::PDFCertificateStore certificateStore;
|
pdf::PDFCertificateStore certificateStore;
|
||||||
certificateStore.loadDefaultUserCertificates();
|
certificateStore.loadDefaultUserCertificates();
|
||||||
|
|
||||||
if (certificateStore.add(pdf::PDFCertificateStore::EntryType::User, certificateData))
|
if (certificateStore.add(pdf::PDFCertificateEntry::EntryType::User, certificateData))
|
||||||
{
|
{
|
||||||
certificateStore.saveDefaultUserCertificates();
|
certificateStore.saveDefaultUserCertificates();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue