Re: [TLS] KeyUpdate and unbounded write obligations

Keith Winstein <keithw@cs.stanford.edu> Thu, 18 August 2016 07:30 UTC

Return-Path: <winstein@gmail.com>
X-Original-To: tls@ietfa.amsl.com
Delivered-To: tls@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 2564612D6AE for <tls@ietfa.amsl.com>; Thu, 18 Aug 2016 00:30:47 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.898
X-Spam-Level:
X-Spam-Status: No, score=-1.898 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_FORGED_FROMDOMAIN=0.001, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.com
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id gw9k3YioqlgW for <tls@ietfa.amsl.com>; Thu, 18 Aug 2016 00:30:44 -0700 (PDT)
Received: from mail-yb0-x22a.google.com (mail-yb0-x22a.google.com [IPv6:2607:f8b0:4002:c09::22a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 9C15A12B011 for <tls@ietf.org>; Thu, 18 Aug 2016 00:30:44 -0700 (PDT)
Received: by mail-yb0-x22a.google.com with SMTP id d10so3147159ybi.1 for <tls@ietf.org>; Thu, 18 Aug 2016 00:30:44 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=vlEiNJILF91RwDf+UuZzDHYsKS3NJ4N8HwyrLFcmCCo=; b=WM1k2vZPbyE0nujaXcBSctvfrSLVX4sJN5hG1HHq0qFyTJtovmOz9LcwQaGTAN3Vck lZfJybL4cDCr1xK3qitDF+K+tsIzOSALWwb94pSjoWyB7wfH20aRkITdqVDlSJSksG2i M+bVpMke/L07eQ01YAybpXn7OENy3Vh/7ft7BfC1aLrsKZK3zADTcIVNNg09+pLjGZbG rAUVuCaMNwoVjegg305+6kzPkA7Fj5/wPMqfNomre2SGK2jP3dhd49mz/uB035GpPCkL PENIpkjzTUmlk7bVpAdBOngtgyBbX4l/45M5+p8SngXkl3z2TnU1OzVzwoLlStSbt+QV qfGg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=vlEiNJILF91RwDf+UuZzDHYsKS3NJ4N8HwyrLFcmCCo=; b=GZgBC//kroKiQ6CIUFXW1yyuMCnbtpl3IlnZa4jgxM7J8pWnJDMOcjXwEH2dLqnSU5 K/84LC/hQXRwk7qwBgG39gTcmjiuRnRalU1cze2XvYcWKiAumnLyNQNBglJ5FgjZN74A gSsqs+SVzkJaSUjABQbuH4t3Q2I6G8TBcTOb7LGuIG08iOaDgayk7fCY0YhHT7YEwlR3 +kmU+y0IqxKDBFDsEMo5sO3Btg3m3bfiWRetAwmhiFbVYQqco3XsHNWSvd3iPrnN3ACI 83jUJIj2h6LgOI8rWQlalAej2/BQfH6i0fc2uma7iLxWv/rV+eINf+yNbhl7O1x8T6rz vBRA==
X-Gm-Message-State: AEkoous982emPWH71WYYobRn64pBMpkQ/2Yhd+XUz8nntcp11bhK4caFqW7XDtNo9JbtKdBCiO9oNel9QYipnQ==
X-Received: by 10.37.79.87 with SMTP id d84mr492532ybb.165.1471505443804; Thu, 18 Aug 2016 00:30:43 -0700 (PDT)
MIME-Version: 1.0
Sender: winstein@gmail.com
Received: by 10.129.79.209 with HTTP; Thu, 18 Aug 2016 00:30:03 -0700 (PDT)
In-Reply-To: <CAF8qwaDgGHGmuBwhZEz9-=Ss2bfzNAYWfmnbMqQDxTQnMUpH7g@mail.gmail.com>
References: <CAF8qwaDgGHGmuBwhZEz9-=Ss2bfzNAYWfmnbMqQDxTQnMUpH7g@mail.gmail.com>
From: Keith Winstein <keithw@cs.stanford.edu>
Date: Thu, 18 Aug 2016 00:30:03 -0700
X-Google-Sender-Auth: h-kgKTUADoZfxESnf3kSl07513s
Message-ID: <CAMzhQmOs-mj2URHnYFOB46SDBa2c4Z3_S=7bzNAgixTc_TNkEQ@mail.gmail.com>
To: David Benjamin <davidben@chromium.org>
Content-Type: text/plain; charset="UTF-8"
Archived-At: <https://mailarchive.ietf.org/arch/msg/tls/L2pKxh8b1tMJrszjfUEutViVKTE>
Cc: "tls@ietf.org" <tls@ietf.org>
Subject: Re: [TLS] KeyUpdate and unbounded write obligations
X-BeenThere: tls@ietf.org
X-Mailman-Version: 2.1.17
Precedence: list
List-Id: "This is the mailing list for the Transport Layer Security working group of the IETF." <tls.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/tls>, <mailto:tls-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/tls/>
List-Post: <mailto:tls@ietf.org>
List-Help: <mailto:tls-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/tls>, <mailto:tls-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 18 Aug 2016 07:30:47 -0000

I think it's probably possible to make everybody happy here.

I appreciate the need to avoid allowing the other side to create an
unbounded deferred write/compute obligation. I also think it's
valuable to preserve the ability for "either side to force an update
to the entire connection," and obviously I think it's valuable for the
initiating side to get an ack that that has happened (hence PR
#426/#580).

To mitigate the unboundedness issue, what would you think about this option:

1) Keep everything the same as the current draft, but
2) Add this text: "An implementation MUST NOT advance its current
sending generation to be greater than its current receiving generation
plus one."

That would be it. If an implementation reads a KeyUpdate that attempts
to advance the receiving generation to be greater than the sending
generation plus one, it may abort because the other side has behaved
in an invalid manner.

I think this eliminates any unbounded deferred write obligation. The
KeyUpdates would still be asynchronous, but after sending one, an
implementation would not be able to send another until it received one
from the other side -- and whether that KeyUpdate is triggered by its
own KeyUpdate, or generated independently, wouldn't matter. (Of course
we also want our PR #580 to be able to resolve that ambiguity, but
these can be basically orthogonal issues.)

-Keith

On Wed, Aug 17, 2016 at 9:29 PM, David Benjamin <davidben@chromium.org> wrote:
> Amusingly, Keith and I appear to have crossed mid-air in our respective
> requests to change KeyUpdate, so this will be a fun collision. Mine is a tad
> larger of a change I'm afraid.
>
> We've currently implemented KeyUpdate in our in-progress TLS 1.3 code, but
> we've for now ignored the requirement for the receiver to send KeyUpdates to
> catch up with the sender. It appears that honoring that will cause
> significant problems.
>
> A TLS stack does not know much of the read/write patterns of the
> higher-level application. It must handle all kinds of flows, so a dumb
> filter is ideal. Some TLS APIs are even structured around this. Rather than
> consume and provide a socket interface, they encrypt and decrypt buffers,
> leaving transport business to the consumer. (And socket-based APIs are often
> used as if they were filters using buffers for sockets.)
>
> We may then have transport reads progress faster than transport writes, or
> the write channel may not even be driven most of the time. (This isn't that
> contrived. Unpipelined HTTP/1.1 never reads and writes in parallel. HTTP/2
> may not have any response to write. Or perhaps it is processing a request
> while an earlier response is still being written.) The receiver can then
> accrue KeyUpdate obligations unboundedly. When the write channel is active
> again, it has to dump all those out as unbounded write overhead. This is
> rather a mess. There should be a tight bound (one, if not zero) on KeyUpdate
> obligations.
>
> I'm unclear on exactly what parts of KeyUpdate the WG finds important, so I
> haven't written a concrete PR yet. But here is roughly the fix I have in
> mind:
>
> Sending one KeyUpdate and 1,000 in a row morally should be the same. But
> both ends share a KeyUpdate track, so any forward secrecy goals require
> matching generations. So branch client-write and server-write first and have
> two KeyUpdate ladders starting at client_traffic_secret_0 and
> server_traffic_secret_0.  (Note bidi KeyUpdate is asynchronous, so
> implementations had to store separate read and write traffic secrets
> anyway.) As a small bonus, we can lose the client/server split from traffic
> key calculations (7.3), having branched at traffic secret already.
>
> However, we lose the "free" (really at the cost of this unboundedness
> problem) generation-based bidirectional KeyUpdate sync. Depending on what we
> want out of KeyUpdate, I can imagine a few options:
>
> - Don't. KeyUpdates are unilateral. Recommend in the spec to KeyUpdate every
> N records or so and leave it at that. (I think this is the best option on
> grounds of simplicity, assuming it meets the primary needs of KeyUpdate.)
>
> - If you receive a KeyUpdate and didn't send one in the last N minutes
> (where N minutes >>> 1 RTT), (optionally?) flag your next write to be
> preceded by KeyUpdate. This is simple but needs an ad-hoc timeout to prevent
> ping-ponging.
>
> - Variations on sticking a please_echo boolean in the KeyUpdate message,
> generation counts, etc., to get synchronization with coalescing if we need
> it. I would much prefer the simpler options unless we truly need this.
> (KeyUpdate is right now a *required* feature, so simplicity should be a
> priority. Rare use cases are what extensions are for.)
>
> Thoughts?
>
> David
>
> PS: We've seen this before with renego (I've seen many OpenSSL consumers
> which lock up if the peer renegotiation), error alerts triggered on reads
> (often they don't get sent), and close_notify (also don't get sent in
> practice). Deviations from dumb filters are expensive.
>
> PPS: I'm wary of over-extending post-handshake auth for the same reason,
> though I haven't had time to look carefully at the latest proposal yet.
> Still, having TLS specify and analyze the crypto while lifting the actual
> messages into application-level framing would be preferable for these sorts
> of side protocols. The application gets to make assumptions about read/write
> flows and knows in which contexts what is and isn't allowed.
>
> _______________________________________________
> TLS mailing list
> TLS@ietf.org
> https://www.ietf.org/mailman/listinfo/tls
>