EKR: July 2012 Archives


July 19, 2012

The other day I went to Home Depot to buy some party supplies (incidentally, check out the party invitation here and the bonus Web site here. It's some of my better work.). One of the things I wanted was a set of rope lights. I eventually picked up three sets of 48' lights for $36.48. However, when I went to ring them up (you know Home Depot is almost all self-check, right?) two rang up at $62.48.

Looking closely, what happened is that the lights were packaged in clear plastic clamshell packaging with two paper labels, one in the front and one in the back. The paper label in the front showed the 48' lights listed above. The back label (the one with the bar code) showed 27' LED lights (LEDs are cooler and cool == expensive). It took a while for Home Depot to sort the problem out. Customer service's initial reaction was that someone had returned a set of the cheap lights but swapped the back labels so that they could get a larger refund. But then they had some more lights pulled off the shelf and they were mismatched as well, so things started to look a bit confused. Eventually, they just pulled the back pages out of the package (I guess to make it hard for me to do a return) and sent me on my way.

Here's the screwed up thing: nobody in this entire transaction was sure which set of actual lights I had in my hand. The matching package (the one which had rung up as expected) looked a lot like the other two packages, but really these things look pretty similar and after all we didn't know that any of the packages was right. I offered to take them out and measure them for length, but nobody seemed interested. So, at the time I walked out the door it seemed quite possible that Home Depot had sold me $188 worth of lights for $109. Of course, I assured them that I would bring them back if they turned out to be the LED lights, but they had no way of knowing I actually would (or of verifying if I did or not). I actually tried to explain this several times, but nobody seemed to care and eventually I gave up and left.

Turns out that they were the right lights after all, though.


July 16, 2012

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:

TCE TCE THE THE Hello, I speak versions 1.0, 2.0 Let's do 2.0 Version 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:

TCE TCE THE THE Hello, 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:

TCE TCE THE THE Hello, I speak versions 1.0, 2.0 Let's do 2.0 Encrypted 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:

TCE TCE Attacker Attacker THE THE Hello, I speak versions 1.0, 2.0 Hello, I speak version 1.0 Let's do 1.0 Unencrypted 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:

TCE TCE Attacker Attacker THE THE I can do AES, DES I can do DES OK, let's do DES Traffic 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:

Client Client Server Server ClientHello ServerHello, Certificate, ServerHelloDone ClientKeyExchange, ChangeCipherSpec, Finished ChangeCipherSpec, 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):

Client Client Server Server ClientHello (TLS 1.0) TCP FIN ClientHello (SSLv3) ClientKeyExchange, ChangeCipherSpec, Finished ChangeCipherSpec, 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:

Client Client Attacker Attacker Server Server ClientHello (TLS 1.0) TCP FIN ClientHello (SSLv3) ClientKeyExchange, ChangeCipherSpec, Finished ChangeCipherSpec, 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.