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 * siginf := Output information about a signature found in an XML file
24 *
25 * Author(s): Berin Lautenbach
26 *
27 * $Id: siginf.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/canon/XSECC14n20010315.hpp>
36 #include <xsec/dsig/DSIGSignature.hpp>
37 #include <xsec/dsig/DSIGReference.hpp>
38 #include <xsec/framework/XSECException.hpp>
39 #include <xsec/enc/XSECCryptoException.hpp>
40 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
41
42 #include <xsec/dsig/DSIGTransformC14n.hpp>
43 #include <xsec/dsig/DSIGTransformBase64.hpp>
44 #include <xsec/dsig/DSIGTransformXSL.hpp>
45 #include <xsec/dsig/DSIGTransformXPath.hpp>
46 #include <xsec/dsig/DSIGTransformXPathFilter.hpp>
47 #include <xsec/dsig/DSIGXPathFilterExpr.hpp>
48 #include <xsec/dsig/DSIGTransformEnvelope.hpp>
49
50 #include <xsec/dsig/DSIGTransformList.hpp>
51
52 #include "../../utils/XSECDOMUtils.hpp"
53
54 // General
55
56 #include <memory.h>
57 #include <string.h>
58 #include <iostream>
59 #include <stdlib.h>
60
61 #if defined (_DEBUG) && defined (_MSC_VER)
62 #include <crtdbg.h>
63 #endif
64
65
66 #include <xercesc/util/PlatformUtils.hpp>
67 #include <xercesc/util/XMLString.hpp>
68
69 #include <xercesc/dom/DOM.hpp>
70 #include <xercesc/parsers/XercesDOMParser.hpp>
71 #include <xercesc/util/XMLException.hpp>
72 #include <xercesc/util/XMLUri.hpp>
73 #include <xercesc/util/Janitor.hpp>
74
75 XERCES_CPP_NAMESPACE_USE
76
77 using std::cerr;
78 using std::cout;
79 using std::endl;
80 using std::ostream;
81
82 #ifdef XSEC_HAVE_XALAN
83
84 // XALAN
85
86 #include <xalanc/XPath/XPathEvaluator.hpp>
87 #include <xalanc/XalanTransformer/XalanTransformer.hpp>
88
89 // If this isn't defined, we're on Xalan 1.12+ and require modern C++
90 #ifndef XALAN_USING_XALAN
91 # define XALAN_USING_XALAN(NAME) using xalanc :: NAME;
92 #endif
93
94 XALAN_USING_XALAN(XPathEvaluator)
95 XALAN_USING_XALAN(XalanTransformer)
96
97 #else
98
99 ostream& operator<< (ostream& target, const XMLCh * s)
100 {
101 char *p = XMLString::transcode(s);
102 target << p;
103 XSEC_RELEASE_XMLCH(p);
104 return target;
105 }
106
107 #endif
108
109 class X2C {
110
111 public:
112
X2C(const XMLCh * in)113 X2C(const XMLCh * in) {
114 mp_cStr = XMLString::transcode(in);
115 }
~X2C()116 ~X2C() {
117 XSEC_RELEASE_XMLCH(mp_cStr);
118 }
119
str(void)120 char * str(void) {
121 return mp_cStr;
122 }
123
124 private :
125
126 char * mp_cStr;
127
128 };
129
operator <<(ostream & target,X2C & x)130 ostream & operator<<(ostream& target, X2C &x) {
131 target << x.str();
132 return target;
133 }
134
135 inline
levelSet(unsigned int level)136 void levelSet(unsigned int level) {
137
138 for (unsigned int i = 0; i < level; ++i)
139 cout << " ";
140
141 }
142
outputTransform(const DSIGTransform * t,unsigned int level)143 void outputTransform(const DSIGTransform * t, unsigned int level) {
144
145
146 if (dynamic_cast<const DSIGTransformBase64*>(t)) {
147 cout << "Base64 Decode" << endl;
148 }
149 else if (dynamic_cast<const DSIGTransformC14n*>(t)) {
150 const XMLCh* cm = dynamic_cast<const DSIGTransformC14n*>(t)->getCanonicalizationMethod();
151 if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_NOC)) {
152 cout << "c14n 1.0 canonicalization (without comments)" << endl;
153 }
154 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_COM)) {
155 cout << "c14n 1.0 canonicalization (with comments)" << endl;
156 }
157 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_NOC)) {
158 cout << "c14n 1.1 canonicalization (without comments)" << endl;
159 }
160 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_COM)) {
161 cout << "c14n 1.1 canonicalization (with comments)" << endl;
162 }
163 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_NOC)) {
164 cout << "Exclusive c14n 1.0 canonicalization (without comments)" << endl;
165 if (dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList() != NULL) {
166 levelSet(level);
167 cout << "Inclusive prefixes : " <<
168 X2C(dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList()).str() << endl;
169 }
170 }
171 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_COM)) {
172 cout << "Exclusive c14n 1.0 canonicalization (with comments)" << endl;
173 if (dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList() != NULL) {
174 levelSet(level);
175 cout << "Inclusive prefixes : " <<
176 X2C(dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList()).str() << endl;
177 }
178 }
179 else {
180 cout << "Unknown c14n method" << endl;
181 }
182 }
183 else if (dynamic_cast<const DSIGTransformEnvelope*>(t)) {
184 cout << "enveloped signature" << endl;
185 }
186 else if (dynamic_cast<const DSIGTransformXPath*>(t)) {
187 const DSIGTransformXPath* xp = dynamic_cast<const DSIGTransformXPath*>(t);
188
189 cout << "XPath" << endl;
190 // Check for namespaces
191 DOMNamedNodeMap* atts = xp->getNamespaces();
192
193 if (atts != 0) {
194 XMLSize_t s = atts->getLength();
195 for (XMLSize_t i = 0 ; i < s; ++i) {
196 levelSet(level);
197 cout << "Namespace : " << X2C(atts->item(i)->getNodeName()).str() <<
198 "=\"" << X2C(atts->item(i)->getNodeValue()).str() << "\"\n";
199 }
200 }
201 levelSet(level);
202 // Hmm - this is really a bug. This should return a XMLCh string
203 cout << "Expr : " << xp->getExpression() << endl;
204 }
205 else if (dynamic_cast<const DSIGTransformXPathFilter*>(t)) {
206 const DSIGTransformXPathFilter * xpf = dynamic_cast<const DSIGTransformXPathFilter*>(t);
207
208 cout << "XPath-Filter2" << endl;
209
210 unsigned int s = xpf->getExprNum();
211
212 for (unsigned int i = 0; i < s; ++i) {
213
214 levelSet(level);
215 cout << "Filter : ";
216
217 const DSIGXPathFilterExpr * e = xpf->expr(i);
218
219 switch (e->getFilterType()) {
220
221 case DSIGXPathFilterExpr::FILTER_UNION :
222 cout << "union : \"";
223 break;
224 case DSIGXPathFilterExpr::FILTER_INTERSECT :
225 cout << "intersect : \"";
226 break;
227 default :
228 cout << "subtract : \"";
229 }
230
231 // Now the expression
232 char * str = XMLString::transcode(e->getFilter());
233 cout << str << "\"" << endl;
234 XSEC_RELEASE_XMLCH(str);
235 }
236 }
237 else if (dynamic_cast<const DSIGTransformXSL*>(t)) {
238 cout << "XSLT" << endl;
239 // Really should serialise and output stylesheet.
240 }
241 else {
242 cout << "unknown transform type" << endl;
243 }
244 }
245
outputReferences(DSIGReferenceList * rl,unsigned int level)246 void outputReferences(DSIGReferenceList *rl, unsigned int level) {
247
248 int s = (int) rl->getSize();
249
250 for (int i = 0; i < s; ++i) {
251
252 levelSet(level);
253 cout << "Reference " << i + 1 << " : " << endl;
254 levelSet(level + 1);
255 cout << "URI : \"" << X2C(rl->item(i)->getURI()).str() << "\"" << endl;
256 levelSet(level + 1);
257 cout << "Digest Algorithm : ";
258 char* alg = XMLString::transcode(rl->item(i)->getAlgorithmURI());
259 cout << (alg ? alg : "Unknown") << endl;
260 XSEC_RELEASE_XMLCH(alg);
261
262 // Now the transforms
263 DSIGTransformList * tl = rl->item(i)->getTransforms();
264 if (tl != NULL) {
265
266 int tlSize = (int) tl->getSize();
267 for (int j = 0 ; j < tlSize; ++j) {
268
269 levelSet(level+1);
270 cout << "Transform " << j + 1 << " : ";
271 outputTransform(tl->item(j), level + 2);
272
273 }
274
275 }
276
277 if (rl->item(i)->isManifest() == true) {
278
279 levelSet(level + 1);
280 cout << "Manifest References : " << endl;
281 outputReferences(rl->item(i)->getManifestReferenceList(), level + 2);
282 levelSet(level + 1);
283 cout << "End Manifest References" << endl;
284
285 }
286
287 }
288
289 }
290
outputSignatureInfo(DSIGSignature * sig,bool skipReferences)291 void outputSignatureInfo(DSIGSignature *sig, bool skipReferences) {
292
293 // First get some information about the main signature
294 cout << "Signature (Signed Info) settings : " << endl;
295 cout << " Canonicalization Method : ";
296
297 const XMLCh* cm = sig->getCanonicalizationMethod();
298 if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_NOC)) {
299 cout << "c14n 1.0 canonicalization (without comments)" << endl;
300 }
301 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_COM)) {
302 cout << "c14n 1.0 canonicalization (with comments)" << endl;
303 }
304 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_NOC)) {
305 cout << "c14n 1.1 canonicalization (without comments)" << endl;
306 }
307 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_COM)) {
308 cout << "c14n 1.1 canonicalization (with comments)" << endl;
309 }
310 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_NOC)) {
311 cout << "Exclusive c14n 1.0 canonicalization (without comments)" << endl;
312 }
313 else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_COM)) {
314 cout << "Exclusive c14n 1.0 canonicalization (with comments)" << endl;
315 }
316 else {
317 cout << "Unknown c14n method" << endl;
318 }
319
320 cout << endl;
321
322 cout << " Signature Algorithm : ";
323 char* alg = XMLString::transcode(sig->getAlgorithmURI());
324 cout << (alg ? alg : "Unknown") << endl;
325 XSEC_RELEASE_XMLCH(alg);
326
327 // Read in the references and output
328
329 if (skipReferences == false) {
330
331 DSIGReferenceList * rl = sig->getReferenceList();
332
333 if (rl != NULL) {
334
335 cout << endl << "Reference List : " << endl;
336 outputReferences(rl, 1);
337
338 }
339 }
340 }
341
printUsage()342 void printUsage() {
343
344 cerr << "\nUsage: siginf [options] <input file name>\n\n";
345 cerr << " Where options are :\n\n";
346 cerr << " --skiprefs/-s\n";
347 cerr << " Skip information on references - output main sig info only\n\n";
348
349 }
350
evaluate(int argc,char ** argv)351 int evaluate(int argc, char ** argv) {
352
353 char * filename = NULL;
354 bool skipRefs = false;
355
356 if (argc < 2) {
357
358 printUsage();
359 return 2;
360 }
361
362 // Run through parameters
363 int paramCount = 1;
364
365 while (paramCount < argc - 1) {
366
367 if (_stricmp(argv[paramCount], "--skiprefs") == 0 || _stricmp(argv[paramCount], "-s") == 0) {
368 skipRefs = true;
369 paramCount++;
370 }
371 else {
372 printUsage();
373 return 2;
374 }
375 }
376
377 if (paramCount >= argc) {
378 printUsage();
379 return 2;
380 }
381
382 filename = argv[paramCount];
383
384 // Create and set up the parser
385
386 XercesDOMParser * parser = new XercesDOMParser;
387 Janitor<XercesDOMParser> j_parser(parser);
388
389 parser->setDoNamespaces(true);
390 parser->setCreateEntityReferenceNodes(true);
391
392 // Now parse out file
393
394 bool errorsOccured = false;
395 XMLSize_t errorCount = 0;
396 try
397 {
398 parser->parse(filename);
399 errorCount = parser->getErrorCount();
400 }
401
402 catch (const XMLException& e)
403 {
404 char * msg = XMLString::transcode(e.getMessage());
405 cerr << "An error occurred during parsing\n Message: "
406 << msg << endl;
407 XSEC_RELEASE_XMLCH(msg);
408 errorsOccured = true;
409 }
410
411
412 catch (const DOMException& e)
413 {
414 cerr << "A DOM error occurred during parsing\n DOMException code: "
415 << e.code << endl;
416 errorsOccured = true;
417 }
418
419 if (errorCount > 0 || errorsOccured) {
420
421 cout << "Errors during parse" << endl;
422 return (2);
423
424 }
425
426 /*
427
428 Now that we have the parsed file, get the DOM document and start looking at it
429
430 */
431
432 DOMNode *doc = parser->getDocument();
433 DOMDocument *theDOM = parser->getDocument();
434
435 // Find the signature node
436
437 DOMNode *sigNode = findDSIGNode(doc, "Signature");
438
439 // Create the signature checker
440
441 if (sigNode == 0) {
442
443 cerr << "Could not find <Signature> node in " << argv[argc-1] << endl;
444 return 1;
445 }
446
447 XSECProvider prov;
448 DSIGSignature * sig = prov.newSignatureFromDOM(theDOM, sigNode);
449
450 try {
451
452 sig->load();
453
454 // If we didn't get an exception, things went well
455
456 cout << "Filename : " << filename << endl;
457
458 outputSignatureInfo(sig, skipRefs);
459 // if (skipRefs == false)
460 // result = sig->verifySignatureOnly();
461 // else
462 // result = sig->verify();
463 }
464
465 catch (const XSECException &e) {
466 char * msg = XMLString::transcode(e.getMsg());
467 cerr << "An error occurred during signature loading\n Message: "
468 << msg << endl;
469 XSEC_RELEASE_XMLCH(msg);
470 errorsOccured = true;
471 return 2;
472 }
473 catch (...) {
474
475 cerr << "Unknown Exception type occurred. Cleaning up and exiting\n" << endl;
476 return 2;
477
478 }
479
480 // Clean up
481
482 prov.releaseSignature(sig);
483 // Janitor will clean up the parser
484 return 0;
485 }
486
487
main(int argc,char ** argv)488 int main(int argc, char **argv) {
489
490 int retResult;
491
492 /* We output a version number to overcome a "feature" in Microsoft's memory
493 leak detection */
494
495 cout << "DSIG Info (Using Apache XML-Security-C Library v" << XSEC_VERSION_MAJOR <<
496 "." << XSEC_VERSION_MEDIUM << "." << XSEC_VERSION_MINOR << ")\n";
497
498 #if defined (_DEBUG) && defined (_MSC_VER)
499
500 // Do some memory debugging under Visual C++
501
502 _CrtMemState s1, s2, s3;
503
504 // At this point we are about to start really using XSEC, so
505 // Take a "before" checkpoing
506
507 _CrtMemCheckpoint( &s1 );
508
509 #endif
510
511 // Initialise the XML system
512
513 try {
514
515 XMLPlatformUtils::Initialize();
516 #ifdef XSEC_HAVE_XALAN
517 XPathEvaluator::initialize();
518 XalanTransformer::initialize();
519 #endif
520 XSECPlatformUtils::Initialise();
521
522 }
523 catch (const XMLException &e) {
524
525 cerr << "Error during initialisation of Xerces" << endl;
526 cerr << "Error Message = : "
527 << e.getMessage() << endl;
528
529 }
530
531 retResult = evaluate(argc, argv);
532
533 XSECPlatformUtils::Terminate();
534 #ifdef XSEC_HAVE_XALAN
535 XalanTransformer::terminate();
536 XPathEvaluator::terminate();
537 #endif
538 XMLPlatformUtils::Terminate();
539
540 #if defined (_DEBUG) && defined (_MSC_VER)
541
542 _CrtMemCheckpoint( &s2 );
543
544 if ( _CrtMemDifference( &s3, &s1, &s2 ) && s3.lCounts[1] > 1) {
545
546 std::cerr << "Total count = " << (unsigned int) s3.lTotalCount << endl;
547
548 // Send all reports to STDOUT
549 _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
550 _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
551 _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
552 _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
553 _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
554 _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
555
556 // Dumpy memory stats
557
558 _CrtMemDumpAllObjectsSince( &s3 );
559 _CrtMemDumpStatistics( &s3 );
560 }
561
562 // Now turn off memory leak checking and end as there are some
563 // Globals that are allocated that get seen as leaks (Xalan?)
564
565 int dbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
566 dbgFlag &= ~(_CRTDBG_LEAK_CHECK_DF);
567 _CrtSetDbgFlag( dbgFlag );
568
569 #endif
570
571 return retResult;
572 }
573