poppler/Form.cc | 277 ++++++++++++++++++++++++----------------------- poppler/Form.h | 21 ++- poppler/PDFDoc.cc | 39 +++--- poppler/PDFDoc.h | 2 poppler/Page.cc | 1 poppler/SignatureInfo.cc | 12 +- poppler/SignatureInfo.h | 14 +- utils/pdfsig.cc | 54 +++------ 8 files changed, 216 insertions(+), 204 deletions(-)
New commits: commit ba311960d2486e07e66f59dd8d8a5f6e49a918d0 Author: Albert Astals Cid <[email protected]> Date: Thu Apr 9 16:59:54 2020 +0200 pdfsig: Show also signatures that aren't attached to any page Move two methods from FormWidgetSignature to FormFieldSignature where they actually belong Rename PDFDoc::getSignatureWidgets to getSignatureFields, making it go through the FormsFields instead of the Page FormWidgets Remove the gotos from pdfsig code Add a few const here and there Fixes part of #895 diff --git a/poppler/Form.cc b/poppler/Form.cc index 872f1bdd..5018bc9d 100644 --- a/poppler/Form.cc +++ b/poppler/Form.cc @@ -479,143 +479,14 @@ SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool fo return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation, validationTime); } -std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds() +std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds() const { - Object* byteRangeObj = static_cast<FormFieldSignature*>(field)->getByteRange(); - std::vector<Goffset> range_vec; - if (byteRangeObj->isArray()) - { - if (byteRangeObj->arrayGetLength() == 4) - { - for (int i = 0; i < 2; ++i) - { - Object offsetObj(byteRangeObj->arrayGet(2*i)); - Object lenObj(byteRangeObj->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; + return static_cast<FormFieldSignature*>(field)->getSignedRangeBounds(); } GooString* FormWidgetSignature::getCheckedSignature(Goffset *checkedFileSize) { - 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(); - *checkedFileSize = 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() && *checkedFileSize > 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 (Goffset i = 2*(sigLen+lenBytes)+4; i < len; ++i) - { - if (gstr.getChar(i) != '0') - { - len = 0; - break; - } - } - } - else - len = 0; - } - } - for ( const char c : gstr.toStr() ) - { - if (!isxdigit(c)) - len = 0; - } - if (len > 0) - { - return new GooString(&gstr, 0, len); - } - } - } - } - return nullptr; + return static_cast<FormFieldSignature*>(field)->getCheckedSignature(checkedFileSize); } void FormWidgetSignature::updateWidgetAppearance() @@ -1729,9 +1600,9 @@ void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset #endif } -FormSignatureType FormWidgetSignature::signatureType() +FormSignatureType FormWidgetSignature::signatureType() const { - return static_cast<FormFieldSignature*>(field)->signature_type; + return static_cast<FormFieldSignature*>(field)->getSignatureType(); } SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime) @@ -1812,6 +1683,144 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for return signature_info; } +std::vector<Goffset> FormFieldSignature::getSignedRangeBounds() const +{ + std::vector<Goffset> range_vec; + if (byte_range.isArray()) + { + if (byte_range.arrayGetLength() == 4) + { + for (int i = 0; i < 2; ++i) + { + const Object offsetObj(byte_range.arrayGet(2*i)); + const Object lenObj(byte_range.arrayGet(2*i+1)); + if (offsetObj.isIntOrInt64() && lenObj.isIntOrInt64()) + { + const Goffset offset = offsetObj.getIntOrInt64(); + const Goffset len = lenObj.getIntOrInt64(); + range_vec.push_back(offset); + range_vec.push_back(offset+len); + } + } + } + } + return range_vec; +} + +GooString* FormFieldSignature::getCheckedSignature(Goffset *checkedFileSize) +{ + 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(); + *checkedFileSize = 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() && *checkedFileSize > 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 (Goffset i = 2*(sigLen+lenBytes)+4; i < len; ++i) + { + if (gstr.getChar(i) != '0') + { + len = 0; + break; + } + } + } + else + len = 0; + } + } + for ( const char c : gstr.toStr() ) + { + if (!isxdigit(c)) + len = 0; + } + if (len > 0) + { + return new GooString(&gstr, 0, len); + } + } + } + } + return nullptr; +} + void FormFieldSignature::print(int indent) { printf ("%*s- (%d %d): [signature] terminal: %s children: %d\n", indent, "", ref.num, ref.gen, diff --git a/poppler/Form.h b/poppler/Form.h index fae63634..cf5b4a6f 100644 --- a/poppler/Form.h +++ b/poppler/Form.h @@ -268,13 +268,13 @@ public: FormWidgetSignature(PDFDoc *docA, Object *dictObj, unsigned num, Ref ref, FormField *p); void updateWidgetAppearance() override; - FormSignatureType signatureType(); + FormSignatureType signatureType() const; // 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(); + std::vector<Goffset> getSignedRangeBounds() const; // checks the length encoding of the signature and returns the hex encoded signature // if the check passed (and the checked file size as output parameter in checkedFileSize) @@ -318,8 +318,10 @@ public: GooString *getFullyQualifiedName(); FormWidget* findWidgetByRef (Ref aref); - int getNumWidgets() { return terminal ? numChildren : 0; } - FormWidget *getWidget(int i) { return terminal ? widgets[i] : nullptr; } + int getNumWidgets() const { return terminal ? numChildren : 0; } + FormWidget *getWidget(int i) const { return terminal ? widgets[i] : nullptr; } + int getNumChildren() const { return !terminal ? numChildren : 0; } + FormField *getChildren(int i) const { return children[i]; } // only implemented in FormFieldButton virtual void fillChildrenSiblingsID (); @@ -528,16 +530,25 @@ protected: //------------------------------------------------------------------------ class FormFieldSignature: public FormField { - friend class FormWidgetSignature; public: FormFieldSignature(PDFDoc *docA, Object &&dict, const Ref ref, FormField *parent, std::set<int> *usedParents); // 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() const; + + // checks the length encoding of the signature and returns the hex encoded signature + // if the check passed (and the checked file size as output parameter in checkedFileSize) + // otherwise a nullptr is returned + GooString* getCheckedSignature(Goffset *checkedFileSize); + ~FormFieldSignature() override; Object* getByteRange() { return &byte_range; } const GooString* getSignature() const { return signature; } + FormSignatureType getSignatureType() const { return signature_type; } private: void parseInfo(); diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc index f534ce7a..8d506da6 100644 --- a/poppler/PDFDoc.cc +++ b/poppler/PDFDoc.cc @@ -597,25 +597,32 @@ void PDFDoc::extractPDFSubtype() { delete pdfSubtypeVersion; } -std::vector<FormWidgetSignature*> PDFDoc::getSignatureWidgets() +static void addSignatureFieldsToVector(FormField *ff, std::vector<FormFieldSignature*> &res) { - int num_pages = getNumPages(); - FormPageWidgets *page_widgets = nullptr; - std::vector<FormWidgetSignature*> widget_vector; - - for (int i = 1; i <= num_pages; i++) { - Page *p = getCatalog()->getPage(i); - if (p) { - page_widgets = p->getFormWidgets(); - for (int j = 0; page_widgets != nullptr && j < page_widgets->getNumWidgets(); j++) { - if (page_widgets->getWidget(j)->getType() == formSignature) { - widget_vector.push_back(static_cast<FormWidgetSignature*>(page_widgets->getWidget(j))); - } - } - delete page_widgets; + if (ff->getNumChildren() == 0) { + if (ff->getType() == formSignature) { + res.push_back(static_cast<FormFieldSignature*>(ff)); } + } else { + for (int i = 0; i < ff->getNumChildren(); ++i) { + FormField *children = ff->getChildren(i); + addSignatureFieldsToVector(children, res); + } + } +} + +std::vector<FormFieldSignature*> PDFDoc::getSignatureFields() +{ +// const int num_pages = getNumPages(); + std::vector<FormFieldSignature*> res; + + const Form *f = catalog->getForm(); + const int nRootFields = f->getNumFields(); + for (int i = 0; i < nRootFields; ++i) { + FormField *ff = f->getRootField(i); + addSignatureFieldsToVector(ff, res); } - return widget_vector; + return res; } void PDFDoc::displayPage(OutputDev *out, int page, diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h index 7ba64b75..ac881a3a 100644 --- a/poppler/PDFDoc.h +++ b/poppler/PDFDoc.h @@ -239,7 +239,7 @@ public: // Is the file encrypted? bool isEncrypted() { return xref->isEncrypted(); } - std::vector<FormWidgetSignature*> getSignatureWidgets(); + std::vector<FormFieldSignature*> getSignatureFields(); // Check various permissions. bool okToPrint(bool ignoreOwnerPW = false) diff --git a/poppler/Page.cc b/poppler/Page.cc index 5140174a..670768ab 100644 --- a/poppler/Page.cc +++ b/poppler/Page.cc @@ -362,6 +362,7 @@ void Page::replaceXRef(XRef *xrefA) { /* Loads standalone fields into Page, should be called once per page only */ void Page::loadStandaloneFields(Annots *annotations, Form *form) { const int numAnnots = annotations ? annotations->getNumAnnots() : 0; + if (numAnnots < 1) return; diff --git a/poppler/SignatureInfo.cc b/poppler/SignatureInfo.cc index f1ad45e3..c39db409 100644 --- a/poppler/SignatureInfo.cc +++ b/poppler/SignatureInfo.cc @@ -67,22 +67,22 @@ SignatureInfo::~SignatureInfo() /* GETTERS */ -SignatureValidationStatus SignatureInfo::getSignatureValStatus() +SignatureValidationStatus SignatureInfo::getSignatureValStatus() const { return sig_status; } -CertificateValidationStatus SignatureInfo::getCertificateValStatus() +CertificateValidationStatus SignatureInfo::getCertificateValStatus() const { return cert_status; } -const char *SignatureInfo::getSignerName() +const char *SignatureInfo::getSignerName() const { return signer_name; } -const char *SignatureInfo::getSubjectDN() +const char *SignatureInfo::getSubjectDN() const { return subject_dn; } @@ -97,12 +97,12 @@ const char *SignatureInfo::getReason() const return reason; } -int SignatureInfo::getHashAlgorithm() +int SignatureInfo::getHashAlgorithm() const { return hash_type; } -time_t SignatureInfo::getSigningTime() +time_t SignatureInfo::getSigningTime() const { return signing_time; } diff --git a/poppler/SignatureInfo.h b/poppler/SignatureInfo.h index 6de83f62..76a67caa 100644 --- a/poppler/SignatureInfo.h +++ b/poppler/SignatureInfo.h @@ -53,15 +53,15 @@ public: SignatureInfo& operator=(const SignatureInfo &) = delete; /* GETTERS */ - SignatureValidationStatus getSignatureValStatus(); - CertificateValidationStatus getCertificateValStatus(); - const char *getSignerName(); - const char *getSubjectDN(); + SignatureValidationStatus getSignatureValStatus() const; + CertificateValidationStatus getCertificateValStatus() const; + const char *getSignerName() const; + const char *getSubjectDN() const; const char *getLocation() const; const char *getReason() const; - int getHashAlgorithm(); // Returns a NSS3 HASH_HashType or -1 if compiled without NSS3 - time_t getSigningTime(); - bool isSubfilterSupported() { return sig_subfilter_supported; } + int getHashAlgorithm() const; // Returns a NSS3 HASH_HashType or -1 if compiled without NSS3 + time_t getSigningTime() const; + bool isSubfilterSupported() const { return sig_subfilter_supported; } const X509CertificateInfo *getCertificateInfo() const; /* SETTERS */ diff --git a/utils/pdfsig.cc b/utils/pdfsig.cc index 94df5635..2ddfd547 100644 --- a/utils/pdfsig.cc +++ b/utils/pdfsig.cc @@ -97,9 +97,9 @@ static char *getReadableTime(time_t unix_time) return time_str; } -static bool dumpSignature(int sig_num, int sigCount, FormWidgetSignature *sig_widget, const char *filename) +static bool dumpSignature(int sig_num, int sigCount, FormFieldSignature *s, const char *filename) { - const GooString *signature = sig_widget->getSignature(); + const GooString *signature = s->getSignature(); if (!signature) { printf("Cannot dump signature #%d\n", sig_num); return false; @@ -149,19 +149,12 @@ static const ArgDesc argDesc[] = { int main(int argc, char *argv[]) { - PDFDoc *doc = nullptr; - unsigned int sigCount; - GooString * fileName = nullptr; - SignatureInfo *sig_info = nullptr; char *time_str = nullptr; - std::vector<FormWidgetSignature*> sig_widgets; globalParams = std::make_unique<GlobalParams>(); Win32Console win32Console(&argc, &argv); - int exitCode = 99; - bool ok; - ok = parseArgs(argDesc, &argc, argv); + const bool ok = parseArgs(argDesc, &argc, argv); if (!ok || argc != 2 || printVersion || printHelp) { fprintf(stderr, "pdfsig version %s\n", PACKAGE_VERSION); @@ -171,47 +164,44 @@ int main(int argc, char *argv[]) printUsage("pdfsig", "<PDF-file>", argDesc); } if (printVersion || printHelp) - exitCode = 0; - goto end; + return 0; + return 99; } - fileName = new GooString(argv[argc - 1]); + std::unique_ptr<GooString> fileName = std::make_unique<GooString>(argv[argc - 1]); SignatureHandler::setNSSDir(nssDir); // open PDF file - doc = PDFDocFactory().createPDFDoc(*fileName, nullptr, nullptr); + std::unique_ptr<PDFDoc> doc(PDFDocFactory().createPDFDoc(*fileName, nullptr, nullptr)); if (!doc->isOk()) { - exitCode = 1; - goto end; + return 1; } - sig_widgets = doc->getSignatureWidgets(); - sigCount = sig_widgets.size(); + const std::vector<FormFieldSignature*> signatures = doc->getSignatureFields(); + const unsigned int sigCount = signatures.size(); if (sigCount >= 1) { if (dumpSignatures) { - exitCode = 0; printf("Dumping Signatures: %u\n", sigCount); for (unsigned int i = 0; i < sigCount; i++) { - const bool dumpingOk = dumpSignature(i, sigCount, sig_widgets.at(i), fileName->c_str()); + const bool dumpingOk = dumpSignature(i, sigCount, signatures.at(i), fileName->c_str()); if (!dumpingOk) { - exitCode = 3; + return 3; } } - goto end; + return 0; } else { printf("Digital Signature Info of: %s\n", fileName->c_str()); } } else { printf("File '%s' does not contain any signatures\n", fileName->c_str()); - exitCode = 2; - goto end; + return 2; } for (unsigned int i = 0; i < sigCount; i++) { - sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false, -1 /* now */); + const SignatureInfo *sig_info = signatures.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()); @@ -244,7 +234,7 @@ int main(int argc, char *argv[]) printf("unknown\n"); } printf(" - Signature Type: "); - switch (sig_widgets.at(i)->signatureType()) + switch (signatures.at(i)->getSignatureType()) { case adbe_pkcs7_sha1: printf("adbe.pkcs7.sha1\n"); @@ -258,13 +248,13 @@ int main(int argc, char *argv[]) default: printf("unknown\n"); } - std::vector<Goffset> ranges = sig_widgets.at(i)->getSignedRangeBounds(); + std::vector<Goffset> ranges = signatures.at(i)->getSignedRangeBounds(); if (ranges.size() == 4) { printf(" - Signed Ranges: [%lld - %lld], [%lld - %lld]\n", ranges[0], ranges[1], ranges[2], ranges[3]); Goffset checked_file_size; - GooString* signature = sig_widgets.at(i)->getCheckedSignature(&checked_file_size); + GooString* signature = signatures.at(i)->getCheckedSignature(&checked_file_size); if (signature && checked_file_size == ranges[3]) { printf(" - Total document signed\n"); } else { @@ -280,11 +270,5 @@ int main(int argc, char *argv[]) printf(" - Certificate Validation: %s\n", getReadableCertState(sig_info->getCertificateValStatus())); } - exitCode = 0; - -end: - delete fileName; - delete doc; - - return exitCode; + return 0; } _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
