IT点滴

我不去想是否能够成功 既然选择了远方 便只顾风雨兼程
  博客园  :: 首页  :: 联系 :: 订阅 订阅  :: 管理

[转]通过CSP读取证书

Posted on 2012-01-12 16:30  Ady Lee  阅读(1617)  评论(0编辑  收藏  举报

1. 通过Csp读取证书使用的函数

CryptGetUserKey

获取公私钥对的句柄

注意AT_SIGNATURE,AT_KEYEXCHANGE的不同,前者签名,后者加密。

CryptGetKeyParam

读取和公私钥对相关联的证书

注意使用KP_CERTIFICATE

2. 指定Csp容器

通常获取证书时,usbkey已经发证完毕。这是比较难以判断容器的名称。通常会选择默认容器,但有些RA发证时比较特别,可能会使用两个容器。签名证书使用默认容器,而加密证书使用指定的某个容器。

为了验证上面所说的情况,需要枚举Usbkey上的容器进行选择查看。

CryptGetProvParam

注意: 第二个参数使用PP_ENUMCONTAINERS

获取第一个容器名称的时候,最后的参数使用CRYPT_FIRST

接下去,调用时使用最后的参数CRYPT_NEXT,当GetLastError的值等于ERROR_NO_MORE_ITEMS则表示没有容器了。

指定好了容器名称后再进行证书的读取工作,下面列出了程序运行结果:

签名证书容器

A crypto context with the MyKeyContainer key container

has been acquired.

0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364

1. ContainName is KOAL_CSP_WRAPPER_CONTAINER

2. ContainName is J

The handle has been released.

Please select a container:

0

A crypto context with the 3d06503f-e4ed-4e89-8d56-2960aa5f0364 key container

has been acquired.

Encrypt Certification:

Invalid parameter

CryptGetKeyParam Failed 0x57

Sign Certification:

CertLen is 791

A new certificate as been created.

测试 310103198301011234

SANCA

The handle has been released.

加密证书容器

A crypto context with the MyKeyContainer key container

has been acquired.

0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364

1. ContainName is KOAL_CSP_WRAPPER_CONTAINER

2. ContainName is J

The handle has been released.

Please select a container:

1

A crypto context with the KOAL_CSP_WRAPPER_CONTAINER key container

has been acquired.

Encrypt Certification:

CertLen is 759

A new certificate as been created.

测试 310103198301011234

SANCA

Sign Certification:

Invalid parameter

CryptGetKeyParam Failed 0x57

The handle has been released.

3. 相关代码

// getPubKey.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
#include <WinCrypt.h>
#include <stdio.h>

#include <vector>
#include <string>

using namespace std;

vector<string> contain_vector;

//CRYPT_DELETEKEYSET

int TestEnumContainers(HCRYPTPROV hCryptProv)
{
BYTE pbData[1000]; // 1000 will hold the longest
DWORD cbData = 1000;
int count = 0;

if ( CryptGetProvParam(
hCryptProv,
PP_ENUMCONTAINERS,
(BYTE *)&pbData,
&cbData,
CRYPT_FIRST))
{
pbData[cbData] = '\0';
printf("%d. ContainName is %s\n", count++, pbData);
contain_vector.push_back((char *)pbData);

pbData[0] = '\0';
cbData = 1000;

while( CryptGetProvParam(
hCryptProv,
PP_ENUMCONTAINERS,
(BYTE *)&pbData,
&cbData,
CRYPT_NEXT)
)
{
if( ERROR_NO_MORE_ITEMS == GetLastError())
{
break;
}

pbData[cbData] = '\0';
printf("%d. ContainName is %s\n", count++, pbData);
contain_vector.push_back((char *)pbData);
pbData[0] = '\0';
cbData = 1000;
}

}

return count;
}

int EnumContainers()
{
//--------------------------------------------------------------------
// Declare and initialize variables.
HCRYPTPROV hCryptProv = NULL; // Handle for a cryptographic

// provider context.
LPCSTR UserName = "MyKeyContainer"; // Name of the key container
LPCSTR ProviderName = "eSafe Cryptographic Service Provider v2.0";

int count = -1;

// to be used.
//--------------------------------------------------------------------
// Attempt to acquire a context and a key
// container. The context will use the default CSP
// for the RSA_FULL provider type. DwFlags is set to 0
// to attempt to open an existing key container.

if(CryptAcquireContext(
&hCryptProv, // Handle to the CSP
NULL, // Container name
ProviderName, // Use the default provider
PROV_RSA_FULL, // Provider type
0)) // Flag values
{
printf("A crypto context with the %s key container \n", UserName);
printf("has been acquired.\n\n");

count = TestEnumContainers(hCryptProv);

}
else
{
//--------------------------------------------------------------------
// An error occurred in acquiring the context. This could mean
// that the key container requested does not exist. In this case,
// the function can be called again to attempt to create a new key
// container. Error codes are defined in winerror.h.
if (GetLastError() == NTE_BAD_KEYSET)
{
if(CryptAcquireContext(
&hCryptProv,
NULL,
ProviderName,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
printf("A new key container has been created.\n");
count = TestEnumContainers(hCryptProv);
}
else
{
printf("Could not create a new key container.\n");
exit(1);
}
}
else
{
printf("A cryptographic service handle could not be acquired.\n");
exit(1);
}

} // End of else

//--------------------------------------------------------------------
// A cryptographic context and a key container is available. Perform
// any functions that require a Cryptographic provider handle.

//--------------------------------------------------------------------
// When the handle is no longer needed, it must be released.

if (CryptReleaseContext(hCryptProv,0))
{
printf("The handle has been released.\n");
}
else
{
printf("The handle could not be released.\n");
}

return count;
}


void DecodePubKey(HCRYPTPROV hCryptProv, DWORD dwKeySpec)
{
HCRYPTKEY hCurKey= 0;
BOOL ret=TRUE;
//
// Check if a key already exisis,
// If it don't generate a key!
///////////////////////////////////////////
if (!CryptGetUserKey(hCryptProv, dwKeySpec, &hCurKey))
{
int error = GetLastError();
// Make sure error is no key.
if (error != NTE_NO_KEY)
{
printf("First Call to CryptGenKey Failed- with error other than NTE_NO_KEY: [0x%X]\n",error);
ret=FALSE;
goto done;
}
}

unsigned char uchCertInfo[2000];
DWORD CertLen = 2000;
DWORD error = 0;

if (!CryptGetKeyParam(hCurKey, KP_CERTIFICATE, uchCertInfo, &CertLen , 0))
{

//ERROR_MORE_DATA


error = GetLastError();

if( ERROR_INVALID_PARAMETER == error)
{
printf("Invalid parameter\n");
}

if (error != NTE_BAD_TYPE) {
// If error is bad_type then we just can't set the property.
// Likely means our provider isn't a smart card.
// If there was another error, we should report it.
printf("CryptGetKeyParam Failed 0x%x\n",error);
}
ret=FALSE;
goto done;
}

printf("CertLen is %d\n", CertLen );


// MAKING X509 CERTIFICATE

#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
PCCERT_CONTEXT pCertContext = NULL;

//------------------------------------------------------------------
// Create a new certificate from the encoded part of
// an available certificate. pDesiredCert is a previously
// assigned PCCERT_CONTEXT variable.
if(pCertContext = CertCreateCertificateContext(
MY_ENCODING_TYPE, // The encoding type
uchCertInfo, // The encoded data from
// the certificate retrieved
CertLen)) // The length of the encoded data
{
printf("A new certificate as been created.\n");

// Use the certificate context as needed.
// ...

CHAR pszBuff[256];
CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
0, NULL, pszBuff, 128);
printf("%s\n", pszBuff); // 显示名
CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG, NULL, pszBuff, 128);
printf("%s\n", pszBuff); // 颁发者

// When finished, free the certificate context.
CertFreeCertificateContext(pCertContext);
}
else
{
printf("A new certificate could not be created.\n");
goto done;
}

done:
if (hCurKey) CryptDestroyKey(hCurKey);
}

void GetPublicKey(const char *ContainName)
{
//--------------------------------------------------------------------
// Declare and initialize variables.
HCRYPTPROV hCryptProv = NULL; // Handle for a cryptographic

// provider context.
LPCSTR ProviderName = "eSafe Cryptographic Service Provider v2.0";


// to be used.
//--------------------------------------------------------------------
// Attempt to acquire a context and a key
// container. The context will use the default CSP
// for the RSA_FULL provider type. DwFlags is set to 0
// to attempt to open an existing key container.

if(CryptAcquireContext(
&hCryptProv, // Handle to the CSP
ContainName, // Container name
ProviderName, // Use the default provider
PROV_RSA_FULL, // Provider type
0)) // Flag values
{
printf("A crypto context with the %s key container \n", ContainName);
printf("has been acquired.\n\n");


printf("Encrypt Certification:\n");
DecodePubKey(hCryptProv, AT_KEYEXCHANGE);

printf("Sign Certification:\n");
DecodePubKey(hCryptProv, AT_SIGNATURE);


}
else
{
//--------------------------------------------------------------------
// An error occurred in acquiring the context. This could mean
// that the key container requested does not exist. In this case,
// the function can be called again to attempt to create a new key
// container. Error codes are defined in winerror.h.
if (GetLastError() == NTE_BAD_KEYSET)
{
if(CryptAcquireContext(
&hCryptProv,
ContainName,
ProviderName,
PROV_RSA_FULL,
CRYPT_NEWKEYSET))
{
printf("A new key container has been created.\n");
}
else
{
printf("Could not create a new key container.\n");
exit(1);
}
}
else
{
printf("A cryptographic service handle could not be acquired.\n");
exit(1);
}

} // End of else

//--------------------------------------------------------------------
// A cryptographic context and a key container is available. Perform
// any functions that require a Cryptographic provider handle.

//--------------------------------------------------------------------
// When the handle is no longer needed, it must be released.

if (CryptReleaseContext(hCryptProv,0))
{
printf("The handle has been released.\n");
}
else
{
printf("The handle could not be released.\n");
}
}

int main(int argc, CHAR* argv[])
{

int count = EnumContainers();
int selectno;


printf("Please select a container:\n");
scanf("%d", &selectno);
if( selectno <= count )
{
GetPublicKey(contain_vector[selectno].c_str());
}

// 0. ContainName is 3d06503f-e4ed-4e89-8d56-2960aa5f0364
// 签名证书

// 1. ContainName is KOAL_CSP_WRAPPER_CONTAINER
// 加密证书

return 0;
}