Subject: [TLS] Re: draft-ietf-tls-rfc4346-bis-01.txt

From: Martin Rex <[email-masked]>
Date: Tue, 27 Jun 2006 22:39:10 +0200 (MET DST)

While privately discussing I-D draft-pettersen-tls-interop-experience-00.txt
I came across what I consider a potential ambiguity in TLS v1.0 (rfc2246)
and TLS v1.1 (rfc4346):

Appendix E "Backward Compatibility With SSL" 2nd paragraph says this:

   TLS versions 1.1, 1.0, and SSL 3.0 are very similar; thus, supporting
   both is easy. TLS clients who wish to negotiate with such older
   servers SHOULD send client hello messages using the SSL 3.0 record
   format and client hello structure, sending {3, 2} for the version
   field to note that they support TLS 1.1. If the server supports only
   TLS 1.0 or SSL 3.0, it will respond with a downrev 3.0 server hello;
   if it supports TLS 1.1 it will respond with a TLS 1.1 server hello.
   The negotiation then proceeds as appropriate for the negotiated
   protocol.

It should read instead

   ...
   servers SHOULD send client hello messages using the SSL 3.0 record
   format and client hello structure, sending {3, 2} for the client_version
                                                             ^^^^^^^

because it ought to refer to the Protocol version field in the
ClientHello message, and *NOT* the version field in the record layer.

The comment in the OpenSSL code suggests that the Netscape 6.0 browser
was the first defective SSL client to incorrectly use a {3, 1}
version tag on the record protocol for the initial client hello,
but it could be that others have copied this bug.

Microsoft appears to be shipping a new variant of the bug with IIS,
which erroneously sends the {3,1} tag in the record protocol when
forcing an SSLv3 client through renegotiation in order to ask for
an SSL client certificate _after_ reading the HTTP request over
an anonymous SSL-client connection--which is kind of odd since
the session is fully established as 3.0 and the Server Hello
correctly contains 3.0...

Btw.  all previous TLS documents increased the TLS protocol version
in Appendix A.1.1 / A.1, draft-ietf-tls-rfc4346-bis-01.txt hasn't
yet done so.

The ProtocolVersion tag on the SSL/TLS record protocol defines
the encoding of the PDU, and therefore older implementations
ought not even try to parse PDUs which they can not be expected to
understand/recognize.

Regards,
-Martin

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

---

From: <[email-masked]>
Date: Mon, 3 Jul 2006 19:14:15 +0300

Hi Martin,

I agree that the spec is ambiguous in this respect, but I'm not
so sure about what the correct interpretation should be. In 
other words, when a TLS client supports more than one of (SSLv3,
TLSv10, TLSv11), should the record layer version number contain
the lowest supported protocol, or the same value as handshake
layer ClientHello?

A quick and totally unscientific survey of what some widely used
SSL/TLS implementations do:

- OpenSSL (0.9.8)
  - When configured in "both SSLv3 and TLSv10 allowed" mode,
    sends V2 ClientHello.
  - When configured in "TLS10 only" mode, sends {03,01} in both fields
- Mozilla Firefox 1.5
  - Seems to send V2 ClientHello no matter what the settings??
- MS Internet Explorer 6.0
  - When configured in "both SSLv3 and TLSv1.0 allowed" mode,
    sends V3 ClientHello with {03,01} in both fields
- SunJSSE (JDK 1.4.2)
  - When configured in "both SSLv3 and TLSv1.0 allowed" mode,
    sends V3 ClientHello with {03,01} in both fields
- GnuTLS (10.0.20)
  - When configured in "both SSLv3 and TLSv1.0 allowed" mode,
    sends V3 ClientHello with {03,01} in both fields
  - When configured in "SSLv3, TLSv1.0 and TLSv1.1 allowed" mode,
    sends V3 ClientHello with {03,02} in both fields

In other words: All these implementation seem to follow the
rule that TLSPlaintext.version==ClientHello.client_version, or
use V2 ClientHellos...

Given that Yngve's interoperability draft suggests that some
servers incorrectly use the record layer version number for
negotiation, I think the safest clarification would be to 
say that the two version numbers must be equal.

Best regards,
Pasi

> -----Original Message-----
> From: ext Martin Rex [mailto:[email-masked]] 
> Sent: 27 June, 2006 23:39
> To: [email-masked]
> Subject: [TLS] Re: draft-ietf-tls-rfc4346-bis-01.txt
> 
> 
> While privately discussing I-D 
> draft-pettersen-tls-interop-experience-00.txt

---

From: Martin Rex <[email-masked]>
Date: Mon, 3 Jul 2006 19:08:59 +0200 (MET DST)

> the lowest supported protocol, or the same value as handshake

It SHOULD contain the lowest protocol version that the client
is willing to negotiate.  Anything else is going to cause interoperability
problems.  The most interesing question: what does the installed
base do today when it receives a client hello with a 3.2 or even 3.3 or 3.4
version the "version" field of the SSL/TLS record protocol AND in the
client_version of the ClientHello message.  I expect some servers to
choke heavily (and rightfully).

The potential ambiguity is only for the casual reader, there definitely
never was an abiguity for the careful protocol implementor.  The SSLv3
spec (which somewhat happened after the fact) does not contain any
ambiguity either, because it doesn't define anything other than {3, 0} PDUs
and version numbers.

The root of any ambiguity is that the spec fails to clearly seperare version
tags for the purpose of negotation (client_version, server_version)
and version tags (version) that indicates a particular PDU encoding.  

The description of the PDUs in the appendix of SSL/TLS specs contains
the protocol version in exactly three distinct variants:

    version
    client_version (only in ClientHello and PreMasterSecret)
    server_version (only in ServerHello)

All existing specs were NOT ambiguous in that exactly one field was
supposed to contain the negotiated version number.  And from the
description of the individual PDUs in Appendix A, it should have
been obvious to implementors which version field should have been
meant, and which one should not have been meant.

There are very few error-free specs, and this particular error (and
the correct wording) are fairly easy to figure, IMHO.

>   - When configured in "both SSLv3 and TLSv10 allowed" mode,

fine.

>   - When configured in "TLS10 only" mode, sends {03,01} in both fields

fine.

>   - Seems to send V2 ClientHello no matter what the settings??

fine.

>     sends V3 ClientHello with {03,01} in both fields

broken.

>     sends V3 ClientHello with {03,01} in both fields

broken.

>     sends V3 ClientHello with {03,01} in both fields

broken.

>     sends V3 ClientHello with {03,02} in both fields

broken.

> rule that TLSPlaintext.version==ClientHello.client_version, or

Didn't you just say that OpenSSL and Mozilla used a correct behaviour
on the client side?

The more interesting question is what SSL/TLS servers do upon receipt,
and in particular what they do upon receipt of a high up version number,
like {03,03} or {03,04}.

> say that the two version numbers must be equal.

The clarification should say that there's an awfully large installed
base that is broken and that the server will likely have to entirely
ignore the version number in the record protocol when processing
a ClientHello message, and upons sending, should send the lowest
version number that they're willing to use.
This makes protocol layering not as independent as it should be.

-Martin

---

From: David Hopwood <[email-masked]>
Date: Mon, 03 Jul 2006 18:16:30 +0100

> say that the two version numbers must be equal.

Rather, that clients MUST send ClientHello records with the two
version numbers equal.

Saying just that they "MUST be equal" would allow servers to reject
records where they are not equal, which would be incorrect.

-- 
David Hopwood <[email-masked]>

---

From: Bodo Moeller <[email-masked]>
Date: Tue, 4 Jul 2006 11:41:06 +0200

>   - When configured in "both SSLv3 and TLSv10 allowed" mode,

This is the behavior of OpenSSL versions up to 0.9.7g.  Versions
0.9.7h and later, including 0.9.8, will actually send a TLS/SSL3
format Client Hello message with version number {03,01} in both
fields.  How did you run the test?  If you really used OpenSSL 0.9.8
and really disabled SSL 2.0, then the library shouldn't have used
the V2 Client Hello message format.

The code used by OpenSSL to create the TLS/SSL3 record header
for the Client Hello message is as follows:

			/* fill in 5-byte record header */
			d=buf;
			*(d++) = SSL3_RT_HANDSHAKE;
			*(d++) = version_major;
			*(d++) = version_minor; /* arguably we should send the *lowest* suported version here
			                         * (indicating, e.g., TLS 1.0 in "SSL 3.0 format") */
			s2n((int)l,d);

The specification specifically demands the "SSL 3.0 record format and
client hello structure", which is essentially the same as the TLS 1.0
record format and client hello structure, with the notable exception
of the version number field.  So it's quite clear that you should put
{03,00} into the record header version field, since this is the only
way you can actually avoid the "TLS 1.0 record format" and use the
"SSL 3.0 record format".  On the other hand, this could trigger some
bugs in thoughtlessly done server implementations, which are avoided
by sending {03,01} in the record version field.

In contrast, sending too large a minor version number (such as {03,01}
for a record supposed to be in "SSL 3.0 record format") can be
expected to work well with thoughfully done server implementations:
If a server obtains a {03,xx} format Client Hello where the version
number specified by the client is larger than the highest protocol
version supported by the server ({03,yy}, say), then the best the
server can do is try its highest protocol version, and send an
according Server Hello message.  Either this will work since the
client does support {03,yy}, too; or otherwise the protocol mismatch
is unavoidable, and will be detected by the client.

So if a TLS 1.0 or TLS 1.1 server receives a Client Hello contained in
a record of protocol version number {03,2A} or whatever, it should
just try to parse this in its own native format, and negotiate the
protocol version accordingly.  Things can't get worse than triggering
a protocol_version alert from the client, and this is not very likely
to happen.  (If the *major* protocol version number is unknown, such
as {04,00}, then it certainly makes sense to abort the handshake
immediately.)

> say that the two version numbers must be equal.

The experiment that we'd really have to run is to test various servers
out there with Client Hello messages where the record protocol version
and the Client Hello protocol version differ, to see what protocol
version the servers will negotiate:

- Send a Client Hello with a client_version of {03,2A} (say) in a
  record with version {03,00} and see if the server picks SSL 3.0
  ({03,00}) or some version of TLS.

- Then, unless the server picked the highest protocol number defined
  at this time, try again using a uniform-version Client Hello naming
  a protocol version higher than the one from the first experiment.
  (E.g., if the server picked SSL 3.0 in the first test, check if it
  does support TLS 1.0 after all.)

- Finally, send a Client Hello with both version field set to
  {03,2A} (say) to see if the server handles unknown protocol versions
  properly and gracefully falls back to an existing protocol version.

---

From: <[email-masked]>
Date: Wed, 5 Jul 2006 14:15:37 +0300

> the V2 Client Hello message format.

Hmm... I rechecked everything, and it turns out that I had
accidentally used an older version of OpenSSL installed from RPM
instead of the latest version I compiled myself.

When I re-ran the test using the latest version, it does indeed
behave the way you described.

Two additional data points: The Mozilla NSS library also sends
TLS/SSL3 format ClientHello with {03,01} in both fields if you set the
"SSL_V2_COMPATIBLE_HELLO" option to FALSE, and allow both SSLv3 and
TLSv10 (but apparently in Firefox this flag is TRUE even when
you disable SSL2 from the GUI).

PureTLS 0.9b5 also sends TLS/SSL3 format ClientHello with {03,01} in
both fields (when configured in "both SSLv3 and TLSv10 allowed" mode).

> 			*(d++) = version_minor; /* arguably we 
> should send the *lowest* suported version here
> 			                         * (indicating, 
> The specification specifically demands the "SSL 3.0 record
> format and client hello structure", which is essentially the
> same as the TLS 1.0 record format and client hello structure,
> with the notable exception of the version number field.  So it's
> quite clear that you should put {03,00} into the record header
> version field, since this is the only way you can actually avoid
> the "TLS 1.0 record format" and use the "SSL 3.0 record format".
> On the other hand, this could trigger some bugs in thoughtlessly
> done server implementations, which are avoided by sending
> {03,01} in the record version field.

Yes; it seems that most other implementations also do this (and thus
servers also work with this, at least when the version is 03,01).

> is unavoidable, and will be detected by the client.

Yes; and also it's quite likely that the format of ClientHello will
remain backwards-compatible in future versions of TLS, since
otherwise we'd lose the ability to gracefully negotiate older
versions. 
> as {04,00}, then it certainly makes sense to abort the handshake

The TLS specification does not actually say what meaning the "major"
and "minor" version numbers have. But your intepretation -- that an
implementation should attempt to parse ClientHellos with the same
major version it supports, but not with different major versions --
certainly sounds reasonable. 

<snip>

>   properly and gracefully falls back to an existing protocol version.

I've been working on a testing tool what would allow running tests
exactly like this. It's not quite finished yet, but some preliminary
data points:

- OpenSSL 0.9.8: 
  - With ClientHello version {03,01}, succesfully negotiates TLS1.0 as
    long as the record version is {03,something}. Closes connection
    if record version is not {03,something}.
- GnuTLS 1.0.20:
  - With ClientHello version {03,01}, succesfully negotiates TLS1.0
    no matter what the record version is (i.e., record version seems
    to be ignored)

More data will come once I get SSL3 and TLS1.1 handshakes implemented,
and get time to set up more servers for testing...

Best regards,
Pasi

---

From: Rob Dugal <[email-masked]>
Date: Wed, 5 Jul 2006 07:32:09 -0400

Bodo Moeller <[email-masked]> wrote on 07/04/2006 05:41:06 AM:

> fields. 

The 0.9.8 behavior doesn't make sense to me. I think the correct behaviour 
would be to encode the minimum protocol {03,00} in the record's protocol 
field and the highest protocol {03,01} in the client_hello message's 
protocol field. A server that understands only SSLv3 could reject a client 
hello message that uses a record protocol of TLSv1. To negotiate with an 
SSLv2 server the client must send an SSLv2 client hello so why would the 
situation be any different for SSLv3/TLSv1? 

-----------------------------------------------
Robert Dugal
Member of Development Group
Certicom Corp.
EMAIL: [email-masked]
PHONE: (905) 501-3848
FAX  : (905) 507-4230
WEBSITE: www.certicom.com
_______________________________________________
TLS mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/tls

---

From: <[email-masked]>
Date: Wed, 5 Jul 2006 14:33:49 +0300

Martin,

While your interpretation of the spec does make sense in general, it
is exactly the opposite of what most implementations seem to use.

After some additional work with OpenSSL and Mozilla NSS (see my
reply to Bodo earlier today), *all* the implementations mentioned so
far (OpenSSL, Mozilla NSS, Microsoft IE, SunJSSE, GnuTLS, PureTLS)
seem to send 03,01 in both fields (when V2 hellos are disabled, and
both SSL3 and TLS1.0 are enabled), and *none* of them seems to ever
send different values in these fields.

Since the goal of the specification is to help interoperability, the
right clarification to this ambiguity should not be based solely on a
"protocol lawyer reading" of the spec (and declaring most current
implementations "broken"), but also on what existing widely used
implementations do.

But as you and Bodo pointed out, while knowing what existing clients 
do is useful, it's not sufficient: what existing servers do also
matters. This requires some further investigation...

(I do agree that for servers, the best guidance seems to be that
"when receiving ClientHello, ignore the record version (or at least
the minor version) and try to parse it anyway").

Best regards,
Pasi

> Sent: 03 July, 2006 20:09
> To: Eronen Pasi (Nokia-NRC/Helsinki)
> Cc: [email-masked]; [email-masked]
> Subject: Re: [TLS] Re: draft-ietf-tls-rfc4346-bis-01.txt
> 
> It SHOULD contain the lowest protocol version that the client is
> willing to negotiate.  Anything else is going to cause
> interoperability problems.  The most interesing question: what does
> the installed base do today when it receives a client hello with a
> 3.2 or even 3.3 or 3.4 version the "version" field of the SSL/TLS
> record protocol AND in the client_version of the ClientHello
> message.  I expect some servers to choke heavily (and rightfully).
> 
> The potential ambiguity is only for the casual reader, there
> definitely never was an abiguity for the careful protocol
> implementor.  The SSLv3 spec (which somewhat happened after the
> fact) does not contain any ambiguity either, because it doesn't
> define anything other than {3, 0} PDUs and version numbers.
> 
> The root of any ambiguity is that the spec fails to clearly seperare
> version tags for the purpose of negotation (client_version,
> server_version) and version tags (version) that indicates a
> particular PDU encoding.
> 
> and in particular what they do upon receipt of a high up 
> version number, like {03,03} or {03,04}.
> 
> >

---

From: Bodo Moeller <[email-masked]>
Date: Wed, 5 Jul 2006 14:27:26 +0200

> situation be any different for SSLv3/TLSv1? 

Using {03,00} for the record protocol field certainly would make the
most sense, when you're trying to follow the protocol specification.
However, the RFCs aren't totally clear about the situation: RFC 2246
only requests that "a TLS server which wishes to interoperate with SSL
3.0 clients should accept SSL 3.0 client hello messages", but it does
not demand that TLS-1.0-*only* servers (with no intention to
interoperate with SSL 3.0 clients) tolerate a {03,00} version in the
record header.  On the other hand, RFC 2246 only says that "TLS
clients who wish to negotiate with SSL 3.0 servers should send client
hello messages using the SSL 3.0 record format and client hello
structure" and does not makes this a "must".  The language in RFC 4346
(with another minor protocol version to take into account) does not
clear this up, in fact if you try to take it literally it makes
matters worse since the backwards compatibility section only mentions
SSL 2.0 and SSL 3.0 client hello messages, but no TLS 1.0 client hello
messages (which would make a lot of sense for the TLS1.0 + TLS1.1
case).

Essentially, OpenSSL 0.9.7h is following a trend set by other client
implementations.  If everyone was using {03,00} version records to
encapsulate TLS 1.0 Client Hellos, then OpenSSL probably would do this
too.  But there are plenty of broken servers out there, and the
experience is that some of these will mistakenly use {03,00} as the
client's maximum protocol version, even if this really is higher (and
correctly sent in the actual content of the Client Hello message).
This means that an obsolete protocol version will be negotiated
(SSL 3.0 when both parties actually do support TLS 1.0 or later), and
in the case of an RSA key exchange, it may lead to an aborted
handshake (since client_version is duplicated in the encrypted
premaster secret).  Heuristically, sending {03,01} in the record header
appears to be less problematic since typical SSL 3.0-only servers will
accept this Client Hello without complaining.  (Some very broken SSL 3.0
servers used to of problems even with this, but we can't accommodate
everything.)

I'm not saying that SSL3.0 + TLS1.0 clients *should* use {03,01} for
the record protocol field, though.  They are absolutely welcome to use
{03,00}, and similarly, it is perfect for TLS1.0 + TLS1.1 clients to
use {03,01} (TLS 1.0) rather than {03,02} (TLS 1.1), and for future
TLS1.1 + TLS 1.2 clients to use {03,02} rather than {03,03}.  Sending
any value {03,xx} where the respective protocol version is supported
by the client looks OK to me, and should be tolerated by servers, even
if the server does not know about said protocol version.  (If the
handshake attempt fails since the server has to downgrade from a
protocol {03,xx} supported by the client to {03,yy}, yy < xx, where
{03,yy} is not supported by the client, then at least the client will
learn about the highest version supported by the server, providing for
an informative error message.)

This, of course, assumes that the Client Hello format is not actually
changed between minor protocol versions.  If there were actual
significant differences (apart from hello extensions, which rely on a
forward compatilibity provision in the original SSL 3.0 and TLS 1.0
specifications), there was bound to be chaos.  However, given the
current state and the unclear language in RFC 2246 and RFC 4346, we
can conclude that it would be utter madness to ever change the Client
Hello structure in an incompatible way without changing the major
protocol version: If such a change was ever considered necessary, then
we'd again have a situation like the current SSL2.0 / SSL3.0+TLS1.x
interoperability situation on a higher level, i.e. the Client Hello
message would be sent in SSL3.0+TLS1.x format (using the current
structure definition) and the Client Hello message would name some
version {04,xx}, without being able to use any new features requiring
the new native Client Hello format (like we currently can't use
Client Hello extensions in SSL 2.0 backwards compatible mode).

---

From: Rob Dugal <[email-masked]>
Date: Wed, 5 Jul 2006 12:01:24 -0400

FYI - Opera 9 will sometimes send a client hello with SSLv3 as the record 
version and TLSv1 as the client version.
In my tests with SSLv3 & TLSv1 enabled it first sends a client hello with 
TLSv1as the record version and TLSv1 as the client version.
If this handshake fails it retries using SSLv3/TLS1.