本控件只是个示例,功能比较简单,共有三个方法,本别是获取当前个人存储区证书列表、获取指定证书、使用指定证书签名。在Windows下使用Visual C++ 6.0开发ActiveX控件的步骤如下所示。
(1) 打开VC6,单击【File】|【New】命令,弹出【New】对话框。
(2)在【Projects】选项卡中,选择【MFC ActiveX ControlWizard】选项,创建一个ActiveX控件。在【Projectname】文本框中,输入项目名称“PKIAppControl”,如图所示。
(2)单击【OK】按钮,弹出ActiveX向导对话框,如图所示:
(3)使用默认设置,始终单击【Next】按钮,直到创建项目结束。为控件添加方法,如图所示:
添加GetUserList方法,无输入参数,返回值为BSTR。如图所示:
依次添加三个方法:
q BSTR GetUserList();//获得证书列表
q BSTR GetUserCert(BSTR sUserName);//根据证书名称获得对应证书(Base64编码)
q BSTR SignData(BSTR sUserName, BSTR sDataToSign);//根据证书名称对数据签名,返回Base64编码的签名数据
三个函数的实现源码如下所示,主要是调用用第三篇涉及到的CryptoAPI函数。
/*获得系统个人存储区的签名证书列表
返回证书名称列表,格式为 CertName&&&CertName
如:郭靖&&&黄蓉&&&
*/
BSTR CPKIAppControlCtrl::GetUserList()
{
CString strResult="";
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertContext = NULL;
char pszNameString[256];
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG |
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");
if(hCertStore == NULL)
{
return strResult.AllocSysString();
}
while(pCertContext= CertEnumCertificatesInStore(
hCertStore,
pCertContext))
{
CertGetNameString(pCertContext,CERT_NAME_SIMPLE_DISPLAY_TYPE,0,NULL,pszNameString,128);
strResult +=pszNameString;
strResult +="&&&";
}
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
//根据证书名称获得Base64编码的证书
BSTR CPKIAppControlCtrl::GetUserCert(LPCTSTR sUserName)
{
CString strResult="";
// TODO: Add your dispatch handler code here
CString strUserName = sUserName;
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertContext = NULL;
PCRYPT_KEY_PROV_INFO pKeyProvInfo=NULL;
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG |
CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if(hCertStore == NULL)
{
return strResult.AllocSysString();
}
pCertContext=CertFindCertificateInStore(hCertStore,X509_ASN_ENCODING ,0,CERT_FIND_SUBJECT_STR,strUserName.AllocSysString(),NULL);
if(pCertContext==NULL)
{
return strResult.AllocSysString();
}
char * strCert=NULL;
DWORD dwCertLen;
CryptBinaryToString(pCertContext->pbCertEncoded,pCertContext->cbCertEncoded,CRYPT_STRING_BASE64,strCert,&dwCertLen);
strCert= (char *)malloc(dwCertLen+1);
CryptBinaryToString(pCertContext->pbCertEncoded,pCertContext->cbCertEncoded,CRYPT_STRING_BASE64,strCert,&dwCertLen);
strCert[dwCertLen]='/0';
strResult=strCert;
free(strCert);
free(pKeyProvInfo);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
//对数据进行签名,返回Base64编码的PKCS1格式的签名数据
BSTR CPKIAppControlCtrl::SignData(LPCTSTR sUserName, LPCTSTR sDataToSign)
{
CString strResult="";
// TODO: Add your dispatch handler code here
CString strUserName = sUserName;
CString strDataToSign = sDataToSign;
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertContext = NULL;
PCRYPT_KEY_PROV_INFO pKeyProvInfo=NULL;
DWORD dwLen;
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, 0,
CERT_STORE_OPEN_EXISTING_FLAG |
CERT_SYSTEM_STORE_CURRENT_USER, L"MY");
if(hCertStore == NULL)
{
return strResult.AllocSysString();
}
pCertContext=CertFindCertificateInStore(hCertStore,X509_ASN_ENCODING ,0,CERT_FIND_SUBJECT_STR,strUserName.AllocSysString(),NULL);
if(pCertContext==NULL)
{
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
if(!CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,pKeyProvInfo,&dwLen))
{
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
pKeyProvInfo = (PCRYPT_KEY_PROV_INFO)malloc(dwLen);
if(!CertGetCertificateContextProperty(pCertContext,CERT_KEY_PROV_INFO_PROP_ID,pKeyProvInfo,&dwLen))
{
free(pKeyProvInfo);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
HCRYPTPROV hProv = 0;
CString sContainerName = pKeyProvInfo->pwszContainerName;
CString sProvName = pKeyProvInfo->pwszProvName;
if(!CryptAcquireContext(
&hProv,
sContainerName.GetBuffer(0),
sProvName.GetBuffer(0),
pKeyProvInfo->dwProvType,
0))
{
free(pKeyProvInfo);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
HCRYPTHASH hHash;
if(!CryptCreateHash(
hProv,
CALG_SHA1,
0,
0,
&hHash))
{
free(pKeyProvInfo);
CryptReleaseContext(hProv,0);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
if(!CryptHashData(
hHash,
(BYTE *)strDataToSign.GetBuffer(0),
strDataToSign.GetLength(),
0))
{
CryptDestroyHash(hHash);
free(pKeyProvInfo);
CryptReleaseContext(hProv,0);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
unsigned char Sign[256];
DWORD dwSignLen;
if(!CryptSignHash(
hHash,
pKeyProvInfo->dwKeySpec,
NULL,
0,
NULL,
&dwSignLen))
{
CryptDestroyHash(hHash);
free(pKeyProvInfo);
CryptReleaseContext(hProv,0);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
if(!CryptSignHash(
hHash,
pKeyProvInfo->dwKeySpec,
NULL,
0,
Sign,
&dwSignLen))
{
CryptDestroyHash(hHash);
free(pKeyProvInfo);
CryptReleaseContext(hProv,0);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
return strResult.AllocSysString();
}
CryptDestroyHash(hHash);
free(pKeyProvInfo);
CryptReleaseContext(hProv,0);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
char * strSign=NULL;
DWORD dwStrSignLen=0;
CryptBinaryToString(Sign,dwSignLen,CRYPT_STRING_BASE64,strSign,&dwStrSignLen);
strSign= (char *)malloc(dwStrSignLen+1);
CryptBinaryToString(Sign,dwSignLen,CRYPT_STRING_BASE64,strSign,&dwStrSignLen);
strSign[dwStrSignLen]='/0';
strResult=strSign;
free(strSign);
return strResult.AllocSysString();
}
该控件的工程源码请参考附属光盘,目录“Code/第五篇-电子商务网站应用/PKIAppControl”。