C-C++ Source: setStoreHandle.cpp

 

[This sample code uses features that were implemented in MSXML 5.0 for Microsoft Office Applications. XML digital signatures are not supported in MXSML 6.0 and later.]

#import <msxml5.dll>
using namespace MSXML2;

#include <stdio.h>
#include <wincrypt.h>

#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.setStoreHandle.rsa.xml"

IXMLDOMDocument3Ptr xmldoc = NULL;
IXMLDigitalSignatureExPtr xmldsig = NULL;
VARIANT_BOOL objectsAreInitialized = VARIANT_FALSE;
HCERTSTORE hCertStore = NULL;

// Method that loads a source xml file:
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;

}

// Method that signs a signature document:
VARIANT_BOOL SignXML(XMLDSIG_WRITEKEYINFO fwWriteKeyInfo)
{
   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;
   }

   IXMLDSigKeyPtr pKeyOut = xmldsig->sign(pKey, fwWriteKeyInfo);
   if (NULL == pKeyOut) {
      printf("sign failed.\n");
      return false;
   }

   printf("The specified data was signed successfully.\n");
   printf("Resultant signature:\n");
   printf((LPCSTR)xmldoc->xml);
   printf("\n");

   return true;
}

//
// Initialize the project: creating DOM and opening the "MY" certificate store.
//
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;


   if(hCertStore = CertOpenSystemStore(0, "MY"))
   {
     printf("The MY system store is open. Continue.\n");
   }
   else
   {
     printf("The MY system setStoreHandle did not open.\n");
     return VARIANT_FALSE;
   }

   objectsAreInitialized = VARIANT_TRUE;
   return VARIANT_TRUE;
}

void cleanObjects()
{
   if (xmldoc) xmldoc.Release();
   if (xmldsig) xmldsig.Release();
   if (hCertStore) CertCloseStore(hCertStore, 0);
}

void main() 
{
   HRESULT hr;

   if ( CoInitialize(NULL) == E_FAIL) {
      printf("can't initialize COM Lib\n");
      exit(-1);
   }

   if (!initObjects()) {
      cleanObjects();
      exit(-1);
   }


   if (VARIANT_TRUE == LoadXML(INFILE)) {
      // First sign without setting a store handle.
      printf("Sign with fwWriteKeyInfo = CERTIFICATES:\n");
      SignXML(CERTIFICATES);

      if (hCertStore) {
         hr = xmldsig->setStoreHandle((void*)hCertStore);
         printf("the store is set on xmldsig.\n");
      }
      else {
         printf("invalid certstore\n");
      }

      // Then sign with setting a store handle.
      printf("Sign with fwWriteKeyInfo = CERTIFICATES:\n");
      SignXML(XMLDSIG_WRITEKEYINFO(CERTIFICATES|PURGE));
   }

   cleanObjects();
   CoUninitialize();
}

Try It!

  1. Ensure that you have completed all the procedures in Getting Started with XML Digital Signatures.

  2. Start Visual C++.

  3. From the File menu, select New. On the Projects tab of the New dialog box that appears, select Win32 Console Application in the left pane. Then type "setStoreHandleProj" in the Project name field. For the project Location field, either accept the default setting or choose another location. Click OK.

  4. The Win32 Console Application property page will appear. For the type of Console Application, select An empty project and click Finish. When the New Project Information box displays, click OK.

  5. Select FileView on the project browser, and highlight setStoreHandleProj files. From the File menu, select New.

  6. On the Files tab of the New dialog box, highlight C++ Source File. Then type "signature_template.setStoreHandle.rsa.xml" in the File name text box.

  7. Click OK.

  8. Copy the XML signature template file from Resource Files, and paste it into the text file you just created.

  9. Repeat steps 5-8 for the C++ file above (setStoreHandle.cpp).

  10. From the Project menu, click Settings..., then click the Link tab.

  11. In Object/library modules, type "crypt32.lib". Insert this text either before or after the existing string that lists all objects and modules for the current project. Then click OK.

  12. Build the sample by selecting Build setStoreHandleProj.exe from the Build menu.

  13. Execute the sample application by selecting !Execute setStoreHandleProj.exe from the Build menu.

  14. Verify that you output is similar to that listed in the Output topic.