Subject: Re: [TLS] TLS 1.2 hash agility

From: Eric Rescorla <[email-masked]>
Date: Fri, 07 Sep 2007 09:52:13 -0700

At Thu, 9 Aug 2007 12:34:07 +0300,
<[email-masked]> wrote:
> 
> Mike ([email-masked]) wrote:
> 
> > I think the solution we need is to specifically list each supported
> > signature algorithm, e.g.
> > 
> >      enum {
> >        rsa_with_md5(0),    rsa_with_sha1(1),
> >        rsa_with_sha256(2), rsa_with_sha384(3),
> >        rsa_with_sha512(4), dsa_with_sha1(5),
> >        (65535)
> >      };
> > 
> > These may not be specific enough, as I've seen suggestions for,
> > e.g. rsa_pkcs1v1_5_with_sha1, and I've heard that some algorithms
> > need parameters, but I think I've made my point.
> 
> I think your suggestion looks good; it seems to handle the DSA and
> ECDSA cases better than just a list of hashes, and it's more
> in TLS style than sending DER-encoded AlgorithmIdentifiers. 
> And then we could change Signature structure to
> 
>    struct {
>       SignatureAlgorithm signature_algorithm;
>       opaque signature_value<0..2^16-1>;
>    } Signature;  
> 
> Eric, what's your opinion?

This seems superficially reasonable. I'll try to cram it into
the new version and see if it causes trouble.

-Ekr

_______________________________________________
TLS mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/tls

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 14 Sep 2007 14:56:10 -0700

> Eric, what's your opinion?

OK, I started trying to wire this into TLS and it's messy.
There are three contexts we have to think about:

- Certs (from either side)
- CertificateVerify
- ServerKeyExchange

The difficulty is that the latter two already have signals indicating
what acceptable signature algorithms are, in the ClientCertificateType,
and the ciphersuite respectively. So, we either need to significantly
reconstruct those or have duplication of information, with the 
result that you have to potentially deal with mismatched information,
e.g., only offering RSA in the SKE, but offering RSA and DSA in the
new value.

-Ekr

---

From: Mike <[email-masked]>
Date: Fri, 14 Sep 2007 15:50:22 -0700

> e.g., only offering RSA in the SKE, but offering RSA and DSA in the

I think this information is disjoint.  For example, you can have a DSA
key in a certificate that is signed by RSA/SHA-1.

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Fri, 14 Sep 2007 15:56:05 -0700

At Fri, 14 Sep 2007 15:50:22 -0700,
> key in a certificate that is signed by RSA/SHA-1.

Yes, that's why I separated certificates from the other two situations.

Currently (in TLS 1.1) there are basically no restrictions on what
algorithms are used to sign the certs.

The ciphersuite and the ClientCertificateType indicate only the 
public key algorithm and not the hash algorithm.

So, we need to extend all three cases, to indicate the hash algorithms
that are supported.

-Ekr

---

From: Mike <[email-masked]>
Date: Sat, 15 Sep 2007 11:56:39 -0700

I have an idea.  Change the Cert Hash Types extension to the Supported
Signature Algorithms extension, and allow the server to respond with
its supported algorithms (only if the client sends its list, of course).

     struct {
         SignatureAlgorithm supported_algorithms<2..2^16-2>;
     } SupportedSignatureAlgorithms;

If the client doesn't send the extension, the server would assume the
client supports rsa_with_sha1, rsa_with_md5 (?), and dsa_with_sha1
(and the appropriate ecdsa algorithms if an ECDSA cipher suite is
negotiated).  Since the server can't send its list if the client
doesn't, the client must assume that the server only supports the same
list of algorithms.

If the client sends its list, and the server doesn't respond with the
extension, the client must assume that the server only supports the
algorithms mentioned above.  A client that requires better algorithms
than MD5 and SHA-1, can abort the session if it doesn't receive the
extension in the ServerHello, or if the list doesn't contain an
acceptable algorithm.

You can remove the HashType list from the CertificateRequest message
since it is handled by the server's SupportedSignatureAlgorithms
extension.  The client also chooses a certificate signed with a listed
algorithm.

If the Signature becomes (as Pasi suggested):

     struct {

we'd also need to add a null signature algorithm:

     enum {
         null(0),            rsa_with_md5(1),
         rsa_with_sha1(2),   rsa_with_sha256(3),
         rsa_with_sha384(4), rsa_with_sha512(5),
         dsa_with_sha1(6),
         (65535)
     } SignatureAlgorithm;

for use with anonymous exchanges.

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Mon, 17 Sep 2007 11:58:20 -0700

At Sat, 15 Sep 2007 11:56:39 -0700,
> doesn't, the client must assume that the server only supports the same

I don't see how this solves the major problem, which is that you
are advertising your public key algorithm support in two places.

- In the case of the ServerKeyExchange, the client signals his
support in this extension *and* in the cipher suite.

- In the case of the CertificateVerify, the server signals his
  support in the CertificateRequest and in this extension.

Taking the ServerKeyExchange as the paradigmatic example, ISTM that
we either need to rework the entire negotiation scheme, e.g.,
to create new cipher suites which specify also the digest used
for signature, or just live with this duplication. The former
seems superior.

So, I propose we simply replace the HashTypes type with a signature
algorithms type that specifies both hash algorithm and signature
algorithm. As you suggest:

     struct {

This would go wherever HashTypes goes now.

However, the interpretation rules need to be extremely clear,
as below.

CERTIFICATEREQUEST
For signatures by the client (i.e., CertificateVerify and Certificate),
the following rules apply:

    struct {
        ClientCertificateType certificate_types<1..2^8-1>;
        SignatureAlgorithm signature_types<1..2^16-1>;
        DistinguishedName certificate_authorities<0..2^16-1>;
    } CertificateRequest;
 
- Any certificate offered by the client must be signed with an
  algorithm described in signature_types.
- The certificate must contain a public key with an
  algorithm specified in certificate_types.
- The CertificateVerify must be signed with a signature algorithm
  in signature_types.

Consider the following examples:

(1) 
certificate_types = rsa_sign
signature_types   = rsa_sha1, rsa_sha256

In this case:

- The client's certificate must be signed with rsa_sha1 or rsa_sha256
- The client must sign with either rsa_sha1 or rsa_sha256

(2) 
certificate_types = rsa_sign
signature_types   = rsa_sha1, rsa_sha256, dsa_sha1

In this case:

- The client's certificate must be signed with rsa_sha1 or rsa_sha256, or 
  dsa_sha1
- The client must sign with rsa_sha1 or rsa_sha256, but NOT DSA

(3) 
certificate_types = rsa_sign, dsa_sign
signature_types   = rsa_sha1, rsa_sha256

In this case:

- The client's certificate must be signed with rsa_sha1 or rsa_sha256
- The client must sign with either rsa_sha1 or rsa_sha256

Note that even though the server advertised dsa, it didn't advertise
any hashes so it's not actually usable.

SIGNATUREALGORITHMS
As you suggest, the client would offer a SignatureAlgorithms
extension. The rules would be similar:

- Any certificate offered by the server must be signed with an
  algorithm described in signature_types.
- The certificate key must contain a public key which has
  an algorithm that matches the cipher suite, either for
  signing (in the case of cipher suites which have it)
  or encryption (in the case of cipher suites which don't).
- The ServerKeyExchange must be signed with an algorithm that
  matches signature_types.

Examples:
(1) 
cipher suite      = TLS_RSA_WITH_AES_128_CBC_SHA
signature_types   = rsa_sha1, rsa_sha256

In this case:

- The server's certificate must be signed with rsa_sha1 or rsa_sha256
- The server's certificate must contain an RSA key.

(2) 
cipher suite      = TLS_RSA_DHE_WITH_AES_128_CBC_SHA
signature_types   = rsa_sha1, rsa_sha256

- The server's certificate must be signed with rsa_sha1 or rsa_sha256
- The server's certificate must contain an RSA key.
- The ServerKeyExchange MUST be signed with rsa_sha1 or rsa_sha256

-Ekr

---

From: <[email-masked]>
Date: Wed, 26 Sep 2007 14:37:52 +0300

Eric,

Looks very good!

There's one corner case that probably needs explicit clarification 
in the spec: certificate request containg any of the fixed-DH client
certificate types (rsa_fixed_dh, dss_fixed_dh, rsa_fixed_ecdh, and
ecdsa_fixed_ecdh).

One option would be to simply replace these with "fixed_dh" and
"fixed_ecdh" -- but that would require updating RFC 4492 as well,
and maybe we don't want to go there.

So perhaps the simplest solution would be just to add another
rule for certificate request processing:

- In case of "*_fixed_dh" client certificate types, the 
  client certificate must be signed by an algorithm specified 
  in certificate_types. This restriction applies only to the
  end-entity certificate, not other certificates possibly
  included in the certificate chain.

Or we could just remove this redundancy, and instead say:

- For historical reasons, the names of some client certificate 
  types include the algorithm used to sign the certificate.
  For example, in earlier versions of TLS, rsa_fixed_dh meant a 
  certificate signed with RSA and containing a static DH key.

  In TLS 1.2, this functionality has been obsoleted by the
  signature_types field, and the certificate type no longer 
  restricts the algorithm used to sign the certificate.
  For example, if the server sends dss_fixed_dh certificate type
  and {dss_sha1, rsa_sha1} signature types, the client is allowed
  to reply with a certificate containing a static DH key, signed
  with RSA-SHA1.

(The latter alternative would bring us more flexibility,
and would enable combinations not currently possible: e.g.
fixed_dh key signed with ecdsa).

Best regards,
Pasi

> -----Original Message-----
> From: ext Eric Rescorla [mailto:[email-masked]] 
> Sent: 17 September, 2007 21:58
> To: Mike
> Cc: [email-masked]
> Subject: Re: [TLS] TLS 1.2 hash agility
>

---

From: Mike <[email-masked]>
Date: Wed, 26 Sep 2007 08:01:46 -0700

Sorry for taking so long to respond to this....

> are advertising your public key algorithm support in two places.

I look at the Supported Signature Algorithms extension as a hybrid
of the sender's list of capabilities (which algorithms his encryption
library supports), and the sender's list of algorithms he deems
acceptable from a security standpoint.  If you exchange this
information in the (proposed) extension, then you don't need to
send it again in other places.

>   support in this extension *and* in the cipher suite.

The cipher suite doesn't have all the information about which
signature algorithm to use.

     TLS_RSA_WITH_RC4_128_MD5
     TLS_RSA_WITH_RC4_128_SHA
     TLS_RSA_WITH_3DES_EDE_CBC_SHA
     TLS_RSA_WITH_AES_128_CBC_SHA
     TLS_RSA_WITH_AES_256_CBC_SHA

The above cipher suites specify that the public key in the
certificate must be an RSA key, but they don't say anything about
what algorithm is used to sign the certificate.

     TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
     TLS_DHE_DSS_WITH_AES_128_CBC_SHA
     TLS_DHE_DSS_WITH_AES_256_CBC_SHA

These specify that the DH parameters are signed with DSS, but they
don't say which hash to use.  Right now you can only use SHA-1, so
it implicitly limits you to that, but isn't this going to change
soon?

     TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
     TLS_DHE_RSA_WITH_AES_128_CBC_SHA
     TLS_DHE_RSA_WITH_AES_256_CBC_SHA

Similarly, these say to use RSA to sign the DH parameters, but don't
specify the hash algorithm, so you still need to specify that some-
where.

>   support in the CertificateRequest and in this extension.

I would argue that all you need to do is remove the redundant list
from the CertificateRequest message.  Since the extension has
already indicated to the client which algorithms the server will
accept, there is no need to send the list again.

> for signature, or just live with this duplication. The former

It's my opinion that the current cipher suites will continue to
work fine.  As I said above, the current cipher suites are under-
specified, so adding the extension fills in the missing blanks.

> This would go wherever HashTypes goes now.

My point is that if you specify this information in ClientHello
and ServerHello, you never have to exchange it again, so you can
eliminate HashTypes altogether.  This will also benefit any future
addition to TLS that requires a signature, since there won't be
the need to exchange the list of supported signature algorithms
yet again.

>   algorithm described in signature_types.

The certificate would be signed with an algorithm listed in the
server's Supported Signature Algorithms extension.

>   algorithm specified in certificate_types.

Yes, we still need certificate_types.

> - The CertificateVerify must be signed with a signature algorithm

Again, the CertificateVerify would be signed with an algorithm
from the server's extension.

> - The ServerKeyExchange must be signed with an algorithm that

I agree with all of that.

At the risk of being redundant, I assert that making this extension
symmetric and allowing the server to respond with its own list of
supported algorithms, is better than having the server send its
list every place where it is needed (now and in the future).  Send
it once in ServerHello, and use it where it's needed.

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Wed, 26 Sep 2007 08:29:06 -0700

At Wed, 26 Sep 2007 08:01:46 -0700,
> it once in ServerHello, and use it where it's needed.

There is only one place where it's needed: CertificateRequest.

This has two advantages over the extension:
1. It works even if the client doesn't offer the extension.
2. It puts the parameters for the certificate in the same place
   as the request for it.

-Ekr

---

From: Mike <[email-masked]>
Date: Wed, 26 Sep 2007 10:07:52 -0700

> There is only one place where it's needed: CertificateRequest.

That is true at the moment, but if a future addition to the protocol
also requires a signature, you will need to send the list twice.

> 1. It works even if the client doesn't offer the extension.

You could make the extension mandatory for TLS 1.2 or later.  Even
if it is not mandatory, if the client does not specify the extension,
there are default capabilities that can be assumed.  If the server
requires that the client authenticate with a certificate, and also
that the default algorithms are unacceptable, it can abort the
session immediately after ClientHello is received, which is an
added performance benefit.

> 2. It puts the parameters for the certificate in the same place

While I agree that this is in general good design, my opinion is
that the other factors outweigh it.  Gentlemen can disagree.

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Wed, 26 Sep 2007 10:16:27 -0700

At Wed, 26 Sep 2007 10:07:52 -0700,
> also requires a signature, you will need to send the list twice.

Or simply make the change then.

> that the other factors outweigh it.  Gentlemen can disagree.

Yes.

-Ekr

---

From: Mike <[email-masked]>
Date: Wed, 26 Sep 2007 22:45:59 -0700

> added performance benefit.

I realized half way through an all-day meeting that this performance
benefit does not depend on where you put the server's list of
signature algorithms; so it is not a valid argument for the server
extension.

> that the other factors outweigh it.  Gentlemen can disagree.

I spent the rest of the meeting trying to come up with other valid
reasons for using the extension to advertise the server's
capabilities, versus putting them in the CertificateRequest.  The
only thing I could come up with is that putting the list of
signature algorithms in the CertificateRequest is a change to the
format of that message, so it requires version-specific processing,
whereas if you use the server extension, the format of Certificate
Request is the same as previous TLS versions.

Mike

---

From: Mike <[email-masked]>
Date: Wed, 26 Sep 2007 22:51:08 -0700

> Or simply make the change then.

I see two options:

   1) use a server extension to advertise signature algorithm support

   2) modify the format of CertificateRequest now, and possibly
      have to change it back later and implement choice 1 anyway

I would choose option 1.

Mike

---

From: <[email-masked]>
Date: Thu, 27 Sep 2007 12:30:42 +0300

> what algorithm is used to sign the certificate.

In TLS 1.0 and 1.1, these ciphersuites required that the certificate
is also signed with RSA. (But that's something we can change in 
TLS 1.2, if we so decide.)

Best regards,
Pasi

---

From: <[email-masked]>
Date: Thu, 27 Sep 2007 12:41:39 +0300

[email-masked] wrote:

> The only thing I could come up with is that putting the list of

CertificateRequest will require version-specific processing anyway,
because its semantics will change. For example, in TLS 1.0/1.1
ClientCertificateType "rsa_sign" meant a certificate containing
an RSA key, and signed with RSA. In TLS 1.2, it will probably
mean just a cert containing an RSA key; the signature algorithm
part will be specified separately.

(Another difference is that in TLS 1.0/1.1, clients that didn't
have certificates often just ignored CertificateRequest; 
current draft of TLS 1.2 mandates sending an empty Certificate 
message instead.)

Best regards,
Pasi

---

From: Mike <[email-masked]>
Date: Thu, 27 Sep 2007 07:18:38 -0700

> I spent [a lot of time] trying to come up with other valid

I came up with a few more ideas, unfortunately at the expense of
not being able to sleep:

   - The extension mechanism was added to TLS to enable the
     addition of functionality without needing to constantly
     change handshake message formats; so I would argue that
     any functionality that -can- be added using an extension
     -should- use an extension instead of modifying messages.
     (Yes, Signature had to change so messages will be
     different, but limiting the damage is a worthy goal.)

   - There is a potential performance benefit on the client
     side: if the client requires better algorithms than the
     defaults and the server either doesn't reply with the
     extension, or if the list doesn't contain an acceptable
     algorithm, then the client can abort the connection
     immediately after parsing the ServerHello message.  It
     can avoid the need to parse the Certificate message to
     determine how it was signed.

The only counter argument I could find is that the server's list
of acceptable algorithms might be different in different places.
Even if so, the client can benefit from knowing the server's
certificate signature algorithms up front, so having the server
respond with the extension is useful.  Then I would suggest
that signature_algorithms in CertificateRequest could be empty,
which would mean, "use the same list given in the server's
signature algorithms extension."

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 27 Sep 2007 07:30:28 -0700

At Thu, 27 Sep 2007 07:18:38 -0700,
>      different, but limiting the damage is a worthy goal.)

No, I don't agree with this claim about the purpose of the
extension mechanism. Some things are appropriately done
in extensions, some should be part of the main protocol.
It's a *bad* idea to move as much as possible into extensions.

>      determine how it was signed.

As you indicated in your previous message, this is not in fact
an advantage.

> of acceptable algorithms might be different in different places.

And yet, I mentioned several other reasons in my previous message:

- Locality of information.
- It works even if the client does not offer the extension.

> respond with the extension is useful.

I don't see any significant value in this.

-Ekr

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 27 Sep 2007 07:30:42 -0700

At Wed, 26 Sep 2007 22:51:08 -0700,
>       have to change it back later and implement choice 1 anyway

As you say, gentleman can disagree.

-Ekr

---

From: Mike <[email-masked]>
Date: Thu, 27 Sep 2007 07:38:10 -0700

> part will be specified separately.

Ok, this is valid.  However, I have too much code that looks like:

    if (version == ssl3)
       do_this;
    else if (version <= tls11)
       do_that;
    else
       do_the_other;

Which is a maintenance nightmare.  In some places I used separate
functions for different TLS versions, all of which are very similar,
so that is not ideal either.  The less of this we need, the better.

> current draft of TLS 1.2 mandates sending an empty Certificate 

Yes, but you can change your code to always send an empty Certificate
even for the earlier versions.

Mike

---

From: Mike <[email-masked]>
Date: Thu, 27 Sep 2007 08:00:49 -0700

> As you indicated in your previous message, this is not in fact

It is a different benefit (for the client, not the server), so
yes it is an advantage.

> - Locality of information.

For CertificateRequest, yes, but by putting it there, the client
has to parse the Certificate to figure out if it is signed with
an acceptable algorithm.  If the server's list of acceptable
algorithms was passed in a ServerHello extension, the client
would be able to determine if it should even bother.  (That is
the benefit I referred to above.)

> - It works even if the client does not offer the extension.

A client that does not offer the extension doesn't support any
advanced algorithms.  If it did, why wouldn't it tell the server?

> I don't see any significant value in this.

In the end, it is your specification, so all I can do is present
my point of view....

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 27 Sep 2007 09:10:04 -0700

At Thu, 27 Sep 2007 08:00:49 -0700,
> the benefit I referred to above.)

I'm sorry, I don't understand your point: the client tells
the server what algorithms it supports. A compliant server
MUST NOT send a certificate with a different algorithm,
but rather abort the connection. The client at this point
needs to assume that the server's certificate is OK and
parse it, yes. But if we're assuming that the server is
noncompliant, then you can't count on the indicator you're
talking about anyway.

You and I seem to be assuming different semantics here:
the design I propose is not a negotiation. The client says
"I will accept stuff signed with X" and the server does
likewise. The only restriction is that the signer use an
algorithm within the other side's set. These sets need
not intersect.

> advanced algorithms.  If it did, why wouldn't it tell the server?

It might have a certificate signed with a better algorithm but that
it can't itself verify. It might simply be configured to prefer
a certain set of algorithms. Remember that the signature over
the client's certificate and CertificateVerify is for the 
client's benefit, not the servers, and vice versa, so just 
because you only trust algorithm X doesn't mean you can't
generate algorithm Y.

> In the end, it is your specification, so all I can do is present

This is a WG document, so it's actually the WG's position that
matters. But given that you and I are the people who have
expressed opinions...

-Ekr

---

From: Mike <[email-masked]>
Date: Thu, 27 Sep 2007 09:49:35 -0700

> but rather abort the connection.

You understood my point correctly, but it was flawed....

> algorithm within the other side's set. These sets need

The only thing we disagree on is where the server should
put its preferences.  You've convinced me that it doesn't
much matter technically.

> Remember that the signature over
> client's benefit, not the servers, and vice versa....

I thought that the signature over the client's certificate
was to prove to the server that you have the corresponding
private key, and therefore that you are the entity named in
the certificate (and deserve access to private information
about that entity).

Mike

---

From: Mike <[email-masked]>
Date: Thu, 27 Sep 2007 10:20:47 -0700

>> the client's certificate and CertificateVerify is for the client's 
>> benefit, not the servers, and vice versa....
> 

Oops, I meant signature in CertificateVerify.

Mike

---

From: Eric Rescorla <[email-masked]>
Date: Thu, 27 Sep 2007 10:45:26 -0700

At Thu, 27 Sep 2007 09:49:35 -0700,
> the certificate (and deserve access to private information

Yes, I agree with this. My point is that the enforcement of
the client's identity *must* happen by the server. There
is nothing the client can do to force the server to enforce
a strong policy for client auth.

Consider the following case:

- SHA-1 has been broken.
- I have a classic RSA certificate signed with RSA-SHA-256.
- The server isn't under my control and foolishly accepts SHA-1.

No matter how I configure my client, an attacker can impersonate
me and sign with SHA-1 and the server will accept it.

-Ekr

---

From: Russ Housley <[email-masked]>
Date: Thu, 27 Sep 2007 12:26:01 -0400

For backward compatibility, wouldn't it be cleaner to add a new 
rsa_xxx type to indicate the different semantics.  The new type would 
not be supported by non-TLS v1.2 implementations, nut the handling of 
rsa_sign wouid be the same in all cases.

Russ

---

From: <[email-masked]>
Date: Fri, 28 Sep 2007 11:59:16 +0300

The "_sign" part in "rsa_sign" also means that the cert has to 
contain a RSA public key that can be used for signing. So
if we defined a new type, it would be called "rsa_sign_v1_2" 
or something...

At this point of the protocol, we already know what protocol 
version was negotiated, so changing the semantics is possible 
without ruining backwards compatibility.

Besides, it wouldn't be enough to define a new "rsa_" type; 
this issue applies to all client certificate types, so 
we'd have to obsolete all of them ("MUST NOT send any of these
if TLS 1.2 is negotiated") and assign new numbers. This would 
also require revising RFC 4492, which I'd rather avoid...

Best regards,
Pasi

> From: ext Russ Housley [mailto:[email-masked]] 
> Sent: 27 September, 2007 19:26
> To: Eronen Pasi (Nokia-NRC/Helsinki)
> Cc: [email-masked]
> Subject: RE: [TLS] TLS 1.2 hash agility
>

---

From: <[email-masked]>
Date: Fri, 28 Sep 2007 12:02:22 +0300

> matters. But given that you and I are the people who have

<all hats off>

Either alternative seems to work technically -- but as the server
already indicates in CertificateRequest what kind of public key
the cert should contain, and which CA issued it, putting the
signature algorithm list there as well seems slightly nicer to me.

Best regards,
Pasi