poppler/Form.cc | 30 +++++++++++++++--------------- poppler/Form.h | 2 +- poppler/SignatureHandler.cc | 7 +------ poppler/SignatureHandler.h | 6 +++++- 4 files changed, 22 insertions(+), 23 deletions(-)
New commits: commit 3a3965a5cc7f20fd0d6cbfe92a45b3999456d7a0 Author: Sune Vuorela <[email protected]> Date: Tue Mar 14 09:47:51 2023 +0100 Remove need for dual signing of data Instead of creating a placeholder signature of dummy data, just use dummy data as a placeholder and then pad the real signature with zeroes to fit in the same size as the dummy data. This is also kind of what the pdf specification suggests. It also ensures that for certain smart card setups requiring a distinct pin per signature will only be asked once. diff --git a/poppler/Form.cc b/poppler/Form.cc index 608f4aa6..3f4b0181 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -611,15 +611,7 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st return false; } - // calculate a signature over tmp_buffer with the certificate to get its size - unsigned char tmp_buffer[4]; - memcpy(tmp_buffer, "PDF", 4); SignatureHandler sigHandler(certNickname, HashAlgorithm::Sha256); - sigHandler.updateHash(tmp_buffer, 4); - const std::unique_ptr<GooString> tmpSignature = sigHandler.signDetached(password); - if (!tmpSignature) { - return false; - } FormFieldSignature *signatureField = static_cast<FormFieldSignature *>(field); std::unique_ptr<X509CertificateInfo> certInfo = sigHandler.getCertificateInfo(); @@ -633,7 +625,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), tmpSignature.get(), reason, location)) { + if (!createSignature(vObj, vref, GooString(signerName), maxSupportedSignatureSize, reason, location)) { return false; } @@ -661,7 +653,6 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st } // compute hash of byte ranges - sigHandler.restartHash(); if (!hashFileRange(file, &sigHandler, 0LL, sigStart)) { fclose(file); return false; @@ -678,6 +669,15 @@ bool FormWidgetSignature::signDocument(const std::string &saveFilename, const st return false; } + if (signature->getLength() > maxSupportedSignatureSize) { + fclose(file); + return false; + } + + // pad with zeroes to placeholder length + auto length = signature->getLength(); + signature->append(std::string(maxSupportedSignatureSize - length, '\0')); + // write signature to saved file if (!updateSignature(file, sigStart, sigEnd, signature.get())) { fprintf(stderr, "signDocument: unable update signature\n"); @@ -811,12 +811,12 @@ bool FormWidgetSignature::updateOffsets(FILE *f, Goffset objStart, Goffset objEn } buf[bufSize] = 0; // prevent string functions from searching past the end - // search for the Contents field which contains the signature - // which always must start with hex digits 308 + // search for the Contents field which contains the signature placeholder + // which always must start with hex digits 000 *sigStart = -1; *sigEnd = -1; for (size_t i = 0; i < bufSize - 14; i++) { - if (buf[i] == '/' && strncmp(&buf[i], "/Contents <308", 14) == 0) { + if (buf[i] == '/' && strncmp(&buf[i], "/Contents <000", 14) == 0) { *sigStart = objStart + i + 10; char *p = strchr(&buf[i], '>'); if (p) { @@ -878,7 +878,7 @@ bool FormWidgetSignature::updateSignature(FILE *f, Goffset sigStart, Goffset sig return true; } -bool FormWidgetSignature::createSignature(Object &vObj, Ref vRef, const GooString &name, const GooString *signature, const GooString *reason, const GooString *location) +bool FormWidgetSignature::createSignature(Object &vObj, Ref vRef, const GooString &name, int placeholderLength, const GooString *reason, const GooString *location) { vObj.dictAdd("Type", Object(objName, "Sig")); vObj.dictAdd("Filter", Object(objName, "Adobe.PPKLite")); @@ -893,7 +893,7 @@ bool FormWidgetSignature::createSignature(Object &vObj, Ref vRef, const GooStrin vObj.dictAdd("Location", Object(location->copy())); } - vObj.dictAdd("Contents", Object(objHexString, signature->copy())); + vObj.dictAdd("Contents", Object(objHexString, new GooString(std::string(placeholderLength, '\0')))); Object bObj(new Array(xref)); // reserve space in byte range for maximum number of bytes bObj.arrayAdd(Object(static_cast<long long>(0LL))); diff --git a/poppler/Form.h b/poppler/Form.h index ac714791..d9bf7a45 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -324,7 +324,7 @@ public: const GooString *getSignature() const; private: - bool createSignature(Object &vObj, Ref vRef, const GooString &name, const GooString *signature, const GooString *reason = nullptr, const GooString *location = nullptr); + bool createSignature(Object &vObj, Ref vRef, const GooString &name, int placeholderLength, const GooString *reason = nullptr, const GooString *location = nullptr); 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); diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc index 4aa02297..7ba09136 100644 --- a/poppler/SignatureHandler.cc +++ b/poppler/SignatureHandler.cc @@ -839,11 +839,6 @@ void SignatureHandler::updateHash(unsigned char *data_block, int data_len) } } -void SignatureHandler::restartHash() -{ - hash_context.reset(HASH_Create(HASH_GetHashTypeByOidTag(ConvertHashAlgorithmToNss(digest_alg_tag)))); -} - SignatureHandler::~SignatureHandler() { if (CMSMessage) { @@ -1118,7 +1113,7 @@ std::unique_ptr<GooString> SignatureHandler::signDetached(const std::string &pas { void operator()(PLArenaPool *arena) { PORT_FreeArena(arena, PR_FALSE); } }; - std::unique_ptr<PLArenaPool, PLArenaFreeFalse> arena { PORT_NewArena(10000) }; + std::unique_ptr<PLArenaPool, PLArenaFreeFalse> arena { PORT_NewArena(maxSupportedSignatureSize) }; // Add the signing certificate as a signed attribute. ESSCertIDv2 *aCertIDs[2]; diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h index 0174c6e8..d483607b 100644 --- a/poppler/SignatureHandler.h +++ b/poppler/SignatureHandler.h @@ -43,6 +43,11 @@ #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; + class POPPLER_PRIVATE_EXPORT SignatureHandler { public: @@ -54,7 +59,6 @@ public: std::string getSignerSubjectDN() const; HashAlgorithm getHashAlgorithm() const; void updateHash(unsigned char *data_block, int data_len); - void restartHash(); SignatureValidationStatus validateSignature(); // Use -1 as validation_time for now CertificateValidationStatus validateCertificate(time_t validation_time, bool ocspRevocationCheck, bool useAIACertFetch);
