我正在使用
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的信任存储,以便验证将下载并缓存信任根,就像一个本机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,NULL,certname,_countof(certname)); flags = 0; if (!CertGetCertificateChain(HCCE_LOCAL_MACHINE,cert,&ccp,flags,&ccc)) { printf("Certificate %s CertGetCertificateChain: %u\n",GetLastError()); } else { printf("Certificate %s : %x (%x)\n",ccc->TrustStatus.dwErrorStatus,ccc->TrustStatus.dwInfoStatus); } } void mainfn(void) { HCERTSTORE sst; PCCERT_CONTEXT cert; DWORD count; sst = CertOpenStore(CERT_STORE_PROV_FILENAME_W,(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文件,以便包括任何本地添加的证书.)