Some of the parallel discussion on the SSH list - especially comments by Simon Tatham and Niels Möller - made me think of an alternative design that would not only hide TLS headers but also ensure that they are integrity-checked by the receiver *before* the receiver attempts to interpret the record header in any way. This alternative approach already feels to me like an improvement over my last one, and perhaps even those who are skeptical of the need to encrypt TLS headers might appreciate the desirability of closing vulnerabilities to length-fiddling attacks: e.g., where an attacker sets the high bit of the length field in the last TLS record so that the receiver will likely hang on a long read before detecting the change.
Proposal: The basic idea is in some respects even simpler than the last one: 1. We move the TLS header from the "additional data" field to the start of the "plaintext" field. That is, the sender encrypts the header along with the payload, and the receiver decrypts and integrity-checks the header along with the payload, using the standard AEAD interface. The "additional data" field now contains *only* the sequence number, which both sender and receiver track and compute implicitly. 2. The 2-byte length field in each record's header no longer indicates the length of the *current* record but instead indicates the length of the *next* record. The length of the first record might be defined in a new field we add to the handshake/key-exchange protocol, or it might simply be set to some well-known standard first record size. That's basically it. The key advantage is that this way the receiver always "knows" the correct size of each record before having to read or interpret any part of it in any way. In fact, because the record is fully encrypted, the receiver implementation is basically forced to use the AEAD to decrypt and integrity-check the record before doing anything at all with it, which closes down not only the well-known length-fiddling attack that has dogged SSH, but a whole class of possible potential implementation bugs regarding the (delicate) handling of cleartext TLS headers before they've been integrity-checked. Basically, this ensures that if the receiver have any bugs in the handling of the TLS header, they can be exploited only by its communication partner, and not by an attacker in the middle of the path. To me this seems like a useful robustness benefit completely independent of the (also desirable) benefits with respect to traffic analysis. Choosing next-record lengths: Of course this approach presents the minor challenge that the sender must always "commit" to the length of the next record before sending the current one. But this challenge is pretty easy to deal with. The easiest way to handle it, of course, is if the sender simply pads all packets to the same record length - a solution I would generally be quite happy with due to its complementary traffic analysis resistance benefits, and I would even favor explicitly encouraging that solution in the TLS RFC. I would love it if the next TLS RFC ended up containing a clause of the form: The TLS sender SHOULD always transmit TLS records of length exactly X, unless this is deemed impractical due to overriding performance or bandwidth-efficiency considerations. ...where "X" is some reasonable value we discuss and decide on. But my (new) proposal does not require all TLS implementations to maintain a fixed record size. If the sender implementation wants to use variable-size records, it can still process batches of records written together normally up until the last record in the batch. But when processing the last record in a write - or in general the last record before "going idle" where it does not yet have a next record to send - the sender simply "picks something." That something might for example be a minimum record size, meaning the next record will be big enough to hold a "next record length" indicating a useful length, but will otherwise be basically a no-op record, so we'll pay the cost of an extra small record and AEAD encryption/decryption each time transmission resumes after being idle. Alternatively the sender of variable-length records might pick a "typical record size" as the next-record-size to transmit in the last record in a burst; that way once transmission resumes the next record can probably carry useful data, but might need padding if its committed size is larger than the amount of data to be transmitted. The (important) existence of the padding mechanism already added in TLS 1.3 makes this alternative possible. DTLS: Now there's still the important question of whether this (new) proposal could be made to work in the context of DTLS. For the DTLS case, my current thinking is that some elements of my earlier proposal is probably more suitable: namely using a stream cipher (or AEAD used as a stream cipher) to encrypt and recognize the explicitly-transmitted sequence numbers that DTLS needs. This could operate basically the same as I described in my earlier E-mail on this topic. Note that the length field is no longer a problem in DTLS as it is in TLS, because the receiver already gets the length of the datagram from UDP. Comments/discussion? Is the above more (or less) palatable than my previous proposal? Cheers Bryan
smime.p7s
Description: S/MIME Cryptographic Signature
_______________________________________________ TLS mailing list TLS@ietf.org https://www.ietf.org/mailman/listinfo/tls