• CSP:使用CryptoAPI解码X509证书内容


            微软的CryptoAPI提供了一套解码X509证书的函数,一个X509证书解码之后,得到一个PCCERT_CONTEXT类型的结构体指针。

    通过该结构体,我们就能够获取想要的证书项和属性等。

            X509证书文件,依据封装的不同,主要有下面三种类型:

    *.cer:单个X509证书文件,不私钥。能够是二进制和Base64格式。该类型的证书最常见;

    *.p7b:PKCS#7格式的证书链文件,包括一个或多个X509证书,不含私钥。通常从CA中心申请RSA证书时,返回的签名证书就是p7b格式的证书文件。

    *.pfx:PKCS#12格式的证书文件,能够包括一个或者多个X509证书,含有私钥。一般有password保护。

    通常从CA中心申请RSA证书时,加密证书和RSA加密私钥就是一个pfx格式的文件返回。

            以下。针对这三种类型的证书文件。使用CryptoAPI进行解码,得到相应的PCCERT_CONTEXT结构体指针。须要注意的是,演示样例代码中的证书文件内容都是指二进制数据,假设证书文件本身使用的Base64格式。从文件读取之后,须要将Base64格式的内容转化为二进制数据,才干使用以下的解码函数。

    一、解码CER证书文件

    CER格式的文件最简单,仅仅须要调用API CertCreateCertificateContext()就可以。演示样例代码例如以下(lpCertData为二进制数据):

    ULONG CCSPCertificate::_DecodeX509Cert(LPBYTE lpCertData, ULONG ulDataLen)
    {	
    	if (!lpCertData || ulDataLen == 0)
    	{
    		return CERT_ERR_INVALIDPARAM;
    	}
    		
    	m_pCertContext = CertCreateCertificateContext(GLOBAL_ENCODING_TYPE, lpCertData, ulDataLen);
    	if (!m_pCertContext)
    	{
    		return GetLastError();
    	}
    			
    	return CERT_ERR_OK;
    }

    二、解码P7B证书文件

    因为P7B是个证书链文件,理论上能够包括多个X509证书。可是实际应用中。往往仅仅包括一个文件,所以我们仅仅处理第一个证书。演示样例代码例如以下:

    ULONG CCSPCertificate::_DecodeP7bCert(LPBYTE lpCertData, ULONG ulDataLen)
    {
    	ULONG ulRes = CERT_ERR_OK;
    	ULONG ulFlag = CRYPT_FIRST;
    	ULONG ulContainerNameLen = 512;
    	CHAR csContainerName[512] = {0};
    	BOOL bFoundContainer = FALSE;
    	
    	if (!lpCertData || ulDataLen == 0)
    	{
    		return CERT_ERR_INVALIDPARAM;
    	}
    	
    	// 由证书链创建一个证书库
    	HCERTSTORE hCertStore = NULL;
    	CRYPT_DATA_BLOB dataBlob = {ulDataLen, lpCertData};
    	hCertStore = CertOpenStore(CERT_STORE_PROV_PKCS7, GLOBAL_ENCODING_TYPE, NULL, 0, &dataBlob);
    	if (NULL == hCertStore)
    	{
    		ulRes = GetLastError();
    		return ulRes;
    	}
    	
    	// 释放之前的证书内容
    	if (m_pCertContext)
    	{
    		CertFreeCertificateContext(m_pCertContext);
    		m_pCertContext = NULL;
    	}
    
    	// 得到第一个证书内容
    	m_pCertContext = CertEnumCertificatesInStore(hCertStore, m_pCertContext);
    	if (NULL == m_pCertContext)
    	{
    		ulRes = GetLastError();
    		goto CLOSE_STORE;
    	}			
    	
    	// 关闭证书库
    CLOSE_STORE:
    	if (hCertStore)
    	{
    		CertCloseStore(hCertStore, 0);
    		hCertStore = NULL;
    	}
    
    	return ulRes;
    }
    如在特殊的情况下。须要处理整个证书链中的全部证书,则仅仅须要循环调用CertEnumCertificatesInStore()知道返回为NULL为止。

    三、解码PFX证书文件

    解码PFX证书时,和处理P7B非常相似。仅仅是多了password检验。演示样例代码例如以下:

    ULONG CCSPCertificate::_DecodePfxCert(LPBYTE lpCertData, ULONG ulDataLen, LPSTR lpscPassword)
    {
    	ULONG ulRes = 0;
    	HCERTSTORE hCertStore = NULL;
    	PCCERT_CONTEXT  pCertContext = NULL;  
    	
    	USES_CONVERSION;
    
    	if (!lpCertData || ulDataLen == 0)
    	{
    		return CERT_ERR_INVALIDPARAM;
    	}
    		
    	// 创建证书库
    	CRYPT_DATA_BLOB dataBlob = {ulDataLen, lpCertData};
    	hCertStore = PFXImportCertStore(&dataBlob, lpscPassword ? A2W(lpscPassword) : NULL, CRYPT_EXPORTABLE);
    	if (NULL == hCertStore)
    	{
    		hCertStore = PFXImportCertStore(&dataBlob, L"", CRYPT_EXPORTABLE);
    	}
    	if (NULL == hCertStore)
    	{
    		ulRes = GetLastError();
    		return ulRes;
    	}
    		
    	// 枚举证书,仅仅处理第一个证书
    	while(pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext))
    	{		
    		if (pCertContext->pbCertEncoded && pCertContext->cbCertEncoded > 0)
    		{
    			m_pCertContext = CertDuplicateCertificateContext(pCertContext);
    			break;
    		}
    	}
    	
    	// 关闭证书库
    	CertCloseStore(hCertStore, 0);
    	hCertStore = NULL;
    
    	return ulRes;
    }

    至此,三种常见证书文件的解码以完毕。通过解码得到的证书上下文结构体指针m_pCertContext 就能够解析证书的项和扩展属性了。详细的解析方法。将在兴许的Blog中逐一介绍。

    相关博文:CSP:使用CryptoAPI解析X509证书基本项

  • 相关阅读:
    Django_05_模板
    Django_04_视图
    Django_03_后台管理
    Django_02_创建模型
    Django_01_创建图书管理项目
    Djang简介
    day_03比特币转账的运行原理
    day_02比特币的转账机制及其7个名词
    day01_人类社会货币的演变
    Socket问题
  • 原文地址:https://www.cnblogs.com/llguanli/p/6865868.html
Copyright © 2020-2023  润新知