[poppler] 2 commits - CMakeLists.txt config.h.cmake poppler/CryptoSignBackend.cc poppler/CryptoSignBackend.h poppler/Form.cc poppler/Form.h poppler/SignatureHandler.cc poppler/SignatureHandler.h qt5/src qt6/src utils/pdfsig.cc
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Thu Apr 13 08:58:23 UTC 2023
CMakeLists.txt | 25 ++++++++++
config.h.cmake | 6 ++
poppler/CryptoSignBackend.cc | 97 +++++++++++++++++++++++++++++++++++++++++
poppler/CryptoSignBackend.h | 101 +++++++++++++++++++++++++++++++++++++++++++
poppler/Form.cc | 87 ++++++++++++++++++-------------------
poppler/Form.h | 8 ++-
poppler/SignatureHandler.cc | 56 ++++++++++++-----------
poppler/SignatureHandler.h | 45 ++++++++++---------
qt5/src/poppler-form.cc | 30 ++++++------
qt6/src/poppler-form.cc | 30 ++++++------
utils/pdfsig.cc | 3 -
11 files changed, 366 insertions(+), 122 deletions(-)
New commits:
commit cc5ac1665aa3056d1f90a12e12d24a02536647e0
Author: Sune Vuorela <sune at vuorela.dk>
Date: Mon Mar 27 10:40:19 2023 +0200
Adapt signature code to the backend interface
Also set the signature info a bit later;
gpgme only gives us the info after the validateSignature call
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c6c757c8..63a0970b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -358,6 +358,29 @@ if(TIFF_FOUND)
set(ENABLE_LIBTIFF ON)
endif()
+set(SIGNATURE_BACKENDS "")
+if(ENABLE_NSS3)
+ list(APPEND SIGNATURE_BACKENDS "NSS")
+endif()
+
+list(LENGTH SIGNATURE_BACKENDS _signing_backends_count)
+if (_signing_backends_count GREATER 0)
+ if (NOT DEFAULT_SIGNATURE_BACKEND)
+ # If not specified at compiletime, we take the first one added.
+ # This means that the order we append them to the list is significant
+ list(GET SIGNATURE_BACKENDS 0 DEFAULT_SIGNATURE_BACKEND)
+ endif()
+ if (NOT DEFAULT_SIGNATURE_BACKEND IN_LIST SIGNATURE_BACKENDS)
+ message(FATAL_ERROR "default signature backend must be one of ${SIGNATURE_BACKENDS}, was ${DEFAULT_SIGNATURE_BACKEND}")
+ endif()
+ set(ENABLE_SIGNATURES ON)
+endif()
+if (NOT DEFAULT_SIGNATURE_BACKEND)
+ set(DEFAULT_SIGNATURE_BACKEND "None")
+endif()
+
+
+
# Recent versions of poppler-data install a .pc file.
# Use it to determine the encoding data path, if available.
# Default to the same prefix otherwise.
@@ -418,6 +441,7 @@ set(poppler_SRCS
poppler/Catalog.cc
poppler/CharCodeToUnicode.cc
poppler/CMap.cc
+ poppler/CryptoSignBackend.cc
poppler/DateInfo.cc
poppler/Decrypt.cc
poppler/Dict.cc
@@ -836,6 +860,7 @@ show_end_message_yesno("use libtiff" ENABLE_LIBTIFF)
show_end_message_yesno("use zlib compress" ENABLE_ZLIB)
show_end_message_yesno("use zlib uncompress" ENABLE_ZLIB_UNCOMPRESS)
show_end_message_yesno("use nss3" ENABLE_NSS3)
+show_end_message(" default signature backend" ${DEFAULT_SIGNATURE_BACKEND})
show_end_message_yesno("use curl" ENABLE_LIBCURL)
show_end_message_yesno("use libopenjpeg2" WITH_OPENJPEG)
show_end_message_yesno("use lcms2" USE_CMS)
diff --git a/config.h.cmake b/config.h.cmake
index ea679a4f..4d6ef551 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -27,6 +27,12 @@
/* Build against libnss3 for digital signature validation */
#cmakedefine ENABLE_NSS3 1
+/* Signatures enabled */
+#cmakedefine ENABLE_SIGNATURES 1
+
+/* Default signature backend */
+#cmakedefine DEFAULT_SIGNATURE_BACKEND "${DEFAULT_SIGNATURE_BACKEND}"
+
/* Use cairo for rendering. */
#cmakedefine HAVE_CAIRO 1
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 2c0c35a4..b5a41c53 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -63,9 +63,7 @@
#include "Form.h"
#include "PDFDoc.h"
#include "DateInfo.h"
-#ifdef ENABLE_NSS3
-# include "SignatureHandler.h"
-#endif
+#include "CryptoSignBackend.h"
#include "SignatureInfo.h"
#include "CertificateInfo.h"
#include "XRef.h"
@@ -573,10 +571,12 @@ SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool fo
return static_cast<FormFieldSignature *>(field)->validateSignature(doVerifyCert, forceRevalidation, validationTime, ocspRevocationCheck, enableAIA);
}
-#ifdef ENABLE_NSS3
// update hash with the specified range of data from the file
-static bool hashFileRange(FILE *f, SignatureSignHandler *handler, Goffset start, Goffset end)
+static bool hashFileRange(FILE *f, CryptoSign::SigningInterface *handler, Goffset start, Goffset end)
{
+ if (!handler) {
+ return false;
+ }
const int BUF_SIZE = 65536;
unsigned char *buf = new unsigned char[BUF_SIZE];
@@ -594,27 +594,29 @@ static bool hashFileRange(FILE *f, SignatureSignHandler *handler, Goffset start,
delete[] buf;
return false;
}
- handler->updateHash(buf, len);
+ handler->addData(buf, len);
start += len;
}
delete[] buf;
return true;
}
-#endif
bool FormWidgetSignature::signDocument(const std::string &saveFilename, const std::string &certNickname, const std::string &password, const GooString *reason, const GooString *location, const std::optional<GooString> &ownerPassword,
const std::optional<GooString> &userPassword)
{
-#ifdef ENABLE_NSS3
+ auto backend = CryptoSign::Factory::createActive();
+ if (!backend) {
+ return false;
+ }
if (certNickname.empty()) {
fprintf(stderr, "signDocument: Empty nickname\n");
return false;
}
- SignatureSignHandler sigHandler(certNickname, HashAlgorithm::Sha256);
+ auto sigHandler = backend->createSigningHandler(certNickname, HashAlgorithm::Sha256);
FormFieldSignature *signatureField = static_cast<FormFieldSignature *>(field);
- std::unique_ptr<X509CertificateInfo> certInfo = sigHandler.getCertificateInfo();
+ std::unique_ptr<X509CertificateInfo> certInfo = sigHandler->getCertificateInfo();
if (!certInfo) {
fprintf(stderr, "signDocument: error getting signature info\n");
return false;
@@ -625,7 +627,7 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st
Object vObj(new Dict(xref));
Ref vref = xref->addIndirectObject(vObj);
- if (!createSignature(vObj, vref, GooString(signerName), maxSupportedSignatureSize, reason, location)) {
+ if (!createSignature(vObj, vref, GooString(signerName), CryptoSign::maxSupportedSignatureSize, reason, location)) {
return false;
}
@@ -653,33 +655,33 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st
}
// compute hash of byte ranges
- if (!hashFileRange(file, &sigHandler, 0LL, sigStart)) {
+ if (!hashFileRange(file, sigHandler.get(), 0LL, sigStart)) {
fclose(file);
return false;
}
- if (!hashFileRange(file, &sigHandler, sigEnd, fileSize)) {
+ if (!hashFileRange(file, sigHandler.get(), sigEnd, fileSize)) {
fclose(file);
return false;
}
// and sign it
- const std::unique_ptr<GooString> signature = sigHandler.signDetached(password);
+ auto signature = sigHandler->signDetached(password);
if (!signature) {
fclose(file);
return false;
}
- if (signature->getLength() > maxSupportedSignatureSize) {
+ if (signature->getLength() > CryptoSign::maxSupportedSignatureSize) {
fclose(file);
return false;
}
// pad with zeroes to placeholder length
auto length = signature->getLength();
- signature->append(std::string(maxSupportedSignatureSize - length, '\0'));
+ signature->append(std::string(CryptoSign::maxSupportedSignatureSize - length, '\0'));
// write signature to saved file
- if (!updateSignature(file, sigStart, sigEnd, signature.get())) {
+ if (!updateSignature(file, sigStart, sigEnd, signature.value())) {
fprintf(stderr, "signDocument: unable update signature\n");
fclose(file);
return false;
@@ -689,9 +691,6 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st
fclose(file);
return true;
-#else
- return false;
-#endif
}
bool FormWidgetSignature::signDocumentWithAppearance(const std::string &saveFilename, const std::string &certNickname, const std::string &password, const GooString *reason, const GooString *location,
@@ -859,18 +858,18 @@ bool FormWidgetSignature::updateOffsets(FILE *f, Goffset objStart, Goffset objEn
}
// Overwrite signature string in the file with new signature
-bool FormWidgetSignature::updateSignature(FILE *f, Goffset sigStart, Goffset sigEnd, const GooString *signature)
+bool FormWidgetSignature::updateSignature(FILE *f, Goffset sigStart, Goffset sigEnd, const GooString &signature)
{
- if (signature->getLength() * 2 + 2 != sigEnd - sigStart) {
+ if (signature.getLength() * 2 + 2 != sigEnd - sigStart) {
return false;
}
if (Gfseek(f, sigStart, SEEK_SET) != 0) {
return false;
}
- const char *c = signature->c_str();
+ const char *c = signature.c_str();
fprintf(f, "<");
- for (int i = 0; i < signature->getLength(); i++) {
+ for (int i = 0; i < signature.getLength(); i++) {
unsigned char value = *(c + i) & 0x000000ff;
fprintf(f, "%2.2x", value);
}
@@ -2305,9 +2304,11 @@ void FormFieldSignature::parseInfo()
}
}
-void FormFieldSignature::hashSignedDataBlock(SignatureVerificationHandler *handler, Goffset block_len)
+void FormFieldSignature::hashSignedDataBlock(CryptoSign::VerificationInterface *handler, Goffset block_len)
{
-#ifdef ENABLE_NSS3
+ if (!handler) {
+ return;
+ }
const int BLOCK_SIZE = 4096;
unsigned char signed_data_buffer[BLOCK_SIZE];
@@ -2316,15 +2317,14 @@ void FormFieldSignature::hashSignedDataBlock(SignatureVerificationHandler *handl
Goffset bytes_left = block_len - i;
if (bytes_left < BLOCK_SIZE) {
doc->getBaseStream()->doGetChars(static_cast<int>(bytes_left), signed_data_buffer);
- handler->updateHash(signed_data_buffer, static_cast<int>(bytes_left));
+ handler->addData(signed_data_buffer, static_cast<int>(bytes_left));
i = block_len;
} else {
doc->getBaseStream()->doGetChars(BLOCK_SIZE, signed_data_buffer);
- handler->updateHash(signed_data_buffer, BLOCK_SIZE);
+ handler->addData(signed_data_buffer, BLOCK_SIZE);
i += BLOCK_SIZE;
}
}
-#endif
}
FormSignatureType FormWidgetSignature::signatureType() const
@@ -2339,7 +2339,11 @@ void FormWidgetSignature::setSignatureType(FormSignatureType fst)
SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime, bool ocspRevocationCheck, bool enableAIA)
{
-#ifdef ENABLE_NSS3
+ auto backend = CryptoSign::Factory::createActive();
+ if (!backend) {
+ return signature_info;
+ }
+
if (signature_info->getSignatureValStatus() != SIGNATURE_NOT_VERIFIED && !forceRevalidation) {
return signature_info;
}
@@ -2363,7 +2367,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
const int signature_len = signature->getLength();
std::vector<unsigned char> signatureData(signature_len);
memcpy(signatureData.data(), signature->c_str(), signature_len);
- SignatureVerificationHandler signature_handler(std::move(signatureData));
+ auto signature_handler = backend->createVerificationHandler(std::move(signatureData));
Goffset fileLength = doc->getBaseStream()->getLength();
for (int i = 0; i < arrayLen / 2; i++) {
@@ -2384,35 +2388,32 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
}
doc->getBaseStream()->setPos(offset);
- hashSignedDataBlock(&signature_handler, len);
+ hashSignedDataBlock(signature_handler.get(), len);
}
- signature_info->setSignerName(signature_handler.getSignerName().c_str());
- signature_info->setSubjectDN(signature_handler.getSignerSubjectDN());
- signature_info->setHashAlgorithm(signature_handler.getHashAlgorithm());
-
if (!signature_info->isSubfilterSupported()) {
error(errUnimplemented, 0, "Unable to validate this type of signature");
return signature_info;
}
-
- const SignatureValidationStatus sig_val_state = signature_handler.validateSignature();
+ const SignatureValidationStatus sig_val_state = signature_handler->validateSignature();
signature_info->setSignatureValStatus(sig_val_state);
+ signature_info->setSignerName(signature_handler->getSignerName());
+ signature_info->setSubjectDN(signature_handler->getSignerSubjectDN());
+ signature_info->setHashAlgorithm(signature_handler->getHashAlgorithm());
// verify if signature contains a 'signing time' attribute
- if (signature_handler.getSigningTime() != 0) {
- signature_info->setSigningTime(signature_handler.getSigningTime());
+ if (signature_handler->getSigningTime() != std::chrono::system_clock::time_point {}) {
+ signature_info->setSigningTime(std::chrono::system_clock::to_time_t(signature_handler->getSigningTime()));
}
if (sig_val_state != SIGNATURE_VALID || !doVerifyCert) {
return signature_info;
}
- const CertificateValidationStatus cert_val_state = signature_handler.validateCertificate(validationTime, ocspRevocationCheck, enableAIA);
+ const CertificateValidationStatus cert_val_state = signature_handler->validateCertificate(std::chrono::system_clock::from_time_t(validationTime), ocspRevocationCheck, enableAIA);
signature_info->setCertificateValStatus(cert_val_state);
- signature_info->setCertificateInfo(signature_handler.getCertificateInfo());
+ signature_info->setCertificateInfo(signature_handler->getCertificateInfo());
-#endif
return signature_info;
}
diff --git a/poppler/Form.h b/poppler/Form.h
index 80be38e6..5ebdec0e 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -56,7 +56,9 @@ class GfxResources;
class PDFDoc;
class SignatureInfo;
class X509CertificateInfo;
-class SignatureVerificationHandler;
+namespace CryptoSign {
+class VerificationInterface;
+}
enum FormFieldType
{
@@ -328,7 +330,7 @@ private:
bool getObjectStartEnd(const GooString &filename, int objNum, Goffset *objStart, Goffset *objEnd, const std::optional<GooString> &ownerPassword, const std::optional<GooString> &userPassword);
bool updateOffsets(FILE *f, Goffset objStart, Goffset objEnd, Goffset *sigStart, Goffset *sigEnd, Goffset *fileSize);
- bool updateSignature(FILE *f, Goffset sigStart, Goffset sigEnd, const GooString *signature);
+ bool updateSignature(FILE *f, Goffset sigStart, Goffset sigEnd, const GooString &signature);
};
//------------------------------------------------------------------------
@@ -640,7 +642,7 @@ public:
private:
void parseInfo();
- void hashSignedDataBlock(SignatureVerificationHandler *handler, Goffset block_len);
+ void hashSignedDataBlock(CryptoSign::VerificationInterface *handler, Goffset block_len);
FormSignatureType signature_type;
Object byte_range;
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 99163000..a306c358 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -534,7 +534,7 @@ std::string SignatureVerificationHandler::getSignerSubjectDN() const
return std::string { signing_cert->subjectName };
}
-time_t SignatureVerificationHandler::getSigningTime() const
+std::chrono::system_clock::time_point SignatureVerificationHandler::getSigningTime() const
{
if (!CMSSignerInfo) {
return {};
@@ -542,10 +542,10 @@ time_t SignatureVerificationHandler::getSigningTime() const
PRTime sTime; // time in microseconds since the epoch
if (NSS_CMSSignerInfo_GetSigningTime(CMSSignerInfo, &sTime) != SECSuccess) {
- return 0;
+ return {};
}
- return static_cast<time_t>(sTime / 1000000);
+ return std::chrono::system_clock::from_time_t(static_cast<time_t>(sTime / 1000000));
}
static X509CertificateInfo::EntityInfo getEntityInfo(CERTName *entityName)
@@ -787,14 +787,14 @@ HashAlgorithm SignatureVerificationHandler::getHashAlgorithm() const
}
}
-void SignatureVerificationHandler::updateHash(unsigned char *data_block, int data_len)
+void SignatureVerificationHandler::addData(unsigned char *data_block, int data_len)
{
if (hashContext) {
hashContext->updateHash(data_block, data_len);
}
}
-void SignatureSignHandler::updateHash(unsigned char *data_block, int data_len)
+void SignatureSignHandler::addData(unsigned char *data_block, int data_len)
{
hashContext->updateHash(data_block, data_len);
}
@@ -947,7 +947,7 @@ SignatureValidationStatus SignatureVerificationHandler::validateSignature()
}
}
-CertificateValidationStatus SignatureVerificationHandler::validateCertificate(time_t validation_time, bool ocspRevocationCheck, bool useAIACertFetch)
+CertificateValidationStatus SignatureVerificationHandler::validateCertificate(std::chrono::system_clock::time_point validation_time, bool ocspRevocationCheck, bool useAIACertFetch)
{
CERTCertificate *cert;
@@ -960,8 +960,8 @@ CertificateValidationStatus SignatureVerificationHandler::validateCertificate(ti
}
PRTime vTime = 0; // time in microseconds since the epoch, special value 0 means now
- if (validation_time > 0) {
- vTime = 1000000 * (PRTime)validation_time;
+ if (validation_time > std::chrono::system_clock::time_point {}) {
+ vTime = 1000000 * (PRTime)std::chrono::system_clock::to_time_t(validation_time);
}
CERTValInParam inParams[4];
inParams[0].type = cert_pi_revocationFlags;
@@ -1003,10 +1003,10 @@ CertificateValidationStatus SignatureVerificationHandler::validateCertificate(ti
return CERTIFICATE_GENERIC_ERROR;
}
-std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string &password)
+std::optional<GooString> SignatureSignHandler::signDetached(const std::string &password)
{
if (!hashContext) {
- return nullptr;
+ return {};
}
std::vector<unsigned char> digest_buffer = hashContext->endHash();
SECItem digest;
@@ -1022,54 +1022,54 @@ std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string
};
std::unique_ptr<NSSCMSMessage, NSSCMSMessageDestroyer> cms_msg { NSS_CMSMessage_Create(nullptr) };
if (!cms_msg) {
- return nullptr;
+ return {};
}
NSSCMSSignedData *cms_sd = NSS_CMSSignedData_Create(cms_msg.get());
if (!cms_sd) {
- return nullptr;
+ return {};
}
NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(cms_msg.get());
if (NSS_CMSContentInfo_SetContent_SignedData(cms_msg.get(), cms_cinfo, cms_sd) != SECSuccess) {
- return nullptr;
+ return {};
}
cms_cinfo = NSS_CMSSignedData_GetContentInfo(cms_sd);
// Attach NULL data as detached data
if (NSS_CMSContentInfo_SetContent_Data(cms_msg.get(), cms_cinfo, nullptr, PR_TRUE) != SECSuccess) {
- return nullptr;
+ return {};
}
// hardcode SHA256 these days...
NSSCMSSignerInfo *cms_signer = NSS_CMSSignerInfo_Create(cms_msg.get(), signing_cert, SEC_OID_SHA256);
if (!cms_signer) {
- return nullptr;
+ return {};
}
if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) {
- return nullptr;
+ return {};
}
if (NSS_CMSSignedData_AddCertificate(cms_sd, signing_cert) != SECSuccess) {
- return nullptr;
+ return {};
}
if (NSS_CMSSignedData_AddSignerInfo(cms_sd, cms_signer) != SECSuccess) {
- return nullptr;
+ return {};
}
if (NSS_CMSSignedData_SetDigestValue(cms_sd, SEC_OID_SHA256, &digest) != SECSuccess) {
- return nullptr;
+ return {};
}
struct PLArenaFreeFalse
{
void operator()(PLArenaPool *arena) { PORT_FreeArena(arena, PR_FALSE); }
};
- std::unique_ptr<PLArenaPool, PLArenaFreeFalse> arena { PORT_NewArena(maxSupportedSignatureSize) };
+ std::unique_ptr<PLArenaPool, PLArenaFreeFalse> arena { PORT_NewArena(CryptoSign::maxSupportedSignatureSize) };
// Add the signing certificate as a signed attribute.
ESSCertIDv2 *aCertIDs[2];
@@ -1084,7 +1084,7 @@ std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string
unsigned char certhash[32];
SECStatus rv = PK11_HashBuf(SEC_OID_SHA256, certhash, signing_cert->derCert.data, signing_cert->derCert.len);
if (rv != SECSuccess) {
- return nullptr;
+ return {};
}
aCertHashItem.type = siBuffer;
@@ -1107,7 +1107,7 @@ std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string
SECItem *pEncodedCertificate = SEC_ASN1EncodeItem(nullptr, nullptr, &aCertificate, SigningCertificateV2Template);
if (!pEncodedCertificate) {
- return nullptr;
+ return {};
}
NSSCMSAttribute aAttribute;
@@ -1129,7 +1129,7 @@ std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string
* smime(16) id-aa(2) 47 }
*/
if (my_SEC_StringToOID(arena.get(), &aOidData.oid, "1.2.840.113549.1.9.16.2.47", 0) != SECSuccess) {
- return nullptr;
+ return {};
}
aOidData.offset = SEC_OID_UNKNOWN;
@@ -1141,7 +1141,7 @@ std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string
aAttribute.encoded = PR_TRUE;
if (my_NSS_CMSSignerInfo_AddAuthAttr(cms_signer, &aAttribute) != SECSuccess) {
- return nullptr;
+ return {};
}
SECItem cms_output;
@@ -1150,14 +1150,14 @@ std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string
NSSCMSEncoderContext *cms_ecx = NSS_CMSEncoder_Start(cms_msg.get(), nullptr, nullptr, &cms_output, arena.get(), passwordCallback, password.empty() ? nullptr : const_cast<char *>(password.c_str()), nullptr, nullptr, nullptr, nullptr);
if (!cms_ecx) {
- return nullptr;
+ return {};
}
if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess) {
- return nullptr;
+ return {};
}
- auto signature = std::make_unique<GooString>(reinterpret_cast<const char *>(cms_output.data), cms_output.len);
+ auto signature = GooString(reinterpret_cast<const char *>(cms_output.data), cms_output.len);
SECITEM_FreeItem(pEncodedCertificate, PR_TRUE);
@@ -1238,3 +1238,5 @@ HashAlgorithm HashContext::getHashAlgorithm() const
{
return digest_alg_tag;
}
+
+NSSCryptoSignBackend::~NSSCryptoSignBackend() = default;
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index c9fb575e..8a978f09 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -43,11 +43,7 @@
#include <secoid.h>
#include <secmodt.h>
#include <sechash.h>
-
-// experiments seems to say that this is a bit above
-// what we have seen in the wild, and much larger than
-// what we have managed to get nss and gpgme to create.
-static const int maxSupportedSignatureSize = 10000;
+#include "CryptoSignBackend.h"
class HashContext
{
@@ -67,20 +63,20 @@ private:
HashAlgorithm digest_alg_tag;
};
-class POPPLER_PRIVATE_EXPORT SignatureVerificationHandler
+class POPPLER_PRIVATE_EXPORT SignatureVerificationHandler final : public CryptoSign::VerificationInterface
{
public:
explicit SignatureVerificationHandler(std::vector<unsigned char> &&p7data);
- ~SignatureVerificationHandler();
- SignatureValidationStatus validateSignature();
- time_t getSigningTime() const;
- std::string getSignerName() const;
- std::string getSignerSubjectDN() const;
+ ~SignatureVerificationHandler() final;
+ SignatureValidationStatus validateSignature() final;
+ std::chrono::system_clock::time_point getSigningTime() const final;
+ std::string getSignerName() const final;
+ std::string getSignerSubjectDN() const final;
// Use -1 as validation_time for now
- CertificateValidationStatus validateCertificate(time_t validation_time, bool ocspRevocationCheck, bool useAIACertFetch);
- std::unique_ptr<X509CertificateInfo> getCertificateInfo() const;
- void updateHash(unsigned char *data_block, int data_len);
- HashAlgorithm getHashAlgorithm() const;
+ CertificateValidationStatus validateCertificate(std::chrono::system_clock::time_point validation_time, bool ocspRevocationCheck, bool useAIACertFetch) final;
+ std::unique_ptr<X509CertificateInfo> getCertificateInfo() const final;
+ void addData(unsigned char *data_block, int data_len) final;
+ HashAlgorithm getHashAlgorithm() const final;
SignatureVerificationHandler(const SignatureVerificationHandler &) = delete;
SignatureVerificationHandler &operator=(const SignatureVerificationHandler &) = delete;
@@ -94,14 +90,14 @@ private:
std::unique_ptr<HashContext> hashContext;
};
-class POPPLER_PRIVATE_EXPORT SignatureSignHandler
+class POPPLER_PRIVATE_EXPORT SignatureSignHandler final : public CryptoSign::SigningInterface
{
public:
SignatureSignHandler(const std::string &certNickname, HashAlgorithm digestAlgTag);
- ~SignatureSignHandler();
- std::unique_ptr<X509CertificateInfo> getCertificateInfo() const;
- void updateHash(unsigned char *data_block, int data_len);
- std::unique_ptr<GooString> signDetached(const std::string &password);
+ ~SignatureSignHandler() final;
+ std::unique_ptr<X509CertificateInfo> getCertificateInfo() const final;
+ void addData(unsigned char *data_block, int data_len) final;
+ std::optional<GooString> signDetached(const std::string &password) final;
SignatureSignHandler(const SignatureSignHandler &) = delete;
SignatureSignHandler &operator=(const SignatureSignHandler &) = delete;
@@ -133,4 +129,13 @@ private:
static std::string sNssDir;
};
+class NSSCryptoSignBackend final : public CryptoSign::Backend
+{
+public:
+ std::unique_ptr<CryptoSign::VerificationInterface> createVerificationHandler(std::vector<unsigned char> &&pkcs7) final { return std::make_unique<SignatureVerificationHandler>(std::move(pkcs7)); }
+ std::unique_ptr<CryptoSign::SigningInterface> createSigningHandler(const std::string &certID, HashAlgorithm digestAlgTag) final { return std::make_unique<SignatureSignHandler>(certID, digestAlgTag); }
+ std::vector<std::unique_ptr<X509CertificateInfo>> getAvailableSigningCertificates() final { return SignatureHandler::getAvailableSigningCertificates(); }
+ ~NSSCryptoSignBackend() final;
+};
+
#endif
diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index dfdcd391..05852bb4 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -45,6 +45,7 @@
#include <Link.h>
#include <SignatureInfo.h>
#include <CertificateInfo.h>
+#include <CryptoSignBackend.h>
#ifdef ENABLE_NSS3
# include <SignatureHandler.h>
#endif
@@ -56,10 +57,6 @@
#include <cmath>
#include <cctype>
-#ifdef ENABLE_NSS3
-# include <hasht.h>
-#endif
-
namespace {
Qt::Alignment formTextAlignment(::FormWidget *fm)
@@ -779,14 +776,18 @@ QByteArray CertificateInfo::certificateData() const
bool CertificateInfo::checkPassword(const QString &password) const
{
-#ifdef ENABLE_NSS3
+#ifdef ENABLE_SIGNATURES
+ auto backend = CryptoSign::Factory::createActive();
+ if (!backend) {
+ return false;
+ }
Q_D(const CertificateInfo);
- SignatureSignHandler sigHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256);
+ auto sigHandler = backend->createSigningHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256);
unsigned char buffer[5];
memcpy(buffer, "test", 5);
- sigHandler.updateHash(buffer, 5);
- std::unique_ptr<GooString> tmpSignature = sigHandler.signDetached(password.toStdString());
- return tmpSignature.get() != nullptr;
+ sigHandler->addData(buffer, 5);
+ std::optional<GooString> tmpSignature = sigHandler->signDetached(password.toStdString());
+ return tmpSignature.has_value();
#else
return false;
#endif
@@ -856,7 +857,7 @@ QString SignatureValidationInfo::reason() const
SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const
{
-#ifdef ENABLE_NSS3
+#ifdef ENABLE_SIGNATURES
Q_D(const SignatureValidationInfo);
switch (d->hash_algorithm) {
@@ -1131,16 +1132,17 @@ bool hasNSSSupport()
QVector<CertificateInfo> getAvailableSigningCertificates()
{
+ auto backend = CryptoSign::Factory::createActive();
+ if (!backend) {
+ return {};
+ }
QVector<CertificateInfo> vReturnCerts;
-
-#ifdef ENABLE_NSS3
- std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = SignatureHandler::getAvailableSigningCertificates();
+ std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = backend->getAvailableSigningCertificates();
for (auto &cert : vCerts) {
CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(cert.get());
vReturnCerts.append(CertificateInfo(certPriv));
}
-#endif
return vReturnCerts;
}
diff --git a/qt6/src/poppler-form.cc b/qt6/src/poppler-form.cc
index b415c08e..83dc79d7 100644
--- a/qt6/src/poppler-form.cc
+++ b/qt6/src/poppler-form.cc
@@ -45,6 +45,7 @@
#include <Link.h>
#include <SignatureInfo.h>
#include <CertificateInfo.h>
+#include <CryptoSignBackend.h>
#ifdef ENABLE_NSS3
# include <SignatureHandler.h>
#endif
@@ -56,10 +57,6 @@
#include <cmath>
#include <cctype>
-#ifdef ENABLE_NSS3
-# include <hasht.h>
-#endif
-
namespace {
Qt::Alignment formTextAlignment(::FormWidget *fm)
@@ -779,14 +776,18 @@ QByteArray CertificateInfo::certificateData() const
bool CertificateInfo::checkPassword(const QString &password) const
{
-#ifdef ENABLE_NSS3
+#ifdef ENABLE_SIGNATURES
+ auto backend = CryptoSign::Factory::createActive();
+ if (!backend) {
+ return false;
+ }
Q_D(const CertificateInfo);
- SignatureSignHandler sigHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256);
+ auto sigHandler = backend->createSigningHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256);
unsigned char buffer[5];
memcpy(buffer, "test", 5);
- sigHandler.updateHash(buffer, 5);
- std::unique_ptr<GooString> tmpSignature = sigHandler.signDetached(password.toStdString());
- return tmpSignature.get() != nullptr;
+ sigHandler->addData(buffer, 5);
+ std::optional<GooString> tmpSignature = sigHandler->signDetached(password.toStdString());
+ return tmpSignature.has_value();
#else
return false;
#endif
@@ -856,7 +857,7 @@ QString SignatureValidationInfo::reason() const
SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const
{
-#ifdef ENABLE_NSS3
+#ifdef ENABLE_SIGNATURES
Q_D(const SignatureValidationInfo);
switch (d->hash_algorithm) {
@@ -1131,16 +1132,17 @@ bool hasNSSSupport()
QVector<CertificateInfo> getAvailableSigningCertificates()
{
+ auto backend = CryptoSign::Factory::createActive();
+ if (!backend) {
+ return {};
+ }
QVector<CertificateInfo> vReturnCerts;
-
-#ifdef ENABLE_NSS3
- std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = SignatureHandler::getAvailableSigningCertificates();
+ std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = backend->getAvailableSigningCertificates();
for (auto &cert : vCerts) {
CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(cert.get());
vReturnCerts.append(CertificateInfo(certPriv));
}
-#endif
return vReturnCerts;
}
diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
index 490795f9..334c9372 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -42,6 +42,7 @@
#include "Error.h"
#include "GlobalParams.h"
#include "SignatureHandler.h"
+#include "CryptoSignBackend.h"
#include "SignatureInfo.h"
#include "Win32Console.h"
#include "numberofcharacters.h"
@@ -201,7 +202,7 @@ static std::vector<std::unique_ptr<X509CertificateInfo>> getAvailableSigningCert
}
};
SignatureHandler::setNSSPasswordCallback(passwordCallback);
- std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = SignatureHandler::getAvailableSigningCertificates();
+ std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = CryptoSign::Factory::createActive()->getAvailableSigningCertificates();
SignatureHandler::setNSSPasswordCallback({});
if (passwordNeeded) {
*error = true;
commit cb96047d029e2145191d79b7ece17b4a215794cd
Author: Sune Vuorela <sune at vuorela.dk>
Date: Thu Mar 23 16:40:59 2023 +0100
Backending infrastructure
diff --git a/poppler/CryptoSignBackend.cc b/poppler/CryptoSignBackend.cc
new file mode 100644
index 00000000..86703470
--- /dev/null
+++ b/poppler/CryptoSignBackend.cc
@@ -0,0 +1,97 @@
+//========================================================================
+//
+// CryptoSignBackend.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2023 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune at vuorela.dk>
+//========================================================================
+#include "CryptoSignBackend.h"
+#include "config.h"
+#ifdef ENABLE_NSS3
+# include "SignatureHandler.h"
+#endif
+
+namespace CryptoSign {
+
+void Factory::setPreferredBackend(CryptoSign::Backend::Type backend)
+{
+ preferredBackend = backend;
+}
+static std::string_view toStringView(const char *str)
+{
+ if (str) {
+ return std::string_view(str);
+ }
+ return {};
+}
+
+std::optional<CryptoSign::Backend::Type> Factory::typeFromString(std::string_view string)
+{
+ if (string.empty()) {
+ return std::nullopt;
+ }
+ if ("NSS" == string) {
+ return Backend::Type::NSS3;
+ }
+ return std::nullopt;
+}
+
+CryptoSign::Backend::Type Factory::getActive()
+{
+ if (preferredBackend) {
+ return *preferredBackend;
+ }
+ static auto backendFromEnvironment = typeFromString(toStringView(getenv("POPPLER_SIGNATURE_BACKEND")));
+ if (backendFromEnvironment) {
+ return *backendFromEnvironment;
+ }
+ static auto backendFromCompiledDefault = typeFromString(toStringView(DEFAULT_SIGNATURE_BACKEND));
+ if (backendFromCompiledDefault) {
+ return *backendFromCompiledDefault;
+ }
+
+ return Backend::Type::None;
+}
+static std::vector<Backend::Type> createAvailableBackends()
+{
+ std::vector<Backend::Type> backends;
+#ifdef ENABLE_NSS3
+ backends.push_back(Backend::Type::NSS3);
+#endif
+ return backends;
+}
+std::vector<Backend::Type> Factory::getAvailable()
+{
+ static std::vector<Backend::Type> availableBackends = createAvailableBackends();
+ return availableBackends;
+}
+std::unique_ptr<Backend> Factory::createActive()
+{
+ return create(getActive());
+}
+std::unique_ptr<CryptoSign::Backend> CryptoSign::Factory::create(Backend::Type backend)
+{
+ switch (backend) {
+ case Backend::Type::NSS3:
+#ifdef ENABLE_NSS3
+ return std::make_unique<NSSCryptoSignBackend>();
+#else
+ return nullptr;
+#endif
+ case Backend::Type::None: {
+ return nullptr;
+ }
+ }
+ return nullptr;
+}
+/// backend specific settings
+
+// Android build wants some methods out of line in the interfaces
+Backend::~Backend() = default;
+SigningInterface::~SigningInterface() = default;
+VerificationInterface::~VerificationInterface() = default;
+
+std::optional<Backend::Type> Factory::preferredBackend = std::nullopt;
+
+} // namespace Signature;
diff --git a/poppler/CryptoSignBackend.h b/poppler/CryptoSignBackend.h
new file mode 100644
index 00000000..b106ec47
--- /dev/null
+++ b/poppler/CryptoSignBackend.h
@@ -0,0 +1,101 @@
+//========================================================================
+//
+// CryptoSignBackend.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2023 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune at vuorela.dk>
+//========================================================================
+
+#ifndef SIGNATUREBACKEND_H
+#define SIGNATUREBACKEND_H
+
+#include <vector>
+#include <memory>
+#include <chrono>
+#include <optional>
+#include "HashAlgorithm.h"
+#include "CertificateInfo.h"
+#include "SignatureInfo.h"
+#include "goo/GooString.h"
+#include "poppler_private_export.h"
+
+namespace CryptoSign {
+
+// experiments seems to say that this is a bit above
+// what we have seen in the wild, and much larger than
+// what we have managed to get nss and gpgme to create.
+static const int maxSupportedSignatureSize = 10000;
+
+// Classes to help manage signature backends
+
+class VerificationInterface
+{
+public:
+ virtual void addData(unsigned char *data_block, int data_len) = 0;
+ virtual SignatureValidationStatus validateSignature() = 0;
+ virtual std::chrono::system_clock::time_point getSigningTime() const = 0;
+ virtual std::string getSignerName() const = 0;
+ virtual std::string getSignerSubjectDN() const = 0;
+ virtual HashAlgorithm getHashAlgorithm() const = 0;
+ virtual CertificateValidationStatus validateCertificate(std::chrono::system_clock::time_point validation_time, bool ocspRevocationCheck, bool useAIACertFetch) = 0;
+ virtual std::unique_ptr<X509CertificateInfo> getCertificateInfo() const = 0;
+ virtual ~VerificationInterface();
+ VerificationInterface() = default;
+ VerificationInterface(const VerificationInterface &other) = delete;
+ VerificationInterface &operator=(const VerificationInterface &other) = delete;
+};
+
+class SigningInterface
+{
+public:
+ virtual void addData(unsigned char *data_block, int data_len) = 0;
+ virtual std::unique_ptr<X509CertificateInfo> getCertificateInfo() const = 0;
+ virtual std::optional<GooString> signDetached(const std::string &password) = 0;
+ virtual ~SigningInterface();
+ SigningInterface() = default;
+ SigningInterface(const SigningInterface &other) = delete;
+ SigningInterface &operator=(const SigningInterface &other) = delete;
+};
+
+class Backend
+{
+public:
+ enum class Type
+ {
+ None,
+ NSS3
+ };
+ virtual std::unique_ptr<VerificationInterface> createVerificationHandler(std::vector<unsigned char> &&pkcs7) = 0;
+ virtual std::unique_ptr<SigningInterface> createSigningHandler(const std::string &certID, HashAlgorithm digestAlgTag) = 0;
+ virtual std::vector<std::unique_ptr<X509CertificateInfo>> getAvailableSigningCertificates() = 0;
+ virtual ~Backend();
+ Backend() = default;
+ Backend(const Backend &other) = delete;
+ Backend &operator=(const Backend &other) = delete;
+};
+
+class POPPLER_PRIVATE_EXPORT Factory
+{
+public:
+ // Sets the user preferred backend
+ static void setPreferredBackend(Backend::Type backend);
+ // Gets the current active backend
+ // prioritized from 1) setPreferredBackend,
+ // 2) POPPLER_SIGNATURE_BACKEND
+ // 3) Compiled in default
+ static Backend::Type getActive();
+ static std::vector<Backend::Type> getAvailable();
+ static std::unique_ptr<Backend> createActive();
+ static std::unique_ptr<Backend> create(Backend::Type);
+ static std::optional<Backend::Type> typeFromString(std::string_view string);
+ Factory() = delete;
+ /// backend specific settings
+
+private:
+ static std::optional<Backend::Type> preferredBackend;
+};
+
+}
+
+#endif // SIGNATUREBACKEND_H
More information about the poppler
mailing list