On 07/09/2014 05:43, Prasad Dabak wrote:
Hello,

Given a signed Windows portable executable, I want to programmatically verify two things using openssl APIs

1. Verify the digital signature.
2. Confirm that the executable is signed by a specific company using that company's public key.

It seems that part (1) can be done by parsing the signedData attribute in the portable executable, extracting the hashing algorithm and digest stored there, re-computing the digest of the executable using the same hashing algorithm and match them.

I have following questions.

1. The signData contains messageDigest (unencrypted) and encryptedDigest (encrypted). Is it enough to match messgaeDigest with the computed digest? OR we also need to decrypt the encryptedDigest using the company public key and match that as well?
Both.

Comparing the stored messageDigest to the actual digest in the
spcIndirectDataContext structure checks that the signature
actually is for this file.  Note that Authenticode defines a
specific file format specific "formula" for omitting the
signature itself from the input to the message digest.

Decrypting the "encryptedDigest" (really validating the
signedDigest against a digest of the relevant part of the PKCS#7
structure, the field name is historic) is necessary to check if
the signature is a valid signature made with the expected public
key.  This step is, technically, the actual signature
verififcation, but it is meaningless without all the other checks.

Additionally, for Authenticode, you need to do a few extra things
(that should be done *first*, since they are cheaper than the
actual signature check, and one of them affects the signature
check):

- Verify that the PKCS#7 structure field contentInfo is a
 spcIndirectDataContext structure containing a list of attributes.
 This is consistent with the original PKCS#7 standard/RFC, but
 not entirely with the later e-mail focused CMS standard/RFC.
- Verify that the spcIndirectDataContext structure includes the
 correct set of magic attributes for the file type, as otherwise,
 the signature is not for this file even if the digest value
 matches.  These fields indicate the choice of "formula" ("Subject
 Identification Package") for determining the subset of file bytes
 to pass the the message digest.In particalar, if the spcSipInfo
 field is present it must have the correct value, and check the
 presence of any other file format specific attributes (for PE
 EXE/DLL/OCX/SYS files, this means an spcPEImageData attribute
 of a very specific form that includes the BMPString
 "<<<Obsolete>>>" to distinguish it from the historic Authenticode1
 signatures).
- Verify that the spcIndirectDataContext structure includes an
 attribute whose OID is the OID of a hash algorithm and contains
 the number of bytes for that type of message digest, and matches
 your own calculation of that message digest of the file type
 specific subset of bytes of the file itself.
- Verify that each signerInfo in signerInfos has at least the
 following authenticated attributes: contentType ==
 spcIndirectDataContext and a messageDigest (see also answer 2) .
 Other authenticated attributes are usually present, but not
 mandatory.
- If there is an authenticated attribute of type spcSpOpusInfo, you
 may want to consider this the file description and information URL
 from the manufacturer who signed this signerInfo, but only after
 all the checks pass.
- If a signerInfo contains one or more unauthenticatedAttributes
 of type counterSignature, those should be validated first as being
 valid signerinfos for signatures of the encryptedDigest of the outer
 signerinfo.  If one of them is, and contains an (inner)
 authenticatedAttribute of type signingTime that countersignature is
 for an entity whose certificate in the certificates collection is
 valid for extended usage purpose "timeStamping" (including a
 recursive requirement that this purpose is also present for its
 issuer), then the time indicated by that signingTime field overrides
 the value of the local clock when determining the validity of the
 certificates for the signature on that particular outer signerinfo.
- Other spcIndirectDataContext attributes,
 unauthenticatedAttributes and/or authenticatedAttributes are
 usually present, but are not mandatory.  An attribute present
 in the wrong of the attribute lists should also be ignored.
 For example a signingTime in the outer signerinfo cannot be used
 to set the time used for the validity checks of that outer
 signerinfo.
- Verify that each of the outer signerinfos refers to a signature
 in the certificates collection which is valid for the extended
 usage purpose of "Code Signing" and a basic constraint of CA:FALSE.
 This check may fail for some test signatures, but should not fail
 for real signatures made with officially issued certificates.
 This check can be done during the PKCS7_verify call via callbacks
 etc.

2. What does PKCS7_Verify exactly do? I looked at https://www.openssl.org/docs/crypto/PKCS7_verify.htmland I understand that it verifies certificate chain. However, it's not clear to me as to what exactly it does with respect to signature verification?
I think it also verifies that the signerinfo refers to a certificate
that can be traced via the included certificates collection to one of
the loaded certificate authority root certificates.  And that the
encryptedDigest actuallymatches a locally computed digest of the
authenticatedAttributes and that the messageDigest
authenticatedAttribute matches a locally computed digest of the
contentInfo.  It doesn't know about spcIndirectDataContext and the
attributes therein, so it won't check that.  Also, it currently
doesn't know about time stamping counterSignatures, so you have to
implement that yourself, including the possible use of a different
time during the certificate validations.

It is critical that you pass the verification functions both the CA
certificates and up to date CRLs for both the CAs and for any
intermediary CAs found in the PKCS#7 certificates collection.
Otherwise you may end up believing certificates made with stolen
keys, such as the stolen key that was used to sign the StuxNet
malware.  The OpenSSL code will happily verify signatures without a
CRL, but the result may be catastrophically wrong.

3. I am assuming that I require to do both (1) and (2) in order to verify the authenticode signature?
Yes.
4. What is the best way to verify if the executable is signed by specific company using that company's public key?

Perform all of the above checks, and also check that the Subject of
the certificate referenced in the signerInfo you check is that
company and that that particular certificate was issued by the
certificate authority known to be used by that company (if you happen
to know which one they prefer to use, for example Microsoft uses
certificates issued by their own CA, at least recently).
Any inputs will be greatly appreciated!

Additionally, note that many Microsoft files, and many device
drivers, are signed ina slightly different way.  There is (in a
specific subdirectory of the Windows dir)a ".cat" file which
contains a list of file hashes (each computed in the same way
as a hash in an spcIndirectDataContext) for unspecified files.
That .cat file is itselfsigned by either Microsoft or the
manufacturer in the same way as described above,but with
details indicating that this is a signature for the .cat file.
For each valid.cat file, you need to add the listed hashes
to your own list of file hashes that indicate thata file with
any of those hashes should be considered signed by the company
that signed the .cat file, even if it doesn't contain such a
signature itself.

Also note that for drivers, it is often the case that the driver
files themselves aresigned by the company that made them, but
the .cat file is signed by the Microsoftdepartment that manages
the list of "certified compatible" drivers.  This is called
WHQL signing.

Signatures on installed kernel mode .SYS, .DLL and other such files
often containan extra "cross certificate" in their certificates
collection, issued by"Microsoft Code Verification Root" to the
actual CA that issued the companycertificate. This is because
the signature checking code in Microsoft's bootloaderonly knows
about that Microsoft CA.

Enjoy and good luck

Jakob
--
Jakob Bohm, CIO, Partner, WiseMo A/S.  http://www.wisemo.com
Transformervej 29, 2860 Søborg, Denmark.  Direct +45 31 13 16 10
This public discussion message is non-binding and may contain errors.
WiseMo - Remote Service Management for PCs, Phones and Embedded


Reply via email to