Microsoft signs all code that ships from it (that is except for the case when it doesn’t); so how does one verify that the code came from them vs. anyone with a fraudulent certificate claiming to be them?
Well the answer is pinning, but the pinning for the most part does not happen at the signing certificate level as those keys change to frequently to be pinned. The pinning happens at the certificate issuer level, much like has been proposed by CAA.
So to understand how this happens in code you need to understand code signing in Windows a little. There are two types of signatures those that are “embedded” and those that are “attached”.
Authenticode would be an example of an embedded signature; Catalog Files on the other hand are detached signatures. There are other examples of both of these but in general these other formats have the same abstract properties.
So when do you use one vs. the other? Well if a user will download your binary directly (ActiveX, Setup, etc.) you would typically embed a signature.
If that’s not the case you would use a detached signature because a single signature can be placed on a list of binaries without increasing the package size (it’s one signature on n hashes). You produce these signatures with SignerSignEx.
For the two signature formats I mentioned you do your signature verifications using an API called WinVerifyTrust. You can also use this API to get information out of a signature (who signed it, when, etc.).
With that information you do a certificate validation that is accomplished with the CertGetCertificateChain API, that gives you a CERT_CHAIN_CONTEXT which you can use to call CertVerifyCertificateChainPolicy.
This API is used to do application specific verifications, for example in the case of TLS the CERT_CHAIN_POLICY_SSL provider is used – this is where the name and EKU verification logic for Windows exists.
The providers we care about for our story today are:
- CERT_CHAIN_POLICY_AUTHENTICODE – Is this certificate appropriate for code-signing?
- CERT_CHAIN_POLICY_AUTHENTICODE_TS – Is this certificate appropriate for time stamping code?
- CERT_CHAIN_POLICY_MICROSOFT_ROOT – Is this certificate ultimately issued by a Microsoft Product Root?
The last one is the one in has an array of hashes in it, I don’t recall if they are key hashes or thumbprints of the certificate. In essence what it does is look at the top of the chain to see if the Root matches one of these hashes if it does it passes, if it doesn’t it fails.
Applications may choose to do additional “pinning” also, for example in the case of Windows Update Services a manifest is exchanged between the client and server, that manifest comes down over SSL they may choose to also do pinning to a set of certificates for the SSL session or apply digital signatures to the manifest and do pinning for the keys that are used to do signing.
I do not know personally for a fact that any such pinning takes place but I have been told by several people I respect that it does.
It looks as if Windows Update was not doing pinning but as of this week it will, this is of course a best practice and I am glad to see them doing it now.
So now you know how to validate that code is coming from Microsoft, or at least how it’s supposed to work.
Issues like represented in MSRC 2718704 / Flame put some of these assumptions in question, it’s clear that pinning is an important concept though and one that should be supported more broadly.