Commit ddf97254 authored by Albert Astals Cid's avatar Albert Astals Cid Committed by Albert Astals Cid

Make sure Base URI is encrypted if the document is before using it

Otherwise we may be being targetted by a link content exfiltration
parent bdafd606
......@@ -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();
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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:
......
......@@ -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(); }
......
......@@ -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);
}
......
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment