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