Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an API to pre-retrieve the list of trusted root certificates on Windows?

I am using Python and OpenSSL to connect to a site using TLS (in some cross-platform software, so it would be too much work to switch to CryptoAPI for everything); I don't want to distribute (and update) a custom list of certificates, though. I want to get them from the platform. On OS X and Linux this is fairly straightforward, but Windows ships with an incomplete list of trusted root certificate authorities for TLS; basically just Microsoft's own certificates, then dynamically adds trust roots to the store when high-level TLS stuff (such as loading a web page in Internet Explorer over HTTPS) has to verify a trust root it hasn't previously seen. (This process is explained here.) This means I can enumerate the Windows root certificate store with wincertstore, but it's useless because on machines with more recently-installed OSes, that store will be almost empty.

Microsoft provides detailed instructions for administrators to pre-retrieve this list so as to be able to operate machines with tightly-controlled network access; however, I cannot find any reference to an API that will do the same thing, and just download all trusted root certificates from Microsoft. (Honestly, in the age of weekly multi-megabyte system updates, I don't see why pre-downloading these is such a big deal, if it's just a cache; for bonus points please explain why this needs to happen at all.)

So: is there an API that would allow me to tell the system to just pre-cache the trusted root certificates according to whatever rules it uses? Failing that, if it's really impossible (i.e. if CryptoAPI can only download one trust root at a time and only if you feed it a certificate signed by that root), is there a way to hook up OpenSSL certificate verification to CryptoAPI's trust store so that the verification will download and cache trust roots just like a native TLS connection would?

like image 788
Glyph Avatar asked Jan 11 '16 22:01

Glyph


People also ask

How do I find trusted root certificates in Windows?

Select Run from the Start menu, and then enter certmgr. msc. The Certificate Manager tool for the current user appears. To view your certificates, under Certificates - Current User in the left pane, expand the directory for the type of certificate you want to view.

Where are the trusted root certificates stored?

Certificate Directory - Win32 apps A Windows public key infrastructure (PKI) saves certificates on the server that hosts the certification authority (CA) and on the local computer or device.

How do I access trusted root certification authorities?

Expand the Computer Configuration section and open Windows Settings\Security Settings\Public Key. Right-click Trusted Root Certification Authorities and select Import. Follow the prompts in the wizard to import the root certificate (for example, rootCA. cer) and click OK.


1 Answers

This is not an ideal approach, but it should do at a pinch and it may give you somewhere to start. This code will take the .sst file generated by certutil -generateSSTFromWU and add all the certificates to the root store:

#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;
}

Alternatively, in your context, you might prefer to use the root certificates in the .sst file directly, without also adding them to the root store. (In that case you should probably enumerate the root store as well as the .sst file, so as to include any locally added certificates.)

like image 143
Harry Johnston Avatar answered Sep 21 '22 07:09

Harry Johnston