Subject: [tcpinc] The TCP-ENO draft

From: Yoav Nir <[email-masked]>
Date: Thu, 10 Mar 2016 23:15:40 +0200

Hi,

I’ve reviewed version -01 of the TCP-ENO draft. In general I find it understandable enough that I could implement it from the spec. 

As a protocol, it is more complex than I would have liked, considering that its entire purpose is to choose between two mechanisms, and that we don’t really expect more such mechanisms to pop up, because both proposals already have quite a bit of algorithm agility and several variations.  

Most of the complexity could have been avoided if we were willing to sacrifice a round-trip: “I support this and that — I choose that — first message of that” and require that those first negotiation messages be incorporated into some hash in the protocol “that”.  But adding a round-trip is, I guess, anathema, so we end up with an encoding for “I support this and that, and here’s the first message of this and the first message of that — I choose that and here’s the first reply of that”, which explains part of the complexity.

Another part is the general options that specify things like application awareness, because applications can be extended to recognize and configure tcpcrypt and then channel-bind with it. I am not convinced that we actually want this. If changing applications is part of the game, the applications can change enough to use TLS. Our use case is opportunistic - add encryption to existing HTTP applications, telnet, FTP and others that are typically deployed unencrypted. I don’t believe we need application integration at all. To summarize, I think this could be simplified greatly. 

OK, that’s enough for my rant about complexity. Note that I don’t see any security issues from this. It’s just a generic “complexity is bad” rant. I think the security of the protocol in this draft is fine, but it does suffer from mission creep. There is an attempt to provide security against active attackers by modifying applications, which I believe is out of scope for this working group. We already have protocols for security against MITM: TLS, which requires modifying the application and IPsec.

More issues, mostly nits:

- In the introduction: "Increased option space in TCP ... could reduce round trip times and simplify protocols.”. No. Increased option space could reduce the *number* of round trips. RTT is pretty much a function of network topology, node delay and physics.

- Also in the introduction:
   o  API revisions to socket interfaces [RFC3493] could benefit from
      integration with TCP-level encryption, particularly if combined
      with technologies such as DANE [RFC6394].

And after that, DANE is never mentioned again. I can imagine some ways this could happen, but I don’t think an RFC should contain a “teaser" for a draft we’re going to write in 2018. If this is not specified in this spec, it should not be here.

   o  Cryptographic developments that either shorten or lengthen the
      minimal key exchange messages required could affect how such
      messages are best encoded in TCP segments.

This is also never explained. I can assume "shorten" is about adoption of elliptic or even hyper-elliptic curves and “lengthen" is about quantum resistant cryptography, but as it is, this bullet item is mysterious. Better to explain it or remove it.

The text in section 3 about the different kinds of bytes could be made clearer. And if the “marker byte” is just a length field, it should be called that. Here’s my shot at it:
   +---++---------+-------------------------------------------------+
   | v | cs       | Meaning                                         |
   +---+----------+-------------------------------------------------+
   | 1 |0x00-0x1f | Length byte. Length is the value of cs. See     |
   |   |          | section 3.4.                                    |
   | 0 |0x00-0x1f | General options. See section 3.3.               |
   |   |          |                                                 |
   | 1 |0x20-0x7f | Used to designate encryption specs. [1]         |
   |   |          |                                                 |
   | 0 |0x20-0x7f | Encryption specs without option data            |
   +-----------+----------------------------------------------------+
   
   [1] If preceded by a length byte, this byte is followed by option data of 
       the length specified by that byte. If not, the option data extends to 
       the end of the TCP option.

It is not clear to me why section 3.1 avoids the use of common terms like “client” and “server”, opting instead for “active opener” and “passive opener”. I realize that there are nuances in simultaneous open, but these are the exceptions, not the rule. As a rule, the client has role A and the server has role B.

The logic of assigning roles is rather complex to accommodate simultaneous open. There is a "b" bit that is sent explicitly and a "p" bit that is inferred from the other side's SYN packet (0=no ACK, 1=has ACK). Nowhere does it say "send 'b=1' if XXXXX; send 'b=0' if YYYYY". Apparently, b=1 means the sender plays the B role whereas b=0 means the sender plays the A role. And what if they both send the same thing?   "TCP-ENO fails and reverts to unencrypted TCP". 

The next paragraph makes things more complex by having the "p" bit be a tie-breaker. That seems wrong, because the "p" bit will be different only if one sender is an active opener (client), while the other is a passive opener (server), and in that case it's pretty easy to set the "b" bit so that it's 1 for the server and zero for the client. The hard case is simultaneous open where both sides believe they may be the active opener and thus both sides will also believe they are going to assume the A role. And in that case TCP-ENO will fail. Do we make it up to protocol designers or implementers to make sure that different sides to a connection have a different b bit?

It's not clear to me why the transcript in section 3.5 is useful. Everything done in TCPINC is supposed to be secure against passive eavesdropping, not active attacks. Tampering with transcripts is something an active attacker would do, and an active attacker can do much to circumvent everything in this document. Section 4.1 has the session ID depend on this transcript so as to prevent collisions with different specs, but it's still not clear why either side would want to tamper with it and how.

Section 4:
   o  Specs MUST NOT allow the negotiation of encryption modes that do
      not provide forward secrecy some bounded, short time after the
      close of a TCP connection.
      
That's not up to the specs. The best that specs can do is to *allow* forward secrecy by not requiring that session keys be derived from long-term keys and inputs sent in the clear. Nothing in any spec that mandates ECDHE, for example, prevents an implementation from hard-coding a key pair, or generating one just once.

Section 7 has requirements to prevent active attacks. I thought that was out of scope. It also recommends that applications be modified to verify that TCP-level encryption is present and verify that there is no MITM. I don't think this should be in scope. If we are allowed to require applications to be upgraded, we might as well upgrade them to use regular TLS.

---

From: David Mazieres <[email-masked]>
Date: Fri, 11 Mar 2016 01:59:39 -0800

Yoav Nir <[email-masked]> writes:

> I’ve reviewed version -01 of the TCP-ENO draft. In general I find it
> understandable enough that I could implement it from the spec.

Thanks for the detailed feedback.  Comments and clarifications in line.
For some of these points, I think improvements to the draft are obvious.
For others, I hope my response makes sense, in which case it's just a
question of clarifying motivation in the tcpeno draft.  For still
others, more discussion or suggestions may be warranted...

> As a protocol, it is more complex than I would have liked, considering
>that its entire purpose is to choose between two mechanisms, and that
>we don’t really expect more such mechanisms to pop up, because both
>proposals already have quite a bit of algorithm agility and several
>variations.

That is one of the goals.  The other goal is to abstract away the
specifics of the underlying encryption specs, so that people can update
TLS or tcpcrypt without needing to change applications.

> Another part is the general options that specify things like
> application awareness, because applications can be extended to
> recognize and configure tcpcrypt and then channel-bind with it. I am
> not convinced that we actually want this. If changing applications is
> part of the game, the applications can change enough to use TLS. Our
> use case is opportunistic - add encryption to existing HTTP
> applications, telnet, FTP and others that are typically deployed
> unencrypted. I don’t believe we need application integration at
> all. To summarize, I think this could be simplified greatly.

The problem is that changing a network application must generally be
done incrementally, where both the old and new versions interoperate for
some period.  The application aware bits are what allow you to change
the application without breaking wire compatibility--essentially a way
to shoehorn a STARTTLS command into the TCP header for protocols that
couldn't otherwise accommodate it.  It should also ideally facilitate
libraries that generically upgrade application security for multiple
applications without needing to find some clever unique way to embed a
signal in each protocol.  That's kind of what the (admittedly too
oblique) point about Dane was alluding to.

> OK, that’s enough for my rant about complexity. Note that I don’t see
> any security issues from this. It’s just a generic “complexity is bad”
> rant. I think the security of the protocol in this draft is fine, but
> it does suffer from mission creep. There is an attempt to provide
> security against active attackers by modifying applications, which I
> believe is out of scope for this working group.

The scope is set by the charter, which says "hooks for external
authentication must be made available."  So while this kind of channel
binding adds some complexity, I don't think anyone has (yet) suggested a
simpler way of complying with that requirement.

> - In the introduction: "Increased option space in TCP ... could reduce
> round trip times and simplify protocols.”. No. Increased option space
> could reduce the *number* of round trips. RTT is pretty much a
> function of network topology, node delay and physics.

Good catch.

> And after that, DANE is never mentioned again. I can imagine some ways
> this could happen, but I don’t think an RFC should contain a “teaser"
> for a draft we’re going to write in 2018. If this is not specified in
> this spec, it should not be here.

Right, see my comments about application aware bits above.  But we could
also delete this point if it is too oblique.

> This is also never explained. I can assume "shorten" is about adoption
> of elliptic or even hyper-elliptic curves and “lengthen" is about
> quantum resistant cryptography, but as it is, this bullet item is
> mysterious. Better to explain it or remove it.

Yeah, this too may be too oblique.  The point is that if you can fit a
public key in the SYN option space, that makes some things better.  And
if you can't fit a public key in a single TCP segment, then maybe you
want some kind of more complicated caching scheme.  Protocols for those
different situations would be so different that you are better off
designing each one from scratch than trying to anticipate all of them in
a tcpcrypt- or TLS-like protocol.

> The text in section 3 about the different kinds of bytes could be made clearer. And if the “marker byte” is just a length field, it should be called that. Here’s my shot at it:

This is an excellent suggestion.

> It is not clear to me why section 3.1 avoids the use of common terms
> like “client” and “server”, opting instead for “active opener” and
> “passive opener”. I realize that there are nuances in simultaneous
> open, but these are the exceptions, not the rule. As a rule, the
> client has role A and the server has role B.

Active/passive are just the terms established by RFC793.  Servers are
often but not always passive openers, so it seemed less ambiguous to
stick with the standard terminology.  We attempted to define this in as
clear a way as possible at the beginning of 3.1, but it's not set apart
from the rest of the text.  So we could also conceivably add a whole
section just on defining terms if you think it would clarify things.

> The logic of assigning roles is rather complex to accommodate
> simultaneous open. There is a "b" bit that is sent explicitly and a
> "p" bit that is inferred from the other side's SYN packet (0=no ACK,
> 1=has ACK). Nowhere does it say "send 'b=1' if XXXXX; send 'b=0' if
> YYYYY". Apparently, b=1 means the sender plays the B role whereas b=0
> means the sender plays the A role. And what if they both send the same
> thing?  "TCP-ENO fails and reverts to unencrypted TCP".

Ah... the b bit is set by the application.  Currently this is discussed
in the companion informational API document
(https://datatracker.ietf.org/doc/draft-bittau-tcpinc-api/).  However, I
we should say in the TCP-ENO that the b bit MUST be 0 by default and
implementations SHOULD provide a way for applications to set it to 1.
Otherwise, without that context I think the TCP-ENO draft must indeed
seem puzzling.

> The next paragraph makes things more complex by having the "p" bit be
> a tie-breaker. That seems wrong, because the "p" bit will be different
> only if one sender is an active opener (client), while the other is a
> passive opener (server), and in that case it's pretty easy to set the
> "b" bit so that it's 1 for the server and zero for the client. The
> hard case is simultaneous open where both sides believe they may be
> the active opener and thus both sides will also believe they are going
> to assume the A role. And in that case TCP-ENO will fail. Do we make
> it up to protocol designers or implementers to make sure that
> different sides to a connection have a different b bit?

The tricky part here is that we are trying to be as parsimonious as
possible with option space.  Otherwise, we could get rid of p and just
say passive openers always send b=1 while passive openers send b=0 by
default and can be configured with b=1 for simultaneous open.  But that
would require every passive opener to send a general suboption.  Would
it help if we gave more of this rationale?

Basically you've picked up on the fact that we've paid a little bit of
complexity to use one fewer byte of SYN-ACK option space in the common
case.  Whether or not this is worth it is certainly something we could
discuss in the working group.

> It's not clear to me why the transcript in section 3.5 is
> useful. Everything done in TCPINC is supposed to be secure against
> passive eavesdropping, not active attacks. Tampering with transcripts
> is something an active attacker would do, and an active attacker can
> do much to circumvent everything in this document. Section 4.1 has the
> session ID depend on this transcript so as to prevent collisions with
> different specs, but it's still not clear why either side would want
> to tamper with it and how.

This is necessary for the authentication hooks required by the charter.
Without a way to authenticate the transcript, connections would be
vulnerable to downgrade attacks.

> That's not up to the specs. The best that specs can do is to *allow*
> forward secrecy by not requiring that session keys be derived from
> long-term keys and inputs sent in the clear. Nothing in any spec that
> mandates ECDHE, for example, prevents an implementation from
> hard-coding a key pair, or generating one just once.

That's an interesting point.  For example, tcpcrypt says implementations
SHOULD discard keys quickly and SHOULD NOT write them to persistent
storage, but doesn't make it a MUST, because who knows--some weird
device may need to go into some deep sleep mode for 24 hours or
something.  However, I do think we want to prohibit hard-coding a key
pair.  I wonder what the right wording would be...

> Section 7 has requirements to prevent active attacks. I thought that
> was out of scope. It also recommends that applications be modified to
> verify that TCP-level encryption is present and verify that there is
> no MITM. I don't think this should be in scope. If we are allowed to
> require applications to be upgraded, we might as well upgrade them to
> use regular TLS.

The active attack falls under the authentication hooks requirement.

Thanks,
David

---

From: Yoav Nir <[email-masked]>
Date: Wed, 16 Mar 2016 08:55:24 +0200

> On 11 Mar 2016, at 11:59 AM, David Mazieres <[email-masked]> wrote:
> 

I’m not sure that is necessary. In HTTP the use of TLS is “negotiated” by the choice of port. And on that port we’ve gone from SSLv2 to (soon) TLS 1.3 using a version negotiation mechanism within TLS. So supposing at some point you’ll see a need for tcpcryptv2, do you expect to use TCP-ENO for the version negotiation? It is attractive in its way. A lot of the clunky bits of TLS 1.3 are there because of the need for version negotiation.

> oblique) point about Dane was alluding to.

That makes sense. I would still lose the DANE bit.

> simpler way of complying with that requirement.

Interesting. I totally missed that bullet point in the charter. Yes, that does seem to require channel binding.

> also delete this point if it is too oblique.

I think that’s best, mostly because the target audience of RFCs is implementers. While it’s fine to include some rationale and explanation of the design, I think future plans don’t really belong there.

> section just on defining terms if you think it would clarify things.

I think more recent specs call them “client” and “server”. The TCP Fast Open RFC and the TCP-EDO draft both use “client” and “server”. And any implementer who might be given this document will certainly recognize what “client” and “server” are. Less so for active/passive opener.

> Otherwise, without that context I think the TCP-ENO draft must indeed

That makes sense to me.

> vulnerable to downgrade attacks.

Yeah, sorry about that. I now see that the charter requires this.

> pair.  I wonder what the right wording would be…

Those crafty implementers will realize that this does not affect interoperability and so can be ignored.  You might want to stick a “Keys must be generated using a good random source or a properly seeded random bit generator and should be replaced quickly according to industry best practices.” in the security considerations. Not much we can do if people decide to ignore this.