Subject: [TLS] TLS and unnecessary complexity

From: Watson Ladd <[email-masked]>
Date: Thu, 13 Mar 2014 20:13:27 -0700

Dear all,

TLS is supposed to do three things.
1: Make connections in side of which data is secret, no matter what is
sent through them.
2: Let one, both, or none of these sides be authenticated by a public
key, plus additional information which TLS doesn't handle or impose
restrictions on.
3: Provide information that only the two ends of the connection can
possibly know. (SRTP, Channel Binding, etc).

TLS 1.2 succeeds only at 1, and only in some configurations. 1,2,and 3
can be achieved with more than ordinary care. TLS 1.0 can't achieve 1,
and neither can TLS 1.1. SSL v3 is utterly terrible. In order to fix
this you need to deploy all sorts of things not in the RFCs that claim
to define TLS, but are rather in extensions.

Furthermore, this assumes that both sides actually can reach TLS 1.2.
Unnecessary fallbacks are still not fixed. Each implementation is a
ball of mud in the usual case: PolarSSL is slightly better. The
specification is useful for implementors, but not for auditors: there
is no explicit state machine, nor is it easy to determine how
particular handshakes work. This is why the security failures of these
past few years happened: it was impossible to determine they could
not. Even when security issues where known, they were not fixed
properly.

The complexity of the protocol shows up in the implementations.

By contrast a complete implementation of CurveCP fits in fewer pages
than RFC 5246 takes to define the language it uses to explain the
structures of TLS. The core cryptographic code is 16,000 characters.
Purists will object that CurveCP doesn't do authentication, and they
are right, but TLS doesn't do any of the TCP functions CurveCP does.
Passing an opaque blob to higher levels is probably much shorter than
a TCP implementation.

This failure mode is not unique to TLS: the Scheme specification is
shorter then the index to the Common Lisp specification. However, TLS
is inevitably part of every TCB, because of its usefulness and
ubiquity. Attempts such as MinimalLT to replace it recognise this and
as a result are dead simple.

How can TLS 1.3 solve this problem?

TLS 1.3 should be described as a state machine that receives and sends
messages. The functions used to send and receive messages should be
deliberately crippled to force the author to remove complexity as much
as possible. This would make it much easier to catch things like the
return of renegotiation bugs, as the state machine would have enabled
tools like ProVerif to run on it. There is a reason miTLS caught the
resumption bug: they were the only people looking with tools powerful
enough.

No reference should be made to anything beyond the definition of
cryptographic transforms. Certificates should be opaque and handed to
higher layers, to enable DANE to work on the same basis as X509.
Necessary extensions should be documented in the spec itself.

All messages should be from regular languages. The current TLS spec
fails badly in this respect. This is necessary to write clean,
correct, parsing code.

Key verification serves the purpose of making cryptographers unhappy.
It should be removed. (I can explain at length why this is so)

Finally, we should use well-understood primitives in correct manners,
and prove that our use is correct.

Sincerely,
Watson Ladd