From cdacb4158258d91ee74b70d21079c2c54bdb89c1 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 5 Sep 2017 22:02:53 +0930 Subject: [PATCH 2/4] pdfsig: add -nssdir option to specify nssdb directory --- poppler/Form.cc | 12 ++++++------ poppler/Form.h | 7 ++++--- poppler/SignatureHandler.cc | 24 ++++++++++++++++-------- poppler/SignatureHandler.h | 6 +++--- qt5/src/poppler-form.cc | 4 ++-- utils/pdfsig.1 | 15 +++++++++++++-- utils/pdfsig.cc | 7 +++++-- 7 files changed, 49 insertions(+), 26 deletions(-) diff --git a/poppler/Form.cc b/poppler/Form.cc index 1925b278..f16144c9 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -452,12 +452,12 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu type = formSignature; } -SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime) +SignatureInfo *FormWidgetSignature::validateSignature(const char *nssDir, bool doVerifyCert, bool forceRevalidation, time_t validationTime) { - return static_cast(field)->validateSignature(doVerifyCert, forceRevalidation, validationTime); + return static_cast(field)->validateSignature(nssDir, doVerifyCert, forceRevalidation, validationTime); } -GBool FormWidgetSignature::signDocument(const char* certNickname, const char* digestName, +GBool FormWidgetSignature::signDocument(const char *nssDir, const char* certNickname, const char* digestName, const char* password, const char* reason) { GBool ok = gFalse; @@ -465,7 +465,7 @@ GBool FormWidgetSignature::signDocument(const char* certNickname, const char* di { unsigned char tmp_buffer[4]; memcpy(tmp_buffer, "PDF", 4); - SignatureHandler sigHandler(certNickname, SignatureHandler::getHashOidTag(digestName)); + SignatureHandler sigHandler(nssDir, certNickname, SignatureHandler::getHashOidTag(digestName)); sigHandler.updateHash(tmp_buffer, 4); // calculate a signature over tmp_buffer with the certificate to get its size GooString* tmpSignature = sigHandler.signDetached(password); @@ -1870,7 +1870,7 @@ void FormWidgetSignature::setSignatureType(FormSignatureType type) static_cast(field)->signature_type = type; } -SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime) +SignatureInfo *FormFieldSignature::validateSignature(const char *nssDir, bool doVerifyCert, bool forceRevalidation, time_t validationTime) { #ifdef ENABLE_NSS3 if (!signature_info->isSubfilterSupported()) { @@ -1903,7 +1903,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for const int signature_len = signature->getLength(); unsigned char *signatureuchar = (unsigned char *)gmalloc(signature_len); memcpy(signatureuchar, signature->getCString(), signature_len); - SignatureHandler signature_handler(signatureuchar, signature_len); + SignatureHandler signature_handler(nssDir, signatureuchar, signature_len); Goffset fileLength = doc->getBaseStream()->getLength(); for (int i = 0; i < arrayLen/2; i++) { diff --git a/poppler/Form.h b/poppler/Form.h index f5e8b1ad..ad41e264 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -270,7 +270,7 @@ public: void setSignatureType(FormSignatureType type); // Use -1 for now as validationTime - SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime); + SignatureInfo *validateSignature(const char *nssDir, bool doVerifyCert, bool forceRevalidation, time_t validationTime); // creates or replaces the dictionary name "V" in the signature dictionary and // fills it with the fields of the signature; the field "Contents" is the signature @@ -278,7 +278,8 @@ public: // document except for the signature itself; this byte range is specified in the // field "ByteRange" in the dictionary "V" // return success - GBool signDocument(const char *certNickname, const char *digestName, + GBool signDocument(const char *nssDir, + const char *certNickname, const char *digestName, const char *password, const char *reason = nullptr); // returns a list with the boundaries of the signed ranges @@ -550,7 +551,7 @@ public: FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set *usedParents); // Use -1 for now as validationTime - SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime); + SignatureInfo *validateSignature(const char *nssDir, bool doVerifyCert, bool forceRevalidation, time_t validationTime); ~FormFieldSignature(); Object* getByteRange() { return &byte_range; } diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc index c2f3ef8f..75fff98a 100644 --- a/poppler/SignatureHandler.cc +++ b/poppler/SignatureHandler.cc @@ -149,14 +149,22 @@ GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux() /** * Initialise NSS */ -void SignatureHandler::init_nss() +void SignatureHandler::init_nss(const char *nssDir) { + SECStatus status; + GooString *certDBPath = getDefaultFirefoxCertDB_Linux(); - if (certDBPath == NULL) { - NSS_Init("sql:/etc/pki/nssdb"); + if (nssDir) { + status = NSS_Init(nssDir); + } else if (certDBPath) { + status = NSS_Init(certDBPath->getCString()); } else { - NSS_Init(certDBPath->getCString()); + status = NSS_Init("sql:/etc/pki/nssdb"); + } + if (status != SECSuccess) { + fprintf(stderr, "NSS_Init failed: %s\n", PR_ErrorToString(PORT_GetError(), PR_LANGUAGE_I_DEFAULT)); } + //Make sure NSS root certificates module is loaded SECMOD_AddNewModule("Root Certs", "libnssckbi.so", 0, 0); @@ -164,7 +172,7 @@ void SignatureHandler::init_nss() } -SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length) +SignatureHandler::SignatureHandler(const char *nssDir, unsigned char *p7, int p7_length) : hash_context(NULL), CMSMessage(NULL), CMSSignedData(NULL), @@ -172,7 +180,7 @@ SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length) signing_cert(nullptr), temp_certs(NULL) { - init_nss(); + init_nss(nssDir); CMSitem.data = p7; CMSitem.len = p7_length; CMSMessage = CMS_MessageCreate(&CMSitem); @@ -183,7 +191,7 @@ SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length) } } -SignatureHandler::SignatureHandler(const char *certNickname, SECOidTag digestAlgTag) +SignatureHandler::SignatureHandler(const char *nssDir, const char *certNickname, SECOidTag digestAlgTag) : hash_length(digestLength(digestAlgTag)), digest_alg_tag(digestAlgTag), CMSitem(), @@ -194,7 +202,7 @@ SignatureHandler::SignatureHandler(const char *certNickname, SECOidTag digestAlg signing_cert(nullptr), temp_certs(nullptr) { - init_nss(); + init_nss(nssDir); CMSMessage = NSS_CMSMessage_Create(nullptr); signing_cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), certNickname); hash_context = HASH_Create(HASH_GetHashTypeByOidTag(digestAlgTag)); diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h index 0f4e3b1f..c844c9cb 100644 --- a/poppler/SignatureHandler.h +++ b/poppler/SignatureHandler.h @@ -33,8 +33,8 @@ class SignatureHandler { public: - SignatureHandler(unsigned char *p7, int p7_length); - SignatureHandler(const char *certNickname, SECOidTag digestAlgTag); + SignatureHandler(const char *nssDir, unsigned char *p7, int p7_length); + SignatureHandler(const char *nssDir, const char *certNickname, SECOidTag digestAlgTag); ~SignatureHandler(); time_t getSigningTime(); char * getSignerName(); @@ -67,7 +67,7 @@ private: SignatureHandler(const SignatureHandler &); SignatureHandler& operator=(const SignatureHandler &); - void init_nss(); + void init_nss(const char *nssDir); GooString * getDefaultFirefoxCertDB_Linux(); unsigned int digestLength(SECOidTag digestAlgId); diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc index 09045293..a6cd59f7 100644 --- a/qt5/src/poppler-form.cc +++ b/qt5/src/poppler-form.cc @@ -662,7 +662,7 @@ bool FormFieldSignature::sign(const QString& certNickname, const QString& passwo } if (!reason.isEmpty()) rs = reason.toUtf8().constData(); - GBool ok = fws->signDocument(name, digest, pw, rs); + GBool ok = fws->signDocument(nullptr, name, digest, pw, rs); free(name); free(pw); return ok; @@ -677,7 +677,7 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime& v { FormWidgetSignature* fws = static_cast(m_formData->fm); const time_t validationTimeT = validationTime.isValid() ? validationTime.toTime_t() : -1; - SignatureInfo* si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT); + SignatureInfo* si = fws->validateSignature(nullptr, opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT); SignatureValidationInfoPrivate* priv = new SignatureValidationInfoPrivate; switch (si->getSignatureValStatus()) { case SIGNATURE_VALID: diff --git a/utils/pdfsig.1 b/utils/pdfsig.1 index ef2e0c3d..1e614ed1 100644 --- a/utils/pdfsig.1 +++ b/utils/pdfsig.1 @@ -17,13 +17,23 @@ the type of the signature as stated in the PDF and the signed ranges with a statement wether the total document is signed. Moreover, with option -sign it can sign a PDF document. .PP -The signer certificate validation uses the trusted certificates stored in the following locations: +The signer certificate validation uses the trusted certificates stored in the +Network Security Services (NSS) Database. The NSS Database is search for in the following locations: .IP \(bu -The NSS Certificate database in the default Firefox profile. +If the \-nssdir option is specified, the directory specified by this option. +.IP \(bu +The NSS Certificate database in the default Firefox profile. ie $HOME/.mozilla/firefox/*.default. .IP \(bu The NSS Certificate database in /etc/pki/nssdb. .SH OPTIONS .TP +.B \-nssdir "[prefix]directory" +Specify the database directory containing the certificate and key +database files. See certutil(1) -d option for details of the +prefix. If not specified the other search locations described in +.B DESCRIPTION +are used. +.TP .B \-nocert Do not validate the certificate. .TP @@ -70,3 +80,4 @@ and copyright 2005-2015 The Poppler Developers - http://poppler.freedesktop.org .BR pdftotext (1) .BR pdfseparate (1), .BR pdfunite (1) +.BR certutil (1) diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc index 24a4fb5b..a4d83e63 100644 --- a/utils/pdfsig.cc +++ b/utils/pdfsig.cc @@ -86,6 +86,7 @@ char *getReadableTime(time_t unix_time) return time_str; } +static GooString nssDir; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static GBool dontVerifyCert = gFalse; @@ -97,6 +98,8 @@ static char digestName[256] = "SHA256"; static char reason[256] = ""; static const ArgDesc argDesc[] = { + {"-nssdir", argGooString, &nssDir, 0, + "don't perform certificate validation"}, {"-nocert", argFlag, &dontVerifyCert, 0, "don't perform certificate validation"}, {"-sign", argInt, &signatureNumber, 0, @@ -194,7 +197,7 @@ int main(int argc, char *argv[]) fws->setSignatureType(ETSI_CAdES_detached); const char* pw = (strlen(password) == 0) ? nullptr : password; const char* rs = (strlen(reason) == 0) ? nullptr : reason; - if (fws->signDocument(certNickname, digestName, pw, rs)) { + if (fws->signDocument(nssDir.getCString(), certNickname, digestName, pw, rs)) { GooString* out = new GooString(argv[2]); exitCode = doc->saveAs(out); delete out; @@ -214,7 +217,7 @@ int main(int argc, char *argv[]) } for (unsigned int i = 0; i < sigCount; i++) { - sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false, -1 /* now */); + sig_info = sig_widgets.at(i)->validateSignature(nssDir.getCString(), !dontVerifyCert, false, -1 /* now */); printf("Signature #%u:\n", i+1); printf(" - Signer Certificate Common Name: %s\n", sig_info->getSignerName()); printf(" - Signer full Distinguished Name: %s\n", sig_info->getSubjectDN()); -- 2.11.0