Note

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

Access to this page requires authorization. You can try .

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.


Feedback

Was this page helpful?

Additional resources