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 <[email protected]> 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 <[email protected]> // Copyright 2015 André Esser <[email protected]> -// Copyright 2015 Albert Astals Cid <[email protected]> +// Copyright 2015, 2017 Albert Astals Cid <[email protected]> // Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 André Esser <[email protected]> // Copyright 2017 Hans-Ulrich Jüttner <[email protected]> +// Copyright 2017 Albert Astals Cid <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 André Esser <[email protected]> -// Copyright 2015 Albert Astals Cid <[email protected]> +// Copyright 2015, 2017 Albert Astals Cid <[email protected]> // Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 André Esser <[email protected]> -// Copyright 2015 Albert Astals Cid <[email protected]> +// Copyright 2015, 2017 Albert Astals Cid <[email protected]> // Copyright 2016 Markus Kilås <[email protected]> // Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // @@ -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 <[email protected]> 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 <[email protected]> // Copyright 2015 André Esser <[email protected]> // Copyright 2017 Roland Hieber <[email protected]> +// Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 Markus Kilås <[email protected]> // Copyright 2017 Sebastian Rasmussen <[email protected]> +// Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 André Esser <[email protected]> // Copyright 2015 Albert Astals Cid <[email protected]> +// Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 André Esser <[email protected]> +// Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> // Copyright 2015 André Esser <[email protected]> // Copyright 2015 Albert Astals Cid <[email protected]> +// Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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 <[email protected]> * Copyright (C) 2012, Adam Reichold <[email protected]> * Copyright (C) 2016, Hanno Meyer-Thurow <[email protected]> + * Copyright (C) 2017, Hans-Ulrich Jüttner <[email protected]> * * 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 <[email protected]> * Copyright (C) 2012, Adam Reichold <[email protected]> * Copyright (C) 2016, Hanno Meyer-Thurow <[email protected]> + * Copyright (C) 2017, Hans-Ulrich Jüttner <[email protected]> * * 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 <[email protected]> // Copyright 2015 Albert Astals Cid <[email protected]> // Copyright 2016 Markus Kilås <[email protected]> +// Copyright 2017 Hans-Ulrich Jüttner <[email protected]> // //======================================================================== @@ -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) {
_______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
