[poppler] 37 commits - CMakeLists.txt cmake/modules config.h.cmake configure.ac poppler/DateInfo.cc poppler/DateInfo.h poppler/Form.cc poppler/Form.h poppler/Makefile.am poppler/Object.h poppler/PDFDoc.cc poppler/PDFDoc.h poppler/SignatureHandler.cc poppler/SignatureHandler.h poppler/SignatureInfo.cc poppler/SignatureInfo.h utils/CMakeLists.txt utils/.gitignore utils/Makefile.am utils/pdfdetach.1 utils/pdffonts.1 utils/pdfimages.1 utils/pdfinfo.1 utils/pdfseparate.1 utils/pdfsig.1 utils/pdfsig.cc utils/pdftocairo.1 utils/pdftohtml.1 utils/pdftoppm.1 utils/pdftops.1 utils/pdftotext.1 utils/pdfunite.1

Albert Astals Cid aacid at kemper.freedesktop.org
Tue Mar 1 23:39:50 UTC 2016


 CMakeLists.txt               |   15 +
 cmake/modules/FindNSS3.cmake |   22 ++
 config.h.cmake               |    3 
 configure.ac                 |   20 ++
 poppler/DateInfo.cc          |   26 +++
 poppler/DateInfo.h           |    3 
 poppler/Form.cc              |  168 ++++++++++++++++++++-
 poppler/Form.h               |   18 ++
 poppler/Makefile.am          |   22 ++
 poppler/Object.h             |   12 +
 poppler/PDFDoc.cc            |   25 +++
 poppler/PDFDoc.h             |    7 
 poppler/SignatureHandler.cc  |  339 +++++++++++++++++++++++++++++++++++++++++++
 poppler/SignatureHandler.h   |   74 +++++++++
 poppler/SignatureInfo.cc     |   87 +++++++++++
 poppler/SignatureInfo.h      |   71 +++++++++
 utils/.gitignore             |    1 
 utils/CMakeLists.txt         |   10 +
 utils/Makefile.am            |    7 
 utils/pdfdetach.1            |    5 
 utils/pdffonts.1             |    3 
 utils/pdfimages.1            |    5 
 utils/pdfinfo.1              |    3 
 utils/pdfseparate.1          |   12 +
 utils/pdfsig.1               |   47 +++++
 utils/pdfsig.cc              |  177 ++++++++++++++++++++++
 utils/pdftocairo.1           |    3 
 utils/pdftohtml.1            |    3 
 utils/pdftoppm.1             |    3 
 utils/pdftops.1              |    3 
 utils/pdftotext.1            |    5 
 utils/pdfunite.1             |   10 +
 32 files changed, 1198 insertions(+), 11 deletions(-)

New commits:
commit 9d33825e6f6167f07b2739645b93249b2bc043da
Merge: a8853b1 f3e3ebe
Author: Albert Astals Cid <aacid at kde.org>
Date:   Wed Mar 2 00:37:11 2016 +0100

    Merge remote-tracking branch 'origin/signatureHandling'

diff --cc CMakeLists.txt
index d5474f6,ca71630..07d9eb2
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@@ -726,8 -732,8 +740,9 @@@ show_end_message("use gtk-doc" "not sup
  show_end_message_yesno("use libjpeg" ENABLE_LIBJPEG)
  show_end_message_yesno("use libpng" ENABLE_LIBPNG)
  show_end_message_yesno("use libtiff" ENABLE_LIBTIFF)
 -show_end_message_yesno("use zlib" ENABLE_ZLIB)
 +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_yesno("use curl" ENABLE_LIBCURL)
  show_end_message_yesno("use libopenjpeg" WITH_OPENJPEG)
  if(USE_OPENJPEG1)
diff --cc config.h.cmake
index 60c5120,b62994f..85c6d32
--- a/config.h.cmake
+++ b/config.h.cmake
@@@ -18,12 -18,12 +18,15 @@@
  /* Do not hardcode the library location */
  #cmakedefine ENABLE_RELOCATABLE 1
  
 -/* Use zlib instead of builtin zlib decoder. */
 +/* Build against zlib. */
  #cmakedefine ENABLE_ZLIB 1
  
 +/* Use zlib instead of builtin zlib decoder to uncompress flate streams. */
 +#cmakedefine ENABLE_ZLIB_UNCOMPRESS 1
 +
+ /* Build against libnss3 for digital signature validation */
+ #cmakedefine ENABLE_NSS3 1
+ 
  /* Use cairo for rendering. */
  #cmakedefine HAVE_CAIRO 1
  
diff --cc configure.ac
index 879901d,da18b23..8cc9044
--- a/configure.ac
+++ b/configure.ac
@@@ -1016,20 -1013,20 +1035,21 @@@ echo "  splash output:       $enable_sp
  if test x$enable_cmyk = xyes;then
          echo "      with CMYK support"
  fi
 -echo "  cairo output:       $use_cairo"
 -echo "  qt4 wrapper:        $enable_poppler_qt4"
 -echo "  qt5 wrapper:        $enable_poppler_qt5"
 -echo "  glib wrapper:       $use_glib"
 -echo "    introspection:    $found_introspection"
 -echo "  cpp wrapper:        $enable_poppler_cpp"
 -echo "  use gtk-doc:        $enable_gtk_doc"
 -echo "  use libjpeg:        $enable_libjpeg"
 -echo "  use libpng:         $enable_libpng"
 -echo "  use libtiff:        $enable_libtiff"
 -echo "  use zlib:           $enable_zlib"
 -echo "  use nss             $enable_nss"
 -echo "  use libcurl:        $enable_libcurl"
 -echo "  use libopenjpeg:    $enable_libopenjpeg"
 +echo "  cairo output:        $use_cairo"
 +echo "  qt4 wrapper:         $enable_poppler_qt4"
 +echo "  qt5 wrapper:         $enable_poppler_qt5"
 +echo "  glib wrapper:        $use_glib"
 +echo "    introspection:     $found_introspection"
 +echo "  cpp wrapper:         $enable_poppler_cpp"
 +echo "  use gtk-doc:         $enable_gtk_doc"
 +echo "  use libjpeg:         $enable_libjpeg"
 +echo "  use libpng:          $enable_libpng"
 +echo "  use libtiff:         $enable_libtiff"
 +echo "  use zlib compress:   $enable_zlib"
 +echo "  use zlib uncompress: $enable_zlib_uncompress"
++echo "  use nss:             $enable_nss"
 +echo "  use libcurl:         $enable_libcurl"
 +echo "  use libopenjpeg:     $enable_libopenjpeg"
  if test x$enable_libopenjpeg = xyes;then
      if test x$openjpeg1 = xyes;then
          echo "      with openjpeg1"
diff --cc poppler/Makefile.am
index 90340b8,1b6500f..de6748b
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@@ -208,7 -218,7 +226,8 @@@ libpoppler_la_SOURCES =		
  	$(splash_sources)	\
  	$(libjpeg_sources)	\
  	$(zlib_sources)		\
 +	$(zlib_uncompress_sources) \
+ 	$(nss_sources)      \
  	$(libjpeg2000_sources)	\
  	$(curl_sources)		\
  	Annot.cc		\
commit f3e3ebe51483050cfdf8773dbd0d6646521f17cb
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Wed Mar 2 00:35:05 2016 +0100

    Load NSS root certs module
    
    This change is needed to actually do certificate validation, because as it is NSS is trying to load the module which contains all the builtin root certs from the Firefox profile directory where it is usually missing. This way it will load the module from a system library directory.

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index f299b7e..01496e3 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -15,6 +15,7 @@
 
 #include "SignatureHandler.h"
 #include "goo/gmem.h"
+#include <nss/secmod.h>
 
 #include <dirent.h>
 #include <Error.h>
@@ -95,6 +96,8 @@ void SignatureHandler::init_nss()
   } else {
     NSS_Init(certDBPath->getCString());
   }
+  //Make sure NSS root certificates module is loaded
+  SECMOD_AddNewModule("Root Certs", "libnssckbi.so", 0, 0);
 
   delete certDBPath;
 }
commit dcefd7a232ba17af878b95efaa4ffaf147d095b7
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Jan 8 16:49:25 2016 +1030

    check all byte ranges in signature dictionary

diff --git a/poppler/Form.cc b/poppler/Form.cc
index d94757a..910c179 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1473,48 +1473,51 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
     return signature_info;
   }
 
-  if (!byte_range.isArray() || signature == NULL) {
+  if (signature == NULL) {
+    error(errSyntaxError, 0, "Invalid or missing Signature string");
     return signature_info;
   }
 
-  Object r2, r3, r4;
-  NSSCMSVerificationStatus sig_val_state;
-  SECErrorCodes cert_val_state;
-
-  byte_range.arrayGet(1, &r2);
-  byte_range.arrayGet(2, &r3);
-  byte_range.arrayGet(3, &r4);
-
-  Goffset fileLength = doc->getBaseStream()->getLength();
-  Goffset r_values[3];
-
-  r_values[0] = r2.isInt64() ? r2.getInt64() : r2.getInt();
-  r_values[1] = r3.isInt64() ? r3.getInt64() : r3.getInt();
-  r_values[2] = r4.isInt64() ? r4.getInt64() : r4.getInt();
+  if (!byte_range.isArray()) {
+    error(errSyntaxError, 0, "Invalid or missing ByteRange array");
+    return signature_info;
+  }
 
-  if (r_values[0] <= 0 || r_values[1] <= 0 || r_values[2] <= 0 || r_values[1] <= r_values[0] ||
-    r_values[1] + r_values[2] > fileLength)
-  {
-      error(errSyntaxError, 0, "Illegal values in ByteRange array");
-      return signature_info;
+  int arrayLen = byte_range.arrayGetLength();
+  if (arrayLen < 2) {
+    error(errSyntaxError, 0, "Too few elements in ByteRange array");
+    return signature_info;
   }
 
+  NSSCMSVerificationStatus sig_val_state;
+  SECErrorCodes cert_val_state;
   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);
 
-  //Read the 2 slices of data that are signed
-  doc->getBaseStream()->setPos(0);
-  Goffset block_len = r_values[0];
+  Goffset fileLength = doc->getBaseStream()->getLength();
+  for (int i = 0; i < arrayLen/2; i++) {
+    Object offsetObj, lenObj;
+    byte_range.arrayGet(i*2, &offsetObj);
+    byte_range.arrayGet(i*2+1, &lenObj);
+
+    if (!offsetObj.isIntOrInt64() || !lenObj.isIntOrInt64()) {
+      error(errSyntaxError, 0, "Illegal values in ByteRange array");
+      return signature_info;
+    }
 
-  hashSignedDataBlock(&signature_handler, block_len);
+    Goffset offset = offsetObj.getIntOrInt64();
+    Goffset len = lenObj.getIntOrInt64();
 
-  doc->getBaseStream()->setPos(r_values[1]);
-  block_len = r_values[2];
+    if (offset < 0 || offset >= fileLength || len < 0 || len > fileLength || offset + len > fileLength) {
+      error(errSyntaxError, 0, "Illegal values in ByteRange array");
+      return signature_info;
+    }
 
-  hashSignedDataBlock(&signature_handler, block_len);
+    doc->getBaseStream()->setPos(offset);
+    hashSignedDataBlock(&signature_handler, len);
+  }
 
   sig_val_state = signature_handler.validateSignature();
   signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
@@ -1534,7 +1537,6 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
 
 #endif
   return signature_info;
-
 }
 
 #ifdef DEBUG_FORMS
diff --git a/poppler/Object.h b/poppler/Object.h
index 1b06a3c..b9cae28 100644
--- a/poppler/Object.h
+++ b/poppler/Object.h
@@ -50,7 +50,14 @@
         abort(); \
     }
 
-#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \
+#define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2) \
+    if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \
+        error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
+	      "not the expected type {1:d} or {2:d}", type, wanted_type1, wanted_type2); \
+        abort(); \
+    }
+
+#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3)	\
     if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \
         error(errInternal, 0, "Call to Object where the object was type {0:d}, " \
 	      "not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \
@@ -181,6 +188,7 @@ public:
   GBool isEOF() { return type == objEOF; }
   GBool isNone() { return type == objNone; }
   GBool isInt64() { return type == objInt64; }
+  GBool isIntOrInt64() { return type == objInt || type == objInt64; }
 
   // Special type checking.
   GBool isName(const char *nameA)
@@ -213,6 +221,8 @@ public:
   int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
   char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
   long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
+  long long getIntOrInt64() { OBJECT_2TYPES_CHECK(objInt, objInt64);
+    return type == objInt ? intg : int64g; }
 
   // Array accessors.
   int arrayGetLength();
commit e5104973197c63c3a46e6d2c0f41c9de111d4686
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Fri Jan 8 17:02:35 2016 +1030

    Improve robustness of SignatureHandler::validateCertificate

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index e5ad4f8..f299b7e 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -228,14 +228,15 @@ NSSCMSVerificationStatus SignatureHandler::validateSignature()
   if ((NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == NULL)
     CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
 
-  if (CMSSignedData->contentInfo.content.data != NULL)
+  SECItem * content_info_data = CMSSignedData->contentInfo.content.data;
+  if (content_info_data != NULL && content_info_data->data != NULL)
   {
     /*
       This means it's not a detached type signature
       so the digest is contained in SignedData->contentInfo
     */
-    if(memcmp(digest.data, CMSSignedData->contentInfo.content.data->data, hash_length) == 0
-        && digest.len == CMSSignedData->contentInfo.content.data->len)
+    if (memcmp(digest.data, content_info_data->data, hash_length) == 0
+        && digest.len == content_info_data->len)
     {
       PORT_Free(digest_buffer);
       return NSSCMSVS_GoodSignature;
@@ -276,15 +277,10 @@ SECErrorCodes SignatureHandler::validateCertificate()
   inParams[0].value.pointer.revocation = CERT_GetClassicOCSPEnabledSoftFailurePolicy();
   inParams[1].type = cert_pi_end;
 
-  if (CERT_PKIXVerifyCert(cert, certificateUsageEmailSigner, inParams, NULL, 
-                CMSSignerInfo->cmsg->pwfn_arg) != SECSuccess) {
-    retVal = (SECErrorCodes) PORT_GetError();
-  } else {
-    // PORT_GetError() will return 0 if everything was fine, 
-    // there are other possible outcomes even if the previous return was SECSuccess.
-    retVal = (SECErrorCodes) PORT_GetError();
-  }
+  CERT_PKIXVerifyCert(cert, certificateUsageEmailSigner, inParams, NULL,
+                CMSSignerInfo->cmsg->pwfn_arg);
 
+  retVal = (SECErrorCodes) PORT_GetError();
 
   if (cert)
     CERT_DestroyCertificate(cert);
commit 4b0f6e5ec04058d12fbf7537c80b662cbea931b9
Author: Markus Kilås <digital at markuspage.com>
Date:   Wed Jan 6 23:36:17 2016 +0100

    Fix printf for unsigned int

diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
index 6762c37..2190fea 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -7,6 +7,7 @@
 // Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright 2015 André Esser <bepandre at hotmail.com>
 // Copyright 2015 Albert Astals Cid <aacid at kde.org>
+// Copyright 2016 Markus Kilås <digital at markuspage.com>
 //
 //========================================================================
 
@@ -154,7 +155,7 @@ int main(int argc, char *argv[])
 
   for (unsigned int i = 0; i < sigCount; i++) {
     sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false);
-    printf("Signature #%d:\n", i+1);
+    printf("Signature #%u:\n", i+1);
     printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
     printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
     printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
commit 8859cebef5bb5308757505c8f2c8ca9fc12e154d
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sat Oct 31 08:04:51 2015 +1030

    gitignore

diff --git a/utils/.gitignore b/utils/.gitignore
index 093d3cf..e3e3e59 100644
--- a/utils/.gitignore
+++ b/utils/.gitignore
@@ -15,3 +15,4 @@ pdftops
 pdftotext
 pdftocairo
 pdfdetach
+pdfsig
commit 946eb417e6da11491f6409669119254c769b6945
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Thu Oct 29 21:59:06 2015 +1030

    man pages: remove final comma in see also list

diff --git a/utils/pdfdetach.1 b/utils/pdfdetach.1
index ff71431..525173e 100644
--- a/utils/pdfdetach.1
+++ b/utils/pdfdetach.1
@@ -86,4 +86,4 @@ Cog, LLC.
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdffonts.1 b/utils/pdffonts.1
index b44600c..810d953 100644
--- a/utils/pdffonts.1
+++ b/utils/pdffonts.1
@@ -119,4 +119,4 @@ The pdffonts software and documentation are copyright 1996-2011 Glyph
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdfimages.1 b/utils/pdfimages.1
index c10e331..166570d 100644
--- a/utils/pdfimages.1
+++ b/utils/pdfimages.1
@@ -260,4 +260,4 @@ The pdfimages software and documentation are copyright 1998-2011 Glyph
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdfinfo.1 b/utils/pdfinfo.1
index c82e9bd..af960b0 100644
--- a/utils/pdfinfo.1
+++ b/utils/pdfinfo.1
@@ -152,4 +152,4 @@ Cog, LLC.
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdfseparate.1 b/utils/pdfseparate.1
index 8b2a054..856f345 100644
--- a/utils/pdfseparate.1
+++ b/utils/pdfseparate.1
@@ -56,4 +56,4 @@ The pdfseparate software and documentation are copyright 1996-2004 Glyph
 .BR pdftops (1),
 .BR pdftotext (1)
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdfsig.1 b/utils/pdfsig.1
index 6e7c540..8029ff0 100644
--- a/utils/pdfsig.1
+++ b/utils/pdfsig.1
@@ -44,4 +44,4 @@ and copyright 2005-2015 The Poppler Developers - http://poppler.freedesktop.org
 .BR pdftops (1),
 .BR pdftotext (1)
 .BR pdfseparate (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index ac112e5..9adf434 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -295,4 +295,4 @@ The pdftocairo software and documentation are copyright 1996-2004 Glyph
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdftohtml.1 b/utils/pdftohtml.1
index 76ded91..5de4288 100644
--- a/utils/pdftohtml.1
+++ b/utils/pdftohtml.1
@@ -107,4 +107,4 @@ for the Debian GNU/Linux system (but may be used by others).
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdftoppm.1 b/utils/pdftoppm.1
index e30174b..e16ca7d 100644
--- a/utils/pdftoppm.1
+++ b/utils/pdftoppm.1
@@ -170,4 +170,4 @@ The pdftoppm software and documentation are copyright 1996-2011 Glyph
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdftops.1 b/utils/pdftops.1
index 2154773..6907b82 100644
--- a/utils/pdftops.1
+++ b/utils/pdftops.1
@@ -234,4 +234,4 @@ Cog, LLC.
 .BR pdftotext (1)
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdftotext.1 b/utils/pdftotext.1
index 4fe4848..b42aaa5 100644
--- a/utils/pdftotext.1
+++ b/utils/pdftotext.1
@@ -141,4 +141,4 @@ The pdftotext software and documentation are copyright 1996-2011 Glyph
 .BR pdftops (1),
 .BR pdfseparate (1),
 .BR pdfsig (1),
-.BR pdfunite (1),
+.BR pdfunite (1)
diff --git a/utils/pdfunite.1 b/utils/pdfunite.1
index d00b4cd..880d730 100644
--- a/utils/pdfunite.1
+++ b/utils/pdfunite.1
@@ -40,4 +40,4 @@ and copyright 2005-2011 The Poppler Developers - http://poppler.freedesktop.org
 .BR pdftops (1),
 .BR pdftotext (1)
 .BR pdfseparate (1),
-.BR pdfsig (1),
+.BR pdfsig (1)
commit 1c66076bac768774e8b2b514bc0c555bc0395348
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Thu Oct 29 21:55:46 2015 +1030

    pdfsig: update man page

diff --git a/utils/pdfsig.1 b/utils/pdfsig.1
index 5f9894e..6e7c540 100644
--- a/utils/pdfsig.1
+++ b/utils/pdfsig.1
@@ -1,16 +1,17 @@
 .\" Copyright 2011 The Poppler Developers - http://poppler.freedesktop.org
 .TH pdfsig 1 "28 October 2015"
 .SH NAME
-pdfsig \- Portable Document Format (PDF) digitial signatures tool
+pdfsig \- Portable Document Format (PDF) digital signatures tool
 .SH SYNOPSIS
 .B pdfsig
 [options]
 .RI [ PDF-file ]
 .SH DESCRIPTION
 .B pdfsig
-verifies the digital signature in a PDF document.
+verifies the digital signatures in a PDF document.
+It also displays the identity of each signer (commonName field of the signer certificate) and the time and date of the signature.
 .PP
-Certificates are searched for in the following locations:
+The signer certificate validation uses the trusted certificates stored in the following locations:
 .IP \(bu
 The NSS Certificate database in the default Firefox profile.
 .IP \(bu
commit 298caa2fc52cf50e92e1afda39b77b11f2de9743
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Oct 28 20:54:43 2015 +1030

    Add pdfsig reference (and other missing utils) to man pages

diff --git a/utils/pdfdetach.1 b/utils/pdfdetach.1
index 2bba58b..ff71431 100644
--- a/utils/pdfdetach.1
+++ b/utils/pdfdetach.1
@@ -76,11 +76,14 @@ Other error.
 The pdfinfo software and documentation are copyright 1996-2011 Glyph &
 Cog, LLC.
 .SH "SEE ALSO"
-.BR pdfimages (1),
 .BR pdffonts (1),
+.BR pdfimages (1),
 .BR pdfinfo (1),
 .BR pdftocairo (1),
 .BR pdftohtml (1),
 .BR pdftoppm (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdffonts.1 b/utils/pdffonts.1
index 4afc395..b44600c 100644
--- a/utils/pdffonts.1
+++ b/utils/pdffonts.1
@@ -117,3 +117,6 @@ The pdffonts software and documentation are copyright 1996-2011 Glyph
 .BR pdftoppm (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdfimages.1 b/utils/pdfimages.1
index 8485f3d..c10e331 100644
--- a/utils/pdfimages.1
+++ b/utils/pdfimages.1
@@ -250,7 +250,7 @@ Other error.
 The pdfimages software and documentation are copyright 1998-2011 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
-.BR pdfdetach (1)
+.BR pdfdetach (1),
 .BR pdffonts (1),
 .BR pdfinfo (1),
 .BR pdftocairo (1),
@@ -258,3 +258,6 @@ The pdfimages software and documentation are copyright 1998-2011 Glyph
 .BR pdftoppm (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdfinfo.1 b/utils/pdfinfo.1
index 1dd7466..c82e9bd 100644
--- a/utils/pdfinfo.1
+++ b/utils/pdfinfo.1
@@ -150,3 +150,6 @@ Cog, LLC.
 .BR pdftoppm (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdfseparate.1 b/utils/pdfseparate.1
index 07779a1..8b2a054 100644
--- a/utils/pdfseparate.1
+++ b/utils/pdfseparate.1
@@ -46,4 +46,14 @@ sample-1.pdf, sample-2.pdf, sample-3.pdf
 The pdfseparate software and documentation are copyright 1996-2004 Glyph
 & Cog, LLC and copyright 2005-2011 The Poppler Developers - http://poppler.freedesktop.org
 .SH "SEE ALSO"
+.BR pdfdetach (1),
+.BR pdffonts (1),
+.BR pdfimages (1),
+.BR pdfinfo (1),
+.BR pdftocairo (1),
+.BR pdftohtml (1),
+.BR pdftoppm (1),
+.BR pdftops (1),
+.BR pdftotext (1)
+.BR pdfsig (1),
 .BR pdfunite (1),
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index 7575cab..ac112e5 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -293,3 +293,6 @@ The pdftocairo software and documentation are copyright 1996-2004 Glyph
 .BR pdftoppm (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdftohtml.1 b/utils/pdftohtml.1
index e179070..76ded91 100644
--- a/utils/pdftohtml.1
+++ b/utils/pdftohtml.1
@@ -105,3 +105,6 @@ for the Debian GNU/Linux system (but may be used by others).
 .BR pdftoppm (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdftoppm.1 b/utils/pdftoppm.1
index 7f88b6d..e30174b 100644
--- a/utils/pdftoppm.1
+++ b/utils/pdftoppm.1
@@ -168,3 +168,6 @@ The pdftoppm software and documentation are copyright 1996-2011 Glyph
 .BR pdftohtml (1),
 .BR pdftops (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdftops.1 b/utils/pdftops.1
index acaec99..2154773 100644
--- a/utils/pdftops.1
+++ b/utils/pdftops.1
@@ -232,3 +232,6 @@ Cog, LLC.
 .BR pdftohtml (1),
 .BR pdftoppm (1),
 .BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdftotext.1 b/utils/pdftotext.1
index b53f82f..4fe4848 100644
--- a/utils/pdftotext.1
+++ b/utils/pdftotext.1
@@ -138,4 +138,7 @@ The pdftotext software and documentation are copyright 1996-2011 Glyph
 .BR pdftocairo (1),
 .BR pdftohtml (1),
 .BR pdftoppm (1),
-.BR pdftops (1)
+.BR pdftops (1),
+.BR pdfseparate (1),
+.BR pdfsig (1),
+.BR pdfunite (1),
diff --git a/utils/pdfunite.1 b/utils/pdfunite.1
index 9b1f2e8..d00b4cd 100644
--- a/utils/pdfunite.1
+++ b/utils/pdfunite.1
@@ -30,4 +30,14 @@ merges all pages from sample1.pdf and sample2.pdf (in that order) and creates sa
 The pdfunite software and documentation are copyright 1996-2004 Glyph & Cog, LLC
 and copyright 2005-2011 The Poppler Developers - http://poppler.freedesktop.org
 .SH "SEE ALSO"
+.BR pdfdetach (1),
+.BR pdffonts (1),
+.BR pdfimages (1),
+.BR pdfinfo (1),
+.BR pdftocairo (1),
+.BR pdftohtml (1),
+.BR pdftoppm (1),
+.BR pdftops (1),
+.BR pdftotext (1)
 .BR pdfseparate (1),
+.BR pdfsig (1),
commit 5a6d6f5ec8782bb69a5805d8d8379a33aa00edec
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Oct 28 20:54:23 2015 +1030

    Add pdfsig man page

diff --git a/utils/pdfsig.1 b/utils/pdfsig.1
new file mode 100644
index 0000000..5f9894e
--- /dev/null
+++ b/utils/pdfsig.1
@@ -0,0 +1,46 @@
+.\" Copyright 2011 The Poppler Developers - http://poppler.freedesktop.org
+.TH pdfsig 1 "28 October 2015"
+.SH NAME
+pdfsig \- Portable Document Format (PDF) digitial signatures tool
+.SH SYNOPSIS
+.B pdfsig
+[options]
+.RI [ PDF-file ]
+.SH DESCRIPTION
+.B pdfsig
+verifies the digital signature in a PDF document.
+.PP
+Certificates are searched for in the following locations:
+.IP \(bu
+The NSS Certificate database in the default Firefox profile.
+.IP \(bu
+The NSS Certificate database in /etc/pki/nssdb.
+.SH OPTIONS
+.TP
+.B \-nocert
+Do not validate the certificate.
+.TP
+.B \-v
+Print copyright and version information.
+.TP
+.B \-h
+Print usage information.
+.RB ( \-help
+and
+.B \-\-help
+are equivalent.)
+.SH AUTHOR
+The pdfsig software and documentation are copyright 1996-2004 Glyph & Cog, LLC
+and copyright 2005-2015 The Poppler Developers - http://poppler.freedesktop.org
+.SH "SEE ALSO"
+.BR pdfdetach (1),
+.BR pdffonts (1),
+.BR pdfimages (1),
+.BR pdfinfo (1),
+.BR pdftocairo (1),
+.BR pdftohtml (1),
+.BR pdftoppm (1),
+.BR pdftops (1),
+.BR pdftotext (1)
+.BR pdfseparate (1),
+.BR pdfunite (1),
commit 1f8e1a029773cefe0c31357c1e450cc4ecd5a5b5
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Oct 28 19:38:14 2015 +1030

    pdfsig: rename -c to -nocert
    
    and make help options consistent with other tools (add -? and list
    help options last)

diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
index 88abcdc..6762c37 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -89,14 +89,17 @@ static GBool printHelp = gFalse;
 static GBool dontVerifyCert = gFalse;
 
 static const ArgDesc argDesc[] = {
+  {"-nocert", argFlag,     &dontVerifyCert,     0,
+   "don't perform certificate validation"},
+
   {"-v",      argFlag,     &printVersion,  0,
    "print copyright and version info"},
   {"-h",      argFlag,     &printHelp,     0,
    "print usage information"},
   {"-help",   argFlag,     &printHelp,     0,
    "print usage information"},
-  {"-c",      argFlag,     &dontVerifyCert,     0,
-   "don't perform certificate validation"},
+  {"-?",      argFlag,     &printHelp,     0,
+   "print usage information"},
   {NULL}
 };
 
commit 9d5bf425bd82dda303362380c488559be0007d78
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Wed Oct 28 19:34:26 2015 +1030

    rename pdfsigverify to pdfsig

diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 8155cb2..af81161 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -90,13 +90,13 @@ install(TARGETS pdfinfo DESTINATION bin)
 install(FILES pdfinfo.1 DESTINATION ${SHARE_INSTALL_DIR}/man/man1)
 
 if (ENABLE_NSS3)
-  # pdfsigverify
-  set(pdfsigverify_SOURCES ${common_srcs}
-    pdfsigverify.cc
+  # pdfsig
+  set(pdfsig_SOURCES ${common_srcs}
+    pdfsig.cc
   )
-  add_executable(pdfsigverify ${pdfsigverify_SOURCES})
-  target_link_libraries(pdfsigverify ${common_libs})
-  install(TARGETS pdfsigverify DESTINATION bin)
+  add_executable(pdfsig ${pdfsig_SOURCES})
+  target_link_libraries(pdfsig ${common_libs})
+  install(TARGETS pdfsig DESTINATION bin)
 endif (ENABLE_NSS3)
 
 # pdftops
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 2ddcca0..8ea0b85 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -26,7 +26,7 @@ bin_PROGRAMS =					\
 	pdfunite
 
 if BUILD_NSS
-bin_PROGRAMS += pdfsigverify
+bin_PROGRAMS += pdfsig
 endif
 
 if BUILD_SPLASH_OUTPUT
@@ -64,8 +64,8 @@ pdfdetach_SOURCES =				\
 pdffonts_SOURCES =				\
 	pdffonts.cc
 
-pdfsigverify_SOURCES =				\
-	pdfsigverify.cc
+pdfsig_SOURCES =				\
+	pdfsig.cc
 
 pdfimages_SOURCES =				\
 	pdfimages.cc				\
diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
new file mode 100644
index 0000000..88abcdc
--- /dev/null
+++ b/utils/pdfsig.cc
@@ -0,0 +1,173 @@
+//========================================================================
+//
+// pdfsig.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+// Copyright 2015 Albert Astals Cid <aacid at kde.org>
+//
+//========================================================================
+
+#include "config.h"
+#include <poppler-config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include "parseargs.h"
+#include "Object.h"
+#include "Array.h"
+#include "Page.h"
+#include "PDFDoc.h"
+#include "PDFDocFactory.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "SignatureInfo.h"
+
+
+const char * getReadableSigState(SignatureValidationStatus sig_vs)
+{
+  switch(sig_vs) {
+    case SIGNATURE_VALID:
+      return "Signature is Valid.";
+
+    case SIGNATURE_INVALID:
+      return "Signature is Invalid.";
+
+    case SIGNATURE_DIGEST_MISMATCH:
+      return "Digest Mismatch.";
+
+    case SIGNATURE_DECODING_ERROR:
+      return "Document isn't signed or corrupted data.";
+
+    case SIGNATURE_NOT_VERIFIED:
+      return "Signature has not yet been verified.";
+
+    default:
+      return "Unknown Validation Failure.";
+  }
+}
+
+const char * getReadableCertState(CertificateValidationStatus cert_vs)
+{
+  switch(cert_vs) {
+    case CERTIFICATE_TRUSTED:
+      return "Certificate is Trusted.";
+
+    case CERTIFICATE_UNTRUSTED_ISSUER:
+      return "Certificate issuer isn't Trusted.";
+
+    case CERTIFICATE_UNKNOWN_ISSUER:
+      return "Certificate issuer is unknown.";
+
+    case CERTIFICATE_REVOKED:
+      return "Certificate has been Revoked.";
+
+    case CERTIFICATE_EXPIRED:
+      return "Certificate has Expired";
+
+    case CERTIFICATE_NOT_VERIFIED:
+      return "Certificate has not yet been verified.";
+
+    default:
+      return "Unknown issue with Certificate or corrupted data.";
+  }
+}
+
+char *getReadableTime(time_t unix_time)
+{
+  char * time_str = (char *) gmalloc(64);
+  strftime(time_str, 64, "%b %d %Y %H:%M:%S", localtime(&unix_time));
+  return time_str;
+}
+
+static GBool printVersion = gFalse;
+static GBool printHelp = gFalse;
+static GBool dontVerifyCert = gFalse;
+
+static const ArgDesc argDesc[] = {
+  {"-v",      argFlag,     &printVersion,  0,
+   "print copyright and version info"},
+  {"-h",      argFlag,     &printHelp,     0,
+   "print usage information"},
+  {"-help",   argFlag,     &printHelp,     0,
+   "print usage information"},
+  {"-c",      argFlag,     &dontVerifyCert,     0,
+   "don't perform certificate validation"},
+  {NULL}
+};
+
+
+int main(int argc, char *argv[])
+{
+  PDFDoc *doc = NULL;
+  unsigned int sigCount;
+  GooString * fileName = NULL;
+  SignatureInfo *sig_info = NULL;
+  char *time_str = NULL;
+  std::vector<FormWidgetSignature*> sig_widgets;
+  globalParams = new GlobalParams();
+
+  int exitCode = 99;
+  GBool ok;
+
+  ok = parseArgs(argDesc, &argc, argv);
+
+  if (!ok || argc != 2 || printVersion || printHelp) {
+    fprintf(stderr, "pdfsig version %s\n", PACKAGE_VERSION);
+    fprintf(stderr, "%s\n", popplerCopyright);
+    fprintf(stderr, "%s\n", xpdfCopyright);
+    if (!printVersion) {
+      printUsage("pdfsig", "<PDF-file>", argDesc);
+    }
+    if (printVersion || printHelp)
+      exitCode = 0;
+    goto end;
+  }
+
+  fileName = new GooString(argv[argc - 1]);
+
+  // open PDF file
+  doc = PDFDocFactory().createPDFDoc(*fileName, NULL, NULL);
+
+  if (!doc->isOk()) {
+    exitCode = 1;
+    goto end;
+  }
+
+  sig_widgets = doc->getSignatureWidgets();
+  sigCount = sig_widgets.size();
+
+  if (sigCount >= 1) {
+    printf("Digital Signature Info of: %s\n", fileName->getCString());
+  } else {
+    printf("File '%s' does not contain any signatures\n", fileName->getCString());
+    exitCode = 2;
+    goto end;
+  }
+
+  for (unsigned int i = 0; i < sigCount; i++) {
+    sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false);
+    printf("Signature #%d:\n", i+1);
+    printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
+    printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
+    printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
+    gfree(time_str);
+    if (sig_info->getSignatureValStatus() != SIGNATURE_VALID || dontVerifyCert) {
+      continue;
+    }
+    printf("  - Certificate Validation: %s\n", getReadableCertState(sig_info->getCertificateValStatus()));
+  }
+
+  exitCode = 0;
+
+end:
+  delete globalParams;
+  delete fileName;
+  delete doc;
+
+  return exitCode;
+}
diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
deleted file mode 100644
index a9a801d..0000000
--- a/utils/pdfsigverify.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-//========================================================================
-//
-// pdfsigverify.cc
-//
-// This file is licensed under the GPLv2 or later
-//
-// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
-// Copyright 2015 André Esser <bepandre at hotmail.com>
-// Copyright 2015 Albert Astals Cid <aacid at kde.org>
-//
-//========================================================================
-
-#include "config.h"
-#include <poppler-config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <time.h>
-#include "parseargs.h"
-#include "Object.h"
-#include "Array.h"
-#include "Page.h"
-#include "PDFDoc.h"
-#include "PDFDocFactory.h"
-#include "Error.h"
-#include "GlobalParams.h"
-#include "SignatureInfo.h"
-
-
-const char * getReadableSigState(SignatureValidationStatus sig_vs)
-{
-  switch(sig_vs) {
-    case SIGNATURE_VALID:
-      return "Signature is Valid.";
-
-    case SIGNATURE_INVALID:
-      return "Signature is Invalid.";
-
-    case SIGNATURE_DIGEST_MISMATCH:
-      return "Digest Mismatch.";
-
-    case SIGNATURE_DECODING_ERROR:
-      return "Document isn't signed or corrupted data.";
-
-    case SIGNATURE_NOT_VERIFIED:
-      return "Signature has not yet been verified.";
-
-    default:
-      return "Unknown Validation Failure.";
-  }
-}
-
-const char * getReadableCertState(CertificateValidationStatus cert_vs)
-{
-  switch(cert_vs) {
-    case CERTIFICATE_TRUSTED:
-      return "Certificate is Trusted.";
-
-    case CERTIFICATE_UNTRUSTED_ISSUER:
-      return "Certificate issuer isn't Trusted.";
-
-    case CERTIFICATE_UNKNOWN_ISSUER:
-      return "Certificate issuer is unknown.";
-
-    case CERTIFICATE_REVOKED:
-      return "Certificate has been Revoked.";
-
-    case CERTIFICATE_EXPIRED:
-      return "Certificate has Expired";
-
-    case CERTIFICATE_NOT_VERIFIED:
-      return "Certificate has not yet been verified.";
-
-    default:
-      return "Unknown issue with Certificate or corrupted data.";
-  }
-}
-
-char *getReadableTime(time_t unix_time)
-{
-  char * time_str = (char *) gmalloc(64);
-  strftime(time_str, 64, "%b %d %Y %H:%M:%S", localtime(&unix_time));
-  return time_str;
-}
-
-static GBool printVersion = gFalse;
-static GBool printHelp = gFalse;
-static GBool dontVerifyCert = gFalse;
-
-static const ArgDesc argDesc[] = {
-  {"-v",      argFlag,     &printVersion,  0,
-   "print copyright and version info"},
-  {"-h",      argFlag,     &printHelp,     0,
-   "print usage information"},
-  {"-help",   argFlag,     &printHelp,     0,
-   "print usage information"},
-  {"-c",      argFlag,     &dontVerifyCert,     0,
-   "don't perform certificate validation"},
-  {NULL}
-};
-
-
-int main(int argc, char *argv[])
-{
-  PDFDoc *doc = NULL;
-  unsigned int sigCount;
-  GooString * fileName = NULL;
-  SignatureInfo *sig_info = NULL;
-  char *time_str = NULL;
-  std::vector<FormWidgetSignature*> sig_widgets;
-  globalParams = new GlobalParams();
-
-  int exitCode = 99;
-  GBool ok;
-
-  ok = parseArgs(argDesc, &argc, argv);
-
-  if (!ok || argc != 2 || printVersion || printHelp) {
-    fprintf(stderr, "pdfsigverify version %s\n", PACKAGE_VERSION);
-    fprintf(stderr, "%s\n", popplerCopyright);
-    fprintf(stderr, "%s\n", xpdfCopyright);
-    if (!printVersion) {
-      printUsage("pdfsigverify", "<PDF-file>", argDesc);
-    }
-    if (printVersion || printHelp)
-      exitCode = 0;
-    goto end;
-  }
-
-  fileName = new GooString(argv[argc - 1]);
-
-  // open PDF file
-  doc = PDFDocFactory().createPDFDoc(*fileName, NULL, NULL);
-
-  if (!doc->isOk()) {
-    exitCode = 1;
-    goto end;
-  }
-
-  sig_widgets = doc->getSignatureWidgets();
-  sigCount = sig_widgets.size();
-
-  if (sigCount >= 1) {
-    printf("Digital Signature Info of: %s\n", fileName->getCString());
-  } else {
-    printf("File '%s' does not contain any signatures\n", fileName->getCString());
-    exitCode = 2;
-    goto end;
-  }
-
-  for (unsigned int i = 0; i < sigCount; i++) {
-    sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false);
-    printf("Signature #%d:\n", i+1);
-    printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
-    printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
-    printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
-    gfree(time_str);
-    if (sig_info->getSignatureValStatus() != SIGNATURE_VALID || dontVerifyCert) {
-      continue;
-    }
-    printf("  - Certificate Validation: %s\n", getReadableCertState(sig_info->getCertificateValStatus()));
-  }
-
-  exitCode = 0;
-
-end:
-  delete globalParams;
-  delete fileName;
-  delete doc;
-
-  return exitCode;
-}
commit 1d97f708ceb7cd34ccdb1a4f85192efe83d1853c
Author: Albert Astals Cid <aacid at kde.org>
Date:   Tue Oct 27 22:27:31 2015 +0100

    Differentiate between unknown and untrusted issuer

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index bd1ed45..e5ad4f8 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -323,8 +323,10 @@ CertificateValidationStatus SignatureHandler::NSS_CertTranslate(SECErrorCodes ns
   switch(nss_code)
   {
     case SEC_ERROR_UNKNOWN_ISSUER:
+      return CERTIFICATE_UNKNOWN_ISSUER;
+
     case SEC_ERROR_UNTRUSTED_ISSUER:
-      return CERTIFICATE_UNTRUSTED;
+      return CERTIFICATE_UNTRUSTED_ISSUER;
 
     case SEC_ERROR_REVOKED_CERTIFICATE:
       return CERTIFICATE_REVOKED;
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
index 1843aeb..82b4ec4 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -6,6 +6,7 @@
 //
 // Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright 2015 André Esser <bepandre at hotmail.com>
+// Copyright 2015 Albert Astals Cid <aacid at kde.org>
 //
 //========================================================================
 
@@ -28,7 +29,8 @@ enum SignatureValidationStatus
 enum CertificateValidationStatus
 {
   CERTIFICATE_TRUSTED,
-  CERTIFICATE_UNTRUSTED,
+  CERTIFICATE_UNTRUSTED_ISSUER,
+  CERTIFICATE_UNKNOWN_ISSUER,
   CERTIFICATE_REVOKED,
   CERTIFICATE_EXPIRED,
   CERTIFICATE_GENERIC_ERROR,
diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
index fb636bc..a9a801d 100644
--- a/utils/pdfsigverify.cc
+++ b/utils/pdfsigverify.cc
@@ -57,8 +57,11 @@ const char * getReadableCertState(CertificateValidationStatus cert_vs)
     case CERTIFICATE_TRUSTED:
       return "Certificate is Trusted.";
 
-    case CERTIFICATE_UNTRUSTED:
-      return "Certificate isn't Trusted.";
+    case CERTIFICATE_UNTRUSTED_ISSUER:
+      return "Certificate issuer isn't Trusted.";
+
+    case CERTIFICATE_UNKNOWN_ISSUER:
+      return "Certificate issuer is unknown.";
 
     case CERTIFICATE_REVOKED:
       return "Certificate has been Revoked.";
commit 19e20dc69a631f92bf4fdc0be0dd840a460cfc92
Author: Markus Kilås <digital at markuspage.com>
Date:   Tue Oct 27 22:23:06 2015 +0100

    Handle untrusted issuer

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 10caed7..bd1ed45 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -7,6 +7,7 @@
 // Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright 2015 André Esser <bepandre at hotmail.com>
 // Copyright 2015 Albert Astals Cid <aacid at kde.org>
+// Copyright 2015 Markus Kilås <digital at markuspage.com>
 //
 //========================================================================
 
@@ -322,6 +323,7 @@ CertificateValidationStatus SignatureHandler::NSS_CertTranslate(SECErrorCodes ns
   switch(nss_code)
   {
     case SEC_ERROR_UNKNOWN_ISSUER:
+    case SEC_ERROR_UNTRUSTED_ISSUER:
       return CERTIFICATE_UNTRUSTED;
 
     case SEC_ERROR_REVOKED_CERTIFICATE:
commit 02d3564faa5d8174ed93ce66fcda975b1a898ec5
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Wed Oct 14 22:50:05 2015 +0200

    Incremental hashing + large file support for digital signatures

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 42ef2c1..d94757a 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1435,6 +1435,32 @@ void FormFieldSignature::parseInfo()
   sig_dict.free();
 }
 
+void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset block_len)
+{
+  const int BLOCK_SIZE = 4096;
+  unsigned char signed_data_buffer[BLOCK_SIZE];
+
+  Goffset i = 0;
+  while(i < block_len)
+  {
+    Goffset bytes_left = block_len - i;
+    if (bytes_left < BLOCK_SIZE)
+    {
+      doc->getBaseStream()->doGetChars(bytes_left, signed_data_buffer);
+      handler->updateHash(signed_data_buffer, bytes_left);
+      i = block_len;
+    }
+    else
+    {
+      doc->getBaseStream()->doGetChars(BLOCK_SIZE, signed_data_buffer);
+      handler->updateHash(signed_data_buffer, BLOCK_SIZE);
+      i += BLOCK_SIZE;
+    }
+  }
+
+}
+
+
 SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
 {
 #ifdef ENABLE_NSS3
@@ -1459,32 +1485,38 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
   byte_range.arrayGet(2, &r3);
   byte_range.arrayGet(3, &r4);
 
-  unsigned int signed_data_len = 0;
-
   Goffset fileLength = doc->getBaseStream()->getLength();
+  Goffset r_values[3];
+
+  r_values[0] = r2.isInt64() ? r2.getInt64() : r2.getInt();
+  r_values[1] = r3.isInt64() ? r3.getInt64() : r3.getInt();
+  r_values[2] = r4.isInt64() ? r4.getInt64() : r4.getInt();
 
-  if (r2.getInt() <= 0 || r3.getInt() <= 0 || r4.getInt() <= 0 || r3.getInt() <= r2.getInt() ||
-    r3.getInt() + r4.getInt() > fileLength)
+  if (r_values[0] <= 0 || r_values[1] <= 0 || r_values[2] <= 0 || r_values[1] <= r_values[0] ||
+    r_values[1] + r_values[2] > fileLength)
   {
       error(errSyntaxError, 0, "Illegal values in ByteRange array");
       return signature_info;
   }
 
-  signed_data_len = r2.getInt() + r4.getInt();
-  unsigned char *to_check = (unsigned char *)gmalloc(signed_data_len);
-
-  //Read the 2 slices of data that are signed
-  doc->getBaseStream()->setPos(0);
-  doc->getBaseStream()->doGetChars(r2.getInt(), to_check);
-  doc->getBaseStream()->setPos(r3.getInt());
-  doc->getBaseStream()->doGetChars(r4.getInt(), to_check+r2.getInt());
-
   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);
 
-  sig_val_state = signature_handler.validateSignature(to_check, signed_data_len);
+  //Read the 2 slices of data that are signed
+  doc->getBaseStream()->setPos(0);
+  Goffset block_len = r_values[0];
+
+  hashSignedDataBlock(&signature_handler, block_len);
+
+  doc->getBaseStream()->setPos(r_values[1]);
+  block_len = r_values[2];
+
+  hashSignedDataBlock(&signature_handler, block_len);
+
+  sig_val_state = signature_handler.validateSignature();
   signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
   signature_info->setSignerName(signature_handler.getSignerName());
 
@@ -1493,8 +1525,6 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
     signature_info->setSigningTime(signature_handler.getSigningTime());
   }
 
-  free(to_check);
-
   if (sig_val_state != NSSCMSVS_GoodSignature || !doVerifyCert) {
     return signature_info;
   }
@@ -1504,6 +1534,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
 
 #endif
   return signature_info;
+
 }
 
 #ifdef DEBUG_FORMS
diff --git a/poppler/Form.h b/poppler/Form.h
index ff4dc1e..b566fe0 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -500,6 +500,7 @@ public:
 
 private:
   void parseInfo();
+  void hashSignedDataBlock(SignatureHandler *handler, Goffset block_len);
   Object byte_range;
   GooString *signature;
   SignatureInfo *signature_info;
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 357bac4..10caed7 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -18,14 +18,6 @@
 #include <dirent.h>
 #include <Error.h>
 
-void SignatureHandler::digestFile(unsigned char *digest_buffer, unsigned char *input_data, int input_data_len, SECOidTag hashOIDTag)
-{
-  HASH_HashType hashType;
-  hashType    = HASH_GetHashTypeByOidTag(hashOIDTag);
-  HASH_HashBuf(hashType, digest_buffer, input_data, input_data_len);
-
-}
-
 unsigned int SignatureHandler::digestLength(SECOidTag digestAlgId)
 {
   switch(digestAlgId){
@@ -119,8 +111,23 @@ SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length)
   CMSMessage = CMS_MessageCreate(&CMSitem);
   CMSSignedData = CMS_SignedDataCreate(CMSMessage);
   CMSSignerInfo = CMS_SignerInfoCreate(CMSSignedData);
+  hash_context = initHashContext();
+}
+
+HASHContext * SignatureHandler::initHashContext()
+{
+
+  SECItem usedAlgorithm = NSS_CMSSignedData_GetDigestAlgs(CMSSignedData)[0]->algorithm;
+  hash_length = digestLength(SECOID_FindOIDTag(&usedAlgorithm));
+  HASH_HashType hashType;
+  hashType    = HASH_GetHashTypeByOidTag(SECOID_FindOIDTag(&usedAlgorithm));
+  return HASH_Create(hashType);
 }
 
+void SignatureHandler::updateHash(unsigned char * data_block, int data_len)
+{
+  HASH_Update(hash_context, data_block, data_len);
+}
 
 SignatureHandler::~SignatureHandler()
 {
@@ -132,6 +139,9 @@ SignatureHandler::~SignatureHandler()
   if (CMSMessage)
     NSS_CMSMessage_Destroy(CMSMessage);
 
+  if (hash_context)
+    HASH_Destroy(hash_context);
+
   free(temp_certs);
 
   if (NSS_Shutdown()!=SECSuccess)
@@ -198,19 +208,17 @@ NSSCMSSignerInfo *SignatureHandler::CMS_SignerInfoCreate(NSSCMSSignedData * cms_
   }
 }
 
-NSSCMSVerificationStatus SignatureHandler::validateSignature(unsigned char *signed_data, int signed_data_len)
+NSSCMSVerificationStatus SignatureHandler::validateSignature()
 {
   unsigned char *digest_buffer = NULL;
 
   if (!CMSSignedData)
     return NSSCMSVS_MalformedSignature;
 
-  SECItem usedAlgorithm = NSS_CMSSignedData_GetDigestAlgs(CMSSignedData)[0]->algorithm;
-  unsigned int hash_length = digestLength(SECOID_FindOIDTag(&usedAlgorithm));
-
   digest_buffer = (unsigned char *)PORT_Alloc(hash_length);
+  unsigned int result_len = 0;
 
-  digestFile(digest_buffer, signed_data, signed_data_len, SECOID_FindOIDTag(&usedAlgorithm));
+  HASH_End(hash_context, digest_buffer, &result_len, hash_length);
 
   SECItem digest;
   digest.data = digest_buffer;
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index 7946d25..e6ace24 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -41,8 +41,10 @@ public:
   time_t getSigningTime();
   char * getSignerName();
   void setSignature(unsigned char *, int);
-  NSSCMSVerificationStatus validateSignature(unsigned char *signed_data, int signed_data_len);
+  void updateHash(unsigned char * data_block, int data_len);
+  NSSCMSVerificationStatus validateSignature();
   SECErrorCodes validateCertificate();
+
   //Translate NSS error codes
   static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code);
   static CertificateValidationStatus NSS_CertTranslate(SECErrorCodes nss_code);
@@ -52,14 +54,17 @@ private:
   SignatureHandler& operator=(const SignatureHandler &);
 
   void init_nss();
+
   GooString * getDefaultFirefoxCertDB_Linux();
   unsigned int digestLength(SECOidTag digestAlgId);
   NSSCMSMessage *CMS_MessageCreate(SECItem * cms_item);
   NSSCMSSignedData *CMS_SignedDataCreate(NSSCMSMessage * cms_msg);
   NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data);
-  void digestFile(unsigned char *digest_buffer, unsigned char *input_data, int input_data_len, SECOidTag hashOIDTag);
+  HASHContext * initHashContext();
 
+  unsigned int hash_length;
   SECItem CMSitem;
+  HASHContext *hash_context;
   NSSCMSMessage *CMSMessage;
   NSSCMSSignedData *CMSSignedData;
   NSSCMSSignerInfo *CMSSignerInfo;
commit 5570c70a20ae62a9b3341372fafc64e916774adb
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Mon Oct 5 16:50:30 2015 +0200

    NSS conditional build

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ce16d53..ca71630 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,7 +105,7 @@ endif(WITH_FONTCONFIGURATION_FONTCONFIG)
 macro_optional_find_package(JPEG)
 macro_optional_find_package(PNG)
 macro_optional_find_package(TIFF)
-find_package(NSS3 REQUIRED)
+macro_optional_find_package(NSS3)
 if(JPEG_FOUND)
   set(ENABLE_LIBJPEG ${JPEG_FOUND})
 endif(JPEG_FOUND)
@@ -203,8 +203,6 @@ if(ENABLE_LIBCURL)
   set(POPPLER_HAS_CURL_SUPPORT ON)
 endif(ENABLE_LIBCURL)
 
-add_definitions(${NSS3_CFLAGS})
-
 add_definitions(-DHAVE_CONFIG_H=1)
 if(MINGW)
   # Use mingw's ansi stdio extensions
@@ -237,6 +235,11 @@ endif(CMAKE_USE_PTHREADS_INIT)
 if(ENABLE_ZLIB)
   include_directories(${ZLIB_INCLUDE_DIR})
 endif(ENABLE_ZLIB)
+
+if (NSS3_FOUND)
+  add_definitions(${NSS3_CFLAGS})
+  set(ENABLE_NSS3 ON)
+endif(NSS3_FOUND)
 if(JPEG_FOUND)
   include_directories(${JPEG_INCLUDE_DIR})
   set(ENABLE_LIBJPEG ON)
@@ -367,7 +370,6 @@ set(poppler_SRCS
   poppler/ProfileData.cc
   poppler/PreScanOutputDev.cc
   poppler/PSTokenizer.cc
-  poppler/SignatureHandler.cc
   poppler/SignatureInfo.cc
   poppler/Stream.cc
   poppler/StructTreeRoot.cc
@@ -417,7 +419,7 @@ endif(ENABLE_SPLASH)
 if(FONTCONFIG_FOUND)
   set(poppler_LIBS ${poppler_LIBS} ${FONTCONFIG_LIBRARIES})
 endif(FONTCONFIG_FOUND)
-set(poppler_LIBS ${poppler_LIBS} ${NSS3_LIBRARIES})
+
 if(JPEG_FOUND)
   set(poppler_SRCS ${poppler_SRCS}
     poppler/DCTStream.cc
@@ -437,6 +439,12 @@ if(ENABLE_LIBCURL)
   )
   set(poppler_LIBS ${poppler_LIBS} ${CURL_LIBRARIES})
 endif(ENABLE_LIBCURL)
+if (ENABLE_NSS3)
+  set(poppler_SRCS ${poppler_SRCS}
+    poppler/SignatureHandler.cc
+  )
+  set(poppler_LIBS ${poppler_LIBS} ${NSS3_LIBRARIES})
+endif(ENABLE_NSS3)  
 if(LIBOPENJPEG_FOUND)
   set(poppler_SRCS ${poppler_SRCS}
     poppler/JPEG2000Stream.cc
@@ -725,6 +733,7 @@ show_end_message_yesno("use libjpeg" ENABLE_LIBJPEG)
 show_end_message_yesno("use libpng" ENABLE_LIBPNG)
 show_end_message_yesno("use libtiff" ENABLE_LIBTIFF)
 show_end_message_yesno("use zlib" ENABLE_ZLIB)
+show_end_message_yesno("use nss3" ENABLE_NSS3)
 show_end_message_yesno("use curl" ENABLE_LIBCURL)
 show_end_message_yesno("use libopenjpeg" WITH_OPENJPEG)
 if(USE_OPENJPEG1)
diff --git a/config.h.cmake b/config.h.cmake
index 400b16b..b62994f 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -21,6 +21,9 @@
 /* Use zlib instead of builtin zlib decoder. */
 #cmakedefine ENABLE_ZLIB 1
 
+/* Build against libnss3 for digital signature validation */
+#cmakedefine ENABLE_NSS3 1
+
 /* Use cairo for rendering. */
 #cmakedefine HAVE_CAIRO 1
 
diff --git a/configure.ac b/configure.ac
index 741001d..da18b23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,12 +264,29 @@ else
   enable_libopenjpeg=no
 fi
 
-PKG_CHECK_MODULES(NSS3, nss, [], [])
+dnl Test for NSS
+AC_ARG_ENABLE(libnss,
+        AC_HELP_STRING([--disable-nss],
+                       [Do not build against libnss3.]),
+              enable_libnss=$enableval,
+              enable_libnss="try")
+
+if test x$enable_libnss != xno; then
+  PKG_CHECK_MODULES(NSS3, nss, [enable_nss="yes"],
+      [enable_nss="no"])
+fi
+
+if test x$enable_nss = xyes; then
+  AC_DEFINE(ENABLE_NSS3, 1, [Build against NSS.])
+fi
 
 AM_CONDITIONAL(BUILD_LIBOPENJPEG, test x$openjpeg1 = xyes || test x$openjpeg2 = xyes)
 AH_TEMPLATE([ENABLE_LIBOPENJPEG],
 	    [Use libopenjpeg instead of builtin jpeg2000 decoder.])
 
+AM_CONDITIONAL(BUILD_NSS, test x$enable_nss = xyes)
+AH_TEMPLATE([ENABLE_NSS3], [Build Poppler against NSS for digital signature support.])
+
 dnl ##### Test for libtiff
 AC_ARG_ENABLE(libtiff,
 		AC_HELP_STRING([--disable-libtiff],
@@ -1007,6 +1024,7 @@ echo "  use libjpeg:        $enable_libjpeg"
 echo "  use libpng:         $enable_libpng"
 echo "  use libtiff:        $enable_libtiff"
 echo "  use zlib:           $enable_zlib"
+echo "  use nss             $enable_nss"
 echo "  use libcurl:        $enable_libcurl"
 echo "  use libopenjpeg:    $enable_libopenjpeg"
 if test x$enable_libopenjpeg = xyes;then
diff --git a/poppler/Form.cc b/poppler/Form.cc
index a2fd0cf..42ef2c1 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -39,7 +39,10 @@
 #include "Form.h"
 #include "PDFDoc.h"
 #include "DateInfo.h"
+#ifdef ENABLE_NSS3
 #include "SignatureHandler.h"
+#endif
+#include "SignatureInfo.h"
 #include "XRef.h"
 #include "PDFDocEncoding.h"
 #include "Annot.h"
@@ -1380,6 +1383,7 @@ FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& re
   : FormField(docA, dict, ref, parent, usedParents, formSignature)
 {
   signature = NULL;
+
   signature_info = new SignatureInfo();
   parseInfo();
 }
@@ -1433,7 +1437,7 @@ void FormFieldSignature::parseInfo()
 
 SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
 {
-
+#ifdef ENABLE_NSS3
   if (!signature_info->isSubfilterSupported()) {
     error(errUnimplemented, 0, "Unable to validate this type of signature");
     return signature_info;
@@ -1498,6 +1502,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
   cert_val_state = signature_handler.validateCertificate();
   signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state));
 
+#endif
   return signature_info;
 }
 
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index 2d8c5e6..1b6500f 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -78,6 +78,22 @@ libjpeg2000_sources =				\
 
 endif
 
+if BUILD_NSS
+
+nss_sources =                   \
+	SignatureHandler.cc
+
+nss_libs =                      \
+	$(NSS3_LIBS)
+
+nss_includes =                  \
+	$(NSS3_CFLAGS)
+
+nss_headers =
+	SignatureHandler.h
+
+endif	
+
 
 if BUILD_ZLIB
 
@@ -119,6 +135,7 @@ poppler_includedir = $(includedir)/poppler
 poppler_include_HEADERS =	\
 	$(splash_headers)	\
 	$(curl_headers)		\
+	$(nss_headers) 		\
 	Annot.h			\
 	Array.h			\
 	BuiltinFont.h		\
@@ -166,8 +183,7 @@ poppler_include_HEADERS =	\
 	PreScanOutputDev.h	\
 	PSTokenizer.h		\
 	Rendition.h		\
-	SignatureHandler.h	\
-	SignatureInfo.h	\
+	SignatureInfo.h		\
 	StdinCachedFile.h	\
 	StdinPDFDocBuilder.h	\
 	Stream-CCITT.h		\
@@ -202,6 +218,7 @@ libpoppler_la_SOURCES =		\
 	$(splash_sources)	\
 	$(libjpeg_sources)	\
 	$(zlib_sources)		\
+	$(nss_sources)      \
 	$(libjpeg2000_sources)	\
 	$(curl_sources)		\
 	Annot.cc		\
@@ -249,8 +266,7 @@ libpoppler_la_SOURCES =		\
 	PreScanOutputDev.cc \
 	PSTokenizer.cc		\
 	Rendition.cc		\
-	SignatureHandler.cc	\
-	SignatureInfo.cc \
+	SignatureInfo.cc	\
 	StdinCachedFile.cc	\
 	StdinPDFDocBuilder.cc	\
 	Stream.cc 		\
@@ -279,7 +295,7 @@ libpoppler_la_CPPFLAGS =			\
 	$(libjpeg2000_includes)			\
 	$(libpng_includes)			\
 	$(libcurl_includes)			\
-	$(NSS3_CFLAGS)				\
+	$(nss_includes)				\
 	$(FREETYPE_CFLAGS)			\
 	$(FONTCONFIG_CFLAGS)			\
 	$(AM_CPPFLAGS)
@@ -294,8 +310,8 @@ libpoppler_la_LIBADD =				\
 	$(libpng_libs)				\
 	$(zlib_libs)				\
 	$(libcurl_libs)				\
+	$(nss_libs)                 \
 	$(libjpeg2000_libs)			\
-	$(NSS3_LIBS)				\
 	$(FREETYPE_LIBS)			\
 	$(FONTCONFIG_LIBS)			\
 	$(PTHREAD_LIBS)				\
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index ea56bd2..8155cb2 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -89,13 +89,15 @@ target_link_libraries(pdfinfo ${common_libs})
 install(TARGETS pdfinfo DESTINATION bin)
 install(FILES pdfinfo.1 DESTINATION ${SHARE_INSTALL_DIR}/man/man1)
 
-# pdfsigverify
-set(pdfsigverify_SOURCES ${common_srcs}
-  pdfsigverify.cc
-)
-add_executable(pdfsigverify ${pdfsigverify_SOURCES})
-target_link_libraries(pdfsigverify ${common_libs})
-install(TARGETS pdfsigverify DESTINATION bin)
+if (ENABLE_NSS3)
+  # pdfsigverify
+  set(pdfsigverify_SOURCES ${common_srcs}
+    pdfsigverify.cc
+  )
+  add_executable(pdfsigverify ${pdfsigverify_SOURCES})
+  target_link_libraries(pdfsigverify ${common_libs})
+  install(TARGETS pdfsigverify DESTINATION bin)
+endif (ENABLE_NSS3)
 
 # pdftops
 set(pdftops_SOURCES ${common_srcs}
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 318cfb6..2ddcca0 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -23,9 +23,12 @@ bin_PROGRAMS =					\
 	pdftotext				\
 	pdftohtml				\
 	pdfseparate				\
-	pdfsigverify				\
 	pdfunite
 
+if BUILD_NSS
+bin_PROGRAMS += pdfsigverify
+endif
+
 if BUILD_SPLASH_OUTPUT
 bin_PROGRAMS += pdftoppm
 endif
commit c7c0207b1cfe49a4353d6cda93dbebef4508138f
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Mon Oct 5 15:57:04 2015 +0200

    Support for adbe.pkcs7.sha1 signatures

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 5bf3492..a2fd0cf 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1423,7 +1423,7 @@ void FormFieldSignature::parseInfo()
 
   // check if subfilter is supported for signature validation, only detached signatures work for now
   sig_dict.dictLookup("SubFilter", &subfilterName);
-  if (subfilterName.isName("adbe.pkcs7.detached")) {
+  if (subfilterName.isName("adbe.pkcs7.detached") || subfilterName.isName("adbe.pkcs7.sha1")) {
     signature_info->setSubFilterSupport(true);
   }
 
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index c741958..357bac4 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -219,10 +219,33 @@ NSSCMSVerificationStatus SignatureHandler::validateSignature(unsigned char *sign
   if ((NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == NULL)
     CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
 
-  if (NSS_CMSSignerInfo_Verify(CMSSignerInfo, &digest, NULL) != SECSuccess) {
+  if (CMSSignedData->contentInfo.content.data != NULL)
+  {
+    /*
+      This means it's not a detached type signature
+      so the digest is contained in SignedData->contentInfo
+    */
+    if(memcmp(digest.data, CMSSignedData->contentInfo.content.data->data, hash_length) == 0
+        && digest.len == CMSSignedData->contentInfo.content.data->len)
+    {
+      PORT_Free(digest_buffer);
+      return NSSCMSVS_GoodSignature;
+    }
+    else
+    {
+      PORT_Free(digest_buffer);
+      return NSSCMSVS_DigestMismatch;
+    }
+
+  }
+  else if (NSS_CMSSignerInfo_Verify(CMSSignerInfo, &digest, NULL) != SECSuccess)
+  {
+
     PORT_Free(digest_buffer);
     return CMSSignerInfo->verificationStatus;
-  } else {
+  }
+  else
+  {
     PORT_Free(digest_buffer);
     return NSSCMSVS_GoodSignature;
   }
commit 4f7903ebc037c63683637973285bc34ea83542dc
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Thu Sep 24 23:57:46 2015 +0200

    Fix for Buffer overflow

diff --git a/poppler/Form.cc b/poppler/Form.cc
index c5631dc..5bf3492 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1455,7 +1455,18 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
   byte_range.arrayGet(2, &r3);
   byte_range.arrayGet(3, &r4);
 
-  unsigned int signed_data_len = r2.getInt()+r4.getInt();
+  unsigned int signed_data_len = 0;
+
+  Goffset fileLength = doc->getBaseStream()->getLength();
+
+  if (r2.getInt() <= 0 || r3.getInt() <= 0 || r4.getInt() <= 0 || r3.getInt() <= r2.getInt() ||
+    r3.getInt() + r4.getInt() > fileLength)
+  {
+      error(errSyntaxError, 0, "Illegal values in ByteRange array");
+      return signature_info;
+  }
+
+  signed_data_len = r2.getInt() + r4.getInt();
   unsigned char *to_check = (unsigned char *)gmalloc(signed_data_len);
 
   //Read the 2 slices of data that are signed
commit 10693fb236ff92c6aa0c0a9f762362d2fd9ea738
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 20:19:00 2015 +0200

    include shuffling

diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index fad779c..5c3e6c0 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -78,8 +78,6 @@
 #endif
 #include "PDFDoc.h"
 #include "Hints.h"
-#include "DateInfo.h"
-#include "SignatureHandler.h"
 
 #if MULTITHREADED
 #  define pdfdocLocker()   MutexLocker locker(&mutex)
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 8ffaedd..0bb15c4 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -52,8 +52,6 @@
 #include "Form.h"
 #include "OptionalContent.h"
 #include "Stream.h"
-#include "poppler-config.h"
-#include "SignatureInfo.h"
 
 class GooString;
 class GooFile;
@@ -67,7 +65,6 @@ class Linearization;
 class SecurityHandler;
 class Hints;
 class StructTreeRoot;
-class SignatureHandler;
 
 enum PDFWriteMode {
   writeStandard,
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 4f62eca..c741958 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -13,7 +13,6 @@
 #include <config.h>
 
 #include "SignatureHandler.h"
-#include "goo/GooString.h"
 #include "goo/gmem.h"
 
 #include <dirent.h>
diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
index c537e64..fb636bc 100644
--- a/utils/pdfsigverify.cc
+++ b/utils/pdfsigverify.cc
@@ -25,6 +25,7 @@
 #include "PDFDocFactory.h"
 #include "Error.h"
 #include "GlobalParams.h"
+#include "SignatureInfo.h"
 
 
 const char * getReadableSigState(SignatureValidationStatus sig_vs)
commit 6e24d374987fbba0f5a133d73dfcb3e73129b534
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 19:59:09 2015 +0200

    Simplify biterange handling

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 60b865d..c5631dc 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1379,7 +1379,6 @@ GooString *FormFieldChoice::getSelectedChoice() {
 FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
   : FormField(docA, dict, ref, parent, usedParents, formSignature)
 {
-  byte_range = NULL;
   signature = NULL;
   signature_info = new SignatureInfo();
   parseInfo();
@@ -1387,10 +1386,7 @@ FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& re
 
 FormFieldSignature::~FormFieldSignature()
 {
-  if (byte_range) {
-    byte_range->free();
-    delete byte_range;
-  }
+  byte_range.free();
   delete signature_info;
   delete signature;
 }
@@ -1400,7 +1396,7 @@ void FormFieldSignature::parseInfo()
   if (!obj.isDict())
     return;
 
-  Object sig_dict, contents_obj, byterange_obj, time_of_signing, subfilterName;
+  Object sig_dict, contents_obj, time_of_signing, subfilterName;
 
   // retrieve PKCS#7
   obj.dictLookup("V", &sig_dict);
@@ -1415,11 +1411,7 @@ void FormFieldSignature::parseInfo()
   }
   contents_obj.free();
 
-  sig_dict.dictLookup("ByteRange", &byterange_obj);
-
-  if (byterange_obj.isArray()) {
-    byte_range = new Object(byterange_obj);
-  }
+  sig_dict.dictLookup("ByteRange", &byte_range);
 
   // retrieve SigningTime
   sig_dict.dictLookup("M", &time_of_signing);
@@ -1451,7 +1443,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
     return signature_info;
   }
 
-  if (byte_range == NULL || !byte_range->isArray() || signature == NULL) {
+  if (!byte_range.isArray() || signature == NULL) {
     return signature_info;
   }
 
@@ -1459,9 +1451,9 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
   NSSCMSVerificationStatus sig_val_state;
   SECErrorCodes cert_val_state;
 
-  byte_range->arrayGet(1, &r2);
-  byte_range->arrayGet(2, &r3);
-  byte_range->arrayGet(3, &r4);
+  byte_range.arrayGet(1, &r2);
+  byte_range.arrayGet(2, &r3);
+  byte_range.arrayGet(3, &r4);
 
   unsigned int signed_data_len = r2.getInt()+r4.getInt();
   unsigned char *to_check = (unsigned char *)gmalloc(signed_data_len);
diff --git a/poppler/Form.h b/poppler/Form.h
index e6c75d6..ff4dc1e 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -500,7 +500,7 @@ public:
 
 private:
   void parseInfo();
-  Object *byte_range;
+  Object byte_range;
   GooString *signature;
   SignatureInfo *signature_info;
 
commit 7afa26fc389f4b2aa67cdf286e9c4ebfb3d78de5
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 19:50:56 2015 +0200

    Disable SignatureInfo and SignatureHandler copy ctr and assignment operator

diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index 8a5532b..7946d25 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -48,6 +48,9 @@ public:
   static CertificateValidationStatus NSS_CertTranslate(SECErrorCodes nss_code);
 
 private:
+  SignatureHandler(const SignatureHandler &);
+  SignatureHandler& operator=(const SignatureHandler &);
+
   void init_nss();
   GooString * getDefaultFirefoxCertDB_Linux();
   unsigned int digestLength(SECOidTag digestAlgId);
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
index e46349c..1843aeb 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -56,6 +56,9 @@ public:
   void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; }
 
 private:
+  SignatureInfo(const SignatureInfo &);
+  SignatureInfo& operator=(const SignatureInfo &);
+
   SignatureValidationStatus sig_status;
   CertificateValidationStatus cert_status;
   char *signer_name;
commit 5348f8d080ae9f0ee58d75fd7ae2bc9f23692eca
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 19:46:23 2015 +0200

    Fix some leaks in SignatureHandler

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index f8a44b8..4f62eca 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -74,8 +74,9 @@ GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux()
   homePath = homePath->append("/.mozilla/firefox/");
 
   if ((toSearchIn = opendir(homePath->getCString())) == NULL) {
-	error(errInternal, 0, "couldn't find default Firefox Folder");
-	return NULL;
+    error(errInternal, 0, "couldn't find default Firefox Folder");
+    delete homePath;
+    return NULL;
   }
   do {
     if ((subFolder = readdir(toSearchIn)) != NULL) {
@@ -87,6 +88,7 @@ GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux()
     }
   } while (subFolder != NULL);
 
+  closedir(toSearchIn);
   return NULL;
 }
 
@@ -102,9 +104,7 @@ void SignatureHandler::init_nss()
     NSS_Init(certDBPath->getCString());
   }
 
-  if (certDBPath) {
-    delete certDBPath;
-  }
+  delete certDBPath;
 }
 
 
commit 17b3a8dc2f8ab50696dd1247c4b6dd75991ab17e
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 19:40:30 2015 +0200

    Signatures: keep Goostring and convert to uchar when needed

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 18fbca4..60b865d 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1392,6 +1392,7 @@ FormFieldSignature::~FormFieldSignature()
     delete byte_range;
   }
   delete signature_info;
+  delete signature;
 }
 
 void FormFieldSignature::parseInfo()
@@ -1410,10 +1411,7 @@ void FormFieldSignature::parseInfo()
 
   sig_dict.dictLookup("Contents", &contents_obj);
   if (contents_obj.isString()) {
-    GooString *str = contents_obj.getString();
-    signature_len = str->getLength();
-    signature = (unsigned char *)gmalloc(signature_len);
-    memcpy(signature, str->getCString(), signature_len);
+    signature = contents_obj.getString()->copy();
   }
   contents_obj.free();
 
@@ -1474,7 +1472,10 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
   doc->getBaseStream()->setPos(r3.getInt());
   doc->getBaseStream()->doGetChars(r4.getInt(), to_check+r2.getInt());
 
-  SignatureHandler signature_handler(signature, signature_len);
+  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);
 
   sig_val_state = signature_handler.validateSignature(to_check, signed_data_len);
   signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
diff --git a/poppler/Form.h b/poppler/Form.h
index c179874..e6c75d6 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -6,7 +6,7 @@
 //
 // Copyright 2006 Julien Rebetez <julienr at svn.gnome.org>
 // Copyright 2007, 2008, 2011 Carlos Garcia Campos <carlosgc at gnome.org>
-// Copyright 2007-2010, 2012 Albert Astals Cid <aacid at kde.org>
+// Copyright 2007-2010, 2012, 2015 Albert Astals Cid <aacid at kde.org>
 // Copyright 2010 Mark Riedesel <mark at klowner.com>
 // Copyright 2011 Pino Toscano <pino at kde.org>
 // Copyright 2012 Fabio D'Urso <fabiodurso at hotmail.it>
@@ -501,8 +501,7 @@ public:
 private:
   void parseInfo();
   Object *byte_range;
-  unsigned char *signature;
-  unsigned int signature_len;
+  GooString *signature;
   SignatureInfo *signature_info;
 
 #ifdef DEBUG_FORMS
commit a4ac855435325225e3d89d83870ff08ec73d86f8
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:52:41 2015 +0200

    PDFDoc::getSignatureWidgets: Do not assume a given page exists

diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 4a41899..fad779c 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -463,13 +463,16 @@ std::vector<FormWidgetSignature*> PDFDoc::getSignatureWidgets()
   std::vector<FormWidgetSignature*> widget_vector;
 
   for (int i = 1; i <= num_pages; i++) {
-    page_widgets = getCatalog()->getPage(i)->getFormWidgets();
-    for (int j = 0; page_widgets != NULL && j < page_widgets->getNumWidgets(); j++) {
-      if (page_widgets->getWidget(j)->getType() == formSignature) {
-          widget_vector.push_back(static_cast<FormWidgetSignature*>(page_widgets->getWidget(j)));
+    Page *p = getCatalog()->getPage(i);
+    if (p) {
+      page_widgets = p->getFormWidgets();
+      for (int j = 0; page_widgets != NULL && j < page_widgets->getNumWidgets(); j++) {
+	if (page_widgets->getWidget(j)->getType() == formSignature) {
+	    widget_vector.push_back(static_cast<FormWidgetSignature*>(page_widgets->getWidget(j)));
+	}
       }
+      delete page_widgets;
     }
-    delete page_widgets;
   }
   return widget_vector;
 }
commit 6509068cf6e4a92359bcc5402f9e9eb9649d641c
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:45:47 2015 +0200

    SignatureHandler initialize members on constructor

diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 2d4ecde..f8a44b8 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -109,6 +109,10 @@ void SignatureHandler::init_nss()
 
 
 SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length)
+ : CMSMessage(NULL),
+   CMSSignedData(NULL),
+   CMSSignerInfo(NULL),
+   temp_certs(NULL)
 {
   init_nss();
   CMSitem.data = p7;
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index a46bd81..8a5532b 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -57,10 +57,10 @@ private:
   void digestFile(unsigned char *digest_buffer, unsigned char *input_data, int input_data_len, SECOidTag hashOIDTag);
 
   SECItem CMSitem;
-  NSSCMSMessage *CMSMessage = NULL;
-  NSSCMSSignedData *CMSSignedData = NULL;
-  NSSCMSSignerInfo *CMSSignerInfo = NULL;
-  CERTCertificate **temp_certs = NULL;
+  NSSCMSMessage *CMSMessage;
+  NSSCMSSignedData *CMSSignedData;
+  NSSCMSSignerInfo *CMSSignerInfo;
+  CERTCertificate **temp_certs;
 };
 
 #endif
commit 5d8dfaa9d55932cde638880bcee063a6f084689f
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:43:16 2015 +0200

    SignatureInfo::setSignerName: free old signer_name

diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc
index 418d235..8f7ec45 100644
--- a/poppler/SignatureInfo.cc
+++ b/poppler/SignatureInfo.cc
@@ -77,6 +77,7 @@ void SignatureInfo::setCertificateValStatus(enum CertificateValidationStatus cer
 
 void SignatureInfo::setSignerName(char *signerName)
 {
+  free(signer_name);
   signer_name = signerName;
 }
 
commit f284cfc7394175ea675d7c76d97a1f8461cf17d2
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:42:11 2015 +0200

    Start function names on lowercase

diff --git a/poppler/Form.cc b/poppler/Form.cc
index ec508dc..18fbca4 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1476,7 +1476,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
 
   SignatureHandler signature_handler(signature, signature_len);
 
-  sig_val_state = signature_handler.ValidateSignature(to_check, signed_data_len);
+  sig_val_state = signature_handler.validateSignature(to_check, signed_data_len);
   signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
   signature_info->setSignerName(signature_handler.getSignerName());
 
@@ -1491,7 +1491,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
     return signature_info;
   }
 
-  cert_val_state = signature_handler.ValidateCertificate();
+  cert_val_state = signature_handler.validateCertificate();
   signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state));
 
   return signature_info;
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 632e39e..2d4ecde 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -6,6 +6,7 @@
 //
 // Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright 2015 André Esser <bepandre at hotmail.com>
+// Copyright 2015 Albert Astals Cid <aacid at kde.org>
 //
 //========================================================================
 
@@ -194,7 +195,7 @@ NSSCMSSignerInfo *SignatureHandler::CMS_SignerInfoCreate(NSSCMSSignedData * cms_
   }
 }
 
-NSSCMSVerificationStatus SignatureHandler::ValidateSignature(unsigned char *signed_data, int signed_data_len)
+NSSCMSVerificationStatus SignatureHandler::validateSignature(unsigned char *signed_data, int signed_data_len)
 {
   unsigned char *digest_buffer = NULL;
 
@@ -224,7 +225,7 @@ NSSCMSVerificationStatus SignatureHandler::ValidateSignature(unsigned char *sign
   }
 }
 
-SECErrorCodes SignatureHandler::ValidateCertificate()
+SECErrorCodes SignatureHandler::validateCertificate()
 {
   SECErrorCodes retVal;
   CERTCertificate *cert;
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index 5b8d5e6..a46bd81 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -6,6 +6,7 @@
 //
 // Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright 2015 André Esser <bepandre at hotmail.com>
+// Copyright 2015 Albert Astals Cid <aacid at kde.org>
 //
 //========================================================================
 
@@ -40,8 +41,8 @@ public:
   time_t getSigningTime();
   char * getSignerName();
   void setSignature(unsigned char *, int);
-  NSSCMSVerificationStatus ValidateSignature(unsigned char *signed_data, int signed_data_len);
-  SECErrorCodes ValidateCertificate();
+  NSSCMSVerificationStatus validateSignature(unsigned char *signed_data, int signed_data_len);
+  SECErrorCodes validateCertificate();
   //Translate NSS error codes
   static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code);
   static CertificateValidationStatus NSS_CertTranslate(SECErrorCodes nss_code);
commit 127ad3bb038d90ad7579e2e94cff2890869e2f43
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:40:31 2015 +0200

    FormFieldSignature::parseInfo: check for isString instead !isNull

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 91c9867..ec508dc 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1425,7 +1425,7 @@ void FormFieldSignature::parseInfo()
 
   // retrieve SigningTime
   sig_dict.dictLookup("M", &time_of_signing);
-  if (!time_of_signing.isNull()) {
+  if (time_of_signing.isString()) {
     GooString *time_str = time_of_signing.getString();
     signature_info->setSigningTime(pdfTimeToInteger(time_str)); // Put this information directly in SignatureInfo object
     time_of_signing.free();
commit e428a3b8449830bf00706b4ccf86c27a55970f1f
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:39:57 2015 +0200

    FormFieldSignature::parseInfo: Use shorter isName version

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 76cfbb3..91c9867 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1433,7 +1433,7 @@ void FormFieldSignature::parseInfo()
 
   // check if subfilter is supported for signature validation, only detached signatures work for now
   sig_dict.dictLookup("SubFilter", &subfilterName);
-  if (subfilterName.isName() && strcmp(subfilterName.getName(), "adbe.pkcs7.detached") == 0) {
+  if (subfilterName.isName("adbe.pkcs7.detached")) {
     signature_info->setSubFilterSupport(true);
   }
 
commit ba3a4ec30fcd303e91ef41bef491c230a822bd32
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:36:44 2015 +0200

    Delete the signature_info in FormFieldSignature not in pdfsigverify

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 3ae198e..76cfbb3 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1391,6 +1391,7 @@ FormFieldSignature::~FormFieldSignature()
     byte_range->free();
     delete byte_range;
   }
+  delete signature_info;
 }
 
 void FormFieldSignature::parseInfo()
diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
index 6ab1174..c537e64 100644
--- a/utils/pdfsigverify.cc
+++ b/utils/pdfsigverify.cc
@@ -151,12 +151,11 @@ int main(int argc, char *argv[])
     printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
     printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
     printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
+    gfree(time_str);
     if (sig_info->getSignatureValStatus() != SIGNATURE_VALID || dontVerifyCert) {
       continue;
     }
     printf("  - Certificate Validation: %s\n", getReadableCertState(sig_info->getCertificateValStatus()));
-    gfree(time_str);
-    delete sig_info;
   }
 
   exitCode = 0;
commit e6b3d696adea70c79f60a67c275e23c29d2534c3
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:33:56 2015 +0200

    Make signature code more resilient
    
    Do not abort with sign-a-pdf-with-reader-enabled.pdf

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 079190f..3ae198e 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1379,6 +1379,7 @@ GooString *FormFieldChoice::getSelectedChoice() {
 FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
   : FormField(docA, dict, ref, parent, usedParents, formSignature)
 {
+  byte_range = NULL;
   signature = NULL;
   signature_info = new SignatureInfo();
   parseInfo();
@@ -1394,44 +1395,49 @@ FormFieldSignature::~FormFieldSignature()
 
 void FormFieldSignature::parseInfo()
 {
-  if (obj.isDict()) {
-    Object sig_dict, contents_obj, byterange_obj, time_of_signing, subfilterName;
-
-    // retrieve PKCS#7
-    obj.dictLookup("V", &sig_dict);
-    sig_dict.dictLookup("Contents", &contents_obj);
-    if (contents_obj.isString()) {
-      GooString *str = contents_obj.getString();
-      signature_len = str->getLength();
-      signature = (unsigned char *)gmalloc(signature_len);
-      memcpy(signature, str->getCString(), signature_len);
-    }
-    contents_obj.free();
+  if (!obj.isDict())
+    return;
 
-    sig_dict.dictLookup("ByteRange", &byterange_obj);
+  Object sig_dict, contents_obj, byterange_obj, time_of_signing, subfilterName;
 
-    if (byterange_obj.isArray()) {
-      byte_range = new Object(byterange_obj);
-    }
+  // retrieve PKCS#7
+  obj.dictLookup("V", &sig_dict);
+  if (!sig_dict.isDict()) {
+    sig_dict.free();
+    return;
+  }
 
-    // retrieve SigningTime
-    sig_dict.dictLookup("M", &time_of_signing);
-    if (!time_of_signing.isNull()) {
-      GooString *time_str = time_of_signing.getString();
-      signature_info->setSigningTime(pdfTimeToInteger(time_str)); // Put this information directly in SignatureInfo object
-      time_of_signing.free();
-    }
+  sig_dict.dictLookup("Contents", &contents_obj);
+  if (contents_obj.isString()) {
+    GooString *str = contents_obj.getString();
+    signature_len = str->getLength();
+    signature = (unsigned char *)gmalloc(signature_len);
+    memcpy(signature, str->getCString(), signature_len);
+  }
+  contents_obj.free();
 
-    // check if subfilter is supported for signature validation, only detached signatures work for now
-    sig_dict.dictLookup("SubFilter", &subfilterName);
-    if (subfilterName.isName() && strcmp(subfilterName.getName(), "adbe.pkcs7.detached") == 0) {
-      signature_info->setSubFilterSupport(true);
-    }
+  sig_dict.dictLookup("ByteRange", &byterange_obj);
 
-    subfilterName.free();
-    sig_dict.free();
+  if (byterange_obj.isArray()) {
+    byte_range = new Object(byterange_obj);
+  }
+
+  // retrieve SigningTime
+  sig_dict.dictLookup("M", &time_of_signing);
+  if (!time_of_signing.isNull()) {
+    GooString *time_str = time_of_signing.getString();
+    signature_info->setSigningTime(pdfTimeToInteger(time_str)); // Put this information directly in SignatureInfo object
+    time_of_signing.free();
+  }
+
+  // check if subfilter is supported for signature validation, only detached signatures work for now
+  sig_dict.dictLookup("SubFilter", &subfilterName);
+  if (subfilterName.isName() && strcmp(subfilterName.getName(), "adbe.pkcs7.detached") == 0) {
+    signature_info->setSubFilterSupport(true);
   }
 
+  subfilterName.free();
+  sig_dict.free();
 }
 
 SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
commit 23fa84ff91666d1feb2242fe4572eb397c791c55
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:28:18 2015 +0200

    cmake: No need if NSS3_FOUND if it's required

diff --git a/CMakeLists.txt b/CMakeLists.txt
index a134f15..ce16d53 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -202,9 +202,8 @@ if(ENABLE_LIBCURL)
   include_directories(${CURL_INCLUDE_DIR})
   set(POPPLER_HAS_CURL_SUPPORT ON)
 endif(ENABLE_LIBCURL)
-if (NSS3_FOUND)
-  add_definitions(${NSS3_CFLAGS})
-endif(NSS3_FOUND)
+
+add_definitions(${NSS3_CFLAGS})
 
 add_definitions(-DHAVE_CONFIG_H=1)
 if(MINGW)
@@ -418,9 +417,7 @@ endif(ENABLE_SPLASH)
 if(FONTCONFIG_FOUND)
   set(poppler_LIBS ${poppler_LIBS} ${FONTCONFIG_LIBRARIES})
 endif(FONTCONFIG_FOUND)
-if (NSS3_FOUND)
-  set(poppler_LIBS ${poppler_LIBS} ${NSS3_LIBRARIES})
-endif(NSS3_FOUND)
+set(poppler_LIBS ${poppler_LIBS} ${NSS3_LIBRARIES})
 if(JPEG_FOUND)
   set(poppler_SRCS ${poppler_SRCS}
     poppler/DCTStream.cc
commit 7a1dac27d380f0b1a68383525a4ae4a0c7f3e6f5
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:26:31 2015 +0200

    FormFieldSignature::validateSignature: Free to_check earlier

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 38579af..079190f 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -5,7 +5,7 @@
 // This file is licensed under the GPLv2 or later
 //
 // Copyright 2006-2008 Julien Rebetez <julienr at svn.gnome.org>
-// Copyright 2007-2012 Albert Astals Cid <aacid at kde.org>
+// Copyright 2007-2012, 2015 Albert Astals Cid <aacid at kde.org>
 // Copyright 2007-2008, 2011 Carlos Garcia Campos <carlosgc at gnome.org>
 // Copyright 2007, 2013 Adrian Johnson <ajohnson at redneon.com>
 // Copyright 2007 Iñigo Martínez <inigomartinez at gmail.com>
@@ -1478,6 +1478,8 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
     signature_info->setSigningTime(signature_handler.getSigningTime());
   }
 
+  free(to_check);
+
   if (sig_val_state != NSSCMSVS_GoodSignature || !doVerifyCert) {
     return signature_info;
   }
@@ -1485,7 +1487,6 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
   cert_val_state = signature_handler.ValidateCertificate();
   signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state));
 
-  free(to_check);
   return signature_info;
 }
 
commit 71cc344d85aba7a4ae79e2c4c454341096a2329b
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:25:31 2015 +0200

    Remove PDFDoc::countSignatures

diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 3856d71..4a41899 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005, 2006, 2008 Brad Hards <bradh at frogmouth.net>
-// Copyright (C) 2005, 2007-2009, 2011-2014 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2005, 2007-2009, 2011-2015 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2008 Julien Rebetez <julienr at svn.gnome.org>
 // Copyright (C) 2008, 2010 Pino Toscano <pino at kde.org>
 // Copyright (C) 2008, 2010, 2011 Carlos Garcia Campos <carlosgc at gnome.org>
@@ -456,11 +456,6 @@ GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword)
   return ret;
 }
 
-unsigned int PDFDoc::countSignatures()
-{
-  return getSignatureWidgets().size();
-}
-
 std::vector<FormWidgetSignature*> PDFDoc::getSignatureWidgets()
 {
   int num_pages = getNumPages();
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 97b1e7b..8ffaedd 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -14,7 +14,7 @@
 // under GPL version 2 or later
 //
 // Copyright (C) 2005, 2006, 2008 Brad Hards <bradh at frogmouth.net>
-// Copyright (C) 2005, 2009, 2014 Albert Astals Cid <aacid at kde.org>
+// Copyright (C) 2005, 2009, 2014, 2015 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2008 Julien Rebetez <julienr at svn.gnome.org>
 // Copyright (C) 2008 Pino Toscano <pino at kde.org>
 // Copyright (C) 2008 Carlos Garcia Campos <carlosgc at gnome.org>
@@ -205,7 +205,6 @@ public:
   // Is the file encrypted?
   GBool isEncrypted() { return xref->isEncrypted(); }
 
-  unsigned int countSignatures();
   std::vector<FormWidgetSignature*> getSignatureWidgets();
 
   // Check various permissions.
diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
index 90b0558..6ab1174 100644
--- a/utils/pdfsigverify.cc
+++ b/utils/pdfsigverify.cc
@@ -134,7 +134,8 @@ int main(int argc, char *argv[])
     goto end;
   }
 
-  sigCount = doc->countSignatures();
+  sig_widgets = doc->getSignatureWidgets();
+  sigCount = sig_widgets.size();
 
   if (sigCount >= 1) {
     printf("Digital Signature Info of: %s\n", fileName->getCString());
@@ -144,11 +145,7 @@ int main(int argc, char *argv[])
     goto end;
   }
 
-  sig_widgets = doc->getSignatureWidgets();
-  if (sig_widgets.size() == 0)
-    goto end;
-
-  for(unsigned int i = 0; i < sigCount; i++) {
+  for (unsigned int i = 0; i < sigCount; i++) {
     sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false);
     printf("Signature #%d:\n", i+1);
     printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
commit c68954dd73202f21b62899dc335fd74218d5b595
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:20:41 2015 +0200

    pdfsigverify: move assignment before if

diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
index 5e658dd..90b0558 100644
--- a/utils/pdfsigverify.cc
+++ b/utils/pdfsigverify.cc
@@ -130,8 +130,8 @@ int main(int argc, char *argv[])
   doc = PDFDocFactory().createPDFDoc(*fileName, NULL, NULL);
 
   if (!doc->isOk()) {
-    goto end;
     exitCode = 1;
+    goto end;
   }
 
   sigCount = doc->countSignatures();
commit 8727fe6c08b7326523d6e15c90ce89e5e9d7300e
Author: Albert Astals Cid <aacid at kde.org>
Date:   Mon Sep 14 01:20:16 2015 +0200

    pdfsigverify: no if before delete

diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
index cb37d4f..5e658dd 100644
--- a/utils/pdfsigverify.cc
+++ b/utils/pdfsigverify.cc
@@ -6,6 +6,7 @@
 //
 // Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
 // Copyright 2015 André Esser <bepandre at hotmail.com>
+// Copyright 2015 Albert Astals Cid <aacid at kde.org>
 //
 //========================================================================
 
@@ -165,10 +166,8 @@ int main(int argc, char *argv[])
 
 end:
   delete globalParams;
-  if (fileName)
-    delete fileName;
-  if (doc)
-    delete doc;
+  delete fileName;
+  delete doc;
 
   return exitCode;
 }
commit eb1a6a6254fb393555d6d30b99f4ea800d8d446b
Author: André Guerreiro <aguerreiro1985 at gmail.com>
Date:   Mon Sep 14 01:17:30 2015 +0200

    Core: Support for digital signatures
    
    Coded with André Esser <bepandre at hotmail.com>
    
    Bug #16770

diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac3d090..a134f15 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,6 +105,7 @@ endif(WITH_FONTCONFIGURATION_FONTCONFIG)
 macro_optional_find_package(JPEG)
 macro_optional_find_package(PNG)
 macro_optional_find_package(TIFF)
+find_package(NSS3 REQUIRED)
 if(JPEG_FOUND)
   set(ENABLE_LIBJPEG ${JPEG_FOUND})
 endif(JPEG_FOUND)
@@ -201,6 +202,9 @@ if(ENABLE_LIBCURL)
   include_directories(${CURL_INCLUDE_DIR})
   set(POPPLER_HAS_CURL_SUPPORT ON)
 endif(ENABLE_LIBCURL)
+if (NSS3_FOUND)
+  add_definitions(${NSS3_CFLAGS})
+endif(NSS3_FOUND)
 
 add_definitions(-DHAVE_CONFIG_H=1)
 if(MINGW)
@@ -364,6 +368,8 @@ set(poppler_SRCS
   poppler/ProfileData.cc
   poppler/PreScanOutputDev.cc
   poppler/PSTokenizer.cc
+  poppler/SignatureHandler.cc
+  poppler/SignatureInfo.cc
   poppler/Stream.cc
   poppler/StructTreeRoot.cc
   poppler/StructElement.cc
@@ -412,6 +418,9 @@ endif(ENABLE_SPLASH)
 if(FONTCONFIG_FOUND)
   set(poppler_LIBS ${poppler_LIBS} ${FONTCONFIG_LIBRARIES})
 endif(FONTCONFIG_FOUND)
+if (NSS3_FOUND)
+  set(poppler_LIBS ${poppler_LIBS} ${NSS3_LIBRARIES})
+endif(NSS3_FOUND)
 if(JPEG_FOUND)
   set(poppler_SRCS ${poppler_SRCS}
     poppler/DCTStream.cc
diff --git a/cmake/modules/FindNSS3.cmake b/cmake/modules/FindNSS3.cmake
new file mode 100644
index 0000000..657cad8
--- /dev/null
+++ b/cmake/modules/FindNSS3.cmake
@@ -0,0 +1,22 @@
+# - try to find NSS3 libraries
+# Once done this will define
+#
+#  NSS_FOUND - system has NSS3
+#  NSS3_CFLAGS - the NSS CFlags
+#  NSS3_LIBRARIES - Link these to use NSS
+#
+# Copyright 2015 André Guerreiro, <aguerreiro1985 at gmail.com>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+include(FindPackageHandleStandardArgs)
+
+if (NOT WIN32)
+  find_package(PkgConfig REQUIRED)
+
+  pkg_check_modules(NSS3 "nss>=3.19")
+
+  find_package_handle_standard_args(NSS3 DEFAULT_MSG NSS3_LIBRARIES NSS3_CFLAGS)
+
+endif(NOT WIN32)
diff --git a/configure.ac b/configure.ac
index 4bc1524..741001d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -264,6 +264,8 @@ else
   enable_libopenjpeg=no
 fi
 
+PKG_CHECK_MODULES(NSS3, nss, [], [])
+
 AM_CONDITIONAL(BUILD_LIBOPENJPEG, test x$openjpeg1 = xyes || test x$openjpeg2 = xyes)
 AH_TEMPLATE([ENABLE_LIBOPENJPEG],
 	    [Use libopenjpeg instead of builtin jpeg2000 decoder.])
diff --git a/poppler/DateInfo.cc b/poppler/DateInfo.cc
index 563204a..8cd4883 100644
--- a/poppler/DateInfo.cc
+++ b/poppler/DateInfo.cc
@@ -4,6 +4,8 @@
 //
 // Copyright (C) 2008 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
+// Copyright (C) 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright (C) 2015 André Esser <bepandre at hotmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -116,3 +118,27 @@ GooString *timeToDateString(time_t *timet) {
   return dateString;
 }
 
+time_t pdfTimeToInteger(GooString *time_str)
+{
+  int year, mon, day, hour, min, sec, tz_hour, tz_minute;
+  char tz;
+  struct tm time_struct;
+
+  if (!parseDateString (time_str->getCString(), &year,
+        &mon, &day, &hour, &min, &sec, &tz, &tz_hour, &tz_minute))
+    return 0;
+
+  time_struct.tm_year = year - 1900;
+  time_struct.tm_mon = mon - 1;
+  time_struct.tm_mday = day;
+  time_struct.tm_hour = hour;
+  time_struct.tm_min = min;
+  time_struct.tm_sec = sec;
+  time_struct.tm_wday = -1;
+  time_struct.tm_yday = -1;
+  time_struct.tm_isdst = -1;
+
+  time_t unix_time = mktime(&time_struct);
+
+  return unix_time;
+}
diff --git a/poppler/DateInfo.h b/poppler/DateInfo.h
index 116350f..840ee5a 100644
--- a/poppler/DateInfo.h
+++ b/poppler/DateInfo.h
@@ -4,6 +4,8 @@
 //
 // Copyright (C) 2008 Albert Astals Cid <aacid at kde.org>
 // Copyright (C) 2009 Carlos Garcia Campos <carlosgc at gnome.org>
+// Copyright (C) 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright (C) 2015 André Esser <bepandre at hotmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -31,5 +33,6 @@ GBool parseDateString(const char *string, int *year, int *month, int *day, int *
  * If timet is NULL, current time is used.
  */
 GooString *timeToDateString(time_t *timet);
+time_t pdfTimeToInteger(GooString *time_str);
 
 #endif
diff --git a/poppler/Form.cc b/poppler/Form.cc
index a46a659..38579af 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -15,7 +15,9 @@
 // Copyright 2009 KDAB via Guillermo Amaral <gamaral at amaral.com.mx>
 // Copyright 2010, 2012 Mark Riedesel <mark at klowner.com>
 // Copyright 2012 Fabio D'Urso <fabiodurso at hotmail.it>
-// 
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+//
 //========================================================================
 
 #include <config.h>
@@ -36,6 +38,8 @@
 #include "Gfx.h"
 #include "Form.h"
 #include "PDFDoc.h"
+#include "DateInfo.h"
+#include "SignatureHandler.h"
 #include "XRef.h"
 #include "PDFDocEncoding.h"
 #include "Annot.h"
@@ -441,6 +445,11 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu
   parent = static_cast<FormFieldSignature*>(field);
 }
 
+SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
+{
+  return parent->validateSignature(doVerifyCert, forceRevalidation);
+}
+
 void FormWidgetSignature::updateWidgetAppearance()
 {
   // Unimplemented
@@ -1370,11 +1379,114 @@ GooString *FormFieldChoice::getSelectedChoice() {
 FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
   : FormField(docA, dict, ref, parent, usedParents, formSignature)
 {
+  signature = NULL;
+  signature_info = new SignatureInfo();
+  parseInfo();
 }
 
 FormFieldSignature::~FormFieldSignature()
 {
+  if (byte_range) {
+    byte_range->free();
+    delete byte_range;
+  }
+}
+
+void FormFieldSignature::parseInfo()
+{
+  if (obj.isDict()) {
+    Object sig_dict, contents_obj, byterange_obj, time_of_signing, subfilterName;
+
+    // retrieve PKCS#7
+    obj.dictLookup("V", &sig_dict);
+    sig_dict.dictLookup("Contents", &contents_obj);
+    if (contents_obj.isString()) {
+      GooString *str = contents_obj.getString();
+      signature_len = str->getLength();
+      signature = (unsigned char *)gmalloc(signature_len);
+      memcpy(signature, str->getCString(), signature_len);
+    }
+    contents_obj.free();
+
+    sig_dict.dictLookup("ByteRange", &byterange_obj);
+
+    if (byterange_obj.isArray()) {
+      byte_range = new Object(byterange_obj);
+    }
+
+    // retrieve SigningTime
+    sig_dict.dictLookup("M", &time_of_signing);
+    if (!time_of_signing.isNull()) {
+      GooString *time_str = time_of_signing.getString();
+      signature_info->setSigningTime(pdfTimeToInteger(time_str)); // Put this information directly in SignatureInfo object
+      time_of_signing.free();
+    }
+
+    // check if subfilter is supported for signature validation, only detached signatures work for now
+    sig_dict.dictLookup("SubFilter", &subfilterName);
+    if (subfilterName.isName() && strcmp(subfilterName.getName(), "adbe.pkcs7.detached") == 0) {
+      signature_info->setSubFilterSupport(true);
+    }
+
+    subfilterName.free();
+    sig_dict.free();
+  }
+
+}
+
+SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
+{
+
+  if (!signature_info->isSubfilterSupported()) {
+    error(errUnimplemented, 0, "Unable to validate this type of signature");
+    return signature_info;
+  }
+
+  if (signature_info->getSignatureValStatus() != SIGNATURE_NOT_VERIFIED && !forceRevalidation) {
+    return signature_info;
+  }
+
+  if (byte_range == NULL || !byte_range->isArray() || signature == NULL) {
+    return signature_info;
+  }
+
+  Object r2, r3, r4;
+  NSSCMSVerificationStatus sig_val_state;
+  SECErrorCodes cert_val_state;
+
+  byte_range->arrayGet(1, &r2);
+  byte_range->arrayGet(2, &r3);
+  byte_range->arrayGet(3, &r4);
+
+  unsigned int signed_data_len = r2.getInt()+r4.getInt();
+  unsigned char *to_check = (unsigned char *)gmalloc(signed_data_len);
+
+  //Read the 2 slices of data that are signed
+  doc->getBaseStream()->setPos(0);
+  doc->getBaseStream()->doGetChars(r2.getInt(), to_check);
+  doc->getBaseStream()->setPos(r3.getInt());
+  doc->getBaseStream()->doGetChars(r4.getInt(), to_check+r2.getInt());
+
+  SignatureHandler signature_handler(signature, signature_len);
+
+  sig_val_state = signature_handler.ValidateSignature(to_check, signed_data_len);
+  signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
+  signature_info->setSignerName(signature_handler.getSignerName());
+
+  // verify if signature contains a 'signing time' attribute
+  if (signature_handler.getSigningTime() != 0) {
+    signature_info->setSigningTime(signature_handler.getSigningTime());
+  }
+
+  if (sig_val_state != NSSCMSVS_GoodSignature || !doVerifyCert) {
+    return signature_info;
+  }
+
+  cert_val_state = signature_handler.ValidateCertificate();
+  signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state));
 
+  free(to_check);
+  return signature_info;
 }
 
 #ifdef DEBUG_FORMS
@@ -1475,7 +1587,7 @@ Form::Form(PDFDoc *docA, Object* acroFormA)
 
 Form::~Form() {
   int i;
-  for(i = 0; i< numFields; ++i)
+  for(i = 0; i < numFields; ++i)
     delete rootFields[i];
   gfree (rootFields);
   delete defaultAppearance;
diff --git a/poppler/Form.h b/poppler/Form.h
index 3778ff6..c179874 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -11,6 +11,8 @@
 // Copyright 2011 Pino Toscano <pino at kde.org>
 // Copyright 2012 Fabio D'Urso <fabiodurso at hotmail.it>
 // Copyright 2013 Adrian Johnson <ajohnson at redneon.com>
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
 //
 //========================================================================
 
@@ -35,6 +37,8 @@ class Annots;
 class LinkAction;
 class GfxResources;
 class PDFDoc;
+class SignatureInfo;
+class SignatureHandler;
 
 enum FormFieldType {
   formButton,
@@ -245,6 +249,9 @@ class FormWidgetSignature: public FormWidget {
 public:
   FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
   void updateWidgetAppearance();
+
+  SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation);
+
 protected:
   FormFieldSignature *parent;
 };
@@ -487,8 +494,17 @@ class FormFieldSignature: public FormField {
 public:
   FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
 
+  SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation);
+
   virtual ~FormFieldSignature();
 
+private:
+  void parseInfo();
+  Object *byte_range;
+  unsigned char *signature;
+  unsigned int signature_len;
+  SignatureInfo *signature_info;
+
 #ifdef DEBUG_FORMS
   void print(int indent = 0);
 #endif
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index 9a5d026..2d8c5e6 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -166,6 +166,8 @@ poppler_include_HEADERS =	\
 	PreScanOutputDev.h	\
 	PSTokenizer.h		\
 	Rendition.h		\
+	SignatureHandler.h	\
+	SignatureInfo.h	\
 	StdinCachedFile.h	\
 	StdinPDFDocBuilder.h	\
 	Stream-CCITT.h		\
@@ -247,6 +249,8 @@ libpoppler_la_SOURCES =		\
 	PreScanOutputDev.cc \
 	PSTokenizer.cc		\
 	Rendition.cc		\
+	SignatureHandler.cc	\
+	SignatureInfo.cc \
 	StdinCachedFile.cc	\
 	StdinPDFDocBuilder.cc	\
 	Stream.cc 		\
@@ -275,6 +279,7 @@ libpoppler_la_CPPFLAGS =			\
 	$(libjpeg2000_includes)			\
 	$(libpng_includes)			\
 	$(libcurl_includes)			\
+	$(NSS3_CFLAGS)				\
 	$(FREETYPE_CFLAGS)			\
 	$(FONTCONFIG_CFLAGS)			\
 	$(AM_CPPFLAGS)
@@ -290,6 +295,7 @@ libpoppler_la_LIBADD =				\
 	$(zlib_libs)				\
 	$(libcurl_libs)				\
 	$(libjpeg2000_libs)			\
+	$(NSS3_LIBS)				\
 	$(FREETYPE_LIBS)			\
 	$(FONTCONFIG_LIBS)			\
 	$(PTHREAD_LIBS)				\
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 46c4544..3856d71 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -32,6 +32,8 @@
 // Copyright (C) 2013 Adam Reichold <adamreichold at myopera.com>
 // Copyright (C) 2014 Bogdan Cristea <cristeab at gmail.com>
 // Copyright (C) 2015 Li Junling <lijunling at sina.com>
+// Copyright (C) 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright (C) 2015 André Esser <bepandre at hotmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -76,6 +78,8 @@
 #endif
 #include "PDFDoc.h"
 #include "Hints.h"
+#include "DateInfo.h"
+#include "SignatureHandler.h"
 
 #if MULTITHREADED
 #  define pdfdocLocker()   MutexLocker locker(&mutex)
@@ -452,6 +456,29 @@ GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword)
   return ret;
 }
 
+unsigned int PDFDoc::countSignatures()
+{
+  return getSignatureWidgets().size();
+}
+
+std::vector<FormWidgetSignature*> PDFDoc::getSignatureWidgets()
+{
+  int num_pages = getNumPages();
+  FormPageWidgets *page_widgets = NULL;
+  std::vector<FormWidgetSignature*> widget_vector;
+
+  for (int i = 1; i <= num_pages; i++) {
+    page_widgets = getCatalog()->getPage(i)->getFormWidgets();
+    for (int j = 0; page_widgets != NULL && j < page_widgets->getNumWidgets(); j++) {
+      if (page_widgets->getWidget(j)->getType() == formSignature) {
+          widget_vector.push_back(static_cast<FormWidgetSignature*>(page_widgets->getWidget(j)));
+      }
+    }
+    delete page_widgets;
+  }
+  return widget_vector;
+}
+
 void PDFDoc::displayPage(OutputDev *out, int page,
 			 double hDPI, double vDPI, int rotate,
 			 GBool useMediaBox, GBool crop, GBool printing,
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 6c40f7b..97b1e7b 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -27,6 +27,8 @@
 // Copyright (C) 2013 Adrian Johnson <ajohnson at redneon.com>
 // Copyright (C) 2013 Adam Reichold <adamreichold at myopera.com>
 // Copyright (C) 2013 Adrian Perez de Castro <aperez at igalia.com>
+// Copyright (C) 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright (C) 2015 André Esser <bepandre at hotmail.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -47,8 +49,11 @@
 #include "Catalog.h"
 #include "Page.h"
 #include "Annot.h"
+#include "Form.h"
 #include "OptionalContent.h"
 #include "Stream.h"
+#include "poppler-config.h"
+#include "SignatureInfo.h"
 
 class GooString;
 class GooFile;
@@ -62,6 +67,7 @@ class Linearization;
 class SecurityHandler;
 class Hints;
 class StructTreeRoot;
+class SignatureHandler;
 
 enum PDFWriteMode {
   writeStandard,
@@ -199,6 +205,9 @@ public:
   // Is the file encrypted?
   GBool isEncrypted() { return xref->isEncrypted(); }
 
+  unsigned int countSignatures();
+  std::vector<FormWidgetSignature*> getSignatureWidgets();
+
   // Check various permissions.
   GBool okToPrint(GBool ignoreOwnerPW = gFalse)
     { return xref->okToPrint(ignoreOwnerPW); }
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
new file mode 100644
index 0000000..632e39e
--- /dev/null
+++ b/poppler/SignatureHandler.cc
@@ -0,0 +1,301 @@
+//========================================================================
+//
+// SignatureHandler.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "SignatureHandler.h"
+#include "goo/GooString.h"
+#include "goo/gmem.h"
+
+#include <dirent.h>
+#include <Error.h>
+
+void SignatureHandler::digestFile(unsigned char *digest_buffer, unsigned char *input_data, int input_data_len, SECOidTag hashOIDTag)
+{
+  HASH_HashType hashType;
+  hashType    = HASH_GetHashTypeByOidTag(hashOIDTag);
+  HASH_HashBuf(hashType, digest_buffer, input_data, input_data_len);
+
+}
+
+unsigned int SignatureHandler::digestLength(SECOidTag digestAlgId)
+{
+  switch(digestAlgId){
+    case SEC_OID_SHA1:
+      return 20;
+    case SEC_OID_SHA256:
+      return 32;
+    case SEC_OID_SHA384:
+      return 48;
+    case SEC_OID_SHA512:
+      return 64;
+    default:
+      printf("ERROR: Unrecognized Hash ID\n");
+      return 0;
+  }
+}
+
+char *SignatureHandler::getSignerName()
+{
+  if (!CMSSignerInfo)
+      return NULL;
+
+  CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
+  return CERT_GetCommonName(&cert->subject);
+}
+
+time_t SignatureHandler::getSigningTime()
+{
+  PRTime sTime; // time in microseconds since the epoch
+
+  if (NSS_CMSSignerInfo_GetSigningTime (CMSSignerInfo, &sTime) != SECSuccess)
+    return 0;
+
+  return (time_t) sTime/1000000;
+}
+
+
+GooString *SignatureHandler::getDefaultFirefoxCertDB_Linux()
+{
+  GooString * finalPath = NULL;
+  DIR *toSearchIn;
+  struct dirent *subFolder;
+
+  GooString * homePath = new GooString(getenv("HOME"));
+  homePath = homePath->append("/.mozilla/firefox/");
+
+  if ((toSearchIn = opendir(homePath->getCString())) == NULL) {
+	error(errInternal, 0, "couldn't find default Firefox Folder");
+	return NULL;
+  }
+  do {
+    if ((subFolder = readdir(toSearchIn)) != NULL) {
+      if (strstr(subFolder->d_name, "default") != NULL) {
+	finalPath = homePath->append(subFolder->d_name);
+	closedir(toSearchIn);
+	return finalPath;
+      }
+    }
+  } while (subFolder != NULL);
+
+  return NULL;
+}
+
+/**
+ * Initialise NSS
+ */
+void SignatureHandler::init_nss() 
+{
+  GooString *certDBPath = getDefaultFirefoxCertDB_Linux();
+  if (certDBPath == NULL) {
+    NSS_Init("sql:/etc/pki/nssdb");
+  } else {
+    NSS_Init(certDBPath->getCString());
+  }
+
+  if (certDBPath) {
+    delete certDBPath;
+  }
+}
+
+
+SignatureHandler::SignatureHandler(unsigned char *p7, int p7_length)
+{
+  init_nss();
+  CMSitem.data = p7;
+  CMSitem.len = p7_length;
+  CMSMessage = CMS_MessageCreate(&CMSitem);
+  CMSSignedData = CMS_SignedDataCreate(CMSMessage);
+  CMSSignerInfo = CMS_SignerInfoCreate(CMSSignedData);
+}
+
+
+SignatureHandler::~SignatureHandler()
+{
+  SECITEM_FreeItem(&CMSitem, PR_FALSE);
+  if (CMSSignerInfo)
+    NSS_CMSSignerInfo_Destroy(CMSSignerInfo);
+  if (CMSSignedData)
+    NSS_CMSSignedData_Destroy(CMSSignedData);
+  if (CMSMessage)
+    NSS_CMSMessage_Destroy(CMSMessage);
+
+  free(temp_certs);
+
+  if (NSS_Shutdown()!=SECSuccess)
+    fprintf(stderr, "Detail: %s\n", PR_ErrorToString(PORT_GetError(), PR_LANGUAGE_I_DEFAULT));
+}
+
+NSSCMSMessage *SignatureHandler::CMS_MessageCreate(SECItem * cms_item)
+{
+  if (cms_item->data){
+    return NSS_CMSMessage_CreateFromDER(cms_item, NULL, NULL /* Content callback */
+                        , NULL, NULL /*Password callback*/
+                        , NULL, NULL /*Decrypt callback*/);
+  } else {
+    return NULL;
+  }
+}
+
+NSSCMSSignedData *SignatureHandler::CMS_SignedDataCreate(NSSCMSMessage * cms_msg)
+{
+  if (!NSS_CMSMessage_IsSigned(cms_msg)) {
+    error(errInternal, 0, "Input couldn't be parsed as a CMS signature");
+    return NULL;
+  }
+
+  NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(cms_msg, 0);
+  if (!cinfo) {
+    error(errInternal, 0, "Error in NSS_CMSMessage_ContentLevel");
+    return NULL;
+  }
+
+  NSSCMSSignedData *signedData = (NSSCMSSignedData*) NSS_CMSContentInfo_GetContent(cinfo);
+  if (!signedData) {
+    error(errInternal, 0, "CError in NSS_CMSContentInfo_GetContent()");
+    return NULL;
+  }
+
+  if (signedData->rawCerts)
+  {
+    size_t i;
+    for (i = 0; signedData->rawCerts[i]; ++i) {} // just count the length of the certificate chain
+
+    // tempCerts field needs to be filled for complete memory release by NSSCMSSignedData_Destroy
+    signedData->tempCerts = (CERTCertificate **) gmallocn( i+1, sizeof(CERTCertificate *));
+    memset(signedData->tempCerts, 0, (i+1) * sizeof(CERTCertificate *));
+    // store the adresses of these temporary certificates for future release
+    for (i = 0; signedData->rawCerts[i]; ++i)
+      signedData->tempCerts[i] = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), signedData->rawCerts[i], NULL, 0, 0);
+
+    temp_certs = signedData->tempCerts;
+    return signedData;
+  } else {
+    return NULL;
+  }
+}
+
+NSSCMSSignerInfo *SignatureHandler::CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data)
+{
+  NSSCMSSignerInfo *signerInfo = NSS_CMSSignedData_GetSignerInfo(cms_sig_data, 0);
+  if (!signerInfo) {
+    printf("Error in NSS_CMSSignedData_GetSignerInfo()\n");
+    return NULL;
+  } else {
+    return signerInfo;
+  }
+}
+
+NSSCMSVerificationStatus SignatureHandler::ValidateSignature(unsigned char *signed_data, int signed_data_len)
+{
+  unsigned char *digest_buffer = NULL;
+
+  if (!CMSSignedData)
+    return NSSCMSVS_MalformedSignature;
+
+  SECItem usedAlgorithm = NSS_CMSSignedData_GetDigestAlgs(CMSSignedData)[0]->algorithm;
+  unsigned int hash_length = digestLength(SECOID_FindOIDTag(&usedAlgorithm));
+
+  digest_buffer = (unsigned char *)PORT_Alloc(hash_length);
+
+  digestFile(digest_buffer, signed_data, signed_data_len, SECOID_FindOIDTag(&usedAlgorithm));
+
+  SECItem digest;
+  digest.data = digest_buffer;
+  digest.len = hash_length;
+
+  if ((NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == NULL)
+    CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
+
+  if (NSS_CMSSignerInfo_Verify(CMSSignerInfo, &digest, NULL) != SECSuccess) {
+    PORT_Free(digest_buffer);
+    return CMSSignerInfo->verificationStatus;
+  } else {
+    PORT_Free(digest_buffer);
+    return NSSCMSVS_GoodSignature;
+  }
+}
+
+SECErrorCodes SignatureHandler::ValidateCertificate()
+{
+  SECErrorCodes retVal;
+  CERTCertificate *cert;
+
+  if (!CMSSignerInfo)
+    return (SECErrorCodes) -1; //error code to avoid matching error codes defined in SECErrorCodes
+
+  if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == NULL)
+    CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
+
+  CERTValInParam inParams[2];
+  inParams[0].type = cert_pi_revocationFlags;
+  inParams[0].value.pointer.revocation = CERT_GetClassicOCSPEnabledSoftFailurePolicy();
+  inParams[1].type = cert_pi_end;
+
+  if (CERT_PKIXVerifyCert(cert, certificateUsageEmailSigner, inParams, NULL, 
+                CMSSignerInfo->cmsg->pwfn_arg) != SECSuccess) {
+    retVal = (SECErrorCodes) PORT_GetError();
+  } else {
+    // PORT_GetError() will return 0 if everything was fine, 
+    // there are other possible outcomes even if the previous return was SECSuccess.
+    retVal = (SECErrorCodes) PORT_GetError();
+  }
+
+
+  if (cert)
+    CERT_DestroyCertificate(cert);
+
+  return retVal;
+}
+
+
+SignatureValidationStatus SignatureHandler::NSS_SigTranslate(NSSCMSVerificationStatus nss_code)
+{
+  switch(nss_code)
+  {
+    case NSSCMSVS_GoodSignature:
+      return SIGNATURE_VALID;
+
+    case NSSCMSVS_BadSignature:
+      return SIGNATURE_INVALID;
+
+      case NSSCMSVS_DigestMismatch:
+      return SIGNATURE_DIGEST_MISMATCH;
+
+    case NSSCMSVS_ProcessingError:
+      return SIGNATURE_DECODING_ERROR;
+
+    default:
+      return SIGNATURE_GENERIC_ERROR;
+  }
+}
+
+CertificateValidationStatus SignatureHandler::NSS_CertTranslate(SECErrorCodes nss_code)
+{
+  // 0 not defined in SECErrorCodes, it means success for this purpose.
+  if (nss_code == (SECErrorCodes) 0)
+    return CERTIFICATE_TRUSTED;
+
+  switch(nss_code)
+  {
+    case SEC_ERROR_UNKNOWN_ISSUER:
+      return CERTIFICATE_UNTRUSTED;
+
+    case SEC_ERROR_REVOKED_CERTIFICATE:
+      return CERTIFICATE_REVOKED;
+
+    case SEC_ERROR_EXPIRED_CERTIFICATE:
+      return CERTIFICATE_EXPIRED;
+
+    default:
+      return CERTIFICATE_GENERIC_ERROR;
+  }
+}
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
new file mode 100644
index 0000000..5b8d5e6
--- /dev/null
+++ b/poppler/SignatureHandler.h
@@ -0,0 +1,65 @@
+//========================================================================
+//
+// SignatureHandler.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+//
+//========================================================================
+
+#ifndef SIGNATURE_HANDLER_H
+#define SIGNATURE_HANDLER_H
+
+#include "goo/GooString.h"
+#include "SignatureInfo.h"
+
+/* NSPR Headers */
+#include <nspr/prprf.h>
+#include <nspr/prtypes.h>
+#include <nspr/plgetopt.h>
+#include <nspr/prio.h>
+#include <nspr/prerror.h>
+
+/* NSS headers */
+#include <nss/cms.h>
+#include <nss/nss.h>
+#include <nss/cert.h>
+#include <nss/cryptohi.h>
+#include <nss/secerr.h>
+#include <nss/secoid.h>
+#include <nss/secmodt.h>
+#include <nss/sechash.h>
+
+class SignatureHandler
+{
+public:
+  SignatureHandler(unsigned char *p7, int p7_length);
+  ~SignatureHandler();
+  time_t getSigningTime();
+  char * getSignerName();
+  void setSignature(unsigned char *, int);
+  NSSCMSVerificationStatus ValidateSignature(unsigned char *signed_data, int signed_data_len);
+  SECErrorCodes ValidateCertificate();
+  //Translate NSS error codes
+  static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code);
+  static CertificateValidationStatus NSS_CertTranslate(SECErrorCodes nss_code);
+
+private:
+  void init_nss();
+  GooString * getDefaultFirefoxCertDB_Linux();
+  unsigned int digestLength(SECOidTag digestAlgId);
+  NSSCMSMessage *CMS_MessageCreate(SECItem * cms_item);
+  NSSCMSSignedData *CMS_SignedDataCreate(NSSCMSMessage * cms_msg);
+  NSSCMSSignerInfo *CMS_SignerInfoCreate(NSSCMSSignedData * cms_sig_data);
+  void digestFile(unsigned char *digest_buffer, unsigned char *input_data, int input_data_len, SECOidTag hashOIDTag);
+
+  SECItem CMSitem;
+  NSSCMSMessage *CMSMessage = NULL;
+  NSSCMSSignedData *CMSSignedData = NULL;
+  NSSCMSSignerInfo *CMSSignerInfo = NULL;
+  CERTCertificate **temp_certs = NULL;
+};
+
+#endif
diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc
new file mode 100644
index 0000000..418d235
--- /dev/null
+++ b/poppler/SignatureInfo.cc
@@ -0,0 +1,86 @@
+//========================================================================
+//
+// SignatureInfo.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+//
+//========================================================================
+
+#include <config.h>
+
+#include "SignatureInfo.h"
+#include "goo/gmem.h"
+#include <stdlib.h>
+#include <string.h>
+
+/* Constructor & Destructor */
+
+SignatureInfo::SignatureInfo()
+{
+  sig_status = SIGNATURE_NOT_VERIFIED;
+  cert_status = CERTIFICATE_NOT_VERIFIED;
+  signer_name = NULL;
+  signing_time = 0;
+  sig_subfilter_supported = false;
+}
+
+SignatureInfo::SignatureInfo(SignatureValidationStatus sig_val_status, CertificateValidationStatus cert_val_status)
+{
+  sig_status = sig_val_status;
+  cert_status = cert_val_status;
+  signer_name = NULL;
+  signing_time = 0;
+  sig_subfilter_supported = false;
+}
+
+SignatureInfo::~SignatureInfo()
+{
+  free(signer_name);
+}
+
+/* GETTERS */
+
+SignatureValidationStatus SignatureInfo::getSignatureValStatus()
+{
+  return sig_status;
+}
+
+CertificateValidationStatus SignatureInfo::getCertificateValStatus()
+{
+  return cert_status;
+}
+
+char *SignatureInfo::getSignerName()
+{
+  return signer_name;
+}
+
+time_t SignatureInfo::getSigningTime()
+{
+  return signing_time;
+}
+
+/* SETTERS */
+
+void SignatureInfo::setSignatureValStatus(enum SignatureValidationStatus sig_val_status)
+{
+  sig_status = sig_val_status;
+}
+
+void SignatureInfo::setCertificateValStatus(enum CertificateValidationStatus cert_val_status)
+{
+  cert_status = cert_val_status;
+}
+
+void SignatureInfo::setSignerName(char *signerName)
+{
+  signer_name = signerName;
+}
+
+void SignatureInfo::setSigningTime(time_t signingTime)
+{
+  signing_time = signingTime;
+}
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
new file mode 100644
index 0000000..e46349c
--- /dev/null
+++ b/poppler/SignatureInfo.h
@@ -0,0 +1,66 @@
+//========================================================================
+//
+// SignatureInfo.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+//
+//========================================================================
+
+#ifndef SIGNATUREINFO_H
+#define SIGNATUREINFO_H
+
+#include <time.h>
+
+enum SignatureValidationStatus
+{
+  SIGNATURE_VALID,
+  SIGNATURE_INVALID,
+  SIGNATURE_DIGEST_MISMATCH,
+  SIGNATURE_DECODING_ERROR,
+  SIGNATURE_GENERIC_ERROR,
+  SIGNATURE_NOT_FOUND,
+  SIGNATURE_NOT_VERIFIED
+};
+
+enum CertificateValidationStatus
+{
+  CERTIFICATE_TRUSTED,
+  CERTIFICATE_UNTRUSTED,
+  CERTIFICATE_REVOKED,
+  CERTIFICATE_EXPIRED,
+  CERTIFICATE_GENERIC_ERROR,
+  CERTIFICATE_NOT_VERIFIED
+};
+
+class SignatureInfo {
+public:
+  SignatureInfo();
+  SignatureInfo(SignatureValidationStatus, CertificateValidationStatus);
+  ~SignatureInfo();
+
+  /* GETTERS */
+  SignatureValidationStatus getSignatureValStatus();
+  CertificateValidationStatus getCertificateValStatus();
+  char *getSignerName();
+  time_t getSigningTime();
+  bool isSubfilterSupported() { return sig_subfilter_supported; }
+
+  /* SETTERS */
+  void setSignatureValStatus(enum SignatureValidationStatus );
+  void setCertificateValStatus(enum CertificateValidationStatus );
+  void setSignerName(char *);
+  void setSigningTime(time_t);
+  void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; }
+
+private:
+  SignatureValidationStatus sig_status;
+  CertificateValidationStatus cert_status;
+  char *signer_name;
+  time_t signing_time;
+  bool sig_subfilter_supported;
+};
+
+#endif
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index e533ff8..ea56bd2 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -89,6 +89,14 @@ target_link_libraries(pdfinfo ${common_libs})
 install(TARGETS pdfinfo DESTINATION bin)
 install(FILES pdfinfo.1 DESTINATION ${SHARE_INSTALL_DIR}/man/man1)
 
+# pdfsigverify
+set(pdfsigverify_SOURCES ${common_srcs}
+  pdfsigverify.cc
+)
+add_executable(pdfsigverify ${pdfsigverify_SOURCES})
+target_link_libraries(pdfsigverify ${common_libs})
+install(TARGETS pdfsigverify DESTINATION bin)
+
 # pdftops
 set(pdftops_SOURCES ${common_srcs}
   pdftops.cc
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 376d021..318cfb6 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -23,6 +23,7 @@ bin_PROGRAMS =					\
 	pdftotext				\
 	pdftohtml				\
 	pdfseparate				\
+	pdfsigverify				\
 	pdfunite
 
 if BUILD_SPLASH_OUTPUT
@@ -60,6 +61,9 @@ pdfdetach_SOURCES =				\
 pdffonts_SOURCES =				\
 	pdffonts.cc
 
+pdfsigverify_SOURCES =				\
+	pdfsigverify.cc
+
 pdfimages_SOURCES =				\
 	pdfimages.cc				\
 	ImageOutputDev.cc			\
diff --git a/utils/pdfsigverify.cc b/utils/pdfsigverify.cc
new file mode 100644
index 0000000..cb37d4f
--- /dev/null
+++ b/utils/pdfsigverify.cc
@@ -0,0 +1,174 @@
+//========================================================================
+//
+// pdfsigverify.cc
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
+// Copyright 2015 André Esser <bepandre at hotmail.com>
+//
+//========================================================================
+
+#include "config.h"
+#include <poppler-config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <time.h>
+#include "parseargs.h"
+#include "Object.h"
+#include "Array.h"
+#include "Page.h"
+#include "PDFDoc.h"
+#include "PDFDocFactory.h"
+#include "Error.h"
+#include "GlobalParams.h"
+
+
+const char * getReadableSigState(SignatureValidationStatus sig_vs)
+{
+  switch(sig_vs) {
+    case SIGNATURE_VALID:
+      return "Signature is Valid.";
+
+    case SIGNATURE_INVALID:
+      return "Signature is Invalid.";
+
+    case SIGNATURE_DIGEST_MISMATCH:
+      return "Digest Mismatch.";
+
+    case SIGNATURE_DECODING_ERROR:
+      return "Document isn't signed or corrupted data.";
+
+    case SIGNATURE_NOT_VERIFIED:
+      return "Signature has not yet been verified.";
+
+    default:
+      return "Unknown Validation Failure.";
+  }
+}
+
+const char * getReadableCertState(CertificateValidationStatus cert_vs)
+{
+  switch(cert_vs) {
+    case CERTIFICATE_TRUSTED:
+      return "Certificate is Trusted.";
+
+    case CERTIFICATE_UNTRUSTED:
+      return "Certificate isn't Trusted.";
+
+    case CERTIFICATE_REVOKED:
+      return "Certificate has been Revoked.";
+
+    case CERTIFICATE_EXPIRED:
+      return "Certificate has Expired";
+
+    case CERTIFICATE_NOT_VERIFIED:
+      return "Certificate has not yet been verified.";
+
+    default:
+      return "Unknown issue with Certificate or corrupted data.";
+  }
+}
+
+char *getReadableTime(time_t unix_time)
+{
+  char * time_str = (char *) gmalloc(64);
+  strftime(time_str, 64, "%b %d %Y %H:%M:%S", localtime(&unix_time));
+  return time_str;
+}
+
+static GBool printVersion = gFalse;
+static GBool printHelp = gFalse;
+static GBool dontVerifyCert = gFalse;
+
+static const ArgDesc argDesc[] = {
+  {"-v",      argFlag,     &printVersion,  0,
+   "print copyright and version info"},
+  {"-h",      argFlag,     &printHelp,     0,
+   "print usage information"},
+  {"-help",   argFlag,     &printHelp,     0,
+   "print usage information"},
+  {"-c",      argFlag,     &dontVerifyCert,     0,
+   "don't perform certificate validation"},
+  {NULL}
+};
+
+
+int main(int argc, char *argv[])
+{
+  PDFDoc *doc = NULL;
+  unsigned int sigCount;
+  GooString * fileName = NULL;
+  SignatureInfo *sig_info = NULL;
+  char *time_str = NULL;
+  std::vector<FormWidgetSignature*> sig_widgets;
+  globalParams = new GlobalParams();
+
+  int exitCode = 99;
+  GBool ok;
+
+  ok = parseArgs(argDesc, &argc, argv);
+
+  if (!ok || argc != 2 || printVersion || printHelp) {
+    fprintf(stderr, "pdfsigverify version %s\n", PACKAGE_VERSION);
+    fprintf(stderr, "%s\n", popplerCopyright);
+    fprintf(stderr, "%s\n", xpdfCopyright);
+    if (!printVersion) {
+      printUsage("pdfsigverify", "<PDF-file>", argDesc);
+    }
+    if (printVersion || printHelp)
+      exitCode = 0;
+    goto end;
+  }
+
+  fileName = new GooString(argv[argc - 1]);
+
+  // open PDF file
+  doc = PDFDocFactory().createPDFDoc(*fileName, NULL, NULL);
+
+  if (!doc->isOk()) {
+    goto end;
+    exitCode = 1;
+  }
+
+  sigCount = doc->countSignatures();
+
+  if (sigCount >= 1) {
+    printf("Digital Signature Info of: %s\n", fileName->getCString());
+  } else {
+    printf("File '%s' does not contain any signatures\n", fileName->getCString());
+    exitCode = 2;
+    goto end;
+  }
+
+  sig_widgets = doc->getSignatureWidgets();
+  if (sig_widgets.size() == 0)
+    goto end;
+
+  for(unsigned int i = 0; i < sigCount; i++) {
+    sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false);
+    printf("Signature #%d:\n", i+1);
+    printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
+    printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
+    printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
+    if (sig_info->getSignatureValStatus() != SIGNATURE_VALID || dontVerifyCert) {
+      continue;
+    }
+    printf("  - Certificate Validation: %s\n", getReadableCertState(sig_info->getCertificateValStatus()));
+    gfree(time_str);
+    delete sig_info;
+  }
+
+  exitCode = 0;
+
+end:
+  delete globalParams;
+  if (fileName)
+    delete fileName;
+  if (doc)
+    delete doc;
+
+  return exitCode;
+}


More information about the poppler mailing list