记录成功通过CSP接口获取Ukey的X509数字证书过程

这篇具有很好参考价值的文章主要介绍了记录成功通过CSP接口获取Ukey的X509数字证书过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

通过CSP接口获取X509数字证书

所谓CPS接口其实就是windowAPI ,其实就是wincrypt.h提供的接口,Visual Studio 直接包含以下内容即可

#include<wincrypt.h>
#pragma comment(lib,"Crypt32")

首先确定调用流程

开始通过百度总结调用流程如下:

调用流程
/*
1.CryptAcquireContext
2.CryptGetUserKey
3.CryptGetKeyParam
4.CertCreateCertificateContext
5.CryptDestroyKey
6.CryptReleaseContext
*/

悲催过程

  • 撸撸撸,把6个过程实现完,开始测试,走到第二步CryptGetUserKey就返回失败了,通过LastError提示找不到对象。把AT_SIGNATURE : AT_KEYEXCHANGE两个类型都试了不行。看到由的文章说如果找不到那就调用CryptGenKey,去生成一个key。成功返回key了,下一个CryptGetKeyParam时候找不到了。
  • 在试了几次,尼玛,直接把我Ukey里面的证书损坏了…

问题解决

首先ukey里面是存在多个容器的,一般证书都不会在这个默认容器里面,所以CryptGetUserKey就失败了。解决办法:首先进行枚举容器,把ukey里面的容器都枚举出来。在根据容器名称循环调用上面6个流程,最终把x509证书读出来了。

//枚举容器过程
	if (CryptAcquireContext(
	   &hCryptProv, // Handle to the CSP
		NULL, // Container name
		mProviderName, // Use the default provider
		PROV_RSA_FULL, // Provider type
		CRYPT_NEWKEYSET)) // Flag values
	{

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

	}

}

补充

  1. cps ukey的providerName 一般为:eSafe Cryptographic Service Provider v1.0
  2. 可以通过注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider 查看具体的Provider.
  3. CertCreateCertificateContext 出参BYTE * pbCert就是x509证书的二进制,可以直接通过其他x509证书解析库解析。也可以通过CertGetNameString解析证书相关信息。
pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbCert, dwCertLen);

调用过程代码

BOOL CryptHelper::GetPublicKey(LPCSTR containName, BYTE** certInfo, DWORD& certLength, LPTSTR& message)
{
	//1.获得一个CSP句柄
	HCRYPTPROV hCryptProv;
	printf("csp name:%s;contain name:%s.\n", mProviderName, containName);
	BOOL res = CryptAcquireContext(&hCryptProv, containName, mProviderName, PROV_RSA_FULL, 0);
	if (!res) //如果没有可用CSP
	{
		GetErrorToString(TEXT("CryptAcquireContext"), message);
		printf(message);
		return FALSE;
	}
	//2.获取签名秘钥
	HCRYPTKEY hKey;
	res = CryptGetUserKey(hCryptProv, mAlgId, &hKey);
	if (!res)    //没有可用的签名秘钥
	{
		GetErrorToString(TEXT("CryptGetUserKey"), message);
		printf(message);
		return FALSE;
	}
	//3.获取证书参数
	DWORD dwCertLen = 2048;
	BYTE* pbCert = (BYTE*)malloc(dwCertLen);
	res = CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCert, &dwCertLen, 0);
	if (!res)
	{
		GetErrorToString(TEXT("CryptGetKeyParam"), message);
		printf(message);
		return FALSE;
	}
	//4.导出证书
	if (pbCert)
	{
		PCCERT_CONTEXT pCertContext = NULL;
		pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, pbCert, dwCertLen);
		if (pCertContext)
		{
			message = "success";
			certLength = dwCertLen;
			*certInfo = (BYTE*)malloc(certLength);
			memcpy(*certInfo, pbCert, certLength);
			CHAR pszBuff[256];
			CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE,
				0, NULL, pszBuff, 128);
			printf("%s\n", pszBuff); // 显示名
			//7.释放证书
			CertFreeCertificateContext(pCertContext);
		}
		else
		{
			GetErrorToString(TEXT("CertCreateCertificateContext"), message);
			printf(message);
			return FALSE;
		}
	}
	//6.释放key;
	if (hKey)
	{
		CryptDestroyKey(hKey);
		printf("The hKey could  be released.\n");
	}
	//7.释放容器
	if (hCryptProv)
	{
		CryptReleaseContext(hCryptProv, 0);
		printf("The hCryptProv could  be released.\n");
	}
	return TRUE;
}

LastError()解析

lastError()方法放回的是错误码,具体什么错误并不知道。具体通过FormatMessage解析文章来源地址https://www.toymoban.com/news/detail-450002.html

BOOL CryptHelper::GetErrorToString(LPTSTR funcName, LPTSTR& Message)
{
	DWORD lastError = GetLastError();
	LPVOID lpMsgBuf;
	LPVOID lpDisplayBuf;
	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		lastError,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR)& lpMsgBuf,
		0, NULL);
	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)funcName) + 40) * sizeof(TCHAR));
	StringCchPrintf((LPTSTR)lpDisplayBuf,LocalSize(lpDisplayBuf),TEXT("%s failure with error %d: %s"),funcName, lastError, lpMsgBuf);
	Message = (LPTSTR)lpDisplayBuf;
	LocalFree(lpMsgBuf);
	LocalFree(lpDisplayBuf);
	return TRUE;
}

到了这里,关于记录成功通过CSP接口获取Ukey的X509数字证书过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包