#include <stdio.h>
#import <msxml5.dll>
using namespace MSXML2;
#define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"
// Change this key container name to your own if necessary.
#define RSA_KEY "MyRSAFullKeys"
#define INFILE "signature_template.setRef.rsa.xml"
#define OUTFILE1 "signature.setRef.rsa.obj1.xml"
#define OUTFILE2 "signature.setRef.rsa.obj2.xml"
_bstr_t infile, outfile;
IXMLDOMDocument3Ptr xmldoc = NULL;
IXMLDigitalSignaturePtr xmldsig = NULL;
VARIANT_BOOL objectsAreInitialized = VARIANT_FALSE;
VARIANT_BOOL LoadXML(_bstr_t sigFile)
{
if (!objectsAreInitialized) {
printf("Must initialize objects before loading signature.\n");
return VARIANT_FALSE;
}
if (xmldoc->load(sigFile) == VARIANT_FALSE) {
printf("Can't load %s\n", (LPCSTR)sigFile);
return VARIANT_FALSE;
}
xmldoc->setProperty("SelectionNamespaces", DSIGNS);
// Set the signature property to a <ds:Signature> DOM node.
xmldsig->signature = xmldoc->selectSingleNode(".//ds:Signature");
if (xmldsig->signature == NULL) {
printf("Failed to set the signature property.\n");
return VARIANT_FALSE;
}
return VARIANT_TRUE;
}
VARIANT_BOOL SignXML(_bstr_t objID)
{
if (xmldsig->signature == NULL) {
printf("Invalid signature template\n");
return false;
}
IXMLDSigKeyPtr pKey = xmldsig->createKeyFromCSP(
PROV_RSA_FULL, "", RSA_KEY, 0);
if (pKey==NULL) {
printf("Invalid key\n");
return false;
}
_bstr_t xpath =".//ds:Object[@Id='"+ objID +"']";
IXMLDOMNodePtr pNode = xmldoc->selectSingleNode(xpath);
if (pNode == NULL) {
printf("Can't select node\n");
return false;
}
HRESULT hr = xmldsig->setReferenceData("#obj2", pNode);
if (FAILED(hr)) {
printf("Can't set reference data\n");
return false;
}
IXMLDSigKeyPtr pKeyOut = xmldsig->sign(pKey, KEYVALUE);
if (NULL == pKeyOut) {
printf("sign failed.\n");
return false;
}
printf("The specified data was signed successfully.\n");
printf("Resultant signature:\n\n");
printf((LPCSTR)xmldoc->xml);
printf("\n");
hr = xmldoc->save(outfile);
if (FAILED(hr)) {
printf("can't save the signed signature file.\n");
return false;
}
return true;
}
VARIANT_BOOL VerifyXML(_bstr_t objID)
{
IXMLDOMNodePtr pKeyInfo, pNode;
IXMLDSigKeyPtr pKey, pKeyOut;
pKeyInfo = xmldoc->selectSingleNode(".//ds:KeyInfo/ds:KeyValue");
if (pKeyInfo == NULL) {
printf("Invalid <ds:KeyInfo>\n");
return VARIANT_FALSE;
}
pKey = xmldsig->createKeyFromNode(pKeyInfo);
if (pKey== NULL) {
printf("Invalid key from <ds:KeyInfo>\n");
return VARIANT_FALSE;
}
_bstr_t xpath = ".//ds:Object[@Id='"+ objID +"']";
pNode = xmldoc->selectSingleNode(xpath);
HRESULT hr =xmldsig->setReferenceData("#obj2", pNode);
if (FAILED(hr)) {
printf("Can't set Reference data source\n");
return VARIANT_FALSE;
}
pKeyOut = xmldsig->verify(pKey);
if (pKeyOut== NULL) {
printf("Invalid signature.\n");
return VARIANT_FALSE;
}
printf("Signature verified on the data.\n");
return VARIANT_TRUE;
}
VARIANT_BOOL initObjects()
{
if (FAILED(xmldsig.CreateInstance(__uuidof(MXDigitalSignature50)) )) {
printf("Installation of msxml5 is required to run this app.\n");
return VARIANT_FALSE;
}
if (FAILED(xmldoc.CreateInstance(__uuidof(DOMDocument50)) )) {
printf("Installation of msxml5 is required to run this app.\n");
return VARIANT_FALSE;
}
xmldoc->async = VARIANT_FALSE;
xmldoc->validateOnParse = VARIANT_FALSE;
xmldoc->preserveWhiteSpace = VARIANT_TRUE;
xmldoc->resolveExternals = VARIANT_FALSE;
objectsAreInitialized = VARIANT_TRUE;
return VARIANT_TRUE;
}
void cleanObjects()
{
if (xmldoc) xmldoc.Release();
if (xmldsig) xmldsig.Release();
}
void main()
{
if ( CoInitialize(NULL) == E_FAIL) {
printf("can't initialize COM Lib\n");
exit(-1);
}
if (!initObjects()) {
cleanObjects();
exit(-1);
}
infile = INFILE;
printf("Attempting to sign the object of 'obj1'\n\n");
outfile = OUTFILE1;
if (VARIANT_TRUE == LoadXML(infile)) {
SignXML("obj1");
}
if(VARIANT_TRUE == LoadXML(outfile)) {
VerifyXML("obj1");
}
printf("Attempting to sign the object of 'obj2'\n\n");
outfile = OUTFILE2;
if (VARIANT_TRUE == LoadXML(infile)) {
SignXML("obj2");
}
if(VARIANT_TRUE == LoadXML(outfile)) {
VerifyXML("obj2");
}
cleanObjects();
CoUninitialize();
}
Try It!
Note You can also copy the file into the project's main directory using Windows Explorer (or a command prompt).