Various signature related improvements

Export signature via Qt5 interface.
Add support for signatures of SubFilter "ETSI.CAdES.detached".
Add an optional validation time to method validateSignature().
Print full Subject Distinguished Name, signing time, hash algorithm and a statement wether the total document is signed in pdfsig.

Fixes bug #99271
diff --git a/poppler/Form.cc b/poppler/Form.cc
index aaf9684..fac4e6a 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -28,10 +28,12 @@
 #endif
 
 #include <set>
+#include <limits>
 #include <stddef.h>
 #include <string.h>
 #include "goo/gmem.h"
 #include "goo/GooString.h"
+#include "goo/GooList.h"
 #include "Error.h"
 #include "Object.h"
 #include "Array.h"
@@ -437,11 +439,151 @@
 	FormWidget(docA, aobj, num, ref, p)
 {
   type = formSignature;
+  file_size = 0;
 }
 
-SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
+SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime)
 {
-  return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation);
+  return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation, validationTime);
+}
+
+std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds()
+{
+  Object* obj = static_cast<FormFieldSignature*>(field)->getByteRange();
+  std::vector<Goffset> range_vec;
+  if (obj && obj->isArray())
+  {
+    if (obj->arrayGetLength() == 4)
+    {
+      for (int i = 0; i < 2; ++i)
+      {
+        Object offsetObj(obj->arrayGet(2*i));
+        Object lenObj(obj->arrayGet(2*i+1));
+        if (offsetObj.isIntOrInt64() && lenObj.isIntOrInt64())
+        {
+          Goffset offset = offsetObj.getIntOrInt64();
+          Goffset len = lenObj.getIntOrInt64();
+          range_vec.push_back(offset);
+          range_vec.push_back(offset+len);
+        }
+      }
+    }
+  }
+  return range_vec;
+}
+
+GooString* FormWidgetSignature::getCheckedSignature()
+{
+  Goffset start = 0;
+  Goffset end = 0;
+  const std::vector<Goffset> ranges = getSignedRangeBounds();
+  if (ranges.size() == 4)
+  {
+    start = ranges[1];
+    end = ranges[2];
+  }
+  if (end >= start+6)
+  {
+    BaseStream* stream = doc->getBaseStream();
+    file_size = stream->getLength();
+    Goffset len = end-start;
+    stream->setPos(end-1);
+    int c2 = stream->lookChar();
+    stream->setPos(start);
+    int c1 = stream->getChar();
+    // PDF signatures are first ASN1 DER, then hex encoded PKCS#7 structures,
+    // possibly padded with 0 characters and enclosed in '<' and '>'.
+    // The ASN1 DER encoding of a PKCS#7 structure must start with the tag 0x30
+    // for SEQUENCE. The next byte must be 0x80 for ASN1 DER indefinite length
+    // encoding or (0x80 + n) for ASN1 DER definite length encoding
+    // where n is the number of subsequent "length bytes" which big-endian
+    // encode the length of the content of the SEQUENCE following them.
+    if (len <= std::numeric_limits<int>::max() && file_size > end && c1 == '<' && c2 == '>')
+    {
+      GooString gstr;
+      ++start;
+      --end;
+      len = end-start;
+      Goffset pos = 0;
+      do
+      {
+        c1 = stream->getChar();
+        if (c1 == EOF)
+          return nullptr;
+        gstr.append(static_cast<char>(c1));
+      } while (++pos < len);
+      if (gstr.getChar(0) == '3' && gstr.getChar(1) == '0')
+      {
+        if (gstr.getChar(2) == '8' && gstr.getChar(3) == '0')
+        {
+          // ASN1 DER indefinite length encoding:
+          // We only check that all characters up to the enclosing '>'
+          // are hex characters and that there are two hex encoded 0 bytes
+          // just before the enclosing '>' marking the end of the indefinite
+          // length encoding.
+          int paddingCount = 0;
+          while (gstr.getChar(len-1) == '0' && gstr.getChar(len-2) == '0')
+          {
+            ++paddingCount;
+            len -= 2;
+          }
+          if (paddingCount < 2 || len%2 == 1)
+            len = 0;
+        }
+        else if (gstr.getChar(2) == '8')
+        {
+          // ASN1 DER definite length encoding:
+          // We calculate the length of the following bytes from the length bytes and
+          // check that after the length bytes and the following calculated number of
+          // bytes all bytes up to the enclosing '>' character are hex encoded 0 bytes.
+          int lenBytes = gstr.getChar(3) - '0';
+          if (lenBytes > 0 && lenBytes <= 4)
+          {
+            int sigLen = 0;
+            for (int i = 0; i < 2*lenBytes; ++i)
+            {
+              sigLen <<= 4;
+              char c = gstr.getChar(i+4);
+              if (isdigit(c))
+                sigLen += c - '0';
+              else if (isxdigit(c) && c >= 'a')
+                sigLen += c - 'a' + 10;
+              else if (isxdigit(c) && c >= 'A')
+                sigLen += c - 'A' + 10;
+              else
+              {
+                len = 0;
+                break;
+              }
+            }
+            if (sigLen > 0 && 2*(sigLen+lenBytes) <= len-4)
+            {
+              for (int i = 2*(sigLen+lenBytes)+4; i < len; ++i)
+              {
+                if (gstr.getChar(i) != '0')
+                {
+                  len = 0;
+                  break;
+                }
+              }
+            }
+            else
+              len = 0;
+          }
+        }
+        for (int i = 0; i < len; ++i)
+        {
+          if (!isxdigit(gstr.getChar(i)))
+            len = 0;
+        }
+        if (len > 0)
+        {
+          return new GooString(&gstr, 0, len);
+        }
+      }
+    }
+  }
+  return nullptr;
 }
 
 void FormWidgetSignature::updateWidgetAppearance()
@@ -1345,7 +1487,9 @@
 // FormFieldSignature
 //------------------------------------------------------------------------
 FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents)
-  : FormField(docA, dict, ref, parent, usedParents, formSignature)
+  : FormField(docA, dict, ref, parent, usedParents, formSignature),
+    signature_type(adbe_pkcs7_detached), byte_range(),
+    signature(nullptr), signature_info(nullptr)
 {
   signature = NULL;
 
@@ -1375,7 +1519,7 @@
     signature = contents_obj.getString()->copy();
   }
 
-  Object byte_range = sig_dict.dictLookup("ByteRange");
+  byte_range = sig_dict.dictLookup("ByteRange");
 
   // retrieve SigningTime
   Object time_of_signing = sig_dict.dictLookup("M");
@@ -1386,7 +1530,16 @@
 
   // check if subfilter is supported for signature validation, only detached signatures work for now
   Object subfilterName = sig_dict.dictLookup("SubFilter");
-  if (subfilterName.isName("adbe.pkcs7.detached") || subfilterName.isName("adbe.pkcs7.sha1")) {
+  if (subfilterName.isName("adbe.pkcs7.sha1")) {
+    signature_type = adbe_pkcs7_sha1;
+    signature_info->setSubFilterSupport(true);
+  }
+  else if (subfilterName.isName("adbe.pkcs7.detached")) {
+    signature_type = adbe_pkcs7_detached;
+    signature_info->setSubFilterSupport(true);
+  }
+  else if (subfilterName.isName("ETSI.CAdES.detached")) {
+    signature_type = ETSI_CAdES_detached;
     signature_info->setSubFilterSupport(true);
   }
 }
@@ -1417,8 +1570,17 @@
 #endif
 }
 
+FormSignatureType FormWidgetSignature::signatureType()
+{
+  return static_cast<FormFieldSignature*>(field)->signature_type;
+}
 
-SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
+void FormWidgetSignature::setFormSignatureType(FormSignatureType type)
+{
+  static_cast<FormFieldSignature*>(field)->signature_type = type;
+}
+
+SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime)
 {
 #ifdef ENABLE_NSS3
   if (!signature_info->isSubfilterSupported()) {
@@ -1478,6 +1640,8 @@
   sig_val_state = signature_handler.validateSignature();
   signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state));
   signature_info->setSignerName(signature_handler.getSignerName());
+  signature_info->setSubjectDN(signature_handler.getSignerSubjectDN());
+  signature_info->setHashAlgorithm(signature_handler.getHashAlgorithm());
 
   // verify if signature contains a 'signing time' attribute
   if (signature_handler.getSigningTime() != 0) {
@@ -1488,7 +1652,7 @@
     return signature_info;
   }
 
-  cert_val_state = signature_handler.validateCertificate();
+  cert_val_state = signature_handler.validateCertificate(validationTime);
   signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state));
 
 #endif
diff --git a/poppler/Form.h b/poppler/Form.h
index c055008..91808c9 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -14,6 +14,7 @@
 // Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
 // Copyright 2015 André Esser <bepandre@hotmail.com>
 // Copyright 2017 Roland Hieber <r.hieber@pengutronix.de>
+// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
 //
 //========================================================================
 
@@ -27,9 +28,11 @@
 #include "Object.h"
 #include "Annot.h"
 
+#include <list>
 #include <set>
 #include <vector>
 
+class GooList;
 class GooString;
 class Array;
 class Dict;
@@ -62,6 +65,12 @@
   quaddingRightJustified
 };
 
+enum FormSignatureType {
+  adbe_pkcs7_sha1,
+  adbe_pkcs7_detached,
+  ETSI_CAdES_detached
+};
+
 class Form;
 class FormField;
 class FormFieldButton;
@@ -253,7 +262,23 @@
   FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p);
   void updateWidgetAppearance() override;
 
-  SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation);
+  FormSignatureType signatureType();
+  void setFormSignatureType(FormSignatureType type);
+  SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime = -1);
+
+  // returns a list with the boundaries of the signed ranges
+  // the elements of the list are of type Goffset
+  std::vector<Goffset> getSignedRangeBounds();
+
+  // checks the length encoding of the signature and returns the hex encoded signature
+  // if the check passed otherwise a nullptr is returned
+  GooString* getCheckedSignature();
+
+  // this method only gives the correct file size if getCheckedSignature()
+  // has been called before
+  Goffset getCheckedFileSize() const { return file_size; }
+protected:
+  Goffset file_size;
 };
 
 //------------------------------------------------------------------------
@@ -492,16 +517,21 @@
 //------------------------------------------------------------------------
 
 class FormFieldSignature: public FormField {
+  friend class FormWidgetSignature;
 public:
   FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents);
 
-  SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation);
+  SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime = -1);
 
   ~FormFieldSignature();
+  Object* getByteRange() { return &byte_range; }
+  GooString* getSignature() { return signature; }
 
 private:
   void parseInfo();
   void hashSignedDataBlock(SignatureHandler *handler, Goffset block_len);
+
+  FormSignatureType signature_type;
   Object byte_range;
   GooString *signature;
   SignatureInfo *signature_info;
diff --git a/poppler/SignatureHandler.cc b/poppler/SignatureHandler.cc
index 71644e5..bddc45f 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -9,6 +9,7 @@
 // Copyright 2015, 2016 Albert Astals Cid <aacid@kde.org>
 // Copyright 2015 Markus Kilås <digital@markuspage.com>
 // Copyright 2017 Sebastian Rasmussen <sebras@gmail.com>
+// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
 //
 //========================================================================
 
@@ -47,6 +48,26 @@
   return CERT_GetCommonName(&cert->subject);
 }
 
+const char * SignatureHandler::getSignerSubjectDN()
+{
+  if (!CMSSignerInfo)
+    return nullptr;
+
+  CERTCertificate *cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB());
+  if (!cert)
+    return nullptr;
+  return cert->subjectName;
+}
+
+HASH_HashType SignatureHandler::getHashAlgorithm()
+{
+  if (hash_context && hash_context->hashobj)
+  {
+    return hash_context->hashobj->type;
+  }
+  return HASH_AlgNULL;
+}
+
 time_t SignatureHandler::getSigningTime()
 {
   PRTime sTime; // time in microseconds since the epoch
@@ -54,7 +75,7 @@
   if (NSS_CMSSignerInfo_GetSigningTime (CMSSignerInfo, &sTime) != SECSuccess)
     return 0;
 
-  return (time_t) sTime/1000000;
+  return static_cast<time_t>(sTime/1000000);
 }
 
 
@@ -271,7 +292,7 @@
   }
 }
 
-SECErrorCodes SignatureHandler::validateCertificate()
+SECErrorCodes SignatureHandler::validateCertificate(time_t validation_time)
 {
   SECErrorCodes retVal;
   CERTCertificate *cert;
@@ -282,10 +303,15 @@
   if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(CMSSignerInfo, CERT_GetDefaultCertDB())) == NULL)
     CMSSignerInfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
 
-  CERTValInParam inParams[2];
+  PRTime vTime = 0; // time in microseconds since the epoch, special value 0 means now
+  if (validation_time > 0)
+    vTime = 1000000*(PRTime)validation_time;
+  CERTValInParam inParams[3];
   inParams[0].type = cert_pi_revocationFlags;
   inParams[0].value.pointer.revocation = CERT_GetClassicOCSPEnabledSoftFailurePolicy();
-  inParams[1].type = cert_pi_end;
+  inParams[1].type = cert_pi_date;
+  inParams[1].value.scalar.time = vTime;
+  inParams[2].type = cert_pi_end;
 
   CERT_PKIXVerifyCert(cert, certificateUsageEmailSigner, inParams, NULL,
                 CMSSignerInfo->cmsg->pwfn_arg);
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index 8e2a4da..715ab9f 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -7,6 +7,7 @@
 // Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
 // Copyright 2015 André Esser <bepandre@hotmail.com>
 // Copyright 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
 //
 //========================================================================
 
@@ -36,10 +37,12 @@
   ~SignatureHandler();
   time_t getSigningTime();
   char * getSignerName();
+  const char * getSignerSubjectDN();
+  HASH_HashType getHashAlgorithm();
   void setSignature(unsigned char *, int);
   void updateHash(unsigned char * data_block, int data_len);
   NSSCMSVerificationStatus validateSignature();
-  SECErrorCodes validateCertificate();
+  SECErrorCodes validateCertificate(time_t validation_time = -1);
 
   //Translate NSS error codes
   static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code);
diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc
index 8f7ec45..86b1cfa 100644
--- a/poppler/SignatureInfo.cc
+++ b/poppler/SignatureInfo.cc
@@ -6,6 +6,7 @@
 //
 // Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
 // Copyright 2015 André Esser <bepandre@hotmail.com>
+// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
 //
 //========================================================================
 
@@ -16,13 +17,17 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <hasht.h>
+
 /* Constructor & Destructor */
 
 SignatureInfo::SignatureInfo()
 {
   sig_status = SIGNATURE_NOT_VERIFIED;
   cert_status = CERTIFICATE_NOT_VERIFIED;
-  signer_name = NULL;
+  signer_name = nullptr;
+  subject_dn = nullptr;
+  hash_type = HASH_AlgNULL;
   signing_time = 0;
   sig_subfilter_supported = false;
 }
@@ -31,7 +36,9 @@
 {
   sig_status = sig_val_status;
   cert_status = cert_val_status;
-  signer_name = NULL;
+  signer_name = nullptr;
+  subject_dn = nullptr;
+  hash_type = HASH_AlgNULL;
   signing_time = 0;
   sig_subfilter_supported = false;
 }
@@ -53,11 +60,21 @@
   return cert_status;
 }
 
-char *SignatureInfo::getSignerName()
+const char *SignatureInfo::getSignerName()
 {
   return signer_name;
 }
 
+const char *SignatureInfo::getSubjectDN()
+{
+  return subject_dn;
+}
+
+int SignatureInfo::getHashAlgorithm()
+{
+  return hash_type;
+}
+
 time_t SignatureInfo::getSigningTime()
 {
   return signing_time;
@@ -81,6 +98,16 @@
   signer_name = signerName;
 }
 
+void SignatureInfo::setSubjectDN(const char *subjectDN)
+{
+  subject_dn = subjectDN;
+}
+
+void SignatureInfo::setHashAlgorithm(int type)
+{
+  hash_type = type;
+}
+
 void SignatureInfo::setSigningTime(time_t signingTime)
 {
   signing_time = signingTime;
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
index 82b4ec4..7ed4428 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -7,6 +7,7 @@
 // Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
 // Copyright 2015 André Esser <bepandre@hotmail.com>
 // Copyright 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
 //
 //========================================================================
 
@@ -46,7 +47,9 @@
   /* GETTERS */
   SignatureValidationStatus getSignatureValStatus();
   CertificateValidationStatus getCertificateValStatus();
-  char *getSignerName();
+  const char *getSignerName();
+  const char *getSubjectDN();
+  int getHashAlgorithm();
   time_t getSigningTime();
   bool isSubfilterSupported() { return sig_subfilter_supported; }
 
@@ -54,6 +57,8 @@
   void setSignatureValStatus(enum SignatureValidationStatus );
   void setCertificateValStatus(enum CertificateValidationStatus );
   void setSignerName(char *);
+  void setSubjectDN(const char *);
+  void setHashAlgorithm(int);
   void setSigningTime(time_t);
   void setSubFilterSupport(bool isSupported) { sig_subfilter_supported = isSupported; }
 
@@ -64,6 +69,8 @@
   SignatureValidationStatus sig_status;
   CertificateValidationStatus cert_status;
   char *signer_name;
+  const char *subject_dn;
+  int hash_type;
   time_t signing_time;
   bool sig_subfilter_supported;
 };
diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index 6cbceb0..859273a 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -4,6 +4,7 @@
  * Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
  * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth@web.de>
+ * Copyright (C) 2017, Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,6 +36,20 @@
 #include "poppler-annotation-helper.h"
 
 #include <math.h>
+#include <ctype.h>
+
+enum HASH_HashType
+{
+    HASH_AlgNULL = 0,
+    HASH_AlgMD2 = 1,
+    HASH_AlgMD5 = 2,
+    HASH_AlgSHA1 = 3,
+    HASH_AlgSHA256 = 4,
+    HASH_AlgSHA384 = 5,
+    HASH_AlgSHA512 = 6,
+    HASH_AlgSHA224 = 7,
+    HASH_AlgTOTAL
+};
 
 namespace {
 
@@ -447,8 +462,13 @@
 	SignatureValidationInfo::SignatureStatus signature_status;
 	SignatureValidationInfo::CertificateStatus certificate_status;
 
+	QByteArray signature;
 	QString signer_name;
+	QString signer_subject_dn;
+	int hash_algorithm;
 	time_t signing_time;
+	QList<qint64> range_bounds;
+	qint64 docLength;
 };
 
 
@@ -484,12 +504,62 @@
   return d->signer_name;
 }
 
+QString SignatureValidationInfo::signerSubjectDN() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->signer_subject_dn;
+}
+
+SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const
+{
+  Q_D(const SignatureValidationInfo);
+  return static_cast<HashAlgorithm>(d->hash_algorithm);
+}
+
 time_t SignatureValidationInfo::signingTime() const
 {
   Q_D(const SignatureValidationInfo);
   return d->signing_time;
 }
 
+QDateTime SignatureValidationInfo::signingDateTime() const
+{
+  return QDateTime::fromTime_t(signingTime());
+}
+
+QByteArray SignatureValidationInfo::signature() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->signature;
+}
+
+QList<qint64> SignatureValidationInfo::signedRangeBounds() const
+{
+  Q_D(const SignatureValidationInfo);
+  return d->range_bounds;
+}
+
+bool SignatureValidationInfo::signsTotalDocument() const
+{
+  Q_D(const SignatureValidationInfo);
+  if (d->range_bounds.size() == 4 && d->range_bounds.value(0) == 0 &&
+      d->range_bounds.value(1) >= 0 &&
+      d->range_bounds.value(2) > d->range_bounds.value(1) &&
+      d->range_bounds.value(3) >= d->range_bounds.value(2))
+  {
+    // The range from d->range_bounds.value(1) to d->range_bounds.value(2) is
+    // not authenticated by the signature and should only contain the signature
+    // itself padded with 0 bytes. This has been checked in readSignature().
+    // If it failed, d->signature is empty.
+    // A potential range after d->range_bounds.value(3) would be also not
+    // authenticated. Therefore d->range_bounds.value(3) should coincide with
+    // the end of the document.
+    if (d->docLength == d->range_bounds.value(3) && !d->signature.isEmpty())
+      return true;
+  }
+  return false;
+}
+
 SignatureValidationInfo &SignatureValidationInfo::operator=(const SignatureValidationInfo &other)
 {
   if ( this != &other )
@@ -511,9 +581,33 @@
 {
   return FormField::FormSignature;
 }
+ 
+FormFieldSignature::SignatureType FormFieldSignature::signatureType() const
+{
+  SignatureType sigType = AdbePkcs7detached;
+  FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
+  switch (fws->signatureType())
+  {
+    case adbe_pkcs7_sha1:
+      sigType = AdbePkcs7sha1;
+      break;
+    case adbe_pkcs7_detached:
+      sigType = AdbePkcs7detached;
+      break;
+    case ETSI_CAdES_detached:
+      sigType = EtsiCAdESdetached;
+      break;
+  }
+  return sigType;
+}
 
 SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
 {
+  return validate(opt, QDateTime());
+}
+
+SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime& validationTime) const
+{
   FormWidgetSignature* fws = static_cast<FormWidgetSignature*>(m_formData->fm);
   SignatureInfo* si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation);
   SignatureValidationInfoPrivate* priv = new SignatureValidationInfoPrivate;
@@ -566,7 +660,25 @@
       break;
   }
   priv->signer_name = si->getSignerName();
+  priv->signer_subject_dn = si->getSubjectDN();
+  priv->hash_algorithm = si->getHashAlgorithm();
+
   priv->signing_time = si->getSigningTime();
+  std::vector<Goffset> ranges = fws->getSignedRangeBounds();
+  if (!ranges.empty())
+  {
+    for (Goffset bound : ranges)
+    {
+      priv->range_bounds.append(bound);
+    }
+  }
+  GooString* checkedSignature = fws->getCheckedSignature();
+  if (priv->range_bounds.size() == 4 && checkedSignature)
+  {
+    priv->signature = QByteArray::fromHex(checkedSignature->getCString());
+    priv->docLength = fws->getCheckedFileSize();
+  }
+  delete checkedSignature;
 
   return SignatureValidationInfo(priv);
 }
diff --git a/qt5/src/poppler-form.h b/qt5/src/poppler-form.h
index 44928b3..7a8d575 100644
--- a/qt5/src/poppler-form.h
+++ b/qt5/src/poppler-form.h
@@ -3,6 +3,7 @@
  * Copyright (C) 2008, 2011, 2016, 2017, Albert Astals Cid <aacid@kde.org>
  * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
  * Copyright (C) 2016, Hanno Meyer-Thurow <h.mth@web.de>
+ * Copyright (C) 2017, Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +23,8 @@
 #ifndef _POPPLER_QT5_FORM_H_
 #define _POPPLER_QT5_FORM_H_
 
+#include <QtCore/QDateTime>
+#include <QtCore/QList>
 #include <QtCore/QRectF>
 #include <QtCore/QStringList>
 #include <QtCore/QSharedPointer>
@@ -401,6 +404,22 @@
 	    CertificateNotVerified      ///< The certificate is not yet verified.
 	};
 
+	/**
+	 * The hash algorithme of the signature
+	 */
+	enum HashAlgorithm
+	{
+	    HashAlgNULL = 0,
+	    HashAlgMD2 = 1,
+	    HashAlgMD5 = 2,
+	    HashAlgSHA1 = 3,
+	    HashAlgSHA256 = 4,
+	    HashAlgSHA384 = 5,
+	    HashAlgSHA512 = 6,
+	    HashAlgSHA224 = 7,
+	    HashAlgTOTAL
+	};
+
 	/// \cond PRIVATE
 	SignatureValidationInfo(SignatureValidationInfoPrivate *priv);
 	/// \endcond
@@ -422,9 +441,36 @@
 	QString signerName() const;
 
 	/**
+	  The signer subject distinguished name associated with the signature.
+	 */
+	QString signerSubjectDN() const;
+
+	/**
+	  The the hash algorithm used for the signature.
+	 */
+	HashAlgorithm hashAlgorithm() const;
+
+	/**
 	  The signing time associated with the signature.
 	 */
 	time_t signingTime() const;
+	QDateTime signingDateTime() const;
+
+	/**
+	  Get the signature binary data.
+	 */
+        QByteArray signature() const;
+
+	/**
+	  Get the bounds of the ranges of the document which are signed.
+	 */
+        QList<qint64> signedRangeBounds() const;
+
+	/**
+	  Checks whether the signature authenticates the total document
+          except for the signature itself.
+	 */
+        bool signsTotalDocument() const;
 
 	SignatureValidationInfo(const SignatureValidationInfo &other);
 	SignatureValidationInfo &operator=(const SignatureValidationInfo &other);
@@ -443,6 +489,15 @@
     class POPPLER_QT5_EXPORT FormFieldSignature : public FormField {
     public:
 
+        /**
+           The types of signature fields.
+         */
+        enum SignatureType {
+            AdbePkcs7sha1,
+            AdbePkcs7detached,
+            EtsiCAdESdetached
+        };
+
 	/**
 	   The validation options of this signature.
 	*/
@@ -458,12 +513,15 @@
 
 	FormType type() const override;
 
+        SignatureType signatureType() const;
+
 	/**
 	  Validate the signature.
 
 	  Reset signature validatation info of scoped instance.
 	 */
 	SignatureValidationInfo validate(ValidateOptions opt) const;
+	SignatureValidationInfo validate(int opt, const QDateTime& validationTime) const;
 
 	private:
 	Q_DISABLE_COPY(FormFieldSignature)
diff --git a/utils/pdfsig.1 b/utils/pdfsig.1
index 8029ff0..99ca056 100644
--- a/utils/pdfsig.1
+++ b/utils/pdfsig.1
@@ -9,7 +9,11 @@
 .SH DESCRIPTION
 .B pdfsig
 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.
+It also displays the identity of each signer
+(commonName field and full distinguished name of the signer certificate),
+the time and date of the signature, the hash algorithm used for signing,
+the type of the signature as stated in the PDF and
+the signed ranges with a statement wether the total document is signed.
 .PP
 The signer certificate validation uses the trusted certificates stored in the following locations:
 .IP \(bu
diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
index 2190fea..b2cc14a 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -8,6 +8,7 @@
 // Copyright 2015 André Esser <bepandre@hotmail.com>
 // Copyright 2015 Albert Astals Cid <aacid@kde.org>
 // Copyright 2016 Markus Kilås <digital@markuspage.com>
+// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
 //
 //========================================================================
 
@@ -18,6 +19,7 @@
 #include <stddef.h>
 #include <string.h>
 #include <time.h>
+#include "goo/GooList.h"
 #include "parseargs.h"
 #include "Object.h"
 #include "Array.h"
@@ -29,6 +31,19 @@
 #include "SignatureInfo.h"
 
 
+enum HASH_HashType
+{
+    HASH_AlgNULL = 0,
+    HASH_AlgMD2 = 1,
+    HASH_AlgMD5 = 2,
+    HASH_AlgSHA1 = 3,
+    HASH_AlgSHA256 = 4,
+    HASH_AlgSHA384 = 5,
+    HASH_AlgSHA512 = 6,
+    HASH_AlgSHA224 = 7,
+    HASH_AlgTOTAL
+};
+
 const char * getReadableSigState(SignatureValidationStatus sig_vs)
 {
   switch(sig_vs) {
@@ -157,7 +172,65 @@
     sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false);
     printf("Signature #%u:\n", i+1);
     printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
+    printf("  - Signer full Distinguished Name: %s\n", sig_info->getSubjectDN());
     printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
+    printf("  - Signing Hash Algorithm: ");
+    switch (sig_info->getHashAlgorithm())
+    {
+      case HASH_AlgMD2:
+        printf("MD2\n");
+        break;
+      case HASH_AlgMD5:
+        printf("MD5\n");
+        break;
+      case HASH_AlgSHA1:
+        printf("SHA1\n");
+        break;
+      case HASH_AlgSHA256:
+        printf("SHA-256\n");
+        break;
+      case HASH_AlgSHA384:
+        printf("SHA-384\n");
+        break;
+      case HASH_AlgSHA512:
+        printf("SHA-512\n");
+        break;
+      case HASH_AlgSHA224:
+        printf("SHA-224\n");
+        break;
+      default:
+        printf("unknown\n");
+    }
+    printf("  - Signature Type: ");
+    switch (sig_widgets.at(i)->signatureType())
+    {
+      case adbe_pkcs7_sha1:
+        printf("adbe.pkcs7.sha1\n");
+        break;
+      case adbe_pkcs7_detached:
+        printf("adbe.pkcs7.detached\n");
+        break;
+      case ETSI_CAdES_detached:
+        printf("ETSI.CAdES.detached\n");
+        break;
+      default:
+        printf("unknown\n");
+    }
+    std::vector<Goffset> ranges = sig_widgets.at(i)->getSignedRangeBounds();
+    if (ranges.size() == 4)
+    {
+      int i = 0;
+      printf("  - Signed Ranges: [%lld - %lld], [%lld - %lld]\n",
+             ranges[0], ranges[1], ranges[2], ranges[3]);
+      GooString* signature = sig_widgets.at(i)->getCheckedSignature();
+      if (signature && sig_widgets.at(i)->getCheckedFileSize() == ranges[3])
+      {
+        printf("  - Total document signed\n");
+        delete signature;
+      }
+      else
+        printf("  - Not total document signed\n");
+    }
     printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
     gfree(time_str);
     if (sig_info->getSignatureValStatus() != SIGNATURE_VALID || dontVerifyCert) {