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

是否有用于在Windows上预检索受信任根证书列表的API?,windows,ssl,cryptoapi,Windows,Ssl,Cryptoapi,我正在使用Python和OpenSSL连接到使用TLS的站点(在一些跨平台软件中,因此切换到CryptoAPI进行所有操作将是太多的工作);不过,我不想分发(和更新)自定义证书列表。我想把他们从站台上弄下来。在OSX和Linux上,这相当简单,但Windows附带了一个不完整的TLS受信任根证书颁发机构列表;基本上只是微软自己的证书,然后当高级TLS人员(例如通过HTTPS在Internet Explorer中加载网页)必须验证以前未见过的信任根时,动态地将信任根添加到存储中。这意味着我可以,但

我正在使用Python和OpenSSL连接到使用TLS的站点(在一些跨平台软件中,因此切换到CryptoAPI进行所有操作将是太多的工作);不过,我不想分发(和更新)自定义证书列表。我想把他们从站台上弄下来。在OSX和Linux上,这相当简单,但Windows附带了一个不完整的TLS受信任根证书颁发机构列表;基本上只是微软自己的证书,然后当高级TLS人员(例如通过HTTPS在Internet Explorer中加载网页)必须验证以前未见过的信任根时,动态地将信任根添加到存储中。这意味着我可以,但这是无用的,因为在安装了较新操作系统的机器上,该存储几乎是空的

微软提供预先检索此列表的功能,以便能够通过严格控制的网络访问操作机器;但是,我找不到任何对API的引用,该API将执行相同的操作,而只是从Microsoft下载所有受信任的根证书。(老实说,在每周都会有好几兆字节的系统更新的时代,如果只是缓存,我不明白为什么预下载这么重要;要获得额外分数,请解释为什么需要这样做。)


那么:是否有一个API允许我告诉系统根据它使用的任何规则预先缓存受信任的根证书?否则,如果确实不可能(即,CryptoAPI一次只能下载一个信任根,并且仅当您向其提供由该根签名的证书时),有没有一种方法可以将OpenSSL证书验证连接到CryptoAPI的信任存储,以便验证可以像本地TLS连接一样下载和缓存信任根?

这不是一种理想的方法,但它应该在紧要关头进行,并可能为您提供一个起点。此代码将获取由
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;
}
#包括
#包括
#pragma注释(lib,“crypt32.lib”)
#包括
作废过程证书(PCCERT上下文证书)
{
PCCERT_CHAIN_CONTEXT ccc;
证书链段ccp={sizeof(证书链段)};
德沃德旗;
char-certname[256];
CertGetNameStringA(证书,证书名称,简单显示类型,0,NULL,证书名称,证书计数(证书名称));
flags=0;
如果(!CertGetCertificateCain(HCCE\u本地\u计算机、证书、NULL、NULL和ccp、标志、NULL和ccc))
{
printf(“证书%s CertGetCertificateCain:%u\n”,证书名,GetLastError());
}
其他的
{
printf(“证书%s:%x(%x)\n”,证书名,ccc->TrustStatus.dwErrorStatus,ccc->TrustStatus.dwFoStatus);
}
}
无效mainfn(无效)
{
HCERTSTORE sst;
PCCERT_上下文证书;
德沃德计数;
sst=CertOpenStore(CERT_STORE_PROV_FILENAME_W,0,(HCRYPTPROV)NULL,CERT_STORE_OPEN_现有_标志| CERT_STORE_READONLY_标志,L“c:\\downloads\\roots.sst”);
如果(sst==NULL)
{
printf(“CertOpenStore:%x\n”,GetLastError());
返回;
}
对于(cert=NULL,count=0;cert=certnumcertificatesinstare(sst,cert);count++)进程\证书(cert);
{
DWORD err=GetLastError();
如果(错误!=未找到密码)
{
printf(“CertEnumCertificate:%u\n”,错误);
返回;
}
}
}
int main(int argc,字符**argv)
{
mainfn();
返回0;
}

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

。我想我没有在我的虚拟机上看到这一点,因为我大部分时间都让它们挂起?@HarryJohnston-也许使用该命令实际上是以编程方式执行此操作的正确答案。但是知道它在调用什么API,这样我们就不需要子进程了,这将是一个理想的选择。因此,
certutil-syncWithWU
只是将证书放在一个目录中。它不会将它们保存在
“ROOT”
存储中,我相信这是它们需要的位置。我想知道Windows Update API是否适合查找此项:不,我没有。您如何查询根存储?我正在使用
python-c'导入wincertstore;打印(len(list(wincertstore.CertSystemStore(“ROOT”)))”
这会从根存储中删除所有证书吗?我想做吴通常做的事情;如果用户已解除对证书的信任,我不想重新信任它;如果他们添加了自定义证书,我想尊重他们。这不会删除任何证书,也不会影响存储中已经存在的证书。它所做的只是让Windows确认每个证书都是有效的。当然,这与Internet Explorer的唯一区别在于,您直接向Windows询问根证书,而不是询问指向根证书的证书链。(如果OpenSSL允许您自己验证站点证书,这可能是一个更好的选择。如果您使用CertGetCertificateCain和friends进行验证,您的程序将完全像Internet Explorer一样,只将特定站点实际需要的根证书加载到存储中。)不幸的是,我试图满足的API是“这里有一个要验证的证书列表”。可能可以进入OpenSSL并告诉它更改其验证方式,但至少在我需要与之交谈的一个API中,这并不是一个真正的选项。是的,我也这么认为,但我认为我最好不要认为这是理所当然的。我想如果你从.sst的证书和根目录的证书中列出一个列表存储,实际上不需要将证书导入到