Filename: 169-eliminating-renegotiation.txt
Title: Eliminate TLS renegotiation for the Tor connection handshake
Author: Nick Mathewson
Created: 27-Jan-2010
Status: Superseded
Target: 0.2.2
Superseded-By: 176
1. Overview
I propose a backward-compatible change to the Tor connection
establishment protocol to avoid the use of TLS renegotiation.
Rather than doing a TLS renegotiation to exchange certificates
and authenticate the original handshake, this proposal takes an
approach similar to Steven Murdoch's proposal 124, and uses Tor
cells to finish authenticating the parties' identities once the
initial TLS handshake is finished.
Terminological note: I use "client" below to mean the Tor
instance (a client or a relay) that initiates a TLS connection,
and "server" to mean the Tor instance (a relay) that accepts it.
2. Motivation and history
In the original Tor TLS connection handshake protocol ("V1", or
"two-cert"), parties that wanted to authenticate provided a
two-cert chain of X.509 certificates during the handshake setup
phase. Every party that wanted to authenticate sent these
certificates.
In the current Tor TLS connection handshake protocol ("V2", or
"renegotiating"), the parties begin with a single certificate
sent from the server (responder) to the client (initiator), and
then renegotiate to a two-certs-from-each-authenticating-party.
We made this change to make Tor's handshake look like a browser
speaking SSL to a webserver. (See proposal 130, and
tor-spec.txt.) To tell whether to use the V1 or V2 handshake,
servers look at the list of ciphers sent by the client. (This is
ugly, but there's not much else in the ClientHello that they can
look at.) If the list contains any cipher not used by the V1
protocol, the server sends back a single cert and expects a
renegotiation. If the client gets back a single cert, then it
withholds its own certificates until the TLS renegotiation phase.
In other words, initiator behavior now looks like this:
- Begin TLS negotiation with V2 cipher list; wait for
certificate(s).
- If we get a certificate chain:
- Then we are using the V1 handshake. Send our own
certificate chain as part of this initial TLS handshake
if we want to authenticate; otherwise, send no
certificates. When the handshake completes, check
certificates. We are now mutually authenticated.
Otherwise, if we get just a single certificate:
- Then we are using the V2 handshake. Do not send any
certificates during this handshake.
- When the handshake is done, immediately start a TLS
renegotiation. During the renegotiation, expect
a certificate chain from the server; send a certificate
chain of our own if we want to authenticate ourselves.
- After the renegotiation, check the certificates. Then
send (and expect) a VERSIONS cell from the other side to
establish the link protocol version.
And V2 responder behavior now looks like this:
- When we get a TLS ClientHello request, look at the cipher
list.
- If the cipher list contains only the V1 ciphersuites:
- Then we're doing a V1 handshake. Send a certificate
chain. Expect a possible client certificate chain in
response.
Otherwise, if we get other ciphersuites:
- We're using the V2 handshake. Send back a single
certificate and let the handshake complete.
- Do not accept any data until the client has renegotiated.
- When the client is renegotiating, send a certificate
chain, and expect (possibly multiple) certificates in
reply.
- Check the certificates when the renegotiation is done.
Then exchange VERSIONS cells.
Late in 2009, researchers found a flaw in most applications' use
of TLS renegotiation: Although TLS renegotiation does not
reauthenticate any information exchanged before the renegotiation
takes place, many applications were treating it as though it did,
and assuming that data sent _before_ the renegotiation was
authenticated with the credentials negotiated _during_ the
renegotiation. This problem was exacerbated by the fact that
most TLS libraries don't actually give you an obvious good way to
tell where the renegotiation occurred relative to the datastream.
Tor wasn't directly affected by this vulnerability, but its
aftermath hurts us in a few ways:
1) OpenSSL has disabled renegotiation by default, and created
a "yes we know what we're doing" option we need to set to
turn it back on. (Two options, actually: one for openssl
0.9.8l and one for 0.9.8m and later.)
2) Some vendors have removed all renegotiation support from
their versions of OpenSSL entirely, forcing us to tell
users to either replace their versions of OpenSSL or to
link Tor against a hand-built one.
3) Because of 1 and 2, I'd expect TLS renegotiation to become
rarer and rarer in the wild, making our own use stand out
more.
3. Design
3.1. The view in the large
Taking a cue from Steven Murdoch's proposal 124, I propose that
we move the work currently done by the TLS renegotiation step
(that is, authenticating the parties to one another) and do it
with Tor cells instead of with TLS.
Using _yet another_ variant response from the responder (server),
we allow the client to learn that it doesn't need to rehandshake
and can instead use a cell-based authentication system. Once the
TLS handshake is done, the client and server exchange VERSIONS
cells to determine link protocol version (including
handshake version). If they're using the handshake version
specified here, the client and server arrive at link protocol
version 3 (or higher), and use cells to exchange further
authentication information.
3.2. New TLS handshake variant
We already used the list of ciphers from the clienthello to
indicate whether the client can speak the V2 ("renegotiating")
handshake or later, so we can't encode more information there.
We can, however, change the DN in the certificate passed by the
server back to the client. Currently, all V2 certificates are
generated with CN values ending with ".net". I propose that we
have the ".net" commonName ending reserved to indicate the V2
protocol, and use commonName values ending with ".com" to
indicate the V3 ("minimal") handshake described herein.
Now, once the initial TLS handshake is done, the client can look
at the server's certificate(s). If there is a certificate chain,
the handshake is V1. If there is a single certificate whose
subject commonName ends in ".net", the handshake is V2 and the
client should try to renegotiate as it would currently.
Otherwise, the client should assume that the handshake is V3+.
[Servers should _only_ send ".com" addesses, to allow room for
more signaling in the future.]
3.3. Authenticating inside Tor
Once the TLS handshake is finished, if the client renegotiates,
then the server should go on as it does currently.
If the client implements this proposal, however, and the server
has shown it can understand the V3+ handshake protocol, the
client immediately sends a VERSIONS cell to the server
and waits to receive a VERSIONS cell in return. We negotiate
the Tor link protocol version _before_ we proceed with the
negotiation, in case we need to change the authentication
protocol in the future.
Once either party has seen the VERSIONS cell from the other, it
knows which version they will pick (that is, the highest version
shared by both parties' VERSIONS cells). All Tor instances using
the handshake protocol described in 3.2 MUST support at least
link protocol version 3 as described here.
On learning the link protocol, the server then sends the client a
CERT cell and a NETINFO cell. If the client wants to
authenticate to the server, it sends a CERT cell, an AUTHENTICATE
cell, and a NETINFO cell; or it may simply send a NETINFO cell if
it does not want to authenticate.
The CERT cell describes the keys that a Tor instance is claiming
to have. It is a variable-length cell. Its payload format is:
N: Number of certs in cell [1 octet]
N times:
CLEN [2 octets]
Certificate [CLEN octets]
Any extra octets at the end of a CERT cell MUST be ignored.
Each certificate has the form:
CertType [1 octet]
CertPurpose [1 octet]
PublicKeyLen [2 octets]
PublicKey [PublicKeyLen octets]
NotBefore [4 octets]
NotAfter [4 octets]
SignerID [HASH256_LEN octets]
SignatureLen [2 octets]
Signature [SignatureLen octets]
where CertType is 1 (meaning "RSA/SHA256")
CertPurpose is 1 (meaning "link certificate")
PublicKey is the DER encoding of the ASN.1 representation
of the RSA key of the subject of this certificate
NotBefore is a time in HOURS since January 1, 1970, 00:00
UTC before which this certificate should not be
considered valid.
NotAfter is a time in HOURS since January 1, 1970, 00:00
UTC after which this certificate should not be
considered valid.
SignerID is the SHA-256 digest of the public key signing
this certificate
and Signature is the signature of all the other fields in
this certificate, using SHA256 as described in proposal
158.
While authenticating, a server need send only a self-signed
certificate for its identity key. (Its TLS certificate already
contains its link key signed by its identity key.) A client that
wants to authenticate MUST send two certificates: one containing
a public link key signed by its identity key, and one self-signed
cert for its identity.
Tor instances MUST ignore any certificate with an unrecognized
CertType or CertPurpose, and MUST ignore extra bytes in the cert.
The AUTHENTICATE cell proves to the server that the client with
whom it completed the initial TLS handshake is the one possessing
the link public key in its certificate. It is a variable-length
cell. Its contents are:
SignatureType [2 octets]
SignatureLen [2 octets]
Signature [SignatureLen octets]
where SignatureType is 1 (meaning "RSA-SHA256") and Signature is
an RSA-SHA256 signature of the HMAC-SHA256, using the TLS master
secret key as its key, of the following elements:
- The SignatureType field (0x00 0x01)
- The NUL terminated ASCII string: "Tor certificate verification"
- client_random, as sent in the Client Hello
- server_random, as sent in the Server Hello
Once the above handshake is complete, the client knows (from the
initial TLS handshake) that it has a secure connection to an
entity that controls a given link public key, and knows (from the
CERT cell) that the link public key is a valid public key for a
given Tor identity.
If the client authenticates, the server learns from the CERT cell
that a given Tor identity has a given current public link key.
From the AUTHENTICATE cell, it knows that an entity with that
link key knows the master secret for the TLS connection, and
hence must be the party with whom it's talking, if TLS works.
3.4. Security checks
If the TLS handshake indicates a V2 or V3+ connection, the server
MUST reject any connection from the client that does not begin
with either a renegotiation attempt or a VERSIONS cell containing
at least link protocol version "3". If the TLS handshake
indicates a V3+ connection, the client MUST reject any connection
where the server sends anything before the client has sent a
VERSIONS cell, and any connection where the VERSIONS cell does
not contain at least link protocol version "3".
If link protocol version 3 is chosen:
Clients and servers MUST check that all digests and signatures
on the certificates in CERT cells they are given are as
described above.
After the VERSIONS cell, clients and servers MUST close the
connection if anything besides a CERT or AUTH cell is sent
before the
CERT or AUTHENTICATE cells anywhere after the first NETINFO
cell must be rejected.
... [write more here. What else?] ...
3.5. Summary
We now revisit the protocol outlines from section 2 to incorporate
our changes. New or modified steps are marked with a *.
The new initiator behavior now looks like this:
- Begin TLS negotiation with V2 cipher list; wait for
certificate(s).
- If we get a certificate chain:
- Then we are using the V1 handshake. Send our own
certificate chain as part of this initial TLS handshake
if we want to authenticate; otherwise, send no
certificates. When the handshake completes, check
certificates. We are now mutually authenticated.
Otherwise, if we get just a single certificate:
- Then we are using the V2 or the V3+ handshake. Do not
send any certificates during this handshake.
* When the handshake is done, look at the server's
certificate's subject commonName.
* If it ends with ".net", we're doing a V2 handshake:
- Immediately start a TLS renegotiation. During the
renegotiation, expect a certificate chain from the
server; send a certificate chain of our own if we
want to authenticate ourselves.
- After the renegotiation, check the certificates. Then
send (and expect) a VERSIONS cell from the other side
to establish the link protocol version.
* If it ends with anything else, assume a V3 or later
handshake:
* Send a VERSIONS cell, and wait for a VERSIONS cell
from the server.
* If we are authenticating, send CERT and AUTHENTICATE
cells.
* Send a NETINFO cell. Wait for a CERT and a NETINFO
cell from the server.
* If the CERT cell contains a valid self-identity cert,
and the identity key in the cert can be used to check
the signature on the x.509 certificate we got during
the TLS handshake, then we know we connected to the
server with that identity. If any of these checks
fail, or the identity key was not what we expected,
then we close the connection.
* Once the NETINFO cell arrives, continue as before.
And V3+ responder behavior now looks like this:
- When we get a TLS ClientHello request, look at the cipher
list.
- If the cipher list contains only the V1 ciphersuites:
- Then we're doing a V1 handshake. Send a certificate
chain. Expect a possible client certificate chain in
response.
Otherwise, if we get other ciphersuites:
- We're using the V2 handshake. Send back a single
certificate whose subject commonName ends with ".com",
and let the handshake complete.
* If the client does anything besides renegotiate or send a
VERSIONS cell, drop the connection.
- If the client renegotiates immediately, it's a V2
connection:
- When the client is renegotiating, send a certificate
chain, and expect (possibly multiple certificates in
reply).
- Check the certificates when the renegotiation is done.
Then exchange VERSIONS cells.
* Otherwise we got a VERSIONS cell and it's a V3 handshake.
* Send a VERSIONS cell, a CERT cell, an AUTHENTICATE
cell, and a NETINFO cell.
* Wait for the client to send cells in reply. If the
client sends a CERT and an AUTHENTICATE and a NETINFO,
use them to authenticate the client. If the client
sends a NETINFO, it is unauthenticated. If it sends
anything else before its NETINFO, it's rejected.
4. Numbers to assign
We need a version number for this link protocol. I've been
calling it "3".
We need to reserve command numbers for CERT and AUTH cells. I
suggest that in link protocol 3 and higher, we reserve command
numbers 128..240 for variable-length cells. (241-256 we can hold
for future extensions.)
5. Efficiency
This protocol adds a round-trip step when the client sends a
VERSIONS cell to the server and waits for the {VERSIONS, CERT,
NETINFO} response in turn. (The server then waits for the
client's {NETINFO} or {CERT, AUTHENTICATE, NETINFO} reply,
but it would have already been waiting for the client's NETINFO,
so that's not an additional wait.)
This is actually fewer round-trip steps than required before for
TLS renegotiation, so that's a win.
6. Open questions:
- Should we use X.509 certificates instead of the certificate-ish
things we describe here? They are more standard, but more ugly.
- May we cache which certificates we've already verified? It
might leak in timing whether we've connected with a given server
before, and how recently.
- Is there a better secret than the master secret to use in the
AUTHENTICATE cell? Say, a portable one? Can we get at it for
other libraries besides OpenSSL?
- Does using the client_random and server_random data in the
AUTHENTICATE message actually help us? How hard is it to pull
them out of the OpenSSL data structure?
- Can we give some way for clients to signal "I want to use the
V3 protocol if possible, but I can't renegotiate, so don't give
me the V2"? Clients currently have a fair idea of server
versions, so they could potentially do the V3+ handshake with
servers that support it, and fall back to V1 otherwise.
- What should servers that don't have TLS renegotiation do? For
now, I think they should just get it. Eventually we can
deprecate the V2 handshake as we did with the V1 handshake.