Cryptographic protection of TCP Streams (tcpcrypt)

Summary: Has a DISCUSS. Has enough positions to pass once DISCUSS positions are resolved.

Eric Rescorla Discuss

Discuss (2017-11-10 for -09)

   2^64 bytes in the underlying TCP datastream (which would cause the
   "offset" field to wrap) before re-keying.
In TLS and other WGs, we have adopted the practice of
salting the nonce with a secret per-connection value to avoid
large-scale surveillance attacks. Why did you opt to use a weaker
construction. See:

   FIN flag set, it MUST immediately send a frame (with empty
   application data if necessary) with "rekey = 1".
I don't think that the algorithm in this section
necessarily works properly, because you have to handle rekeys in

Frame 1 [0:999]
Frame 2 [1000:1999, rekey=1]
Frame 3 [2000:2999, rekey=1]

Now what happens if the frames are re-ordered so you get Frame 3 and
then Frame 2. You will try to decrypt Frame 3 with generation 2 and
Frame 2 with generation 3, neither of which will work (though you
might be able to interpret the text loosely to have you try to decrypt
Frame 2 with generation 2). Note that if you were to resequence before
processing, this wouldn't happen.

At minimum I think some clarification is needed here.

Given that you are allowing P-256 and point reuse, you
should be requiring point validation. See:

You should probably also be requiring Curve25519 output validation.

You still seem to need to specify an MTI symmetric algorithm.
Comment (2017-11-10 for -09)
The design of session resumption here essentially precludes doing
tcpcrypt resumption across servers (as one does with TLS) because you
need extremely tight control of ss[i] or you have catastrophic
results. Was this a deliberate choice by the WG?

   suboption containing the TEP identifier and "v = 0".  In order to
   propose session resumption (described further below) with a
   particular TEP, a host sends a variable-length suboption containing

It would be clearer if you explained resumption here.

          PRK = Extract(N_A, eno-transcript | Init1 | Init2 | ES)
What is the rationale for providing N_A as the salt to HKDF-Extract, given that you also supply N_A in the Init1 message?

   session resumption such that a given pre-session key "ss[0]" is only
   used for either passive or active opens at the same host, not both.
This seems like it probably needs some more emphasis, as failure to follow this instruction results in GCM compromise.

It would probably be useful to explain why you opted for this design rather than having nonces, which would remove the need for such strict ss[i] management. I assume the reason is that you want to save the round trip?

   connection; but if it aborts, the implementation MUST raise an error
   condition distinct from the end-of-file condition.
Note that this interacts badly with the rekey issue I raise below.

   format", and MUST accept values encoded in "compressed",
   "uncompressed" or "hybrid" formats.
Why are you allowing multiple formats here? Generally, if you're going to encourage compressed, you want to just require it.

Ben Campbell Yes

Comment (2017-11-10 for -09)
In section 3.3, the last bullet: Why are the SHOULDs not MUSTs? Do you envision times where it might make sense not refresh an ephemeral public key, or write one to persistent storage?

Spencer Dawkins Yes

Comment (2017-10-25 for -08)
I really like this draft, and I can understand it fairly well. I do have some questions to go along with my Yes ballot.


  o  "PK_A", "PK_B": ephemeral public keys for hosts A and B,
      respectively.  These, as well as their corresponding private keys,
      are short-lived values that SHOULD be refreshed periodically.  The
      private keys SHOULD NOT ever be written to persistent storage.

is just begging for some justification as to why this is important enough to be a SHOULD NOT, and not important enough to be a MUST NOT. Could you give an example of a reason why this would be a good idea?

It's likely that everyone but me knows why 

                resume[i] = CPRF(ss[i], CONST_RESUME, 18)

is "18" and not some other integer, but there's no explanation or reference that I could find explaining why.

It would be helpful to explain why

  In a particular SYN segment, a host SHOULD NOT send more than one
   resumption suboption,

is a SHOULD NOT, since it's allowed, so doing so must have some purpose.


  A host SHOULD NOT initiate more than one concurrent re-key operation
   if it has no data to send; that is, it should not initiate re-keying
   with an empty encryption frame more than once while its record of the
   remote generation number is less than its own.

is allowed - could you explain why a host would need to violate that SHOULD NOT?

Just for my benefit - Section 8.3 explains why ECDHE using Curve25519 has been chosen as MTI, but also explains why ECDHE using P-256 has not been chosen as a second MTI. Is the intention to discourage use of ECDHE using P-256 at all, based on the concerns expressed about making it MTI? 

Also for my benefit, but somewhat more worrying - is the working group fairly confident that a specifying second MTI key management scheme will be possible at some point, that does not trip over the problems described in [nist-ecc] and can be implemented in kernels, or is conforming to the guidance in [RFC7696] going to be problematic? I see Mirja mentioned SEC discussions about only one MTI key management mechanism being chosen now, but my question is a little different - I'm asking if the situation is likely to improve anytime soon.

Mirja K├╝hlewind Yes

Comment (2017-10-23 for -08)
Based on comments received during IETF last cast, the latest version of this document (-08) now recommends a different AEAD algorithm as MIT. There is still some on-going  discussion with the SEC ADs if only one MIT is acceptable. There is consensus in the working group to move forward with only one but they are also open for other recommendations as feedback from the IESG evaluation.

Alexey Melnikov Yes

Comment (2017-11-29 for -10)
I am looking forward to seeing resolutions to Ekr's DISCUSS points.

(Kathleen Moriarty) Yes

Comment (2017-11-11 for -09)
Thank you for the discussion and agreement on the two points for additional (SHOULD) algorithms and your work on this draft and experiment.

I support Eric's discuss.

I'd also like to see Barry's SecDir review and the Steve Kent review he referenced discussed and resolved.
Barry's SecDir review:

Adam Roach Yes

Comment (2017-11-08 for -09)
Thanks for a well-written document. I have some suggestions for improvement (two minor, and one significant).

This document has several references to tables that are quite distant from the table being referenced. It might be useful to readers if these were phrased something like "Table 4 in section 7," so they know where to go looking for the table.

Section 3.5 says:

   If an active opener receives a resumption suboption for a particular
   TEP and the received identifier-half does not match the "resume[i]"
   value whose other half it previously sent in a resumption suboption
   for the same TEP, it MUST ignore that suboption.  In the typical case
   that this was the only ENO suboption received, this means the host
   MUST disable TCP-ENO and tcpcrypt: that is, it MUST NOT send any more
   ENO options and MUST NOT encrypt the connection.

I think the text here would benefit from pointing out that the client MUST NOT attempt to resume a session with this host for the next TCP connection attempt.


Section 3.6 stipulates:

   When a frame is received, tcpcrypt reconstructs the associated data
   and frame nonce values (the former contains only data sent in the
   clear, and the latter is implicit in the TCP stream), and provides
   these and the ciphertext value to the the AEAD decryption operation.
   The output of this operation is either a plaintext value "P" or the
   special symbol FAIL.  In the latter case, the implementation MUST
   either drop the TCP segment(s) containing the frame or abort the
   connection; but if it aborts, the implementation MUST raise an error
   condition distinct from the end-of-file condition.

In the text above, the choice to "drop the TCP segment(s)" seems a little underspecified, and both ways that I can interpret it are problematic.

In one interpretation, the TCP stack acts as if those packets were never received, and so they are never acknowledged. Since retransmissions will contain the same contents and also fail to decrypt, this is basically just going to cause a connection failure upon expiration of the retransmission timer -- in which case an immediate failure is clearly preferable.

The other interpretation is that the TCP packet is processed as received, but that all of the data that could not be decrypted is elided from the stream of bytes provided to the receiving application. This is also a problem, since many applications rely on the in-order delivery aspects of TCP. The prospect that a sender could provide "Message A", "Message B", and then"Message C" to its TCP socket and the receiver only get "Message A" followed immediately by "Message C" is not something that applications will generally be capable of handling. As before, a connection reset would be preferable to violating the in-order delivery guarantees of TCP.

Unless my analysis here is confused, I think this text needs to be changed to conclude:

   In the latter case, the implementation MUST
   abort the connection and raise an error
   condition distinct from the end-of-file condition.

(Alia Atlas) No Objection

Deborah Brungard No Objection

(Benoit Claise) No Objection

Comment (2017-11-10 for -09)
Nothing against the publication of this document but ... as for any experimental RFCs, we must describe the criteria for a successful experiment (evaluation)?

Alissa Cooper No Objection

Suresh Krishnan No Objection

Terry Manderson No Objection

Alvaro Retana No Objection

Ignas Bagdonas No Record

Benjamin Kaduk No Record

Warren Kumari No Record

Martin Vigoureux No Record