Today I learned something fascinating about how Windows deals with trusted root CA certificates. It might surprise you, and it certainly did for me, but out-of-the-box Windows doesn't come with a set of root CA certificates sufficient for web browsing.
You can see this for yourself if you install a fresh copy of Windows without a network connection and view the machine certificates:

The certificates included with Windows are a basic set just for doing authenticode verification. So then how does Windows perform any form of certificate chain validation without any preinstalled roots? Let's find out!
In short, when an application such as a web browser asks Windows to build and validate a TLS certificate chain, it queries the local certificate store for a matching root. If no match is found, it will then reference a catalog of certificates downloaded from Windows Update. If a match is found in there, the certificate is downloaded and installed in the store for future use.
You can view which of these catalogs have been cached on your machine with certutil.exe -URLCache cab:
These catalogs are served as Windows Cabinet (.cab) files. However, unlike most cab files served by Windows update - these don't have an authenticode signature attached to them.
Instead, these cabs contain only a single file with an .stl extension. Information on .stl files is scarce at best, with most results pointing to a format used by CAD software (including Windows 3D Paint), which is definitely not what we're dealing with.
Instead, these STL files are actually just a PKCS#7 archive with signed data. PKCS#7 is a standardized way of storing signed or encrypted data, archiving certificates, or revocation lists in a single file. In a way you can kinda think of a P7 archive like a signed or encrypted ZIP, except there's no inherent compression here and it's not storing files or folders, but just raw data.
Using OpenSSL you can view the contents of the STL file, so let's explore:
PKCS7:
type: pkcs7-signedData (1.2.840.113549.1.7.2)
d.sign:
version: 1
md_algs:
algorithm: sha256 (2.16.840.1.101.3.4.2.1)
parameter: NULL
The header confirms what I was saying earlier, that a .STL file is actually just a PKCS#7 archive. In this case we can see that it contains signed data, and the signature used sha256 for its hashing algorithm.
Note that PKCS#7 signatures aren't for the entire file, but rather for portions of data within the file. The signature of that data is included in an unsigned portion of the file.
When validating the archive, a signing and intermediate certificate are included in the .STL files signature. This can be seen if you try to open the .STL file in the certificate manager:

The root certificate, "Microsoft Root Certificate Authority 2010", is included with every base install of Microsoft Windows (and can be seen in the first screenshot). I'm not positive on the exact validation rules, but Windows does reject a .STL file if it's signed by a certificate with a different, but still trusted, root.
One interesting observation is that Windows does not appear to care about the signing certificate being expired. Normally, like with websites, when a certificates notAfter time is in the past then the validation will fail. However, for things like software and other artifact signing, that might not work. Imagine not being able to run an old but perfectly fine bit of software just because the code signature uses an expired certificate.
To work around this, clients typically compare the certificate against the time at which the signature was applied. The same is true for PKCS#7 archives, which can have a signing time attribute that can be used to validate the signing certificate.
What's interesting is that the .STL file does not have this signing time attribute. I'm not sure on exactly how Windows validates the validity period of the signing certificate, if at all. It may be using a date found within the signed data itself, or perhaps forgoing this check entirely.
Either way, as of writing, the signing certificate for the .STL file is actually expired, but this hasn't caused any issues, nor has it in the past.
Regardless, once Windows has validated the signature, it's now safe to move onto reading the signed data. The first portion of the signed contents is a timestamp (as evidence by the UTCTIME object). This likely represents the last update time for the catalog and is used by the clients for caching purposes.
contents:
type: undefined (1.3.6.1.4.1.311.10.1)
d.other:
SEQUENCE:
SEQUENCE
SEQUENCE
OBJECT :1.3.6.1.4.1.311.10.3.9
INTEGER :1401D8F9409A49C9FA
UTCTIME :221115222126Z
SEQUENCE
OBJECT :sha1
NULL
SEQUENCE
Now we get to the certificate data. Note that the actual certificate isn't included here, but rather metadata about the certificate that can be used while building a chain.
Each certificate starts with a string containing a SHA1 fingerprint of the certificate, followed by a set of properties with more information.
Most of the OIDs are (or at least were) documented on Microsoft's support website. An archive of that page is available here. The remaining OIDs I figured out by comparing the values against the published certificate list available here.
| Object ID (OID) | Description |
|---|---|
| 1.3.6.1.4.1.311.10.11.11 | Friendly Name |
| 1.3.6.1.4.1.311.10.11.98 | SHA256 Fingerprint |
| 1.3.6.1.4.1.311.10.11.20 | Key Identifier |
| 1.3.6.1.4.1.311.10.11.29 | MD5 Hash of Certificate Subject |
| 1.3.6.1.4.1.311.10.11.105 | Microsoft Extended Key Usage |
| 1.3.6.1.4.1.311.10.11.104 | Date of which the certificate was disabled (Only included on revoked certs) |
| 1.3.6.1.4.1.311.10.11.126 | Not-Before date of a revoked certificate, similar to above (Only included on revoked certs) |
The Microsoft Extended Key Usage is flags about the acceptable uses for this certificate. Similar to the key usage field and extended key usage extension of a certificate, except that these values don't appear on the certificates themselves.
Seen below is the Cybertrust Global Root certificate which expired in December 2021.
OCTET STRING [HEX DUMP]:5F43E5B1BFF8788CAC1CC7CA4A9AC6222BCC34C6 SET SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.104 SET OCTET STRING SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.126 SET OCTET STRING [HEX DUMP]:0080C82B6886D701 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.127 SET OCTET STRING [HEX DUMP]:300A06082B06010505070303 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.29 SET OCTET STRING [HEX DUMP]:CBB63E347AD7916D1400F32B391E6451 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.20 SET OCTET STRING [HEX DUMP]:B6087B0D7ACCAC204C8656325ECFAB6E852D7057 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.98 SET OCTET STRING [HEX DUMP]:960ADF0063E96356750C2965DD0A0867DA0B9CBD6E77714AEAFB2349AB393DA3 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.83 SET OCTET STRING [HEX DUMP]:30223020060A2B06010401B13E01640130123010060A2B0601040182373C0101030200C0 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.11 SET OCTET STRING [HEX DUMP]:4300790062006500720074007200750073007400200047006C006F00620061006C00200052006F006F0074000000 SEQUENCE OBJECT :1.3.6.1.4.1.311.10.11.9 SET OCTET STRING [HEX DUMP]:303206082B0601050507030206082B0601050507030306082B0601050507030406082B0601050507030106082B06010505070308
So let's imagine that it's still 2021 and I've just visited a website with a server certificate with this Cybertrust certificate as its root.
Now we could just iterate through all of the certificates already installed on the system and check the signature, but that'd be very expensive. Instead, TLS clients (not just Windows), prefer to first try and find the best matching certificate before performing the expensive cryptographic operations.
There are two ways to go about this: the subject/authority key identifier and the subject/issuer name. The key identifier is a quick and easy way for certificates to say who issued them (using the issuer key identifier), and for certificates to identify their associated keys (subject key identifier). One advantage of using key identifiers is that you can cross-sign a certificate (two different certificates with the same private key). Because there are no requirements about what content the identifier actually is, this makes for very straightforward byte comparison operations.
However not all certificates will use key identifiers as it's not a mandatory field, therefor the subject and issuer name would be used as a fallback.
When Windows is building the certificate chain it will first query its local certificate store for a matching key identifier or name. If no match is found it then performs the same check in the authroot.stl catalog. Assuming a match is found there Windows will then download the full certificate, because remember that the authroot.stl catalog doesn't actually contain certificates.
DER-encoded certificates are served by Window Update based on their SHA-1 fingerprint:
http://ctldl.windowsupdate.com/msdownload/update/v3/static/trustedr/en/<SHA1 Fingerprint>.crt
Windows will then install this certificate in the Trusted Root Certification Authorities for future use, and continue on with chain validation.
The next time I visited this website, the certificate would already be installed in the local store, so there's no need to query for the certificate elsewhere.
Disclaimer: while I am employed at Microsoft I do not work on the Windows team. This post is not sponsored by, endorsed by, or affiliated with Microsoft. The information contained in this post is publicly available and the behaviours described are reproducible on almost any Windows device. Please don't sue me.