Example Code Using CryptSignMessage

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