The following example code implements the procedure described in the previous section. Comments show which code fragments pertain to each step in the procedure. The details of the functions and structures can be found in Cryptographic Functions, Simplified Message Functions, and Data Structures.
//-------------------------------------------------------------
//-------------------------------------------------------------
// EXAMPLE CODE - SIGNING DATA FOR A MESSAGE USING
// CryptSignMessage().
//-------------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
// Get a pointer to the message - this code creates a message
// and gets a pointer to it. In reality, usually the message
// will exist somewhere and a pointer will get passed to the
// application (Step 1).
//-------------------------------------------------------------
char szMessage[] = "Secret Message"; // The message
char* pszMessage = szMessage; // A string pointer
BYTE* pbMessage = (BYTE*) pszMessage; // A byte pointer
DWORD cbMessage = sizeof(szMessage); // Size of message
AfxMessageBox(pszMessage);
//-------------------------------------------------------------
// Create the MessageArray (Step 2).
//-------------------------------------------------------------
const BYTE* MessageArray[] = {pbMessage};
DWORD MessageSizeArray[1];
MessageSizeArray[0] = cbMessage;
//-------------------------------------------------------------
// Get a handle to a crytographic provider (Step 3).
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;
fReturn = CryptAcquireContext(
&hCryptProv, // Address for handle to be returned.
NULL, // Use the current user's logon name.
NULL, // Use the default provider.
PROV_RSA_FULL, // Need to do both encrypt & sign.
NULL); // No flags needed.
if(TRUE != fReturn)
; // An error occurred. Call GetLastError and handle.
fReturn = FALSE;
// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.
//-------------------------------------------------------------
// Open a system certificate store (Step 4).
//-------------------------------------------------------------
HCERTSTORE hStoreHandle = NULL;
// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
AfxMessageBox( "Error Getting Store Handle");
return;
}
// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.
//-------------------------------------------------------------
// Get a pointer to your signature certificate (Step 5).
//-------------------------------------------------------------
PCCERT_CONTEXT pSignerCert = NULL;
// Call the GetMySignerCert function. See the function code at the end
// of this code fragment.
pSignerCert = GetMySignerCert(hStoreHandle);
if(!pSignerCert)
{
AfxMessageBox( "Error Getting Signer Cert");
return;
}
//-------------------------------------------------------------
// Create a MsgCertArray (Step 6).
//-------------------------------------------------------------
PCCERT_CONTEXT MsgCertArray[1];
MsgCertArray[0] = pSignerCert;
//-------------------------------------------------------------
// Normally, at this point, additional certificates would be
// assigned to index locations within MsgCertArray. For the sake
// of clarity, this step is bypassed in this example, and only
// the signer's certificate is included with the message.
// (Step 7)
//-------------------------------------------------------------
//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure (Step 8).
//-------------------------------------------------------------
DWORD HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize); // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5; // Then set the
// necessary field.
//-------------------------------------------------------------
// Initialize the signature structure (Step 9).
//-------------------------------------------------------------
CRYPT_SIGN_MESSAGE_PARA SigParams;
DWORD SigParamsSize = sizeof(SigParams);
memset(&SigParams, 0, SigParamsSize); // Init. to zero
// Then set the necessary
// fields.
SigParams.cbSize = SigParamsSize;
SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
SigParams.pSigningCert = pSignerCert;
SigParams.HashAlgorithm = HashAlgorithm;
SigParams.cMsgCert = 1;
SigParams.rgpMsgCert = MsgCertArray;
//-------------------------------------------------------------
// Sign the message (Step 10).
//-------------------------------------------------------------
// Get the size of the output SignedBlob.
DWORD cbSignedMessageBlob = NULL;
fReturn = FALSE;
fReturn = CryptSignMessage(
&SigParams, // Signature parameters
FALSE, // Not detached
1, // Number of messages
MessageArray, // Messages to be signed
MessageSizeArray, // Size of messages
NULL, // Buffer for signed msg
&cbSignedMessageBlob); // Size of buffer
if(FALSE == fReturn)
AfxMessageBox("Getting Signed Blob Size Failed");
// Allocate memory for the signed blob.
BYTE* pbSignedMessageBlob;
pbSignedMessageBlob = (BYTE*)malloc(cbSignedMessageBlob);
memset(pbSignedMessageBlob, 49, cbSignedMessageBlob);
if(!pbSignedMessageBlob)
AfxMessageBox("Memory allocation error while signing");
// Get the SignedMessageBlob.
DWORD dwLastError;
fReturn = FALSE;
fReturn = CryptSignMessage(
&SigParams, // Signature parameters
FALSE, // Not detached
1, // Number of messages
MessageArray, // Messages to be signed
MessageSizeArray, // Size of messages
pbSignedMessageBlob, // Buffer for signed msg
&cbSignedMessageBlob); // Size of buffer
if(FALSE == fReturn)
{
dwLastError = GetLastError();
AfxMessageBox("Getting Signed Blob Failed");
}else
AfxMessageBox("Meassge was signed successfully");
// If the call was successful, the signed blob now resides at
// the location pointed to by pbSignedMessageBlob.
... use the message.
//-------------------------------------------------------------
// Clean up, free memory, and so forth.
//-------------------------------------------------------------
free(pbSignedMessageBlob);
CertFreeCertificateContext(pSignerCert);
fReturn = CertCloseStore(
hStoreHandle,
CERT_CLOSE_STORE_CHECK_FLAG);
if(FALSE == fReturn)
AfxMessageBox("Store Closed After Signing - \n"
"Not All Certs or CRLs Were Freed");
//*****************************************************************
// GetMySignerCert() - A function to enumerate all the certificates
// in the store and get a handle to one of them.
//*****************************************************************
PCCERT_CONTEXT GetMySignerCert(HCERTSTORE hCertStore)
{
PCCERT_CONTEXT pPrevCertContext = NULL;
PCCERT_CONTEXT pCertContext = NULL;
BOOL fReturnFlag = FALSE;
BOOL fTestFlag;
DWORD dwSize = NULL;
CRYPT_KEY_PROV_INFO* pKeyInfo = NULL;
while(TRUE)
{
pCertContext = CertEnumCertificatesInStore(
hCertStore,
pPrevCertContext);
if(!pCertContext)
{
fTestFlag = FALSE;
break;
}
else
{
// For clarity, this code searches for the first
// occurrence of a signature key. This works here,
// as there is only one certificate in the store. Normally
// you would search for a name as well as the key type.
// Call CertGetCertificateContextProperty to get the
// returned structure size.
fReturnFlag = CertGetCertificateContextProperty(
pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize);
if(FALSE == fReturnFlag)
AfxMessageBox("Error Getting Key Property");
// Allocate memory for the returned structure.
If(pKeyInfo)
free(pKeyInfo);
pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize);
if(!pKeyInfo)
AfxMessageBox("Error Allocating Memory");
// Get the key info structure.
fReturnFlag = CertGetCertificateContextProperty(
pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
pKeyInfo,
&dwSize);
// Does it have a signature key?
if(pKeyInfo->dwKeySpec == AT_SIGNATURE)
{
AfxMessageBox("Signaure Cert Found");
fTestFlag = TRUE;
break;
}
}
pPrevCertContext = pCertContext;
}
CertFreeCertificateContext(pPrevCertContext);
if(pKeyInfo)
free(pKeyInfo);
if(FALSE == fTestFlag)
{
AfxMessageBox("Signature Cert Not Found");
return NULL;
}else
return (pCertContext);
}