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

from  http://blog.youkuaiyun.com/yyfzy/article/details/46681679

     微软的CryptoAPI提供了一套解码X509证书的函数,一个X509证书解码之后,得到一个PCCERT_CONTEXT类型的结构体指针。通过该结构体,我们就可以获取想要的证书项和属性等。

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

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

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

*.pfx:PKCS#12格式的证书文件,可以包含一个或者多个X509证书,含有私钥,一般有密码保护。通常从CA中心申请RSA证书时,加密证书和RSA加密私钥就是一个pfx格式的文件返回。

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

一、解码CER证书文件

CER格式的文件最简单,只需要调用API CertCreateCertificateContext()即可。示例代码如下(lpCertData为二进制数据):

[cpp]  view plain  copy
  1. ULONG CCSPCertificate::_DecodeX509Cert(LPBYTE lpCertData, ULONG ulDataLen)  
  2. {     
  3.     if (!lpCertData || ulDataLen == 0)  
  4.     {  
  5.         return CERT_ERR_INVALIDPARAM;  
  6.     }  
  7.           
  8.     m_pCertContext = CertCreateCertificateContext(GLOBAL_ENCODING_TYPE, lpCertData, ulDataLen);  
  9.     if (!m_pCertContext)  
  10.     {  
  11.         return GetLastError();  
  12.     }  
  13.               
  14.     return CERT_ERR_OK;  
  15. }  

二、解码P7B证书文件

由于P7B是个证书链文件,理论上可以包含多个X509证书。但是实际应用中,往往只包含一个文件,所以我们只处理第一个证书。示例代码如下:

[cpp]  view plain  copy
  1. ULONG CCSPCertificate::_DecodeP7bCert(LPBYTE lpCertData, ULONG ulDataLen)  
  2. {  
  3.     ULONG ulRes = CERT_ERR_OK;  
  4.     ULONG ulFlag = CRYPT_FIRST;  
  5.     ULONG ulContainerNameLen = 512;  
  6.     CHAR csContainerName[512] = {0};  
  7.     BOOL bFoundContainer = FALSE;  
  8.       
  9.     if (!lpCertData || ulDataLen == 0)  
  10.     {  
  11.         return CERT_ERR_INVALIDPARAM;  
  12.     }  
  13.       
  14.     // 由证书链创建一个证书库  
  15.     HCERTSTORE hCertStore = NULL;  
  16.     CRYPT_DATA_BLOB dataBlob = {ulDataLen, lpCertData};  
  17.     hCertStore = CertOpenStore(CERT_STORE_PROV_PKCS7, GLOBAL_ENCODING_TYPE, NULL, 0, &dataBlob);  
  18.     if (NULL == hCertStore)  
  19.     {  
  20.         ulRes = GetLastError();  
  21.         return ulRes;  
  22.     }  
  23.       
  24.     // 释放之前的证书内容  
  25.     if (m_pCertContext)  
  26.     {  
  27.         CertFreeCertificateContext(m_pCertContext);  
  28.         m_pCertContext = NULL;  
  29.     }  
  30.   
  31.     // 得到第一个证书内容  
  32.     m_pCertContext = CertEnumCertificatesInStore(hCertStore, m_pCertContext);  
  33.     if (NULL == m_pCertContext)  
  34.     {  
  35.         ulRes = GetLastError();  
  36.         goto CLOSE_STORE;  
  37.     }             
  38.       
  39.     // 关闭证书库  
  40. CLOSE_STORE:  
  41.     if (hCertStore)  
  42.     {  
  43.         CertCloseStore(hCertStore, 0);  
  44.         hCertStore = NULL;  
  45.     }  
  46.   
  47.     return ulRes;  
  48. }  
如在特殊的情况下,需要处理整个证书链中的所有证书,则只需要循环调用CertEnumCertificatesInStore()知道返回为NULL为止。

三、解码PFX证书文件

解码PFX证书时,和处理P7B很相似,只是多了密码检验。示例代码如下:

[cpp]  view plain  copy
  1. ULONG CCSPCertificate::_DecodePfxCert(LPBYTE lpCertData, ULONG ulDataLen, LPSTR lpscPassword)  
  2. {  
  3.     ULONG ulRes = 0;  
  4.     HCERTSTORE hCertStore = NULL;  
  5.     PCCERT_CONTEXT  pCertContext = NULL;    
  6.       
  7.     USES_CONVERSION;  
  8.   
  9.     if (!lpCertData || ulDataLen == 0)  
  10.     {  
  11.         return CERT_ERR_INVALIDPARAM;  
  12.     }  
  13.           
  14.     // 创建证书库  
  15.     CRYPT_DATA_BLOB dataBlob = {ulDataLen, lpCertData};  
  16.     hCertStore = PFXImportCertStore(&dataBlob, lpscPassword ? A2W(lpscPassword) : NULL, CRYPT_EXPORTABLE);  
  17.     if (NULL == hCertStore)  
  18.     {  
  19.         hCertStore = PFXImportCertStore(&dataBlob, L"", CRYPT_EXPORTABLE);  
  20.     }  
  21.     if (NULL == hCertStore)  
  22.     {  
  23.         ulRes = GetLastError();  
  24.         return ulRes;  
  25.     }  
  26.           
  27.     // 枚举证书,只处理第一个证书  
  28.     while(pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext))  
  29.     {         
  30.         if (pCertContext->pbCertEncoded && pCertContext->cbCertEncoded > 0)  
  31.         {  
  32.             m_pCertContext = CertDuplicateCertificateContext(pCertContext);  
  33.             break;  
  34.         }  
  35.     }  
  36.       
  37.     // 关闭证书库  
  38.     CertCloseStore(hCertStore, 0);  
  39.     hCertStore = NULL;  
  40.   
  41.     return ulRes;  
  42. }  

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

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值