Re: [TLS] ESNI interoperability questions

Rob Sayre <> Mon, 28 October 2019 03:46 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 8DBCE1200B6 for <>; Sun, 27 Oct 2019 20:46:18 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.998
X-Spam-Status: No, score=-1.998 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001] 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 bJgqRnMsaR1S for <>; Sun, 27 Oct 2019 20:46:15 -0700 (PDT)
Received: from ( [IPv6:2607:f8b0:4864:20::131]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id 8E68D120044 for <>; Sun, 27 Oct 2019 20:46:15 -0700 (PDT)
Received: by with SMTP id s75so7000563ilc.3 for <>; Sun, 27 Oct 2019 20:46:15 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to; bh=6j+VVaYsCVz7n5cAQTFFA4anNBmFkmdMBDWwTsy/WVg=; b=IsxTXHE3Wi3G8BV+2cl3IAmmt7oG2OR5n2ESM0HFBO+lHzGuIw9ajifTfk/a0w1a50 frQxM8jvYuthXR4dzb1shIgGmQdfJdhXRmtNaZSF/7th6zNP/TjYfGKTqeOduTr5W+rV S7PEYL5SQ2AI4Yq1UsWBEUpRfsAGRSCET41iitgwd3TVi1+XVz4gf9JkP9ljnrDN2dKM 9Q1yVml/brVQOL9axygChOmxBOkWh/KV4gf3HaQOesIZhuptY8UKt5RcsNfRAWw6HFLX hNZQfaVSE+UHeianlTWun2ysxeq7VP4cRrh6zGpyrIlfwrt6Zte0Bp69lBcEz/PjV+G/ O94g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to; bh=6j+VVaYsCVz7n5cAQTFFA4anNBmFkmdMBDWwTsy/WVg=; b=a0WLhidJKyHoPe0BVU3vtBKj6bTYBbxhb1+O4GSOaYsLw6aOXewhuCXG3i2hWWwwd9 eVrfxK1BYzc15WH6meRhM45qAc/Kq/9TwrF+UldBjFfAwrtmDQ7kCFxTQe7mzqR+TQ0T Xkt+ye9kwDSdYrJlrsAhBGQZawfRhcrY/U8C9Gm8x0qGZWzuGtnVqiDRhZVI1/LcnZky p/CGRa25q/yvhB0toUarv+UVJ7eH8pqZCWNjj7d+NPYKb7MCbxSj0s7hLUN2q8PAGGsn n1Q9ApcqBW/QV9/j8lQyUGMIBjvZ+bMfLWUu3NmGja/5dVQvRV/2T2BJoLj+RhGGUBT1 tl0g==
X-Gm-Message-State: APjAAAWMCNm6qZIkN0TIdVJsTdNCi+G6aFwGTlcet7UEtA+bqB5bjGVb c28qJAqBcJlF9p8WP5OvNwj+XwtTJxnXQE8j/J4gqX4Ir20=
X-Google-Smtp-Source: APXvYqwBXVe9OhKjDRkZmt/WKU6aKJmA+3fgExMu3B4YnQ07oEQaO7CLPhDuETdNfJSMUVphjsB//U5cxpXBR13uVzk=
X-Received: by 2002:a92:5d49:: with SMTP id r70mr18253928ilb.257.1572234374399; Sun, 27 Oct 2019 20:46:14 -0700 (PDT)
MIME-Version: 1.0
References: <> <> <>
In-Reply-To: <>
From: Rob Sayre <>
Date: Sun, 27 Oct 2019 20:46:01 -0700
Message-ID: <>
To: "" <>
Content-Type: multipart/alternative; boundary="00000000000063cd260595f05789"
Archived-At: <>
Subject: Re: [TLS] ESNI interoperability questions
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." <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Mon, 28 Oct 2019 03:46:19 -0000


The joke is on me, because also does not check any SNI / ESNI
field. :)

However, I did notice that my record_digest value was off vs Firefox. And,
now, I don't feel so bad.

I noticed that esni-02 and esni-03 defined record_digest as:

record_digest  A cryptographic hash of the ESNIKeys structure from
      which the ESNI key was obtained, i.e., from the first byte of
      "checksum" to the end of the structure.  This hash is computed
      using the hash function associated with "suite".

but, esni-04 defines record_digest like so:

record_digest  A cryptographic hash of the ESNIKeys structure from
      which the ESNI key was obtained, i.e., from the first byte of
      "version" to the end of the structure.  This hash is computed
      using the hash function associated with "suite".

By following the record_digest algorithm from esni-04, I was able to match
Firefox's record_digest fields for a given domain. This strikes me as very
odd, since the ESNIKeys structure changed in esni-04, but I'm still using
the older, esni-02 definition. So, it sure seems like people are running a
strange mix of drafts at the moment. I think there's still something wrong
with my calculation of the encrypted_sni field--perhaps I will have to read
more NSS source code to figure out what that is. :)


On Sun, Oct 27, 2019 at 2:33 PM Rob Sayre <> wrote:

> Hi,
> This code works with (hosted by Cloudflare). I was previously
> testing with a parked domain. Maybe there's some signaling needed when the
> handshake fails based on Split Mode / Shared Mode configuration.
> thanks,
> Rob
> On Sat, Oct 26, 2019 at 7:43 PM Rob Sayre <> wrote:
>> As an update,
>> I seem to be able to negotiate a handshake with "", but
>> I must be making a mistake in my ClientHello. Wireshark sees Firefox's
>> ClientHello as TLS 1.3, but mine only shows up as TLS 1.0, although the "
>>" ServerHello does show up as TLS 1.3. You check out
>> the details on that host at .
>> My client fails to read application data after that, although the server
>> does seem to send it.
>> You can check out my fork of Rustls here:
>> If you then do something like:
>> $ cd rustls/rustls-mio/
>> $ cargo run --example esniclient
>> you should see some ESNI traffic. Some of the code in the fork is a
>> little messy so far, but it's still in the "make it work" phase. :)
>> thanks,
>> Rob
>> On Sat, Oct 26, 2019 at 3:31 PM Rob Sayre <> wrote:
>>> Hi,
>>> I think I have a working ESNI client, but I'm encountering a strange
>>> error testing with Cloudflare.
>>> I initially tested with "", but found this was a bad
>>> idea, because that host doesn't seem to require an SNI or ESNI. So, a bogus
>>> ESNI triggered no errors.
>>> When my client sends an ESNI to a Cloudfront-fronted domain, I get a
>>> handshake_failure error (40). According to the -02 draft, this should only
>>> happen if the server fails to negotiate TLS 1.3. I've got my client
>>> configured for TLS 1.3 only, so this shouldn't be an issue. When I add an
>>> unencrypted SNI to an otherwise identical ClientHello, everything works
>>> over TLS 1.3. If there are problems with my ESNI encryption, I should see
>>> other errors. Things like "illegal_parameter" or "decrypt_error", right?
>>> In Wireshark, I can at least see that my encrypted_server_name extension
>>> matches Firefox's cipher and key share entries, and the lengths of
>>> record_digest and encrypted_sni are the same. Firefox does send some
>>> extensions I don't, like ALPN. Does the absence of unencrypted SNI imply
>>> the presence of other extensions?
>>> I also wondered about extension order. Since the ClientHello.key_share
>>> is part of the ESNI calculation, does it need to appear first in the
>>> extensions list?
>>> thanks,
>>> Rob