blob: c5aed7388a6e983afd68a6e132bc57a6f2600e36 [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
*
* 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;
}