| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /* |
| * XSEC |
| * |
| * siginf := Output information about a signature found in an XML file |
| * |
| * Author(s): Berin Lautenbach |
| * |
| * $Id$ |
| * |
| */ |
| |
| // XSEC |
| |
| #include <xsec/utils/XSECPlatformUtils.hpp> |
| #include <xsec/framework/XSECProvider.hpp> |
| #include <xsec/canon/XSECC14n20010315.hpp> |
| #include <xsec/dsig/DSIGSignature.hpp> |
| #include <xsec/dsig/DSIGReference.hpp> |
| #include <xsec/framework/XSECException.hpp> |
| #include <xsec/enc/XSECCryptoException.hpp> |
| #include <xsec/enc/XSECKeyInfoResolverDefault.hpp> |
| |
| #include <xsec/dsig/DSIGTransformC14n.hpp> |
| #include <xsec/dsig/DSIGTransformBase64.hpp> |
| #include <xsec/dsig/DSIGTransformXSL.hpp> |
| #include <xsec/dsig/DSIGTransformXPath.hpp> |
| #include <xsec/dsig/DSIGTransformXPathFilter.hpp> |
| #include <xsec/dsig/DSIGXPathFilterExpr.hpp> |
| #include <xsec/dsig/DSIGTransformEnvelope.hpp> |
| |
| #include <xsec/dsig/DSIGTransformList.hpp> |
| |
| #include "../../utils/XSECDOMUtils.hpp" |
| |
| // General |
| |
| #include <memory.h> |
| #include <string.h> |
| #include <iostream> |
| #include <stdlib.h> |
| |
| #if defined (_DEBUG) && defined (_MSC_VER) |
| #include <crtdbg.h> |
| #endif |
| |
| |
| #include <xercesc/util/PlatformUtils.hpp> |
| #include <xercesc/util/XMLString.hpp> |
| |
| #include <xercesc/dom/DOM.hpp> |
| #include <xercesc/parsers/XercesDOMParser.hpp> |
| #include <xercesc/util/XMLException.hpp> |
| #include <xercesc/util/XMLUri.hpp> |
| #include <xercesc/util/Janitor.hpp> |
| |
| XERCES_CPP_NAMESPACE_USE |
| |
| using std::cerr; |
| using std::cout; |
| using std::endl; |
| using std::ostream; |
| |
| #ifdef XSEC_HAVE_XALAN |
| |
| // XALAN |
| |
| #include <xalanc/XPath/XPathEvaluator.hpp> |
| #include <xalanc/XalanTransformer/XalanTransformer.hpp> |
| |
| XALAN_USING_XALAN(XPathEvaluator) |
| XALAN_USING_XALAN(XalanTransformer) |
| |
| #else |
| |
| ostream& operator<< (ostream& target, const XMLCh * s) |
| { |
| char *p = XMLString::transcode(s); |
| target << p; |
| XSEC_RELEASE_XMLCH(p); |
| return target; |
| } |
| |
| #endif |
| |
| class X2C { |
| |
| public: |
| |
| X2C(const XMLCh * in) { |
| mp_cStr = XMLString::transcode(in); |
| } |
| ~X2C() { |
| XSEC_RELEASE_XMLCH(mp_cStr); |
| } |
| |
| char * str(void) { |
| return mp_cStr; |
| } |
| |
| private : |
| |
| char * mp_cStr; |
| |
| }; |
| |
| ostream & operator<<(ostream& target, X2C &x) { |
| target << x.str(); |
| return target; |
| } |
| |
| inline |
| void levelSet(unsigned int level) { |
| |
| for (unsigned int i = 0; i < level; ++i) |
| cout << " "; |
| |
| } |
| |
| void outputTransform(const DSIGTransform * t, unsigned int level) { |
| |
| |
| if (dynamic_cast<const DSIGTransformBase64*>(t)) { |
| cout << "Base64 Decode" << endl; |
| } |
| else if (dynamic_cast<const DSIGTransformC14n*>(t)) { |
| const XMLCh* cm = dynamic_cast<const DSIGTransformC14n*>(t)->getCanonicalizationMethod(); |
| if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_NOC)) { |
| cout << "c14n 1.0 canonicalization (without comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_COM)) { |
| cout << "c14n 1.0 canonicalization (with comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_NOC)) { |
| cout << "c14n 1.1 canonicalization (without comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_COM)) { |
| cout << "c14n 1.1 canonicalization (with comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_NOC)) { |
| cout << "Exclusive c14n 1.0 canonicalization (without comments)" << endl; |
| if (dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList() != NULL) { |
| levelSet(level); |
| cout << "Inclusive prefixes : " << |
| X2C(dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList()).str() << endl; |
| } |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_COM)) { |
| cout << "Exclusive c14n 1.0 canonicalization (with comments)" << endl; |
| if (dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList() != NULL) { |
| levelSet(level); |
| cout << "Inclusive prefixes : " << |
| X2C(dynamic_cast<const DSIGTransformC14n*>(t)->getPrefixList()).str() << endl; |
| } |
| } |
| else { |
| cout << "Unknown c14n method" << endl; |
| } |
| } |
| else if (dynamic_cast<const DSIGTransformEnvelope*>(t)) { |
| cout << "enveloped signature" << endl; |
| } |
| else if (dynamic_cast<const DSIGTransformXPath*>(t)) { |
| const DSIGTransformXPath* xp = dynamic_cast<const DSIGTransformXPath*>(t); |
| |
| cout << "XPath" << endl; |
| // Check for namespaces |
| DOMNamedNodeMap* atts = xp->getNamespaces(); |
| |
| if (atts != 0) { |
| XMLSize_t s = atts->getLength(); |
| for (XMLSize_t i = 0 ; i < s; ++i) { |
| levelSet(level); |
| cout << "Namespace : " << X2C(atts->item(i)->getNodeName()).str() << |
| "=\"" << X2C(atts->item(i)->getNodeValue()).str() << "\"\n"; |
| } |
| } |
| levelSet(level); |
| // Hmm - this is really a bug. This should return a XMLCh string |
| cout << "Expr : " << xp->getExpression() << endl; |
| } |
| else if (dynamic_cast<const DSIGTransformXPathFilter*>(t)) { |
| const DSIGTransformXPathFilter * xpf = dynamic_cast<const DSIGTransformXPathFilter*>(t); |
| |
| cout << "XPath-Filter2" << endl; |
| |
| unsigned int s = xpf->getExprNum(); |
| |
| for (unsigned int i = 0; i < s; ++i) { |
| |
| levelSet(level); |
| cout << "Filter : "; |
| |
| const DSIGXPathFilterExpr * e = xpf->expr(i); |
| |
| switch (e->getFilterType()) { |
| |
| case DSIGXPathFilterExpr::FILTER_UNION : |
| cout << "union : \""; |
| break; |
| case DSIGXPathFilterExpr::FILTER_INTERSECT : |
| cout << "intersect : \""; |
| break; |
| default : |
| cout << "subtract : \""; |
| } |
| |
| // Now the expression |
| char * str = XMLString::transcode(e->getFilter()); |
| cout << str << "\"" << endl; |
| XSEC_RELEASE_XMLCH(str); |
| } |
| } |
| else if (dynamic_cast<const DSIGTransformXSL*>(t)) { |
| cout << "XSLT" << endl; |
| // Really should serialise and output stylesheet. |
| } |
| else { |
| cout << "unknown transform type" << endl; |
| } |
| } |
| |
| void outputReferences(DSIGReferenceList *rl, unsigned int level) { |
| |
| int s = (int) rl->getSize(); |
| |
| for (int i = 0; i < s; ++i) { |
| |
| levelSet(level); |
| cout << "Reference " << i + 1 << " : " << endl; |
| levelSet(level + 1); |
| cout << "URI : \"" << X2C(rl->item(i)->getURI()).str() << "\"" << endl; |
| levelSet(level + 1); |
| cout << "Digest Algorithm : "; |
| char* alg = XMLString::transcode(rl->item(i)->getAlgorithmURI()); |
| cout << (alg ? alg : "Unknown") << endl; |
| XSEC_RELEASE_XMLCH(alg); |
| |
| // Now the transforms |
| DSIGTransformList * tl = rl->item(i)->getTransforms(); |
| if (tl != NULL) { |
| |
| int tlSize = (int) tl->getSize(); |
| for (int j = 0 ; j < tlSize; ++j) { |
| |
| levelSet(level+1); |
| cout << "Transform " << j + 1 << " : "; |
| outputTransform(tl->item(j), level + 2); |
| |
| } |
| |
| } |
| |
| if (rl->item(i)->isManifest() == true) { |
| |
| levelSet(level + 1); |
| cout << "Manifest References : " << endl; |
| outputReferences(rl->item(i)->getManifestReferenceList(), level + 2); |
| levelSet(level + 1); |
| cout << "End Manifest References" << endl; |
| |
| } |
| |
| } |
| |
| } |
| |
| void outputSignatureInfo(DSIGSignature *sig, bool skipReferences) { |
| |
| // First get some information about the main signature |
| cout << "Signature (Signed Info) settings : " << endl; |
| cout << " Canonicalization Method : "; |
| |
| const XMLCh* cm = sig->getCanonicalizationMethod(); |
| if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_NOC)) { |
| cout << "c14n 1.0 canonicalization (without comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N_COM)) { |
| cout << "c14n 1.0 canonicalization (with comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_NOC)) { |
| cout << "c14n 1.1 canonicalization (without comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIC14N11_COM)) { |
| cout << "c14n 1.1 canonicalization (with comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_NOC)) { |
| cout << "Exclusive c14n 1.0 canonicalization (without comments)" << endl; |
| } |
| else if (XMLString::equals(cm, DSIGConstants::s_unicodeStrURIEXC_C14N_COM)) { |
| cout << "Exclusive c14n 1.0 canonicalization (with comments)" << endl; |
| } |
| else { |
| cout << "Unknown c14n method" << endl; |
| } |
| |
| cout << endl; |
| |
| cout << " Signature Algorithm : "; |
| char* alg = XMLString::transcode(sig->getAlgorithmURI()); |
| cout << (alg ? alg : "Unknown") << endl; |
| XSEC_RELEASE_XMLCH(alg); |
| |
| // Read in the references and output |
| |
| if (skipReferences == false) { |
| |
| DSIGReferenceList * rl = sig->getReferenceList(); |
| |
| if (rl != NULL) { |
| |
| cout << endl << "Reference List : " << endl; |
| outputReferences(rl, 1); |
| |
| } |
| } |
| } |
| |
| void printUsage() { |
| |
| cerr << "\nUsage: siginf [options] <input file name>\n\n"; |
| cerr << " Where options are :\n\n"; |
| cerr << " --skiprefs/-s\n"; |
| cerr << " Skip information on references - output main sig info only\n\n"; |
| |
| } |
| |
| int evaluate(int argc, char ** argv) { |
| |
| char * filename = NULL; |
| bool skipRefs = false; |
| |
| if (argc < 2) { |
| |
| printUsage(); |
| return 2; |
| } |
| |
| // Run through parameters |
| int paramCount = 1; |
| |
| while (paramCount < argc - 1) { |
| |
| if (_stricmp(argv[paramCount], "--skiprefs") == 0 || _stricmp(argv[paramCount], "-s") == 0) { |
| skipRefs = true; |
| paramCount++; |
| } |
| else { |
| printUsage(); |
| return 2; |
| } |
| } |
| |
| if (paramCount >= argc) { |
| printUsage(); |
| return 2; |
| } |
| |
| filename = argv[paramCount]; |
| |
| // Create and set up the parser |
| |
| XercesDOMParser * parser = new XercesDOMParser; |
| Janitor<XercesDOMParser> j_parser(parser); |
| |
| parser->setDoNamespaces(true); |
| parser->setCreateEntityReferenceNodes(true); |
| |
| // Now parse out file |
| |
| bool errorsOccured = false; |
| XMLSize_t errorCount = 0; |
| try |
| { |
| parser->parse(filename); |
| errorCount = parser->getErrorCount(); |
| } |
| |
| catch (const XMLException& e) |
| { |
| char * msg = XMLString::transcode(e.getMessage()); |
| cerr << "An error occurred during parsing\n Message: " |
| << msg << endl; |
| XSEC_RELEASE_XMLCH(msg); |
| errorsOccured = true; |
| } |
| |
| |
| catch (const DOMException& e) |
| { |
| cerr << "A DOM error occurred during parsing\n DOMException code: " |
| << e.code << endl; |
| errorsOccured = true; |
| } |
| |
| if (errorCount > 0 || errorsOccured) { |
| |
| cout << "Errors during parse" << endl; |
| return (2); |
| |
| } |
| |
| /* |
| |
| Now that we have the parsed file, get the DOM document and start looking at it |
| |
| */ |
| |
| DOMNode *doc = parser->getDocument(); |
| DOMDocument *theDOM = parser->getDocument(); |
| |
| // Find the signature node |
| |
| DOMNode *sigNode = findDSIGNode(doc, "Signature"); |
| |
| // Create the signature checker |
| |
| if (sigNode == 0) { |
| |
| cerr << "Could not find <Signature> node in " << argv[argc-1] << endl; |
| return 1; |
| } |
| |
| XSECProvider prov; |
| DSIGSignature * sig = prov.newSignatureFromDOM(theDOM, sigNode); |
| |
| try { |
| |
| sig->load(); |
| |
| // If we didn't get an exception, things went well |
| |
| cout << "Filename : " << filename << endl; |
| |
| outputSignatureInfo(sig, skipRefs); |
| // if (skipRefs == false) |
| // result = sig->verifySignatureOnly(); |
| // else |
| // result = sig->verify(); |
| } |
| |
| catch (const XSECException &e) { |
| char * msg = XMLString::transcode(e.getMsg()); |
| cerr << "An error occurred during signature loading\n Message: " |
| << msg << endl; |
| XSEC_RELEASE_XMLCH(msg); |
| errorsOccured = true; |
| return 2; |
| } |
| catch (...) { |
| |
| cerr << "Unknown Exception type occurred. Cleaning up and exiting\n" << endl; |
| return 2; |
| |
| } |
| |
| // Clean up |
| |
| prov.releaseSignature(sig); |
| // Janitor will clean up the parser |
| return 0; |
| } |
| |
| |
| int main(int argc, char **argv) { |
| |
| int retResult; |
| |
| /* We output a version number to overcome a "feature" in Microsoft's memory |
| leak detection */ |
| |
| cout << "DSIG Info (Using Apache XML-Security-C Library v" << XSEC_VERSION_MAJOR << |
| "." << XSEC_VERSION_MEDIUM << "." << XSEC_VERSION_MINOR << ")\n"; |
| |
| #if defined (_DEBUG) && defined (_MSC_VER) |
| |
| // Do some memory debugging under Visual C++ |
| |
| _CrtMemState s1, s2, s3; |
| |
| // At this point we are about to start really using XSEC, so |
| // Take a "before" checkpoing |
| |
| _CrtMemCheckpoint( &s1 ); |
| |
| #endif |
| |
| // Initialise the XML system |
| |
| try { |
| |
| XMLPlatformUtils::Initialize(); |
| #ifdef XSEC_HAVE_XALAN |
| XPathEvaluator::initialize(); |
| XalanTransformer::initialize(); |
| #endif |
| XSECPlatformUtils::Initialise(); |
| |
| } |
| catch (const XMLException &e) { |
| |
| cerr << "Error during initialisation of Xerces" << endl; |
| cerr << "Error Message = : " |
| << e.getMessage() << endl; |
| |
| } |
| |
| retResult = evaluate(argc, argv); |
| |
| XSECPlatformUtils::Terminate(); |
| #ifdef XSEC_HAVE_XALAN |
| XalanTransformer::terminate(); |
| XPathEvaluator::terminate(); |
| #endif |
| XMLPlatformUtils::Terminate(); |
| |
| #if defined (_DEBUG) && defined (_MSC_VER) |
| |
| _CrtMemCheckpoint( &s2 ); |
| |
| if ( _CrtMemDifference( &s3, &s1, &s2 ) && s3.lCounts[1] > 1) { |
| |
| std::cerr << "Total count = " << (unsigned int) s3.lTotalCount << endl; |
| |
| // Send all reports to STDOUT |
| _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); |
| _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); |
| _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); |
| _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); |
| _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); |
| _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT ); |
| |
| // Dumpy memory stats |
| |
| _CrtMemDumpAllObjectsSince( &s3 ); |
| _CrtMemDumpStatistics( &s3 ); |
| } |
| |
| // Now turn off memory leak checking and end as there are some |
| // Globals that are allocated that get seen as leaks (Xalan?) |
| |
| int dbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); |
| dbgFlag &= ~(_CRTDBG_LEAK_CHECK_DF); |
| _CrtSetDbgFlag( dbgFlag ); |
| |
| #endif |
| |
| return retResult; |
| } |