Re: [TLS] Refactoring the negotiation syntax

Eric Rescorla <> Wed, 13 July 2016 17:22 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 7395C12D16C for <>; Wed, 13 Jul 2016 10:22:21 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -2.599
X-Spam-Status: No, score=-2.599 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_LOW=-0.7] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (2048-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id 9WQUt44JlIUT for <>; Wed, 13 Jul 2016 10:22:19 -0700 (PDT)
Received: from ( [IPv6:2607:f8b0:4002:c05::233]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id EA50C12B03C for <>; Wed, 13 Jul 2016 10:22:18 -0700 (PDT)
Received: by with SMTP id i12so49111830ywa.1 for <>; Wed, 13 Jul 2016 10:22:18 -0700 (PDT)
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; bh=qTuYnYmTIeByBQXqQAwhMpWgNWiWeKYH8MAypHLRVuE=; b=lEGFFvINtfUp7F1DNzClnjq4RjjJNw+COE4G8rNXtrutMzKPO64JBrTjiDESEX1vrN FVXwMRLuZiUNRGuf7oZeTyFtcL+VJyMTkJ5k78AlAfOfEjkq7DvE4mehsiMvNC4eYPzc 5eKXH4Q2eu2vSyOs3dd12/rSquflNpzyZWv3dtEWqkelBUSI/3w5LXS2F1s6p4mP/x3r 7PdgyIDGhQ4CMW9Yh2+HUuwWKnvvTG9ZPTTmjJyZHQLZDvBDb3VXjPYFBjUfyn/Lwm7F eINoJVLoSolUmRa8loszPOeftOQV3VeHNXDNNE2rwm+drnBF6HsQS7jSZYaMllaLJ2yl PLiA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to; bh=qTuYnYmTIeByBQXqQAwhMpWgNWiWeKYH8MAypHLRVuE=; b=QLKgyWr34LQ59xKHP8G8rs2Dt+tM5ux/rdpFV2rx3iAp+f4xnpZjaFWbzCTvX3m4dt W5OMIpprfqSps18o9pe4MqgVlKFNVwZyjZlH6YJVkd+YJf9cnXTpnir+8DL8CO3RHxGd +J8TWw4VareH+7DTQj91C45Am0BvzHUtwZ0UPTfidUScTcqyAGkSwelH4U2Uzlg13Z8v acB+F5z2vK7vXQZ0ElX2FrjRcUrr/jz/L3zrcDE+Nj7tNSzSDj/07mXbIrs9nClemNIS xvR0pj54X9eOTZFPmJib5NbINZCR0eZniIeCjvg45xmnzqIgtNGesQQurCorQfH01MX7 VMyw==
X-Gm-Message-State: ALyK8tL7IYrHk/7TstP/ancoQBSrHq63VYI6PddmTDzeRxLKPQ+LmxvgJUQELxsZQDUNBD8GM3X7n1W4tYFs9g==
X-Received: by with SMTP id n191mr7413330ywn.16.1468430537955; Wed, 13 Jul 2016 10:22:17 -0700 (PDT)
MIME-Version: 1.0
Received: by with HTTP; Wed, 13 Jul 2016 10:21:38 -0700 (PDT)
In-Reply-To: <>
References: <>
From: Eric Rescorla <>
Date: Wed, 13 Jul 2016 10:21:38 -0700
Message-ID: <>
To: "" <>
Content-Type: multipart/alternative; boundary="001a1141826a97c8fc053787a0d9"
Archived-At: <>
Subject: Re: [TLS] Refactoring the negotiation syntax
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." <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Wed, 13 Jul 2016 17:22:21 -0000

Replying to myself:
We obviously don't *need* to do this. We have working implementations that
use the current syntax, so we know it can be done, and "finished is a
feature", so we have to balance against that whether this is a better
syntax. OTOH, if you think this is a worse syntax, then it's easy. :)


On Wed, Jul 13, 2016 at 10:12 AM, Eric Rescorla <> wrote:

> Hi folks,
> There have been a lot of discussions about whether we should try to
> refactor cipher-suite negotiation to be less monolithic in the cipher
> suite. I've generally been on the "no" side of that on cost/benefit
> grounds as well as not quite seeing how it would fit into the rest
> of the infrastructure. However, now that we're starting to get full
> implementations, and it's becoming clearer how the new elements
> (principally PSK-resumption and key_shares) interact with cipher
> suites, I've started to think that in fact we may be able to clean
> things up. One proposal for this is below [0]. I know this is
> pretty late in the process, but if we do want this change it's
> better to do it now.
> I'm sure we'll need to discuss this in Berlin, but in the meantime,
> fire away.
> The basic idea here is to factor out the TLS 1.3 negotiation into three
> mostly orthogonal axes.
> - Symmetric cipher/PRF  -- indicated by the cipher suite list as in TLS 1.2
> - Key exchange -- indicated by the key_shares and pre_shared_key extensions
> - Authentication -- indicated the signature_algorithms and pre_shared_key
>   extensions
> A proposal for how to do this is below. See the end for other options,
> caveats, etc.
> If we take PSK out of the picture, this gives us a very simple structure:
> - The client offers a set of key_shares and the server picks one that it
>   likes [1].
> - The client offers a list of signature_algorithms and the server picks
>   a certificate/key that matches that list and signs with it.
> In other words, we just eliminate the redundancy with the cipher suite
> indications. This leaves is with the question of how to handle the
> existing TLS 1.2 cipher suites. We can either assign new cipher suites
> or say that any cipher suite with *_aead_alg_hash means that we
> support aead_alg_hash. Matter of taste.
> PSK is handled by extending the concept of PSK flags that we already
> have in NewSessionTicket to also include uses of PSKs where you
> indicate the way in which you are using the PSK (or want it to be
> used). There a bunch of ways to encode this. I'll give you the one I
> mostly prefer below and then a one that's a smaller change but I think
> a little less elegant at the end [note #4].
> First, we replace the flags word of the different KE modes for the
> ticket with lists of code points, as below:
>    enum {
>      psk_ke(0),          // PSK key exchange
>      psk_dhe_ke(1),      // PSK + DHE key exchange
>      (255)
>    } PskKeModes;
> And then add new code points for being able to use the PSK with and
> without signatures (from the server). We had pretty rough consensus in
> B-A that we needed this mode and [draft-thomson-tls-0rtt-and-certs-01]
> is part of the motivation for this idea.
>    enum {
>      psk_auth(0),        // PSK only
>      psk_sign_auth(1),   // PSK + a signature (as in draft-thomson) [5]
>      (255)
>    } PskAuthModes;
> This gives us the following NewSessionTicket message where we have
> replaced the flags word with two (potentially ordered) lists:
>    struct {
>        uint32 ticket_lifetime;
>        PskAuthModes auth_modes<1..255>;
>        PskKeModes ke_modes<1..255>;
>        TicketExtension extensions<2..2^16-2>;
>        opaque ticket<0..2^16-1>;
>    } NewSessionTicket;
> We now need a way to indicate that the server will do 0-RTT (previously
> in the flags word) so we add a new 0-RTT extension:
>    struct {
>        uint32 ticket_age_add;
>    } TicketEarlyDataInfo;
> This has two nice properties:
> - You don't need to provide ticket_age_add when you don't do 0-RTT
>   (and it is silly if you don't).
> - It exercises this extension mechanism, which is good for future-proofing.
> PreSharedKeyExtension becomes:
>     struct {
>        PskAuthMode auth_modes<1..255>;
>        PskKeModee ke_modes<1..255>;
>        opaque identity<0..2^16-1>;
>     } PskIdentity;
>     struct {
>          select (Role) {
>              case client:
>                  PskIdentity identities<2..2^16-1>;
>               case server:
>                  PskAuthMode auth_mode;
>                  PskKeMode ke_mode;
>                  uint16 selected_identity;
>          }
>      } PreSharedKeyExtension;
> The way to interpret these is as follows:
> - With each identity, the client indicates to the server which modes
>   it can be used with.
> - When the server responds with an identity, it tells you how it
>   used it.
> You might ask why you need the server to indicate what it did.  The
> reason is that we would like the client to know in advance (at the
> time of the ServerHello) whether the server has sent
> Certificate/CertificateVerify rather than having to figure it out from
> what messages the server sends. The ke_mode field is redundant
> (because you also infer it from the server key_shares) but I added it
> for parity.
> I haven't implemented this yet (am going to try to take a crack at that
> before Berlin) but I believe based on experience with the NSS
> negotiation that it will be simpler. I know it removes a bunch of odd
> edge cases which have accumulated over the years, but maybe it adds
> others.
> -Ekr
> 0. I've discussed this with and/or borrowed ideas from Richard Barnes,
> David Benjamin, Karthik Bhargavan, Dave Garrett, Nick Sullivan, Martin
> Thomson, and others. Thanks to those guys, but blame me if you think
> this is bad.
> 1. The other major encoding option here is to have dummy
> group/signature_algorithm indicators that tell you whether you can use
> a pure PSK. When I and others discussed this, the consensus was that
> that was less clean.
> 2. One question that comes up at the same time is whether we should
> allow multiple key shares to be used, which is a structure that this
> makes pretty easy. Basically, the server would just supply as many
> counter-shares as it wanted and then we'd need a defined order for how
> they were inserted into the key schedule. This feature would be nice
> for enabling post-quantum, but probably better to just define
> <PQ-Algorithm + Curve> code points.
> 3. Note that because of this PSK-PRF interaction, PSK isn't totally
> orthogonal with AEAD/PRF. I.e., you cannot use the same PSK with
> HKDF-SHA256 and HKDF-SHA384 if you want to be on the cryptographic
> fairway, but I think it should be easy enough to filter out the cipher
> suites to make that work.
> 4. The other major alternative is just to use the flags bits. So we
> would extend and generalize the flags as shown below.
>    enum {
>      early_data(1),
>      dhe_psk_ke(2),
>      psk_ke(4),
>      psk_auth(8),         // New (no server cert)
>      sig_psk_auth(16)     // New (sign with server cert)
>    } PskUsageFlags;
> These new flags have the expected meaning, namely:
> psk_auth         The server will do connections with just
>                  PSK authentication (equivalent to PSK now)
> sig_psk_auth     The server will do connections with PSK
>                  plus signature (not currently specified).
> Then we update the PreSharedKeyExtension as follows:
>     struct {
>           uint32 usage_flags;
>           opaque identity<0..2^16-1>;
>     } PskIdentity;
>     struct {
>          select (Role) {
>              case client:
>                  PskIdentity identities<2..2^16-1>;
>               case server:
>                  uint32 usage_flags;  // New (one from each category)
>                  uint16 selected_identity;
>          }
>      } PreSharedKeyExtension;
> The idea here is:
> - The client indicates how each PSK can be used (by flags, which
>   need to be a subset of the ticket flags).
> - The server can pick a PSK and indicate how it was actually
>   used.
> For instance, if the client wants to do PSK w/ ECDHE it would indicate
> dhe_psk_ke. If it only wants PSK it would indicate psk_ke. If it was
> willing to do both, it would indicate the bitwise OR.
> Similarly, if the client wants PSK for auth, it would indicate
> psk_auth. If it wants the server to sign, it indicates sig_psk_auth,
> and so on (indicating neither is silly because it makes the key
> unusable).
> By contrast, the server just sets the bits that it actually used.
> I.e., if it sets psk_auth, that means it won't be signing and
> there is no Certificate/CertificateVerify. OTOH if it sets
> sign_psk_auth, that means it will be signing and there will
> be a Certificate/CertificateVerify.
> This leaves early data. As above, the client uses the early_data
> bit to indicate that the PSK was used to encrypt early data
> (obviously, this can just be one key) and the server uses it to
> indicate that it accepted early data. ticket_age needs to go in
> its own extension, but that's easy enough.
> 5. Note: this would allow for modes where the server signs over a PSK
> handshake with no DHE at all. The resumption_ctx mechanism is intended
> to ensure that that is OK, but we'd need to confirm with analysis.