[poppler] 2 commits - poppler/Form.cc poppler/Form.h poppler/SignatureHandler.cc poppler/SignatureHandler.h poppler/SignatureInfo.cc poppler/SignatureInfo.h qt5/src utils/pdfsig.1 utils/pdfsig.cc
Albert Astals Cid
aacid at kemper.freedesktop.org
Tue Aug 15 10:57:18 UTC 2017
poppler/Form.cc | 171 ++++++++++++++++++++++++++++++++++++++++++--
poppler/Form.h | 28 ++++++-
poppler/SignatureHandler.cc | 34 +++++++-
poppler/SignatureHandler.h | 8 +-
poppler/SignatureInfo.cc | 38 +++++++++
poppler/SignatureInfo.h | 11 ++
qt5/src/poppler-form.cc | 120 ++++++++++++++++++++++++++++++
qt5/src/poppler-form.h | 77 +++++++++++++++++++
utils/pdfsig.1 | 6 +
utils/pdfsig.cc | 66 ++++++++++++++++
10 files changed, 533 insertions(+), 26 deletions(-)
New commits:
commit b56a697c58bcf09063827b9c109be9c04a033b8a
Author: Albert Astals Cid <aacid at kde.org>
Date: Tue Aug 15 12:25:26 2017 +0200
Improvements to the previous Signature commit
* Remove FormWidgetSignature::setFormSignatureType, the API was weird,
make it be an output parameter of getCheckedSignature
* include cleanup
* Make validation time mandatory, marking to use -1 for *now*
* Remove setFormSignatureType noone uses
* Fix compilation wihtout NSS3
* Don't static cast between NSS3 HASH_HashType and poppler-qt5 HashAlgorithm
* Actually pass validationTime down in FormFieldSignature::validate
* Add since markers to poppler-qt5 functions/enums
* Fix spacing
* Remove SignatureValidationInfo::signingDateTime that returns
QDateTime, having two functions that return the same is a bit confusing,
and we're not filling the timezone info anyway, so let it be a time_t
diff --git a/poppler/Form.cc b/poppler/Form.cc
index fac4e6ac..0f4718ed 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -33,7 +33,6 @@
#include <string.h>
#include "goo/gmem.h"
#include "goo/GooString.h"
-#include "goo/GooList.h"
#include "Error.h"
#include "Object.h"
#include "Array.h"
@@ -439,7 +438,6 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu
FormWidget(docA, aobj, num, ref, p)
{
type = formSignature;
- file_size = 0;
}
SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime)
@@ -451,7 +449,7 @@ std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds()
{
Object* obj = static_cast<FormFieldSignature*>(field)->getByteRange();
std::vector<Goffset> range_vec;
- if (obj && obj->isArray())
+ if (obj->isArray())
{
if (obj->arrayGetLength() == 4)
{
@@ -472,7 +470,7 @@ std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds()
return range_vec;
}
-GooString* FormWidgetSignature::getCheckedSignature()
+GooString* FormWidgetSignature::getCheckedSignature(Goffset *checkedFileSize)
{
Goffset start = 0;
Goffset end = 0;
@@ -485,7 +483,7 @@ GooString* FormWidgetSignature::getCheckedSignature()
if (end >= start+6)
{
BaseStream* stream = doc->getBaseStream();
- file_size = stream->getLength();
+ *checkedFileSize = stream->getLength();
Goffset len = end-start;
stream->setPos(end-1);
int c2 = stream->lookChar();
@@ -498,7 +496,7 @@ GooString* FormWidgetSignature::getCheckedSignature()
// 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 == '>')
+ if (len <= std::numeric_limits<int>::max() && *checkedFileSize > end && c1 == '<' && c2 == '>')
{
GooString gstr;
++start;
@@ -1488,7 +1486,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),
- signature_type(adbe_pkcs7_detached), byte_range(),
+ signature_type(adbe_pkcs7_detached),
signature(nullptr), signature_info(nullptr)
{
signature = NULL;
@@ -1575,11 +1573,6 @@ FormSignatureType FormWidgetSignature::signatureType()
return static_cast<FormFieldSignature*>(field)->signature_type;
}
-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
diff --git a/poppler/Form.h b/poppler/Form.h
index 91808c98..8498752e 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -28,11 +28,9 @@
#include "Object.h"
#include "Annot.h"
-#include <list>
#include <set>
#include <vector>
-class GooList;
class GooString;
class Array;
class Dict;
@@ -263,22 +261,17 @@ public:
void updateWidgetAppearance() override;
FormSignatureType signatureType();
- void setFormSignatureType(FormSignatureType type);
- SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime = -1);
+ // Use -1 for now as validationTime
+ SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime);
// 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;
+ // if the check passed (and the checked file size as output parameter in checkedFileSize)
+ // otherwise a nullptr is returned
+ GooString* getCheckedSignature(Goffset *checkedFileSize);
};
//------------------------------------------------------------------------
@@ -521,7 +514,8 @@ 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, time_t validationTime = -1);
+ // Use -1 for now as validationTime
+ SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime);
~FormFieldSignature();
Object* getByteRange() { return &byte_range; }
diff --git a/poppler/SignatureHandler.h b/poppler/SignatureHandler.h
index 715ab9ff..3b2f62b9 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -6,7 +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>
+// Copyright 2015, 2017 Albert Astals Cid <aacid at kde.org>
// Copyright 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
//
//========================================================================
@@ -42,7 +42,8 @@ public:
void setSignature(unsigned char *, int);
void updateHash(unsigned char * data_block, int data_len);
NSSCMSVerificationStatus validateSignature();
- SECErrorCodes validateCertificate(time_t validation_time = -1);
+ // Use -1 as validation_time for now
+ SECErrorCodes validateCertificate(time_t validation_time);
//Translate NSS error codes
static SignatureValidationStatus NSS_SigTranslate(NSSCMSVerificationStatus nss_code);
diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc
index 86b1cfa5..7ca8b969 100644
--- a/poppler/SignatureInfo.cc
+++ b/poppler/SignatureInfo.cc
@@ -7,6 +7,7 @@
// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
// Copyright 2015 André Esser <bepandre at hotmail.com>
// Copyright 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
+// Copyright 2017 Albert Astals Cid <aacid at kde.org>
//
//========================================================================
@@ -17,7 +18,11 @@
#include <stdlib.h>
#include <string.h>
-#include <hasht.h>
+#ifdef ENABLE_NSS3
+ #include <hasht.h>
+#else
+ static const int HASH_AlgNULL = -1;
+#endif
/* Constructor & Destructor */
diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h
index 7ed44283..35e7568c 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -6,7 +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>
+// Copyright 2015, 2017 Albert Astals Cid <aacid at kde.org>
// Copyright 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
//
//========================================================================
@@ -49,7 +49,7 @@ public:
CertificateValidationStatus getCertificateValStatus();
const char *getSignerName();
const char *getSubjectDN();
- int getHashAlgorithm();
+ int getHashAlgorithm(); // Returns a NSS3 HASH_HashType or -1 if compiled without NSS3
time_t getSigningTime();
bool isSubfilterSupported() { return sig_subfilter_supported; }
diff --git a/qt5/src/poppler-form.cc b/qt5/src/poppler-form.cc
index 859273a6..02c3a5d3 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -38,18 +38,9 @@
#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
-};
+#ifdef ENABLE_NSS3
+ #include <hasht.h>
+#endif
namespace {
@@ -513,7 +504,27 @@ QString SignatureValidationInfo::signerSubjectDN() const
SignatureValidationInfo::HashAlgorithm SignatureValidationInfo::hashAlgorithm() const
{
Q_D(const SignatureValidationInfo);
- return static_cast<HashAlgorithm>(d->hash_algorithm);
+
+#ifdef ENABLE_NSS3
+ switch (d->hash_algorithm)
+ {
+ case HASH_AlgMD2:
+ return HashAlgorithmMd2;
+ case HASH_AlgMD5:
+ return HashAlgorithmMd5;
+ case HASH_AlgSHA1:
+ return HashAlgorithmSha1;
+ case HASH_AlgSHA256:
+ return HashAlgorithmSha256;
+ case HASH_AlgSHA384:
+ return HashAlgorithmSha384;
+ case HASH_AlgSHA512:
+ return HashAlgorithmSha512;
+ case HASH_AlgSHA224:
+ return HashAlgorithmSha224;
+ }
+#endif
+ return HashAlgorithmUnknown;
}
time_t SignatureValidationInfo::signingTime() const
@@ -522,11 +533,6 @@ time_t SignatureValidationInfo::signingTime() const
return d->signing_time;
}
-QDateTime SignatureValidationInfo::signingDateTime() const
-{
- return QDateTime::fromTime_t(signingTime());
-}
-
QByteArray SignatureValidationInfo::signature() const
{
Q_D(const SignatureValidationInfo);
@@ -581,7 +587,7 @@ FormField::FormType FormFieldSignature::type() const
{
return FormField::FormSignature;
}
-
+
FormFieldSignature::SignatureType FormFieldSignature::signatureType() const
{
SignatureType sigType = AdbePkcs7detached;
@@ -609,7 +615,8 @@ SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
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);
+ const time_t validationTimeT = validationTime.isValid() ? validationTime.toTime_t() : -1;
+ SignatureInfo* si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT);
SignatureValidationInfoPrivate* priv = new SignatureValidationInfoPrivate;
switch (si->getSignatureValStatus()) {
case SIGNATURE_VALID:
@@ -664,7 +671,7 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime& v
priv->hash_algorithm = si->getHashAlgorithm();
priv->signing_time = si->getSigningTime();
- std::vector<Goffset> ranges = fws->getSignedRangeBounds();
+ const std::vector<Goffset> ranges = fws->getSignedRangeBounds();
if (!ranges.empty())
{
for (Goffset bound : ranges)
@@ -672,11 +679,10 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime& v
priv->range_bounds.append(bound);
}
}
- GooString* checkedSignature = fws->getCheckedSignature();
+ GooString* checkedSignature = fws->getCheckedSignature(&priv->docLength);
if (priv->range_bounds.size() == 4 && checkedSignature)
{
priv->signature = QByteArray::fromHex(checkedSignature->getCString());
- priv->docLength = fws->getCheckedFileSize();
}
delete checkedSignature;
diff --git a/qt5/src/poppler-form.h b/qt5/src/poppler-form.h
index 7a8d5756..e39d6a26 100644
--- a/qt5/src/poppler-form.h
+++ b/qt5/src/poppler-form.h
@@ -405,19 +405,19 @@ namespace Poppler {
};
/**
- * The hash algorithme of the signature
+ The hash algorithm of the signature
+ \since 0.58
*/
enum HashAlgorithm
{
- HashAlgNULL = 0,
- HashAlgMD2 = 1,
- HashAlgMD5 = 2,
- HashAlgSHA1 = 3,
- HashAlgSHA256 = 4,
- HashAlgSHA384 = 5,
- HashAlgSHA512 = 6,
- HashAlgSHA224 = 7,
- HashAlgTOTAL
+ HashAlgorithmUnknown,
+ HashAlgorithmMd2,
+ HashAlgorithmMd5,
+ HashAlgorithmSha1,
+ HashAlgorithmSha256,
+ HashAlgorithmSha384,
+ HashAlgorithmSha512,
+ HashAlgorithmSha224
};
/// \cond PRIVATE
@@ -442,11 +442,13 @@ namespace Poppler {
/**
The signer subject distinguished name associated with the signature.
+ \since 0.58
*/
QString signerSubjectDN() const;
/**
The the hash algorithm used for the signature.
+ \since 0.58
*/
HashAlgorithm hashAlgorithm() const;
@@ -454,21 +456,23 @@ namespace Poppler {
The signing time associated with the signature.
*/
time_t signingTime() const;
- QDateTime signingDateTime() const;
/**
Get the signature binary data.
+ \since 0.58
*/
QByteArray signature() const;
/**
Get the bounds of the ranges of the document which are signed.
+ \since 0.58
*/
QList<qint64> signedRangeBounds() const;
/**
Checks whether the signature authenticates the total document
except for the signature itself.
+ \since 0.58
*/
bool signsTotalDocument() const;
@@ -489,14 +493,15 @@ namespace Poppler {
class POPPLER_QT5_EXPORT FormFieldSignature : public FormField {
public:
- /**
- The types of signature fields.
- */
- enum SignatureType {
- AdbePkcs7sha1,
- AdbePkcs7detached,
- EtsiCAdESdetached
- };
+ /**
+ The types of signature fields.
+ \since 0.58
+ */
+ enum SignatureType {
+ AdbePkcs7sha1,
+ AdbePkcs7detached,
+ EtsiCAdESdetached
+ };
/**
The validation options of this signature.
@@ -513,14 +518,26 @@ namespace Poppler {
FormType type() const override;
- SignatureType signatureType() const;
+ /**
+ The signature type
+ \since 0.58
+ */
+ SignatureType signatureType() const;
/**
- Validate the signature.
+ Validate the signature with now as validation time.
Reset signature validatation info of scoped instance.
*/
SignatureValidationInfo validate(ValidateOptions opt) const;
+
+ /**
+ Validate the signature with @p validationTime as validation time.
+
+ Reset signature validatation info of scoped instance.
+
+ \since 0.58
+ */
SignatureValidationInfo validate(int opt, const QDateTime& validationTime) const;
private:
diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc
index b2cc14af..8b5182d9 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -6,7 +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>
+// Copyright 2015, 2017 Albert Astals Cid <aacid at kde.org>
// Copyright 2016 Markus Kilås <digital at markuspage.com>
// Copyright 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
//
@@ -19,7 +19,7 @@
#include <stddef.h>
#include <string.h>
#include <time.h>
-#include "goo/GooList.h"
+#include <hasht.h>
#include "parseargs.h"
#include "Object.h"
#include "Array.h"
@@ -30,20 +30,6 @@
#include "GlobalParams.h"
#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) {
@@ -169,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);
+ sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false, -1 /* now */);
printf("Signature #%u:\n", i+1);
printf(" - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
printf(" - Signer full Distinguished Name: %s\n", sig_info->getSubjectDN());
@@ -222,8 +208,9 @@ int main(int argc, char *argv[])
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])
+ Goffset checked_file_size;
+ GooString* signature = sig_widgets.at(i)->getCheckedSignature(&checked_file_size);
+ if (signature && checked_file_size == ranges[3])
{
printf(" - Total document signed\n");
delete signature;
commit a81700dfa638872fe9641289971ca9a2b50b42ad
Author: Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
Date: Tue Aug 15 10:27:26 2017 +0200
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 aaf96842..fac4e6ac 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 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu
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 @@ GooString *FormFieldChoice::getSelectedChoice() {
// 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 @@ void FormFieldSignature::parseInfo()
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 @@ void FormFieldSignature::parseInfo()
// 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 @@ void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset
#endif
}
+FormSignatureType FormWidgetSignature::signatureType()
+{
+ return static_cast<FormFieldSignature*>(field)->signature_type;
+}
+
+void FormWidgetSignature::setFormSignatureType(FormSignatureType type)
+{
+ static_cast<FormFieldSignature*>(field)->signature_type = type;
+}
-SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation)
+SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime)
{
#ifdef ENABLE_NSS3
if (!signature_info->isSubfilterSupported()) {
@@ -1478,6 +1640,8 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
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 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for
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 c0550084..91808c98 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -14,6 +14,7 @@
// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
// Copyright 2015 André Esser <bepandre at hotmail.com>
// Copyright 2017 Roland Hieber <r.hieber at pengutronix.de>
+// Copyright 2017 Hans-Ulrich Jüttner <huj at 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 @@ enum VariableTextQuadding {
quaddingRightJustified
};
+enum FormSignatureType {
+ adbe_pkcs7_sha1,
+ adbe_pkcs7_detached,
+ ETSI_CAdES_detached
+};
+
class Form;
class FormField;
class FormFieldButton;
@@ -253,7 +262,23 @@ public:
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 @@ protected:
//------------------------------------------------------------------------
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 71644e54..bddc45fe 100644
--- a/poppler/SignatureHandler.cc
+++ b/poppler/SignatureHandler.cc
@@ -9,6 +9,7 @@
// Copyright 2015, 2016 Albert Astals Cid <aacid at kde.org>
// Copyright 2015 Markus Kilås <digital at markuspage.com>
// Copyright 2017 Sebastian Rasmussen <sebras at gmail.com>
+// Copyright 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
//
//========================================================================
@@ -47,6 +48,26 @@ char *SignatureHandler::getSignerName()
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 @@ time_t SignatureHandler::getSigningTime()
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 @@ NSSCMSVerificationStatus SignatureHandler::validateSignature()
}
}
-SECErrorCodes SignatureHandler::validateCertificate()
+SECErrorCodes SignatureHandler::validateCertificate(time_t validation_time)
{
SECErrorCodes retVal;
CERTCertificate *cert;
@@ -282,10 +303,15 @@ SECErrorCodes SignatureHandler::validateCertificate()
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 8e2a4daf..715ab9ff 100644
--- a/poppler/SignatureHandler.h
+++ b/poppler/SignatureHandler.h
@@ -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 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
//
//========================================================================
@@ -36,10 +37,12 @@ public:
~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 8f7ec454..86b1cfa5 100644
--- a/poppler/SignatureInfo.cc
+++ b/poppler/SignatureInfo.cc
@@ -6,6 +6,7 @@
//
// Copyright 2015 André Guerreiro <aguerreiro1985 at gmail.com>
// Copyright 2015 André Esser <bepandre at hotmail.com>
+// Copyright 2017 Hans-Ulrich Jüttner <huj at 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 @@ SignatureInfo::SignatureInfo(SignatureValidationStatus sig_val_status, Certifica
{
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 @@ CertificateValidationStatus SignatureInfo::getCertificateValStatus()
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 @@ void SignatureInfo::setSignerName(char *signerName)
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 82b4ec4d..7ed44283 100644
--- a/poppler/SignatureInfo.h
+++ b/poppler/SignatureInfo.h
@@ -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 2017 Hans-Ulrich Jüttner <huj at froreich-bioscientia.de>
//
//========================================================================
@@ -46,7 +47,9 @@ public:
/* 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 @@ public:
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 @@ private:
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 6cbceb04..859273a6 100644
--- a/qt5/src/poppler-form.cc
+++ b/qt5/src/poppler-form.cc
@@ -4,6 +4,7 @@
* Copyright (C) 2011 Carlos Garcia Campos <carlosgc at gnome.org>
* Copyright (C) 2012, Adam Reichold <adamreichold at myopera.com>
* Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
+ * Copyright (C) 2017, Hans-Ulrich Jüttner <huj at 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 @@ struct SignatureValidationInfoPrivate {
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 @@ QString SignatureValidationInfo::signerName() const
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 @@ FormField::FormType FormFieldSignature::type() const
{
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 @@ SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
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 44928b34..7a8d5756 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 at kde.org>
* Copyright (C) 2012, Adam Reichold <adamreichold at myopera.com>
* Copyright (C) 2016, Hanno Meyer-Thurow <h.mth at web.de>
+ * Copyright (C) 2017, Hans-Ulrich Jüttner <huj at 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 @@ namespace Poppler {
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 @@ namespace Poppler {
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 @@ namespace Poppler {
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 @@ namespace Poppler {
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 8029ff07..99ca056d 100644
--- a/utils/pdfsig.1
+++ b/utils/pdfsig.1
@@ -9,7 +9,11 @@ pdfsig \- Portable Document Format (PDF) digital signatures tool
.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 2190fea4..b2cc14af 100644
--- a/utils/pdfsig.cc
+++ b/utils/pdfsig.cc
@@ -8,6 +8,7 @@
// 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>
+// Copyright 2017 Hans-Ulrich Jüttner <huj at 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 @@ int main(int argc, char *argv[])
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) {
More information about the poppler
mailing list