1/*! # A review of TLS Implementation Vulnerabilities
2
3An important part of engineering involves studying and learning from the mistakes of the past.
4It would be tremendously unfortunate to spend effort re-discovering and re-fixing the same
5vulnerabilities that were discovered in the past.
6
7## Memory safety
8
9Being written entirely in the safe-subset of Rust immediately offers us freedom from the entire
10class of memory safety vulnerabilities. There are too many to exhaustively list, and there will
11certainly be more in the future.
12
13Examples:
14
15- Heartbleed [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160) (OpenSSL)
16- Memory corruption in ASN.1 decoder [CVE-2016-2108](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2108) (OpenSSL)
17- Buffer overflow in read_server_hello [CVE-2014-3466](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3466) (GnuTLS)
18
19## `goto fail`
20
21This is the name of a vulnerability in Apple Secure Transport [CVE-2014-1266](https://nvd.nist.gov/vuln/detail/CVE-2014-1266).
22This boiled down to the following code, which validates the server's signature on the key exchange:
23
24```c
25 if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
26 goto fail;
27 if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
28 goto fail;
29> goto fail;
30 if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
31 goto fail;
32```
33
34The marked line was duplicated, likely accidentally during a merge. This meant
35the remaining part of the function (including the actual signature validation)
36was unconditionally skipped.
37
38Ultimately the one countermeasure to this type of bug is basic testing: that a
39valid signature returns success, and that an invalid one does not. rustls
40has such testing, but this is really table stakes for security code.
41
42Further than this, though, we could consider that the *lack* of an error from
43this function is a poor indicator that the signature was valid. rustls, instead,
44has zero-size and non-copyable types that indicate a particular signature validation
45has been performed. These types can be thought of as *capabilities* originated only
46by designated signature verification functions -- such functions can then be a focus
47of manual code review. Like capabilities, values of these types are otherwise unforgeable,
48and are communicable only by Rust's move semantics.
49
50Values of these types are threaded through the protocol state machine, leading to terminal
51states that look like:
52
53```ignore
54struct ExpectTraffic {
55 (...)
56 _cert_verified: verify::ServerCertVerified,
57 _sig_verified: verify::HandshakeSignatureValid,
58 _fin_verified: verify::FinishedMessageVerified,
59}
60```
61
62Since this state requires a value of these types, it will be a compile-time error to
63reach that state without performing the requisite security-critical operations.
64
65This approach is not infallible, but it has zero runtime cost.
66
67## State machine attacks: EarlyCCS and SMACK/SKIP/FREAK
68
69EarlyCCS [CVE-2014-0224](https://nvd.nist.gov/vuln/detail/CVE-2014-0224) was a vulnerability in OpenSSL
70found in 2014. The TLS `ChangeCipherSpec` message would be processed at inappropriate times, leading
71to data being encrypted with the wrong keys (specifically, keys which were not secret). This resulted
72from OpenSSL taking a *reactive* strategy to incoming messages ("when I get a message X, I should do Y")
73which allows it to diverge from the proper state machine under attacker control.
74
75[SMACK](https://mitls.org/pages/attacks/SMACK) is a similar suite of vulnerabilities found in JSSE,
76CyaSSL, OpenSSL, Mono and axTLS. "SKIP-TLS" demonstrated that some implementations allowed handshake
77messages (and in one case, the entire handshake!) to be skipped leading to breaks in security. "FREAK"
78found that some implementations incorrectly allowed export-only state transitions (i.e., transitions that
79were only valid when an export ciphersuite was in use).
80
81rustls represents its protocol state machine carefully to avoid these defects. We model the handshake,
82CCS and application data subprotocols in the same single state machine. Each state in this machine is
83represented with a single struct, and transitions are modelled as functions that consume the current state
84plus one TLS message[^1] and return a struct representing the next state. These functions fully validate
85the message type before further operations.
86
87A sample sequence for a full TLSv1.2 handshake by a client looks like:
88
89- `hs::ExpectServerHello` (Note: ClientHello is logically sent before this state); transition to `tls12::ExpectCertificate`
90- `tls12::ExpectCertificate`; transition to `tls12::ExpectServerKX`
91- `tls12::ExpectServerKX`; transition to `tls12::ExpectServerDoneOrCertReq`
92- `tls12::ExpectServerDoneOrCertReq`; delegates to `tls12::ExpectCertificateRequest` or `tls12::ExpectServerDone` depending on incoming message.
93 - `tls12::ExpectServerDone`; transition to `tls12::ExpectCCS`
94- `tls12::ExpectCCS`; transition to `tls12::ExpectFinished`
95- `tls12::ExpectFinished`; transition to `tls12::ExpectTraffic`
96- `tls12::ExpectTraffic`; terminal state; transitions to `tls12::ExpectTraffic`
97
98In the future we plan to formally prove that all possible transitions modelled in this system of types
99are correct with respect to the standard(s). At the moment we rely merely on exhaustive testing.
100
101[^1]: a logical TLS message: post-decryption, post-fragmentation.
102
103
104*/
105