[poppler] poppler/Form.cc poppler/Form.h poppler/SignatureHandler.cc poppler/SignatureHandler.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Thu Mar 23 08:30:03 UTC 2023


 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 <sune at vuorela.dk>
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);


More information about the poppler mailing list