[TLS] implementing ESNI/ECH draft-09

Stephen Farrell <stephen.farrell@cs.tcd.ie> Sun, 28 February 2021 17:34 UTC

Return-Path: <stephen.farrell@cs.tcd.ie>
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 7E76B3A19B8 for <tls@ietfa.amsl.com>; Sun, 28 Feb 2021 09:34:56 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -5.099
X-Spam-Level:
X-Spam-Status: No, score=-5.099 tagged_above=-999 required=5 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_HI=-5, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=cs.tcd.ie
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 X21_c0O2t69L for <tls@ietfa.amsl.com>; Sun, 28 Feb 2021 09:34:54 -0800 (PST)
Received: from mercury.scss.tcd.ie (mercury.scss.tcd.ie [134.226.56.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 100EC3A19B7 for <tls@ietf.org>; Sun, 28 Feb 2021 09:34:53 -0800 (PST)
Received: from localhost (localhost [127.0.0.1]) by mercury.scss.tcd.ie (Postfix) with ESMTP id 64BF4BE3E for <tls@ietf.org>; Sun, 28 Feb 2021 17:34:51 +0000 (GMT)
X-Virus-Scanned: Debian amavisd-new at scss.tcd.ie
Received: from mercury.scss.tcd.ie ([127.0.0.1]) by localhost (mercury.scss.tcd.ie [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id K5Qr2nOZjxst for <tls@ietf.org>; Sun, 28 Feb 2021 17:34:49 +0000 (GMT)
Received: from [10.244.2.119] (95-45-153-252-dynamic.agg2.phb.bdt-fng.eircom.net [95.45.153.252]) by mercury.scss.tcd.ie (Postfix) with ESMTPSA id 67FACBE2F for <tls@ietf.org>; Sun, 28 Feb 2021 17:34:49 +0000 (GMT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=cs.tcd.ie; s=mail; t=1614533689; bh=D4rEG64uLSoV1mRR1iGlJOwMzs3j+D3nRmJ9Xm1ocM8=; h=To:From:Subject:Date:From; b=beoHeCpJP1eRRLkBgNmb6AReBk+VpoA4okn23j2oxf4LzbFfDM0gAQXgdy1W9Hobw fpycaem0/ROInj3lQVuJOdREN6/lwz98UrH46MMs/OUOnu53DyED6KxE8+QflkKvf/ vhns3jrB24afFSrmDUDmiDF1QzMzco0VZt2AJYcY=
To: "tls@ietf.org" <tls@ietf.org>
From: Stephen Farrell <stephen.farrell@cs.tcd.ie>
Message-ID: <29b50ab1-a76f-e72d-28d8-b975e39a1f10@cs.tcd.ie>
Date: Sun, 28 Feb 2021 17:34:47 +0000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1
MIME-Version: 1.0
Content-Type: multipart/signed; micalg="pgp-sha256"; protocol="application/pgp-signature"; boundary="WXr515qic7pwNrWRAaEiFozu4XAzMpXKh"
Archived-At: <https://mailarchive.ietf.org/arch/msg/tls/A5y0Y9EoS9ThQq8WPd816Ra_6ME>
Subject: [TLS] implementing ESNI/ECH draft-09
X-BeenThere: tls@ietf.org
X-Mailman-Version: 2.1.29
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: Sun, 28 Feb 2021 17:34:56 -0000

Hiya,

I've just got my OpenSSL code "working" for draft-09.
The s_client and s_server talk to one another and do
ECH; NSS's tstclnt talks to my s_server and does ECH
and my s_client talks to cloudflare's test server and
does ECH. So this can be made work, which is the good
news. (Thanks to Martin Thomson and Chris Patton for
help in getting that done btw.)

Note that the scare quotes on "working" above are
because the code I have now is horrible and needs a
lot of re-factoring but I'm not keen on doing that
yet if we're considering further breaking changes
that might add more horror;-)

I have the following specific comments having done
this:

- This is *much* harder to implement compared to ESNI as
   it interacts with the rest of the TLS stack/library in
   many more ways. It should be an explicit goal to reduce
   that complexity IMO and not increase it further.  That
   complexity leads to *many* new failure modes that not
   everyone will get right, e.g. incorrect encoding of inner
   extensions, extension handlers that have side-effects
   being called twice etc.
     - Possible fix: organise an interim session (or slot
       therein) with the explicit and only goal of
       simplifying ECH.
     - Possible fix: publish test vectors and require a
       test vector from anyone proposing any new construct,
       before accepting their suggested new crypto-wrinkle.
     - Possible fix: make the spec much more explicit about
       what goes into the transcript at every possible
       stage, esp when that changes.

- Including the client-sender's ephemeral public key in
   the AAD means clients cannot use a single-shot HPKE API.
   That then means that the client key pair has to be
   separately generated and held onto until HPKE encryption.
   It'd be a good bit better and simpler were that not the
   case and a single shot HPKE encrypt API could be used
   witout exposing that key pair to the stack.
     - Possible fix: having a value linked to the inner
       plaintext could suffice maybe?

- The SH.random magic confirmation value interacts with
   ticket handling on the server in some ways I don't yet
   understand fully. Messing with the lower 8 octets there
   also breaks internal OpenSSL APIs for handling packets
   but so do other parts of ECH, so that might be fixable.
     - Possible fix: re-consider the use of SH.random as a
       signal - ECH sticks out in the outer CH anyway, so
       maybe return an ECH in the SH with a value that does
       the same trick so the observer can't tell from the
       SH if it was a successful use of ECH, grease or a
       failure in ECH.

- There's no simple, sensible way to decide which
   extensions to "compress" in the inner that I can see. As
   a library, one could come up with some vastly complex API
   to allow applications pretend to handle this, but that'd
   seem more dangerous than useful. While I made the code
   generic, it's not at all clear that'll ever be useful.
     - Possible fix: forget generic compression and define
       a small set of extension types that can be inherited
       from the outer with all others being present as
       needed in inner and outer. For future extensions
       (e.g.  some many-octet PQ key agreement), have the
       extension definition include the option of "see
       outer" within the extension encoding.

- Given inner and outer can have different sets of
   extensions, I guess there'll never be a way to make ECH
   handling constant-time. If so, then that ought be covered
   as a security consideration. If not, how'd that work?
     - Possible fix: document potential consequences of
       ECH never being constant time?

- I don't plan on implementing the "MUST check
   outer.sni==public_name" check ever really. (Unless
   forced to as part of upstreaming maybe.)
     - Possible fix: remove that MUST.

- I've not implemented padding, nor attempted to make
   greasing as complex as called for, so don't yet have
   comments on those features as they are in -09.

There are probably other times when coding this up where
I swore at the spec text but I've forgotten so maybe those
weren't so bad in the end:-)

Cheers,
S.