Subject: Questions on digest and signature algorithm identifiers in CMS

From: "Julien Stern" <[email-masked]>
Date: Fri, 19 Jan 2007 11:00:21 +0100

Folks,

I have a few questions regarding the interpretation of the algorithm
identifiers used in CMS in the SignerInfo structure.

SignerInfo ::= SEQUENCE {
	version CMSVersion,
	sid SignerIdentifier,
	digestAlgorithm DigestAlgorithmIdentifier,
	signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
	signatureAlgorithm SignatureAlgorithmIdentifier,
	signature SignatureValue,
	unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }

This structure includes both a digestAlgorithm and a signatureAlgorithm,
and there are two cases: either signedAttrs are present or not.

Let us first look at case 1, signedAttrs are present.
In that case, we hash the content with the "digestAlgorithm",
and then compute the signature on the DER of signedAttrs with
"signatureAlgorithm".

My first question is: is it authorized to have a _different_
hash function is the digestAlgorithm and the signatureAlgorithm ?
For instance, can I hash the content with MD5 and sign the signedAttrs
with "RSA-SHA1" ? How about PSS ? About about the general case ?

Now, in case 2, we have both a hash function defined in "digestAlgorithm"
and a hash function (implicitely defined) in "signatureAlgorithm"
(except for the special "rsaEncryption" identifier).

In that case, is it authorized to have a _different_ hash function
in digestAlgorithm and signatureAlgorithm ? And if so, how to interpret
it ? Assuming I have MD5 for the digest and RSA-SHA1
for the signature, should I interpret it as a RSA-MD5 signature ?
As a RSA-SHA1 signature ? Or should I consider the CMS as invalid ?
Is there a general rule ?

Thank you very much for your clarifications.

Regards,

--
Julien Stern

---

From: Russ Housley <[email-masked]>
Date: Fri, 19 Jan 2007 12:08:29 -0500

Julien:

Does the examples document (RFC 4134) help answer your questions?

Russ

---

From: "Julien Stern" <[email-masked]>
Date: Fri, 19 Jan 2007 18:53:15 +0100

> Does the examples document (RFC 4134) help answer your questions?

Russ,

unfortunately, they do not. As far as I have seen, they use either
'sha1' as the digestAlgorithm and 'dsaWithSha1' as the signature
algorithm or 'sha1' as the digestAlgorithm and 'rsaEncryption' as
the signature algorithm.

So either there is the "magic" OID rsaEncryption, which is not a
real signature OID, or the hash function defined in 'dsaWithSha1'
matches 'sha1'.

To present my question is a possibly more constructive way,
please find below two snippets of what could be clarifications
to CMS signatures from my humble point of view.

The list could then tell me which snippet is the "correct" one,
and decide whether it could be regarded as a worthwhile addition
to one of the WG document or not.

Regards,

--
Julien

Possible clarification 1:
-------------------------

The signatureAlgorithm field in SignerInfo should be interpreted
in a special way inside CMS. It may either contain a fully-fledged
signature algorithm, or the special OID rsaEncryption.

When it contains a fully-fledged algorithm, the digestAlgorithm
MUST be coherent with the digest used in the signatureAlgorithm
(e.g. if the signature algorithm is RSA with SHA-1, the digestAlgorithm
MUST be SHA-1, otherwise the verification fails).

When it contains the special OID rsaEncryption, the full signature
algorithm is defined by looking the digestAlgorithm and will
be an RSA PKCS1.5 signature with the hash function specified
in digestAlgorithm.

Possible clarification 2:
-------------------------

The signatureAlgorithm field in SignerInfo should be interpreted
in a special way inside CMS. It may either contain a fully-fledged
signature algorithm, or the special OID rsaEncryption and should be
interpreted differently depending on whether signedAttrs are present
or not.

When signedAttrs are present and a fully-fledged signatureAlgorithm
is present, the digestAlgorithm is only used to hash the content,
and the fully-fledged algorithm is used to sign the signedAttrs.
Therefore, it is possible to have MD5 as the digestAlgorithm
and RSA with SHA-1 as the signature algorithm.

When the signedAttrs are present and the special OID rsaEncryption
is present, the digestAlgorithm is used to hash the content,
and an RSA PKCS1.5 signature with the hash function specified in
digestAlgorithm is used to sign the signedAttrs.

When signedAttrs are not present and a fully-fledged signatureAlgorithm
is present, the digestAlgorithm MUST be coherent with the digest used
in the signatureAlgorithm (e.g. if the signature algorithm is RSA with
SHA-1, the digestAlgorithm MUST be SHA-1, otherwise the verification fails).

Finally, when signedAttrs are not present and the special OID rsaEncryption
is present, the full signature algorithm on the content is defined by
looking the digestAlgorithm and will be an RSA PKCS1.5 signature with the
hash function specified in digestAlgorithm.

---

From: Russ Housley <[email-masked]>
Date: Wed, 24 Jan 2007 19:40:40 -0500

Neither of them seem right to me.  Please review section 3 of RFC 3370.

Russ

---

From: "Julien Stern" <[email-masked]>
Date: Thu, 25 Jan 2007 10:03:19 +0100

Russ,

section 3 of RFC3370 is silent on this (and so it 3852 actually).
RFC3370 says that

  "CMS implementations MAY support RSA (PKCS#1 v1.5) signature value
  algorithm identifiers that specify both the RSA (PKCS #1 v1.5)
  signature algorithm and the message digest algorithm."

But it does not say what to include in the digestAlgorithm in that case.
And it seems that RFC3852 and RRFC4056 have different views on this:

RFC3852 says (page 13):

  "digestAlgorithm identifies the message digest algorithm, and any
  associated parameters, used by the signer.  The message digest is
  computed on either the content being signed or the content
  together with the signed attributes using the process
  described in section 5.4."

  ==> This seems to imply that __THE SAME__ digest must be used for
      content and signed attributes

But RFC4056 says (page 3):

  "The same one-way hash function SHOULD be used for computing the
  message digest on both the eContent and the signedAttributes value
  if signedAttributes exist."

  ==> This seems to imply that __DIFFERENT__ digests may be used for
      content and signed attributes

I was simply wondering which RFC was correct.

Regards,

--
Julien

---

From: Russ Housley <[email-masked]>
Date: Thu, 25 Jan 2007 12:04:10 -0500

I think it is clear that they SHOULD be the same.  That is, without a 
really good reason, use the same one-way hash function in both 
places.  I do not know of any case in the real world where they are different.

Russ

---

From: "Julien Stern" <[email-masked]>
Date: Thu, 25 Jan 2007 18:44:18 +0100

Russ,

OK. I agree they SHOULD be the same. I'm simply asking whether or not
they MUST be the same. And if not, what an implementation is
supposed to do when it receives a CMS object where there are NOT the
same ?

- Consider the signature invalid ?
- Ignore the hash function in the digestAlgorithm ?
- Ignore the hash function in the signatureAlgorithm ?
- If signedAtts are present, use the digestAlgorithm for them,
  then use the signatureAlgorithm for the signedAtts ? Otherwise fail ?

--
Julien

---

From: Russ Housley <[email-masked]>
Date: Thu, 25 Jan 2007 14:04:10 -0500

I cannot imagine a situation where they are not the same.

The SigenedData carries a set of digest algorithm identifiers, this 
allows there to be more than one SignerInfo that contain different 
digest algorithms.  The SignerInfor carries a single digest algorithm 
identifier.  It MUST be one of the ones listed in the 
SignedData.  That digest algorithm is used to hash the content to an 
to hash the attributes.  The second one being the digest value that 
is actually signed.

Russ

---

From: "Julien Stern" <[email-masked]>
Date: Fri, 26 Jan 2007 12:00:31 +0100

Russ,

first, I just wanted to say I appreciate that you are taking the time
to reply to my emails and possibly weird questions.

My intent is not to do CMS bashing, to claim there is a mistake,
or to ask for a new version of some documents. I am also not
trying to pinpoint an issue in CMS due to a theoretical situation.

I am just faced with a simple practical problem, namely: what is an
implementation supposed to do when it receives a CMS message where
the hash function in the digestAlgorithm and the signedAlgorithm
are not the same?  I mean, there must be quite a large number of CMS
implementations that were faced with the same problem!

I would also understand that you do not wish to commit to a definitive
answer on this question, so unless you (or someone else on the list)
says otherwise, I think I will just consider the message as "malformed"
if such a case arises.

However, I still generally believe that the current versions of the
RFCs do not provide enough guidance for _verification_ of a CMS
signature, most notably in the bordercase situations.

It might be a good idea to use one of the current draft (cms-mult-sign ?)
to answer the two following simple questions:

- Is it or is it not allowed at all to have different hash functions
in the digestAlgorithm and the signatureAlgorithm?

- What should be the behavior of a verification algorithm which is
faced with such a situation?

Regards,

--
Julien

---

From: Blake Ramsdell <[email-masked]>
Date: Fri, 26 Jan 2007 04:02:28 -0800

> implementations that were faced with the same problem!

OK, so let's see what we've got here. In the SignerInfo we have:

digestAlgorithm DigestAlgorithmIdentifier

and

signatureAlgorithm SignatureAlgorithmIdentifier

The intent is that digestAlgorithm act as a hint for implementors so 
that one-pass processing of the signature is possible. So in the event 
that there is a signedAttrs member (likely) that you digest it with the 
correct algorithm so that when you get to the signature, you will be 
ready to go with a completed digest so you verify the signature. This is 
purely for convenience.

This is the reason for the digestAlgorithms field in the SignedData 
structure also. The encapContentInfo needs to get digested with some 
algorithm(s), so you could use a hint as to which ones might be used.

Now, if the sending implementation or an intermediate agent (including 
an adversary) is a jerk, this digest algorithm hints might be 
inconsistent with the algorithm required for the signature validation, 
which I think is your concern.

There's no way around this potential inconsistency.

Now, a "tough guy" implementation might take the precaution that every 
other implementation is crazy, and digest with every algorithm that they 
understand. In my case, I always digest with MD5 and SHA-1. So I 
personally don't listen to the digestAlgorithms field in SignedData or 
the digestAlgorithm field in SignerInfo. When I get to the signature 
verification, I say "OK, so which digest do I need" and use the right 
one (or freak out if it's not one of those). So I never have the 
heartache of betrayal from these fields, at the acceptable (in my case) 
cost of performance.

> says otherwise, I think I will just consider the message as "malformed"

Personally, I think that's reasonable. Not "liberal", but reasonable.

> in the digestAlgorithm and the signatureAlgorithm?

The description of the field is that it "identifies the message digest 
algorithm, and any associated parameters, used by the signer". If the 
value of this field doesn't meet this criteria, then I'd say "sending 
implementation broken" or "contents modified in a broken way in 
transit". So it's implicitly not allowed -- the spec says to indicate 
the algorithm that you used and that apparently didn't happen.

Being crabby about an inconsistency between the digest algorithm hints 
given previously and the signatureAlgorithm field of the SignerInfo is a 
thing to do, but I don't think it's productive. Your implementation may 
not afford you the luxury of digesting with every algorithm, in which 
case you need to hope for the best I guess.

> faced with such a situation?

Not sure if it's specified anywhere, but that's up to the implementation 
I would say.

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

---

From: "Julien Stern" <[email-masked]>
Date: Fri, 26 Jan 2007 15:42:26 +0100

On Fri, Jan 26, 2007 at 04:02:28AM -0800, Blake Ramsdell wrote:
> [snip]

Blake,

Thank you for your input.
I like your interpretation (considering the digest as a pure hint) too.

> Not sure if it's specified anywhere, but that's up to the implementation 

OK. I guess I have my answer :) So, I'll go for either "reject"
or "use only digests as a hint".

Regards,

--
Julien