Re: [tcpinc] Eric Rescorla's Discuss on draft-ietf-tcpinc-tcpcrypt-09: (with DISCUSS and COMMENT)

Eric Rescorla <> Sat, 18 November 2017 23:05 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 08D5E126DEE for <>; Sat, 18 Nov 2017 15:05:44 -0800 (PST)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.899
X-Spam-Status: No, score=-1.899 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001] autolearn=unavailable autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (2048-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id jaa4jv6QYCnY for <>; Sat, 18 Nov 2017 15:05:41 -0800 (PST)
Received: from ( [IPv6:2607:f8b0:4002:c09::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id 40C59126BFD for <>; Sat, 18 Nov 2017 15:05:38 -0800 (PST)
Received: by with SMTP id y14so1752053ybi.0 for <>; Sat, 18 Nov 2017 15:05:38 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20150623; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=m7VvxIW7iOQbDjdxiKxrnZMEcorWS7XqRX6zQEPxsUQ=; b=daudR76mhEEdrNvhGKAuZwC9/6bYVIPrTpNaqjp7CbO9RHqqNdgjB23m1abJgOxRY0 VfY09tEtjjkyWy14c30TylCyM5xiVyDddcozeBLLCes5IF9Z+sbP1A5y2+XFDwvgGNgI w39qsoY0UxJRU7eL+ba6a41pc3FGkqCO60q0PDD7cZIZFJsjdQKSVdyB1BJ5pWJLz4hT oMAgVT+leXz7ZgoKLuPw95JospGXHBPh9Z34upbwVmBg4S/hPbi+buV233C1qtiAYWHd gltuKb/lZe+mmirSZLmp9bRwCesDnltfIrr65gqemvlkt1J8qYuGSKn8m3SwRMCYzx3l u6ow==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=m7VvxIW7iOQbDjdxiKxrnZMEcorWS7XqRX6zQEPxsUQ=; b=LXpt5R8/2NHuqzE72zJ4ofndlYkMGas6wJY20lSTNirc5eLyEKLirVrhZkJN4MEZuj ZG8ZZJ/B/pV78/rabmdRptWUd5ElRB3VF/XTqOsHvQ6VKlDSZLckcBenLGx04i81d+H4 0zLV3YdG3KJdKwQRDO42WFkBxjP/gihTcJJE4L2nL1dLDKCPUoC2hIVNzXSSJrdehLhC ljcaC64kssVhThT2Yy0aIeb1c7zAoMKOPh6sslPoD4xIlBOtiwqO/0dK6Hqi2jUAPta7 b/Bbn4r1lwkzQJk1+tpfeyDV3jYMC2SPXKAsWtXFqODbaTWWtyv8PC7rjYPrJHzsNyMQ FGPw==
X-Gm-Message-State: AJaThX4wFOvHLC/RIiVJg/gZfbe5/8pp+MvDptAZuMiE+An6Ci5SYElI kdXNRbV9S0yv3cX3uTqzUqIGnmSiiyw2u3J1rF4SDQ==
X-Google-Smtp-Source: AGs4zMYC0F+VI8KQ5U+s0Yi7hONJGuZ0pmY2snaXbiN5vD+UrToqu4QVKcZsXfsXztvoQ5qZ3Y5bxLdtBjItg0tXtd8=
X-Received: by with SMTP id v3mr5587423ybj.208.1511046337191; Sat, 18 Nov 2017 15:05:37 -0800 (PST)
MIME-Version: 1.0
Received: by with HTTP; Sat, 18 Nov 2017 15:04:56 -0800 (PST)
In-Reply-To: <>
References: <> <>
From: Eric Rescorla <>
Date: Sun, 19 Nov 2017 07:04:56 +0800
Message-ID: <>
To: Daniel B Giffin <>
Cc: The IESG <>,, Kyle Rose <>,, tcpinc <>
Content-Type: multipart/alternative; boundary="089e08231c3c2b0688055e49e411"
Archived-At: <>
Subject: Re: [tcpinc] Eric Rescorla's Discuss on draft-ietf-tcpinc-tcpcrypt-09: (with DISCUSS and COMMENT)
X-Mailman-Version: 2.1.22
Precedence: list
List-Id: "Working group mailing list for TCP Increased Security \(tcpinc\)" <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Sat, 18 Nov 2017 23:05:44 -0000

Hi Daniel.

I won't have a chance to review this document until Monday, but I
wanted to respond not to the point about the reuse of ss[i], because I
think you (and others) may have understood me and thought this was
primarily about tickets versus session ids, which it is not.

At a high level, tcpcrypt establishes a master secret which is then
used to create a chain of resumption secrets ss[i]. Each ss[i] value
is intended only to be used for resumption once, in which case things
are fine. However, because the only input to the traffic keys is
ss[i], if you ever reuse ss[i], the result is catastrophic
(potentially leading to a complete loss of integrity if the cipher is

By contrast, TLS 1.3 has a similar design (the secrets are a tree, not
a chain) but because there is always a nonce exchange, and the nonces
are mixed into the traffic keys, so if you *do* reuse a secret, the
main impact is that the two connections in which you use the secret
are linkable (by the ticket ID), and of course that you don't have
FS. IKE PSK has a similar design, and I think it's clear that it's
less brittle than the design in tcpcrypt.

This is an orthogonal question to whether the IDs used for resumption
are lookup keys (like in tcpcrypt) or can be self-contained (TLS 1.3
allows both lookup keys and self-contained IDs). Although designs
where one side dictates the identifier are compatible with
self-encrypted tickets, the need not be used that way, and are
compatible with FS. See, for instance:

Assuming I understand the design of tcpcrypt correctly, it seems like
the reason for the choice not to have a nonce is that you don't have
room in the SYN, and you don't want to take another round trip in the
resumption case. However, I think you can improve on the situation
somewhat even within these constraints. Here's your Figure 9 from
ENO modified to include tcpcrypt as I understand it:

             (1) A -> B:  SYN      ENO<TCPCRYPT sid[i] part 1>
             (2) B -> A:  SYN-ACK  ENO<TCPCRYPT sid[i] part 2>
             (3) A -> B:  ACK      ENO<>

A can start sending encrypted traffic after sending (3) and B can
start sending encrypted traffic after receiving (3). Am I correct
so far?

Assuming I am correct, then it seems like (B) could send a nonce
in message (2) and A could send a nonce in message (3), like so:

             (1) A -> B:  SYN      ENO<TCPCRYPT sid[i] part 1>
             (2) B -> A:  SYN-ACK  ENO<TCPCRYPT sid[i] part 2, N_a>
             (3) A -> B:  ACK      ENO<TCPCRYPT N_b>

You could then derive the keys from ss[i], N_a, and N_b, and avoid
brittleness associated with ss[i] reuse. Of course, you should still
require that people not reuse ss[i], because that gives you FS, but
the consequences if people fail to do so would not be so dire.


On Fri, Nov 17, 2017 at 8:17 PM, Daniel B Giffin <>

> Thanks for the helpful review, Ekr!
> Eric Rescorla wrote:
> > ----------------------------------------------------------------------
> > ----------------------------------------------------------------------
> >
> >
> >
> >    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:
> >
> html#security-record-layer
> > and
> Thanks again for pointing this out.  The next draft
> implements a nonce-randomizing countermeasure.  I'll excerpt
> the relevant changes.  First, what was before the frame
> nonce is now called the frame ID:
>    Lastly, a "frame ID" (used to construct the nonce for the AEAD
>    algorithm) has this format:
>                      byte
>                         +------+------+------+------+
>                       0 |       FRAME_ID_MAGIC      |
>                         +------+------+------+------+
>                       4 |                           |
>                         +           offset          +
>                       8 |                           |
>                         +------+------+------+------+
> Next, the traffic keys are extended by 12 bytes to provide
> bits for nonce randomization.  This bit shows where the keys
> come from:
>    Given a session secret "ss[i]", the two sides compute a series of
>    master keys as follows:
>                  mk[0] = CPRF(ss[i], CONST_REKEY, K_LEN)
>                  mk[j] = CPRF(mk[j-1], CONST_REKEY, K_LEN)
>    The process of advancing through the series of master keys is
>    described in Section 3.8.
>    Finally, each master key "mk[j]" is used to generate traffic keys for
>    protecting application data using authenticated encryption:
>             k_ab[j] = CPRF(mk[j], CONST_KEY_A, ae_keylen + 12)
>             k_ba[j] = CPRF(mk[j], CONST_KEY_B, ae_keylen + 12)
> As before, "ae_keylen" depends on the negotiated AEAD
> algorithm, e.g. 16 bytes for AES128-GCM.
> The encryption operation is detailed in Section 3.6.  After
> explaining the construction of the "plaintext" and
> "associated data" values, it explains how the frame nonce is
> formed:
>    A "frame ID" value (see Section 4.2.3) is also constructed for the
>    frame but not explicitly transmitted.  It contains an "offset" field
>    whose integer value is the zero-indexed byte offset of the beginning
>    of the current encryption frame in the underlying TCP datastream.
>    (That is, the offset in the framing stream, not the plaintext
>    application stream.)  Because it is strictly necessary for the
>    security of the AEAD algorithms specified in this document, an
>    implementation MUST NOT ever transmit distinct frames with the same
>    frame ID value under the same encryption key.  In particular, a
>    retransmitted TCP segment MUST contain the same payload bytes for the
>    same TCP sequence numbers, and a host MUST NOT transmit more than
>    2^64 bytes in the underlying TCP datastream (which would cause the
>    "offset" field to wrap) before re-keying.
>    With reference to the "AEAD Interface" described in Section 2 of
>    [RFC5116], tcpcrypt invokes the AEAD algorithm with values taken from
>    the traffic key "k_ab[j]" or "k_ba[j]" for some "j", according to the
>    host's role as described in Section 3.3.
>    First, the traffic key is divided into two parts:
>         byte   0                        ae_keylen    ae_keylen + 11
>                |                           |            |
>                v                           v            v
>              +----+----+--...--+----+----+----+--...--+----+
>              |             K             |        NR       |
>              +----+----+--...--+----+----+----+--...--+----+
>              \_____________________________________________/
>                               traffic key
>    The first "ae_keylen" bytes of the traffic key provide the AEAD key
>    "K", while the remaining 12 bytes provide a "nonce randomizer" value
>    "NR".  The frame ID is then combined via bitwise exclusive-or with
>    the nonce randomizer to yield "N", the AEAD nonce for the frame:
>                             N = frame_ID xor NR
>    The plaintext value serves as "P", and the associated data as "A".
>    The output of the encryption operation, "C", is transmitted in the
>    frame's "ciphertext" field.
> This packaging of the key and nonce bits into one value is a
> little bit awkward in the above excerpts (versus say the TLS
> approach of doing two separate extractions to get the two
> distinct values), but elsewhere in the spec it saves a lot
> of complexity because the handling of a traffic key can be
> explained without reference to the nonce randomizer.
> Still, I'm open to other ways of describing this.
> >
> >    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
> > sequence:
> >
> > 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.
> As Kyle explained, it works because tcpcrypt is now
> contained by the TCP datastream.  But you may be remembering
> the good old days when it was simply a segment rewriter!
> > Given that you are allowing P-256 and point reuse, you
> > should be requiring point validation. See:
> >
> html#rfc.section.
> >
> html#elliptic-curve-diffie-hellman
> Yes, thank you.  For the NIST curves, I have added:
>         Implementations MUST validate these "pubkey" values according to
> the
>   algorithm in [ieee1363] Section A.16.10.
> But I see that TLS refers to ANSI X9.62 for validation, even
> though it refers to IEEE1363 for DH computation.  Is there a
> good reason not to stick with the one source?
> Also, I guess there's no need to check on-the-curve if we
> allow only compressed format, and it's not perfectly clear
> to me whether we need to check group membership, but I'd
> really rather not have all these details in this document if
> there's a good way to cite it out.
> Lastly, I've added this to section 3.3:
>    If a host receives an ephemeral public key from its peer and a
>    required key-validation step fails (see Section 5), it MUST abort the
>    connection and raise an error condition distinct from the end-of-file
>    condition.
> > You should probably also be requiring Curve25519 output validation.
> I think you're saying we should check that the DH result is
> not zero?
> No harm, I suppose, but I'm going to try to get guidance on
> whether it's necessary.
> > You still seem to need to specify an MTI symmetric algorithm.
> There's a table of the requirements in "6. AEAD Algorithms."
> But you're not the only one who had trouble finding it, so I
> wonder what's going on ...
> > ----------------------------------------------------------------------
> > ----------------------------------------------------------------------
> >
> >
> > 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?
> I think it's a choice to keep key material in the kernel and
> to have control over forward secrecy.
> >
> >    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?
> I'm not qualified to say.  I agree it seems "redundant", but
> it appears to achieve what it needs to.  Perhaps we can find
> a more satisfying answer for you ...
> >    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.
> For our reference, here's the paragraph in question:
>    A session secret may not be used to secure more than one TCP
>    connection.  To prevent this, a host MUST NOT resume with a session
>    secret if it has ever enabled encryption in the past with the same
>    secret, in either role.  In the event that two hosts simultaneously
>    send SYN segments to each other that propose resumption with the same
>    session secret but the two segments are not part of a simultaneous
>    open, both connections will have to revert to fresh key-exchange.  To
>    avoid this limitation, implementations MAY choose to implement
>    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.
> It seems like the straightforward implementation is to mark
> a session secret "used" as soon as a resume succeeds.  The
> only downside is that you could be forced to do fresh key
> exchange in the case of bad timing (if you try to connect to
> the host at the same time it connects to you), so the last
> sentence here gives you a way to avoid that ever happening
> (with I guess the downside of having to store two session
> secrets for the same host).  Does it seem that this
> paragraph is somehow risking a dangerous implementation?
> > 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?
> If I understand the question, I think the choice here is
> mostly to prioritize forward secrecy.  Perhaps we can find a
> way to make this more clear in Security Considerations.
> >    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.
> It's not clear exactly what you mean, but perhaps this is
> another concern that is moot because of the reliable-ordered
> receipt of frames?  In any case (and with relevance to some
> other discussion in this thread), due to other comments we
> have improved the guidance on what to do in the case of
> encryption failure:
>                      [...] The output of this operation is either a
>    plaintext value "P" or the special symbol FAIL.  In the latter case,
>    the implementation SHOULD abort the connection and raise an error
>    condition distinct from the end-of-file condition.  But if none of
>    the TCP segment(s) containing the frame have been acknowledged and
>    retransmission could potentially result in a valid frame, an
>    implementation MAY instead drop these segments.
> >
> >    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.
> That makes sense.  I'm changing this to:
>    Implementations MUST encode these "pubkey" values in "compressed
>    format".
> Thanks again for all the useful comments.
> daniel