如何通过序列号从 windows certstore 检索证书?

问题描述 投票:0回答:1

我正在尝试从 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);
} 
winapi cryptoapi
1个回答
0
投票

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);
    }
© www.soinside.com 2019 - 2024. All rights reserved.