是否有预先检索Windows上受信任根证书列表的API?

时间:2016-01-11 22:50:29

标签: windows ssl cryptoapi

我正在使用Python和OpenSSL使用TLS连接到某个站点(在某些跨平台软件中,因此切换到CryptoAPI的工作量太大了);但是,我不想分发(和更新)自定义证书列表。我想从平台上获取它们。在OS X和Linux上,这是相当简单的,但Windows附带了一个不完整的TLS可信根证书颁发机构列表;基本上只是微软自己的证书,然后当高级TLS内容(例如通过HTTPS在Internet Explorer中加载网页)必须验证它之前没有的信任根时,动态地将信任根添加到商店看到。 (This process is explained here.)这意味着我可以enumerate the Windows root certificate store with wincertstore,但它没用,因为在最近安装了操作系统的计算机上,该商店几乎是空的。

Microsoft提供detailed instructions for administrators预先检索此列表,以便能够操作具有严格控制的网络访问权限的计算机;但是,我找不到任何可以执行相同操作的API的引用,只需从Microsoft下载所有受信任的根证书。 (老实说,在每周多兆字节系统更新的时代,我不明白为什么预先下载这些是如此重要,如果它只是一个缓存;对于奖励积分,请解释为什么这需要完全发生。)

那么:是否有一个API允许我告诉系统根据它使用的规则预先缓存受信任的根证书?如果不这样做,如果它真的不可能(例如,如果CryptoAPI一次只能下载一个信任根,并且只有你提供了由该根签名的证书),有没有办法将OpenSSL证书验证连接到CryptoAPI& #39; s信任存储,以便验证将下载和缓存信任根,就像本机TLS连接一样?

1 个答案:

答案 0 :(得分:1)

这不是一个理想的方法,但它应该在紧要关头做,它可能会给你一个开始的地方。此代码将获取certutil -generateSSTFromWU生成的.sst文件,并将所有证书添加到根存储中:

#include <Windows.h>

#include <WinCrypt.h>

#pragma comment(lib, "crypt32.lib")

#include <stdio.h>

void process_cert(PCCERT_CONTEXT cert)
{
    PCCERT_CHAIN_CONTEXT ccc;
    CERT_CHAIN_PARA ccp = {sizeof(CERT_CHAIN_PARA)};
    DWORD flags;
    char certname[256];

    CertGetNameStringA(cert, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, certname, _countof(certname));

    flags = 0;

    if (!CertGetCertificateChain(HCCE_LOCAL_MACHINE, cert, NULL, NULL, &ccp, flags, NULL, &ccc))
    {
        printf("Certificate %s CertGetCertificateChain: %u\n", certname, GetLastError());
    }
    else
    {
        printf("Certificate %s : %x (%x)\n", certname, ccc->TrustStatus.dwErrorStatus, ccc->TrustStatus.dwInfoStatus);
    }
}

void mainfn(void)
{
    HCERTSTORE sst;
    PCCERT_CONTEXT cert;
    DWORD count;

    sst = CertOpenStore(CERT_STORE_PROV_FILENAME_W, 0, (HCRYPTPROV)NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"c:\\downloads\\roots.sst");

    if (sst == NULL)
    {
        printf("CertOpenStore: %x\n", GetLastError());
        return;
    }

    for (cert = NULL, count = 0; cert = CertEnumCertificatesInStore(sst, cert); count++) process_cert(cert);

    {
        DWORD err = GetLastError();
        if (err != CRYPT_E_NOT_FOUND)
        {
            printf("CertEnumCertificate: %u\n", err);
            return;
        }
    }
}

int main(int argc, char ** argv)
{
    mainfn();
    return 0;
}

或者,在您的上下文中,您可能更喜欢直接使用.sst文件中的根证书,而不是将它们添加到根存储中。 (在这种情况下,您应该枚举根存储以及.sst文件,以便包含任何本地添加的证书。)