Eric Rescorla | 6 Apr 2007 20:30

AlgorithmIdentifier, SHA-1, etc.


I'm trying to get a handle on how one ought to encode AlgorithmIdentifier.

As people will perhaps remember, the ASN.1 is:

AlgorithmIdentifier  ::=  SEQUENCE  {
     algorithm               OBJECT IDENTIFIER,
     parameters              ANY DEFINED BY algorithm OPTIONAL  }
                                -- contains a value of the type
                                -- registered for use with the
                                -- algorithm object identifier value

Present hash functions do not take any useful parameters, leaving
us with two encoding options:

  - omit the parameter.
  - include a NULL

To make things more complicated, there are (at least) two different
contexts in which this production appears:

  - The S/MIME DigestAlgorithmIdentifier production.
  - Inside the DigestInfo of the S/MIME signature.

RFC 3370's guidance is to omit the parameter for SHA-1 and include
a NULL for MD5 (see S 2.1 and 2.2.).

However, the current PKCS#1 errata
(ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1errata.txt)
recommend that when one is encoding DigestInfo, one should
(Continue reading)

Peter Gutmann | 7 Apr 2007 09:01
Picon
Picon
Picon
Favicon

Re: AlgorithmIdentifier, SHA-1, etc.


Eric Rescorla <ekr <at> networkresonance.com> writes:

>So, what's the right answer here?

Read the OID and hash value, toss the rest.  Doing anything else is just
asking for trouble.

(There's really no question here: There are two ways to do this, knowing in
 advance what you'll encounter in the field isn't possible, so the only
 workable solution is to not compare the encoded value, or if you must,
 compare two pre-encoded alternatives for each possible hash algorithm.  This
 still breaks though if someone gets the encoding slightly wrong... comparing
 a pre-built value is just asking for trouble).

>My understanding from discussions in Prague is that this reflects NIST's
>current guidance as well.

This would put them in conflict with ISO, who (the last time I checked) say
the parameter should be omitted.  In any case though it doesn't really matter
which side wants to hold their breath the longest, if you read the OID and
hash and work with that you can't go wrong.

Peter.

Simon Josefsson | 9 Apr 2007 14:11
Favicon
Gravatar

Re: AlgorithmIdentifier, SHA-1, etc.


pgut001 <at> cs.auckland.ac.nz (Peter Gutmann) writes:

> Eric Rescorla <ekr <at> networkresonance.com> writes:
>
>>So, what's the right answer here?
>
> Read the OID and hash value, toss the rest.  Doing anything else is just
> asking for trouble.
>
> (There's really no question here: There are two ways to do this, knowing in
>  advance what you'll encounter in the field isn't possible, so the only
>  workable solution is to not compare the encoded value, or if you must,
>  compare two pre-encoded alternatives for each possible hash algorithm.  This
>  still breaks though if someone gets the encoding slightly wrong... comparing
>  a pre-built value is just asking for trouble).

That approach, to not validate the parameters field, is what led to
the variant of Bleichenbacher's attack in several TLS implementations.
I'm strongly opposed to permit this in conforming implementations.

Even if we restrict it to either absent parameters or NULL parameters,
that would enable a side-channel: you can "leak" one bit of
information by deciding which of NULL or absent you use.  It is not
clear to me how important that threat is.  There are other ways to
leak information in the TLS protocol (packet ordering, random values,
etc).  However, there may be some value in not expanding the ways to
leak information further.

I could live with MUST generate NULL parameters fields on encoding,
(Continue reading)

Eric Rescorla | 7 Apr 2007 16:30

Re: AlgorithmIdentifier, SHA-1, etc.


At Sat, 07 Apr 2007 19:01:26 +1200,
Peter Gutmann wrote:
> 
> 
> Eric Rescorla <ekr <at> networkresonance.com> writes:
> 
> >So, what's the right answer here?
> 
> Read the OID and hash value, toss the rest.  Doing anything else is just
> asking for trouble.
> 
> (There's really no question here: There are two ways to do this, knowing in
>  advance what you'll encounter in the field isn't possible, so the only
>  workable solution is to not compare the encoded value, or if you must,
>  compare two pre-encoded alternatives for each possible hash algorithm.  This
>  still breaks though if someone gets the encoding slightly wrong... comparing
>  a pre-built value is just asking for trouble).

Totally agree.

My question was more what we ought to recommend.

-Ekr

Russ Housley | 6 Apr 2007 22:09

Re: AlgorithmIdentifier, SHA-1, etc.


Note that the DigestInfoValue is part of the structure that is 
"encrypted" with the RSA private key when generating a signature.  It 
is recovered by "decrypting" the signature value with the RSA public key.

An implementation should check that the expected digest algorithm was 
used.  As Eric point out, this check is easier to perform if the two 
values are encoded in exactly the same manner.

One needs to look deeper into signatures in certificates and CMS 
SignerInfo to see where these comparisons are really performed.

The certificate signature has this structure:

    Certificate  ::=  SEQUENCE  {
         tbsCertificate       TBSCertificate,
         signatureAlgorithm   AlgorithmIdentifier,
         signatureValue       BIT STRING  }

In practice, the signature algorithm tells the digest algorithm as 
well as the digital signature algorithm. The ones that are relevant 
to this question are:

    sha1WithRSAEncryption
    sha224WithRSAEncryption
    sha256WithRSAEncryption
    sha384WithRSAEncryption
    sha512WithRSAEncryption

There is no filed that explicitly carries a digest algorithm 
(Continue reading)

Russ Housley | 6 Apr 2007 22:09

Re: AlgorithmIdentifier, SHA-1, etc.


Note that the DigestInfoValue is part of the structure that is 
"encrypted" with the RSA private key when generating a signature.  It 
is recovered by "decrypting" the signature value with the RSA public key.

An implementation should check that the expected digest algorithm was 
used.  As Eric point out, this check is easier to perform if the two 
values are encoded in exactly the same manner.

One needs to look deeper into signatures in certificates and CMS 
SignerInfo to see where these comparisons are really performed.

The certificate signature has this structure:

    Certificate  ::=  SEQUENCE  {
         tbsCertificate       TBSCertificate,
         signatureAlgorithm   AlgorithmIdentifier,
         signatureValue       BIT STRING  }

In practice, the signature algorithm tells the digest algorithm as 
well as the digital signature algorithm. The ones that are relevant 
to this question are:

    sha1WithRSAEncryption
    sha224WithRSAEncryption
    sha256WithRSAEncryption
    sha384WithRSAEncryption
    sha512WithRSAEncryption

There is no filed that explicitly carries a digest algorithm 
(Continue reading)

Dr Stephen Henson | 7 Apr 2007 13:39
Picon
Picon

Re: AlgorithmIdentifier, SHA-1, etc.


Russ Housley wrote:
> 
> Note that the DigestInfoValue is part of the structure that is
> "encrypted" with the RSA private key when generating a signature.  It is
> recovered by "decrypting" the signature value with the RSA public key.
> 

Note that care should be taken when handling the DigestInfo structure
recovered from an RSA signature.

As well as the original Bleichenbacher signature forgery attack (caused
by ignoring trailing garbage after DigestInfo) there is a variant which
inserts garbage in the middle of the recovered structure. Allowing
arbitrary parameter values in the DigestAlgorithmIdentifier (for example
large OCTET STRINGs) is one way to do this. Unlike the original attack
this variant produces a "valid" DigestInfo structure.

As a result in the specific case of the recovered DigestInfo from an RSA
signature OpenSSL now only tolerates a NULL or absent parameter field.
This is OK for all existing digests.

It is more liberal about DigestInfo structures in other contexts.

Steve.

Russ Housley | 8 Apr 2007 00:49

Re: AlgorithmIdentifier, SHA-1, etc.


Thanks for pointing this out.  I did say that you needed to make sure 
it was a valid parameter encoding, but I should have included this 
important additional information.  Thanks.

Russ

At 07:39 AM 4/7/2007, Dr Stephen Henson wrote:

>Russ Housley wrote:
> >
> > Note that the DigestInfoValue is part of the structure that is
> > "encrypted" with the RSA private key when generating a signature.  It is
> > recovered by "decrypting" the signature value with the RSA public key.
> >
>
>Note that care should be taken when handling the DigestInfo structure
>recovered from an RSA signature.
>
>As well as the original Bleichenbacher signature forgery attack (caused
>by ignoring trailing garbage after DigestInfo) there is a variant which
>inserts garbage in the middle of the recovered structure. Allowing
>arbitrary parameter values in the DigestAlgorithmIdentifier (for example
>large OCTET STRINGs) is one way to do this. Unlike the original attack
>this variant produces a "valid" DigestInfo structure.
>
>As a result in the specific case of the recovered DigestInfo from an RSA
>signature OpenSSL now only tolerates a NULL or absent parameter field.
>This is OK for all existing digests.
>
(Continue reading)

Russ Housley | 8 Apr 2007 00:49

Re: AlgorithmIdentifier, SHA-1, etc.


Thanks for pointing this out.  I did say that you needed to make sure 
it was a valid parameter encoding, but I should have included this 
important additional information.  Thanks.

Russ

At 07:39 AM 4/7/2007, Dr Stephen Henson wrote:

>Russ Housley wrote:
> >
> > Note that the DigestInfoValue is part of the structure that is
> > "encrypted" with the RSA private key when generating a signature.  It is
> > recovered by "decrypting" the signature value with the RSA public key.
> >
>
>Note that care should be taken when handling the DigestInfo structure
>recovered from an RSA signature.
>
>As well as the original Bleichenbacher signature forgery attack (caused
>by ignoring trailing garbage after DigestInfo) there is a variant which
>inserts garbage in the middle of the recovered structure. Allowing
>arbitrary parameter values in the DigestAlgorithmIdentifier (for example
>large OCTET STRINGs) is one way to do this. Unlike the original attack
>this variant produces a "valid" DigestInfo structure.
>
>As a result in the specific case of the recovered DigestInfo from an RSA
>signature OpenSSL now only tolerates a NULL or absent parameter field.
>This is OK for all existing digests.
>
(Continue reading)

Eric Rescorla | 7 Apr 2007 16:30

Re: AlgorithmIdentifier, SHA-1, etc.


At Sat, 07 Apr 2007 12:39:07 +0100,
Dr Stephen Henson wrote:
> 
> 
> Russ Housley wrote:
> > 
> > Note that the DigestInfoValue is part of the structure that is
> > "encrypted" with the RSA private key when generating a signature.  It is
> > recovered by "decrypting" the signature value with the RSA public key.
> > 
> 
> Note that care should be taken when handling the DigestInfo structure
> recovered from an RSA signature.
> 
> As well as the original Bleichenbacher signature forgery attack (caused
> by ignoring trailing garbage after DigestInfo) there is a variant which
> inserts garbage in the middle of the recovered structure. Allowing
> arbitrary parameter values in the DigestAlgorithmIdentifier (for example
> large OCTET STRINGs) is one way to do this. Unlike the original attack
> this variant produces a "valid" DigestInfo structure.
> 
> As a result in the specific case of the recovered DigestInfo from an RSA
> signature OpenSSL now only tolerates a NULL or absent parameter field.
> This is OK for all existing digests.
> 
> It is more liberal about DigestInfo structures in other contexts.

Steven,

(Continue reading)

Dr Stephen Henson | 7 Apr 2007 19:07
Picon
Picon

Re: AlgorithmIdentifier, SHA-1, etc.


Eric Rescorla wrote:
> At Sat, 07 Apr 2007 12:39:07 +0100,
> Dr Stephen Henson wrote:
>>
>> Russ Housley wrote:
>>> Note that the DigestInfoValue is part of the structure that is
>>> "encrypted" with the RSA private key when generating a signature.  It is
>>> recovered by "decrypting" the signature value with the RSA public key.
>>>
>> Note that care should be taken when handling the DigestInfo structure
>> recovered from an RSA signature.
>>
>> As well as the original Bleichenbacher signature forgery attack (caused
>> by ignoring trailing garbage after DigestInfo) there is a variant which
>> inserts garbage in the middle of the recovered structure. Allowing
>> arbitrary parameter values in the DigestAlgorithmIdentifier (for example
>> large OCTET STRINGs) is one way to do this. Unlike the original attack
>> this variant produces a "valid" DigestInfo structure.
>>
>> As a result in the specific case of the recovered DigestInfo from an RSA
>> signature OpenSSL now only tolerates a NULL or absent parameter field.
>> This is OK for all existing digests.
>>
>> It is more liberal about DigestInfo structures in other contexts.
> 
> Steven,
> 
> As I recall OpenSSL puts the NULL in the digestAlgorithm encoding
> as well. Am I right about that? 
(Continue reading)

Blake Ramsdell | 6 Apr 2007 22:02
Favicon

Re: AlgorithmIdentifier, SHA-1, etc.


Eric Rescorla wrote:
> Technically these don't conflict, but obviously, it's undesirable to
> have the encoding in the message not match that in the DigestInfo,
> since doing binary comparisons is common practice here. So, what's the
> right answer here?

In my case when I receive a digest AlgorithmIdentifier, I bust it open 
and get the OID out and discard the wrapper (the outer 
AlgorithmIdentifier). So I'm not affected by a mismatch if I do that.

But yeah, short of normalizing the values in some way, you're pretty 
much done. That is, there's no binary comparison, and you perform an 
equivalence check by converting both values in such a way that the same 
answer comes out. So if you have { sha-1, NULL } and { sha-1 } you get 
the same answer.

Blake
--

-- 
Blake Ramsdell | Sendmail, Inc. | http://www.sendmail.com

Eric Rescorla | 6 Apr 2007 22:09

Re: AlgorithmIdentifier, SHA-1, etc.


At Fri, 06 Apr 2007 13:02:58 -0700,
Blake Ramsdell wrote:
> 
> Eric Rescorla wrote:
> > Technically these don't conflict, but obviously, it's undesirable to
> > have the encoding in the message not match that in the DigestInfo,
> > since doing binary comparisons is common practice here. So, what's the
> > right answer here?
> 
> In my case when I receive a digest AlgorithmIdentifier, I bust it open 
> and get the OID out and discard the wrapper (the outer 
> AlgorithmIdentifier). So I'm not affected by a mismatch if I do that.
> 
> But yeah, short of normalizing the values in some way, you're pretty 
> much done. That is, there's no binary comparison, and you perform an 
> equivalence check by converting both values in such a way that the same 
> answer comes out. So if you have { sha-1, NULL } and { sha-1 } you get 
> the same answer.

Yeah, my thinking is that it would be better for these to match
so that naive implementations work.

-Ekr


Gmane