目前,USBKey已广泛应用在网上银行,网上办公,证券交易,网络游戏等众多系统中。那么USBKey又怎么与应用系统连接而进行身份认证的呢?实际上,USBKey中存储着代表用户身份的数字证书。
一张数字证书包括:证书信息+公钥+私钥,其中证书+公钥是可以公开的,私钥是在USBKey中,任何人都无法获取的。当USBKey插入计算机后,USBKey厂商提供的中间件程序会将证书信息注册到Windows系统中,应用系统中在认证时通过Windows系统找到用户证书,该证书通过USBKey厂商的中间件找到USBKey中对应的私钥,然后在USBKey中使用私钥进行签名运算,将结果传给服务器认证。过程如下:
网银àWindows系统中用户证书àUSBKey中间件à私钥签名à服务器验证
本篇文章就介绍一下如何使用微软CAPI接口完成将USBKey中的证书注册到Windows系统中。
(1) 获取CSP句柄。
- CryptAcquireContext(
- &hTokenProv,NULL,
- “EnterSafe ET199Auto CSP V1.0”,
- PROV_RSA_FULL,
- NULL)
CryptAcquireContext(
&hTokenProv,NULL,
“EnterSafe ET199Auto CSP V1.0”,
PROV_RSA_FULL,
NULL)
(2) 获取USBKey内密钥句柄,这时要注意锁内密钥的类型是签名密钥(AT_SIGNATURE)或者交换密钥(AT_KEYEXCHANGE)。
- CryptGetUserKey(hTokenProv,AT_KEYEXCHANGE,&hKeyCAPI)
CryptGetUserKey(hTokenProv,AT_KEYEXCHANGE,&hKeyCAPI)
(3) 获取证书数据(只是证书信息数据,不包括私钥),这时可以通过两次调用,先获取证书数据的长度,分配空间,然后再调用一次。
- CryptGetKeyParam(hKeyCAPI, KP_CERTIFICATE, pbCert, &dwCertLen, 0)
CryptGetKeyParam(hKeyCAPI, KP_CERTIFICATE, pbCert, &dwCertLen, 0)
(4) 创建CERT_CONTEXT结构
- pCertContext = CertCreateCertificateContext(
- PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
- pbCert,
- dwCertLen)
pCertContext = CertCreateCertificateContext(
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
pbCert,
dwCertLen)
- //+-------------------------------------------------------------------------
- // Certificate context.
- //
- // A certificate context contains both the encoded and decoded representation
- // of a certificate. A certificate context returned by a cert store function
- // must be freed by calling the CertFreeCertificateContext function. The
- // CertDuplicateCertificateContext function can be called to make a duplicate
- // copy (which also must be freed by calling CertFreeCertificateContext).
- //--------------------------------------------------------------------------
- // certenrolls_begin -- CERT_CONTEXT
- typedef struct _CERT_CONTEXT {
- DWORD dwCertEncodingType;
- BYTE *pbCertEncoded;
- DWORD cbCertEncoded;
- PCERT_INFO pCertInfo;
- HCERTSTORE hCertStore;
- } CERT_CONTEXT, *PCERT_CONTEXT;
- typedef const CERT_CONTEXT *PCCERT_CONTEXT;
//+-------------------------------------------------------------------------
// Certificate context.
//
// A certificate context contains both the encoded and decoded representation
// of a certificate. A certificate context returned by a cert store function
// must be freed by calling the CertFreeCertificateContext function. The
// CertDuplicateCertificateContext function can be called to make a duplicate
// copy (which also must be freed by calling CertFreeCertificateContext).
//--------------------------------------------------------------------------
// certenrolls_begin -- CERT_CONTEXT
typedef struct _CERT_CONTEXT {
DWORD dwCertEncodingType;
BYTE *pbCertEncoded;
DWORD cbCertEncoded;
PCERT_INFO pCertInfo;
HCERTSTORE hCertStore;
} CERT_CONTEXT, *PCERT_CONTEXT;
typedef const CERT_CONTEXT *PCCERT_CONTEXT;
(5) 打开MY存储区,这个就是Windows系统中“个人”证书存放的区域。
- hSysStore = CertOpenStore(
- CERT_STORE_PROV_SYSTEM_REGISTRY,
- 0,
- 0,
- CERT_SYSTEM_STORE_CURRENT_USER,
- L"MY");
hSysStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_REGISTRY,
0,
0,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");
(6) 设置证书上下文属性。这时要先声明CRYPT_KEY_PROV_INFO结构
- CRYPT_KEY_PROV_INFO ckpi = {0};
- ckpi.pwszProvName = L" EnterSafe ET199Auto CSP V1.0";
- ckpi.pwszContainerName = pbWideContainer;
- ckpi.dwProvType = PROV_RSA_FULL;
- ckpi.dwKeySpec = AT_KEYEXCHANGE;
- ckpi.dwFlags = CERT_KEY_CONTEXT_PROP_ID;
- ckpi.cProvParam = 0;
- ckpi.rgProvParam = NULL;
- CertSetCertificateContextProperty(
- pCertContext,
- CERT_KEY_PROV_INFO_PROP_ID, CERT_STORE_NO_CRYPT_RELEASE_FLAG,
- &ckpi)
CRYPT_KEY_PROV_INFO ckpi = {0};
ckpi.pwszProvName = L" EnterSafe ET199Auto CSP V1.0";
ckpi.pwszContainerName = pbWideContainer;
ckpi.dwProvType = PROV_RSA_FULL;
ckpi.dwKeySpec = AT_KEYEXCHANGE;
ckpi.dwFlags = CERT_KEY_CONTEXT_PROP_ID;
ckpi.cProvParam = 0;
ckpi.rgProvParam = NULL;
CertSetCertificateContextProperty(
pCertContext,
CERT_KEY_PROV_INFO_PROP_ID, CERT_STORE_NO_CRYPT_RELEASE_FLAG,
&ckpi)
(7) 将证书注册到Windows系统中。
- CertAddCertificateContextToStore(
- hSysStore,
- pCertContext,
- CERT_STORE_ADD_REPLACE_EXISTING,
- NULL);
CertAddCertificateContextToStore(
hSysStore,
pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL);
(8) 释放CSP句柄。
- CryptReleaseContext(hTokenProv,0)
CryptReleaseContext(hTokenProv,0)
通过上述步骤就可以将ET199Auto中的证书注册到Windows系统中了。我们可以在IEInternet选项内容证书个人下面查看到ET199Auto中的证书。
以上系转载,感谢原作者。
========================================================================
今天写了一个关于证书安装的程序,现在把主要代码分享出来!
注:
- #include "stdafx.h"
- #include "CertImportx.h"
- #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
- void CCertImport::PrintfError(DWORD err , LPCTSTR szError)
- {
- if( err == 0 )
- {
- MessageBox(NULL,_T("安装成功!"),_T("证书安装"),MB_OK);
- }
- else
- {//
- MessageBox(NULL,_T("安装失败!"),_T("证书安装"),MB_OK);
- }
- }
- // Global function for free handles...
- void CCertImport::FreeHandles(HCERTSTORE hFileStore, PCCERT_CONTEXT pctx, HCERTSTORE pfxStore, HCERTSTORE myStore )
- {
- if (myStore)
- CertCloseStore(myStore, 0);
- if (pfxStore)
- CertCloseStore(pfxStore, CERT_CLOSE_STORE_FORCE_FLAG);
- if(pctx)
- CertFreeCertificateContext(pctx);
- if (hFileStore)
- CertCloseStore(hFileStore, 0);
- }
- int CCertImport::ImportCACert()
- {
- const char* pCert= "-----BEGIN CERTIFICATE-----\
- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML\
- RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp\
- bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5\
- IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp\
- ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy\
- MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3\
- LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp\
- YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG\
- A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp\
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq\
- K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe\
- sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX\
- MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT\
- XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/\
- HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\
- 4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA\
- vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G\
- CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA\
- WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo\
- oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ\
- h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18\
- f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN\
- B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy\
- vUxFnmG6v4SBkgPR0ml8xQ==\
- -----END CERTIFICATE-----";
- BYTE pBinByte[8192]={0};
- unsigned long binBytes = 4096;
- CryptStringToBinaryA( pCert , strlen(pCert) ,CRYPT_STRING_BASE64HEADER , pBinByte , &binBytes ,NULL,NULL);
- return ImportCACert(pBinByte , binBytes );
- }
- // This function imports a CA certificate...
- int CCertImport::ImportCACert(LPCTSTR szFileName)
- {
- HANDLE hfile = INVALID_HANDLE_VALUE;
- BYTE pByte[4096] = {0} , pBinByte[8192]={0};
- unsigned long bytesRead = 0;
- unsigned long binBytes = 4096;
- // Open it...
- hfile = CreateFile(szFileName, FILE_READ_DATA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
- if (INVALID_HANDLE_VALUE == hfile)
- return -1;
- ReadFile( hfile , pByte, 4096, &bytesRead ,NULL );
- CloseHandle(hfile);
- CryptStringToBinaryA( (LPCSTR)pByte , bytesRead ,CRYPT_STRING_BASE64HEADER , pBinByte , &binBytes ,NULL,NULL);
- return ImportCACert(pBinByte , binBytes );
- }
- int CCertImport::ImportCACert(BYTE* pBinByte , unsigned long binBytes)
- {
- HCERTSTORE pfxStore = 0;
- HCERTSTORE myStore = 0;
- HCERTSTORE hFileStore = 0;
- PCCERT_CONTEXT pctx = NULL;
- DWORD err = 0;
- pctx = CertCreateCertificateContext(MY_ENCODING_TYPE, (BYTE*)pBinByte , binBytes );
- if(pctx == NULL)
- {
- DWORD err = GetLastError();
- FreeHandles(hFileStore,pctx, pfxStore, myStore);
- PrintfError( err , _T("Error in 'CertCreateCertificateContext'") );
- return err;
- }
- // we open the store for the CA
- hFileStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root" );
- if (!hFileStore)
- {
- DWORD err = GetLastError();
- FreeHandles(hFileStore,pctx, pfxStore, myStore);
- PrintfError( err , _T("Error in 'CertOpenStore'") );
- return err;
- }
- if( !CertAddCertificateContextToStore(hFileStore, pctx, CERT_STORE_ADD_NEW, 0) )
- {
- err = GetLastError();
- if( CRYPT_E_EXISTS == err )
- {
- // if( AfxMessageBox("An equivalent previous personal certificate already exists. Overwrite ? (Yes/No)", MB_YESNO) == IDYES)
- {
- if( !CertAddCertificateContextToStore(hFileStore, pctx , CERT_STORE_ADD_REPLACE_EXISTING, 0))
- {
- err = GetLastError();
- FreeHandles(hFileStore,pctx, pfxStore, myStore);
- PrintfError( err , _T("Error in 'CertAddCertificateContextToStore'") );
- return err;
- }
- }
- }
- else
- {
- FreeHandles(hFileStore, pctx , pfxStore , myStore);
- PrintfError( err , _T("Error in 'CertAddCertificateContextToStore'") );
- return err;
- }
- }
- FreeHandles(hFileStore,pctx, pfxStore, myStore);
- PrintfError(0 , NULL) ;
- return 0;
- }