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