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