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