Subject: [TLS] Client Hello version during renegotiation.

From: Fabrice Gautier <[email-masked]>
Date: Tue, 26 Mar 2013 16:21:50 -0700

Hi all,

If I'm reading the RFC 5746 correctly, a TLS 1.2 client that initially
negotiated a TLS 1.0 connection with a server should subsequently set
their ClientHello.version to TLS 1.0 in any subsequent renegotiation.

Also, when generating the premaster secret in the RSA key exchange,
the client should use the protocol version sent in its
ClientHello.version, although using the negotiated version may be
acceptable.

As it turns out, it looks like Exchange 2010 servers are not paying
nice with this.

Those servers do not support TLS 1.2 and will downgrade to 1.0.
They will properly accept the 1.2 version in the premaster secret
during the initial handshake.
But when the client send a TLS 1.0 client hello during a
renegotiation, the handshake will fail if a TLS 1.0 version is used in
the premaster secret.
It will succeed if a TLS 1.2 version is used in the premaster secret
during the renegotiation.

On the other hand, using a TLS 1.2 version in the premaster secret,
while sending a TLS 1.0 client hello will break openssl and gnutls
servers.

It looks like this is worked around in OpenSSL (1.0.1) by sending a
TLS 1.2 client hello during the renegotiation, even if the server
indicated that they only supported 1.0.

Gnutls clients (3.0.8) will fail as explained above.

So two questions:
- Is gnutls doing the right thing and Exchange just buggy ?
- Is the OpenSSL workaround a sane thing to do ?

Relevant OpenSSL ChangeLog:

 Changes between 1.0.0h and 1.0.1  [14 Mar 2012]
[...]
  *) Some servers which support TLS 1.0 can choke if we initially indicate
     support for TLS 1.2 and later renegotiate using TLS 1.0 in the RSA
     encrypted premaster secret. As a workaround use the maximum pemitted
     client version in client hello, this should keep such servers happy
     and still work with previous versions of OpenSSL.
     [Steve Henson]

-- Fabrice

---

From: "Ryan Sleevi" <[email-masked]>
Date: Tue, 26 Mar 2013 16:44:23 -0700

>       and still work with previous versions of OpenSSL.

Hi Fabrice,

For better or worse, when we were implementing support for TLS 1.1 within
Chrome/Chromium, we ran into the same issue. Because of the many sites it
affected (namely, sites that use SChannel for SSL/TLS), we adopted the
workaround you've described, and as similar to OpenSSL.

This was captured in the NSS bug
https://bugzilla.mozilla.org/show_bug.cgi?id=783448 - which is the same
underlying cryptographic library used by Firefox and Chrome.

As such, consider this one of the many pieces of TLS lore that gets passed
around for how clients "really" behave.

Cheers,
Ryan

---

From: [email-masked] (Martin Rex)
Date: Wed, 27 Mar 2013 14:52:02 +0100 (CET)

> their ClientHello.version to TLS 1.0 in any subsequent renegotiation.

No, not really.  (rfc5746 says it is merely reiterating rfc5246)

Admittedly, the original text in rfc2246->rfc4346->rfc5246 is
slightly weird:

  7.4.1.2. Client Hello

  http://tools.ietf.org/html/rfc5246#page-41

   client_version
      The version of the TLS protocol by which the client wishes to
      communicate during this session.  This SHOULD be the latest
      (highest valued) version supported by the client.  For this
      version of the specification, the version will be 3.3 (see
      Appendix E for details about backward compatibility).

If you look closely, the first sentence contradicts the second sentence.
But only the second sentence uses "requirements" language, and that
requirement is unconditional.

The rule of thumb is: if the server asks you for renegotiation,
do NOT pull any stunts -- send EXACTLY the same ClientHello as on
the initial handshake, i.e. the exact same ClientHello.client_version
as on the initial handshake, and that should unconditionally contain
the highest version the implementation supports (or more accurately
the highest version that the implementation is configured to offer.

Adding Extensions, removing extensions or playing with TLS version
numbers may cause the reneogtiation handshake to fail, so HANDS OFF.

> ClientHello.version, although using the negotiated version may be

The client MUST send the ClientHello.client_version of the **CURRENT**
handshake in the RSA premaster secret.  This is the part that Microsoft

> As it turns out, it looks like Exchange 2010 servers are not paying

This is the part that Microsoft completely goofed in Win7 SChannel --
they're comparing the RSA premaster secret client_version with the
ClientHello.client_version of the initial handshake of the connection.
I'm puzzled what takes them so long to patch this bug.  They know about
this goof for quite some time.

  http://www.ietf.org/mail-archive/web/tls/current/msg08139.html

-Martin

---

From: Fabrice Gautier <[email-masked]>
Date: Wed, 27 Mar 2013 09:34:41 -0700

> No, not really.  (rfc5746 says it is merely reiterating rfc5246)

Sorry, I meant 5246.

Specifically, I was referring to:

E.1.  Compatibility with TLS 1.0/1.1 and SSL 3.0
[...]
   Whenever a client already knows the highest protocol version known to
   a server (for example, when resuming a session), it SHOULD initiate
   the connection in that native protocol.

Arguably, this could be only meant to apply to new connections and
resumed connections, rather than renegotiation handshakes, since it
otherwise contradicts the part you quoted.

---

From: [email-masked] (Martin Rex)
Date: Wed, 27 Mar 2013 18:25:21 +0100 (CET)

> otherwise contradicts the part you quoted.

There is a subtle difference between a mere proposal of a protocol version,
as represented by "ClientHello.client_version", and the actual use
of a protocol version, as represented by the "ProtocolVersion" field
of the record layer.  So the above "it SHOULD initiate the connection
in that native protocol" technically applies only to the
"protocol being employed".

http://tools.ietf.org/html/rfc5246#section-6.2.1

      struct {
          ContentType type;
          ProtocolVersion version;
          uint16 length;
          opaque fragment[TLSPlaintext.length];
      } TLSPlaintext;

   version
      The version of the protocol being employed.

In case you're wondering whether it is possible to change the protocol
version during renegotiation -- not that is currently impossible, because
it is unspecified.  (Unfortunately, the TLS spec does not mention this).

For cryptographic properties that are negotiated with the cipher suite,
it is well-defined when to switch from the current ciphersuite and the
current properties to the new cipher suite and the new properties
(->ChangeCipherSpec).  For cryptographic properties that are negotiated
through TLS version or through TLS extensions, it is currently undefined
when they take effect.

-Martin