CryptoAPI调用指南(二)

证书操作

在CryptoAPI里,一般使用CERT_CONTEXT类型,即证书上下文,对数字证书进行操作,定义如下。

typedef struct _CERT_CONTEXT {

DWORD dwCertEncodingType;

BYTE *pbCertEncoded;

DWORD cbCertEncoded;

PCERT_INFO pCertInfo;

HCERTSTORE hCertStore;

} CERT_CONTEXT, *PCERT_CONTEXT

在这其中dwCertEncodingType是证书编码类型,常用值为X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;pbCertEncoded为证书数据;cbCertEncoded是数据长度字节数;pCertInfo是证书的各项属性信息,CERT_INFO的结构就不再贴了,大家可以自行查阅介绍,很容易懂;hCertStore是证书所在的证书库。

获得证书上下文的方法很多,下面介绍两种:

  • 从证书库里获得
  1. HCERTSTORE CertOpenStore(

LPCSTR lpszStoreProvider,

DWORD dwEncodingType,

HCRYPTPROV_LEGACY hCryptProv,

DWORD dwFlags,

const void *pvPara

)

通过CertOpenStore方法打开一个证书库。lpszStoreProvider是证书库类型,最常用的几种设置值说明如下表:
CryptoAPI调用指南(二)
dwEncodingType没有实际用处,设置为0;hCryptProv指向一个CSP句柄,推荐传NULL,即使用默认CSP即可;dwFlags的低2字节部分定义了打开证书库的行为特性,如下表:
CryptoAPI调用指南(二)
如果lpszStoreProvider是CERT_STORE_PROV_SYSTEM、CERT_STORE_PROV_SYSTEM_REGISTER或CERT_STORE_PROV_PHYSICAL,dwFlags的高2字节部分用于标识证书库所在位置。比如:

当前用户:CERT_SYSTEM_STORE_CURRENT_USER

本地计算机:CERT_SYSTEM_STORE_LOCAL_MACHINE

dwFlags的其他设置可以参考CryptoAPI手册。

CertOpenStore如果调用成功,则返回打开的证书库的句柄,否则返回NULL。

pvPara指向的数据和lpszStoreProvider有关,具体说明情况下表:
CryptoAPI调用指南(二)

  1. PCCERT_CONTEXT CertEnumCertificatesInStore(

HCERTSTORE hCertStore,

PCCERT_CONTEXT pPrevCertContext

)

调用此方法将返回证书库里的证书上下文。hCertStore是证书库句柄,由CertOpenStore返回;pPrevCertContext是前一个证书的证书上下文对象,如果传NULL,表示返回第一个证书上下文对象,否则返回排在pPrevCertContext下一个位置的证书的上下文对象;如果没有证书可以返回,此方法返回NULL。

通过循环调用CertEnumCertificatesInStore,即可实现对指定证书库的遍历。我们可以根据指定的条件,得遍历的结果进行查找过滤,得到需要的证书上下文或集合。

当返回的上下文对象不再使用时,应当调用CertFreeCertificateContext方法释放。

BOOL CertFreeCertificateContext(

PCCERT_CONTEXT pCertContext

)

pCertContext是要释放的上下文对象。

  • 根据证书数据直接生成
    有时我们已经从其他途径拿到了证书数据,此时就可以通过证书数据直接生成上下文对象。这种情况下,调用CertCreateCertificateContext方法即可。

PCCERT_CONTEXT CertCreateCertificateContext(

DWORD dwCertEncodingType,

const BYTE *pbCertEncoded,

DWORD cbCertEncoded

)

dwCertEncodingType为编码类型,老规矩,一般设置成X509_ASN_ENCODING | PKCS_7_ASN_ENCODING即可;pbCertEncoded是证书数据;cbCertEncoded是证书数据长度。**注意,如果我们拿到的证书数据是BASE64格式的,那需要先将数据转换成二进制字节数组。**方法调用成功会返回证书上下文对象,失败返回NULL,调用GetLastError返回具体错误信息。

同样,上述方法返回的证书上下文对象使用完毕后,需要调用CertFreeCertificateContext方法释放。