Comment on attachment 37425 Initial patch for parsing digitally signed PDFs
>diff --git a/poppler/Form.cc b/poppler/Form.cc >index 4df8a7d..1da9776 100644 >--- a/poppler/Form.cc >+++ b/poppler/Form.cc >@@ -1107,11 +1107,28 @@ void FormFieldChoice::_createChoicesTab () > FormFieldSignature::FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref) > : FormField(xrefA, dict, ref, formSignature) > { >+ Object v, contents; >+ >+ if (dict->dictLookup("V", &v)->isDict()) { >+ if (v.dictLookup("Contents", &contents)->isString()) { >+ this->contents = contents.getString()->copy(); >+ v.dictLookup("ByteRange", &byteRange); >+ v.dictLookup("Filter", &filter); >+ v.dictLookup("SubFilter", &subFilter); >+ } >+ contents.free(); >+ } >+ v.free(); > } > > FormFieldSignature::~FormFieldSignature() > { >- >+ if(contents) { >+ delete contents; >+} >+ byteRange.free(); >+ filter.free(); >+ subFilter.free(); > } > > //------------------------------------------------------------------------ >diff --git a/poppler/Form.h b/poppler/Form.h >index 35d66af..e5d1a1f 100644 >--- a/poppler/Form.h >+++ b/poppler/Form.h >@@ -418,6 +418,18 @@ public: > FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref); > > virtual ~FormFieldSignature(); >+ >+ Array* GetByteRange() { return byteRange.getArray(); } >+ GooString* GetContents() const { return contents; } >+ char* GetFilter() { return filter.getName(); } >+ char* GetSubFilter() { return subFilter.getName();} >+ >+protected: >+ GooString* contents; >+ Object byteRange; >+ Object filter; >+ Object subFilter; >+ > }; > > //------------------------------------------------------------------------ >diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc >index ade5fe4..80b5f6c 100644 >--- a/poppler/PDFDoc.cc >+++ b/poppler/PDFDoc.cc >@@ -358,6 +358,25 @@ GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) > return ret; > } > >+#define SIGFLAGS_SIGNATURES_EXIST 0x1 >+#define SIGFLAGS_APPEND_ONLY 0x2 >+ >+GBool PDFDoc::isSigned() { >+ GBool ret; >+ Object sigFlags; >+ >+ getCatalog()->getAcroForm()->dictLookup("SigFlags", &sigFlags); >+ >+ if (sigFlags.isInt()) { >+ ret = sigFlags.getInt() & SIGFLAGS_SIGNATURES_EXIST; >+ } else { >+ ret = gFalse; >+ } >+ sigFlags.free(); >+ >+ return ret; >+} >+ > void PDFDoc::displayPage(OutputDev *out, int page, > double hDPI, double vDPI, int rotate, > GBool useMediaBox, GBool crop, GBool printing, >diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h >index 6d7dea2..22fdb40 100644 >--- a/poppler/PDFDoc.h >+++ b/poppler/PDFDoc.h >@@ -176,6 +176,9 @@ public: > // Is the file encrypted? > GBool isEncrypted() { return xref->isEncrypted(); } > >+ // Is the file signed? >+ GBool isSigned(); >+ > // Check various permissions. > GBool okToPrint(GBool ignoreOwnerPW = gFalse) > { return xref->okToPrint(ignoreOwnerPW); } >diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc >index 2abe8b4..b4b2233 100644 >--- a/utils/pdfinfo.cc >+++ b/utils/pdfinfo.cc >@@ -49,6 +49,7 @@ > #include "PDFDocEncoding.h" > #include "Error.h" > #include "DateInfo.h" >+#include "Form.h" > > static void printInfoString(Dict *infoDict, char *key, char *text, > UnicodeMap *uMap); >@@ -111,6 +112,8 @@ int main(int argc, char *argv[]) { > int exitCode; > int pg, i; > GBool multiPage; >+ Form *form; >+ FormField *formField; > > exitCode = 99; > >@@ -225,6 +228,61 @@ int main(int argc, char *argv[]) { > printf("no\n"); > } > >+ // print signature info >+ printf("Signed: "); >+ if (doc->isSigned()) { >+ printf("yes ("); >+ >+ form = doc->getCatalog()->getForm(); >+ int sigCounter = 0; >+ >+ for (int i = 0; i < form->getNumFields(); i++) { >+ formField = form->getRootField(i); >+ if (formField->getType() == formSignature) { >+ FormFieldSignature* formFieldSig >+ = static_cast<FormFieldSignature*> (formField); >+ >+ GooString* contents = formFieldSig->GetContents(); >+ >+ if (i != 0) { >+ printf("\n "); >+ } >+ >+ printf("Signature %d: encoding:%s length:%d", >+ ++sigCounter, >+ formFieldSig->GetSubFilter(), >+ contents->getLength()); >+ >+// for (int i = 0; i < contents->getLength(); i++) { >+// printf("%x ", contents->getChar(i) & 0xff); >+// } >+// printf("\n"); >+ >+ Array *byteRange = formFieldSig->GetByteRange(); >+ >+ for (int i = 0; i < byteRange->getLength(); i+=2) { >+ Object start, length; >+ byteRange->get(i, &start); >+ byteRange->get(i+1, &length); >+ printf(" bytes: %d-%d", >+ start.getInt(), start.getInt() + length.getInt()); >+ >+ int oldPos = doc->getBaseStream()->getPos(); >+ doc->getBaseStream()->setPos(start.getInt()); >+// for (int j = 0; j < length.getInt(); j++) { >+// printf("%x ", doc->getBaseStream()->getChar() & 0xff); >+// } >+ doc->getBaseStream()->setPos(oldPos); >+ start.free(); >+ length.free(); >+ } >+ } >+ } >+ printf(")\n"); >+ } else { >+ printf("no\n"); >+ } >+ > // print page size > for (pg = firstPage; pg <= lastPage; ++pg) { > w = doc->getPageCropWidth(pg);
Comment on attachment 37425
Initial patch for parsing digitally signed PDFs
>diff --git a/poppler/Form.cc b/poppler/Form.cc ::_createChoice sTab () ure::FormFieldS ignature( XRef *xrefA, Object *dict, const Ref& ref) dictLookup( "V", &v)->isDict()) { "Contents" , &contents) ->isString( )) { getString( )->copy( ); "ByteRange" , &byteRange); "Filter" , &filter); "SubFilter" , &subFilter); ure::~FormField Signature( ) ------- ------- ------- ------- ------- ------- ------- ------- ------- ---- ure(XRef *xrefA, Object *dict, const Ref& ref); ture(); getArray( ); } getName( );} ------- ------- ------- ------- ------- ------- ------- ------- ------- ---- :checkEncryptio n(GooString *ownerPassword, GooString *userPassword) SIGNATURES_ EXIST 0x1 APPEND_ ONLY 0x2 )->getAcroForm( )->dictLookup( "SigFlags" , &sigFlags); SIGNATURES_ EXIST; :displayPage( OutputDev *out, int page, ed(); } (ignoreOwnerPW) ; } (Dict *infoDict, char *key, char *text, ()->getForm( ); lds(); i++) { eld(i); >getType( ) == formSignature) { cast<FormFieldS ignature* > (formField); >GetContents( ); >GetSubFilter( ), >getLength( )); >getLength( ); i++) { >getChar( i) & 0xff); >GetByteRange( ); >getLength( ); i+=2) { eam()-> getPos( ); eam()-> setPos( start.getInt( )); eam()-> getChar( ) & 0xff); eam()-> setPos( oldPos) ; pWidth( pg);
>index 4df8a7d..1da9776 100644
>--- a/poppler/Form.cc
>+++ b/poppler/Form.cc
>@@ -1107,11 +1107,28 @@ void FormFieldChoice
> FormFieldSignat
> : FormField(xrefA, dict, ref, formSignature)
> {
>+ Object v, contents;
>+
>+ if (dict->
>+ if (v.dictLookup(
>+ this->contents = contents.
>+ v.dictLookup(
>+ v.dictLookup(
>+ v.dictLookup(
>+ }
>+ contents.free();
>+ }
>+ v.free();
> }
>
> FormFieldSignat
> {
>-
>+ if(contents) {
>+ delete contents;
>+}
>+ byteRange.free();
>+ filter.free();
>+ subFilter.free();
> }
>
> //-----
>diff --git a/poppler/Form.h b/poppler/Form.h
>index 35d66af..e5d1a1f 100644
>--- a/poppler/Form.h
>+++ b/poppler/Form.h
>@@ -418,6 +418,18 @@ public:
> FormFieldSignat
>
> virtual ~FormFieldSigna
>+
>+ Array* GetByteRange() { return byteRange.
>+ GooString* GetContents() const { return contents; }
>+ char* GetFilter() { return filter.getName(); }
>+ char* GetSubFilter() { return subFilter.
>+
>+protected:
>+ GooString* contents;
>+ Object byteRange;
>+ Object filter;
>+ Object subFilter;
>+
> };
>
> //-----
>diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
>index ade5fe4..80b5f6c 100644
>--- a/poppler/PDFDoc.cc
>+++ b/poppler/PDFDoc.cc
>@@ -358,6 +358,25 @@ GBool PDFDoc:
> return ret;
> }
>
>+#define SIGFLAGS_
>+#define SIGFLAGS_
>+
>+GBool PDFDoc::isSigned() {
>+ GBool ret;
>+ Object sigFlags;
>+
>+ getCatalog(
>+
>+ if (sigFlags.isInt()) {
>+ ret = sigFlags.getInt() & SIGFLAGS_
>+ } else {
>+ ret = gFalse;
>+ }
>+ sigFlags.free();
>+
>+ return ret;
>+}
>+
> void PDFDoc:
> double hDPI, double vDPI, int rotate,
> GBool useMediaBox, GBool crop, GBool printing,
>diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
>index 6d7dea2..22fdb40 100644
>--- a/poppler/PDFDoc.h
>+++ b/poppler/PDFDoc.h
>@@ -176,6 +176,9 @@ public:
> // Is the file encrypted?
> GBool isEncrypted() { return xref->isEncrypt
>
>+ // Is the file signed?
>+ GBool isSigned();
>+
> // Check various permissions.
> GBool okToPrint(GBool ignoreOwnerPW = gFalse)
> { return xref->okToPrint
>diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
>index 2abe8b4..b4b2233 100644
>--- a/utils/pdfinfo.cc
>+++ b/utils/pdfinfo.cc
>@@ -49,6 +49,7 @@
> #include "PDFDocEncoding.h"
> #include "Error.h"
> #include "DateInfo.h"
>+#include "Form.h"
>
> static void printInfoString
> UnicodeMap *uMap);
>@@ -111,6 +112,8 @@ int main(int argc, char *argv[]) {
> int exitCode;
> int pg, i;
> GBool multiPage;
>+ Form *form;
>+ FormField *formField;
>
> exitCode = 99;
>
>@@ -225,6 +228,61 @@ int main(int argc, char *argv[]) {
> printf("no\n");
> }
>
>+ // print signature info
>+ printf("Signed: ");
>+ if (doc->isSigned()) {
>+ printf("yes (");
>+
>+ form = doc->getCatalog
>+ int sigCounter = 0;
>+
>+ for (int i = 0; i < form->getNumFie
>+ formField = form->getRootFi
>+ if (formField-
>+ FormFieldSignature* formFieldSig
>+ = static_
>+
>+ GooString* contents = formFieldSig-
>+
>+ if (i != 0) {
>+ printf("\n ");
>+ }
>+
>+ printf("Signature %d: encoding:%s length:%d",
>+ ++sigCounter,
>+ formFieldSig-
>+ contents-
>+
>+// for (int i = 0; i < contents-
>+// printf("%x ", contents-
>+// }
>+// printf("\n");
>+
>+ Array *byteRange = formFieldSig-
>+
>+ for (int i = 0; i < byteRange-
>+ Object start, length;
>+ byteRange->get(i, &start);
>+ byteRange->get(i+1, &length);
>+ printf(" bytes: %d-%d",
>+ start.getInt(), start.getInt() + length.getInt());
>+
>+ int oldPos = doc->getBaseStr
>+ doc->getBaseStr
>+// for (int j = 0; j < length.getInt(); j++) {
>+// printf("%x ", doc->getBaseStr
>+// }
>+ doc->getBaseStr
>+ start.free();
>+ length.free();
>+ }
>+ }
>+ }
>+ printf(")\n");
>+ } else {
>+ printf("no\n");
>+ }
>+
> // print page size
> for (pg = firstPage; pg <= lastPage; ++pg) {
> w = doc->getPageCro