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;
}