blob: 19f890e308127cde478e876f1fa9251f43ba5406 [file] [log] [blame]
/**
* 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;
}