Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Example C Program: Encoding and Decoding a Countersigned Message

The following example shows how to encode and decode a countersigned message. This example uses the MyHandleError example function. Code for the MyHandleError function and other auxiliary functions is also listed under General Purpose Functions.

#include <stdafx.h>

#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>

// Link with the Crypt32.lib file.
#pragma comment (lib, "crypt32")

#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

//-------------------------------------------------------------------
// Define the names of two certificate subjects.
// To use this program, the definitions of SIGNER_NAME and 
// COUNTER_SIGNER_NAME must be changed to the names of 
// the subjects of certificates that have access to private keys. 
// These certificates must have either the 
// CERT_KEY_PROV_INFO_PROP_ID or CERT_KEY_CONTEXT_PROP_ID 
// property set for the contexts to provide access to private 
// signature keys.

#define SIGNER_NAME L"Insert_signer_name_here"
#define COUNTER_SIGNER_NAME L"Insert_counter_signer_name_here"

#define MAX_NAME 256

void MyHandleError(char *s);

int _tmain(int argc, _TCHAR* argv[])
{
 //---------------------------------------------------------------
 // Declare and initialize variables. This includes declaring and 
 // initializing a pointer to message content to be countersigned 
 // and encoded. Usually, the message content will exist somewhere
 // and a pointer to it is passed to the application. 

 BYTE* pbContent;
 DWORD cbContent;
 HCRYPTPROV hCryptProv;
 HCERTSTORE hStoreHandle;
 PCCERT_CONTEXT pSignerCert;
 CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
 CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
 CERT_BLOB SignerCertBlob;
 CERT_BLOB SignerCertBlobArray[1];
 CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
 DWORD cbEncodedBlob;
 BYTE* pbEncodedBlob;
 HCRYPTMSG hMsg;
 DWORD cbDecoded;
 BYTE *pbDecoded;
 PCCERT_CONTEXT pCntrSigCert;
 CMSG_SIGNER_ENCODE_INFO CountersignerInfo;
 CMSG_SIGNER_ENCODE_INFO CntrSignArray[1];
 DWORD cbSignerInfo;
 PBYTE pbSignerInfo;
 DWORD cbCountersignerInfo;
 PCRYPT_ATTRIBUTES pCountersignerInfo;
 char pszNameString[MAX_NAME];
 CRYPT_VERIFY_MESSAGE_PARA VerifyParams;
 BYTE *pbDecodedMessageBlob;
 DWORD cbDecodedMessageBlob;
 DWORD dwKeySpec;

 // The message.
 pbContent = (BYTE*)"I must go back to where all messages start.";

 //---------------------------------------------------------------
 // Begin processing. 

 //---------------------------------------------------------------
 // Initialize cbContent to the length of pbContent
 // including the terminating NULL character.
 cbContent = lstrlenA((char *) pbContent) + 1;

 printf("The example message is ->.\n");
 printf("%s\n\n", pbContent);

 //---------------------------------------------------------------
 // Open the MY system certificate store.
 if(!(hStoreHandle = CertOpenStore(
 CERT_STORE_PROV_SYSTEM,
 0,
 NULL,
 CERT_SYSTEM_STORE_CURRENT_USER,
 L"MY")))
 {
 MyHandleError("Could not open the MY system store.");
 }

 //---------------------------------------------------------------
 // Get a pointer to a signer's signature certificate.
 if(pSignerCert = CertFindCertificateInStore(
 hStoreHandle,
 MY_ENCODING_TYPE,
 0,
 CERT_FIND_SUBJECT_STR,
 SIGNER_NAME,
 NULL))
 {
 //-----------------------------------------------------------
 // A certificate was found. Get and print the name of the 
 // subject of the certificate.
 if(CertGetNameStringA(
 pSignerCert,
 CERT_NAME_SIMPLE_DISPLAY_TYPE,
 0,
 NULL,
 pszNameString,
 MAX_NAME) > 1)
 {
 printf("The message signer is %s.\n",pszNameString);
 }
 else
 {
 MyHandleError("Getting the signer name failed.\n");
 }
 }
 else
 {
 MyHandleError("Cert not found.\n");
 }

 //---------------------------------------------------------------
 // Initialize the CMSG_SIGNER_ENCODE_INFO structure.

 //---------------------------------------------------------------
 // Get a handle to a cryptographic provider. 
 if(!(CryptAcquireCertificatePrivateKey(
 pSignerCert,
 0,
 NULL,
 &hCryptProv,
 &dwKeySpec,
 NULL)))
 {
 MyHandleError("CryptAcquireContext failed.");
 }
 
 memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
 SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
 SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
 SignerEncodeInfo.hCryptProv = hCryptProv;
 SignerEncodeInfo.dwKeySpec = dwKeySpec;
 SignerEncodeInfo.HashAlgorithm.pszObjId = szOID_RSA_MD5;
 SignerEncodeInfo.pvHashAuxInfo = NULL;

 //---------------------------------------------------------------
 // Initialize the first element of an array of signers. 
 // Note: Currently, there is only one signer.
 SignerEncodeInfoArray[0] = SignerEncodeInfo;

 //---------------------------------------------------------------
 // Initialize the CMSG_SIGNED_ENCODE_INFO structure.
 SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
 SignerCertBlob.pbData = pSignerCert->pbCertEncoded;

 //---------------------------------------------------------------
 // Initialize the first element of an array of signer BLOBs.
 // Note: In this program, only one signer BLOB is used.
 SignerCertBlobArray[0] = SignerCertBlob;
 memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
 SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
 SignedMsgEncodeInfo.cSigners = 1;
 SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
 SignedMsgEncodeInfo.cCertEncoded = 1;
 SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;

 //---------------------------------------------------------------
 // Get the size of the encoded message BLOB.
 cbEncodedBlob = CryptMsgCalculateEncodedLength(
 MY_ENCODING_TYPE,
 0,
 CMSG_SIGNED,
 &SignedMsgEncodeInfo,
 NULL,
 cbContent);
 if(!cbEncodedBlob)
 {
 MyHandleError("Getting cbEncodedBlob length failed.");
 }

 //---------------------------------------------------------------
 // Allocate memory for the encoded BLOB.
 pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
 if(!pbEncodedBlob)
 {
 MyHandleError("malloc operation failed.");
 }

 //---------------------------------------------------------------
 // Open a message to encode.
 hMsg = CryptMsgOpenToEncode(
 MY_ENCODING_TYPE,
 0,
 CMSG_SIGNED,
 &SignedMsgEncodeInfo,
 NULL,
 NULL);
 if(!hMsg)
 {
 MyHandleError("OpenToEncode failed.");
 }

 //---------------------------------------------------------------
 // Update the message with the data.
 if(!(CryptMsgUpdate(
 hMsg,
 pbContent,
 cbContent,
 TRUE)))
 {
 MyHandleError("CryptMsgUpdate failed.");
 }

 //---------------------------------------------------------------
 // Get the resulting message.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_CONTENT_PARAM,
 0,
 pbEncodedBlob,
 &cbEncodedBlob))
 {
 printf("Message successfully signed.\n");
 }
 else
 {
 MyHandleError("CryptMsgGetParam failed.");
 }

 //---------------------------------------------------------------
 // The message is signed and encoded.
 // Close the message handle and the certificate store.
 CryptMsgClose(hMsg);
 CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
 CryptReleaseContext(hCryptProv,0);

 //---------------------------------------------------------------
 // Next, countersign the signed message. 
 // Assume that pbEncodedBlob, the message just created, was sent 
 // to an intended recipient.

 // From the recipient's point of view, the following code 
 // completes these steps: 
 // 1. Decodes the message
 // 2. Verifies the signature on the message
 // 3. Adds a countersignature to the signed message
 //
 // The counter-signed message is returned to the original signer 
 // of the message, where the counter-signature is verified.

 //---------------------------------------------------------------
 // Open a message for decoding.
 hMsg = CryptMsgOpenToDecode(
 MY_ENCODING_TYPE,
 0,
 0,
 NULL,
 NULL,
 NULL);
 if(!hMsg)
 {
 MyHandleError("CryptOpenToDecode failed.");
 }

 //---------------------------------------------------------------
 // Update the message with the encoded BLOB.
 if(!(CryptMsgUpdate(
 hMsg,
 pbEncodedBlob,
 cbEncodedBlob,
 TRUE)))
 {
 MyHandleError("Decode CryptMsgUpdate failed.");
 }

 //---------------------------------------------------------------
 // Get the size of the message.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_CONTENT_PARAM,
 0,
 NULL,
 &cbDecoded))
 {
 printf("The message is %d bytes long.\n", cbDecoded);
 }
 else
 {
 MyHandleError("Decode CMSG_CONTENT_PARAM failed.");
 }

 //---------------------------------------------------------------
 // Allocate memory.
 pbDecoded = (BYTE*)malloc(cbDecoded);
 if(!pbDecoded)
 {
 MyHandleError("Decode memory allocation failed.");
 }

 //---------------------------------------------------------------
 // Copy the message to the buffer.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_CONTENT_PARAM,
 0,
 pbDecoded,
 &cbDecoded))
 {
 printf("The successfully decoded message is -> ");
 printf("%s\n", pbDecoded);
 }
 else
 {
 MyHandleError("Decode CMSG_CONTENT_PARAM #2 failed.");
 }

 //---------------------------------------------------------------
 // Check the signature. 
 // Initialize the VerifyParams data structure.
 VerifyParams.cbSize = sizeof(CRYPT_VERIFY_MESSAGE_PARA);
 VerifyParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
 VerifyParams.hCryptProv = 0;
 VerifyParams.pfnGetSignerCertificate = NULL;
 VerifyParams.pvGetArg = NULL;

 if(!(CryptVerifyMessageSignature(
 &VerifyParams,
 0,
 pbEncodedBlob,
 cbEncodedBlob,
 NULL,
 &cbDecodedMessageBlob,
 NULL)))
 {
 printf("Getting the size of the verification message " \
 "failed.\n");
 }

 pbDecodedMessageBlob = (BYTE*)malloc(cbDecodedMessageBlob);
 if(!pbDecodedMessageBlob)
 {
 MyHandleError("Memory allocation failed.");
 }

 if(CryptVerifyMessageSignature(
 &VerifyParams,
 0,
 pbEncodedBlob,
 cbEncodedBlob,
 pbDecodedMessageBlob,
 &cbDecodedMessageBlob,
 NULL))
 {
 printf("The Signature verified message is -> \n");
 printf("%s \n\n",pbDecodedMessageBlob);
 }
 else
 {
 MyHandleError("Verification message failed.");
 }

 //---------------------------------------------------------------
 // Proceed with the countersigning.
 // First, open a certificate store.
 if(!(hStoreHandle = CertOpenStore(
 CERT_STORE_PROV_SYSTEM, 
 0, 
 NULL,
 CERT_SYSTEM_STORE_CURRENT_USER,
 L"MY")))
 {
 MyHandleError("Could not open the MY system store.");
 }

 //---------------------------------------------------------------
 // Get the countersigner's certificate. 
 if(pCntrSigCert = CertFindCertificateInStore(
 hStoreHandle,
 MY_ENCODING_TYPE, 
 0, 
 CERT_FIND_SUBJECT_STR, 
 COUNTER_SIGNER_NAME, 
 NULL))
 {
 if(CertGetNameStringA(
 pCntrSigCert ,
 CERT_NAME_SIMPLE_DISPLAY_TYPE,
 0,
 NULL,
 pszNameString,
 MAX_NAME) > 1)
 {
 printf("The counter signer is %s.\n", pszNameString);
 }
 else
 {
 MyHandleError("Getting the countersigner name " \
 "failed.\n");
 }
 }
 else
 {
 MyHandleError("Could not find the countersigner's " \
 "certificate.");
 }

 //---------------------------------------------------------------
 // Initialize the CMSG_SIGNER_ENCODE_INFO structure.
 if(!(CryptAcquireCertificatePrivateKey(
 pCntrSigCert,
 0,
 NULL,
 &hCryptProv,
 &dwKeySpec,
 NULL)))
 {
 MyHandleError("CryptAcquireContext failed.");
 }

 memset(&CountersignerInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
 CountersignerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
 CountersignerInfo.pCertInfo = pCntrSigCert->pCertInfo;
 CountersignerInfo.hCryptProv = hCryptProv;
 CountersignerInfo.dwKeySpec = dwKeySpec;
 CountersignerInfo.HashAlgorithm.pszObjId = szOID_RSA_MD5;

 CntrSignArray[0] = CountersignerInfo;

 //---------------------------------------------------------------
 // Countersign the message.
 if(CryptMsgCountersign(
 hMsg,
 0,
 1,
 CntrSignArray))
 {
 printf("CryptMsgCountersign succeeded.\n");
 }
 else
 {
 MyHandleError("CryptMsgCountersign failed.");
 }

 //---------------------------------------------------------------
 // Get a pointer to the new, countersigned message BLOB.
 // Get the size of memory required.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_ENCODED_MESSAGE,
 0,
 NULL,
 &cbEncodedBlob))
 {
 printf("The size of the encoded BLOB is %d.\n",
 cbEncodedBlob);
 }
 else
 {
 MyHandleError("Sizing of cbSignerInfo failed.");
 }

 //---------------------------------------------------------------
 // Allocate memory.
 pbEncodedBlob = (BYTE*) malloc(cbEncodedBlob);
 if(pbEncodedBlob)
 {
 printf("%d bytes allocated.\n", cbEncodedBlob);
 }
 else
 {
 MyHandleError("cbSignerInfo memory allocation failed.");
 }

 //---------------------------------------------------------------
 // Get the new message encoded BLOB.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_ENCODED_MESSAGE,
 0,
 pbEncodedBlob,
 &cbEncodedBlob))
 {
 printf("The message is complete. \n");
 }
 else
 {
 MyHandleError("Getting pbEncodedBlob failed.");
 }

 //---------------------------------------------------------------
 // The message is complete. Close the handle.
 CryptMsgClose(hMsg); 

 //---------------------------------------------------------------
 // Verify the countersignature.
 // Assume that the countersigned message 
 // went back to the originator, 
 // where, again, it will be decoded.

 //---------------------------------------------------------------
 // Before verifying the countersignature, 
 // the message must first
 // be decoded.

 //---------------------------------------------------------------
 // Open a message for decoding.
 if(hMsg = CryptMsgOpenToDecode(
 MY_ENCODING_TYPE,
 0,
 0,
 0,
 NULL,
 NULL))
 {
 printf("The message to decode has been opened.\n");
 }
 else
 {
 MyHandleError("CryptMsgOpenToDecode failed.");
 }

 //---------------------------------------------------------------
 // Update the message with the encoded BLOB.
 if(CryptMsgUpdate(
 hMsg,
 pbEncodedBlob,
 cbEncodedBlob,
 TRUE))
 {
 printf("The message to decode has been updated.\n");
 }
 else
 {
 MyHandleError("Updating the countersignature message " \
 "failed.");
 }

 //---------------------------------------------------------------
 // Get a pointer to the CERT_INFO member of 
 // countersigner's certificate. 

 //---------------------------------------------------------------
 // Retrieve the signer information from the message.
 // Get the size of memory required.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_ENCODED_SIGNER,
 0,
 NULL,
 &cbSignerInfo))
 {
 printf("Signer information is %d bytes.\n", cbSignerInfo);
 }
 else
 {
 MyHandleError("Sizing of cbSignerInfo failed.");
 }

 //---------------------------------------------------------------
 // Allocate memory.
 pbSignerInfo = (BYTE*) malloc(cbSignerInfo);
 if(!pbSignerInfo)
 {
 MyHandleError("cbSignerInfo memory allocation failed.");
 }

 //---------------------------------------------------------------
 // Get the message signer information.
 if(!(CryptMsgGetParam(
 hMsg,
 CMSG_ENCODED_SIGNER,
 0,
 pbSignerInfo,
 &cbSignerInfo)))
 {
 MyHandleError("Getting pbSignerInfo failed.");
 }

 //---------------------------------------------------------------
 // Retrieve the countersigner information from the message.
 // Get the size of memory required.
 if(CryptMsgGetParam(
 hMsg,
 CMSG_SIGNER_UNAUTH_ATTR_PARAM,
 0,
 NULL,
 &cbCountersignerInfo))
 {
 printf("Counter Signer information is %d bytes.\n", 
 cbCountersignerInfo);
 }
 else
 {
 MyHandleError("Sizing of cbCountersignerInfo failed.");
 }

 //---------------------------------------------------------------
 // Allocate memory.
 pCountersignerInfo = 
 (CRYPT_ATTRIBUTES*)malloc(cbCountersignerInfo);
 if(!pCountersignerInfo)
 {
 MyHandleError("pbCountersignInfo memory allocation failed.");
 }

 //---------------------------------------------------------------
 // Get the message counter signer info.
 if(!(CryptMsgGetParam(
 hMsg,
 CMSG_SIGNER_UNAUTH_ATTR_PARAM,
 0,
 pCountersignerInfo,
 &cbCountersignerInfo)))
 {
 MyHandleError("Getting pbCountersignerInfo failed.");
 }

 //---------------------------------------------------------------
 // Verify the countersignature.
 if(CryptMsgVerifyCountersignatureEncoded(
 0,
 MY_ENCODING_TYPE,
 pbSignerInfo,
 cbSignerInfo,
 pCountersignerInfo->rgAttr->rgValue->pbData,
 pCountersignerInfo->rgAttr->rgValue->cbData,
 pCntrSigCert->pCertInfo))
 {
 printf("Verification of countersignature succeeded.\n");
 }
 else
 {
 printf("Verification of countersignature failed.\n");
 if(GetLastError() == NTE_BAD_SIGNATURE)
 {
 printf("Bad signature.\n");
 }
 else
 {
 printf("Other verification error.\n");
 }
 }

 //---------------------------------------------------------------
 // Clean up.
 free(pbEncodedBlob);
 free(pbDecoded);
 free(pbSignerInfo);
 free(pCountersignerInfo);
 CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
 CryptMsgClose(hMsg);
 CryptReleaseContext(hCryptProv,0);

 return 0;
}

//-------------------------------------------------------------------
// Define function MyHandleError
void MyHandleError(char *s)
{
 fprintf(stderr,"An error occurred in running the program. \n");
 fprintf(stderr,"%s\n",s);
 fprintf(stderr,"Error number %x.\n",GetLastError());
 fprintf(stderr,"Program terminating. \n");
 exit(1);
}

Feedback

Was this page helpful?

Additional resources