source: trunk/poppler/mypoppler/poppler/SecurityHandler.cc @ 461

Last change on this file since 461 was 461, checked in by Silvan Scherrer, 11 years ago

poppler update to 0.14.2

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