我正在尝试从 Windows 证书存储中检索一个随机证书,在本例中是一个通用的 Digicert 根证书(这仅用于测试)。我修改了一些我能找到的示例代码,但无法让它工作。
我怀疑我可能对搜索参数进行了编码错误。MSDN 文档在这里不是很有用,发行者是 SBCS 还是 unicode 字符串?我是否传递颁发者名称或字符串作为完全限定的颁发者(CN、OU、O、C 等)?我还做错了什么?
以下是我完全独立的测试应用程序,因此它不是“漂亮”,也没有太多错误处理:
#pragma comment(lib, "crypt32.lib")
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
void panic(const char* s);
int main(void)
{
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
HCERTSTORE hSystemStore;
PCCERT_CONTEXT pTargetCert = NULL;
if (!(hSystemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE, L"Root")))
panic("Error opening the Root store.");
CERT_NAME_BLOB issuer;
CRYPT_INTEGER_BLOB serial;
const char* issuer_str = "DigiCert Global Root CA";
const char* sn_string = "083be056904246b1a1756ac95991c74a";
serial.cbData = (DWORD)strlen(sn_string) / 2;
serial.pbData = new BYTE[serial.cbData];
const char* pos = sn_string;
for (size_t count = 0; count < serial.cbData; count++) {
sscanf_s(pos, "%2hhx", &serial.pbData[count]);
pos += 2;
}
issuer.cbData = (DWORD)strlen(issuer_str);
issuer.pbData = (BYTE *)issuer_str;
CERT_ISSUER_SERIAL_NUMBER findparams;
findparams.Issuer = issuer;
findparams.SerialNumber = serial;
CERT_ID id;
id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
id.IssuerSerialNumber = findparams;
if (!(pTargetCert = CertFindCertificateInStore(
hSystemStore, // Store handle.
MY_ENCODING_TYPE, // Encoding type.
0, // Not used.
CERT_FIND_CERT_ID,// Find type. Find a string in the
// certificate's subject.
&id, // The string to be searched for.
pTargetCert))) // Previous context.
panic("Could not find the required certificate");
if (pTargetCert)
CertFreeCertificateContext(pTargetCert);
if (hSystemStore)
{
if (!CertCloseStore(
hSystemStore,
CERT_CLOSE_STORE_CHECK_FLAG))
panic("Could not close the certificate store");
}
}
void panic(const char* s)
{
fprintf(stderr, "%s: Error number %x.\n", s, GetLastError());
exit(1);
}
CERT_NAME_BLOB Issuer
必须编码,但不能指向纯文本名称。您可以在此处使用 CryptEncodeObjectEx
和 X509_NAME
并填充 CERT_NAME_INFO
作为输入。或使用CertStrToNameW
需要使用全名 -
"C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA"
然后字符串
"083be056904246b1a1756ac95991c74a"
必须反转(它以反向字节顺序显示在证书属性中,不像Thumbprint)
工作代码:
void reverse(PBYTE pb, size_t cb )
{
if (cb)
{
PBYTE qb = pb + cb;
do
{
BYTE b = *--qb;
*qb = *pb;
*pb++ = b;
} while (pb < qb);
}
}
HRESULT FindCert(_Out_ PCCERT_CONTEXT* ppTargetCert, _In_ PCWSTR issuer_str, _In_ PCWSTR sn_string )
{
CERT_ID id = { CERT_ID_ISSUER_SERIAL_NUMBER };
while (CryptStringToBinaryW(sn_string, 0, CRYPT_STRING_HEXRAW,
id.IssuerSerialNumber.SerialNumber.pbData, &id.IssuerSerialNumber.SerialNumber.cbData, 0, 0))
{
if (id.IssuerSerialNumber.SerialNumber.pbData)
{
reverse(id.IssuerSerialNumber.SerialNumber.pbData, id.IssuerSerialNumber.SerialNumber.cbData);
while (CertStrToNameW(X509_ASN_ENCODING, issuer_str, CERT_X500_NAME_STR|CERT_NAME_STR_COMMA_FLAG, 0,
id.IssuerSerialNumber.Issuer.pbData, &id.IssuerSerialNumber.Issuer.cbData, 0))
{
if (id.IssuerSerialNumber.Issuer.pbData)
{
if (HCERTSTORE hSystemStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE|CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG,
L"root"))
{
ULONG dwError = NOERROR;
if (PCCERT_CONTEXT pTargetCert = CertFindCertificateInStore(hSystemStore,
X509_ASN_ENCODING, 0, CERT_FIND_CERT_ID, &id, 0))
{
*ppTargetCert = pTargetCert;
}
else
{
dwError = GetLastError();
}
CertCloseStore(hSystemStore, 0);
return dwError;
}
break;
}
if (0x400 < id.IssuerSerialNumber.Issuer.cbData)
{
return RPC_S_STRING_TOO_LONG;
}
id.IssuerSerialNumber.Issuer.pbData = (PBYTE)alloca(id.IssuerSerialNumber.Issuer.cbData);
}
break;
}
if (0x100 < id.IssuerSerialNumber.SerialNumber.cbData)
{
return RPC_S_STRING_TOO_LONG;
}
id.IssuerSerialNumber.SerialNumber.pbData = (PBYTE)alloca(id.IssuerSerialNumber.SerialNumber.cbData);
}
return GetLastError();
}
PCCERT_CONTEXT pTargetCert;
if (NOERROR == FindCert(&pTargetCert,
L"C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA",
L"083be056904246b1a1756ac95991c74a"))
{
CertFreeCertificateContext(pTargetCert);
}