Read and validate certificate from executable

19,986

Solution 1

There are many API and approaches how you can get and verify the signature of the executable and how you can get other additional information which you need. The problem is which level you choose (high level like WinVerifyTrust)

The easiest first API which can be used to get cryptography context from the CAT or EXE file is CryptQueryObject function. The code example from the KB323809 could get you the main idea how to decode information what you need. the main difference if you work with CAT files is that you should modify the some parameters of CryptQueryObject. I recommend you just to use CERT_QUERY_CONTENT_FLAG_ALL and CERT_QUERY_FORMAT_FLAG_ALL and CryptQueryObject will do all what you needs internally:

BOOL bIsSuccess;
DWORD dwEncoding, dwContentType, dwFormatType;
HCERTSTORE hStore = NULL;
HCRYPTMSG hMsg = NULL;
PVOID pvContext = NULL;

// fill szFileName
...

// Get message handle and store handle from the signed file.
bIsSuccess = CryptQueryObject (CERT_QUERY_OBJECT_FILE,
                               szFileName,
                               CERT_QUERY_CONTENT_FLAG_ALL,
                               CERT_QUERY_FORMAT_FLAG_ALL,
                               0,
                               &dwEncoding,
                               &dwContentType,
                               &dwFormatType,
                               &hStore,
                               &hMsg,
                               &pvContext);

The value dwContentType set by the CryptQueryObject will get you the base information about the type of the file szFileName. The pvContext will be PCCERT_CONTEXT for the most cases which you need, but it can be also PCCRL_CONTEXT or PCCTL_CONTEXT if you use .ctl or .crl file as the input. You will receive the hStore filled with all certificates from the file szFileName. So with respect of pvContext and hStore you can examine the file contain with CryptoAPI. If you do prefer low-level massages API you can use hMsg which will be additionally set in case of some dwContentType (at least for for CERT_QUERY_CONTENT_PKCS7_SIGNED, CERT_QUERY_CONTENT_PKCS7_UNSIGNED, CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED).

To verify the signature of the file I would recommend you to use CertGetCertificateChain and CertVerifyCertificateChainPolicy to verify not only that the certificate is valid in general, but that it (or all its parents) is valid for authenticode (szOID_PKIX_KP_CODE_SIGNING). CertGetCertificateChain can be used for different revocation scenarios. You should do two separate calls with CERT_CHAIN_POLICY_AUTHENTICODE and CERT_CHAIN_POLICY_AUTHENTICODE_TS to verify that both Authenticode chain policy and Authenticode Time Stamp chain policy are valid.

UPDATED: I reread your current question (the Updated part). Your current problem is how to get the signer/publisher of the file. So I answer only on the question.

If you use the code from sysinternal for the signature verification you should just search for the line

if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )

The statement sill set the fields of the InfoStruct in case that that file is system windows file which signature is verified with respect of some .cat file. The field InfoStruct.wszCatalogFile will get you the name of the .cat file.

For example on my Windows 7 if I try to verify the digital signature of the C:\Windows\explorer.exe file, the .cat where its hash could be found is C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1_for_KB2515325~31bf3856ad364e35~amd64~~6.1.1.0.cat.

If you would use code from KB323809 with described above parameters of CryptQueryObject you will decode the SPC_SP_OPUS_INFO_OBJID ("1.3.6.1.4.1.311.2.1.12") attribute of the C:\Windows\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1_for_KB2515325~31bf3856ad364e35~amd64~~6.1.1.0.cat (see the function GetProgAndPublisherInfo) and you will know

pwszProgramName: "Windows Express Security Catalogs"
pPublisherInfo: NULL
pMoreInfo->dwLinkChoice: SPC_URL_LINK_CHOICE
pMoreInfo->pwszUrl "http://www.microsoft.com"

So no special publisher information are included for the file. If you examine the signer of the the catalog you will find out that:

The signer of the .cat file: "Microsoft Windows"
The signer signed it with the certificate:
    Serial Number: 0x6115230F00000000000A
    Issuer Name: Microsoft Windows Verification PCA
    Full Issuer Name:
        CN = Microsoft Windows Verification PCA
        O = Microsoft Corporation
        L = Redmond
        S = Washington
        C = US
    Subject Name: Microsoft Windows
    Full Subject Name:
        CN = Microsoft Windows
        OU = MOPR
        O = Microsoft Corporation
        L = Redmond
        S = Washington
        C = US
The Date of TimeStamp : 28.02.2011 21:16:36
TimeStamp Certificate: 
    Serial Number: 0x6103DCF600000000000C
    Issuer Name: Microsoft Time-Stamp PCA
    Subject Name: Microsoft Time-Stamp Service

So you should use just the signer of the .cat file, because there are no other signer of explorer.exe.

Solution 2

The WinVerifyTrust function performs a trust verification action on a specified object. The function passes the inquiry to a trust provider that supports the action identifier, if one exists.

For certificate verification, use the CertGetCertificateChain and CertVerifyCertificateChainPolicy functions.

Solution 3

@Davita I read the above problem thoroughly and tried to solve it.

My suggestion is to try CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED instead of CERT_QUERY_CONTENT_FLAG_ALL in the third parameter of CryptQueryObject()

Share:
19,986
Davita
Author by

Davita

Updated on June 19, 2022

Comments

  • Davita
    Davita almost 2 years

    I want to validate certificates of signed executable images (by validation, I mean to tell if the signature comes from MS/Adobe/Oracle etc.). Does windows provides api for this task? How should I do that, no idea. Any help would be appreciated. I'm using Windows and C++. I want to validate native executable images, not .NET assemblies or Java jar files.

    UPDATE


    Ok, I'll try to describe what I want shortly.

    1) Validate PE certificate. Is the signature valid or not. It should work when signature is embedded in PE and when the signature is in security catalog. (I found this on sysinternals forum and works fine, so I don't need this one anymore).

    2) Tell who's the signer/publisher of the file. I know it can be achieved through CryptQueryObject (I found a working example, though it doesn't work with security catalogs), but don't know how to use it with security catalog files.

  • Davita
    Davita over 12 years
    Thanks John, I tried the example provided by MSDN and it works great almost everytime, except when I try to verify windows core files such as explorer.exe. It says that explorer.exe is not signed, but PeExplorer tells me that explorer.exe's signature is verified. I'm confused what I'm missing...
  • Bevan Collins
    Bevan Collins over 12 years
    System files have their hashes stored in a catalog file which is signed. See code here: forum.sysinternals.com/…
  • Davita
    Davita over 12 years
    @Bevan Collins, thank you very much, it worked fine :) Could you please tell me how should I retrieve certificate information, such as who signed the certificate? thanks
  • Bevan Collins
    Bevan Collins over 12 years
    How To Get Information from Authenticode Signed Executables support.microsoft.com/default.aspx?scid=kb;en-us;323809
  • Davita
    Davita over 12 years
    Thank you very much Bevan, I already tried that code but it doesn't work on security catalogs. I have no idea how to use CryptQueryObject with catalogs and couldn't find anything on the net. :(
  • Davita
    Davita over 12 years
    thank you very much and +1, I appreciate your time. Though I still have some problems, thanks to you, I feel I'm much close to the goal than before :). When I call CryptQueryObject (to explorer.exe), it returns an error code 80092009 which means "No match when trying to find the object." I guess it didn't find the catalog for explorer.exe(?). Thank you very much again for your effort :)
  • Oleg
    Oleg over 12 years
    @Davita: If you would try to examine any text file or any unsigned executable file (like explorer.exe) with respect of CryptQueryObject you would receive CRYPT_E_NO_MATCH error. If you examine properties of explorer.exe you will see no "Digital Signatures" tab, so the file is just not signed. If you would have other problems in the implementation you could ask me. Some years ago I spend many time in code signed EXE, CAT and so on. So probably I will able quickly help you.
  • Davita
    Davita over 12 years
    Many thanks Oleg, I really appreciate your effort. There's still some confusion. forum.sysinternals.com/… <-- When i check explorer.exe with this code, WinVerifyTrust tells that the signature is valid. Am I missing something or PE signature and catalog files has different purpose? Sorry for this dumb question, I just really need to get this working :( Thanks again
  • Oleg
    Oleg over 12 years
    @Davita: OK! Good point. You mean the usage of CryptCATAdminXXXX API. I will examine it and write you more information later (tomorrow). In general the idea of .CAT files are to sign the files which could not hold signature inside like .inf files for example. The "C:\Windows\System32\catroot\{F750E6C3-38EE-11D1-85E5-00C04F‌​C295EE}\nt5.cat" file and some other "admin" CAT files has SHA1 or MD5 hashes of the files which are parts of operation system. If you calculate SHA1 or MD5 hashes from any file you can examine whether it is "original" Windows file. CryptCATAdminXXXX simplify that
  • Davita
    Davita over 12 years
    Damn it's quite complicated :( I wish I could repay you somehow :( 250 bounty is nothing compared to your help :( Thanks Oleg and sorry for taking your precious time
  • Oleg
    Oleg over 12 years
    @Davita: I answered on your main question in "UPDATED" part of my question. If some more your questions are opened I could try to help you.
  • Davita
    Davita over 12 years
    thanks, I'll check your answer tomorrow and let you know the result :)
  • Oleg
    Oleg over 12 years
    @Davita: If you now yet seen the link from MSDN it could be interesting for you in addition to the code from sysinternals.
  • Davita
    Davita over 12 years
    I can't express my gratitude with words :) What was a black magic 5 mins ago is now a piece of cake thanks to you. Oleg you saved me, thanks again :)
  • Oleg
    Oleg over 12 years
    @Davita: You are welcome! I am glad that I could help you. I can only repeat that if you would receive more problem in the subject I would be glad to help you again.
  • vitr
    vitr almost 6 years
    @Oleg thanks for the great answer! Can you help to find a way of getting ` InfoStruct.wszCatalogFile` by using pure code from KB323809 (Crypto API ), not the CryptCATCatalogInfoFromContext function from the code from sysinternal (WinVerifyTrust() API)?
  • Oleg
    Oleg almost 6 years
    @vitr: You are welcome! It's difficult to answer you without to know the scenario, which you use. Do you have some CAT file as the input or the EXE file (or some other signed file) as the input? If you have only EXE file as the input then it contains no reference to CAT file. What you try to do?
  • vitr
    vitr almost 6 years
    @Oleg: I have only signed EXE files and want to get the CAT file (e.g. InfoStruct.wszCatalogFile) without calling CryptCATCatalogInfoFromContext and using only C code from the CryptQueryObject example (KB323809), and I see, this is not possible((
  • vitr
    vitr almost 6 years
    @Oleg: to summarize, we can verify and get the certificate attributes (signer, serial, timestamp, etc) for the files signed with embedded certificates using low level function from Crypt32.dll. To do the same for the files signed with external certificates we have to find the .CAT file using functions from Wintrust.dll and process it like a file with embedded certificate. Am I right? And, in your opinion, is it easier to use only higher level functions from Wintrust.dll and skip using low level functions from Crypt32.dll?
  • Oleg
    Oleg almost 6 years
    @vitr: This week I'm in a business trip by one of my customers. I'll try to answer you at the evening after I'll come to hotel.
  • Oleg
    Oleg almost 6 years
    @vitr: A .CAT file is nothing more as the list of hashes of files, which one should interpret as "valid". In many cases one even not saves the filename (the name of exe) or the path of the file as attributes of .CAT file. During installation of some software product (for example a driver) windows copy the corresponding .CAT file in C:\Windows\System32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC‌​295EE} folder and includes all hash values from the CAT tile in common index. It allows to get the CatFileName by simple call of CryptCATAdminAcquireContext,CryptCATAdminCalcHashFromFileHan‌​dle functs.
  • Anup
    Anup about 4 years
    does this work in kernel mode? . . how to get PE sign info in kernel mode?
  • Oleg
    Oleg about 4 years
    @Anup: It depends on what you need exactly. You can try to use Fips. sys, which is a Kernal Mode Cryptographic Module (see csrc.nist.gov/csrc/media/projects/…).