Prevent an infinite loop in XRef_fetchUncompressed
for encrypted PDF files with indirect objects in the /Encrypt dictionary (issue 7665)
This commit is contained in:
parent
6c263c1994
commit
3e77cf6b32
@ -31,11 +31,12 @@
|
||||
var PasswordException = sharedUtil.PasswordException;
|
||||
var PasswordResponses = sharedUtil.PasswordResponses;
|
||||
var bytesToString = sharedUtil.bytesToString;
|
||||
var warn = sharedUtil.warn;
|
||||
var error = sharedUtil.error;
|
||||
var assert = sharedUtil.assert;
|
||||
var isInt = sharedUtil.isInt;
|
||||
var stringToBytes = sharedUtil.stringToBytes;
|
||||
var utf8StringToString = sharedUtil.utf8StringToString;
|
||||
var warn = sharedUtil.warn;
|
||||
var Name = corePrimitives.Name;
|
||||
var isName = corePrimitives.isName;
|
||||
var isDict = corePrimitives.isDict;
|
||||
@ -1932,6 +1933,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
|
||||
var cfDict = dict.get('CF');
|
||||
var streamCryptoName = dict.get('StmF');
|
||||
if (isDict(cfDict) && isName(streamCryptoName)) {
|
||||
cfDict.suppressEncryption = true; // See comment below.
|
||||
var handlerDict = cfDict.get(streamCryptoName.name);
|
||||
keyLength = (handlerDict && handlerDict.get('Length')) || 128;
|
||||
if (keyLength < 40) {
|
||||
@ -2013,7 +2015,15 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
|
||||
this.encryptionKey = encryptionKey;
|
||||
|
||||
if (algorithm >= 4) {
|
||||
this.cf = dict.get('CF');
|
||||
var cf = dict.get('CF');
|
||||
if (isDict(cf)) {
|
||||
// The 'CF' dictionary itself should not be encrypted, and by setting
|
||||
// `suppressEncryption` we can prevent an infinite loop inside of
|
||||
// `XRef_fetchUncompressed` if the dictionary contains indirect objects
|
||||
// (fixes issue7665.pdf).
|
||||
cf.suppressEncryption = true;
|
||||
}
|
||||
this.cf = cf;
|
||||
this.stmf = dict.get('StmF') || identityName;
|
||||
this.strf = dict.get('StrF') || identityName;
|
||||
this.eff = dict.get('EFF') || this.stmf;
|
||||
@ -2041,6 +2051,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
|
||||
}
|
||||
|
||||
function buildCipherConstructor(cf, name, num, gen, key) {
|
||||
assert(isName(name), 'Invalid crypt filter name.');
|
||||
var cryptFilter = cf.get(name.name);
|
||||
var cfm;
|
||||
if (cryptFilter !== null && cryptFilter !== undefined) {
|
||||
|
@ -633,6 +633,11 @@ var XRef = (function XRefClosure() {
|
||||
if (encrypt) {
|
||||
var ids = trailerDict.get('ID');
|
||||
var fileId = (ids && ids.length) ? ids[0] : '';
|
||||
// The 'Encrypt' dictionary itself should not be encrypted, and by
|
||||
// setting `suppressEncryption` we can prevent an infinite loop inside
|
||||
// of `XRef_fetchUncompressed` if the dictionary contains indirect
|
||||
// objects (fixes issue7665.pdf).
|
||||
encrypt.suppressEncryption = true;
|
||||
this.encrypt = new CipherTransformFactory(encrypt, fileId,
|
||||
this.password);
|
||||
}
|
||||
@ -1079,11 +1084,11 @@ var XRef = (function XRefClosure() {
|
||||
return null;
|
||||
},
|
||||
|
||||
fetchIfRef: function XRef_fetchIfRef(obj) {
|
||||
fetchIfRef: function XRef_fetchIfRef(obj, suppressEncryption) {
|
||||
if (!isRef(obj)) {
|
||||
return obj;
|
||||
}
|
||||
return this.fetch(obj);
|
||||
return this.fetch(obj, suppressEncryption);
|
||||
},
|
||||
|
||||
fetch: function XRef_fetch(ref, suppressEncryption) {
|
||||
@ -1201,11 +1206,11 @@ var XRef = (function XRefClosure() {
|
||||
return xrefEntry;
|
||||
},
|
||||
|
||||
fetchIfRefAsync: function XRef_fetchIfRefAsync(obj) {
|
||||
fetchIfRefAsync: function XRef_fetchIfRefAsync(obj, suppressEncryption) {
|
||||
if (!isRef(obj)) {
|
||||
return Promise.resolve(obj);
|
||||
}
|
||||
return this.fetchAsync(obj);
|
||||
return this.fetchAsync(obj, suppressEncryption);
|
||||
},
|
||||
|
||||
fetchAsync: function XRef_fetchAsync(ref, suppressEncryption) {
|
||||
|
@ -73,6 +73,7 @@ var Dict = (function DictClosure() {
|
||||
this.map = Object.create(null);
|
||||
this.xref = xref;
|
||||
this.objId = null;
|
||||
this.suppressEncryption = false;
|
||||
this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
|
||||
}
|
||||
|
||||
@ -84,40 +85,40 @@ var Dict = (function DictClosure() {
|
||||
// automatically dereferences Ref objects
|
||||
get: function Dict_get(key1, key2, key3) {
|
||||
var value;
|
||||
var xref = this.xref;
|
||||
var xref = this.xref, suppressEncryption = this.suppressEncryption;
|
||||
if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
|
||||
typeof key2 === 'undefined') {
|
||||
return xref ? xref.fetchIfRef(value) : value;
|
||||
return xref ? xref.fetchIfRef(value, suppressEncryption) : value;
|
||||
}
|
||||
if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
|
||||
typeof key3 === 'undefined') {
|
||||
return xref ? xref.fetchIfRef(value) : value;
|
||||
return xref ? xref.fetchIfRef(value, suppressEncryption) : value;
|
||||
}
|
||||
value = this.map[key3] || null;
|
||||
return xref ? xref.fetchIfRef(value) : value;
|
||||
return xref ? xref.fetchIfRef(value, suppressEncryption) : value;
|
||||
},
|
||||
|
||||
// Same as get(), but returns a promise and uses fetchIfRefAsync().
|
||||
getAsync: function Dict_getAsync(key1, key2, key3) {
|
||||
var value;
|
||||
var xref = this.xref;
|
||||
var xref = this.xref, suppressEncryption = this.suppressEncryption;
|
||||
if (typeof (value = this.map[key1]) !== 'undefined' || key1 in this.map ||
|
||||
typeof key2 === 'undefined') {
|
||||
if (xref) {
|
||||
return xref.fetchIfRefAsync(value);
|
||||
return xref.fetchIfRefAsync(value, suppressEncryption);
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
if (typeof (value = this.map[key2]) !== 'undefined' || key2 in this.map ||
|
||||
typeof key3 === 'undefined') {
|
||||
if (xref) {
|
||||
return xref.fetchIfRefAsync(value);
|
||||
return xref.fetchIfRefAsync(value, suppressEncryption);
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
value = this.map[key3] || null;
|
||||
if (xref) {
|
||||
return xref.fetchIfRefAsync(value);
|
||||
return xref.fetchIfRefAsync(value, suppressEncryption);
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
},
|
||||
@ -125,7 +126,7 @@ var Dict = (function DictClosure() {
|
||||
// Same as get(), but dereferences all elements if the result is an Array.
|
||||
getArray: function Dict_getArray(key1, key2, key3) {
|
||||
var value = this.get(key1, key2, key3);
|
||||
var xref = this.xref;
|
||||
var xref = this.xref, suppressEncryption = this.suppressEncryption;
|
||||
if (!isArray(value) || !xref) {
|
||||
return value;
|
||||
}
|
||||
@ -134,7 +135,7 @@ var Dict = (function DictClosure() {
|
||||
if (!isRef(value[i])) {
|
||||
continue;
|
||||
}
|
||||
value[i] = xref.fetch(value[i]);
|
||||
value[i] = xref.fetch(value[i], suppressEncryption);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user