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