I was advised by Microsoft developer @tannergooding to post this question here. I am a senior architect at HP Inc. and I am writing code to verify PE file digital signatures. From my research, there seems to be two ways of doing this: WinVerifyTrust and CertVerifyCertificateChainPolicy (via X509Chain). WinVerifyTrust's documentation says the following:
For certificate verification, use the CertGetCertificateChain and CertVerifyCertificateChainPolicy functions.
However, it was my impression that WinVerifyTrust can be configured to perform certificate chain verification. Now I am very confused about which of these--or both, in some specific order--I should authoritatively be using. If the answer is to use CertVerifyCertificateChainPolicy then I feel comfortable relying on the APIs exposed by the X509Chain class.
Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq
Notify danmosemsft if you want to be subscribed.
Also, the MSDN documentation for WinTrustVerify could use some work. It doesn't list more than a couple of possible return codes. It mentions that the delegated trust provider can return its own codes but there is no link to a list of codes for the standard Microsoft Authenticode provider (WINTRUST_ACTION_GENERIC_VERIFY_V2). I submitted feedback on the page stating the same.
It seems that CertVerifyCertificateChainPolicy may be more powerful--or at least more configurable--than WinVerifyTrust. For example, it's possible with CertVerifyCertificateChainPolicy to request internet revocation verification but later detect that internet revocation didn't work (likely due to no internet connection) and thus handle that situation specially. I am not sure the same is possible with WinVerifyTrust.
My understanding is that if you're actually trying to verify Authenticode, you should use WinVerifyTrust. In addition to checking the certificate chain against CERT_CHAIN_POLICY_AUTHENTICODE (which the X509Chain class won't do) it looks at user-specific data regarding trusted / distrusted publishers, and can use the built-in user consent dialog (or not, at the caller discretion).
The comment in the docs is, I believe, simply suggesting that if you found that function while looking for how to simply "verify chain trust" that you're looking for a different function.
Since this question isn't about .NET, and it's outside of our areas of authority/expertise, there's not really much more to be said here. A sample for code-signing/WinVerifyTrust exists at https://github.com/microsoft/Windows-classic-samples/blob/master/Samples/Security/CodeSigning/; I don't know how well issues there are monitored, but it's the best alternate location I could come up with.
AFAIK, WinVerifyTrust only verifies the _primary_ authenticode signature - any nested ones will have to be checked separately, e.g. using CertVerifyCertificateChainPolicy (or possible using WinVerifyTrust with the WTD_CHOICE_BLOB type, but I never got that to work and couldn't find any samples doing it).
@cocowalla I wish the documentation was better for such an important security-related function. It was difficult as it was determining how to correctly use WinVerifyTrust. It being closed-source and all, I can't even guarantee the correctness of the code I did write.