beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / SecurityHandler.cc
blob63d8b4e1287981a49639c447899133f1348e076c
1 //========================================================================
2 //
3 // SecurityHandler.cc
4 //
5 // Copyright 2004 Glyph & Cog, LLC
6 //
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
18 // Copyright (C) 2014 Fabio D'Urso <fabiodurso@hotmail.it>
20 // To see a description of the changes please see the Changelog file that
21 // came with your tarball or type make ChangeLog if you are building from git
23 //========================================================================
25 #include <config.h>
27 #ifdef USE_GCC_PRAGMAS
28 #pragma implementation
29 #endif
31 #include "GooString.h"
32 #include "PDFDoc.h"
33 #include "Decrypt.h"
34 #include "Error.h"
35 #include "GlobalParams.h"
36 #ifdef ENABLE_PLUGINS
37 # include "XpdfPluginAPI.h"
38 #endif
39 #include "SecurityHandler.h"
41 #include <limits.h>
43 //------------------------------------------------------------------------
44 // SecurityHandler
45 //------------------------------------------------------------------------
47 SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
48 Object filterObj;
49 SecurityHandler *secHdlr;
50 #ifdef ENABLE_PLUGINS
51 XpdfSecurityHandler *xsh;
52 #endif
54 encryptDictA->dictLookup("Filter", &filterObj);
55 if (filterObj.isName("Standard")) {
56 secHdlr = new StandardSecurityHandler(docA, encryptDictA);
57 } else if (filterObj.isName()) {
58 #ifdef ENABLE_PLUGINS
59 if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) {
60 secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh);
61 } else {
62 #endif
63 error(errSyntaxError, -1, "Couldn't find the '{0:s}' security handler",
64 filterObj.getName());
65 secHdlr = NULL;
66 #ifdef ENABLE_PLUGINS
68 #endif
69 } else {
70 error(errSyntaxError, -1,
71 "Missing or invalid 'Filter' entry in encryption dictionary");
72 secHdlr = NULL;
74 filterObj.free();
75 return secHdlr;
78 SecurityHandler::SecurityHandler(PDFDoc *docA) {
79 doc = docA;
82 SecurityHandler::~SecurityHandler() {
85 GBool SecurityHandler::checkEncryption(GooString *ownerPassword,
86 GooString *userPassword) {
87 void *authData;
88 GBool ok;
89 int i;
91 if (ownerPassword || userPassword) {
92 authData = makeAuthData(ownerPassword, userPassword);
93 } else {
94 authData = NULL;
96 ok = authorize(authData);
97 if (authData) {
98 freeAuthData(authData);
100 for (i = 0; !ok && i < 3; ++i) {
101 if (!(authData = getAuthData())) {
102 break;
104 ok = authorize(authData);
105 if (authData) {
106 freeAuthData(authData);
109 if (!ok) {
110 if (!ownerPassword && !userPassword) {
111 GooString dummy;
112 return checkEncryption(&dummy, &dummy);
113 } else {
114 error(errCommandLine, -1, "Incorrect password");
117 return ok;
120 //------------------------------------------------------------------------
121 // StandardSecurityHandler
122 //------------------------------------------------------------------------
124 class StandardAuthData {
125 public:
127 StandardAuthData(GooString *ownerPasswordA, GooString *userPasswordA) {
128 ownerPassword = ownerPasswordA;
129 userPassword = userPasswordA;
132 ~StandardAuthData() {
133 if (ownerPassword) {
134 delete ownerPassword;
136 if (userPassword) {
137 delete userPassword;
141 GooString *ownerPassword;
142 GooString *userPassword;
145 StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
146 Object *encryptDictA):
147 SecurityHandler(docA)
149 Object versionObj, revisionObj, lengthObj;
150 Object ownerKeyObj, userKeyObj, ownerEncObj, userEncObj;
151 Object permObj, fileIDObj, fileIDObj1;
152 Object cryptFiltersObj, streamFilterObj, stringFilterObj;
153 Object cryptFilterObj, cfmObj, cfLengthObj;
154 Object encryptMetadataObj;
156 ok = gFalse;
157 fileID = NULL;
158 ownerKey = NULL;
159 userKey = NULL;
160 ownerEnc = NULL;
161 userEnc = NULL;
162 fileKeyLength = 0;
164 encryptDictA->dictLookup("V", &versionObj);
165 encryptDictA->dictLookup("R", &revisionObj);
166 encryptDictA->dictLookup("Length", &lengthObj);
167 encryptDictA->dictLookup("O", &ownerKeyObj);
168 encryptDictA->dictLookup("U", &userKeyObj);
169 encryptDictA->dictLookup("OE", &ownerEncObj);
170 encryptDictA->dictLookup("UE", &userEncObj);
171 encryptDictA->dictLookup("P", &permObj);
172 if (permObj.isInt64()) {
173 unsigned int permUint = permObj.getInt64();
174 int perms = permUint - UINT_MAX - 1;
175 permObj.free();
176 permObj.initInt(perms);
178 doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
179 if (versionObj.isInt() &&
180 revisionObj.isInt() &&
181 permObj.isInt() &&
182 ownerKeyObj.isString() &&
183 userKeyObj.isString()) {
184 encVersion = versionObj.getInt();
185 encRevision = revisionObj.getInt();
186 if ((encRevision <= 4 &&
187 ownerKeyObj.getString()->getLength() == 32 &&
188 userKeyObj.getString()->getLength() == 32) ||
189 (encRevision == 5 &&
190 // the spec says 48 bytes, but Acrobat pads them out longer
191 ownerKeyObj.getString()->getLength() >= 48 &&
192 userKeyObj.getString()->getLength() >= 48 &&
193 ownerEncObj.isString() &&
194 ownerEncObj.getString()->getLength() == 32 &&
195 userEncObj.isString() &&
196 userEncObj.getString()->getLength() == 32)) {
197 encAlgorithm = cryptRC4;
198 // revision 2 forces a 40-bit key - some buggy PDF generators
199 // set the Length value incorrectly
200 if (encRevision == 2 || !lengthObj.isInt()) {
201 fileKeyLength = 5;
202 } else {
203 fileKeyLength = lengthObj.getInt() / 8;
205 encryptMetadata = gTrue;
206 //~ this currently only handles a subset of crypt filter functionality
207 //~ (in particular, it ignores the EFF entry in encryptDictA, and
208 //~ doesn't handle the case where StmF, StrF, and EFF are not all the
209 //~ same)
210 if ((encVersion == 4 || encVersion == 5) &&
211 (encRevision == 4 || encRevision == 5)) {
212 encryptDictA->dictLookup("CF", &cryptFiltersObj);
213 encryptDictA->dictLookup("StmF", &streamFilterObj);
214 encryptDictA->dictLookup("StrF", &stringFilterObj);
215 if (cryptFiltersObj.isDict() &&
216 streamFilterObj.isName() &&
217 stringFilterObj.isName() &&
218 !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
219 if (!strcmp(streamFilterObj.getName(), "Identity")) {
220 // no encryption on streams or strings
221 encVersion = encRevision = -1;
222 } else {
223 if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
224 &cryptFilterObj)->isDict()) {
225 cryptFilterObj.dictLookup("CFM", &cfmObj);
226 if (cfmObj.isName("V2")) {
227 encVersion = 2;
228 encRevision = 3;
229 if (cryptFilterObj.dictLookup("Length",
230 &cfLengthObj)->isInt()) {
231 //~ according to the spec, this should be cfLengthObj / 8
232 fileKeyLength = cfLengthObj.getInt();
234 cfLengthObj.free();
235 } else if (cfmObj.isName("AESV2")) {
236 encVersion = 2;
237 encRevision = 3;
238 encAlgorithm = cryptAES;
239 if (cryptFilterObj.dictLookup("Length",
240 &cfLengthObj)->isInt()) {
241 //~ according to the spec, this should be cfLengthObj / 8
242 fileKeyLength = cfLengthObj.getInt();
244 cfLengthObj.free();
245 } else if (cfmObj.isName("AESV3")) {
246 encVersion = 5;
247 encRevision = 5;
248 encAlgorithm = cryptAES256;
249 if (cryptFilterObj.dictLookup("Length",
250 &cfLengthObj)->isInt()) {
251 //~ according to the spec, this should be cfLengthObj / 8
252 fileKeyLength = cfLengthObj.getInt();
254 cfLengthObj.free();
256 cfmObj.free();
258 cryptFilterObj.free();
261 stringFilterObj.free();
262 streamFilterObj.free();
263 cryptFiltersObj.free();
264 if (encryptDictA->dictLookup("EncryptMetadata",
265 &encryptMetadataObj)->isBool()) {
266 encryptMetadata = encryptMetadataObj.getBool();
268 encryptMetadataObj.free();
270 permFlags = permObj.getInt();
271 ownerKey = ownerKeyObj.getString()->copy();
272 userKey = userKeyObj.getString()->copy();
273 if (encVersion >= 1 && encVersion <= 2 &&
274 encRevision >= 2 && encRevision <= 3) {
275 if (fileIDObj.isArray()) {
276 if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
277 fileID = fileIDObj1.getString()->copy();
278 } else {
279 fileID = new GooString();
281 fileIDObj1.free();
282 } else {
283 fileID = new GooString();
285 if (fileKeyLength > 16 || fileKeyLength < 0) {
286 fileKeyLength = 16;
288 ok = gTrue;
289 } else if (encVersion == 5 && encRevision == 5) {
290 fileID = new GooString(); // unused for V=R=5
291 if (ownerEncObj.isString() && userEncObj.isString()) {
292 ownerEnc = ownerEncObj.getString()->copy();
293 userEnc = userEncObj.getString()->copy();
294 if (fileKeyLength > 32 || fileKeyLength < 0) {
295 fileKeyLength = 32;
297 ok = gTrue;
298 } else {
299 error(errSyntaxError, -1, "Weird encryption owner/user info");
301 } else if (!(encVersion == -1 && encRevision == -1)) {
302 error(errUnimplemented, -1,
303 "Unsupported version/revision ({0:d}/{1:d}) of Standard security handler",
304 encVersion, encRevision);
306 } else {
307 error(errSyntaxError, -1, "Invalid encryption key length");
309 } else {
310 error(errSyntaxError, -1, "Weird encryption info");
312 fileIDObj.free();
313 permObj.free();
314 userEncObj.free();
315 ownerEncObj.free();
316 userKeyObj.free();
317 ownerKeyObj.free();
318 lengthObj.free();
319 revisionObj.free();
320 versionObj.free();
323 StandardSecurityHandler::~StandardSecurityHandler() {
324 if (fileID) {
325 delete fileID;
327 if (ownerKey) {
328 delete ownerKey;
330 if (userKey) {
331 delete userKey;
333 if (ownerEnc) {
334 delete ownerEnc;
336 if (userEnc) {
337 delete userEnc;
341 GBool StandardSecurityHandler::isUnencrypted() {
342 return encVersion == -1 && encRevision == -1;
345 void *StandardSecurityHandler::makeAuthData(GooString *ownerPassword,
346 GooString *userPassword) {
347 return new StandardAuthData(ownerPassword ? ownerPassword->copy()
348 : (GooString *)NULL,
349 userPassword ? userPassword->copy()
350 : (GooString *)NULL);
353 void *StandardSecurityHandler::getAuthData() {
354 return NULL;
357 void StandardSecurityHandler::freeAuthData(void *authData) {
358 delete (StandardAuthData *)authData;
361 GBool StandardSecurityHandler::authorize(void *authData) {
362 GooString *ownerPassword, *userPassword;
364 if (!ok) {
365 return gFalse;
367 if (authData) {
368 ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
369 userPassword = ((StandardAuthData *)authData)->userPassword;
370 } else {
371 ownerPassword = NULL;
372 userPassword = NULL;
374 if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
375 ownerKey, userKey, ownerEnc, userEnc,
376 permFlags, fileID,
377 ownerPassword, userPassword, fileKey,
378 encryptMetadata, &ownerPasswordOk)) {
379 return gFalse;
381 return gTrue;
384 #ifdef ENABLE_PLUGINS
386 //------------------------------------------------------------------------
387 // ExternalSecurityHandler
388 //------------------------------------------------------------------------
390 ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
391 Object *encryptDictA,
392 XpdfSecurityHandler *xshA):
393 SecurityHandler(docA)
395 encryptDictA->copy(&encryptDict);
396 xsh = xshA;
397 encAlgorithm = cryptRC4; //~ this should be obtained via getKey
398 ok = gFalse;
400 if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,
401 (XpdfObject)encryptDictA, &docData)) {
402 return;
405 ok = gTrue;
408 ExternalSecurityHandler::~ExternalSecurityHandler() {
409 (*xsh->freeDoc)(xsh->handlerData, docData);
410 encryptDict.free();
413 void *ExternalSecurityHandler::makeAuthData(GooString *ownerPassword,
414 GooString *userPassword) {
415 char *opw, *upw;
416 void *authData;
418 opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL;
419 upw = userPassword ? userPassword->getCString() : (char *)NULL;
420 if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) {
421 return NULL;
423 return authData;
426 void *ExternalSecurityHandler::getAuthData() {
427 void *authData;
429 if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) {
430 return NULL;
432 return authData;
435 void ExternalSecurityHandler::freeAuthData(void *authData) {
436 (*xsh->freeAuthData)(xsh->handlerData, docData, authData);
439 GBool ExternalSecurityHandler::authorize(void *authData) {
440 char *key;
441 int length;
443 if (!ok) {
444 return gFalse;
446 permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData);
447 if (!(permFlags & xpdfPermissionOpen)) {
448 return gFalse;
450 if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion, &encRevision)) {
451 return gFalse;
453 if ((fileKeyLength = length) > 16) {
454 fileKeyLength = 16;
456 memcpy(fileKey, key, fileKeyLength);
457 (*xsh->freeKey)(xsh->handlerData, docData, key, length);
458 return gTrue;
461 #endif // ENABLE_PLUGINS