Problems with secure upgrade to TLS 1.1

One of the most common responses to the Rizzo/Duong “BEAST” attack was
why
not just deploy TLS 1.1
. See, for instance, this incredibly long
Bugzilla
bug
about TLS 1.1 in
Network
Security Services (NSS)
, the SSL/TLS stack used by both Chrome and
Firefox. Unfortunately, while TLS 1.1 deployment is a good idea in and
of itself, it turns out not to be a very useful defense against this
particular attack. The problem isn’t that servers don’t support TLS 1.1
(though most still don’t) but rather that the attacker can force
a client and server which both implement TLS 1.1 to negotiate TLS 1.0
(which is vulnerable).

Background: Protocol Negotiation and Downgrade Attacks

Say we are designing a new protocol to remotely control toasters,
the Toaster Control Protocol (TCP). TCP has a client
controller, a Toaster Control Equipment (TCE), and a
device responsible for toasting the bread, or Toaster Heading
Equipment
(THE). We’ll start by developing
TCP 1.0, but we expect that as time goes on we’ll want to add
new features and eventually we’ll want to deploy TCP 2.0. So,
for instance, maybe TCP 1.0 will only support toasters up to
two slots, but TCP 2.0 will add toaster ovens (as has been
widely observed, TCP 3.0 will allow you to send and receive
e-mail). We may also change the protocol encoding between
versions, so TCP 1.0 could have an ASCII representation whereas
TCP 2.0 added a binary encoding to save bits on the wire.
For obvious reasons, each version doesn’t roll out all at
once, so I might want TCP 2.0 TCE to talk to my TCP 1.0 THE.
Obviously, that communication will be TCP 1.0, but if I
later add a TCP 2.0 toaster oven, I want that to communicate
with my TCE using TCP 2.0.

One traditional way to address this problem is to have some sort
of initial handshake in which each side advertises its capabilities
and they converge on a common version (typically the most recent common
version). So, for instance, my TCE would say “I speak 2.0”
but if the says “I only speak 1.0” then you end up
with 1.0. On the other hand if the TCE advertises 2.0 and the
THE speaks 2.0, then you end up with 2.0. As in:

TCETCETHETHEHello, I speak versions 1.0, 2.0Let’s do 2.0Version 2.0 traffic…

Another common approach is to have individual feature negotiation
rather than version numbers. For instance, the TCE might say
“do you know how to make grilled cheese” and the THE would say
“yes” or “no”. In that case, you can roll out individual features
rather than have a big version number jump.
Sometimes, systems will have both types of negotiation,
with the version number indicating a pile of features that
go together and also being able to negotiate individual
features. TLS is actually one such protocol, though the
features are called “extensions” (not an uncommon name for this). So you
get something like:

TCETCETHETHEHello, I do “toaster oven”, “grilled cheese”, “bagels”I can do “bagels”OK, let’s toast some bagels

For non-security protocol, or rather ones where you
don’t need to worry about attackers, or rather those where you don’t
think you need to worry about attackers, this kind of approach mostly works
pretty well, though there’s always the risk that someone will
screw up their side of the negotiation. With protocols
that are security relevant, however, things are a little
different. Let’s say that in TCP 2.0 we decide to add
encryption. So the negotiation looks pretty much the same as before:

TCETCETHETHEHello, I speak versions 1.0, 2.0Let’s do 2.0Encrypted traffic

But since we’re talking security we need to assume someone might be
attacking us, and in particular they might be tampering with the
traffic, like so:

TCETCEAttackerAttackerTHETHEHello, I speak versions 1.0, 2.0Hello, I speak version 1.0 Let’s do 1.0Unencrypted traffic

This is what’s called a downgrade attack or a bid-down attack.
Even though in principle both sides could do version 2.0 (and an
encrypted channel), the attacker has forced them down to 1.0
(and a clear channel). Similar attacks can be mounted
against negotiation of cryptographic features. Consider,
for instance, the case where we are negotiating cryptographic
algorithms and each side supports both AES (a strong algorithm)
and DES (a weak algorithm), and the attacker forces both sides
down to DES:

TCETCEAttackerAttackerTHETHEI can do AES, DESI can do DES OK, let’s do DESTraffic encrypted with DES

There are two basic defenses against this kind of downgrade attack.
The first is for sides to remember the other side’s capabilities
and complain if those expectations are violated. So, for instance,
the first time that the TCE and THE communicate, the TCE
notices that the THE can do TCP 2.0 and from then on it refuses
to do TCP 1.0. Obviously, an attacker can downgrade you on the
first communication, but if you ever get a communication without
the attacker in the way, then you are immune from attack
thereafter (at least until both sides upgrade again). This
isn’t a fantastic defense for a number of reasons, but it’s
more or less the best you can do in the non-cryptographic setting.
In the setting where you are building a security protocol, however,
there’s a better solution. Most association-oriented security
protocols (SSL/TLS, IPsec, etc.) have a handshake phase where
they do version/feature negotiation and key establishment, followed
by a data transfer phase where the actual communications happen.
In most such protocols, the handshake phase includes an integrity
check over the handshake messages. So, for instance, in SSL/TLS,
the Finished messages include a Message Authentication
Code
(MAC) computed over the handshake and keyed with the
exchanged master secret:

ClientClientServerServerClientHelloServerHello, Certificate, ServerHelloDoneClientKeyExchange, ChangeCipherSpec, FinishedChangeCipherSpec, Finished

Any tampering with any of the handshake values causes the handshake to
fail. This makes downgrade attacks more difficult: as long as the
weakest share key exchange protocol and the weakest shared MAC are
sufficiently strong (both of these things are true for TLS), then
pretty much everything else can be negotiated safely, including
features and version numbers.
[Technical note: SSL version 2 didn’t have anti-downgrade defenses
and so there’s some other anti-downgrade mechanisms in
SSL/TLS as well.]
This is why it’s so important to establish a baseline level of
cryptographic security in the first level of the protocol, so
you can prevent downgrade attack to the nonsecure version.

Attacks on TLS 1.1 Negotiation

Based on what I said above, it would seem that rolling out TLS 1.1
securely would be no problem. And if everything was perfect, then
that would indeed be true. Unfortunately, everything is not perfect.
In order for version negotiation to work properly, a version X
implementation needs to accept offers of version Y > X
(although of course it will negotiate version X).
However, some nontrivial number of TLS servers and/or intermediaries
(on the order of 1%) will not complete the TLS handshake if TLS 1.1 is offered
(I don’t mean they negotiate 1.0 but instead an error is observed).
There are similar problems (though less extensive with TLS extensions
and offering TLS 1.0 as opposed to SSLv3).

No browser wants to break on 1% of the sites in the world, so
instead when some browser clients (at least Chrome and Firefox)
encounter a server which throws some error with a modern
ClientHello, they seamlessly fall back to older
versions. I.e., something like this (the exact details of the fallback order depend on the browser):

ClientClientServerServerClientHello (TLS 1.0)TCP FINClientHello (SSLv3)ClientKeyExchange, ChangeCipherSpec, FinishedChangeCipherSpec, Finished

It seems very likely that browsers will continue this behavior for
negotiating TLS 1.1 and/or 1.2.
Here’s the problem: this fallback happens outside of the ordinary
TLS version negotiation machinery, so it’s not protected by any of
the cryptographic checks designed to prevent downgrade attack.
Any attacker can forge a TCP FIN or RST, thus forcing clients
back to SSLv3, TLS 1.0, or whatever the lowest version they support
is. The attack looks like this:

ClientClientAttackerAttackerServerServerClientHello (TLS 1.0)TCP FIN ClientHello (SSLv3)ClientKeyExchange, ChangeCipherSpec, FinishedChangeCipherSpec, Finished

The underlying problem here is that the various extension mechanisms
for TLS weren’t completely tested (or in some cases, specified; extensions in particular weren’t
part of SSLv3), and so the browsers have to fall back on ad hoc
feature/version negotiation mechanisms. Unfortunately, those mechanisms,
unlike the official mechanisms, aren’t secure against downgrade
attack.1

There is, however, one SSL/TLS negotiation mechanism that
is extremely reliable: cipher suite negotiation. In TLS,
each cipher suite is rendered as a 16-bit number: the client
offers a pile of cipher suites and the server selects the
one it likes. Because new cipher suites are introduced
fairly regularly, and ignoring unknown suites is so easy,
this mechanism has gotten a lot of testing, and it works
pretty well, even through nearly all intermediaries. The result
is that if you really need to have downgrade attack resistance,
you need to put something in the cipher suites field. This is
the idea behind the Signaling Cipher Suite Value used
by the TLS Renegotiation Indication Extension [RFC 5746].
Recently, there have been
several
proposals that are intended
to indicate TLS 1.1 and/or extension support in the cipher suite
field. The idea here is to allow detection of version rollback
attacks. Once you can detect version rollback, then you can
use the ordinary handshake anti-tampering mechanisms to detect
removal of extensions.2

The bad news about these mechanisms is that they require upgrading
the server to detect the new cipher suite. On the other hand, they
can be incrementally deployed.
(Yngve Pettersen has a client-side only proposal which leverages
the RI SCSV to a similar end, but relies on the assumption that
any server which does RI is modern enough to handle extensions
properly).

What’s the lesson here? Minimally, this kind of negotiation facility
needs to be clearly specified from the start and then extensively
tested (and hopefully exercised as soon as possible). Once you’ve
got a significant installed base of noncompliant implementations,
it gets very difficult to distinguish a noncompliant peer and
a downgrade attack and thus problematic to refuse to connect to
apparently noncompliant peers.

1 Note that this isn’t always a big deal. Consider, for
instance, the TLS Server Name Indication message, which allows a server
to host multiple HTTPS sites on the same IP. The attacker could force
an SNI downgrade, but this will generally just cause a connection
failure, which they could have easily have done by forging an
RST for every connection. Downgrade attacks are mostly an issue
when the attacker is forcing you to a weaker security posture, rather
than just breaking stuff.

Share this post

Share on facebook
Share on linkedin
Share on print
Share on email

Subscribe to our Monthly Cyber Security Digest

Get monthly content to keep you up to date on the latest news and tips