#import <msxml5.dll>
using namespace MSXML2;
#include <stdio.h>
#include <wincrypt.h>
#define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"
#define INFILE "signature_signed.rsa.cert.xml"
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;
}
// Load signature document from file:
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;
}
// Test if the certificate of a key (pKey) is valid.
// In this simple example, the certificate is verified
// if a trust chain can be built up without errors. In
// a production application, more elaborate verification
// criteria may be necessary. For more information, see
// the CryptoAPI documentation.
VARIANT_BOOL IsCertificateValid(IXMLDSigKeyExPtr pKey)
{
if (pKey == NULL) {
printf("invalid key object.\n");
return VARIANT_FALSE;
}
// Retrieve the ceritificate from the verifying key.
PCCERT_CONTEXT pCert=NULL;
pCert = (PCCERT_CONTEXT)pKey->getVerifyingCertificateContext();
if (pCert == NULL) {
printf ("Can't get verifying certificate context\n");
return VARIANT_FALSE;
}
// Use CryptoAPI to verify the certificate.
CERT_CHAIN_ENGINE_CONFIG chainConfig;
PCCERT_CHAIN_CONTEXT pChainContext;
CERT_CHAIN_PARA chainPara;
HCERTCHAINENGINE hChainEngine=NULL; // Use the default chain engine.[HCCE_CURRENT_USER]
// Initialize chainPara:
chainPara.cbSize = sizeof(CERT_CHAIN_PARA);
chainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
chainPara.RequestedUsage.Usage.cUsageIdentifier =0;
chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
// Initialize chainConfig:
chainConfig.cbSize = sizeof(CERT_CHAIN_ENGINE_CONFIG);
chainConfig.hRestrictedRoot = NULL;
chainConfig.hRestrictedTrust = NULL;
chainConfig.hRestrictedOther = NULL;
chainConfig.cAdditionalStore = 0;
chainConfig.rghAdditionalStore = NULL;
chainConfig.dwFlags = CERT_CHAIN_CACHE_END_CERT;
chainConfig.dwUrlRetrievalTimeout = 0 ;
chainConfig.MaximumCachedCertificates = 0 ;
chainConfig.CycleDetectionModulus = 0;
// Creates a certificate chain engine to build a certificate trust chain.
if( !CertCreateCertificateChainEngine(&chainConfig, &hChainEngine) )
{
printf("Can't create certificate chain engine. Error Code= %d\n", GetLastError());
return VARIANT_FALSE;
}
// Build a certificate chain from the chain engine.
if( !CertGetCertificateChain(hChainEngine, // chain engine handle
pCert, // Pointer to the end certificate.
NULL, // Use the default time.
NULL, // Search no additional stores.
&chainPara, // Use AND logic, and enhanced key usage as indicated in the ChainPara data structure.
CERT_CHAIN_REVOCATION_CHECK_END_CERT,
NULL, // Currently reserved.
&pChainContext)) // Return a pointer to the chain created.
{
printf("Failed to complete the trust chain of the certificate. ");
printf("Error code = %d\n", GetLastError());
CertFreeCertificateChain(pChainContext);
CertFreeCertificateChainEngine(hChainEngine);
CertFreeCertificateContext(pCert);
return VARIANT_FALSE;
}
// Verification successful.
CertFreeCertificateChain(pChainContext);
CertFreeCertificateChainEngine(hChainEngine);
CertFreeCertificateContext(pCert);
return VARIANT_TRUE;
}
VARIANT_BOOL VerifyXML(XMLDSIG_WRITEKEYINFO fWriteKeyInfo)
{
IXMLDOMNodePtr pKeyInfo, pNode;
IXMLDSigKeyPtr pKey, pKeyOut;
if (xmldsig->signature == NULL) {
printf("Invalid signature.\n");
return VARIANT_FALSE;
}
switch (fWriteKeyInfo & CERTIFICATES)
{
case CERTIFICATES:
pKeyInfo = xmldoc->selectSingleNode(
".//ds:KeyInfo/ds:X509Data");
break;
case KEYVALUE:
pKeyInfo = xmldoc->selectSingleNode(
".//ds:KeyInfo/ds:KeyValue");
break;
}
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;
}
pKeyOut = xmldsig->verify(pKey);
if (pKeyOut== NULL) {
printf("Invalid signature.\n");
return VARIANT_FALSE;
}
printf("Signature verified on the data.\n\n");
if ( (fWriteKeyInfo & CERTIFICATES) == CERTIFICATES) {
if (IsCertificateValid(pKeyOut)) {
printf("certificate used is valid.\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);
}
printf("Verifying signature.\n\n");
if (VARIANT_TRUE == LoadXML(INFILE)) {
VerifyXML(CERTIFICATES);
}
cleanObjects();
CoUninitialize();
}
Try It!
Note You can also copy the file into the project's main directory using Windows Explorer (or a command prompt).