Annex E.1 of RFC 5246 contains the following text which is a nice summary of the situation:
Note: some server implementations are known to implement version negotiation incorrectly. For example, there are buggy TLS 1.0 servers that simply close the connection when the client offers a version newer than TLS 1.0. Also, it is known that some servers will refuse the connection if any TLS extensions are included in ClientHello. Interoperability with such buggy servers is a complex topic beyond the scope of this document, and may require multiple connection attempts by the client.
For a single connection, SSL/TLS contains the necessary protection against version rollback. Namely, the ClientHello
message contains the client_version
field, which advertises its highest supported version, and the full contents of the ClientHello
message, including this field, are part of the input to the hash function used to compute the Finished
messages at the end of the handshake. This makes sure that the server saw the "right value", i.e. the same one as the client.
The crucial point, though, is that this relies on the security of SSL 3.0, not TLS 1.2. This kind of protection against rollback works not because the new version of the protocol is "protected", but because the old version already includes the protection. It also requires that the old standard (SSL 3.0) still has a "robust enough" handshake: an attacker who performs a version rollback attack, pushing back client and server down to SSL 3.0, must have the ability to completely break SSL 3.0 right before the Finished
messages; otherwise, these Finished
messages will detect the rollback.
SSL 2.0 did not have such hash-based Finished
messages (it had verification messages, but based on random challenges, not on the contents of previous handshake messages), it was possible for a MitM attacker to force a client and server to do SSL 2.0 instead of SSL 3.0 and they would not know it. SSL 2.0 is not "protected enough" against rollback, contrary to SSL 3.0, so the solution was to smuggle an equivalent of the client_version
field in a place where cryptography would protect it (as specified in SSL 3.0, this was done in the PKCS#1 v1.5 "type 2" padding for RSA-encryption of the premaster secret).
Version rollback attacks are moot; or at least so it can be argued. Indeed, any version rollback attack can force client and server to use only versions and algorithms that they are willing to use. If SSL 3.0 was considered weak, then why would the client and server agree to use it ? If falling back to SSL 3.0 was considered a problem, then a client noticing a server which apparently cannot handle TLS 1.x for any value of x would simply refuse to connect at all. Conversely, if the client accepts to use SSL 3.0, then SSL 3.0 is fine.
This argument is of course a bit abrupt, but it highlights the fact that version selection is an opportunistic system meant to unlock non-essential functionalities, and should not be considered a security feature. If the client really wants to favour interoperability over security, as @Henrick explains, then there is no real way to prevent it.
For instance, suppose that TLS is expanded with an anti-rollback protection mechanism. This requires, as in the case of SSL 2, smuggling a true_client_version
field somewhere in the SSL 3.0 handshake messages in a way which won't prevent interoperability with old, buggy servers (or old, buggy firewalls and intrusion detection systems). Extensions (at the end of the ClientHello
) cannot be used, because such extensions are part of what makes old buggy servers fail. However, one could put things in the client_random
value. That random has length 32 bytes; the first four bytes are the current time, so there are 28 actually random bytes. 16 random bytes are sufficient for "randomness"; this leaves us 12 bytes to play with. One could specify that the last 12 bytes of the client_random
should contain a specific value, e.g. 6 successive copies of the actual most recent version supported by the client. A client unaware of this convention has only probability 2-80 to follow this pattern, and an old buggy server should not break on such a client_random
.
Then a recent server, aware of the convention, would be able to see whether it is talking to a client which apparently requests SSL 3.0 or TLS 1.0, but claims in this surreptitious way that it can do TLS 1.2. The server would then be aware of some foul play. However, that could be the result of some misbehaving firewall, which, from a cryptographer's point of view, is an attacker, but not from a business point of view. Old, buggy systems are much more common than attacks. Even if the server decided to shut down the connection at that point, the client may still decide that, possibly, some old and buggy firewall blocks TLS 1.2 ClientHello
, and then try again, mimicking a SSL 3.0 client -- including not encoding the version in the client_random
, thereby deactivating the anti-rollback system we just defined. A Web browser who already tries multiple connections to deal with old buggy servers would probably keep on doing that.
To sum up, as long as the client really wants to connect, even if it implies falling back to SSL 3.0, and the server still accepts to talk to an SSL 3.0-only client (thus without any kind of anti-rollback system defined afterwards), then there is nothing that can be done on the server to prevent it. The client always has the possibility to perfectly mimic an old client, if that's what it takes to get through firewalls and anti-rollback systems and whatever. This is not specific to SSL.
To a large extent, the same applies to SSL 2.0. The anti-rollback system which was added in SSL 3.0 makes sense only as a transitioning mechanism. If SSL 2.0 is weak, then the security issue is not that an attacker could force client and server to fallback to SSL 2.0; the real issue is that client and server accept to use SSL 2.0 at all. The real protection against version rollback attacks is to reject weak versions altogether (as RFC 6176 suggests).