#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#import <msxml5.dll>
using namespace MSXML2;
#define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"
#define SIG_IN "signature_template.rsa.xml"
IXMLDOMDocument3Ptr xmldoc = NULL;
IXMLDigitalSignatureExPtr xmldsig = NULL;
VARIANT_BOOL objectsAreInitialized = VARIANT_FALSE;
// Get the first certifcate context from the "MY" system store.
PCCERT_CONTEXT GetCertContext()
{
HCERTSTORE hCertStore=NULL;
PCCERT_CONTEXT pCert=NULL;
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
hCertStore = CertOpenSystemStore(0, "MY");
if (!hCertStore) {
printf("failed to open store\n");
return NULL;
}
pCert = CertFindCertificateInStore(
hCertStore,
MY_ENCODING_TYPE,
0,
CERT_FIND_ANY,
NULL,
NULL);
if (!pCert) {
printf("Failed to find certificate in store\n");
return NULL;
}
CertCloseStore(hCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
return pCert;
}
// Load an XML file (a signature template), sigFile, as a DOM object.
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);
xmldsig->signature = xmldoc->selectSingleNode(".//ds:Signature");
if (xmldsig->signature == NULL) {
printf("Failed to set the signature property.\n");
return VARIANT_FALSE;
}
return VARIANT_TRUE;
}
// Sign the XML data embedded in the signature template.
VARIANT_BOOL SignXML()
{
IXMLDSigKeyPtr pKey, pKeyOut;
if (xmldsig->signature == NULL)
{
printf("Invalid signature template.\n");
return VARIANT_FALSE;
}
PCCERT_CONTEXT pCertContext = GetCertContext();
pKey = xmldsig->createKeyFromCertContext((void*)pCertContext);
if (pKey== NULL) {
printf("Invalid key from CertContext\n");
return VARIANT_FALSE;
}
pKeyOut = xmldsig->sign(pKey, KEYVALUE);
if (pKeyOut== NULL) {
printf("Invalid signature.\n");
return VARIANT_FALSE;
}
CertFreeCertificateContext(pCertContext);
printf("The data referenced in the signature template was signed ");
printf("successfully.\nResultant signature:\n\n%s\n",(LPCSTR)xmldoc->xml);
return VARIANT_TRUE;
}
// Helper function that creates and initiates required DOM objects:
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;
}
// Helper function that releases objects of the application scope:
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);
}
if(VARIANT_TRUE == LoadXML(SIG_IN)) {
if (VARIANT_TRUE != SignXML()) {
printf("exit with failure.\n");
}
}
cleanObjects();
CoUninitialize();
}
Try It!
Note You can also copy the file into the project's main directory using Windows Explorer (or a command prompt).