pythonopensslcertificatesignatureauthenticode

Verify signature of PE file


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?


Solution

  • 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