Was this page helpful?
Your feedback about this content is important. Let us know what you think.
Additional feedback?
1500 characters remaining
Export (0) Print
Expand All

Alternate Code for Encoding an Enveloped Message

The following example demonstrates an alternate process of encoding a signed message, using that signed message as the inner content for an enveloped message. In preparation for decoding, the inner content is tested to determine its inner-content type.

This example illustrates the following CryptoAPI functions:

This example also uses the functions MyHandleError and GetSignerCert. C code for these functions is included with the example. For code that demonstrates these and other auxiliary functions, see General Purpose Functions.



//--------------------------------------------------------------------
// Copyright (C) Microsoft.  All rights reserved.
// In this and all other examples, 
// use the #define and
// #include statements listed under #includes and #defines.
#pragma comment(lib, "crypt32.lib")

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void MyHandleError(char *s);

//--------------------------------------------------------------------
// This program uses the function GetSignerCert, declared here and
// defined after main.

PCCERT_CONTEXT GetSignerCert(
     HCERTSTORE hCertStore);

void main(void)
{
//--------------------------------------------------------------------
// 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 = (BYTE*)"The message to be countersigned.";
                               // The message
DWORD cbContent;               // Size of message
HCRYPTPROV hCryptProv;         // CSP handle
HCERTSTORE hStoreHandle;       // Store handle
PCCERT_CONTEXT pSignerCert;    // Signer certificate
DWORD HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
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;

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

cbContent = strlen((char *) pbContent)+1;
            // One is added to include the final NULL character.
printf("Processing begins.\n");
printf("The length of the original message is %d.\n",cbContent);
printf("Example message:->%s\n", pbContent);

//--------------------------------------------------------------------
// Get a handle to a cryptographic provider. 

if(CryptAcquireContext(
      &hCryptProv,        // Address for handle to be returned
      NULL,               // Use the logon name for the current user
      NULL,               // Use the default provider
      PROV_RSA_FULL,      // Provider type
      0))                 // Zero allows access to private keys
{
   printf("The CSP has been opened.");
}
else
{
    MyHandleError("CryptAcquireContext failed");
}
//--------------------------------------------------------------------
// Open the MY system certificate store.

if(hStoreHandle = CertOpenStore(
     CERT_STORE_PROV_SYSTEM, // The system store will be a 
                             // virtual store.
     0,                      // Encoding type not needed with 
                             // this PROV.
     NULL,                   // Accept the default HCRYPTPROV. 
     CERT_SYSTEM_STORE_CURRENT_USER,
                             // Set the system store location in the
                             // registry.
     L"MY"))                 // Other predefined system stores 
                             // could have been used,
                             // including trust, CA, or root.
{
   printf("Opened the MY system store. \n");
}else
{
   MyHandleError( "Could not open the MY system store.");
}
//--------------------------------------------------------------------
// Get a pointer to the signature certificate of the signer.

if(pSignerCert = GetSignerCert(hStoreHandle))
{
   printf("A signer certificate was found. \n");
}
else
{
   MyHandleError("Error getting signer certificate.");
}
//--------------------------------------------------------------------
// Initialize the algorithm identifier structure.

HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);  // Initialize to zero,
HashAlgorithm.pszObjId = szOID_RSA_MD5;  // then set the 
                                         // necessary member.

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

memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
SignerEncodeInfo.hCryptProv = hCryptProv;
SignerEncodeInfo.dwKeySpec = AT_KEYEXCHANGE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;

//--------------------------------------------------------------------
// Initialize the first element of an array of signers. 
// There can be 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.
//  Only one signer BLOB 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;
SignedMsgEncodeInfo.rgCrlEncoded = NULL;

//--------------------------------------------------------------------
// Get the size of the encoded message BLOB.

if(cbEncodedBlob = CryptMsgCalculateEncodedLength(
       MY_ENCODING_TYPE,     // Message encoding type
       0,                    // Flags
       CMSG_SIGNED,          // Message type
       &SignedMsgEncodeInfo, // Pointer to structure
       NULL,                 // Inner content OID
       cbContent))           // Size of content
{
   printf("The size for the encoded BLOB is %d.\n",cbEncodedBlob);
}
else
{
    MyHandleError("Getting cbEncodedBlob length failed.");
}
//--------------------------------------------------------------------
// Allocate memory for the encoded BLOB.

if(pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob))
{
   printf("Memory has been allocated for the BLOB. \n");
}
else
{
   MyHandleError("Malloc operation failed.");
}
//--------------------------------------------------------------------
// Open a message to encode.

if(hMsg = CryptMsgOpenToEncode(
         MY_ENCODING_TYPE,      // Encoding type
         0,                     // Flags
         CMSG_SIGNED,           // Message type
         &SignedMsgEncodeInfo,  // Pointer to structure
         NULL,                  // Inner content OID
         NULL))                 // Stream information (not used)
{
   printf("The message to encode is open. \n");
}
else
{
   MyHandleError("OpenToEncode failed");
}
//-------------------------------------------------------------
// Update the message with the data.

if(CryptMsgUpdate(
      hMsg,       // Handle to the message
      pbContent,  // Pointer to the content
      cbContent,  // Size of the content
      TRUE))      // Last call
{
   printf("Message to encode has been updated. \n");
}
else
{
   MyHandleError("MsgUpdate failed");
}
//--------------------------------------------------------------------
// Get the resulting message.

if(CryptMsgGetParam(
        hMsg,               // Handle to the message
        CMSG_CONTENT_PARAM, // Parameter type
        0,                  // Index
        pbEncodedBlob,      // Pointer to the BLOB
        &cbEncodedBlob))    // Size of the BLOB
{
   printf("Message successfully signed. \n");
}
else
{
   MyHandleError("MsgGetParam failed.");
}
//--------------------------------------------------------------------
// pbEncodedBlob points to the encoded, signed content.
// Include any further processing here.

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

//--------------------------------------------------------------------
// Next, countersign the signed message. 
// Assume that the message just created and that a pointer
// (pbEncodedBlob) to the message were sent to the intended 
// recipient.
// The following code, from the recipient's point of view, adds a 
// countersignature to the signed message.
//
// Before countersigning, the message must be decoded.

//--------------------------------------------------------------------
// Open a message for decoding.

if(hMsg = CryptMsgOpenToDecode(
       MY_ENCODING_TYPE,   // Encoding type
       0,                  // Flags
       0,                  // Message type (get from message)
       hCryptProv,         // Cryptographic provider
       NULL,               // Recipient information
       NULL))              // Stream information
{
   printf("The message for decoding has been opened. \n");
}
else
{
   MyHandleError("OpenToDecode failed.");
}
//--------------------------------------------------------------------
// Update the message with the data (encoded BLOB).
// In this example, pbEncodedBlob and cbEncodedBlob were
// created in the previous code.

if(CryptMsgUpdate(
   hMsg,            // Handle to the message
   pbEncodedBlob,   // Pointer to the encoded BLOB
   cbEncodedBlob,   // Size of the encoded BLOB
   TRUE))           // Last call
{
   printf("The message to be decoded has been updated. \n");
}
else
{
   MyHandleError("Decode MsgUpdate failed.");
}
//--------------------------------------------------------------------
// Get the size of the content.

if(CryptMsgGetParam(
      hMsg,                    // Handle to the message
      CMSG_CONTENT_PARAM,      // Parameter type
      0,                       // Index
      NULL,                    // Address for returned 
                               // information
      &cbDecoded))             // Size of the returned 
                               // information
{
   printf("The message to be decoded is %d bytes long. \n", 
	   cbDecoded);
}
else
{
   MyHandleError("Decode CMSG_CONTENT_PARAM failed");
}
//--------------------------------------------------------------------
// Allocate memory.

if(pbDecoded = (BYTE *) malloc(cbDecoded))
{
   printf("Memory has been allocated. \n");
}
else
{
   MyHandleError("Decode memory allocation failed");
}
//--------------------------------------------------------------------
// Get a pointer to the content.

if(CryptMsgGetParam(
      hMsg,                // Handle to the message
      CMSG_CONTENT_PARAM,  // Parameter type
      0,                   // Index
      pbDecoded,           // Address for returned information
      &cbDecoded))         // Size of the returned information
{
    printf("The successfully decoded message is =>%s\n",pbDecoded);
}
else
{
   MyHandleError("Decode CMSG_CONTENT_PARAM #2 failed.");
}
//--------------------------------------------------------------------
// Proceed with the countersigning.

//--------------------------------------------------------------------
// Initialize the CRYPT_ALGORITHM_IDENTIFIER structure. In this 
// case, the initialization performed for signing the message in 
// the previous code is used.

//--------------------------------------------------------------------
// Get the certificate of the countersigner. A certificate with a 
// subject name that matches the string in parameter five must  
// be in the MY store and must have its CERT_KEY_PROV_INFO_PROP_ID 
// property set.

if(pCntrSigCert=CertFindCertificateInStore(      
      hStoreHandle,
      MY_ENCODING_TYPE,            // Use X509_ASN_ENCODING.
      0,                           // No dwFlags needed. 
      CERT_FIND_SUBJECT_STR,       // Find a certificate with a
                                   // subject that matches the string
                                   // in the next parameter.
      L"Full Test Cert",           // The Unicode string to be found
                                   // in a certificate's subject.
      NULL))                       // NULL for the first call to the
                                   // function. In all subsequent
                                   // calls, it is the last pointer
                                   // returned by the function.
{
  printf("The desired certificate was found. \n");
}
else
{
   MyHandleError("Could not find the countersigner's certificate.");
}
//--------------------------------------------------------------------
// Initialize the PCMSG_SIGNER_ENCODE_INFO structure.

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

CntrSignArray[0] = CountersignerInfo;

//--------------------------------------------------------------------
// Countersign the message.

if(CryptMsgCountersign(
       hMsg,
       0,
       1,
       CntrSignArray))
{
    printf("Countersign succeeded. \n");
}
else
{
    MyHandleError("Countersign failed.");
}
//--------------------------------------------------------------------
// Get a pointer to the new, countersigned message BLOB.
// Get the size of memory required.

if(CryptMsgGetParam(
      hMsg,                  // Handle to the message
      CMSG_ENCODED_MESSAGE,  // Parameter type
      0,                     // Index
      NULL,                  // Address for returned information
      &cbEncodedBlob))       // Size of the returned information
{
   printf("The size for the encoded BLOB is %d.\n",cbEncodedBlob);
}
else
{
   MyHandleError("Sizing of cbSignerInfo failed.");
}
//--------------------------------------------------------------------
// Allocate memory.

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

if(CryptMsgGetParam(
     hMsg,                   // Handle to the message
     CMSG_ENCODED_MESSAGE,   // Parameter type
     0,                      // Index
     pbEncodedBlob,          // Address for returned information
     &cbEncodedBlob))        // Size of the returned information
{
    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,    // Encoding type
      0,                   // Flags
      0,                   // Message type (get from message)
      hCryptProv,          // Cryptographic provider
      NULL,                // Recipient information
      NULL))               // Stream information
{
   printf("The message to decode has been opened. \n");
}
else
{
   MyHandleError("OpenToDecode failed.");
}
//--------------------------------------------------------------------
// Update the message with the encoded BLOB.
// In this example, pbEncodedBlob and cbEncodedBlob were
// initialized in the previous code.

if(CryptMsgUpdate(
      hMsg,            // Handle to the message
      pbEncodedBlob,   // Pointer to the encoded BLOB
      cbEncodedBlob,   // Size of the encoded BLOB
      TRUE))           // Last call
{
   printf("The message to decode has been updated. \n");
}
else
{
    MyHandleError("Updating of the verified countersignature "
		"message failed.");
}
//-------------------------------------------------------------
// Get a pointer to the CERT_INFO member of the certificate of the  
// countersigner. In this case, the certificate retrieved in the
// previous code segment will be used (pCntrSigCert).

//--------------------------------------------------------------
// Retrieve the signer information from the message.
// Get the size of memory required.

if(CryptMsgGetParam(
      hMsg,                  // Handle to the message
      CMSG_ENCODED_SIGNER,   // Parameter type
      0,                     // Index
      NULL,                  // Address for returned information
      &cbSignerInfo))        // Size of the returned information
{
   printf("The size of the signer information has been "
	   "retrieved.\n");
}
else
{
    MyHandleError("Sizing of cbSignerInfo failed.");
}
//--------------------------------------------------------------------
// Allocate memory.

if(pbSignerInfo = (BYTE*) malloc(cbSignerInfo))
{
   printf("%d bytes allocated for the signer "
	   "information. \n", cbSignerInfo);
}
else
{
    MyHandleError("cbSignerInfo memory allocation failed");
}
//--------------------------------------------------------------------
// Get the message signer information.

if(CryptMsgGetParam(
      hMsg,                 // Handle to the message
      CMSG_ENCODED_SIGNER,  // Parameter type
      0,                    // Index
      pbSignerInfo,         // Address for returned information
      &cbSignerInfo))       // Size of the returned information
{
   printf("The signer information is retrieved. \n");
}
else
{
   MyHandleError("Getting pbSignerInfo failed.");
}
//--------------------------------------------------------------------
// Retrieve the countersigner information from the message.
// Get the size of memory required.

if(CryptMsgGetParam(
       hMsg,                         // Handle to the message
       CMSG_SIGNER_UNAUTH_ATTR_PARAM,// Parameter type
       0,                            // Index
       NULL,                         // Address for returned 
                                     // information
       &cbCountersignerInfo))        // Size of returned 
                                     // information
{
   printf("The length of the countersigner's information is "
	   "retrieved. \n");
}
else
{
   MyHandleError("Sizing of cbCountersignerInfo failed.");
}
//--------------------------------------------------------------------
// Allocate memory.

if(pCountersignerInfo =
         (CRYPT_ATTRIBUTES*)malloc(cbCountersignerInfo))
{
   printf("%d bytes allocated. \n", cbCountersignerInfo);
}
else
{
    MyHandleError("pbCountersignInfo memory allocation failed.");
}
//--------------------------------------------------------------------
// Get the message SIGNER_INFO.

if(CryptMsgGetParam(
     hMsg,                           // Handle to the message
     CMSG_SIGNER_UNAUTH_ATTR_PARAM,  // Parameter type
     0,                              // Index
     pCountersignerInfo,             // Address for returned 
                                     // information
     &cbCountersignerInfo))          // Size of the returned 
                                     // information
{
   printf("Countersigner information retrieved. \n");
}
else
{
    MyHandleError("Getting pbCountersignerInfo failed.");
}
//--------------------------------------------------------------------
// Verify the countersignature.

if(CryptMsgVerifyCountersignatureEncoded(
     hCryptProv,
     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");
}
//--------------------------------------------------------------------
// Clean up.

free(pbEncodedBlob);
free(pbDecoded);
free(pbSignerInfo);
free(pCountersignerInfo);
CertCloseStore(
     hStoreHandle, 
     CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
CryptReleaseContext(hCryptProv,0);

} // End of main

//--------------------------------------------------------------------
// 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);
}

// GetSignerCert enumerates the certificates in a store and
// finds the first certificate that has a signature key. If a 
// certificate is found, a pointer to the certificate is returned.

PCCERT_CONTEXT GetSignerCert(
        HCERTSTORE hCertStore)
//--------------------------------------------------------------------
// Parameter passed in:
// hCertStore, the handle of the store to be searched.

{
//--------------------------------------------------------------------
// Declare and initialize local variables.

PCCERT_CONTEXT       pCertContext = NULL;
BOOL                 fMore = TRUE;
DWORD                dwSize = NULL;
CRYPT_KEY_PROV_INFO* pKeyInfo = NULL;
DWORD                PropId = CERT_KEY_PROV_INFO_PROP_ID;

//--------------------------------------------------------------------
// Find certificates in the store until the end of the store
// is reached or a certificate with an AT_SIGNATURE key is found.

while(fMore && 
  (pCertContext= CertFindCertificateInStore(
     hCertStore,           // Handle of the store to be searched.
     0,                    // Encoding type. Not used for this search.
     0,                    // dwFindFlags. Special find criteria.
                           // Not used in this search.
     CERT_FIND_PROPERTY,   // Find type. Determines the kind of  
                           // search to be done. In this case, search 
                           // for certificates that have a specific 
                           // extended property.
     &PropId,              // pvFindPara. Gives the specific 
                           // value searched for, here the identifier
                           // of an extended property.
     pCertContext)))       // pCertContext is NULL for the 
                           // first call to the function. 
                           // If the function were being called
                           // in a loop, after the first call,
                           // pCertContext would be the certificate
                           // returned by the previous call.
{
//-------------------------------------------------------------
// For simplicity, this code only searches 
// for the first occurrence of an AT_SIGNATURE key. 
// In many situations, a search would also look for a 
// specific subject name as well as the key type.

//-------------------------------------------------------------
// Call CertGetCertificateContextProperty once to get the
// returned structure size.

   if(!(CertGetCertificateContextProperty(
                 pCertContext,
                 CERT_KEY_PROV_INFO_PROP_ID,
                 NULL,
                 &dwSize)))
   {
      MyHandleError("Error getting key property");
   }
//--------------------------------------------------------------
// Allocate memory for the returned structure.
    
   if(pKeyInfo)
        free(pKeyInfo);
   if(!(pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize)))
   {
       MyHandleError("Error allocating memory for pKeyInfo");
   }
   //--------------------------------------------------------------
   // Get the key information structure.

   if(!(CertGetCertificateContextProperty(
       pCertContext,
       CERT_KEY_PROV_INFO_PROP_ID,
       pKeyInfo,
       &dwSize)))
   {
       MyHandleError("The second call to the function failed.");
   }
   //-------------------------------------------     
   // Check the dwKeySpec member for a signature key.
   if(pKeyInfo->dwKeySpec == AT_SIGNATURE)
   {
        fMore  = FALSE;
    }
}  // End of while loop

if(pKeyInfo)
   free(pKeyInfo);
return (pCertContext);
}  // End of GetSignerCert.



 

 

Community Additions

ADD
Show:
© 2015 Microsoft