xsec/tools/xtest/xtest.cpp (1,792 lines of code) (raw):

/** * 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 * * xtest := basic test application to run through a series of tests of * the XSEC library. * * Author(s): Berin Lautenbach * * $Id$ * */ #include <xsec/framework/XSECDefs.hpp> #include <cassert> #include <memory.h> #include <iostream> #include <stdlib.h> #include <xercesc/util/PlatformUtils.hpp> #include <xercesc/util/XMLUniDefs.hpp> #include <xercesc/util/XMLString.hpp> #include <xercesc/parsers/XercesDOMParser.hpp> #include <xercesc/framework/XMLFormatter.hpp> #include <xercesc/framework/StdOutFormatTarget.hpp> #include <xercesc/framework/MemBufFormatTarget.hpp> #include <xercesc/framework/MemBufInputSource.hpp> #include <xercesc/dom/DOM.hpp> #include <xercesc/util/XMLException.hpp> #include <xercesc/util/Janitor.hpp> #include <xsec/transformers/TXFMOutputFile.hpp> #include <xsec/dsig/DSIGTransformXPath.hpp> #include <xsec/dsig/DSIGTransformXPathFilter.hpp> #include <xsec/dsig/DSIGTransformC14n.hpp> #include <xsec/dsig/DSIGObject.hpp> // XALAN #ifdef XSEC_HAVE_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) #endif // XSEC #include <xsec/canon/XSECC14n20010315.hpp> #include <xsec/dsig/DSIGReference.hpp> #include <xsec/dsig/DSIGSignature.hpp> #include <xsec/dsig/DSIGKeyInfoX509.hpp> #include <xsec/dsig/DSIGKeyInfoName.hpp> #include <xsec/dsig/DSIGKeyInfoPGPData.hpp> #include <xsec/dsig/DSIGKeyInfoSPKIData.hpp> #include <xsec/dsig/DSIGKeyInfoMgmtData.hpp> #include <xsec/enc/XSECCryptoException.hpp> #include <xsec/enc/XSECCryptoSymmetricKey.hpp> #include <xsec/framework/XSECError.hpp> #include <xsec/framework/XSECProvider.hpp> #include <xsec/xenc/XENCCipher.hpp> #include <xsec/xenc/XENCEncryptedData.hpp> #include <xsec/xenc/XENCEncryptedKey.hpp> #include <xsec/xenc/XENCEncryptionMethod.hpp> #include <xsec/utils/XSECNameSpaceExpander.hpp> #include <xsec/utils/XSECBinTXFMInputStream.hpp> #include <xsec/utils/XSECPlatformUtils.hpp> #include "../../utils/XSECDOMUtils.hpp" #if defined (XSEC_HAVE_OPENSSL) # include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp> # include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp> # include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp> # include <openssl/rand.h> # include <openssl/evp.h> # include <openssl/pem.h> #endif #if defined (XSEC_HAVE_WINCAPI) # include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp> # include <xsec/enc/WinCAPI/WinCAPICryptoKeyRSA.hpp> # include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp> #endif #if defined (XSEC_HAVE_NSS) # include <xsec/enc/NSS/NSSCryptoKeyHMAC.hpp> # include <xsec/enc/NSS/NSSCryptoKeyRSA.hpp> # include <xsec/enc/NSS/NSSCryptoProvider.hpp> #endif using std::ostream; using std::cout; using std::cerr; using std::endl; using std::flush; /* * Because of all the characters, it's easiest to inject entire Xerces namespace * into global */ XERCES_CPP_NAMESPACE_USE // -------------------------------------------------------------------------------- // Global variables // -------------------------------------------------------------------------------- bool g_printDocs = false; bool g_useWinCAPI = false; bool g_useNSS = false; bool g_haveAES = true; bool g_testGCM = true; // -------------------------------------------------------------------------------- // Known "Good" Values // -------------------------------------------------------------------------------- unsigned char createdDocRefs [9][20] = { { 0x51, 0x3c, 0xb5, 0xdf, 0xb9, 0x1e, 0x9d, 0xaf, 0xd4, 0x4a, 0x95, 0x79, 0xf1, 0xd6, 0x54, 0xe, 0xb0, 0xb0, 0x29, 0xe3, }, { 0x51, 0x3c, 0xb5, 0xdf, 0xb9, 0x1e, 0x9d, 0xaf, 0xd4, 0x4a, 0x95, 0x79, 0xf1, 0xd6, 0x54, 0xe, 0xb0, 0xb0, 0x29, 0xe3, }, { 0x52, 0x74, 0xc3, 0xe4, 0xc5, 0xf7, 0x20, 0xb0, 0xd9, 0x52, 0xdb, 0xb3, 0xee, 0x46, 0x66, 0x8f, 0xe1, 0xb6, 0x30, 0x9d, }, { 0x5a, 0x14, 0x9c, 0x5a, 0x40, 0x34, 0x51, 0x4f, 0xef, 0x1d, 0x85, 0x44, 0xc7, 0x2a, 0xd3, 0xd2, 0x2, 0xed, 0x67, 0xb4, }, { 0x88, 0xd1, 0x65, 0xed, 0x2a, 0xe7, 0xc0, 0xbd, 0xea, 0x3e, 0xe6, 0xf3, 0xd4, 0x8c, 0xf7, 0xdd, 0xc8, 0x85, 0xa9, 0x6d, }, { 0x52, 0x74, 0xc3, 0xe4, 0xc5, 0xf7, 0x20, 0xb0, 0xd9, 0x52, 0xdb, 0xb3, 0xee, 0x46, 0x66, 0x8f, 0xe1, 0xb6, 0x30, 0x9d, }, { 0x52, 0x74, 0xc3, 0xe4, 0xc5, 0xf7, 0x20, 0xb0, 0xd9, 0x52, 0xdb, 0xb3, 0xee, 0x46, 0x66, 0x8f, 0xe1, 0xb6, 0x30, 0x9d, }, { 0x69, 0xBA, 0xF1, 0x53, 0x7D, 0x81, 0x78, 0xCA, 0xCA, 0x60, 0x3B, 0x2F, 0x55, 0x9C, 0x8E, 0x5F, 0xEB, 0x35, 0x38, 0x25, }, { 0x51, 0x3c, 0xb5, 0xdf, 0xb9, 0x1e, 0x9d, 0xaf, 0xd4, 0x4a, 0x95, 0x79, 0xf1, 0xd6, 0x54, 0xe, 0xb0, 0xb0, 0x29, 0xe3, } }; unsigned char longShaRefs [4][64] = { { 0x7f, 0xa4, 0xab, 0xe8, 0x07, 0x06, 0x35, 0xf3, 0xa3, 0x56, 0xe8, 0x64, 0x2d, 0xc4, 0x7c, 0x8c, 0x1e, 0x48, 0x74, 0xf0, 0x48, 0x63, 0x1b, 0xea, 0x57, 0xec, 0x96, 0xa6, }, { 0x75, 0xec, 0xba, 0x51, 0xda, 0xb7, 0x42, 0x16, 0x34, 0x2d, 0xd7, 0x4e, 0x6a, 0x33, 0xb6, 0xb3, 0xe3, 0x2d, 0x28, 0xf6, 0x7b, 0x87, 0x21, 0xfd, 0xd2, 0x2e, 0x50, 0xb9, 0x55, 0x81, 0x23, 0x06, }, { 0x99, 0x25, 0x92, 0xa3, 0xa9, 0x44, 0x12, 0x4d, 0xa1, 0x86, 0x3f, 0x81, 0xd3, 0xa7, 0x37, 0x61, 0xff, 0x86, 0x9f, 0x02, 0x16, 0x48, 0x16, 0xa0, 0xec, 0x7c, 0xd5, 0x33, 0x30, 0xeb, 0xb2, 0x9f, 0x93, 0xb9, 0x4a, 0x32, 0x20, 0x2e, 0x8a, 0xfd, 0xa6, 0x6e, 0x67, 0x1d, 0x96, 0xcd, 0xf1, 0xcb, }, { 0xf8, 0xf5, 0xf3, 0xb6, 0xab, 0x7c, 0x25, 0x52, 0x06, 0x23, 0x2c, 0x9f, 0x4e, 0x25, 0x0f, 0x16, 0x58, 0xf3, 0xc6, 0xdc, 0xb4, 0x85, 0x04, 0x3d, 0x9f, 0xee, 0x7d, 0x5d, 0x73, 0x86, 0xe3, 0xd4, 0x3a, 0xe0, 0xd5, 0x8a, 0xec, 0x7f, 0xd4, 0x63, 0x4f, 0x9a, 0xcf, 0xfa, 0x15, 0xdb, 0x0f, 0xe5, 0x09, 0x6b, 0xf1, 0xa1, 0x36, 0x05, 0x42, 0x69, 0x49, 0xc3, 0x9e, 0x8c, 0x99, 0xa6, 0x75, 0xae, }, }; // -------------------------------------------------------------------------------- // Some test data // -------------------------------------------------------------------------------- // "CN=<Test,>,O=XSEC " XMLCh s_tstDName[] = { chLatin_C, chLatin_N, chEqual, chOpenAngle, chLatin_T, chLatin_e, chLatin_s, chLatin_t, chComma, chCloseAngle, chComma, chLatin_O, chEqual, chLatin_X, chLatin_S, chLatin_E, chLatin_C, chSpace, chSpace, chNull }; XMLCh s_tstKeyName[] = { chLatin_F, chLatin_r, chLatin_e, chLatin_d, chSingleQuote, chLatin_s, chSpace, chLatin_n, chLatin_a, chLatin_m, chLatin_e, chNull }; XMLCh s_tstPGPKeyID[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_P, chLatin_G, chLatin_P, chSpace, chLatin_I, chLatin_D, chNull }; XMLCh s_tstPGPKeyPacket[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_P, chLatin_G, chLatin_P, chSpace, chLatin_P, chLatin_a, chLatin_c, chLatin_k, chLatin_e, chLatin_t, chNull }; XMLCh s_tstSexp1[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_S, chLatin_e, chLatin_x, chLatin_p, chDigit_1, chNull }; XMLCh s_tstSexp2[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_S, chLatin_e, chLatin_x, chLatin_p, chDigit_2, chNull }; XMLCh s_tstMgmtData[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_M, chLatin_g, chLatin_m, chLatin_t, chSpace, chLatin_D, chLatin_a, chLatin_t, chLatin_a, chNull }; XMLCh s_tstCarriedKeyName[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_C, chLatin_a, chLatin_r, chLatin_r, chLatin_y, chNull }; XMLCh s_tstRecipient[] = { chLatin_D, chLatin_u, chLatin_m, chLatin_m, chLatin_y, chSpace, chLatin_R, chLatin_e, chLatin_c, chLatin_i, chLatin_p, chLatin_i, chLatin_e, chLatin_n, chLatin_t, chNull }; XMLCh s_tstEncoding[] = { chLatin_B, chLatin_a, chLatin_s, chLatin_e, chDigit_6, chDigit_4, chNull }; XMLCh s_tstMimeType[] = { chLatin_i, chLatin_m, chLatin_a, chLatin_g, chLatin_e, chForwardSlash, chLatin_p, chLatin_n, chLatin_g, chNull }; unsigned char s_tstOAEPparams[] = "12345678"; unsigned char s_tstBase64EncodedString[] = "YmNkZWZnaGlqa2xtbm9wcRrPXjQ1hvhDFT+EdesMAPE4F6vlT+y0HPXe0+nAGLQ8"; char s_tstDecryptedString[] = "A test encrypted secret"; // -------------------------------------------------------------------------------- // Some test keys // -------------------------------------------------------------------------------- // A PKCS8 PEM encoded PrivateKey structure (not Encrypted) char s_tstRSAPrivateKey[] = "\n\ -----BEGIN RSA PRIVATE KEY-----\n\ MIICXAIBAAKBgQDQj3pktZckAzwshRnfvLhz3daNU6xpAzoHo3qjCftxDwH1RynP\n\ A5eycJVkV8mwH2C1PFktpjtQTZ2CvPjuKmUV5zEvmYzuIo6SWYaVZN/PJjzsEZMa\n\ VA+U8GhfX1YF/rsuFzXCi8r6FVd3LN//pXHEwoDGdJUdlpdVEuX1iFKlNQIDAQAB\n\ AoGAYQ7Uc7e6Xa0PvNw4XVHzOSC870pISxqQT+u5b9R+anAEhkQW5dsTJpyUOX1N\n\ RCRmGhG6oq7gnY9xRN1yr0uVfJNtc9/HnzJL7L1jeJC8Ub+zbEBvNuPDL2P21ArW\n\ tcXRycUlfRCRBLop7rfOYPXsjtboAGnQY/6hK4rOF4XGrQUCQQD3Euj+0mZqRRZ4\n\ M1yN2wVP0mKOMg2i/HZXaNeVd9X/wyBgK6b7BxHf6onf/mIBWnJnRBlvdCrSdhuT\n\ lPKEoSgvAkEA2BhfWwQihqD4qJcV65nfosjzOZG41rHX69nIqHI7Ejx5ZgeQByH9\n\ Ym96yXoSpZj9ZlFsJYNogTBBnUBjs+jL2wJAFjpVS9eR7y2X/+hfA0QZDj1XMIPA\n\ RlGANAzymDfXwNLFLuG+fAb+zK5FCSnRl12TvUabIzPIRnbptDVKPDRjcQJBALn8\n\ 0CVv+59P8HR6BR3QRBDBT8Xey+3NB4Aw42lHV9wsPHg6ThY1hPYx6MZ70IzCjmZ/\n\ 8cqfvVRjijWj86wm0z0CQFKfRfBRraOZqfmOiAB4+ILhbJwKBBO6avX9TPgMYkyN\n\ mWKCxS+9fPiy1iI+G+B9xkw2gJ9i8P81t7fsOvdTDFA=\n\ -----END RSA PRIVATE KEY-----"; char s_tstECPrivateKey[] = "\n\ -----BEGIN PRIVATE KEY-----\n\ MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAGJjEIHP3P1fDZV9lG\n\ lVfblOulUksJ+QdX9SeOswKIiQ9Oc5l6NTswN2bm+IRhaouhZANiAARrJ/UeKETr\n\ cFdFSM9sjB31PDIB6IdjtwyzMUIAJHlqoQ6IJo3887jvgUZyevY0+CUoS0N3L+9W\n\ mPgOiq9TRw6O5mrjSk1rmCx+2o2bnk+tWEysp7AWswUgNGgVkhumq9A=\n\ -----END PRIVATE KEY-----"; static char s_keyStr[] = "abcdefghijklmnopqrstuvwxyzabcdef"; // -------------------------------------------------------------------------------- // Find a node // -------------------------------------------------------------------------------- DOMNode * findNode(DOMNode * n, XMLCh * name) { if (XMLString::compareString(name, n->getNodeName()) == 0) return n; DOMNode * c = n->getFirstChild(); while (c != NULL) { if (c->getNodeType() == DOMNode::ELEMENT_NODE) { DOMNode * s = findNode(c, name); if (s != NULL) return s; } c = c->getNextSibling(); } return NULL; } // -------------------------------------------------------------------------------- // Create a key // -------------------------------------------------------------------------------- XSECCryptoKeyHMAC * createHMACKey(const unsigned char * str) { // Create the HMAC key XSECCryptoKeyHMAC * hmacKey = NULL; #if defined(XSEC_HAVE_WINCAPI) if (g_useWinCAPI == true) { hmacKey = new WinCAPICryptoKeyHMAC(0); } #endif # if defined (XSEC_HAVE_NSS) if (g_useNSS == true) { hmacKey = new NSSCryptoKeyHMAC(); } #endif #if defined (XSEC_HAVE_OPENSSL) if (hmacKey == NULL) hmacKey = new OpenSSLCryptoKeyHMAC(); #endif hmacKey->setKey((unsigned char *) str, (unsigned int) strlen((char *)str)); return hmacKey; } // -------------------------------------------------------------------------------- // Utility function for outputting hex data // -------------------------------------------------------------------------------- void outputHex(unsigned char * buf, int len) { cout << std::hex; for (int i = 0; i < len; ++i) { cout << "0x" << (unsigned int) buf[i] << ", "; } cout << std::ios::dec << endl; } // -------------------------------------------------------------------------------- // Create a basic document // -------------------------------------------------------------------------------- DOMDocument * createTestDoc(DOMImplementation * impl) { DOMDocument *doc = impl->createDocument( 0, // root element namespace URI. MAKE_UNICODE_STRING("ADoc"), // root element name NULL);// DOMDocumentType()); // document type object (DTD). DOMElement *rootElem = doc->getDocumentElement(); rootElem->setAttributeNS(DSIGConstants::s_unicodeStrURIXMLNS, MAKE_UNICODE_STRING("xmlns:foo"), MAKE_UNICODE_STRING("http://www.foo.org")); DOMElement * prodElem = doc->createElement(MAKE_UNICODE_STRING("product")); rootElem->appendChild(prodElem); DOMText * prodDataVal = doc->createTextNode(MAKE_UNICODE_STRING("XMLSecurityC")); prodElem->appendChild(prodDataVal); DOMElement *catElem = doc->createElement(MAKE_UNICODE_STRING("category")); rootElem->appendChild(catElem); catElem->setAttributeNS(NULL,MAKE_UNICODE_STRING("idea"), MAKE_UNICODE_STRING("great")); DOMText *catDataVal = doc->createTextNode(MAKE_UNICODE_STRING("XML Security Tools")); catElem->appendChild(catDataVal); return doc; } // -------------------------------------------------------------------------------- // Output a document if so required // -------------------------------------------------------------------------------- void outputDoc(DOMImplementation * impl, DOMDocument * doc) { if (g_printDocs == false) return; XMLFormatTarget *formatTarget = new StdOutFormatTarget(); // DOM L3 version as per Xerces 3.0 API DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer(); // Get the config so we can set up pretty printing DOMConfiguration *dc = theSerializer->getDomConfig(); dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false); // Now create an output object to format to UTF-8 DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput(); Janitor<DOMLSOutput> j_theOutput(theOutput); theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8")); theOutput->setByteStream(formatTarget); cerr << endl; theSerializer->write(doc, theOutput); cout << endl; cerr << endl; delete theSerializer; delete formatTarget; } // -------------------------------------------------------------------------------- // Unit test helper functions // -------------------------------------------------------------------------------- bool reValidateSig(DOMImplementation *impl, DOMDocument * inDoc, XSECCryptoKey *k) { // Take a signature in DOM, serialise and re-validate try { MemBufFormatTarget *formatTarget = new MemBufFormatTarget(); DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer(); // Get the config so we can set up pretty printing DOMConfiguration *dc = theSerializer->getDomConfig(); dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false); // Now create an output object to format to UTF-8 DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput(); Janitor<DOMLSOutput> j_theOutput(theOutput); theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8")); theOutput->setByteStream(formatTarget); theSerializer->write(inDoc,theOutput); // Copy to a new buffer XMLSize_t len = formatTarget->getLen(); char * mbuf = new char [len + 1]; memcpy(mbuf, formatTarget->getRawBuffer(), len); mbuf[len] = '\0'; delete theSerializer; delete formatTarget; /* * Re-parse */ XercesDOMParser parser; parser.setDoNamespaces(true); parser.setCreateEntityReferenceNodes(true); MemBufInputSource* memIS = new MemBufInputSource ((const XMLByte*) mbuf, len, "XSECMem"); parser.parse(*memIS); DOMDocument * doc = parser.adoptDocument(); delete(memIS); delete[] mbuf; /* * Validate signature */ XSECProvider prov; DSIGSignature * sig = prov.newSignatureFromDOM(doc); sig->load(); sig->setSigningKey(k); bool ret = sig->verify(); doc->release(); return ret; } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } } // -------------------------------------------------------------------------------- // Unit tests for signature // -------------------------------------------------------------------------------- void unitTestEnvelopingSignature(DOMImplementation * impl) { // This tests an enveloping signature as the root node cerr << "Creating enveloping signature ... "; try { // Create a document DOMDocument * doc = impl->createDocument(); // Create the signature XSECProvider prov; DSIGSignature *sig; DOMElement *sigNode; sig = prov.newSignature(); sig->setDSIGNSPrefix(MAKE_UNICODE_STRING("ds")); sig->setPrettyPrint(true); sigNode = sig->createBlankSignature(doc, DSIGConstants::s_unicodeStrURIC14N_COM, DSIGConstants::s_unicodeStrURIHMAC_SHA1); doc->appendChild(sigNode); // Add an object DSIGObject * obj = sig->appendObject(); obj->setId(MAKE_UNICODE_STRING("ObjectId")); // Create a text node DOMText * txt= doc->createTextNode(MAKE_UNICODE_STRING("A test string")); obj->appendChild(txt); // Add a Reference sig->createReference(MAKE_UNICODE_STRING("#ObjectId"), DSIGConstants::s_unicodeStrURISHA1); // Get a key cerr << "signing ... "; sig->setSigningKey(createHMACKey((unsigned char *) "secret")); sig->sign(); cerr << "validating ... "; if (!sig->verify()) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... serialise and re-verify ... "; if (!reValidateSig(impl, doc, createHMACKey((unsigned char *) "secret"))) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... "; // Now set to bad txt->setNodeValue(MAKE_UNICODE_STRING("A bad string")); cerr << "verify bad data ... "; if (sig->verify()) { cerr << "bad - should have failed!" << endl; exit(1); } cerr << "OK (verify false) ... serialise and re-verify ... "; if (reValidateSig(impl, doc, createHMACKey((unsigned char *) "secret"))) { cerr << "bad - should have failed" << endl; exit(1); } cerr << "OK" << endl; // Reset to OK txt->setNodeValue(MAKE_UNICODE_STRING("A test string")); outputDoc(impl, doc); doc->release(); } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } } void unitTestBase64NodeSignature(DOMImplementation * impl) { // This tests a normal signature with a reference to a Base64 element cerr << "Creating a base64 Element reference ... "; try { // Create a document DOMDocument * doc = impl->createDocument(); // Create the signature XSECProvider prov; DSIGSignature *sig; DOMElement *sigNode; sig = prov.newSignature(); sig->setDSIGNSPrefix(MAKE_UNICODE_STRING("ds")); sig->setPrettyPrint(true); sigNode = sig->createBlankSignature(doc, DSIGConstants::s_unicodeStrURIC14N_COM, DSIGConstants::s_unicodeStrURIHMAC_SHA1); doc->appendChild(sigNode); // Add an object DSIGObject * obj = sig->appendObject(); obj->setId(MAKE_UNICODE_STRING("ObjectId")); // Create a text node DOMText * txt= doc->createTextNode(MAKE_UNICODE_STRING("QSB0ZXN0IHN0cmluZw==")); obj->appendChild(txt); // Add a Reference DSIGReference * ref = sig->createReference(MAKE_UNICODE_STRING("#ObjectId"), DSIGConstants::s_unicodeStrURISHA1); // Add a Base64 transform ref->appendBase64Transform(); // Get a key cerr << "signing ... "; sig->setSigningKey(createHMACKey((unsigned char *) "secret")); sig->sign(); cerr << "validating ... "; if (!sig->verify()) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... serialise and re-verify ... "; if (!reValidateSig(impl, doc, createHMACKey((unsigned char *) "secret"))) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... "; // Now set to bad txt->setNodeValue(MAKE_UNICODE_STRING("QSAybmQgdGVzdCBzdHJpbmc=")); cerr << "verify bad data ... "; if (sig->verify()) { cerr << "bad - should have failed!" << endl; exit(1); } cerr << "OK (verify false) ... serialise and re-verify ... "; if (reValidateSig(impl, doc, createHMACKey((unsigned char *) "secret"))) { cerr << "bad - should have failed" << endl; exit(1); } cerr << "OK" << endl; // Reset to OK txt->setNodeValue(MAKE_UNICODE_STRING("QSB0ZXN0IHN0cmluZw==")); outputDoc(impl, doc); doc->release(); } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } } void unitTestLongSHA(DOMImplementation * impl) { // This tests an enveloping signature as the root node, using SHA224/256/384/512 cerr << "Creating long SHA references using HMAC... "; try { // Create a document DOMDocument * doc = impl->createDocument(); // Create the signature XSECProvider prov; DSIGSignature *sig; DOMElement *sigNode; DSIGReference *ref[4]; sig = prov.newSignature(); sig->setDSIGNSPrefix(MAKE_UNICODE_STRING("ds")); sig->setPrettyPrint(true); sigNode = sig->createBlankSignature(doc, DSIGConstants::s_unicodeStrURIEXC_C14N_COM, DSIGConstants::s_unicodeStrURIHMAC_SHA512); doc->appendChild(sigNode); // Add an object DSIGObject * obj = sig->appendObject(); obj->setId(MAKE_UNICODE_STRING("ObjectId")); // Create a text node DOMText * txt= doc->createTextNode(MAKE_UNICODE_STRING("A test string")); obj->appendChild(txt); // Add a Reference if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA224)) { cerr << "224 ... "; ref[0] = sig->createReference(MAKE_UNICODE_STRING("#ObjectId"), DSIGConstants::s_unicodeStrURISHA224); } else { ref[0] = NULL; } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA256)) { cerr << "256 ... "; ref[1] = sig->createReference(MAKE_UNICODE_STRING("#ObjectId"), DSIGConstants::s_unicodeStrURISHA256); } else { ref[1] = NULL; } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA384)) { cerr << "384 ... "; ref[2] = sig->createReference(MAKE_UNICODE_STRING("#ObjectId"), DSIGConstants::s_unicodeStrURISHA384); } else { ref[2] = NULL; } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA512)) { cerr << "512 ... "; ref[3] = sig->createReference(MAKE_UNICODE_STRING("#ObjectId"), DSIGConstants::s_unicodeStrURISHA512); } else { ref[3] = NULL; } // Get a key cerr << "signing ... "; sig->setSigningKey(createHMACKey((unsigned char *) "secret")); sig->sign(); cerr << "validating ... "; if (!sig->verify()) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... serialise and re-verify ... "; if (!reValidateSig(impl, doc, createHMACKey((unsigned char *) "secret"))) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... "; // Now set to bad txt->setNodeValue(MAKE_UNICODE_STRING("A bad string")); cerr << "verify bad data ... "; if (sig->verify()) { cerr << "bad - should have failed!" << endl; exit(1); } cerr << "OK (verify false) ... serialize and re-verify ... "; if (reValidateSig(impl, doc, createHMACKey((unsigned char *) "secret"))) { cerr << "bad - should have failed" << endl; exit(1); } cerr << "OK" << endl; // Reset to OK txt->setNodeValue(MAKE_UNICODE_STRING("A test string")); // Now check the references cerr << " Checking reference values against known good" << endl; unsigned char buf[128]; int len; const char * shastrings[] = { "SHA224", "SHA256", "SHA384", "SHA512" }; /* * Validate the reference hash values from known good */ int i; for (i = 0; i < 4; ++i) { if (ref[i] == NULL) { continue; } cerr << " Calculating hash for reference " << shastrings[i] << " ... "; len = (int) ref[i]->calculateHash(buf, 128); cerr << " Done\n Checking -> "; if (len < 20) { cerr << "Bad (Length = " << len << ")" << endl; exit (1); } for (int j = 0; j < len; ++j) { if (buf[j] != longShaRefs[i][j]) { cerr << "Bad at location " << j << endl; for (j = 0; j < len; ++j) { fprintf(stderr, "0x%02x, ", buf[j]); } exit (1); } } cerr << "Good.\n"; } outputDoc(impl, doc); doc->release(); } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } } void unitTestSig(DOMImplementation * impl, XSECCryptoKey * k, const XMLCh * AlgURI) { // Given a specific RSA/EC key and particular algorithm URI, sign and validate a document try { // Create a document DOMDocument * doc = impl->createDocument(); // Create the signature XSECProvider prov; DSIGSignature *sig; DOMElement *sigNode; sig = prov.newSignature(); sig->setDSIGNSPrefix(MAKE_UNICODE_STRING("ds")); sig->setPrettyPrint(true); sigNode = sig->createBlankSignature(doc, DSIGConstants::s_unicodeStrURIC14N_COM, AlgURI); doc->appendChild(sigNode); // Add an object DSIGObject * obj = sig->appendObject(); obj->setId(MAKE_UNICODE_STRING("ObjectId")); // Create a text node DOMText * txt= doc->createTextNode(MAKE_UNICODE_STRING("A test string")); obj->appendChild(txt); // Get a key cerr << "signing ... "; sig->setSigningKey(k->clone()); sig->sign(); cerr << "OK ... "; cerr << "validating ... "; if (!sig->verify()) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK ... serialise and re-verify ... "; if (!reValidateSig(impl, doc, k)) { cerr << "bad verify!" << endl; exit(1); } cerr << "OK"; cerr << "\n"; outputDoc(impl, doc); doc->release(); } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } } void unitTestRSA(DOMImplementation * impl) { /* First we load some keys to use! */ XSECCryptoKeyRSA * rsaKey; #if defined (XSEC_HAVE_OPENSSL) if (!g_useWinCAPI && !g_useNSS) { // Load the key BIO * bioMem = BIO_new(BIO_s_mem()); BIO_puts(bioMem, s_tstRSAPrivateKey); EVP_PKEY * pk = PEM_read_bio_PrivateKey(bioMem, NULL, NULL, NULL); rsaKey = new OpenSSLCryptoKeyRSA(pk); BIO_free(bioMem); EVP_PKEY_free(pk); } #endif #if defined (XSEC_HAVE_WINCAPI) if (g_useWinCAPI) { // Use the internal key WinCAPICryptoProvider *cp = (WinCAPICryptoProvider *) (XSECPlatformUtils::g_cryptoProvider); HCRYPTPROV p = cp->getApacheKeyStore(); rsaKey = new WinCAPICryptoKeyRSA(p, AT_KEYEXCHANGE, true); } #endif #if defined (XSEC_HAVE_NSS) if (g_useNSS) { // Heavily based on Mozilla example code SECKEYPrivateKey *prvKey = 0; SECKEYPublicKey *pubKey = 0; PK11SlotInfo *slot = 0; PK11RSAGenParams rsaParams; // Use a bog standard key size rsaParams.keySizeInBits = 1024; rsaParams.pe = 65537; // We need somewhere to temporarily store a generated key slot = PK11_GetInternalKeySlot(); if (!slot) { cerr << "Error generating key - can't get NSS slot\n"; exit (1); } // Do the generate prvKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &pubKey, PR_FALSE, PR_TRUE, 0); if (!prvKey) { if (slot) PK11_FreeSlot(slot); cerr << "Error generating key within NSS\n"; exit (1); } // Now use the key! rsaKey = new NSSCryptoKeyRSA(pubKey, prvKey); } #endif cerr << "Unit testing RSA-SHA1 signature ... "; unitTestSig(impl, (XSECCryptoKeyRSA *) rsaKey->clone(), DSIGConstants::s_unicodeStrURIRSA_SHA1); if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA224)) { cerr << "Unit testing RSA-SHA224 signature ... "; unitTestSig(impl, (XSECCryptoKeyRSA *)rsaKey->clone(), DSIGConstants::s_unicodeStrURIRSA_SHA224); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA256)) { cerr << "Unit testing RSA-SHA256 signature ... "; unitTestSig(impl, (XSECCryptoKeyRSA *)rsaKey->clone(), DSIGConstants::s_unicodeStrURIRSA_SHA256); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA384)) { cerr << "Unit testing RSA-SHA384 signature ... "; unitTestSig(impl, (XSECCryptoKeyRSA *)rsaKey->clone(), DSIGConstants::s_unicodeStrURIRSA_SHA384); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA512)) { cerr << "Unit testing RSA-SHA512 signature ... "; unitTestSig(impl, (XSECCryptoKeyRSA *) rsaKey->clone(), DSIGConstants::s_unicodeStrURIRSA_SHA512); } cerr << "Unit testing RSA-MD5 signature ... "; unitTestSig(impl, rsaKey, DSIGConstants::s_unicodeStrURIRSA_MD5); } void unitTestEC(DOMImplementation * impl) { #if defined (XSEC_HAVE_OPENSSL) && defined (XSEC_OPENSSL_HAVE_EC) /* First we load some keys to use! */ XSECCryptoKeyEC * ecKey; // Load the key BIO * bioMem = BIO_new(BIO_s_mem()); BIO_puts(bioMem, s_tstECPrivateKey); EVP_PKEY * pk = PEM_read_bio_PrivateKey(bioMem, NULL, NULL, NULL); ecKey = new OpenSSLCryptoKeyEC(pk); BIO_free(bioMem); EVP_PKEY_free(pk); cerr << "Unit testing ECDSA-SHA1 signature ... "; unitTestSig(impl, (XSECCryptoKeyEC *) ecKey->clone(), DSIGConstants::s_unicodeStrURIECDSA_SHA1); if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA224)) { cerr << "Unit testing ECDSA-SHA224 signature ... "; unitTestSig(impl, (XSECCryptoKeyEC *)ecKey->clone(), DSIGConstants::s_unicodeStrURIECDSA_SHA224); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA256)) { cerr << "Unit testing ECDSA-SHA256 signature ... "; unitTestSig(impl, (XSECCryptoKeyEC *)ecKey->clone(), DSIGConstants::s_unicodeStrURIECDSA_SHA256); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA384)) { cerr << "Unit testing ECDSA-SHA384 signature ... "; unitTestSig(impl, (XSECCryptoKeyEC *)ecKey->clone(), DSIGConstants::s_unicodeStrURIECDSA_SHA384); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA512)) { cerr << "Unit testing ECDSA-SHA512 signature ... "; } unitTestSig(impl, (XSECCryptoKeyEC *) ecKey->clone(), DSIGConstants::s_unicodeStrURIECDSA_SHA512); #endif } void unitTestSignature(DOMImplementation * impl) { // Test an enveloping signature unitTestEnvelopingSignature(impl); #ifdef XSEC_HAVE_XALAN unitTestBase64NodeSignature(impl); #else cerr << "Skipping base64 node test (Requires XPath)" << endl; #endif // Test "long" sha hashes if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA512)) unitTestLongSHA(impl); else cerr << "Skipping long SHA hash tests as SHA512 not supported by crypto provider" << endl; // Test RSA Signatures unitTestRSA(impl); // Test EC Signatures unitTestEC(impl); } // -------------------------------------------------------------------------------- // Basic tests of signature function // -------------------------------------------------------------------------------- void testSignature(DOMImplementation *impl) { cerr << "Creating a known doc and signing (HMAC-SHA1)" << endl; // Create a document DOMDocument * doc = createTestDoc(impl); // Check signature functions XSECProvider prov; DSIGSignature *sig; DSIGReference *ref[10]; DOMElement *sigNode; int refCount; try { /* * Now we have a document, create a signature for it. */ sig = prov.newSignature(); sig->setDSIGNSPrefix(MAKE_UNICODE_STRING("ds")); sig->setPrettyPrint(true); sigNode = sig->createBlankSignature(doc, DSIGConstants::s_unicodeStrURIC14N_COM, DSIGConstants::s_unicodeStrURIHMAC_SHA1); DOMElement * rootElem = doc->getDocumentElement(); DOMNode * prodElem = rootElem->getFirstChild(); rootElem->appendChild(doc->createTextNode(DSIGConstants::s_unicodeStrNL)); rootElem->insertBefore(doc->createComment(MAKE_UNICODE_STRING(" a comment ")), prodElem); rootElem->appendChild(sigNode); rootElem->insertBefore(doc->createTextNode(DSIGConstants::s_unicodeStrNL), prodElem); /* * Add some test references */ ref[0] = sig->createReference(MAKE_UNICODE_STRING(""), DSIGConstants::s_unicodeStrURISHA1); ref[0]->appendEnvelopedSignatureTransform(); ref[1] = sig->createReference(MAKE_UNICODE_STRING("#xpointer(/)"), DSIGConstants::s_unicodeStrURISHA1); ref[1]->appendEnvelopedSignatureTransform(); ref[1]->appendCanonicalizationTransform(DSIGConstants::s_unicodeStrURIC14N_NOC); ref[2] = sig->createReference(MAKE_UNICODE_STRING("#xpointer(/)"), DSIGConstants::s_unicodeStrURISHA1); ref[2]->appendEnvelopedSignatureTransform(); ref[2]->appendCanonicalizationTransform(DSIGConstants::s_unicodeStrURIC14N_COM); ref[3] = sig->createReference(MAKE_UNICODE_STRING("#xpointer(/)"), DSIGConstants::s_unicodeStrURISHA1); ref[3]->appendEnvelopedSignatureTransform(); ref[3]->appendCanonicalizationTransform(DSIGConstants::s_unicodeStrURIEXC_C14N_NOC); ref[4] = sig->createReference(MAKE_UNICODE_STRING("#xpointer(/)"), DSIGConstants::s_unicodeStrURISHA1); ref[4]->appendEnvelopedSignatureTransform(); ref[4]->appendCanonicalizationTransform(DSIGConstants::s_unicodeStrURIEXC_C14N_COM); ref[5] = sig->createReference(MAKE_UNICODE_STRING("#xpointer(/)"), DSIGConstants::s_unicodeStrURISHA1); ref[5]->appendEnvelopedSignatureTransform(); DSIGTransformC14n * ce = ref[5]->appendCanonicalizationTransform( DSIGConstants::s_unicodeStrURIEXC_C14N_COM); ce->addInclusiveNamespace("foo"); sig->setECNSPrefix(MAKE_UNICODE_STRING("ec")); ref[6] = sig->createReference(MAKE_UNICODE_STRING("#xpointer(/)"), DSIGConstants::s_unicodeStrURISHA1); ref[6]->appendEnvelopedSignatureTransform(); ce = ref[6]->appendCanonicalizationTransform( DSIGConstants::s_unicodeStrURIEXC_C14N_COM); ce->addInclusiveNamespace("foo"); #ifndef XSEC_HAVE_XALAN cerr << "WARNING : No testing of XPath being performed as Xalan not present" << endl; refCount = 7; #else /* * Create some XPath/XPathFilter references */ ref[7] = sig->createReference(MAKE_UNICODE_STRING(""), DSIGConstants::s_unicodeStrURISHA1); sig->setXPFNSPrefix(MAKE_UNICODE_STRING("xpf")); DSIGTransformXPathFilter * xpf = ref[7]->appendXPathFilterTransform(); xpf->appendFilter(DSIGXPathFilterExpr::FILTER_INTERSECT, MAKE_UNICODE_STRING("//ADoc/category")); ref[8] = sig->createReference(MAKE_UNICODE_STRING(""), DSIGConstants::s_unicodeStrURISHA1); /* ref[5]->appendXPathTransform("ancestor-or-self::dsig:Signature", "xmlns:dsig=http://www.w3.org/2000/09/xmldsig#"); */ DSIGTransformXPath * x = ref[8]->appendXPathTransform("count(ancestor-or-self::dsig:Signature | \ here()/ancestor::dsig:Signature[1]) > \ count(ancestor-or-self::dsig:Signature)"); x->setNamespace("dsig", "http://www.w3.org/2000/09/xmldsig#"); refCount = 9; #endif /* * Sign the document, using an HMAC algorithm and the key "secret" */ sig->appendKeyName(MAKE_UNICODE_STRING("The secret key is \"secret\"")); // Append a test DNames DSIGKeyInfoX509 * x509 = sig->appendX509Data(); x509->setX509SubjectName(s_tstDName); // Append a test PGPData element sig->appendPGPData(s_tstPGPKeyID, s_tstPGPKeyPacket); // Append an SPKIData element DSIGKeyInfoSPKIData * spki = sig->appendSPKIData(s_tstSexp1); spki->appendSexp(s_tstSexp2); // Append a MgmtData element sig->appendMgmtData(s_tstMgmtData); sig->setSigningKey(createHMACKey((unsigned char *) "secret")); sig->sign(); // Output the document post signature if necessary outputDoc(impl, doc); cerr << endl << "Doc signed OK - Checking values against Known Good" << endl; unsigned char buf[128]; XMLSize_t len; /* * Validate the reference hash values from known good */ int i; for (i = 0; i < refCount; ++i) { cerr << "Calculating hash for reference " << i << " ... "; len = (int) ref[i]->calculateHash(buf, 128); cerr << " Done\nChecking -> "; if (len != 20) { cerr << "Bad (Length = " << len << ")" << endl; exit (1); } for (int j = 0; j < 20; ++j) { if (buf[j] != createdDocRefs[i][j]) { cerr << "Bad at location " << j << endl; exit (1); } } cerr << "Good.\n"; } /* * Verify the signature check works */ cerr << "Running \"verifySignatureOnly()\" on calculated signature ... "; if (sig->verifySignatureOnly()) { cerr << "OK" << endl; } else { cerr << "Failed" << endl; char * e = XMLString::transcode(sig->getErrMsgs()); cout << e << endl; XSEC_RELEASE_XMLCH(e); exit(1); } /* * Change the document and ensure the signature fails. */ cerr << "Setting incorrect key in Signature object" << endl; sig->setSigningKey(createHMACKey((unsigned char *) "badsecret")); cerr << "Running \"verifySignatureOnly()\" on calculated signature ... "; if (!sig->verifySignatureOnly()) { cerr << "OK (Signature bad)" << endl; } else { cerr << "Failed (signature OK but should be bad)" << endl; exit(1); } // Don't need the signature now the DOM structure is in place prov.releaseSignature(sig); /* * Now serialise the document to memory so we can re-parse and check from scratch */ cerr << "Serialising the document to a memory buffer ... "; MemBufFormatTarget *formatTarget = new MemBufFormatTarget(); DOMLSSerializer *theSerializer = ((DOMImplementationLS*)impl)->createLSSerializer(); // Get the config so we can set up pretty printing DOMConfiguration *dc = theSerializer->getDomConfig(); dc->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, false); // Now create an output object to format to UTF-8 DOMLSOutput *theOutput = ((DOMImplementationLS*)impl)->createLSOutput(); Janitor<DOMLSOutput> j_theOutput(theOutput); theOutput->setEncoding(MAKE_UNICODE_STRING("UTF-8")); theOutput->setByteStream(formatTarget); theSerializer->write(doc,theOutput); // Copy to a new buffer len = formatTarget->getLen(); char * mbuf = new char [len + 1]; memcpy(mbuf, formatTarget->getRawBuffer(), len); mbuf[len] = '\0'; #if 0 cout << mbuf << endl; #endif delete theSerializer; delete formatTarget; cerr << "done\nParsing memory buffer back to DOM ... "; // Also release the document so that we can re-load from scratch doc->release(); /* * Re-parse */ XercesDOMParser parser; parser.setDoNamespaces(true); parser.setCreateEntityReferenceNodes(true); MemBufInputSource* memIS = new MemBufInputSource ((const XMLByte*) mbuf, len, "XSECMem"); parser.parse(*memIS); doc = parser.adoptDocument(); delete(memIS); delete[] mbuf; cerr << "done\nValidating signature ..."; /* * Validate signature */ sig = prov.newSignatureFromDOM(doc); sig->load(); sig->setSigningKey(createHMACKey((unsigned char *) "secret")); if (sig->verify()) { cerr << "OK" << endl; } else { cerr << "Failed\n" << endl; char * e = XMLString::transcode(sig->getErrMsgs()); cerr << e << endl; XSEC_RELEASE_XMLCH(e); exit(1); } /* * Ensure DNames are read back in and decoded properly */ DSIGKeyInfoList * kil = sig->getKeyInfoList(); int nki = (int) kil->getSize(); cerr << "Checking Distinguished name is decoded correctly ... "; for (i = 0; i < nki; ++i) { if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_X509) { if (strEquals(s_tstDName, ((DSIGKeyInfoX509 *) kil->item(i))->getX509SubjectName())) { cerr << "yes" << endl; } else { cerr << "decoded incorrectly" << endl;; exit (1); } } if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_PGPDATA) { cerr << "Validating PGPData read back OK ... "; DSIGKeyInfoPGPData * p = (DSIGKeyInfoPGPData *)kil->item(i); if (!(strEquals(p->getKeyID(), s_tstPGPKeyID) && strEquals(p->getKeyPacket(), s_tstPGPKeyPacket))) { cerr << "no!"; exit(1); } cerr << "yes\n"; } if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_SPKIDATA) { cerr << "Validating SPKIData read back OK ... "; DSIGKeyInfoSPKIData * s = (DSIGKeyInfoSPKIData *)kil->item(i); if (s->getSexpSize() != 2) { cerr << "no - expected two S-expressions"; exit(1); } if (!(strEquals(s->getSexp(0), s_tstSexp1) && strEquals(s->getSexp(1), s_tstSexp2))) { cerr << "no!"; exit(1); } cerr << "yes\n"; } if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_MGMTDATA) { cerr << "Validating MgmtData read back OK ... "; DSIGKeyInfoMgmtData * m = (DSIGKeyInfoMgmtData *)kil->item(i); if (!strEquals(m->getData(), s_tstMgmtData)) { cerr << "no!"; exit(1); } cerr << "yes\n"; } } } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } // Output the document post signature if necessary outputDoc(impl, doc); doc->release(); } // -------------------------------------------------------------------------------- // Unit tests for test encrypt/Decrypt // -------------------------------------------------------------------------------- void unitTestCipherReference(DOMImplementation * impl) { DOMDocument *doc = impl->createDocument( 0, // root element namespace URI. MAKE_UNICODE_STRING("ADoc"), // root element name NULL);// DOMDocumentType()); // document type object (DTD). DOMElement *rootElem = doc->getDocumentElement(); // Use key k to wrap a test key, decrypt it and make sure it is still OK XSECProvider prov; XENCCipher * cipher; try { cipher = prov.newCipher(doc); cerr << "Creating CipherReference ... "; XENCEncryptedData * xenc = cipher->createEncryptedData(XENCCipherData::REFERENCE_TYPE, DSIGConstants::s_unicodeStrURIAES128_CBC, MAKE_UNICODE_STRING("#CipherText")); rootElem->appendChild(xenc->getElement()); // Now create the data that is referenced DOMElement * cipherVal = doc->createElement(MAKE_UNICODE_STRING("MyCipherValue")); rootElem->appendChild(cipherVal); cipherVal->setAttributeNS(NULL, MAKE_UNICODE_STRING("Id"), MAKE_UNICODE_STRING("CipherText")); cipherVal->setIdAttributeNS(NULL, MAKE_UNICODE_STRING("Id"), true); cipherVal->appendChild(doc->createTextNode(MAKE_UNICODE_STRING((char *) s_tstBase64EncodedString))); // Now add the transforms necessary to decrypt XENCCipherReference *cref = xenc->getCipherData()->getCipherReference(); if (cref == NULL) { cerr << "Failed - no CipherReference object" << endl; exit(1); } cerr << "done ... appending XPath and Base64 transforms ... "; //cref->appendXPathTransform("self::text()[parent::rep:CipherValue[@Id="example1"]]"); cref->appendXPathTransform("self::text()[parent::MyCipherValue[@Id=\"CipherText\"]]"); cref->appendBase64Transform(); cerr << "done ... decrypting ... "; // Create a key XSECCryptoSymmetricKey * ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); ks->setKey((unsigned char *) s_keyStr, 16); cipher->setKey(ks); // Now try to decrypt DOMNode * n = findXENCNode(doc, "EncryptedData"); XSECBinTXFMInputStream *is = cipher->decryptToBinInputStream((DOMElement *) n); Janitor<XSECBinTXFMInputStream> j_is(is); XMLByte buf[1024]; cerr << "done ... comparing to known good ... "; XMLSize_t bytesRead = is->readBytes(buf, 1024); buf[bytesRead] = '\0'; if (strcmp((char *) buf, s_tstDecryptedString) == 0) { cerr << "OK" << endl; } else { cerr << "failed - bad compare of decrypted data" << endl; } } catch (const XSECException &e) { cerr << "failed\n"; cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "failed\n"; cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } outputDoc(impl, doc); doc->release(); } void unitTestElementContentEncrypt(DOMImplementation *impl, XSECCryptoKey * key, const XMLCh* algorithm, bool doElementContent) { if (doElementContent) cerr << "Encrypting Element Content ... "; else cerr << "Encrypting Element ... "; // Create a document DOMDocument * doc = createTestDoc(impl); DOMNode * categoryNode = findNode(doc, MAKE_UNICODE_STRING("category")); if (categoryNode == NULL) { cerr << "Error finding category node for encryption test" << endl; exit(1); } // Create and execute cipher XSECProvider prov; XENCCipher * cipher; try { /* * Now we have a document, find the data node. */ cipher = prov.newCipher(doc); cipher->setXENCNSPrefix(MAKE_UNICODE_STRING("xenc")); cipher->setPrettyPrint(true); // Set a key cipher->setKey(key->clone()); // Now encrypt! if (doElementContent) cipher->encryptElementContent(doc->getDocumentElement(), algorithm); else cipher->encryptElement((DOMElement *) categoryNode, algorithm); cerr << "done ... check encrypted ... "; DOMNode * t = findNode(doc, MAKE_UNICODE_STRING("category")); if (t != NULL) { cerr << "no - a category child still exists" << endl; exit(1); } else cerr << "yes" << endl; outputDoc(impl, doc); if (doElementContent) cerr << "Decrypting Element content ... "; else cerr << "Decrypting Element ... "; // OK - Now we try to decrypt // Find the EncryptedData node DOMNode * n = findXENCNode(doc, "EncryptedData"); XENCCipher * cipher2 = prov.newCipher(doc); cipher2->setKey(key); cipher2->decryptElement(static_cast<DOMElement *>(n)); cerr << "done ... check decrypt ... "; t = findNode(doc, MAKE_UNICODE_STRING("category")); if (t == NULL) { cerr << " failed - category did not decrypt properly" << endl; exit(1); } else cerr << "OK" << endl; outputDoc(impl, doc); } catch (const XSECException &e) { cerr << "An error occurred during encryption processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during encryption processing\n Message: " << e.getMsg() << endl; exit(1); } doc->release(); } void unitTestSmallElement(DOMImplementation *impl) { cerr << "Encrypt small input... "; // Create a document DOMDocument * doc = createTestDoc(impl); DOMElement * productNode = (DOMElement *) findNode(doc, MAKE_UNICODE_STRING("product")); if (productNode == NULL) { cerr << "Error finding product node for small input encryption test" << endl; exit(1); } // Shrink the input text DOMNode * textNode = productNode->getFirstChild(); textNode->setNodeValue(MAKE_UNICODE_STRING("sm")); // Create and execute cipher XSECProvider prov; XENCCipher * cipher; try { /* * Now we have a document, find the data node. */ cipher = prov.newCipher(doc); cipher->setXENCNSPrefix(MAKE_UNICODE_STRING("xenc")); cipher->setPrettyPrint(true); // Set a key XSECCryptoSymmetricKey * ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); ks->setKey((unsigned char *) s_keyStr, 24); cipher->setKey(ks->clone()); // Now encrypt! cipher->encryptElementContent(productNode, DSIGConstants::s_unicodeStrURI3DES_CBC); cerr << "done ... check encrypted ... "; DOMNode * t = findNode(doc, MAKE_UNICODE_STRING("product")); t = findFirstChildOfType(t, DOMNode::TEXT_NODE); while (t != NULL && ! strEquals(t->getNodeValue(), "sm")) t = findNextChildOfType(t, DOMNode::TEXT_NODE); if (t != NULL) { cerr << "no - text child still exists" << endl; exit(1); } else cerr << "yes" << endl; outputDoc(impl, doc); cerr << "Decrypting Element content ... "; // OK - Now we try to decrypt // Find the EncryptedData node DOMNode * n = findXENCNode(doc, "EncryptedData"); XENCCipher * cipher2 = prov.newCipher(doc); cipher2->setKey(ks); cipher2->decryptElement(static_cast<DOMElement *>(n)); cerr << "done ... check decrypt ... "; t = findNode(doc, MAKE_UNICODE_STRING("product")); t = findFirstChildOfType(t, DOMNode::TEXT_NODE); if (t == NULL || !strEquals(t->getNodeValue(), "sm")) { cerr << " failed - small text did not decrypt properly" << endl; exit(1); } else cerr << "OK" << endl; outputDoc(impl, doc); } catch (const XSECException &e) { cerr << "An error occurred during encryption processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during encryption processing\n Message: " << e.getMsg() << endl; exit(1); } doc->release(); } void unitTestKeyEncrypt( DOMImplementation* impl, XSECCryptoKey* k, const XMLCh* algorithm, const XMLCh* mgf=NULL, unsigned char* oaepParams=NULL, unsigned int oaepParamsLen=0 ) { // Create a document that we will embed the encrypted key in DOMDocument *doc = impl->createDocument( 0, // root element namespace URI. MAKE_UNICODE_STRING("ADoc"), // root element name NULL);// DOMDocumentType()); // document type object (DTD). DOMElement *rootElem = doc->getDocumentElement(); // Use key k to wrap a test key, decrypt it and make sure it is still OK XSECProvider prov; XENCCipher * cipher; try { // Encrypt a dummy key cerr << "encrypt ... "; static unsigned char toEncryptStr[] = "A test key to use for da"; cipher = prov.newCipher(doc); cipher->setXENCNSPrefix(MAKE_UNICODE_STRING("xenc")); cipher->setPrettyPrint(true); // Set a key cipher->setKEK(k); XENCEncryptedKey * encryptedKey; encryptedKey = cipher->encryptKey( toEncryptStr, (unsigned int) strlen((char *) toEncryptStr), algorithm, mgf, oaepParams, oaepParamsLen ); Janitor<XENCEncryptedKey> j_encryptedKey(encryptedKey); rootElem->appendChild(encryptedKey->getElement()); // Decrypt cerr << "decrypt ... "; XMLByte decBuf[64]; cipher->decryptKey(encryptedKey, decBuf, 64); // Check cerr << "comparing ... "; if (memcmp(decBuf, toEncryptStr, strlen((char *) toEncryptStr)) == 0) { cerr << "OK ... "; } else { cerr << "different = failed!" << endl; exit(2); } cerr << "decrypt from DOM ... "; // Decrypt from DOM DOMNode * keyNode = findXENCNode(doc, "EncryptedKey"); if (keyNode == NULL) { cerr << "no key - failed!" << endl; exit(2); } memset(decBuf, 0, 64); cipher->decryptKey((DOMElement *) keyNode, decBuf, 64); cerr << "comparing ... "; if (memcmp(decBuf, toEncryptStr, strlen((char *) toEncryptStr)) == 0) { cerr << "OK" << endl; } else { cerr << "different = failed!" << endl; exit(2); } } catch (const XSECException &e) { cerr << "failed\n"; cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "failed\n"; cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } outputDoc(impl, doc); doc->release(); } void unitTestEncrypt(DOMImplementation *impl) { try { // Key wraps cerr << "RSA key wrap... "; #if defined (XSEC_HAVE_OPENSSL) if (!g_useWinCAPI && !g_useNSS) { // Load the key BIO * bioMem = BIO_new(BIO_s_mem()); BIO_puts(bioMem, s_tstRSAPrivateKey); EVP_PKEY * pk = PEM_read_bio_PrivateKey(bioMem, NULL, NULL, NULL); OpenSSLCryptoKeyRSA * k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_1_5); cerr << "RSA OAEP key wrap... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, DSIGConstants::s_unicodeStrURIMGF1_SHA1); cerr << "RSA OAEP key wrap + params... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1, DSIGConstants::s_unicodeStrURIMGF1_SHA1, s_tstOAEPparams, (unsigned int) strlen((char *) s_tstOAEPparams)); cerr << "RSA OAEP 1.1 key wrap... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP, DSIGConstants::s_unicodeStrURIMGF1_SHA1); if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA224)) { cerr << "RSA OAEP 1.1 key wrap with MGF1+SHA224... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP, DSIGConstants::s_unicodeStrURIMGF1_SHA224); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA256)) { cerr << "RSA OAEP 1.1 key wrap with MGF1+SHA256... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP, DSIGConstants::s_unicodeStrURIMGF1_SHA256); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA384)) { cerr << "RSA OAEP 1.1 key wrap with MGF1+SHA384... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP, DSIGConstants::s_unicodeStrURIMGF1_SHA384); } if (XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoHash::HASH_SHA512)) { cerr << "RSA OAEP 1.1 key wrap with MGF1+SHA512... "; k = new OpenSSLCryptoKeyRSA(pk); unitTestKeyEncrypt(impl, k, DSIGConstants::s_unicodeStrURIRSA_OAEP, DSIGConstants::s_unicodeStrURIMGF1_SHA512); } BIO_free(bioMem); EVP_PKEY_free(pk); } #endif #if defined (XSEC_HAVE_WINCAPI) if (g_useWinCAPI) { // Use the internal key WinCAPICryptoProvider *cp = (WinCAPICryptoProvider *) (XSECPlatformUtils::g_cryptoProvider); HCRYPTPROV p = cp->getApacheKeyStore(); WinCAPICryptoKeyRSA * rsaKey = new WinCAPICryptoKeyRSA(p, AT_KEYEXCHANGE, true); unitTestKeyEncrypt(impl, rsaKey, DSIGConstants::s_unicodeStrURIRSA_1_5); cerr << "RSA OAEP key wrap... "; rsaKey = new WinCAPICryptoKeyRSA(p, AT_KEYEXCHANGE, true); unitTestKeyEncrypt(impl, rsaKey, DSIGConstants::s_unicodeStrURIRSA_OAEP_MGFP1); cerr << "RSA OAEP 1.1 key wrap... "; rsaKey = new WinCAPICryptoKeyRSA(p, AT_KEYEXCHANGE, true); unitTestKeyEncrypt(impl, rsaKey, DSIGConstants::s_unicodeStrURIRSA_OAEP); } #endif #if defined (XSEC_HAVE_NSS) if (g_useNSS) { // Heavily based on Mozilla example code SECKEYPrivateKey *prvKey = 0; SECKEYPublicKey *pubKey = 0; PK11SlotInfo *slot = 0; PK11RSAGenParams rsaParams; // Use a bog standard key size rsaParams.keySizeInBits = 1024; rsaParams.pe = 65537; // We need somewhere to temporarily store a generated key slot = PK11_GetInternalKeySlot(); if (!slot) { cerr << "Error generating key - can't get NSS slot\n"; exit (1); } // Do the generate prvKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, &pubKey, PR_FALSE, PR_TRUE, 0); if (!prvKey) { if (slot) PK11_FreeSlot(slot); cerr << "Error generating key within NSS\n"; exit (1); } // Now use the key! NSSCryptoKeyRSA * rsaKey = new NSSCryptoKeyRSA(pubKey, prvKey); unitTestKeyEncrypt(impl, rsaKey, DSIGConstants::s_unicodeStrURIRSA_1_5); if (slot) // Actual keys will be deleted by the provider PK11_FreeSlot(slot); cerr << "RSA OAEP key wrap skipped - not yet supported in NSS crypto provider\n"; } #endif XSECCryptoSymmetricKey * ks; if (g_haveAES) { cerr << "AES 128 key wrap... "; ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); ks->setKey((unsigned char *) s_keyStr, 16); unitTestKeyEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIKW_AES128); cerr << "AES 192 key wrap... "; ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_192); ks->setKey((unsigned char *) s_keyStr, 24); unitTestKeyEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIKW_AES192); cerr << "AES 256 key wrap... "; ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_256); ks->setKey((unsigned char *) s_keyStr, 32); unitTestKeyEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIKW_AES256); } else cerr << "Skipped AES key wrap tests" << endl; cerr << "Triple DES key wrap... "; ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); ks->setKey((unsigned char *) s_keyStr, 24); unitTestKeyEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIKW_3DES); // Now do Element encrypts if (g_haveAES) { // 128 AES ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); ks->setKey((unsigned char *) s_keyStr, 16); cerr << "Unit testing AES 128 bit CBC encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURIAES128_CBC, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIAES128_CBC, true); //192 AES ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_192); ks->setKey((unsigned char *) s_keyStr, 24); cerr << "Unit testing AES 192 bit CBC encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURIAES192_CBC, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIAES192_CBC, true); // 256 AES ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_256); ks->setKey((unsigned char *) s_keyStr, 32); cerr << "Unit testing AES 256 bit CBC encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURIAES256_CBC, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIAES256_CBC, true); if (g_testGCM) { // 128 AES-GCM ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); ks->setKey((unsigned char *)s_keyStr, 16); cerr << "Unit testing AES 128 bit GCM encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURIAES128_GCM, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIAES128_GCM, true); //192 AES-GCM ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_192); ks->setKey((unsigned char *)s_keyStr, 24); cerr << "Unit testing AES 192 bit GCM encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURIAES192_GCM, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIAES192_GCM, true); // 256 AES-GCM ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_256); ks->setKey((unsigned char *)s_keyStr, 32); cerr << "Unit testing AES 256 bit GCM encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURIAES256_GCM, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURIAES256_GCM, true); } else { cerr << "Skipped AES-GCM Element tests" << endl; } } else { cerr << "Skipped AES Element tests" << endl; } // 192 3DES ks = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); ks->setKey((unsigned char *) s_keyStr, 24); cerr << "Unit testing 3DES CBC encryption" << endl; unitTestElementContentEncrypt(impl, ks->clone(), DSIGConstants::s_unicodeStrURI3DES_CBC, false); unitTestElementContentEncrypt(impl, ks, DSIGConstants::s_unicodeStrURI3DES_CBC, true); #ifdef XSEC_HAVE_XALAN if (g_haveAES) { cerr << "Unit testing CipherReference creation and decryption" << endl; unitTestCipherReference(impl); } else { cerr << "Skipped Cipher Reference Test (uses AES)" << endl; } #else cerr << "Skipped Cipher Reference Test (requires XPath)" << endl; #endif cerr << "Misc. encryption tests" << endl; unitTestSmallElement(impl); } catch (const XSECCryptoException &e) { cerr << "failed\n"; cerr << "A cryptographic error occurred during encryption unit tests\n Message: " << e.getMsg() << endl; exit(1); } } // -------------------------------------------------------------------------------- // Test encrypt/Decrypt // -------------------------------------------------------------------------------- void testEncrypt(DOMImplementation *impl) { cerr << "Creating a known doc encrypting a portion of it" << endl; // Create a document DOMDocument * doc = createTestDoc(impl); DOMNode * categoryNode = findNode(doc, MAKE_UNICODE_STRING("category")); if (categoryNode == NULL) { cerr << "Error finding category node for encryption test" << endl; exit(1); } // Check signature functions XSECProvider prov; XENCCipher * cipher; try { /* * Now we have a document, find the data node. */ // Generate a key unsigned char randomBuffer[256]; if (XSECPlatformUtils::g_cryptoProvider->getRandom(randomBuffer, 256) != 256) { cerr << "Unable to obtain enough random bytes from Crypto Provider" << endl; exit(1); } cipher = prov.newCipher(doc); cipher->setXENCNSPrefix(MAKE_UNICODE_STRING("xenc")); cipher->setPrettyPrint(true); // Set a key XSECCryptoSymmetricKey * k = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); k->setKey((unsigned char *) randomBuffer, 24); cipher->setKey(k); // Now encrypt! cerr << "Performing 3DES encryption on <category> element ... "; cipher->encryptElement((DOMElement *) categoryNode, DSIGConstants::s_unicodeStrURI3DES_CBC); // Add a KeyInfo cerr << "done\nAppending a <KeyName> ... "; XENCEncryptedData * encryptedData = cipher->getEncryptedData(); encryptedData->appendKeyName(s_tstKeyName); cerr << "done\nAdding Encoding and MimeType ... "; // Add MimeType and Encoding encryptedData->setEncoding(s_tstEncoding); encryptedData->setMimeType(s_tstMimeType); // Set a KeySize cerr << "done\nSetting <KeySize> ... "; encryptedData->getEncryptionMethod()->setKeySize(192); cerr << "done\nSearching for <category> ... "; DOMNode * t = findNode(doc, MAKE_UNICODE_STRING("category")); if (t != NULL) { cerr << "found!\nError - category is not encrypted" << endl; exit(1); } else cerr << "not found (OK - now encrypted)" << endl; // Now try to encrypt the Key cerr << "Encrypting symmetric key ... " << endl; XSECCryptoSymmetricKey * kek; if (g_haveAES) { kek = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); kek->setKey((unsigned char *) s_keyStr, 16); } else { kek = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); kek->setKey((unsigned char *) s_keyStr, 24); } cipher->setKEK(kek); XENCEncryptedKey * encryptedKey; if (g_haveAES) encryptedKey = cipher->encryptKey(randomBuffer, 24, DSIGConstants::s_unicodeStrURIKW_AES128); else encryptedKey = cipher->encryptKey(randomBuffer, 24, DSIGConstants::s_unicodeStrURIKW_3DES); cerr << "done!" << endl; cerr << "Adding CarriedKeyName and Recipient to encryptedKey ... " << endl; encryptedKey->setCarriedKeyName(s_tstCarriedKeyName); encryptedKey->setRecipient(s_tstRecipient); cerr << "done!" << endl; encryptedData->appendEncryptedKey(encryptedKey); outputDoc(impl, doc); // OK - Now we try to decrypt // Find the EncryptedData node DOMNode * n = findXENCNode(doc, "EncryptedData"); XENCCipher * cipher2 = prov.newCipher(doc); XSECCryptoSymmetricKey * k2; if (g_haveAES) { k2 = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_AES_128); k2->setKey((unsigned char *) s_keyStr, 16); } else { k2 = XSECPlatformUtils::g_cryptoProvider->keySymmetric(XSECCryptoSymmetricKey::KEY_3DES_192); k2->setKey((unsigned char *) s_keyStr, 24); } cipher2->setKEK(k2); cerr << "Decrypting ... "; cipher2->decryptElement(static_cast<DOMElement *>(n)); cerr << "done" << endl; cerr << "Checking for <category> element ... "; t = findNode(doc, MAKE_UNICODE_STRING("category")); if (t == NULL) { cerr << " not found!\nError - category did not decrypt properly" << endl; exit(1); } else cerr << "found" << endl; cerr << "Checking <KeyName> element is set correctly ... "; encryptedData = cipher2->getEncryptedData(); if (encryptedData == NULL) { cerr << "no - cannot access EncryptedData element" << endl; exit(1); } DSIGKeyInfoList * kil = encryptedData->getKeyInfoList(); int nki = (int) kil->getSize(); bool foundNameOK = false; int i; for (i = 0; i < nki; ++i) { if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_NAME) { DSIGKeyInfoName *n = (DSIGKeyInfoName *) (kil->item(i)); if (!strEquals(n->getKeyName(), s_tstKeyName)) { cerr << "no!" << endl; exit (1); } foundNameOK = true; break; } } if (foundNameOK == false) { cerr << "no!" << endl; exit(1); } else cerr << "yes." << endl; cerr << "Checking CarriedKeyName and Recipient values ... "; bool foundCCN = false; bool foundRecipient = false; for (i = 0; i < nki; ++i) { if (kil->item(i)->getKeyInfoType() == DSIGKeyInfo::KEYINFO_ENCRYPTEDKEY) { XENCEncryptedKey * xek = (XENCEncryptedKey*)(kil->item(i)); if (strEquals(xek->getCarriedKeyName(), s_tstCarriedKeyName)) { foundCCN = true; } if (strEquals(xek->getRecipient(), s_tstRecipient)) { foundRecipient = true; } } } if (foundCCN == false || foundRecipient == false) { cerr << "no!" << endl; exit(1); } else { cerr << "OK" << endl; } cerr << "Checking MimeType and Encoding ... "; if (encryptedData->getMimeType() == NULL || !strEquals(encryptedData->getMimeType(), s_tstMimeType)) { cerr << "Bad MimeType" << endl; exit(1); } if (encryptedData->getEncoding() == NULL || !strEquals(encryptedData->getEncoding(), s_tstEncoding)) { cerr << "Bad Encoding" << endl; exit(1); } cerr << "OK" << endl; cerr << "Checking KeySize in EncryptionMethod ... "; if (encryptedData->getEncryptionMethod() == NULL || encryptedData->getEncryptionMethod()->getKeySize() != 192) { cerr << "Bad KeySize" << endl; exit(1); } cerr << "OK" << endl; } catch (const XSECException &e) { cerr << "An error occurred during signature processing\n Message: "; char * ce = XMLString::transcode(e.getMsg()); cerr << ce << endl; delete ce; exit(1); } catch (const XSECCryptoException &e) { cerr << "A cryptographic error occurred during signature processing\n Message: " << e.getMsg() << endl; exit(1); } outputDoc(impl, doc); doc->release(); } // -------------------------------------------------------------------------------- // Print usage instructions // -------------------------------------------------------------------------------- void printUsage(void) { cerr << "\nUsage: xtest [options]\n\n"; cerr << " Where options are :\n\n"; cerr << " --help/-h\n"; cerr << " This help message\n\n"; #if defined (XSEC_HAVE_WINCAPI) && defined (XSEC_HAVE_OPENSSL) cerr << " --wincapi/-w\n"; cerr << " Use Windows Crypto API for crypto functionality\n\n"; #endif #if defined (XSEC_HAVE_NSS) cerr << " --nss/-n\n"; cerr << " Use NSS Crypto API for crypto functionality\n\n"; #endif cerr << " --print-docs/-p\n"; cerr << " Print the test documents\n\n"; cerr << " --signature-only/-s\n"; cerr << " Only run basic signature test\n\n"; cerr << " --signature-unit-only/-t\n"; cerr << " Only run signature unit tests\n\n"; cerr << " --encryption-only/-e\n"; cerr << " Only run basic encryption test\n\n"; cerr << " --encryption-unit-only/-u\n"; cerr << " Only run encryption unit tests\n\n"; cerr << " --no-gcm\n"; cerr << " Exclude AES-GCM tests\n\n"; } // -------------------------------------------------------------------------------- // Main // -------------------------------------------------------------------------------- int main(int argc, char **argv) { /* We output a version number to overcome a "feature" in Microsoft's memory leak detection */ cerr << "DSIG Info - Using Apache XML-Security-C Library v" << XSEC_VERSION_MAJOR << "." << XSEC_VERSION_MEDIUM << "." << XSEC_VERSION_MINOR << " (" << _XSEC_VERSION_FULL << ")\n"; // Check parameters bool doEncryptionTest = true; bool doEncryptionUnitTests = true; bool doSignatureTest = true; bool doSignatureUnitTests = true; // Testing for which Crypto API to use by default - only really useful on windows #if !defined(XSEC_HAVE_OPENSSL) #if defined(XSEC_HAVE_WINCAPI) g_useWinCAPI = true; #endif #endif int paramCount = 1; while (paramCount < argc) { if (_stricmp(argv[paramCount], "--help") == 0 || _stricmp(argv[paramCount], "-h") == 0) { printUsage(); exit(0); } else if (_stricmp(argv[paramCount], "--print-docs") == 0 || _stricmp(argv[paramCount], "-p") == 0) { g_printDocs = true; paramCount++; } #if defined(XSEC_HAVE_WINCAPI) && defined(XSEC_HAVE_OPENSSL) else if (_stricmp(argv[paramCount], "--wincapi") == 0 || _stricmp(argv[paramCount], "-w") == 0) { g_useWinCAPI = true; paramCount++; } #endif #if defined(XSEC_HAVE_NSS) else if (_stricmp(argv[paramCount], "--nss") == 0 || _stricmp(argv[paramCount], "-n") == 0) { g_useNSS = true; paramCount++; } #endif else if (_stricmp(argv[paramCount], "--signature-only") == 0 || _stricmp(argv[paramCount], "-s") == 0) { doEncryptionTest = false; doEncryptionUnitTests = false; doSignatureUnitTests = false; paramCount++; } else if (_stricmp(argv[paramCount], "--encryption-only") == 0 || _stricmp(argv[paramCount], "-e") == 0) { doSignatureTest = false; doEncryptionUnitTests = false; doSignatureUnitTests = false; paramCount++; } else if (_stricmp(argv[paramCount], "--encryption-unit-only") == 0 || _stricmp(argv[paramCount], "-u") == 0) { doEncryptionTest = false; doSignatureTest = false; doSignatureUnitTests = false; paramCount++; } else if (_stricmp(argv[paramCount], "--signature-unit-only") == 0 || _stricmp(argv[paramCount], "-t") == 0) { doEncryptionTest = false; doSignatureTest = false; doEncryptionUnitTests = false; paramCount++; } else if (_stricmp(argv[paramCount], "--no-gcm") == 0) { g_testGCM = false; paramCount++; } /* else if (stricmp(argv[paramCount], "--xkms-only") == 0 || stricmp(argv[paramCount], "-x") == 0) { doEncryptionTest = false; doSignatureTest = false; doEncryptionUnitTests = false; doSignatureUnitTests = false; paramCount++; }*/ else { printUsage(); return 2; } } #if defined (_DEBUG) && defined (_MSC_VER) && defined (_XSEC_DO_MEMDEBUG) // 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 // First initialise the XML system try { XMLPlatformUtils::Initialize(); #ifdef XSEC_HAVE_XALAN XPathEvaluator::initialize(); XalanTransformer::initialize(); #endif XSECPlatformUtils::Initialise(); #if defined (XSEC_HAVE_OPENSSL) && defined (XSEC_HAVE_WINCAPI) if (g_useWinCAPI) { // Setup for Windows Crypt API WinCAPICryptoProvider * cp; // First set windows as the crypto provider cp = new WinCAPICryptoProvider(); XSECPlatformUtils::SetCryptoProvider(cp); } #endif #if defined (XSEC_HAVE_NSS) if (g_useNSS) { // Setup for NSS Crypt API NSSCryptoProvider * cp; // First set windows as the crypto provider cp = new NSSCryptoProvider(); XSECPlatformUtils::SetCryptoProvider(cp); } #endif } catch (const XMLException &e) { cerr << "Error during initialisation of Xerces" << endl; cerr << "Error Message = : " << e.getMessage() << endl; } { // Set up for tests g_haveAES = XSECPlatformUtils::g_cryptoProvider->algorithmSupported(XSECCryptoSymmetricKey::KEY_AES_128); // Setup for building documents XMLCh tempStr[100]; XMLString::transcode("Core", tempStr, 99); DOMImplementation *impl = DOMImplementationRegistry::getDOMImplementation(tempStr); // Output some info char * provName = XMLString::transcode(XSECPlatformUtils::g_cryptoProvider->getProviderName()); cerr << "Crypto Provider string : " << provName << endl; XSEC_RELEASE_XMLCH(provName); // Test signature functions if (doSignatureTest) { cerr << endl << "===================================="; cerr << endl << "Testing Signature Function"; cerr << endl << "===================================="; cerr << endl << endl; testSignature(impl); } // Test signature functions if (doSignatureUnitTests) { cerr << endl << "===================================="; cerr << endl << "Performing Signature Unit Tests"; cerr << endl << "===================================="; cerr << endl << endl; unitTestSignature(impl); } // Test encrypt function if (doEncryptionTest) { cerr << endl << "===================================="; cerr << endl << "Testing Encryption Function"; cerr << endl << "===================================="; cerr << endl << endl; testEncrypt(impl); } // Running Encryption Unit test if (doEncryptionUnitTests) { cerr << endl << "===================================="; cerr << endl << "Performing Encryption Unit Tests"; cerr << endl << "===================================="; cerr << endl << endl; unitTestEncrypt(impl); } cerr << endl << "All tests passed" << endl; } XSECPlatformUtils::Terminate(); #ifdef XSEC_HAVE_XALAN XalanTransformer::terminate(); XPathEvaluator::terminate(); #endif XMLPlatformUtils::Terminate(); #if defined (_DEBUG) && defined (_MSC_VER) && defined (_XSEC_DO_MEMDEBUG) _CrtMemCheckpoint( &s2 ); if ( _CrtMemDifference( &s3, &s1, &s2 ) && ( s3.lCounts[0] > 0 || s3.lCounts[1] > 1 || // s3.lCounts[2] > 2 || We don't worry about C Runtime s3.lCounts[3] > 0 || s3.lCounts[4] > 0)) { // Note that there is generally 1 Normal and 1 CRT block // still taken. 1 is from Xalan and 1 from stdio // 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 0; }