The PE executable format (the one used by Windows) supports the use of digital certificates to verify the source of the file. Normally you can verify it using Windows Explorer (by right-clicking on the file and selecting
Properties). It also shows up when you try to run an executable downloaded from the Internet with IE or FF3. If you wish to mass-verify it, you can use a tool like sigcheck by Mark Russinovich.
However, great tool as sigcheck may be, there are at least two problems with it:
- It doesn't run on Linux. Last time I've tried under wine, it complained about missing imports from the cryptography libraries (this might have changed in the meantime)
- It wants to connect to the Internet (to verify CLRs I assume). This can lead to some nasty pseudo-hanging processes on systems which (for security reasons) are cut off from the Internet but are still able to resolve domains.
So I looked into verifying the signatures myself. The method I'll describe in the following paragraphs will work on Linux (in fact it will work on any OS which has OpenSSL binaries), but it has at least two limitations you should be aware of:
- It doesn't work with catalog (.CAT) files. The catalog files use an undocumented binary format, but it has been reverse engineered by both the wine and ReactOS folks, so those implementations should point you in the right direction.
- I'm not actually verifying the validty of the signature, although I give a pointer on how you would possibly do this.
Ok, now with disclaimers set aside, here are the steps:
- Extract the digital signature from the file. This post from Didier Stevens tells you how. What you need is actually the content after the DWORD containing the size and the marker (0x00020200). Just to be clear:
size DWORD = the size of the signature + 4 (the size DWORD) + 4 (the marker) actual signature = location specified by the data directory + 8 (marker + size)The actual signature is in DER format and is a standard PKCS7 signature, as Didier says (there are two standard file formats for PKCS7: DER - a binary format - and PEM - a text format - you will need this when specifying the input format for OpenSSL)
- To calculate the MD5/SHA1 hashes which match the one contained in the certificates, I've used the information from this mail by Peter Gutman. Basically, to calculate the matching hashes, you will need to exclude three fields from hashing: the checksum field and the address/size field from the security data directory. The area hashed ends before the location pointed by the
securityentry in the data directory. The digital signature should be last thing in the file. I didn't test the case when the digital signature is in the middle of the file, but I assume that either an erro is generated, or it is ignored as the afore mentioned three fields (I don't think that there is a security vulnerability which would result in
- The hashes calculated at the previous point should match the one printed out by the command:
openssl asn1parse -inform DER -in "signature.der"The signature can contain either a SHA1 or a MD5 hash. To dump the certificate tree, you can use the command:
openssl pkcs7 -inform DER -print_certs -text -in "signature.der"The first in the list is the one you need to trust (this is usually a big provider like Verisign / Thawte / Comodo / etc) and the last one is the actual signatory of the file.
- If you want to actually verify the signature, you need to create a copy of the file excluding the parts specified at step 2, and issue the command (taken from here):
openssl smime -verify -in signature.der -content modified_executable -inform DER -binary