您的位置:首页 > 编程语言 > C语言/C++

如何将USBKey中的证书注册到Windows系统中、分享一个 证书 C++安装

2015-05-27 14:31 615 查看
USBKey是一种USB接口的硬件设备。如坚石诚信的ET199Auto,内置16位国外进口高性能智能卡芯片,有一定的存储空间,可以存储用户的私钥以及数字证书,利用USBKey内置的RSA公私钥算法实现对用户身份的认证。由于用户私钥保存在ET199Auto中,同时智能卡可以很好的防止物理攻击/边频攻击等窃取手段,从而有效保证任何方式都无法读取ET199Auto中的私钥,因此保证了用户认证的安全性。

目前,USBKey已广泛应用在网上银行,网上办公,证券交易,网络游戏等众多系统中。那么USBKey又怎么与应用系统连接而进行身份认证的呢?实际上,USBKey中存储着代表用户身份的数字证书。

一张数字证书包括:证书信息+公钥+私钥,其中证书+公钥是可以公开的,私钥是在USBKey中,任何人都无法获取的。当USBKey插入计算机后,USBKey厂商提供的中间件程序会将证书信息注册到Windows系统中,应用系统中在认证时通过Windows系统找到用户证书,该证书通过USBKey厂商的中间件找到USBKey中对应的私钥,然后在USBKey中使用私钥进行签名运算,将结果传给服务器认证。过程如下:

网银àWindows系统中用户证书àUSBKey中间件à私钥签名à服务器验证

本篇文章就介绍一下如何使用微软CAPI接口完成将USBKey中的证书注册到Windows系统中。

(1) 获取CSP句柄。

[cpp]
view plaincopyprint?

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)。

[cpp]
view plaincopyprint?

CryptGetUserKey(hTokenProv,AT_KEYEXCHANGE,&hKeyCAPI)

CryptGetUserKey(hTokenProv,AT_KEYEXCHANGE,&hKeyCAPI)


(3) 获取证书数据(只是证书信息数据,不包括私钥),这时可以通过两次调用,先获取证书数据的长度,分配空间,然后再调用一次。

[cpp]
view plaincopyprint?

CryptGetKeyParam(hKeyCAPI, KP_CERTIFICATE, pbCert, &dwCertLen, 0)

CryptGetKeyParam(hKeyCAPI, KP_CERTIFICATE, pbCert, &dwCertLen, 0)


(4) 创建CERT_CONTEXT结构

[cpp]
view plaincopyprint?

pCertContext = CertCreateCertificateContext( PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pbCert, dwCertLen)

pCertContext = CertCreateCertificateContext(
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
pbCert,
dwCertLen)


[cpp]
view plaincopyprint?

//+-------------------------------------------------------------------------
// 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系统中“个人”证书存放的区域。

[cpp]
view plaincopyprint?

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结构

[cpp]
view plaincopyprint?

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系统中。

[cpp]
view plaincopyprint?

CertAddCertificateContextToStore( hSysStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL);

CertAddCertificateContextToStore(
hSysStore,
pCertContext,
CERT_STORE_ADD_REPLACE_EXISTING,
NULL);


(8) 释放CSP句柄。

[cpp]
view plaincopyprint?

CryptReleaseContext(hTokenProv,0)
CryptReleaseContext(hTokenProv,0)


通过上述步骤就可以将ET199Auto中的证书注册到Windows系统中了。我们可以在IEInternet选项内容证书个人下面查看到ET199Auto中的证书。

以上系转载,感谢原作者。

========================================================================

今天写了一个关于证书安装的程序,现在把主要代码分享出来!

注:

在读取到证书文件,如果是
BASE64 文件,就需要通过 CryptStringToBinaryA 转化成 二进制,然后再CertCreateCertificateContext,才能成功,不然会
出现 CRYPT_E_ASN1_BADTAG 错误!

[cpp]
view plaincopyprint?

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: