| /** |
| * 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 |
| * |
| * txfmout:= tool to output the results of the various transforms |
| * used when validating the attached signature. |
| * |
| * 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/framework/XSECURIResolver.hpp> |
| #include <xsec/enc/XSECCryptoException.hpp> |
| #include <xsec/utils/XSECBinTXFMInputStream.hpp> |
| |
| #include "../../utils/XSECDOMUtils.hpp" |
| |
| // General |
| |
| #include <memory.h> |
| #include <string.h> |
| #include <iostream> |
| #include <fstream> |
| #include <stdlib.h> |
| |
| #if defined(HAVE_UNISTD_H) |
| # include <unistd.h> |
| #else |
| # if defined(HAVE_DIRECT_H) |
| # include <direct.h> |
| # endif |
| #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/XMLNetAccessor.hpp> |
| #include <xercesc/util/XMLUri.hpp> |
| |
| XERCES_CPP_NAMESPACE_USE |
| |
| using std::ios; |
| using std::cout; |
| using std::cerr; |
| using std::endl; |
| using std::ofstream; |
| |
| #ifdef XSEC_HAVE_XALAN |
| |
| // XALAN |
| |
| #include <xalanc/XPath/XPathEvaluator.hpp> |
| #include <xalanc/XalanTransformer/XalanTransformer.hpp> |
| |
| // If this isn't defined, we're on Xalan 1.12+ and require modern C++ |
| #ifndef XALAN_USING_XALAN |
| # define XALAN_USING_XALAN(NAME) using xalanc :: NAME; |
| #endif |
| |
| XALAN_USING_XALAN(XPathEvaluator) |
| XALAN_USING_XALAN(XalanTransformer) |
| |
| #else |
| |
| std::ostream& operator<< (std::ostream& target, const XMLCh * s) |
| { |
| char *p = XMLString::transcode(s); |
| target << p; |
| XSEC_RELEASE_XMLCH(p); |
| return target; |
| } |
| |
| #endif |
| |
| // --------------------------------------------------------------------------- |
| // Outputter |
| // --------------------------------------------------------------------------- |
| |
| class outputter { |
| |
| public: |
| |
| outputter(); |
| ~outputter(); |
| |
| // Set methods |
| |
| // Will tell not to use cout and open on this base |
| void setFilename(const char * name); |
| // Will append a number and re-open for each "open" call |
| void setNewFilePerOpen(); |
| |
| // Re-open the file if necessary (new output) |
| void openSection(); |
| // Close if necessary (output section finished) |
| void closeSection(); |
| // Close of and finish |
| void closeAll(); |
| |
| // Output a buffer |
| void output(const unsigned char * buf, unsigned int sz); |
| |
| // Info |
| int getIndex(void); |
| |
| private: |
| |
| char * m_name; // Name of the file (or base name) |
| bool m_cout; // Are we using cout? |
| bool m_newFilePerOpen; // Should we re-open? |
| bool m_fileOpen; // Do we have an open file we should close? |
| int m_counter; // The counter |
| ofstream m_out; // Current output file |
| |
| }; |
| |
| outputter::outputter() : |
| m_name(0), |
| m_cout(true), |
| m_newFilePerOpen(false), |
| m_fileOpen(false), |
| m_counter(0) { |
| |
| } |
| |
| outputter::~outputter() { |
| |
| if (m_fileOpen == true) { |
| |
| m_out.close(); |
| |
| m_fileOpen = false; |
| |
| } |
| |
| if (m_name != 0) |
| delete[] m_name; |
| |
| } |
| |
| void outputter::setFilename(const char * name) { |
| |
| m_name = strdup(name); |
| m_cout = false; |
| |
| } |
| |
| void outputter::setNewFilePerOpen() { |
| |
| m_newFilePerOpen = true; |
| |
| } |
| |
| void outputter::openSection() { |
| |
| if (m_cout == true) |
| return; |
| |
| if (m_fileOpen == true && m_newFilePerOpen == false) |
| return; |
| |
| if (m_out.is_open() != 0) { |
| |
| m_out.close(); |
| |
| } |
| |
| char * buf = new char[strlen(m_name) + 10]; |
| strcpy(buf, m_name); |
| |
| if (m_newFilePerOpen == true) { |
| |
| char numBuf[10]; |
| sprintf(numBuf, "%d", m_counter); |
| //_itoa(m_counter, numBuf, 10); |
| strcat(buf, "."); |
| strcat(buf, numBuf); |
| |
| } |
| |
| m_out.open(buf, ios::out | ios::binary); |
| m_fileOpen = true; |
| delete [] buf; |
| } |
| |
| void outputter::closeSection() { |
| |
| m_counter++; |
| |
| if (m_cout == false && m_newFilePerOpen == true && m_out.is_open() != 0) { |
| |
| m_out.close(); |
| m_fileOpen = false; |
| |
| } |
| |
| |
| } |
| |
| int outputter::getIndex(void) { |
| |
| return m_counter; |
| |
| } |
| |
| void outputter::closeAll() { |
| |
| if (m_out.is_open() != 0) |
| m_out.close(); |
| |
| m_fileOpen = false; |
| |
| } |
| |
| |
| void outputter::output(const unsigned char * buf, unsigned int sz) { |
| |
| if (m_cout || m_out.is_open() == false) { |
| |
| cout.write((const char *) buf,sz); |
| |
| } |
| else { |
| |
| m_out.write((const char *) buf, sz); |
| |
| } |
| |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // Main Program |
| // --------------------------------------------------------------------------- |
| |
| |
| |
| void printUsage(void) { |
| |
| cerr << "\nUsage: txfmout [options] <input file name>\n\n"; |
| cerr << " Where options are :\n\n"; |
| cerr << " --signedinfo/-s\n"; |
| cerr << " Output canonicalised SignedInfo only\n"; |
| cerr << " --out/-o\n"; |
| cerr << " Output to the nominated file name\n"; |
| cerr << " --references/-r [num]\n"; |
| cerr << " Output only references. [num] defines a single reference to output\n"; |
| cerr << " --newfiles/-n\n"; |
| cerr << " Create a new file for each reference/SignedInfo (append .#)\n"; |
| |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Reference Outputter |
| // --------------------------------------------------------------------------- |
| |
| void outputReferenceList (DSIGReferenceList * lst, outputter & theOutputter, int refNum) { |
| |
| if (lst == 0) |
| return; |
| |
| DSIGReference * ref; |
| unsigned int sz; |
| XSECBinTXFMInputStream * is; |
| unsigned char buf[1024]; |
| |
| DSIGReferenceList::size_type lstSz = (int) lst->getSize(); |
| |
| for (DSIGReferenceList::size_type i = 0; i < lstSz; ++i) { |
| |
| ref = lst->item(i); |
| if (refNum == -1 || theOutputter.getIndex() == refNum) { |
| theOutputter.openSection(); |
| |
| try { |
| is = ref->makeBinInputStream(); |
| } |
| catch (const NetAccessorException&) { |
| |
| cerr << "Network error in reference " << theOutputter.getIndex() << endl; |
| is = 0; |
| } |
| |
| |
| if (is != 0) { |
| |
| sz = (unsigned int) is->readBytes(buf, 1023); |
| |
| while (sz != 0) { |
| |
| buf[sz] = '\0'; |
| theOutputter.output(buf, sz); |
| |
| sz = (unsigned int) is->readBytes(buf, 1023); |
| |
| } |
| |
| delete is; |
| |
| } |
| } |
| theOutputter.closeSection(); |
| |
| } |
| |
| // Look for manifests |
| for (DSIGReferenceList::size_type i = 0; i < lstSz; ++i) { |
| |
| ref = lst->item(i); |
| |
| if (ref->isManifest() == true) { |
| outputReferenceList(ref->getManifestReferenceList(), theOutputter, refNum); |
| } |
| |
| } |
| |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Main Program |
| // --------------------------------------------------------------------------- |
| |
| |
| int main(int argc, char **argv) { |
| |
| char * filename = NULL; |
| bool signedInfo = true; |
| bool references = true; |
| outputter theOutputter; |
| int refNum = -1; |
| |
| if (argc < 2) { |
| |
| printUsage(); |
| exit (2); |
| } |
| |
| // Run through parameters |
| int paramCount = 1; |
| |
| while (paramCount < argc - 1) { |
| |
| if (_stricmp(argv[paramCount], "--signedinfo") == 0 || _stricmp(argv[paramCount], "-s") == 0) { |
| paramCount++; |
| references = false; |
| } |
| else if (_stricmp(argv[paramCount], "--out") == 0 || _stricmp(argv[paramCount], "-o") == 0) { |
| paramCount++; |
| theOutputter.setFilename(argv[paramCount++]); |
| } |
| else if (_stricmp(argv[paramCount], "--references") == 0 || _stricmp(argv[paramCount], "-r") == 0) { |
| paramCount++; |
| signedInfo = false; |
| if (argv[paramCount][0] >= '0' && argv[paramCount][0] <= '9') |
| refNum = atoi(argv[paramCount++]); |
| } |
| else if (_stricmp(argv[paramCount], "--newfiles") == 0 || _stricmp(argv[paramCount], "-n") == 0) { |
| paramCount++; |
| theOutputter.setNewFilePerOpen(); |
| } |
| else { |
| printUsage(); |
| exit(2); |
| } |
| } |
| |
| if (paramCount >= argc) { |
| printUsage(); |
| exit (2); |
| } |
| |
| filename = argv[paramCount]; |
| |
| // 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; |
| |
| } |
| |
| // Create and set up the parser |
| |
| XercesDOMParser * parser = new XercesDOMParser; |
| |
| parser->setDoNamespaces(true); |
| parser->setCreateEntityReferenceNodes(true); |
| |
| // Now parse out file |
| |
| bool errorsOccured = false; |
| XMLSize_t errorCount = 0; |
| try |
| { |
| parser->parse(filename); |
| errorCount = parser->getErrorCount(); |
| if (errorCount > 0) |
| errorsOccured = true; |
| } |
| |
| catch (const XMLException& e) |
| { |
| cerr << "An error occurred during parsing\n Message: " |
| << e.getMessage() << endl; |
| errorsOccured = true; |
| } |
| |
| |
| catch (const DOMException& e) |
| { |
| cerr << "A DOM error occurred during parsing\n DOMException code: " |
| << e.code << endl; |
| errorsOccured = true; |
| } |
| |
| if (errorsOccured) { |
| |
| cout << "Errors during parse" << endl; |
| exit (2); |
| |
| } |
| |
| /* |
| |
| Now that we have the parsed file, get the DOM document and start looking at it |
| |
| */ |
| |
| DOMNode *doc; // The document that we parsed |
| |
| 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; |
| exit(2); |
| } |
| |
| XSECProvider prov; |
| DSIGSignature * sig = prov.newSignatureFromDOM(theDOM, sigNode); |
| sig->registerIdAttributeName(MAKE_UNICODE_STRING("ID")); |
| |
| // Map out base path of the file |
| #if XSEC_HAVE_GETCWD_DYN |
| char *path = getcwd(NULL, 0); |
| char *baseURI = (char*)malloc(strlen(path) + 8 + 1 + strlen(filename) + 1); |
| #else |
| char path[PATH_MAX]; |
| char baseURI[(PATH_MAX * 2) + 10]; |
| getcwd(path, PATH_MAX); |
| #endif |
| strcpy(baseURI, "file:///"); |
| strcat(baseURI, path); |
| strcat(baseURI, "/"); |
| strcat(baseURI, filename); |
| |
| // Find any ':' and "\" characters |
| int lastSlash = 0; |
| for (unsigned int i = 8; i < strlen(baseURI); ++i) { |
| if (baseURI[i] == '\\') { |
| lastSlash = i; |
| baseURI[i] = '/'; |
| } |
| else if (baseURI[i] == '/') |
| lastSlash = i; |
| } |
| |
| // The last "\\" must prefix the filename |
| baseURI[lastSlash + 1] = '\0'; |
| |
| sig->getURIResolver()->setBaseURI(MAKE_UNICODE_STRING(baseURI)); |
| #if XSEC_HAVE_GETCWD_DYN |
| free(path); |
| free(baseURI); |
| #endif |
| |
| |
| try { |
| |
| XSECBinTXFMInputStream * is; |
| XMLByte buf[1024]; |
| unsigned int sz; |
| |
| sig->load(); |
| if (references) { |
| outputReferenceList(sig->getReferenceList(), theOutputter, refNum); |
| |
| } |
| if (signedInfo) { |
| is = sig->makeBinInputStream(); |
| if (is != NULL) { |
| |
| theOutputter.openSection(); |
| sz = (unsigned int) is->readBytes(buf, 1023); |
| |
| while (sz != 0) { |
| |
| buf[sz] = '\0'; |
| theOutputter.output(buf, sz); |
| |
| sz = (unsigned int) is->readBytes(buf, 1023); |
| |
| } |
| theOutputter.closeSection(); |
| |
| delete is; |
| |
| } |
| } |
| } |
| |
| catch (const XSECException &e) { |
| char * m = XMLString::transcode(e.getMsg()); |
| cerr << "An error occurred during signature processing\n Message: " |
| << m << endl; |
| XSEC_RELEASE_XMLCH(m); |
| errorsOccured = true; |
| exit (2); |
| } |
| |
| theOutputter.closeAll(); |
| |
| prov.releaseSignature(sig); |
| |
| return 0; |
| } |