Windows has a feature called Automatic Root Update, when CryptoAPI does a chain build, exhausts the locally installed root certificates it downloads (if it has not already done so) a list of certificates it should trust.
This list contains attributes about those certificates (hashes of their subject name and keys, what Microsoft believes it should be trusted for, etc.).
If it finds the certificate it needs in that list it downloads it and installs it.
So how does this technically work?
There is a pre-configured location where Windows looks for this Certificate Trust List (CTL), it is http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/authrootstl.cab.
NOTE: Technically they do use different language codes in the URLs based on the client local but to the best of my knowledge they all map to the same files today.
This list is downloaded and de-compressed; you can do the same thing on Windows (with curl) like this:
expand authrootstl.cab .\authroot.stl
You can open authroot.stl with explorer and look at some of its contents but for the purpose of our exercise that won’t be necessary.
This file is a signed PKCS #7 file, Windows expects this to be signed with key material they own (and protect dearly).
It contains a Microsoft specific ContentInfo structure for CTLs and a few special attributes. WinCrypt.h has the OIDs for these special attributes defined in it but for brevity sake here are the ones you will need for this file:
Copy this list of OIDs and constants into a file called authroot.oids and put it where we extracted the STL file.
We can now use the following OpenSSL command to inspect the contents in more detail:
openssl asn1parse -oid authrootstl.oids -in authroot.stl -inform DER
There is lots of stuff in here, but for this exercise we will just download the certificates referenced in this list.
To do that we need to understand which of the attributes are used to construct the URL we will use to download the actual certificate.
This list values we want are just after the OID_ROOT_LIST_SIGNER, the first one being “CDD4EEAE6000AC7F40C3802C171E30148030C072”, its entry will look like this:
128:d=8 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:CDD4EEAE6000AC7F40C3802C171E30148030C072
150:d=8 hl=3 l= 246 cons: SET
153:d=9 hl=2 l= 30 cons: SEQUENCE
155:d=10 hl=2 l= 10 prim: OBJECT :OID_CERT_PROP_ID_PREFIX_105
167:d=10 hl=2 l= 16 cons: SET
169:d=11 hl=2 l= 14 prim: OCTET STRING [HEX DUMP]:300C060A2B0601040182373C0302
185:d=9 hl=2 l= 32 cons: SEQUENCE
187:d=10 hl=2 l= 10 prim: OBJECT :OID_CERT_SUBJECT_NAME_MD5_HASH_PROP_ID
199:d=10 hl=2 l= 18 cons: SET
201:d=11 hl=2 l= 16 prim: OCTET STRING [HEX DUMP]:F0C402F0404EA9ADBF25A03DDF2CA6FA
219:d=9 hl=2 l= 36 cons: SEQUENCE
221:d=10 hl=2 l= 10 prim: OBJECT :OID_CERT_KEY_IDENTIFIER_PROP_ID
233:d=10 hl=2 l= 22 cons: SET
235:d=11 hl=2 l= 20 prim: OCTET STRING [HEX DUMP]:0EAC826040562797E52513FC2AE10A539559E4A4
257:d=9 hl=2 l= 48 cons: SEQUENCE
259:d=10 hl=2 l= 10 prim: OBJECT :OID_CERT_PROP_ID_PREFIX_98
271:d=10 hl=2 l= 34 cons: SET
273:d=11 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:885DE64C340E3EA70658F01E1145F957FCDA27AABEEA1AB9FAA9FDB0102D4077
307:d=9 hl=2 l= 90 cons: SEQUENCE
309:d=10 hl=2 l= 10 prim: OBJECT :CERT_FRIENDLY_NAME_PROP_ID
321:d=10 hl=2 l= 76 cons: SET
323:d=11 hl=2 l= 74 prim: OCTET STRING [HEX DUMP]:4D006900630072006F0073006F0066007400200052006F006F007400200043006500720074006900660069006300610074006500200041007500740068006F0072006900740079000000
We can download this certificate with the following command:
curl http://www.download.windowsupdate.com/msdownload/update/v3/static/trustedr/en/CDD4EEAE6000AC7F40C3802C171E30148030C072.crt> CDD4EEAE6000AC7F40C3802C171E30148030C072.crt
If we look at the contents of the certificate we can see this is the 4096 bit “Microsoft Root Certificate Authority”.
The next in the list is 245C97DF7514E7CF2DF8BE72AE957B9E04741E85, and then the next is 18F7C1FCC3090203FD5BAA2F861A754976C8DD25 and so forth.
We could go through and parse the ASN.1 to get these values, iterate on them and download them all if we wanted. Of course if we wanted to get all of the root certificates we might as well just download the most recent root update here: http://www.microsoft.com/en-us/download/details.aspx?id=29434
It contains the same information just in a self-contained format (this is whats used by down-level clients that do not have Automatic Root Update).
Anyhow hopefully this will be useful for someone,
Using this info and the PKCS#7 spec, I was able to parse the whole file. Any idea how to interpret the property OctetStrings? They were ASN.1 DER data in the SST file format used in Windows XP, but the STL format seems to use a different scheme.
They added some control flags at some-point, the SST used to just have adds in it — now they can do removes and some other basic operations. My guess is a bitmask of some sort.
I got 411 certs from the stl file, but 46 of them are already expired, so I wonder why MS keep there expired certs information in the stl file?
Could be for code signing and time stamp.
Thank you, this was really helpful. During a wireshark capture, I saw the .CRT download but the CRL had already been downloaded. Your post explained the part of the process that was still a mystery to us.
Each OCTET STRING has the format and meaning identified by the associated OID.
OID_CERT_SUBJECT_NAME_MD5_HASH_PROP_ID is obviously a bare MD5 hash value calculated over some encoding (perhaps DER) of the Subject distinguished name (which another cert may reference as “issuer name”).
OID_CERT_KEY_IDENTIFIER_PROP_ID might (haven’t checked) be the “subject key identifier” from the cert (which another cert may reference as the “authority key identifier” to distinguish CA certs with the same subject name).
CERT_FRIENDLY_NAME_PROP_ID is simply a 0-terminated UTF-16LE string used for display purposes.
Microsoft includes expired certificates because they use timestamping services to check signed files according to the certificate validity at the time of signing, not at the time of checking.
Pingback: Code Signing Certificate Cloning Attacks and Defenses | Copy Paste Programmers
This is great! Is there a way to see restrictions? NotBefore dates placed on specific EKUs?
For those interested in this check out – https://www.npmjs.com/package/tl-create it is a tool I make available for working with these formats.
Thank you friend, this is very illuminating and gives readers a method to see past MS opaqueness.