The following example code creates a signed message, adds a countersignature to it, and then verifies the countersignature.
//===============================================================
// EXAMPLE CODE FOR CREATING A SIGNED MESSAGE, COUNTERSIGNING THE
// SIGNED MESSAGE, AND VERIFYING THE COUNTERSIGNATURE.
//===============================================================
//===============================================================
// CREATE A SIGNED MESSAGE.
//===============================================================
// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)
//-------------------------------------------------------------
// Get a pointer to the message content- this code creates
// the message content and gets a pointer to it. In reality,
// usually the content will exist somewhere and a pointer to it
// will get passed to the application.
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
"Signed Message"; // The message
char* pszContent = szContent; // A string pointer
BYTE* pbContent = (BYTE*) pszContent; // A byte pointer
DWORD cbContent = sizeof(szContent); // Size of message
// Display example name.
MessageBox(hwnd, "CryptMsgCountersign Example", NULL, MB_OK);
//-------------------------------------------------------------
// Get a handle to a cryptographic provider.
//-------------------------------------------------------------
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, // Specifies the provider type
0); // Zero allows access to private keys
if(!fReturn)
{
MessageBox(hwnd, "CryptAcquireContext failed", NULL, MB_OK);
return;
}
// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.
//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------
HCERTSTORE hStoreHandle = NULL;
// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
MessageBox(hwnd, "Error Getting Store Handle", NULL, MB_OK);
return;
}
// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.
//-------------------------------------------------------------
// Get a pointer to the signer's signature certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT pSignerCert = NULL;
// For the implementation of GetMySignerCert(), see the function
// at the end of this example code.
pSignerCert = GetMySignerCert(hwnd, hStoreHandle);
if(!pSignerCert)
{
MessageBox(hwnd, "Error Getting Signer Cert", NULL, MB_OK);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
return;
}
else
MessageBox(hwnd, "Signer's Certificate Found", NULL, MB_OK);
//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure.
//-------------------------------------------------------------
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 CMSG_SIGNER_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
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_SIGNATURE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;
// Create an array of one. NOTE: Currently, there can be only one
// signer.
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
SignerEncodeInfoArray[0] = SignerEncodeInfo;
//-------------------------------------------------------------
// Initialize the CMSG_SIGNED_ENCODE_INFO structure.
//-------------------------------------------------------------
CERT_BLOB SignerCertBlob;
SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
SignerCertBlob.pbData = pSignerCert->pbCertEncoded;
// Create an array of one. Only one certificate is included.
CERT_BLOB SignerCertBlobArray[1];
SignerCertBlobArray[0] = SignerCertBlob;
CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
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.
//-------------------------------------------------------------
DWORD cbEncodedBlob;
BYTE* pbEncodedBlob = NULL;
cbEncodedBlob = CryptMsgCalculateEncodedLength(
MY_ENCODING_TYPE, // Msg encoding type
0, // Flags
CMSG_SIGNED, // Msg type
&SignedMsgEncodeInfo, // Ptr. to struct.
NULL, // Inner content ObjID
cbContent); // size of content
if(0 == cbEncodedBlob)
{
MessageBox(hwnd, "Getting cbEncodedBlob length failed",
NULL, MB_OK);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
return;
}
//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
MessageBox(hwnd, "Malloc failed", NULL, MB_OK);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
return;
}
//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG hMsg = NULL;
hMsg = CryptMsgOpenToEncode(
MY_ENCODING_TYPE, // Encoding type
0, // Flags
CMSG_SIGNED, // Msg type
&SignedMsgEncodeInfo, // Pointer to structure
NULL, // Inner content ObjID
NULL); // Stream Info (not used)
if(NULL == hMsg)
{
MessageBox(hwnd, "OpenToEncode failed", NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;
fResult = CryptMsgUpdate(
hMsg, // Handle to the message
pbContent, // Pointer to the content
cbContent, // Size of the content
TRUE); // Last call
if(!fResult)
{
MessageBox(hwnd, "MsgUpdate failed", NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
pbEncodedBlob, // Pointer to the blob
&cbEncodedBlob); // Size of the blob
if(!fResult)
{
MessageBox(hwnd, "MsgGetParam failed", NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}else
MessageBox(hwnd, "Message successfully signed", NULL, MB_OK);
// If the call was successful, pbEncodedBlob now points to the
// encoded, signed content.
CryptMsgClose(hMsg); // The message is complete - close the handle
//===============================================================
// COUNTERSIGN THE SIGNED MESSAGE. Assume that the message just
// created was sent to the intended recipient, and that a pointer
// (pbEncodedBlob) to the message (encoded blob) has been retrieved.
// The following code will add a countersignature to the signed
// message.
//===============================================================
//---------------------------------------------------------------
// Before countersigning, the message must first be decoded.
// Open a message for decoding.
//---------------------------------------------------------------
hMsg = CryptMsgOpenToDecode(
MY_ENCODING_TYPE, // Encoding type
0, // Flags
0, // Message type (get from msg.)
hCryptProv, // Cryptographic provider
NULL, // Recipient info
NULL); // Stream info
if(NULL == hMsg)
{
MessageBox(hwnd, "OpenToDecode failed", NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Update the message with the data (encoded blob).
// In this example, pbEncodedBlob and cbEncodedBlob were
// initialized in the previous code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
hMsg, // Handle to the message
pbEncodedBlob, // Pointer to the encoded blob
cbEncodedBlob, // Size of the encoded blob
TRUE); // Last call
if(!fResult)
{
MessageBox(hwnd, "Decode MsgUpdate failed", NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Get the size of the content.
//-------------------------------------------------------------
DWORD cbDecoded = 0;
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
NULL, // Address for returned info
&cbDecoded); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Decode CMSG_CONTENT_PARAM failed", NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Allocate memory.
//-------------------------------------------------------------
BYTE *pbDecoded = NULL;
pbDecoded = (BYTE *) malloc(cbDecoded);
if(NULL == pbDecoded)
{
MessageBox(hwnd, "Decode memory allocation failed",
NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Get a pointer to the content.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_CONTENT_PARAM, // Parameter type
0, // Index
pbDecoded, // Address for returned info
&cbDecoded); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Decode CMSG_CONTENT_PARAM #2 failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}else
MessageBox(hwnd, "Message decoded successfully", NULL, MB_OK);
//---------------------------------------------------------------
// 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 countersigner's certificate.
//---------------------------------------------------------------
PCCERT_CONTEXT pCntrSigCert = NULL;
// For the implementation of GetMySignerCert(), see the function
// at the end of this example code.
pCntrSigCert = GetMySignerCert(hwnd, hStoreHandle);
if(!pCntrSigCert)
{
MessageBox(hwnd, "Couldn't Find Countersigner's "
"Certificate", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
else
MessageBox(hwnd, "Countersigner's Certificate Found",
NULL, MB_OK);
// If the call was successful, a pointer to the desired
// certificate now resides at pCntrSigCert.
//---------------------------------------------------------------
// Initialize the PCMSG_SIGNER_ENCODE_INFO structure.
//---------------------------------------------------------------
CMSG_SIGNER_ENCODE_INFO CountersignerInfo;
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_SIGNATURE;
CountersignerInfo.HashAlgorithm = HashAlgorithm;
CMSG_SIGNER_ENCODE_INFO CntrSignArray[1];
CntrSignArray[0] = CountersignerInfo;
//--------------------------------------------------------------
// Countersign the message.
//--------------------------------------------------------------
fReturn = CryptMsgCountersign(
hMsg,
0,
1,
CntrSignArray);
if(!fReturn)
{
MessageBox(hwnd, "Countersign Failed", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
else
MessageBox(hwnd, "Countersign Succeeded", NULL, MB_OK);
//---------------------------------------------------------------
// Get a pointer to the new, countersigned message blob.
//---------------------------------------------------------------
// Get the size of memory required.
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_ENCODED_MESSAGE, // Parameter type
0, // Index
NULL, // Address for returned info
&cbEncodedBlob); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Sizing of cbSignerInfo Failed", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
// Allocate memory.
pbEncodedBlob = (PBYTE) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
MessageBox(hwnd, "cbSignerInfo Memory Allocation Failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
// Get the new message encoded blob.
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_ENCODED_MESSAGE, // Parameter type
0, // Index
pbEncodedBlob, // Address for returned info
&cbEncodedBlob); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Getting pbSignerInfo failed", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
CryptMsgClose(hMsg); // The message is complete - close the handle
//=============================================================
// VERIFY THE COUNTERSIGNATURE. Assume that the countersigned
// message was re-encoded, and sent back to the originator, where
// it will be decoded.
//=============================================================
//---------------------------------------------------------------
// Before verifying the countersignature, the message must first
// be decoded.
//
// Open a message for decoding.
//---------------------------------------------------------------
hMsg = CryptMsgOpenToDecode(
MY_ENCODING_TYPE, // Encoding type
0, // Flags
0, // Message type (get from msg.)
hCryptProv, // Cryptographic provider
NULL, // Recipient info
NULL); // Stream info
if(NULL == hMsg)
{
MessageBox(hwnd, "OpenToDecode For Verify Countersignature "
"Failed", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Update the message with the data (encoded blob).
// In this example, pbEncodedBlob and cbEncodedBlob were
// initialized in the previous code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
hMsg, // Handle to the message
pbEncodedBlob, // Pointer to the encoded blob
cbEncodedBlob, // Size of the encoded blob
TRUE); // Last call
if(!fResult)
{
MessageBox(hwnd, "Verify Countersignature MsgUpdate Failed",
NULL, MB_OK);
free(pbEncodedBlob);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//-------------------------------------------------------------
// Get a pointer to the CERT_INFO member of countersigner's
// certificate. In this case, the certificate retrieved in the
// previous code segment will be used (pCntrSigCert).
//-------------------------------------------------------------
//--------------------------------------------------------------
// Retrieve the SignerInfo from the message.
//--------------------------------------------------------------
// Get the size of memory required.
DWORD cbSignerInfo = 0;
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_ENCODED_SIGNER, // Parameter type
0, // Index
NULL, // Address for returned info
&cbSignerInfo); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Sizing of cbSignerInfo Failed", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
// Allocate memory.
PBYTE pbSignerInfo;
pbSignerInfo = (PBYTE) malloc(cbSignerInfo);
if(NULL == pbSignerInfo)
{
MessageBox(hwnd, "cbSignerInfo Memory Allocation Failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
// Get the message signer information.
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_ENCODED_SIGNER, // Parameter type
0, // Index
pbSignerInfo, // Address for returned info
&cbSignerInfo); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Getting pbSignerInfo failed", NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
free(pbSignerInfo);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//--------------------------------------------------------------
// Retrieve the CountersignerInfo from the message.
//--------------------------------------------------------------
// Get the size of memory required.
DWORD cbCountersignerInfo = 0;
PCRYPT_ATTRIBUTES pCountersignerInfo = NULL;
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_SIGNER_UNAUTH_ATTR_PARAM, // Parameter type
0, // Index
NULL, // Address for returned info
&cbCountersignerInfo); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Sizing of cbCountersignerInfo Failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
// Allocate memory.
pCountersignerInfo = (PCRYPT_ATTRIBUTES) malloc(cbCountersignerInfo);
if(NULL == pCountersignerInfo)
{
MessageBox(hwnd, "pbCountersignInfo Memory Allocation Failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
// Get the message SIGNER_INFO.
fResult = CryptMsgGetParam(
hMsg, // Handle to the message
CMSG_SIGNER_UNAUTH_ATTR_PARAM, // Parameter type
0, // Index
pCountersignerInfo, // Address for returned info
&cbCountersignerInfo); // Size of the returned info
if(!fResult)
{
MessageBox(hwnd, "Getting pbCountersignerInfo failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
free(pbSignerInfo);
free(pCountersignerInfo);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
//---------------------------------------------------------------
// Verify the countersignature.
//---------------------------------------------------------------
fReturn = CryptMsgVerifyCountersignatureEncoded(
hCryptProv,
MY_ENCODING_TYPE,
pbSignerInfo,
cbSignerInfo,
pCountersignerInfo->rgAttr->rgValue->pbData,
pCountersignerInfo->rgAttr->rgValue->cbData,
pCntrSigCert->pCertInfo);
if(!fReturn)
{
MessageBox(hwnd, "Verify Countrsignature Failed",
NULL, MB_OK);
free(pbEncodedBlob);
free(pbDecoded);
free(pbSignerInfo);
free(pCountersignerInfo);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
return;
}
else
MessageBox(hwnd, "Verify Countrsignature Succeeded",
NULL, MB_OK);
//--------------------------------------------------------------
// Clean up.
//--------------------------------------------------------------
free(pbEncodedBlob);
free(pbDecoded);
free(pbSignerInfo);
free(pCountersignerInfo);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);
//************************************************************
// GetMySignerCert() - A function to list all the certificates
// in the store and get a handle to one of them.
//************************************************************
PCCERT_CONTEXT GetMySignerCert(HWND hwnd, 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 certificate containing an exchange key.
// This works here, as there is only one pair of
// certificates in the store. Normally you would search
// for a name as well as the key type.
// Call CertGetCertificateContextProperty to get the
// struct size.
fReturnFlag = CertGetCertificateContextProperty(
pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&dwSize);
if(FALSE == fReturnFlag)
MessageBox(hwnd, "Error Getting Key Property",
NULL, MB_OK);
// Allocate memory for the returned structure.
if(pKeyInfo)
free(pKeyInfo);
pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize);
if(!pKeyInfo)
{
AfxMessageBox("Error Allocating Memory");
fTestFlag = FALSE;
break;
}
// Get the key info struct.
fReturnFlag = CertGetCertificateContextProperty(
pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
pKeyInfo,
&dwSize);
// Does it have a signature key?
if(pKeyInfo->dwKeySpec == AT_SIGNATURE)
{
fTestFlag = TRUE;
break;
}
}
pPrevCertContext = pCertContext;
}
if(pKeyInfo)
free(pKeyInfo);
if(FALSE == fTestFlag)
{
MessageBox(hwnd, "Signature Cert Not Found",
NULL, MB_OK);
return NULL;
}else
return (pCertContext);
}