1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 /*
21  * XSEC
22  *
23  * cipher := Tool to handle basic encryption/decryption of XML documents
24  *
25  * Author(s): Berin Lautenbach
26  *
27  * $Id: cipher.cpp 1894293 2021-10-15 14:14:50Z scantor $
28  *
29  */
30 
31 // XSEC
32 
33 #include <xsec/utils/XSECPlatformUtils.hpp>
34 #include <xsec/framework/XSECProvider.hpp>
35 #include <xsec/framework/XSECException.hpp>
36 #include <xsec/enc/XSECCryptoException.hpp>
37 #include <xsec/enc/XSECCryptoUtils.hpp>
38 #include <xsec/enc/OpenSSL/OpenSSLCryptoSymmetricKey.hpp>
39 #include <xsec/utils/XSECBinTXFMInputStream.hpp>
40 #include <xsec/xenc/XENCEncryptedData.hpp>
41 #include <xsec/xenc/XENCEncryptedKey.hpp>
42 
43 #include "XencInteropResolver.hpp"
44 
45 #include "../../utils/XSECDOMUtils.hpp"
46 
47 // General
48 
49 #include <memory.h>
50 #include <string.h>
51 #include <iostream>
52 #include <fstream>
53 #include <stdlib.h>
54 
55 #if defined(HAVE_UNISTD_H)
56 # include <unistd.h>
57 #else
58 # if defined(HAVE_DIRECT_H)
59 #  include <direct.h>
60 # endif
61 #endif
62 
63 #if defined (_DEBUG) && defined (_MSC_VER)
64 #include <crtdbg.h>
65 #endif
66 
67 
68 #include <xercesc/util/PlatformUtils.hpp>
69 #include <xercesc/util/XMLString.hpp>
70 
71 #include <xercesc/dom/DOM.hpp>
72 #include <xercesc/parsers/XercesDOMParser.hpp>
73 #include <xercesc/util/XMLException.hpp>
74 #include <xercesc/util/XMLUri.hpp>
75 #include <xercesc/util/XMLUni.hpp>
76 #include <xercesc/util/Janitor.hpp>
77 #include <xercesc/util/BinFileInputStream.hpp>
78 #include <xercesc/framework/XMLFormatter.hpp>
79 #include <xercesc/framework/StdOutFormatTarget.hpp>
80 #include <xercesc/framework/LocalFileFormatTarget.hpp>
81 
82 XERCES_CPP_NAMESPACE_USE
83 
84 using std::cerr;
85 using std::cout;
86 using std::endl;
87 using std::ostream;
88 
89 #ifdef XSEC_HAVE_XALAN
90 
91 // XALAN
92 
93 #include <xalanc/XPath/XPathEvaluator.hpp>
94 #include <xalanc/XalanTransformer/XalanTransformer.hpp>
95 
96 // If this isn't defined, we're on Xalan 1.12+ and require modern C++
97 #ifndef XALAN_USING_XALAN
98 # define XALAN_USING_XALAN(NAME) using xalanc :: NAME;
99 #endif
100 
101 XALAN_USING_XALAN(XPathEvaluator)
102 XALAN_USING_XALAN(XalanTransformer)
103 
104 #endif
105 
106 #if defined (XSEC_HAVE_OPENSSL)
107 // OpenSSL
108 
109 #   include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp>
110 #   include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
111 #   include <openssl/err.h>
112 #   include <openssl/bio.h>
113 #   include <openssl/evp.h>
114 #   include <openssl/pem.h>
115 
116 #endif
117 
118 #if defined (XSEC_HAVE_WINCAPI)
119 
120 #   include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp>
121 #   include <xsec/enc/WinCAPI/WinCAPICryptoSymmetricKey.hpp>
122 #   include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp>
123 
124 #endif
125 
126 #if defined (XSEC_HAVE_NSS)
127 
128 #   include <xsec/enc/NSS/NSSCryptoProvider.hpp>
129 #   include <xsec/enc/NSS/NSSCryptoSymmetricKey.hpp>
130 #   include <xsec/enc/NSS/NSSCryptoKeyHMAC.hpp>
131 
132 #endif
133 
134 #include <time.h>
135 
136 #ifndef XSEC_HAVE_XALAN
137 
138 std::ostream& operator<< (std::ostream& target, const XMLCh * s)
139 {
140     char *p = XMLString::transcode(s);
141     target << p;
142     XSEC_RELEASE_XMLCH(p);
143     return target;
144 }
145 
146 #endif
147 
148 // ----------------------------------------------------------------------------
149 //           Checksig
150 // ----------------------------------------------------------------------------
151 
152 
printUsage(void)153 void printUsage(void) {
154 
155     cerr << "\nUsage: cipher [options] <input file name>\n\n";
156     cerr << "     Where options are :\n\n";
157     cerr << "     --decrypt/-d\n";
158     cerr << "         Operate in decrypt mode (default) - outputs the decrypted octet stream\n";
159     cerr << "         Reads in the input file as an XML file, searches for an EncryptedData node\n";
160     cerr << "         and decrypts the content\n";
161     cerr << "     --decrypt-element/-de\n";
162     cerr << "         Operate in decrypt and XML mode.\n";
163     cerr << "         This will output the original XML document with the first encrypted\n";
164     cerr << "         element decrypted.\n";
165     cerr << "     --encrypt-file/-ef\n";
166     cerr << "         Encrypt the contents of the input file as raw data and create an\n";
167     cerr << "         XML Encrypted Data outpu\n";
168     cerr << "     --encrypt-xml/-ex\n";
169     cerr << "         Parse the input file and encrypt the doc element down, storing the\n";
170     cerr << "         output as a XML Encrypted Data\n";
171     cerr << "     --key/-k [kek] <KEY_TYPE> [options]\n";
172     cerr << "         Set the key to use.\n";
173     cerr << "             If the first parameter is \"kek\", the key arguments will be used\n";
174     cerr << "                  as a Key EncryptionKey\n";
175     cerr << "             KEY_TYPE defines what the key is.  Can be one of :\n";
176     cerr << "                  X509, RSA, AES128, AES192, AES256, AES128-GCM, AES192-GCM, AES256-GCM or 3DES\n";
177     cerr << "             options are :\n";
178     cerr << "                  <filename> - for X509 PEM files (must be an RSA KEK certificate\n";
179     cerr << "                  <filename> <password> - for RSA private key files (MUST be a KEK)\n";
180     cerr << "                  <key-string> - For a string to use as the key for AES or DES keys\n";
181 #ifdef XSEC_XKMS_ENABLED
182     cerr << "     --xkms/-x\n";
183     cerr << "         The key that follows on the command line is to be interpreted as\n";
184     cerr << "         an XKMS RSAKeyPair encryption key\n";
185 #endif
186     cerr << "     --interop/-i\n";
187     cerr << "         Use the interop resolver for Baltimore interop examples\n";
188     cerr << "     --out-file/-o\n";
189     cerr << "         Output the result to the indicated file (rather than stdout)\n";
190 #ifdef XSEC_HAVE_WINCAPI
191     cerr << "     --wincapi/-w\n";
192     cerr << "         Force use of Windows Crypto API\n";
193 #endif
194 #ifdef XSEC_HAVE_NSS
195     cerr << "     --nss/-n\n";
196     cerr << "         Force use of NSS Crypto API\n";
197 #endif
198 
199     cerr << "\n     Exits with codes :\n";
200     cerr << "         0 = Decrypt/Encrypt OK\n";
201     cerr << "         1 = Decrypt/Encrypt failed\n";
202     cerr << "         2 = Processing error\n";
203 
204 }
205 
evaluate(int argc,char ** argv)206 int evaluate(int argc, char ** argv) {
207 
208     char                    * filename = NULL;
209     char                    * outfile = NULL;
210     unsigned char           * keyStr = NULL;
211     bool                    doDecrypt = true;
212     bool                    errorsOccured = false;
213     bool                    doDecryptElement = false;
214     bool                    useInteropResolver = false;
215     bool                    encryptFileAsData = false;
216     bool                    parseXMLInput = true;
217     bool                    doXMLOutput = false;
218 #ifdef XSEC_XKMS_ENABLED
219     bool                    isXKMSKey = false;
220 #endif
221     XSECCryptoKey           * kek = NULL;
222     XSECCryptoKey           * key = NULL;
223     int                     keyLen = 0;
224     const XMLCh*            kekAlg = NULL;
225     const XMLCh*            keyAlg = NULL;
226     DOMDocument             *doc;
227     unsigned char           keyBuf[24];
228     XMLFormatTarget         *formatTarget ;
229 
230 #if defined(_WIN32) && defined (XSEC_HAVE_WINCAPI)
231     HCRYPTPROV              win32DSSCSP = 0;        // Crypto Providers
232     HCRYPTPROV              win32RSACSP = 0;
233 
234     CryptAcquireContext(&win32DSSCSP, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT);
235     CryptAcquireContext(&win32RSACSP, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
236 
237 #endif
238 
239     if (argc < 2) {
240 
241         printUsage();
242         return 2;
243     }
244 
245     // Run through parameters
246     int paramCount = 1;
247 
248     while (paramCount < argc - 1) {
249 
250         if (_stricmp(argv[paramCount], "--decrypt-element") == 0 || _stricmp(argv[paramCount], "-de") == 0) {
251             paramCount++;
252             doDecrypt = true;
253             doDecryptElement = true;
254             doXMLOutput = true;
255             parseXMLInput = true;
256         }
257         else if (_stricmp(argv[paramCount], "--interop") == 0 || _stricmp(argv[paramCount], "-i") == 0) {
258             // Use the interop key resolver
259             useInteropResolver = true;
260             paramCount++;
261         }
262         else if (_stricmp(argv[paramCount], "--encrypt-file") == 0 || _stricmp(argv[paramCount], "-ef") == 0) {
263             // Use this file as the input
264             doDecrypt = false;
265             encryptFileAsData = true;
266             doXMLOutput = true;
267             parseXMLInput = false;
268             paramCount++;
269         }
270         else if (_stricmp(argv[paramCount], "--encrypt-xml") == 0 || _stricmp(argv[paramCount], "-ex") == 0) {
271             // Us this file as an XML input file
272             doDecrypt = false;
273             encryptFileAsData = false;
274             doXMLOutput = true;
275             parseXMLInput = true;
276             paramCount++;
277         }
278         else if (_stricmp(argv[paramCount], "--out-file") == 0 || _stricmp(argv[paramCount], "-o") == 0) {
279             if (paramCount +2 >= argc) {
280                 printUsage();
281                 return 1;
282             }
283             paramCount++;
284             outfile = argv[paramCount];
285             paramCount++;
286         }
287 #ifdef XSEC_XKMS_ENABLED
288         else if (_stricmp(argv[paramCount], "--xkms") == 0 || _stricmp(argv[paramCount], "-x") == 0) {
289             paramCount++;
290             isXKMSKey = true;
291         }
292 #endif
293 #ifdef XSEC_HAVE_WINCAPI
294         else if (_stricmp(argv[paramCount], "--wincapi") == 0 || _stricmp(argv[paramCount], "-w") == 0) {
295             // Use the interop key resolver
296             WinCAPICryptoProvider * cp = new WinCAPICryptoProvider();
297             XSECPlatformUtils::SetCryptoProvider(cp);
298             paramCount++;
299         }
300 #endif
301 #ifdef XSEC_HAVE_NSS
302         else if (_stricmp(argv[paramCount], "--nss") == 0 || _stricmp(argv[paramCount], "-n") == 0) {
303             // NSS Crypto Provider
304             NSSCryptoProvider * cp = new NSSCryptoProvider();
305             XSECPlatformUtils::SetCryptoProvider(cp);
306             paramCount++;
307         }
308 #endif
309         else if (_stricmp(argv[paramCount], "--key") == 0 || _stricmp(argv[paramCount], "-k") == 0) {
310 
311             // Have a key!
312             paramCount++;
313             bool isKEK = false;
314             XSECCryptoSymmetricKey::SymmetricKeyType loadKeyAs =
315                 XSECCryptoSymmetricKey::KEY_NONE;
316 
317             if (_stricmp(argv[paramCount], "kek") == 0) {
318                 isKEK = true;
319                 paramCount++;
320                 if (paramCount >= argc) {
321                     printUsage();
322                     return 2;
323                 }
324             }
325 
326             if (_stricmp(argv[paramCount], "3DES") == 0 ||
327                 _stricmp(argv[paramCount], "AES128") == 0 ||
328                 _stricmp(argv[paramCount], "AES192") == 0 ||
329                 _stricmp(argv[paramCount], "AES256") == 0 ||
330                 _stricmp(argv[paramCount], "AES128-GCM") == 0 ||
331                 _stricmp(argv[paramCount], "AES192-GCM") == 0 ||
332                 _stricmp(argv[paramCount], "AES256-GCM") == 0) {
333 
334                 if (paramCount +2 >= argc) {
335                     printUsage();
336                     return 2;
337                 }
338 
339                 switch(argv[paramCount][4]) {
340                 case '\0' :
341                     keyLen = 24;
342                     loadKeyAs = XSECCryptoSymmetricKey::KEY_3DES_192;
343                     keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC;
344                     break;
345                 case '2' :
346                     keyLen = 16;
347                     loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_128;
348                     if (isKEK) {
349                         kekAlg = DSIGConstants::s_unicodeStrURIKW_AES128;
350                     }
351                     else if (strlen(argv[paramCount]) == 6) {
352                         keyAlg = DSIGConstants::s_unicodeStrURIAES128_CBC;
353                     }
354                     else {
355                         keyAlg = DSIGConstants::s_unicodeStrURIAES128_GCM;
356                     }
357                     break;
358                 case '9' :
359                     keyLen = 24;
360                     loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_192;
361                     if (isKEK) {
362                         kekAlg = DSIGConstants::s_unicodeStrURIKW_AES192;
363                     }
364                     else if (strlen(argv[paramCount]) == 6) {
365                         keyAlg = DSIGConstants::s_unicodeStrURIAES192_CBC;
366                     }
367                     else {
368                         keyAlg = DSIGConstants::s_unicodeStrURIAES192_GCM;
369                     }
370                     break;
371                 case '5' :
372                     keyLen = 32;
373                     loadKeyAs = XSECCryptoSymmetricKey::KEY_AES_256;
374                     if (isKEK) {
375                         kekAlg = DSIGConstants::s_unicodeStrURIKW_AES256;
376                     }
377                     else if (strlen(argv[paramCount]) == 6) {
378                         keyAlg = DSIGConstants::s_unicodeStrURIAES256_CBC;
379                     }
380                     else {
381                         keyAlg = DSIGConstants::s_unicodeStrURIAES256_GCM;
382                     }
383                     break;
384                 }
385 
386                 paramCount++;
387                 unsigned char keyStr[64];
388                 if (strlen(argv[paramCount]) > 64) {
389                     cerr << "Key string too long\n";
390                     return 2;
391                 }
392                 XSECCryptoSymmetricKey * sk =
393                     XSECPlatformUtils::g_cryptoProvider->keySymmetric(loadKeyAs);
394 
395 #ifdef XSEC_XKMS_ENABLED
396                 if (isXKMSKey) {
397                     unsigned char kbuf[XSEC_MAX_HASH_SIZE];
398                     CalculateXKMSKEK((unsigned char *) argv[paramCount], (int) strlen(argv[paramCount]), kbuf, XSEC_MAX_HASH_SIZE);
399                     sk->setKey(kbuf, keyLen);
400                 }
401                 else {
402 #endif
403                     memset(keyStr, 0, 64);
404                     strcpy((char *) keyStr, argv[paramCount]);
405                     sk->setKey(keyStr, keyLen);
406 #ifdef XSEC_XKMS_ENABLED
407                 }
408 #endif
409                 paramCount++;
410                 if (isKEK)
411                     kek = sk;
412                 else
413                     key = sk;
414             }
415 
416 
417 #ifdef XSEC_HAVE_OPENSSL
418 
419             else if (_stricmp(argv[paramCount], "RSA") == 0) {
420                 // RSA private key file
421 
422                 if (paramCount + 3 >= argc) {
423 
424                     printUsage();
425                     return 2;
426 
427                 }
428 
429                 if (!isKEK) {
430                     cerr << "RSA private keys may only be KEKs\n";
431                     return 2;
432                 }
433 
434                 BIO * bioKey;
435                 if ((bioKey = BIO_new(BIO_s_file())) == NULL) {
436 
437                     cerr << "Error opening private key file\n\n";
438                     return 1;
439 
440                 }
441 
442                 if (BIO_read_filename(bioKey, argv[paramCount + 1]) <= 0) {
443 
444                     cerr << "Error opening private key file\n\n";
445                     return 1;
446 
447                 }
448 
449                 EVP_PKEY * pkey;
450                 pkey = PEM_read_bio_PrivateKey(bioKey,NULL,NULL,argv[paramCount + 2]);
451 
452                 if (pkey == NULL) {
453 
454                     cerr << "Error loading private key\n\n";
455                     return 1;
456 
457                 }
458 
459                 kek = new OpenSSLCryptoKeyRSA(pkey);
460                 kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
461                 EVP_PKEY_free(pkey);
462                 BIO_free(bioKey);
463                 paramCount += 3;
464             }
465 
466             else if (_stricmp(argv[paramCount], "X509") == 0) {
467 
468                 // X509 cert used to load an encrypting key
469 
470                 if (paramCount + 2 >= argc) {
471 
472                     printUsage();
473                     exit (1);
474 
475                 }
476 
477                 if (!isKEK) {
478                     cerr << "X509 private keys may only be KEKs\n";
479                     return 2;
480                 }
481 
482                 // Load the encrypting key
483                 // For now just read a particular file
484 
485                 BIO * bioX509;
486 
487                 if ((bioX509 = BIO_new(BIO_s_file())) == NULL) {
488 
489                     cerr << "Error opening file\n\n";
490                     exit (1);
491 
492                 }
493 
494                 if (BIO_read_filename(bioX509, argv[paramCount + 1]) <= 0) {
495 
496                     cerr << "Error opening X509 Certificate " << argv[paramCount + 1] << "\n\n";
497                     exit (1);
498 
499                 }
500 
501                 X509 * x
502                     ;
503                 x = PEM_read_bio_X509_AUX(bioX509,NULL,NULL,NULL);
504 
505                 if (x == NULL) {
506 
507                     BIO * bio_err;
508 
509                     if ((bio_err=BIO_new(BIO_s_file())) != NULL)
510                         BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
511 
512                     cerr << "Error loading certificate key\n\n";
513                     ERR_print_errors(bio_err);
514                     BIO_free(bio_err);
515                     exit (1);
516 
517                 }
518 
519                 // Now load the key
520                 EVP_PKEY *pkey;
521 
522                 pkey = X509_get_pubkey(x);
523 #ifdef XSEC_OPENSSL_HAVE_EVP_PKEY_ID
524                 if (pkey == NULL || EVP_PKEY_id(pkey) != EVP_PKEY_RSA)
525 #else
526                 if (pkey == NULL || pkey->type != EVP_PKEY_RSA)
527 #endif
528                 {
529                     cerr << "Error extracting RSA key from certificate" << endl;
530                 }
531 
532                 kek = new OpenSSLCryptoKeyRSA(pkey);
533                 kekAlg = DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1;
534 
535                 // Clean up
536 
537                 EVP_PKEY_free (pkey);
538                 X509_free(x);
539                 BIO_free(bioX509);
540 
541                 paramCount += 2;
542 
543             } /* argv[1] = "--x509cert" */
544 #endif /* XSEC_HAVE_OPENSSL */
545             else {
546                 printUsage();
547                 return 2;
548             }
549         }
550 
551         else {
552             cerr << "Unknown option: " << argv[paramCount] << endl;
553             printUsage();
554             return 2;
555         }
556     }
557 
558     if (paramCount >= argc) {
559         printUsage();
560         return 2;
561     }
562 
563     if (outfile != NULL) {
564         formatTarget = new LocalFileFormatTarget(outfile);
565     }
566     else {
567         formatTarget = new StdOutFormatTarget();
568     }
569 
570     filename = argv[paramCount];
571 
572     if (parseXMLInput) {
573 
574         XercesDOMParser * parser = new XercesDOMParser;
575         Janitor<XercesDOMParser> j_parser(parser);
576 
577         parser->setDoNamespaces(true);
578         parser->setCreateEntityReferenceNodes(true);
579 
580         // Now parse out file
581 
582         XMLSize_t errorCount = 0;
583         try
584         {
585             parser->parse(filename);
586             errorCount = parser->getErrorCount();
587             if (errorCount > 0)
588                 errorsOccured = true;
589         }
590 
591         catch (const XMLException& e)
592         {
593             cerr << "An error occurred during parsing\n   Message: "
594                  << e.getMessage() << endl;
595             errorsOccured = true;
596         }
597 
598 
599         catch (const DOMException& e)
600         {
601            cerr << "A DOM error occurred during parsing\n   DOMException code: "
602                  << e.code << endl;
603             errorsOccured = true;
604         }
605 
606         if (errorsOccured) {
607 
608             cout << "Errors during parse" << endl;
609             return (2);
610 
611         }
612 
613         /*
614 
615             Now that we have the parsed file, get the DOM document and start looking at it
616 
617         */
618 
619         doc = parser->adoptDocument();
620     }
621 
622     else {
623         // Create an empty document
624         XMLCh tempStr[100];
625         XMLString::transcode("Core", tempStr, 99);
626         DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
627         doc = impl->createDocument(
628             0,                    // root element namespace URI.
629             MAKE_UNICODE_STRING("ADoc"),            // root element name
630             NULL);// DOMDocumentType());  // document type object (DTD).
631     }
632 
633 
634     XSECProvider prov;
635     XENCCipher * cipher = prov.newCipher(doc);
636 
637     if (kek != NULL)
638         cipher->setKEK(kek);
639     if (key != NULL)
640         cipher->setKey(key);
641 
642     try {
643 
644         if (doDecrypt) {
645 
646             if (useInteropResolver == true) {
647 
648                 // Map out base path of the file
649 #ifdef XSEC_HAVE_GETCWD_DYN
650                 char *path = getcwd(NULL, 0);
651                 char *baseURI = (char*)malloc(strlen(path) + 8 + 1 + strlen(filename) + 1);
652 #else
653                 char path[PATH_MAX];
654                 char baseURI[(PATH_MAX * 2) + 10];
655                 getcwd(path, PATH_MAX);
656 #endif
657                 strcpy(baseURI, "file:///");
658 
659                 // Ugly and nasty but quick
660                 if (filename[0] != '\\' && filename[0] != '/' && filename[1] != ':') {
661                     strcat(baseURI, path);
662                     strcat(baseURI, "/");
663                 } else if (path[1] == ':') {
664                     path[2] = '\0';
665                     strcat(baseURI, path);
666                 }
667 
668                 strcat(baseURI, filename);
669 
670                 // Find any ':' and "\" characters
671                 int lastSlash = 0;
672                 for (unsigned int i = 8; i < strlen(baseURI); ++i) {
673                     if (baseURI[i] == '\\') {
674                         lastSlash = i;
675                         baseURI[i] = '/';
676                     }
677                     else if (baseURI[i] == '/')
678                         lastSlash = i;
679                 }
680 
681                 // The last "\\" must prefix the filename
682                 baseURI[lastSlash + 1] = '\0';
683 
684                 XMLCh * uriT = XMLString::transcode(baseURI);
685 #ifdef XSEC_HAVE_GETCWD_DYN
686                 free(path);
687                 free(baseURI);
688 #endif
689 
690                 XencInteropResolver ires(doc, &(uriT[8]));
691                 XSEC_RELEASE_XMLCH(uriT);
692                 cipher->setKeyInfoResolver(&ires);
693 
694             }
695             // Find the EncryptedData node
696             DOMNode * n = findXENCNode(doc, "EncryptedData");
697 
698             if (doDecryptElement) {
699                 while (n != NULL) {
700 
701                     // decrypt
702                     cipher->decryptElement(static_cast<DOMElement *>(n));
703 
704                     // Find the next EncryptedData node
705                     n = findXENCNode(doc, "EncryptedData");
706                 }
707 
708             }
709             else {
710                 XSECBinTXFMInputStream * bis = cipher->decryptToBinInputStream(static_cast<DOMElement *>(n));
711                 Janitor<XSECBinTXFMInputStream> j_bis(bis);
712 
713                 XMLByte buf[1024];
714                 XMLSize_t read = bis->readBytes(buf, 1023);
715                 while (read > 0) {
716                     formatTarget->writeChars(buf, read, NULL);
717                     read = bis->readBytes(buf, 1023);
718                 }
719             }
720         }
721         else {
722 
723             XENCEncryptedData *xenc = NULL;
724             // Encrypting
725             if (kek != NULL && key == NULL) {
726                 XSECPlatformUtils::g_cryptoProvider->getRandom(keyBuf, 24);
727                 XSECCryptoSymmetricKey * k =
728                     XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192);
729                 k->setKey(keyBuf, 24);
730                 cipher->setKey(k);
731                 keyAlg = DSIGConstants::s_unicodeStrURI3DES_CBC;
732                 keyStr = keyBuf;
733                 keyLen = 24;
734             }
735 
736             if (encryptFileAsData) {
737 
738                 // Create a BinInputStream
739                 BinFileInputStream * is = new BinFileInputStream(filename, XMLPlatformUtils::fgMemoryManager);
740                 xenc = cipher->encryptBinInputStream(is, keyAlg);
741 
742                 // Replace the document element
743                 DOMElement * elt = doc->getDocumentElement();
744                 doc->replaceChild(xenc->getElement(), elt);
745                 elt->release();
746             }
747             else {
748                 // Document encryption
749                 cipher->encryptElement(doc->getDocumentElement(), keyAlg);
750             }
751 
752             // Do we encrypt a created key?
753             if (kek != NULL && xenc != NULL) {
754                 XENCEncryptedKey *xkey = cipher->encryptKey(keyStr, keyLen, kekAlg);
755                 // Add to the EncryptedData
756                 xenc->appendEncryptedKey(xkey);
757             }
758         }
759 
760         if (doXMLOutput) {
761             // Output the result
762 
763             XMLCh core[] = {
764                 XERCES_CPP_NAMESPACE_QUALIFIER chLatin_C,
765                 XERCES_CPP_NAMESPACE_QUALIFIER chLatin_o,
766                 XERCES_CPP_NAMESPACE_QUALIFIER chLatin_r,
767                 XERCES_CPP_NAMESPACE_QUALIFIER chLatin_e,
768                 XERCES_CPP_NAMESPACE_QUALIFIER chNull
769             };
770 
771             DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(core);
772 
773             DOMLSSerializer   *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer();
774             Janitor<DOMLSSerializer> j_theSerializer(theSerializer);
775 
776             // Get the config so we can set up pretty printing
777             DOMConfiguration *dc = theSerializer->getDomConfig();
778             dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false);
779 
780             // Now create an output object to format to UTF-8
781             DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput();
782             Janitor<DOMLSOutput> j_theOutput(theOutput);
783 
784             theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8"));
785             theOutput->setByteStream(formatTarget);
786 
787             theSerializer->write(doc, theOutput);
788 
789             cout << endl;
790 
791         }
792     }
793 
794     catch (const XSECException &e) {
795         char * msg = XMLString::transcode(e.getMsg());
796         cerr << "An error occurred during encryption/decryption operation\n   Message: "
797         << msg << endl;
798         XSEC_RELEASE_XMLCH(msg);
799         errorsOccured = true;
800         if (formatTarget != NULL)
801             delete formatTarget;
802         doc->release();
803         return 2;
804     }
805     catch (const XSECCryptoException &e) {
806         cerr << "An error occurred during encryption/decryption operation\n   Message: "
807         << e.getMsg() << endl;
808         errorsOccured = true;
809         if (formatTarget != NULL)
810             delete formatTarget;
811         doc->release();
812 
813 #ifdef XSEC_HAVE_OPENSSL
814         ERR_load_crypto_strings();
815         BIO * bio_err;
816         if ((bio_err=BIO_new(BIO_s_file())) != NULL)
817             BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
818 
819         ERR_print_errors(bio_err);
820 #endif
821         return 2;
822     }
823 
824     if (formatTarget != NULL)
825         delete formatTarget;
826 
827     doc->release();
828     return 0;
829 }
830 
831 
main(int argc,char ** argv)832 int main(int argc, char **argv) {
833 
834     int retResult;
835 
836 #if defined (_DEBUG) && defined (_MSC_VER)
837 
838     // Do some memory debugging under Visual C++
839 
840     _CrtMemState s1, s2, s3;
841 
842     // At this point we are about to start really using XSEC, so
843     // Take a "before" checkpoing
844 
845     _CrtMemCheckpoint( &s1 );
846 
847 #endif
848 
849     // Initialise the XML system
850 
851     try {
852 
853         XMLPlatformUtils::Initialize();
854 #ifdef XSEC_HAVE_XALAN
855         XPathEvaluator::initialize();
856         XalanTransformer::initialize();
857 #endif
858         XSECPlatformUtils::Initialise();
859 
860     }
861     catch (const XMLException &e) {
862 
863         cerr << "Error during initialisation of Xerces" << endl;
864         cerr << "Error Message = : "
865              << e.getMessage() << endl;
866 
867     }
868 
869     retResult = evaluate(argc, argv);
870 
871     XSECPlatformUtils::Terminate();
872 #ifdef XSEC_HAVE_XALAN
873     XalanTransformer::terminate();
874     XPathEvaluator::terminate();
875 #endif
876     XMLPlatformUtils::Terminate();
877 
878 #if defined (_DEBUG) && defined (_MSC_VER)
879 
880     _CrtMemCheckpoint( &s2 );
881 
882     if ( _CrtMemDifference( &s3, &s1, &s2 ) && (
883         s3.lCounts[0] > 0 ||
884         s3.lCounts[1] > 1 ||
885         // s3.lCounts[2] > 2 ||  We don't worry about C Runtime
886         s3.lCounts[3] > 0 ||
887         s3.lCounts[4] > 0)) {
888 
889         // Note that there is generally 1 Normal and 1 CRT block
890         // still taken.  1 is from Xalan and 1 from stdio
891 
892         // Send all reports to STDOUT
893         _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
894         _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
895         _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
896         _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
897         _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
898         _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
899 
900         // Dumpy memory stats
901 
902         _CrtMemDumpAllObjectsSince( &s3 );
903         _CrtMemDumpStatistics( &s3 );
904     }
905 
906     // Now turn off memory leak checking and end as there are some
907     // Globals that are allocated that get seen as leaks (Xalan?)
908 
909     int dbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
910     dbgFlag &= ~(_CRTDBG_LEAK_CHECK_DF);
911     _CrtSetDbgFlag( dbgFlag );
912 
913 #endif
914 
915     return retResult;
916 }
917