diff options
-rw-r--r-- | poppler/Catalog.cc | 4 | ||||
-rw-r--r-- | poppler/Dict.cc | 17 | ||||
-rw-r--r-- | poppler/Dict.h | 3 | ||||
-rw-r--r-- | poppler/Stream.cc | 8 | ||||
-rw-r--r-- | poppler/Stream.h | 7 | ||||
-rw-r--r-- | poppler/XRef.cc | 29 | ||||
-rw-r--r-- | poppler/XRef.h | 4 |
7 files changed, 68 insertions, 4 deletions
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc index f1afc6e5..05498c3b 100644 --- a/poppler/Catalog.cc +++ b/poppler/Catalog.cc @@ -102,9 +102,9 @@ Catalog::Catalog(PDFDoc *docA) { acroForm = catDict.dictLookup("AcroForm"); // read base URI - Object obj = catDict.dictLookup("URI"); + Object obj = catDict.getDict()->lookupEnsureEncryptedIfNeeded("URI"); if (obj.isDict()) { - Object obj2 = obj.dictLookup("Base"); + Object obj2 = obj.getDict()->lookupEnsureEncryptedIfNeeded("Base"); if (obj2.isString()) { baseURI = obj2.getString()->copy(); } diff --git a/poppler/Dict.cc b/poppler/Dict.cc index 77b8ee18..61b89c2e 100644 --- a/poppler/Dict.cc +++ b/poppler/Dict.cc @@ -180,6 +180,23 @@ Object Dict::lookup(const char *key, Ref *returnRef, int recursion) const { return Object(objNull); } +Object Dict::lookupEnsureEncryptedIfNeeded(const char *key) const +{ + const auto *entry = find(key); + if (!entry) + return Object(objNull); + + if (entry->second.getType() == objRef && + xref->isEncrypted() && + !xref->isRefEncrypted(entry->second.getRef())) + { + error(errSyntaxError, -1, "{0:s} is not encrypted and the document is. This may be a hacking attempt", key); + return Object(objNull); + } + + return entry->second.fetch(xref); +} + const Object &Dict::lookupNF(const char *key) const { if (const auto *entry = find(key)) { return entry->second; diff --git a/poppler/Dict.h b/poppler/Dict.h index 287d5a3c..140be8b2 100644 --- a/poppler/Dict.h +++ b/poppler/Dict.h @@ -78,6 +78,9 @@ public: Object lookup(const char *key, int recursion = 0) const; // Same as above but if the returned object is a fetched Ref returns such Ref in returnRef, otherwise returnRef is Ref::INVALID() Object lookup(const char *key, Ref *returnRef, int recursion = 0) const; + // Look up an entry and return the value. Returns a null object + // if <key> is not in the dictionary or if it is a ref to a non encrypted object in a partially encrypted document + Object lookupEnsureEncryptedIfNeeded(const char *key) const; const Object &lookupNF(const char *key) const; bool lookupInt(const char *key, const char *alt_key, int *value) const; diff --git a/poppler/Stream.cc b/poppler/Stream.cc index fa89fc5c..59db9d07 100644 --- a/poppler/Stream.cc +++ b/poppler/Stream.cc @@ -176,6 +176,14 @@ Stream *Stream::addFilters(Dict *dict, int recursion) { return str; } +bool Stream::isEncrypted() const { + for (const Stream *str = this; str != nullptr; str = str->getNextStream()) { + if (str->getKind() == strCrypt) + return true; + } + return false; +} + class BaseStreamStream : public Stream { public: diff --git a/poppler/Stream.h b/poppler/Stream.h index b675bcc6..406840e6 100644 --- a/poppler/Stream.h +++ b/poppler/Stream.h @@ -220,12 +220,15 @@ public: StreamColorSpaceMode * /*csMode*/) {} // Return the next stream in the "stack". - virtual Stream *getNextStream() { return nullptr; } + virtual Stream *getNextStream() const { return nullptr; } // Add filters to this stream according to the parameters in <dict>. // Returns the new stream. Stream *addFilters(Dict *dict, int recursion = 0); + // Returns true if this stream includes a crypt filter. + bool isEncrypted() const; + private: friend class Object; // for incRef/decRef @@ -402,7 +405,7 @@ public: Stream *getUndecodedStream() override { return str->getUndecodedStream(); } Dict *getDict() override { return str->getDict(); } Object *getDictObject() override { return str->getDictObject(); } - Stream *getNextStream() override { return str; } + Stream *getNextStream() const override { return str; } int getUnfilteredChar () override { return str->getUnfilteredChar(); } void unfilteredReset () override { str->unfilteredReset(); } diff --git a/poppler/XRef.cc b/poppler/XRef.cc index 8f9dd7fe..b123ad23 100644 --- a/poppler/XRef.cc +++ b/poppler/XRef.cc @@ -1012,6 +1012,35 @@ void XRef::getEncryptionParameters(unsigned char **fileKeyA, CryptAlgorithm *enc } } +bool XRef::isRefEncrypted(Ref r) +{ + xrefLocker(); + + const XRefEntry *e = getEntry(r.num); + if (!e->obj.isNull()) { //check for updated object + return false; + } + + switch (e->type) { + case xrefEntryUncompressed: + { + return encrypted && !e->getFlag(XRefEntry::Unencrypted); + } + + case xrefEntryCompressed: + { + const Object objStr = fetch(e->offset, 0); + return objStr.getStream()->isEncrypted(); + } + + default: + { + } + } + + return false; +} + bool XRef::okToPrint(bool ignoreOwnerPW) const { return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); } diff --git a/poppler/XRef.h b/poppler/XRef.h index 2e72ae54..8950980b 100644 --- a/poppler/XRef.h +++ b/poppler/XRef.h @@ -128,6 +128,9 @@ public: // Is the file encrypted? bool isEncrypted() const { return encrypted; } + // Is the given Ref encrypted? + bool isRefEncrypted(Ref r); + // Check various permissions. bool okToPrint(bool ignoreOwnerPW = false) const; bool okToPrintHighRes(bool ignoreOwnerPW = false) const; @@ -163,6 +166,7 @@ public: // Return the catalog object reference. int getRootNum() const { return rootNum; } int getRootGen() const { return rootGen; } + Ref getRoot() const { return { rootNum, rootGen }; } // Get end position for a stream in a damaged file. // Returns false if unknown or file is not damaged. |