#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).