4

I am trying to verify the certificates/signatures of a a PE file with OpenSSL (or actually with Python, but it seems like Python sucks regarding certificate handling).

I have extracted the DER PKCS7 certificate from the PE file as described here: http://blog.didierstevens.com/2008/01/11/the-case-of-the-missing-digital-signatures-tab/

And I have created a modified version of the PE file without the checksum and signature data, like described here: http://www.mail-archive.com/cryptography@c2.net/msg04202.html

The sha1sum of the modified file is the same as the sha1sum in the certificate.

I have tried to verify the unsigned, modified PE file with openssl as such: openssl smime -verify -in signature.der -content modified_executable.exe -inform DER -binary But I only get

Verification failure 140415508248232:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:342:Verify error:unsupported certificate purpose

If i add -noverify to the command I just get

Verification failure 140595583981224:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:pk7_doit.c:1097: 140595583981224:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:pk7_smime.c:410:

What am I missing?

jww
  • 97,681
  • 90
  • 411
  • 885
espenfjo
  • 200
  • 1
  • 3
  • 9
  • Also see [Verifying Authenticode signed executables and DLLs using OpenSSL API](https://stackoverflow.com/questions/12909102/verifying-authenticode-signed-executables-and-dlls-using-openssl-api). But its lite on implementation details. – jww Mar 13 '14 at 07:47
  • Need to do it with the openssl CLI as the system doing this written in python, and I cannot easily call the openssl C API functions from there. – espenfjo Mar 13 '14 at 09:02
  • What kind of signature? Is it an Authenticode signature? If so, then see [Verifying Authenticode signed executables and DLLs using OpenSSL API](http://stackoverflow.com/q/12909102) and [Verify Authenticode signature as being from our company for automatic updater](http://stackoverflow.com/q/4595537). Also see Microsoft's [Windows Authenticode Portable Executable Signature Format](http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx). – jww Mar 15 '15 at 22:08
  • I've updated my answer substantially. Please vote up if it works for you. – guest Mar 19 '15 at 15:04
  • _it seems like Python sucks regarding certificate handling_ - M2Crypto has reasonably good support for certificate handling and provides PKCS#7 verification functions. Since commit 03eb29d10 you can even set a custom verification callback to ignore the "unsupported certificate purpose" error. – Konstantin Shemyak Jan 02 '17 at 10:04

4 Answers4

2

Assumption: the following is done on Cygwin with OpenSSL 0.9.8e

For the "unsupported certificate purpose", the immediate signer may have no S/MIME purpose.

From OpenSSL documentation:
-purpose purpose
    the intended use for the certificate. Without this option no chain verification will be done.
$ openssl x509 -purpose -in goodcert.pem -noout
Certificate purposes:
SSL client : No
SSL client CA : No
SSL server : No
SSL server CA : No
Netscape SSL server : No
Netscape SSL server CA : No
S/MIME signing : No
S/MIME signing CA : No
S/MIME encryption : No
S/MIME encryption CA : No
CRL signing : No
CRL signing CA : No
Any Purpose : Yes
Any Purpose CA : Yes

With reference to this, I added the switch "-purpose any". Then I no longer see "unsupported certificate purpose" but still encounter same digest & signature failures as you.

1900:error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure:pk7_doit.c:948:
1900:error:21075069:PKCS7 routines:PKCS7_verify:signature failure:pk7_smime.c:312:

With hints from this and lots of research(#1,#2), it turns out the input "modified_exe" to -content was wrong. It should have been the content field in the Sequence ContentInfo of the PKCS #7 SignedData, excluding its DER tag and length bytes.
Refer to Authenticode_PE.docx for the declaration of SignedData.
(simply too much details I don't see fit including!)

Check below for clarity:

openssl asn1parse -inform der -in signature.der > signature.txt
head signature.txt -n30
    0:d=0  hl=4 l=5464 cons: SEQUENCE          
    4:d=1  hl=2 l=   9 prim: OBJECT            :pkcs7-signedData
   15:d=1  hl=4 l=5449 cons: cont [ 0 ]        
   19:d=2  hl=4 l=5445 cons: SEQUENCE          //SignedData
   23:d=3  hl=2 l=   1 prim: INTEGER           :01 //Version
   26:d=3  hl=2 l=  11 cons: SET               //DigestAlgorithmIdentifiers
   28:d=4  hl=2 l=   9 cons: SEQUENCE          
   30:d=5  hl=2 l=   5 prim: OBJECT            :sha1
   37:d=5  hl=2 l=   0 prim: NULL              
   39:d=3  hl=2 l= 104 cons: SEQUENCE          //ContentInfo
   41:d=4  hl=2 l=  10 prim: OBJECT            :1.3.6.1.4.1.311.2.1.4 //ContentType
   53:d=4  hl=2 l=  90 cons: cont [ 0 ]        
   55:d=5  hl=2 l=  88 cons: SEQUENCE          //SpcIndirectDataContent (exclude this tag and length bytes)
   57:d=6  hl=2 l=  51 cons: SEQUENCE          //SpcAttributeTypeAndOptionalValue
   59:d=7  hl=2 l=  10 prim: OBJECT            :1.3.6.1.4.1.311.2.1.15 //ObjectID
   71:d=7  hl=2 l=  37 cons: SEQUENCE          
   73:d=8  hl=2 l=   1 prim: BIT STRING        
   76:d=8  hl=2 l=  32 cons: cont [ 0 ]        
   78:d=9  hl=2 l=  30 cons: cont [ 2 ]        
   80:d=10 hl=2 l=  28 prim: cont [ 0 ]        
  110:d=6  hl=2 l=  33 cons: SEQUENCE          //DigestInfo
  112:d=7  hl=2 l=   9 cons: SEQUENCE          //AlgorithmIdentifier
  114:d=8  hl=2 l=   5 prim: OBJECT            :sha1 //ObjectID
  121:d=8  hl=2 l=   0 prim: NULL              
  123:d=7  hl=2 l=  20 prim: OCTET STRING      [HEX DUMP]:<hash of modified_exe> //digest OCTETSTRING
  145:d=3  hl=4 l=4774 cons: cont [ 0 ]        
  149:d=4  hl=4 l=1332 cons: SEQUENCE          
  153:d=5  hl=4 l= 796 cons: SEQUENCE          
  157:d=6  hl=2 l=   3 cons: cont [ 0 ]        
  159:d=7  hl=2 l=   1 prim: INTEGER           :02

The byte stream from offset 57 to 144 is the correct input to -content!
Exact offset depends on your file.
As a rough guidance, 2 lines before "1.3.6.1.4.1.311.2.1.15" is the "SpcIndirectDataContent", on this line notice that 55+2+88-1=144. the next line start from 57.

final cmd:

openssl smime -verify -inform DER -in signature.der -binary -content signedData -CAfile myCA.crt -purpose any -out tmp

Community
  • 1
  • 1
guest
  • 224
  • 1
  • 10
1

Verification failure 140415508248232:error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error:pk7_smime.c:342:Verify error:unsupported certificate purpose

As already pointed by @guest, OpenSSL has a "feature" when verifying smime (or cms): it behaves as though -purpose smimesign has been passed. Details on this here.

If your signing certificate is not compatible with OpenSSL's smimesign "purpose" (see man x509, section CERTIFICATE EXTENSIONS for list of "purposes"), then you'd have to disable extensions checking with -purpose any (and check them with other functions if your policy requires that).

If i add -noverify to the command

You probably do not want to. This option disables any checks on the signer's certificate.

Konstantin Shemyak
  • 2,369
  • 5
  • 21
  • 41
0

And I have created a modified version of the PE file without the checksum and signature data, like described here: http://www.mail-archive.com/cryptography@c2.net/msg04202.html

Why not just use Microsoft's published format? There's no need to resort to reverse engineering.


What am I missing?

A PE/PE+ executable has parts of its file signed, and not the whole file. When digesting data, you have to omit the checksum from the OptionalHeader, omit the certificates table from the Data Directory, and omit the Attribute Certificate Table section.

Here are two references you might want to get familiar with:

The sections to omit are shown in Windows Authenticode Portable Executable Signature Format, page 6. Its reproduced below.

enter image description here


If you need help walking the PE file format programmatically, see Matt Pietrek's An In-Depth Look into the Win32 Portable Executable File Format from MSDN magazine.

jww
  • 97,681
  • 90
  • 411
  • 885
  • As I wrote in the question I have stripped away the parts that is not signed, and the hash of the modified file is the same as the hash in the extracted certificate. – espenfjo Mar 13 '14 at 09:01
0

the hash of the modified file is the same as the hash in the extracted certificate

My bad. I missed that part.

Here's where you are failing in pk7_smime.c. Its the line i = X509_verify_cert:

i = X509_verify_cert(&cert_ctx);
if (i <= 0) j = X509_STORE_CTX_get_error(&cert_ctx);
X509_STORE_CTX_cleanup(&cert_ctx);
if (i <= 0) {
    PKCS7err(PKCS7_F_PKCS7_VERIFY,PKCS7_R_CERTIFICATE_VERIFY_ERROR);
    ERR_add_error_data(2, "Verify error:",
        X509_verify_cert_error_string(j));
    sk_X509_free(signers);
    return 0;
}

X509_verify_cert is in <openssl dir>/crypto/x509/x509_vfy.c around line 150. Its a rather large function (about 250 lines), so you're probably going to need to walk through it.

Before you walk the function, you might try adding -signer option to openssl smime function. It could be a simple fix. See the OpenSSL docs on simime(3).

I don't know where to get the signing certificate since its not in front of me and searching for "Microsoft Code Signing CA" is producing too much noise. Dump the end entity cert, find the issuer, and then do a search for the issuer's name.

jww
  • 97,681
  • 90
  • 411
  • 885
  • The Signer cert is probably part of the signature entry in the file. For dropbox.exe it has the following certificates:http://pastebin.com/wYPndWb9 – espenfjo Mar 13 '14 at 13:12
  • "Issuer: /C=US/O=Thawte, Inc./CN=Thawte Code Signing CA - G2". But its not offered for download at [Thawte Root Certificates](http://www.thawte.com/roots/). A company called TBS Internet has the certifcates posted at http://www.tbs-certificates.co.uk/FAQ/en/577.html. – jww Mar 13 '14 at 13:22
  • But it is in the file."Subject: /C=US/O=Thawte, Inc./CN=Thawte Code Signing CA - G2" "Issuer : /C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA" all up to Western Cape – espenfjo Mar 13 '14 at 16:14
  • Perhaps you can try with [`cms(1)`](http://www.openssl.org/docs/apps/cms.html) and the `-CAfile` option. In this case, I would try to save the Thawte root and explicitly provide it to `openssl cms -verify`. Sorry I can't be of more help. – jww Mar 13 '14 at 16:20