poppler/Form.cc | 8 +- poppler/Form.h | 4 - poppler/SignatureHandler.cc | 125 +++++++++++++++++++------------------------- poppler/SignatureHandler.h | 64 ++++++++++++++-------- qt5/src/poppler-form.cc | 2 qt6/src/poppler-form.cc | 2 6 files changed, 105 insertions(+), 100 deletions(-)
New commits: commit 08c0766e9d7ab08cdc7ef380ce9c190ae87d789b Author: Sune Vuorela <[email protected]> Date: Fri Mar 3 08:22:13 2023 +0100 Split signature handler for signing and verification Only a little bit of the class state was shared between the signing and verification functions, so split it in the shared hashing bits and a class for signing and one for verification Also clean up a little bit of the memory handling diff --git a/poppler/Form.cc b/poppler/Form.cc index 3f4b0181..2c0c35a4 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -575,7 +575,7 @@ SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool fo #ifdef ENABLE_NSS3 // update hash with the specified range of data from the file -static bool hashFileRange(FILE *f, SignatureHandler *handler, Goffset start, Goffset end) +static bool hashFileRange(FILE *f, SignatureSignHandler *handler, Goffset start, Goffset end) { const int BUF_SIZE = 65536; @@ -611,7 +611,7 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st return false; } - SignatureHandler sigHandler(certNickname, HashAlgorithm::Sha256); + SignatureSignHandler sigHandler(certNickname, HashAlgorithm::Sha256); FormFieldSignature *signatureField = static_cast<FormFieldSignature *>(field); std::unique_ptr<X509CertificateInfo> certInfo = sigHandler.getCertificateInfo(); @@ -2305,7 +2305,7 @@ void FormFieldSignature::parseInfo() } } -void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset block_len) +void FormFieldSignature::hashSignedDataBlock(SignatureVerificationHandler *handler, Goffset block_len) { #ifdef ENABLE_NSS3 const int BLOCK_SIZE = 4096; @@ -2363,7 +2363,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); - SignatureHandler signature_handler(std::move(signatureData)); + SignatureVerificationHandler signature_handler(std::move(signatureData)); Goffset fileLength = doc->getBaseStream()->getLength(); for (int i = 0; i < arrayLen / 2; i++) { diff --git a/poppler/Form.h b/poppler/Form.h index d9bf7a45..80be38e6 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -56,7 +56,7 @@ class GfxResources; class PDFDoc; class SignatureInfo; class X509CertificateInfo; -class SignatureHandler; +class SignatureVerificationHandler; enum FormFieldType { @@ -640,7 +640,7 @@ public: private: void parseInfo(); - void hashSignedDataBlock(SignatureHandler *handler, Goffset block_len); + void hashSignedDataBlock(SignatureVerificationHandler *handler, Goffset block_len); FormSignatureType signature_type; Object byte_range; diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc index 17d7cb17..64ac6594 100644 --- a/poppler/SignatureHandler.cc +++ b/poppler/SignatureHandler.cc @@ -498,30 +498,21 @@ static unsigned int digestLength(HashAlgorithm digestAlgId) } } -std::string SignatureHandler::getSignerName() const +std::string SignatureVerificationHandler::getSignerName() const { if (!NSS_IsInitialized()) { return {}; } - - if (!signing_cert && !CMSSignerInfo) { + if (!CMSSignerInfo) { return {}; } - CERTCertificate *activeCert = nullptr; + auto signing_cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); if (!signing_cert) { - // we are signing, and thus getting the name of the SignerInfo, not of the signing cert. Data owned by CMSSignerInfo - activeCert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); - } else { - // We are verifying. data owned by us. - activeCert = signing_cert; - } - - if (!activeCert) { return {}; } - char *commonName = CERT_GetCommonName(&activeCert->subject); + char *commonName = CERT_GetCommonName(&signing_cert->subject); if (!commonName) { return {}; } @@ -531,38 +522,23 @@ std::string SignatureHandler::getSignerName() const return name; } -std::string SignatureHandler::getSignerSubjectDN() const +std::string SignatureVerificationHandler::getSignerSubjectDN() const { - if (!signing_cert && !CMSSignerInfo) { + if (!CMSSignerInfo) { return {}; } - CERTCertificate *activeCert = nullptr; - + auto signing_cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); if (!signing_cert) { - // we are signing, and thus getting the name of the SignerInfo, not of the signing cert. Data owned by CMSSignerInfo - activeCert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); - } else { - // We are verifying. data owned by us. - activeCert = signing_cert; - } - - if (!activeCert) { return {}; } - - return activeCert->subjectName; + return std::string { signing_cert->subjectName }; } -HashAlgorithm SignatureHandler::getHashAlgorithm() const +time_t SignatureVerificationHandler::getSigningTime() const { - if (hashContext) { - return hashContext->getHashAlgorithm(); + if (!CMSSignerInfo) { + return {}; } - return HashAlgorithm::Unknown; -} - -time_t SignatureHandler::getSigningTime() const -{ PRTime sTime; // time in microseconds since the epoch if (NSS_CMSSignerInfo_GetSigningTime(CMSSignerInfo, &sTime) != SECSuccess) { @@ -670,21 +646,24 @@ static std::unique_ptr<X509CertificateInfo> getCertificateInfoFromCERT(CERTCerti return certInfo; } -std::unique_ptr<X509CertificateInfo> SignatureHandler::getCertificateInfo() const +std::unique_ptr<X509CertificateInfo> SignatureVerificationHandler::getCertificateInfo() const { - if (CMSSignerInfo) { - CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); - if (!cert) { - return nullptr; - } - return getCertificateInfoFromCERT(cert); - } else { - if (!signing_cert) { - return nullptr; - } + if (!CMSSignerInfo) { + return nullptr; + } + CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB()); + if (!cert) { + return nullptr; + } + return getCertificateInfoFromCERT(cert); +} - return getCertificateInfoFromCERT(signing_cert); +std::unique_ptr<X509CertificateInfo> SignatureSignHandler::getCertificateInfo() const +{ + if (!signing_cert) { + return nullptr; } + return getCertificateInfoFromCERT(signing_cert); } static std::optional<std::string> getDefaultFirefoxCertDB() @@ -777,16 +756,15 @@ void SignatureHandler::setNSSPasswordCallback(const std::function<char *(const c PasswordFunction = f; } -SignatureHandler::SignatureHandler(std::vector<unsigned char> &&p7data) : p7(std::move(p7data)), hashContext(nullptr), CMSMessage(nullptr), CMSSignedData(nullptr), CMSSignerInfo(nullptr), signing_cert(nullptr) +SignatureVerificationHandler::SignatureVerificationHandler(std::vector<unsigned char> &&p7data) : p7(std::move(p7data)), CMSMessage(nullptr), CMSSignedData(nullptr), CMSSignerInfo(nullptr) { - setNSSDir({}); + SignatureHandler::setNSSDir({}); CMSitem.data = p7.data(); CMSitem.len = p7.size(); CMSMessage = CMS_MessageCreate(&CMSitem); CMSSignedData = CMS_SignedDataCreate(CMSMessage); if (CMSSignedData) { CMSSignerInfo = CMS_SignerInfoCreate(CMSSignedData); - SECItem usedAlgorithm = NSS_CMSSignedData_GetDigestAlgs(CMSSignedData)[0]->algorithm; auto hashAlgorithm = SECOID_FindOIDTag(&usedAlgorithm); HASH_HashType hashType = HASH_GetHashTypeByOidTag(hashAlgorithm); @@ -794,22 +772,34 @@ SignatureHandler::SignatureHandler(std::vector<unsigned char> &&p7data) : p7(std } } -SignatureHandler::SignatureHandler(const std::string &certNickname, HashAlgorithm digestAlgTag) - : CMSitem(), hashContext(std::make_unique<HashContext>(digestAlgTag)), CMSMessage(nullptr), CMSSignedData(nullptr), CMSSignerInfo(nullptr), signing_cert(nullptr) +SignatureSignHandler::SignatureSignHandler(const std::string &certNickname, HashAlgorithm digestAlgTag) : hashContext(std::make_unique<HashContext>(digestAlgTag)), signing_cert(nullptr) { - setNSSDir({}); - CMSMessage = NSS_CMSMessage_Create(nullptr); + SignatureHandler::setNSSDir({}); signing_cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), certNickname.c_str()); } -void SignatureHandler::updateHash(unsigned char *data_block, int data_len) +HashAlgorithm SignatureVerificationHandler::getHashAlgorithm() const { - if (hashContext) { - hashContext->updateHash(data_block, data_len); - } + return hashContext->getHashAlgorithm(); +} + +void SignatureVerificationHandler::updateHash(unsigned char *data_block, int data_len) +{ + hashContext->updateHash(data_block, data_len); +} + +void SignatureSignHandler::updateHash(unsigned char *data_block, int data_len) +{ + hashContext->updateHash(data_block, data_len); } -SignatureHandler::~SignatureHandler() +SignatureSignHandler::~SignatureSignHandler() +{ + if (signing_cert) { + CERT_DestroyCertificate(signing_cert); + } +} +SignatureVerificationHandler::~SignatureVerificationHandler() { if (CMSMessage) { // in the CMS_SignedDataCreate, we malloc some memory @@ -826,10 +816,6 @@ SignatureHandler::~SignatureHandler() NSS_CMSMessage_Destroy(CMSMessage); free(toFree); } - - if (signing_cert) { - CERT_DestroyCertificate(signing_cert); - } } static NSSCMSMessage *CMS_MessageCreate(SECItem *cms_item) @@ -881,7 +867,7 @@ static NSSCMSSignedData *CMS_SignedDataCreate(NSSCMSMessage *cms_msg) } } -NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData *cms_sig_data) +static NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData *cms_sig_data) { NSSCMSSignerInfo *signerInfo = NSS_CMSSignedData_GetSignerInfo(cms_sig_data, 0); if (!signerInfo) { @@ -912,7 +898,7 @@ static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_c } } -SignatureValidationStatus SignatureHandler::validateSignature() +SignatureValidationStatus SignatureVerificationHandler::validateSignature() { if (!CMSSignedData) { return SIGNATURE_GENERIC_ERROR; @@ -955,7 +941,7 @@ SignatureValidationStatus SignatureHandler::validateSignature() } } -CertificateValidationStatus SignatureHandler::validateCertificate(time_t validation_time, bool ocspRevocationCheck, bool useAIACertFetch) +CertificateValidationStatus SignatureVerificationHandler::validateCertificate(time_t validation_time, bool ocspRevocationCheck, bool useAIACertFetch) { CERTCertificate *cert; @@ -1011,7 +997,7 @@ CertificateValidationStatus SignatureHandler::validateCertificate(time_t validat return CERTIFICATE_GENERIC_ERROR; } -std::unique_ptr<GooString> SignatureHandler::signDetached(const std::string &password) const +std::unique_ptr<GooString> SignatureSignHandler::signDetached(const std::string &password) { if (!hashContext) { return nullptr; @@ -1024,7 +1010,6 @@ std::unique_ptr<GooString> SignatureHandler::signDetached(const std::string &pas ///////////////////////////////////// /// Code from LibreOffice under MPLv2 ///////////////////////////////////// - struct NSSCMSMessageDestroyer { void operator()(NSSCMSMessage *message) { NSS_CMSMessage_Destroy(message); } @@ -1166,11 +1151,11 @@ std::unique_ptr<GooString> SignatureHandler::signDetached(const std::string &pas return nullptr; } - GooString *signature = new GooString(reinterpret_cast<const char *>(cms_output.data), cms_output.len); + auto signature = std::make_unique<GooString>(reinterpret_cast<const char *>(cms_output.data), cms_output.len); SECITEM_FreeItem(pEncodedCertificate, PR_TRUE); - return std::unique_ptr<GooString>(signature); + return signature; } static char *GetPasswordFunction(PK11SlotInfo *slot, PRBool /*retry*/, void * /*arg*/) diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h index fb3aac2e..c9fb575e 100644 --- a/poppler/SignatureHandler.h +++ b/poppler/SignatureHandler.h @@ -29,6 +29,7 @@ #include <vector> #include <functional> +#include <memory> /* NSPR Headers */ #include <nspr.h> @@ -66,23 +67,54 @@ private: HashAlgorithm digest_alg_tag; }; -class POPPLER_PRIVATE_EXPORT SignatureHandler +class POPPLER_PRIVATE_EXPORT SignatureVerificationHandler { public: - explicit SignatureHandler(std::vector<unsigned char> &&p7data); - SignatureHandler(const std::string &certNickName, HashAlgorithm digestAlgTag); - ~SignatureHandler(); + explicit SignatureVerificationHandler(std::vector<unsigned char> &&p7data); + ~SignatureVerificationHandler(); + SignatureValidationStatus validateSignature(); time_t getSigningTime() const; std::string getSignerName() const; std::string getSignerSubjectDN() const; - HashAlgorithm getHashAlgorithm() const; - void updateHash(unsigned char *data_block, int data_len); - SignatureValidationStatus validateSignature(); // 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; + + SignatureVerificationHandler(const SignatureVerificationHandler &) = delete; + SignatureVerificationHandler &operator=(const SignatureVerificationHandler &) = delete; + +private: + std::vector<unsigned char> p7; + NSSCMSMessage *CMSMessage; + NSSCMSSignedData *CMSSignedData; + NSSCMSSignerInfo *CMSSignerInfo; + SECItem CMSitem; + std::unique_ptr<HashContext> hashContext; +}; + +class POPPLER_PRIVATE_EXPORT SignatureSignHandler +{ +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(const SignatureSignHandler &) = delete; + SignatureSignHandler &operator=(const SignatureSignHandler &) = delete; + +private: + std::unique_ptr<HashContext> hashContext; + CERTCertificate *signing_cert; +}; + +class POPPLER_PRIVATE_EXPORT SignatureHandler +{ +public: static std::vector<std::unique_ptr<X509CertificateInfo>> getAvailableSigningCertificates(); - std::unique_ptr<GooString> signDetached(const std::string &password) const; // Initializes the NSS dir with the custom given directory // calling it with an empty string means use the default firefox db, /etc/pki/nssdb, ~/.pki/nssdb @@ -95,21 +127,9 @@ public: static void setNSSPasswordCallback(const std::function<char *(const char *)> &f); -private: - SignatureHandler(const SignatureHandler &); - SignatureHandler &operator=(const SignatureHandler &); - - static void outputCallback(void *arg, const char *buf, unsigned long len); - - std::vector<unsigned char> p7; - HashAlgorithm digest_alg_tag; - SECItem CMSitem; - std::unique_ptr<HashContext> hashContext; - NSSCMSMessage *CMSMessage; - NSSCMSSignedData *CMSSignedData; - NSSCMSSignerInfo *CMSSignerInfo; - CERTCertificate *signing_cert; + SignatureHandler() = delete; +private: static std::string sNssDir; }; diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc index 1bead08b..dfdcd391 100644 --- a/qt5/src/poppler-form.cc +++ b/qt5/src/poppler-form.cc @@ -781,7 +781,7 @@ bool CertificateInfo::checkPassword(const QString &password) const { #ifdef ENABLE_NSS3 Q_D(const CertificateInfo); - SignatureHandler sigHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256); + SignatureSignHandler sigHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256); unsigned char buffer[5]; memcpy(buffer, "test", 5); sigHandler.updateHash(buffer, 5); diff --git a/qt6/src/poppler-form.cc b/qt6/src/poppler-form.cc index ac138261..b415c08e 100644 --- a/qt6/src/poppler-form.cc +++ b/qt6/src/poppler-form.cc @@ -781,7 +781,7 @@ bool CertificateInfo::checkPassword(const QString &password) const { #ifdef ENABLE_NSS3 Q_D(const CertificateInfo); - SignatureHandler sigHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256); + SignatureSignHandler sigHandler(d->nick_name.toStdString(), HashAlgorithm::Sha256); unsigned char buffer[5]; memcpy(buffer, "test", 5); sigHandler.updateHash(buffer, 5);
