I have a problem to sign a document that has a
schema declaration. I have started with the simpleHMAC program
and extended it a bit.
See code below.
I am a newbie with XML security, so it may be obvious to
someone what is wrong.
The few things that differs from the original simpleHMAC
is that I added attributes on the document element node.
I also use code provided with Xerces to output the document,
but I hope that will not change anything, (since my code works ok
without the schema declaration)
Do I have to do anything else?
Best regards,
Peter
First off, run the program without schema declaration.
Run the program as follows:
./simplesignaturetest >tmp.xml;./checksig -h secret tmp.xml
Output:
Signature verified OK!
Adding schema declaration to element node, by running program as follows:
./simplesignaturetest 1 >tmp.xml;./checksig -h secret tmp.xml
Output:
Signature failed verification
Reference URI="" failed to verify
HMAC Validation of <SignedInfo> failed
#include <iostream>
// Xerces
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>
// XML-Security-C (XSEC)
#include <xsec/framework/XSECProvider.hpp>
#include <xsec/dsig/DSIGReference.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyHMAC.hpp>
#include <xsec/framework/XSECException.hpp>
// Xalan
#ifndef XSEC_NO_XALAN
#include <xalanc/XalanTransformer/XalanTransformer.hpp>
XALAN_USING_XALAN(XalanTransformer)
#endif
XERCES_CPP_NAMESPACE_USE
using namespace std;
DOMDocument *createLetter1(DOMImplementation *impl) {
DOMDocument *doc = impl->createDocument(
0,
MAKE_UNICODE_STRING("Letter"),
NULL);
DOMElement *rootElem = doc->getDocumentElement();
// Add the ToAddress
DOMElement *addressElem =
doc->createElement(MAKE_UNICODE_STRING("ToAddress"));
rootElem->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("\n")));
rootElem->appendChild(addressElem);
rootElem->setAttribute(MAKE_UNICODE_STRING("Id"),
MAKE_UNICODE_STRING("ToSign1"));
addressElem->appendChild(doc->createTextNode(
MAKE_UNICODE_STRING("The address of
Recipient 1")));
addressElem->setAttribute(MAKE_UNICODE_STRING("Id"),
MAKE_UNICODE_STRING("ToSign2"));
// A second ToAddress
addressElem = doc->createElement(MAKE_UNICODE_STRING("ToAddress"));
rootElem->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("\n")));
rootElem->appendChild(addressElem);
addressElem->appendChild(doc->createTextNode(
MAKE_UNICODE_STRING("The address of
Recipient 2")));
// Add the FromAddress
addressElem = doc->createElement(MAKE_UNICODE_STRING("FromAddress"));
rootElem->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("\n")));
rootElem->appendChild(addressElem);
addressElem->appendChild(doc->createTextNode(
MAKE_UNICODE_STRING("The address of
the Sender")));
addressElem->setAttribute(MAKE_UNICODE_STRING("Id"),
MAKE_UNICODE_STRING("ToSign3"));
// Add some text
DOMElement *textElem = doc->createElement(MAKE_UNICODE_STRING("Text"));
rootElem->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("\n")));
rootElem->appendChild(textElem);
textElem->appendChild(doc->createTextNode(
MAKE_UNICODE_STRING("\nTo whom it may
concern\n\n...\n")));
return doc;
}
// A document with a schema declaration.
DOMDocument *createLetter2(DOMImplementation *impl) {
DOMDocument *doc = createLetter1(impl);
DOMElement *docElem = doc->getDocumentElement();
docElem->setAttributeNS(MAKE_UNICODE_STRING("http://www.w3.org/2001/XMLSchema-instance"),
MAKE_UNICODE_STRING("xsi:noNamespaceSchemaLocation"),
MAKE_UNICODE_STRING("los-v1.xsd"));
return doc;
}
int main (int argc, char **argv) {
try {
XMLPlatformUtils::Initialize();
#ifndef XSEC_NO_XALAN
XalanTransformer::initialize();
#endif
XSECPlatformUtils::Initialise();
}
catch (const XMLException &e) {
cerr << "Error during initialisation of Xerces" << endl;
cerr << "Error Message = : " << e.getMessage() << endl;
}
// Create a blank Document
DOMImplementation *impl =
DOMImplementationRegistry::getDOMImplementation(MAKE_UNICODE_STRING("Core"));
// Create a letter
DOMDocument *doc;
if (argc == 2)
doc = createLetter2(impl);
else// if (argc == 2)
doc = createLetter1(impl);
DOMElement *rootElem = doc->getDocumentElement();
// The signature
XSECProvider prov;
DSIGSignature *sig;
DOMElement *sigNode;
try {
// Create a signature object
sig = prov.newSignature();
sig->setDSIGNSPrefix(MAKE_UNICODE_STRING("ds"));
// Use it to create a blank signature DOM structure from the doc
sigNode = sig->createBlankSignature(doc, CANON_C14N_COM,
SIGNATURE_HMAC, HASH_SHA1);
// Insert the signature DOM nodes into the doc
rootElem->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("\n")));
rootElem->appendChild(sigNode);
rootElem->appendChild(doc->createTextNode(MAKE_UNICODE_STRING("\n")));
// Create an envelope reference for the text to be signed
DSIGReference * ref;
if (argc == 3) { // Works ok
cerr << "Signing ToAddresses" << endl;
ref = sig->createReference(MAKE_UNICODE_STRING("#ToSign2"));
ref->appendEnvelopedSignatureTransform();
ref = sig->createReference(MAKE_UNICODE_STRING("#ToSign3"));
ref->appendEnvelopedSignatureTransform();
}
else if (argc == 4){ // Does not work as expected.
cerr << "Trying to sign all ToAddresses at once" << endl;
// None of the 2 next lines works as I expect.
ref =
sig->createReference(MAKE_UNICODE_STRING("#xpointer(id('ToSign1')//ToAddress)"));
//ref =
sig->createReference(MAKE_UNICODE_STRING("#xpointer(id('ToSign1')/ToAddress)"));
//ref =
sig->createReference(MAKE_UNICODE_STRING("#xpointer(id('ToSign1'))"));//Works
as expected.
ref->appendEnvelopedSignatureTransform();
} else {
ref = sig->createReference(MAKE_UNICODE_STRING(""));
ref->appendEnvelopedSignatureTransform();
}
// Set the HMAC Key to be the string "secret"
OpenSSLCryptoKeyHMAC * hmacKey = new OpenSSLCryptoKeyHMAC();
hmacKey->setKey((unsigned char *) "secret", (unsigned int)
strlen("secret"));
sig->setSigningKey(hmacKey);
// Add a KeyInfo element
sig->appendKeyName(MAKE_UNICODE_STRING("The secret key is
\"secret\""));
// Sign
sig->sign();
}
catch (XSECException &e) {
cerr << "An error occured during a signature load\n Message: "
<< e.getMsg() << endl;
throw;
}
// Output
// StdOutFormatTarget prints the resultant XML stream
// to stdout once it receives any thing from the serializer.
//
XMLFormatTarget *myFormTarget = new StdOutFormatTarget();
// Output
// get a serializer, an instance of DOMWriter
XMLCh tempStr[100];
XMLString::transcode("LS", tempStr, 99);
DOMWriter *theSerializer =
((DOMImplementationLS*)impl)->createDOMWriter();
//theSerializer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
theSerializer->writeNode(myFormTarget, *doc);
return 0;
}
*******************Internet Email Confidentiality Footer*******************
The contents of this e-mail message (including any attachments hereto) are
confidential to and are intended to be conveyed for the use of the
recipient to whom it is addressed only. If you receive this transmission in
error, please notify the sender of this immediately and delete the message
from your system. Any distribution, reproduction or use of this message by
someone other than recipient is not authorized and may be unlawful.