[openssl-users] PKCS7->signerInfo->encryptedDigest not type X509_SIG

Jakob Bohm jb-openssl at wisemo.com
Fri Sep 11 13:07:20 UTC 2015


On 11/09/2015 12:30, Michael Heide wrote:
> Hi,
> I'm using OpenSSL to verify a (proprietary?) timestamp in Microsoft Authenticode via PKCS7_verify() (in pk7_smime.c).
According to my (initial) research, Microsoft Authenticode
uses two forms of timestamp unauthenticated attributes

Here is an excerpt from my draft specification so far:

...

7. Authenticode signatures SHOULD include a counterSignature attribute
   from a timestamping authority.

8. If there is a valid counterSignature from a timestamping authority
   and this counterSignature passes validation at the time when the
   countersigned signature is checked, and the countersigned signature
   itself was not made with a certificate with the KpLifetimeSigning
   extended key usage (OID 1.3.6.1.4.1.311.10.3.13), THEN the validity
   of the countersigned signature (and in particular the applicable
   certificates) SHOULD be checked as of the time specified by the
   Authenticated signingTime attribute found in the timestamping
   countersignature (not any other signingTime attributes found
   elsewhere in the overall signature structure).

9. If there is no valid counterSignature from a timestamping authority
   or that countersignature does not pass validation or
   KpLifetimeSigning was speficied, the signature SHOULD be checked as
   of the time when it is being checked.  The failure or omission of
   the counterSignature does not invalidate the signature itself (but
   may still cause it to be invalid due to certificate expiration or
   revocation).

10. Authenticode signatures SHOULD include a signingTime authenticated
   attribute (which will usually differ from that attribute in a
   counterSignature).  Recipients should treat this as for information
   only.

...

2.3 AuthentiCode Timestamp countersignature format
==================================================

AuthentiCode signatures typically include a counter signature from a
timestamping authority confirming that the signature was made on or
prior to a specific time.  This is done using a counterSignature
unauthenticated attribute of one of the following forms.

2.3.1 RFC2985 form Timestamp countersignature Attribute
=======================================================

This is a counter signature exactly as described in RFC2985 section
5.3.6 (OID 1.2.840.113549.1.9.6) with the following additional
constraints:

- The countersigning certificate MUST specify the timestamping
  extended key usage (OID 1.3.6.1.5.5.7.3.8)
- The countersigning SignerInfo MUST include a signingTime attribute
  (as defined in RFC2985 section 5.3.3, OID 1.2.840.113549.1.9.5)


2.3.2 RFC3161 form Timestamp countersignature Attribute
=======================================================

   rFC3161CounterSign = 1.3.6.1.4.1.311.3.3.1

   RFC3161CounterSign ::= TimeStampToken -- See RFC3161

The TimeStampToken must specify a messageImprint computed over the
content octets of the encryptedDigest field in the SignerInfo having
the attribute.

This is identical to the SignatureTimeStampToken attribute specified in
RFC3161 Appendix A, except that the OID differs.

This form is understood only by those Microsoft validation programs
that support SHA-2 or later hash algorithms.

Therefore AuthentiCode signatures using the SHA-1 hash algorithm
SHOULD use the RFC2985 timestamp countersignature format.
AuthentiCode signatures not inside an SpcAdditionalSignatures
attribute and made using the SHA-1 or MD5 hash algorithm SHOULD
AVOID using the RFC3161 timestamp counter signature format.


> Those Timestamps are inside a PKCS7 SignerInfo Structure (OpenSSL type PKCS7_SIGNER_INFO). I put those inside a PKCS7 to be able to use PKCS7_verify().
> Most of them are verified fine. In most cases the encryptedDigest structure inside (pkcs7_signer_info_st->enc_digest) corresponds to an OpenSSL type X509_SIG after decryption, which is an ASN.1 encoded Identifier+Hash (sha1,sha256,...). OpenSSL can parse them and use the hash aka message digest inside.
> But sometimes there is only the plain hash (sha1 usually) inside the decrypted "encryptedDigest". OpenSSL doesn't detect this. int_rsa_verify() simply tries to decode it via d2i_X509_SIG() which fails.
I have not encountered this before, which signing authority,
AlgorithmIdentifier and year (first digits of timestamp) did
you see this with?

Have you considered the possibility that this may be an
ISO/IEC 9796-1 or -2 signature (an old format broken in
1999 for 9796-1 and for 9796-2/MD5 and in 2009 for
9796-2/SHA-1)?

Or if neither of those ancient specs match that format, it
might besome other equally weak system, especially because
Authenticode-compatible timestamp authorities are the perfect
victims of chosen-message attacks such as those against ISO
9796-1/-2.

> The solution is simple. If there's only a hash inside, then after decryption and removing the rsa-padding the resulting structure has exactly the size of the expected hash (-> use the hash for comparison). In all other cases the decrypted ASN.1 structure must be bigger than the hash (including headers). This test is simple and fast, at least if it fails in the normal case.
> I've patched OpenSSL and it works. See Attachment.
> I don't think this is a bug inside OpenSSL. In fact, rfc2315 states the encrypted digest has to be a DigestInfo structure:
>    DigestInfo ::= SEQUENCE {
>       digestAlgorithm DigestAlgorithmIdentifier,
>       digest Digest }
> This corresponds to OpenSSLs X509_SIG.
> So I do not report it as a bug. Probably those Authenticode Timestamps are not standards compliant. Or the PKCS7 structure I'm creating around those SignerInfos is wrong/broken/incomplete. Or maybe my approach to use PKCS7_verify() for this is wrong? Thus I would like to share my experiences here.
> Nevertheless, if there are no regular cases where i equals m_len in int_rsa_verify(), then it shouldn't do any harm to include those changes in OpenSSL. (with added handling of rm!=NULL which is ignored so far, doesn't get used by RSA_verify(), simple to implement if needed)
> Regards
>
Due to the likely weakness of this scheme, acceptance should
be restricted to a very small number of specific signer
certificates, and further restricted to specific (claimed)
date ranges.  Though restricting the claimed date rangewill
have very little value, since if that authority signed just
a few timestamps requested by an attacker knowing the method
published in 1999, that attacker now has the ability to sign
anything using any old date as if he was that authority.

Enjoy

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



More information about the openssl-users mailing list