cipher suite list is orthogonal to the list of keys, so each key may be used with any cipher suite. <del> This structure is placed in the RRData section of a TXT record as a base64-encoded string.  If this encoding exceeds the 255 octet limit of TXT strings, it must be split across multiple concatenated strings as per Section 3.1.3 of RFC4408.  Servers MAY supply multiple ESNIKeys values, either of the same or of different versions.  This allows a server to support multiple versions at once.  If the server does not supply any ESNIKeys values with a version known to the client, then the client MUST behave as if no ESNIKeys were found. The name of each TXT record MUST match the name composed of _esni and the query domain name.  That is, if a client queries example.com, the ESNI TXT Resource Record might be: </del>  Servers MUST ensure that if multiple A or AAAA records are returned for a domain with ESNI support, all the servers pointed to by those <del> records are able to handle the keys returned as part of a ESNI TXT </del>  record for that domain. Clients obtain these records by querying DNS for ESNI-enabled server In cases where the domain of the A or AAAA records being resolved do not match the SNI Server Name, such as when RFC7838 is being used, <del> the SNI domain should be used for querying the ESNI TXT record. </del>  Servers operating in Split Mode SHOULD have DNS configured to return the same A (or AAAA) record for all ESNI-enabled servers they key schedule.  It MUST also select an appropriate cipher suite from the list of suites offered by the server.  If the client is unable to select an appropriate group or suite it SHOULD ignore that ESNIKeys <del> value and MAY attempt to use another value provided by the server (recall that servers might provide multiple ESNIKeys in response to a ESNI TXT query).  The client MUST NOT send encrypted SNI using groups or cipher suites not advertised by the server. </del>  When offering an encrypted SNI, the client MUST NOT offer to resume any non-ESNI PSKs.  It additionally MUST NOT offer to resume any 8.3. <del> IANA is requested to create an entry in the DNS Underscore Global Scoped Entry Registry (defined in I-D.ietf-dnsop-attrleaf) with the "RR Type" column value being set to "TXT", the "_NODE NAME" column value being set to "_esni", and the "Reference" column value being set to this document. </del>

Subsumes and .
lgtm
NAME NAME NAME What the... So all already working eSNI in Cloudflare is already outdated? Do you understand how difficult it will be to get new IN ESNI in Bind and Knot and even in dig utility? Do you understand that while IN txt is working in all OS, IN ESNI will not work in any of them (system resolver, I mean)? Do you understand that you use for ESNI RR 0xff9f (which is 65439), so it is reserved for private use in IANA? Solution for this. Can you please use both of them?
this is good for wiretapping for easy to drop all ESNI with DPI for SNI downgrade
PR from NAME implements the ESNI RRType, but there doesn't seem to be another issue currently open to track discussion of it. a new RRType allows the removal of the _esni prefix ( and ) reusing TXT has the potential for conflicts with other uses even with the prefix. (imagine the definition of a TXT record that simply applied to all DNS entries) while both TXT and ESNI are 8 bit clean, some people are surprised to learn that about TXT so using a new type may be more robust. Some generic tools processing TXT records would benefit from this. TXT is a set of <= 255 byte strings, defining a new type removes that complexity and reduces overhead There was initially concern about the viability of new RRTypes, but I believe people are more comfortable with that now than when the text was drafted.
Fixed in .
issue briefly discussed the choice of a esni DNS prefix for the TXT record. I think we should revisit that. My primary concern is that using 2 different names for the addressing and key information makes DNS aliasing un-necessarily complicated. Consider the case where URL is a customer of URL and URL is deploying ESNI for all its customers. A classic way to do this is to have URL be a CNAME for URL unfortunately to use URL's new ESNI infrastructure URL would need to add a CNAME record for URL as well. So the ESNI deployment requires DNS changes outside of the org deploying ESNI, which is going to limit its deployment, which in turn is going to limit the breadth of its anonymity pool. :( Additionally, I've been told that anecdotally putting names under a CNAME is legal but error prone. RFC 1912 seems to have some language that suggests its not even legal (though that is informational). If the ESNI information were instead stored without a prefix then the alias would automatically apply as the CNAME applies to all the RR's of a hostname. Part of the reason for choosing the prefix was to avoid collisions in the TXT space, so it makes sense to also reopen and use a non TXT RR type if we drop the prefix. I think the consensus is moving towards that being fine. This would also to harmonize esni with existing dns deployments.
I forgot to acknowledge the downside here is with apex records. You can't cname an apex record, so the normally annoying second cname with the prefix is actually the only thing the apex can use natively as an alias and this proposal gives that up. otoh apex records inline someone's A records (usually a single provider's anycast) already so they can do the same thing with esni.. and/or we could allow some kind of delegation explicitly as part of the new rrtype (i.e. delegation within the new rrtype data, not via cname)
also see pr
I am not sure if I agree with the problem statement. To me it seems that the argument is based on the assumption that URL is the one to decide if ESNI should be applied for URL I am not sure if all of us would be happy with that assumption. The alternative approach here is to give the owner of each hostname the freedom of deciding whether the hostname should be covered by ESNI. Current design allows the hosting companies to adopt that model, by using the DNS configuration that the hostname owner controls as the switch.
ESNI is already a property of the server not the origin name.. in the same way the version of TLS or the cipher suite set is a property of the server.. or the level of http. All necessarily under the control of URL because it reflects whatever is available on their infrastructure. bighoster may commonly allow their customers to configure this stuff on a per customer or service basis, but that's a bit of a different take and not incompatible with the approach here.
NAME While that might be true, I am not sure if removing the prefix and introducing ESNIInclude () is worth the additional complexity and overhead. Assuming that we merge , becomes a non-issue. Because a wildcard will much all names with the designated type, including the prefix. For example, the following configuration will support ESNI for all the hostnames under URL, like , , because any query for resolves to . So the only downside is that using prefix and a dedicated RR type at the same time might look strange. But it's practical. I am not sure if we would prefer to require alias resolution for every ESNI client. Implementation wise, it's about reimplementing what DNS recursor usually does in the stub resolver. You need to do things like detecting too many redirects and/or loops. There would also be a performance degradation, because each client needs to do the recursive lookup, while with the prefix we can rely on the recursive resolvers to do it and cache it for other clients. To reiterate, I wonder if there is any practical reason to reinvent the wheel.
Stretching the bounds of my DNS knowledge here, but I think this makes divergence between the A/AAAA and ESNIKeys records much less likely. That is, when URL is served by both CDN A and CDN B, the DNS will return or . If both things are record types on the same hostname, then the divergence only happens when the queries happen on opposite sides of a cached CNAME record expiring and getting the opposite answer the next time around. But if they're separate hostnames, as in the current doc, it's entirely possible to get opposite CNAME records cached, and you've diverged for all clients of the caching resolver for the TTL of the shorter CNAME record. That's a far worse probability of divergence.
Fixed in . Closing.
if you dynamically syntehsize a whole bunch of names in URL you would probably use a URL a/aaaa configuration to do so and give them all the same addresses. but you can't do the same things for TXT records with the esni prefix.. basically URL doesn't do the trick (rfc 4592). initially I viewed this as a configuration and implementation issue because queries and responses do not carry the * at all - the records are synthesized on demand from this config. however, the wildcard is part of AXFR which forms an open interface between resolvers so its syntax and meaning is quite reasonably standardized and should be considered.
Minor point but I am not sure if AXFR is something that is exposed to the resolvers. My understanding is standardized interface for synchronizing authoritative servers. So this will be an issue only for websites that use a DNS that either depends on AXFR (or in other ways depend on the vocabulary of the AXFR). I agree that it would be preferable to address the issue.
my thought here is that axfr represents an interface between, potentially, different implementations so we should try and respect that to whatever extent is possible.
My view of the issue is that we can support all the models that we need to support if we adopt so that ESNIKeys will be distributed using a dedicated type with a prefix. The patterns we need to consider are the combination of three types of DNS records (i.e. single-host, APEX, wildcard) and a boolean indicating if DNS is maintained by someone other than the CDN. The table below illustrates how you could configure the DNS on each case. There are certain cases in which you could use CNAME instead of A / ESNI. 1: You will be required to create _esni records for all hosts that you specify explicitly, if it is necessary to disable ESNI for those hosts (or if those hosts use different ESNI keys).
Fixed in .
dns records are 8 bit clean and rfc 6763 is an example of a TXT record carrying arbitrary data
:+1: Base64 is not only complication. It is a space overhead for a large object like ESNIKeys. Seeing corruption of binary will be rare; we can detect them by validating the checksum and fallback to non-ESNI in such case. So why not go for binary? FWIW, base64 was introduced in .
This is solved in which removes base64 with new ESNI RR type.
We only added this since TXT records were claimed to not work well with binary, per Christian’s suggestion. I’m fine either way.
Thanks for the info. I found URL, in which NAME asks: We know that we can store more than 128 octets in TXT record, and that we have a precedent that uses TXT to store binary data, as NAME has pointed out. Regarding configurability, my understanding is that RFC 1035 defines how binary TXT records can be specified in a zone file, and therefore many DNS server "softwares" support having such records. Googling also tells me that managed DNS services like Route 53 and Azure DNS provide the capability, although surprisingly they use different escape sequences ( uses + 3 octal, uses + 3 decimal).
I do not think it’s a complication, and I’m not convinced space is an issue as per your comment above.
only tangentially related - NAME do you know why your URL txt record is broken into 127 char strings instead of 255? Is there a bug being worked around somewhere?
NAME Oh I did not notice that. I am using tinydns (of djbdns), and it seems like tinydns works that way (see URL).
NAME The issue about the size is that with base64 we might hit the 512-octet threshold when publishing keys of multiple strengths. As an example, query for URL currently returns a 186-byte response, which contains just secp256r1 key. If we add secp384r1 and secp521r1, I'd assume that the size will come near to 490 octets. In other words, for longer hostnames we will hit the 512-octet threshold if we publish three keys. If we avoid the base64 encoding, we will have enough room to store 3 ECDH keys that can provide 128-, 192-, 256-bit-level security. I do not think this argument is strong enough to prohibit the use of base64 for the following reasons: we will be using DoH / DNS over TLS between the client and the resolver we might be using DNS over UDP that has the 512-octet threshold between the resolver and the authoritative server, but we would want that to migrate to DNSSEC or something even better we might be just fine with publishing only two keys: X25519, X448 But it does make me prefer not to have the overhead of base64, if that is possible.
Fixed in .
:+1:

cipher suite list is orthogonal to the list of keys, so each key may be used with any cipher suite.  <ins> This structure is placed in the RRData section of an ESNI record as- is.  Servers MAY supply multiple ESNIKeys values, either of the same or of different versions.  This allows a server to support multiple versions at once.  If the server does not supply any ESNIKeys values with a version known to the client, then the client MUST behave as if no ESNIKeys were found. The name of each ESNI record MUST match the query domain name or the query domain name's canonicalized form.  That is, if a client queries example.com, the ESNI Resource Record might be: </ins> Servers MUST ensure that if multiple A or AAAA records are returned for a domain with ESNI support, all the servers pointed to by those  <ins> records are able to handle the keys returned as part of an ESNI </ins> record for that domain. Clients obtain these records by querying DNS for ESNI-enabled server In cases where the domain of the A or AAAA records being resolved do not match the SNI Server Name, such as when RFC7838 is being used,  <ins> the SNI domain should be used for querying the ESNI record. </ins> Servers operating in Split Mode SHOULD have DNS configured to return the same A (or AAAA) record for all ESNI-enabled servers they key schedule.  It MUST also select an appropriate cipher suite from the list of suites offered by the server.  If the client is unable to select an appropriate group or suite it SHOULD ignore that ESNIKeys  <ins> value and MAY attempt to use another value provided by the server. (Recall that servers might provide multiple ESNIKeys in response to a ESNI record query.)  The client MUST NOT send encrypted SNI using groups or cipher suites not advertised by the server. </ins> When offering an encrypted SNI, the client MUST NOT offer to resume any non-ESNI PSKs.  It additionally MUST NOT offer to resume any 8.3.  <ins> IANA is requested to create an entry, ESNI(0xff9f), in the existing registry for Resource Record (RR) TYPEs (defined in RFC6895) with "Meaning" column value being set to "Encrypted SNI". </ins>


complete, perhaps by timing out. In cases where the domain of the A or AAAA records being resolved do <del> not match the SNI Server Name, such as when RFC7838 is being used, the SNI domain should be used for querying the ESNI record. </del>  Servers operating in Split Mode SHOULD have DNS configured to return the same A (or AAAA) record for all ESNI-enabled servers they

The draft currently states: I'm confused about what this means. From reading RFC 7838, I'm not sure the SNI and DNS names do not match when you're querying an alternate name. In particular, RFC 7838 states: Which means, if I understand it correctly, the client will send "URL" in the SNI when trying to query resources from it - the requirement is only that the certificate for "URL" also cover "URL".
Agreed. I'm parsing RFC 7838 the same way. I think we should drop this text.
The problem the text presents is real (though the resolution is arbitrary). no.. that's a misread. See section 2.3 of 7838 The alternate is essentially just a cname for the origin. If host b is an alternate for origin a, in order to use the alternate you look up the DNS a/aaaa of b, do a TCP connect to b, and then use sni=a and expect a certificate valid for a. (indeed the point of the SNI is to tell the server what certificate you expect to see) With esni you would continue to do all of those things, except of course sni=encrypted(a).. and the question becomes where do you find the key used for the encryption. Is it the ESNI DNS record of a (the origin) or b (the alternate host). That's the question the text is trying to resolve - it says to use a (the origin). I could make a case for either choice but I think the text needs to decide
NAME Would you mind suggesting some text with an example to clear this up?
NAME thanks for the clarification and pointer to s2.3 of 7838. After reading that I think the text in the ESNI draft looks fine. (I'd just add a pointer to s2.3 of 7838 instead of just 7838 to help prevent the confusion I had)

complete, perhaps by timing out. In cases where the domain of the A or AAAA records being resolved do  <ins> not match the SNI Server Name, such as when RFC7838 Section 2.3 is being used, the SNI domain should be used for querying the ESNI record. </ins> Servers operating in Split Mode SHOULD have DNS configured to return the same A (or AAAA) record for all ESNI-enabled servers they


therefore allow clients to detect and recover from this situation (see esni-resolution for more details). <del> Servers operating in Split Mode SHOULD have DNS configured to return the same A (or AAAA) record for all ESNI-enabled servers they service.  This yields an anonymity set of cardinality equal to the number of ESNI-enabled server domains supported by a given client- facing server.  Thus, even with SNI encryption, an attacker which can enumerate the set of ESNI-enabled domains supported by a client- facing server can guess the correct SNI with probability at least 1/ K, where K is the size of this ESNI-enabled server anonymity set. This probability may be increased via traffic analysis or other mechanisms. </del>  The following sections describe a DNS record format that achieve these goals.

The current text about anonymity sets for records is too restrictive. If I have 100000 names and 100 IPs and for all queries I randomly return four out of my 100 IPs chosen randomly, I still provide the same anonymity set but I violate the SHOULD. The proposed text
The document currently states: I think this is too restrictive. If I have 100000 names and 100 IPs and for all queries I randomly return four out of my 100 IPs chosen randomly, I still provide the same anonymity set but I violate the SHOULD. How about:
Agreed. At a minimum this should reference a set of A and AAAA records rather than "the record" (as many records across the A and AAAA rrsets is very common). I think NAME proposed text is fine.
NAME sgtm, do you plan to open a PR? I made URL but I think your wording is better.
Created
LGTM -- thanks!

therefore allow clients to detect and recover from this situation (see esni-resolution for more details).  <ins> Content providers operating in Split Mode SHOULD ensure that the A and AAAA records for ESNI-enabled server names do not allow identifying the server name from the IP address.  This can for example be achieved by always returning the same records for all ESNI-enabled names, or by having the function that picks addresses from a pool not depend on the server name.  This yields an anonymity set of cardinality equal to the number of ESNI-enabled server domains supported by a given client-facing server.  Thus, even with SNI encryption, an attacker which can enumerate the set of ESNI-enabled domains supported by a client-facing server can guess the correct SNI with probability at least 1/K, where K is the size of this ESNI- enabled server anonymity set.  This probability may be increased via traffic analysis or other mechanisms. </ins> The following sections describe a DNS record format that achieve these goals.


The SNI encryption key is computed from Z as follows: where ESNIContents is as specified below and Hash is the hash <del> function associated with the HKDF instantiation. </del>  The client then creates a ClientESNIInner structure: The ClientEncryptedSNI.encrypted_sni value is then computed using the usual TLS 1.3 AEAD: <del> Where ClientHello.KeyShareClientHello is the body of the extension but not including the extension header.  Including ClientHello.KeyShareClientHello in the AAD of AEAD-Encrypt binds the </del>  ClientEncryptedSNI value to the ClientHello and prevents cut-and- paste attacks. If the server sends a HelloRetryRequest in response to the ClientHello and the client can send a second updated ClientHello per the rules in RFC8446, the "encrypted_server_name" extension values <del> which do not depend on the (possibly updated) ClientHello.KeyShareClientHello, i.e,, ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, and ClientEncryptedSNI.record_digest, MUST NOT change across ClientHello messages.  Moreover, ClientESNIInner.nonce and ClientESNIInner.realSNI MUST not change across ClientHello messages.  Informally, the values of all unencrypted extension information, as well as the inner extension plaintext, must be consistent between the first and second ClientHello messages. </del>  5.1.3.

While at it, remove the redundant "ClientHello." prefix, the name KeyShareClientHello implies this. _ NAME I did not explicitly mention that "extension_data" is a list of key shares, but hope that the suggested phrase is strong enough to imply that. Do you think that is sufficient or should it become something like: (By the way, the list of client key shares could contain one or more entries, but it could also be empty if the client would like to trigger a HRR. That should still be OK since the key/nonce is derived from the client hello random.)
Those changes seem okish though could maybe be better. My issue was that OpenSSL (afaics) previously ignored all the key shares except the one used, so handling two of 'em as the AAD meant adding some new state. No idea if other implementations are like that though. I guess it might help someone else if it explicitly said that there can be >1 key share to include in the AAD. (BTW, on your BTW, I need to think more about ESNI and HRR handling, haven't tested that yet so not sure if there's a case where the encoding of 0 key shares would be used as ESNI AAD.)
If this adds so much complication, why not drop the KeyShareClientHello completely? If the purpose is to bind this to the original Client Hello, then the Client Random should be sufficient. An implementation that creates the encrypted_sni field is also responsible for generating a random client hello and a new ESNI key share. Assuming that these are always unique between Client Hellos, then removing the KeyShareClientHello extension should still preserve the binding property. And even if for some reason the ESNI key share is reused (e.g. shared between different client hello, or reusing one from KeyShareClientHello), the derived key/nonce would still be different if Client Hello Random is unique. NAME what was the reason for mixing the client key shares list in addition to the existing client random (commit 134b15c87b5c4cde7f52500138662f64757e2e9c)?
If you don't bind in the client key share, there is a trivial attack in which the attacker replaces the key share with their own, causing the server's certificate to be encrypted to them.
What NAME said above. :-)
Thanks for the clarifying text!
Oh I see, the sender of the ESNI extension does not have to prove its knowledge about the ESNI private key, so an attacker could trivially copy the victim's ESNI extension and client random into the attacker's handshake, and recover the certificate if the client key shares were not included. Even if the attacker cannot decrypt SNI, they can still observe the side-effects. Thanks! I think the text could be clarified to highlight this, I'll prepare a proposal for this.
A second point in issue wasn't addressed very clearly by . "...HKDF-Extract(0, Z) should probably become HKDF-Extract("", Z) or be explicit about the salt as is done in URL (or URL)." The current draft does clarify this in the text below, but I initially missed that. The reader has to know that the first argument to HKDF-Extract is named "salt" to put it together. I did end up getting it right, figuring this was intended to mean a buffer of zeros. I think it would be clearer to say:
NAME a PR to clarify this point is most welcome!
It would be ok to take this suggestion into consideration under the terms of the IETF's "Note Well" blue sheet terms, and incorporate it into a PR by the editors.
NAME I agree! Could you please provide that PR?
Oh, I was asking you folks to do it. If there's a reason I need to do it, I'd be happy to.
I don't think this is necessary, so while I'm willing to look at a PR, I'm not going to make one at this time.
It was initially not clear to me what should be included in the AAD for encrypting ClientESNIInner into ClientEncryptedSNI.encryptedsni. The spec currently says: ClientHello.KeyShareClientHello is not defined in this document. At first I thought it would cover ClientEncryptedSNI.keyshare, but that seemed odd. Later I found that it refers to the Key Share extension defined in . Perhaps this reference could be added? On a related note, should probably become or be explicit about the salt as is done in URL (or URL).
FWIW, I also had a little trouble with this. My initial interpretation was to use the h/s key share that ends up being used as the AAD, which worked fine for my client (vs cloudflare) and for my server (vs. NSS' tstclnt). In each of those cases though only one key share was sent by the client. FF nightly however sends two key shares in the h/s so I had to change my code to do the right thing. Could be worth a note in the internet-draft e.g. saying to use (the encoding of) all key shares from the h/s and that some clients do send more than one.

The SNI encryption key is computed from Z as follows: where ESNIContents is as specified below and Hash is the hash  <ins> function associated with the HKDF instantiation.  The salt argument for HKDF-Extract is a string consisting of Hash.length bytes set to zeros. </ins> The client then creates a ClientESNIInner structure: The ClientEncryptedSNI.encrypted_sni value is then computed using the usual TLS 1.3 AEAD:  <ins> Where KeyShareClientHello is the "extension_data" field of the "key_share" extension in a Client Hello (Section 4.2.8 of RFC8446)). Including KeyShareClientHello in the AAD of AEAD-Encrypt binds the </ins> ClientEncryptedSNI value to the ClientHello and prevents cut-and- paste attacks. If the server sends a HelloRetryRequest in response to the ClientHello and the client can send a second updated ClientHello per the rules in RFC8446, the "encrypted_server_name" extension values  <ins> which do not depend on the (possibly updated) KeyShareClientHello, i.e,, ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, and ClientEncryptedSNI.record_digest, MUST NOT change across ClientHello messages.  Moreover, ClientESNIInner.nonce and ClientESNIInner.realSNI MUST not change across ClientHello messages. Informally, the values of all unencrypted extension information, as well as the inner extension plaintext, must be consistent between the first and second ClientHello messages. </ins> 5.1.3.


If the server supports wildcard names, it SHOULD set this value to 260. <del> The moment when the keys become valid for use.  The value is represented as seconds from 00:00:00 UTC on Jan 1 1970, not including leap seconds. The moment when the keys become invalid.  Uses the same unit as not_before. </del> A list of extensions that the client can take into consideration when generating a Client Hello message.  The format is defined in RFC8446; Section 4.2.  The purpose of the field is to provide room including those caused by intermediaries such as a DNS proxy running on a home router. <del> "not_before" and "not_after" fields represent the validity period of the published ESNI keys.  Clients MUST NOT use ESNI keys that was covered by an invalid checksum or beyond the published period.  If none of the ESNI keys values are acceptable, the client SHOULD behave as if no ESNI records were found. Servers SHOULD set the Resource Record TTL small enough so that the record gets discarded by the cache before the ESNI keys reach the end of their validity period.  Note that servers MAY need to retain the decryption key for some time after "not_after", and will need to consider clock skew, internal caches and the like, when selecting the "not_before" and "not_after" values. Client MAY cache the ESNIRecord values for a particular domain based on the TTL of the Resource Record, but SHOULD NOT cache them based on the not_after value of the ESNIKeys structure, to allow servers to rotate the keys often and improve forward secrecy. </del> Note that the length of the ESNIRecord structure MUST NOT exceed 2^16 - 1, as the RDLENGTH is only 16 bits RFC1035.

We now have a proper retry mechanism, so we don't need to prevent clients to connect using expired keys anymore.
NAME notes that the notbefore and notafter fields are there and described, but not really part of the operational notes. Having something there that talks about these, particularly as it relates to clock skew, would be valuable.
(My ~monthly login into URL - this'd be better on the TLS WG list, and I will send mail on this sometime but anyway...) The not-before and not-after fields are a mistake. Same as turned out true for x.509. I was just doing testing where FF nightly barfed on ESNIKeys I'd published for only that non-reason. (There is no overall security win in so-doing, in general.) Creating a tangle between the cadence at which one updates DNS, the ESNIKeys-internal "lifetime" of a key, the DNS TTL and server-state is basically just pointless nonsense. Let's delete those fields from ESNIKeys before we're done and just rely on DNS for what it already does.
Now that has been merged, I agree that there is less need for notbefore and notafter fields. Previously, a client using an expired key led to connection failure, and therefore having these fields were necessary.
Fixed by removing these fields with .
Thank you for the PR. LGTM

If the server supports wildcard names, it SHOULD set this value to 260.  A list of extensions that the client can take into consideration when generating a Client Hello message.  The format is defined in RFC8446; Section 4.2.  The purpose of the field is to provide room including those caused by intermediaries such as a DNS proxy running on a home router.  Note that the length of the ESNIRecord structure MUST NOT exceed 2^16 - 1, as the RDLENGTH is only 16 bits RFC1035.


padded_length The length to pad the ServerNameList value to prior to encryption.  This value SHOULD be set to the largest ServerNameList the server expects to support rounded up the nearest multiple of 16. <del> If the server supports wildcard names, it SHOULD set this value to 260. </del>  A list of extensions that the client can take into consideration when generating a Client Hello message.  The format is defined in I-D.ietf-tls-grease "encrypted_server_name" extension as follows: Select a supported cipher suite, named group, and padded_length <del> value.  The padded_length value SHOULD be 260.  Set the "suite" field to the selected cipher suite. </del>  Set the "key_share" field to a randomly-generated valid public key for the named group.

See discussion at URL
I am not a fan of this change. I don't like encoding this kind of restrictive choice in the protocol.
OK, I've removed the protocol change and made the restriction purely advisory.
Stephen Farrell pointed out on the list that 260 is rather a lot of waste to stick into the ClientHello. URL 260 characters is this large of a hostname: It's probably reasonable to recommend a smaller default value like 64 or 96 or 128. (Numbers pulled out of a hat. I have no data on how big it actually should be.)
Yeah. The question is if we are happy with hostnames longer than the threshold (e.g., 64, 96, 128) sticking out. I think the current design of allowing the server to choose the correct value is the right approach. OTOH, regarding the size you'd use for greasing, I can understand the concern of wasting bytes. Maybe browsers can use smaller sized payloads when greasing the ESNI extension, under the premise that they would be sometimes using the maximum. The size of the extension being different from when it is actually used does not matter in practice, because an observer can typically tell if ESNI was used by checking if the unencrypted SNI record contains the fallback domain name (here I assume that we adopt ).
Agreed that letting the server choose the correct value makes sense. But I think the specification should also be opinionated about this, so we don't get wildly different values for everyone, and so implementors have something to pick if they don't really care. The closely thing the spec currently has to an opinion is 260, which is kind of large.
Absent data that shows there's a tighter upper bound, I would prefer to keep the 260 recommendation and perhaps suggest that servers may choose something smaller if they know better.
According to RFC 1035 host names can be up to 255 octets. I don't think this has changed. So if this document makes a recommendation it should cover the worst case. Someone could argue for something more efficient. For instance, if we were to do draw the distribution of name lengths we would find that the median is 13 characters. (An excellent number) Min is 4 and max is 117. (Source: URL) But this can change and the recommendation in this document will become outdated. Maybe add something like the following: "servers COULD tailor the padding length to cover the longest name associated with the hosts they handle." (And keep the existing number)
In the current text, the "260" number only matters for GREASE; anyone who actually publishes ESNIKeys SHOULD choose the smallest number that covers their names, "rounded up to the nearest multiple of 16". Given NAME data, the most common choices will likely be 16 and 32. This state of affairs makes GREASE less effective, because (1) it doesn't resemble real usage and (2) it isn't exercising the length "joint". As a solution, I would propose recommending that GREASE clients choose a valid length at random. If we want to get fancy we could say that the random choice may be non-uniform (to favor shorter ClientHellos) but should have at least x% chance of choosing each length option. Also, instead of saying that the paddedlength "SHOULD" be 16*N or 260, I think we should consider a "MUST", and/or a denser encoding (e.g. enum with values 0..16). Otherwise, we have to figure out what clients should do if is huge. (I wonder how that interacts with QUIC and DDoS...)
Another proposal is mentioned in of just compressing these bits instead
NAME this should be fixed, with new recommendation text, via . Please re-open if not!
LGTM. Thank you for the text!The recommended text LGTM. NAME NAME NAME please have a look. Hiya, Various bits'n'pieces below... On 13/02/2019 23:55, David Benjamin wrote: Not just that. ESNIKeys is a fairly complex structure that has a number sets/sequences of values. There are various possible deployment models. The current structure assumes that it's ok to encode all that stuff up in one TLS style blob and then put that in the DNS. That might not make sense for some deployments in particular where the DNS operator is not closely tied to the TLS server admin or where there's 1 DNS operator and N TLS server admins (for the same origin). And then there's the use of the TXT RR. But I agree this is orthogonal - I was mostly saying that in agreeing with this PR I continue to think the DNS RR stuff needs other work. Then delete it:-) Disagree. "Just describing" does not match the use of a meaningless marketing term like "trusted blah proxy" sorry. Better to avoid all that fuss really, no? I don't recall that having a concept of it being possible to "correctly" implement breaking the TLS protocol? (As is inherent in being an MITM.) It may be ok to live with such fallback whilst ESNI is being introduced but I think ongoing support for it would be unwise. And such a fallback requires no discussion of MITM attacks. (Other than as an attack.) I object to that term again, sorry:-) It's marketing meaninglessness. "MUST NOT surface" seems like bad phrasing then. That would be ok. Saying that requires no discussion of MITM attacks. (My openssl code would actually make that visible to the application if the application called a status API, but the TLS h/s would have failed from the application POV even if the h/s looks like it worked on the wire.) I'd guess that some implementers may be put off by the wasted bandwidth. Others won't care but if it's the case that sending a bogus ESNI x% of the time gets as good a result as sending all the time (which is how I interpret what the SHOULD calls for) then it seems better to encourage x% and not 100%. "The client" in almost all IETF specs means a thing that really implements the spec. So in this case, yeah, I think it might be good to say that a TLS client implementer who only has time to grease and not do the real thing is still doing good overall by just doing that. (That said, I've no idea if there'd ever be such an implementer, though when we did DKIM there were many mail receivers who parsed but didn't actually check signatures - maybe mail implementers are more slapdash though:-) Yeah, and I disagree with that too:-) Regardless of the above disagreement about 260, if a client has been sending a bunch of CH's including real ESNI that are about 400 bytes because some server's ESNIKeys says to pad to 160, and that client then sends 600 bytes CH's to everyone else, I think it'd be crystal clear which is grease and which not. Cheers, S. >

padded_length The length to pad the ServerNameList value to prior to encryption.  This value SHOULD be set to the largest ServerNameList the server expects to support rounded up the nearest multiple of 16.  <ins> If the server supports arbitrary wildcard names, it SHOULD set this value to 260.  Clients SHOULD reject ESNIKeys as invalid if padded_length is greater than 260. </ins> A list of extensions that the client can take into consideration when generating a Client Hello message.  The format is defined in I-D.ietf-tls-grease "encrypted_server_name" extension as follows: Select a supported cipher suite, named group, and padded_length  <ins> value.  The padded_length value SHOULD be 260 or a multiple of 16 less than Set the "suite" field to the selected cipher suite.  These selections SHOULD vary to exercise all supported configurations, but MAY be held constant for successive connections to the same server in the same session. </ins> Set the "key_share" field to a randomly-generated valid public key for the named group.


a version they do not understand.  [[NOTE: This means that the RFC will presumably have a nonzero value.]] <del> The first four (4) octets of the SHA-256 message digest RFC6234 of the ESNIKeys structure.  For the purpose of computing the checksum, the value of the "checksum" field MUST be set to zero. </del> The non-empty name of the entity trusted to update these encryption keys.  This is used to repair misconfigurations, as described in handle-server-response. query domain name's canonicalized form.  That is, if a client queries example.com, the ESNI Resource Record might be: <del> The "checksum" field provides protection against transmission errors, including those caused by intermediaries such as a DNS proxy running on a home router. </del>  Note that the length of the ESNIRecord structure MUST NOT exceed 2^16 - 1, as the RDLENGTH is only 16 bits RFC1035. shared used to derive the ESNI key. A cryptographic hash of the ESNIKeys structure from which the ESNI <del> key was obtained, i.e., from the first byte of "checksum" to the </del>  end of the structure.  This hash is computed using the hash function associated with "suite".

The checksum seems to add little value with the retry mechanism and record_digest. I think we should remove it. See for some context.
The I-D says: "recorddigest : 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." From looking at the NSS code it appears that the recorddigest input is actually the entire ESNIKeys (after base64 decode) including the version and checksum. Is that correct? IOW, does the following also produce the right value (for CF and sha256)? `
proposes removing the checksum, which should clear this up.
Closing since landed. NAME please re-open if this is still an issue!
The hash used in the extension should use the same hash inputs as the checksum. The difference here just makes using this harder.
I support the change, if that makes people feel more comfortable about having the checksum field in ESNIKeys.
I'm not opposed, but it doesn't help as much as you might think, because you need to compute the label with the cipher hash and not (necessarily) with SHA-256.
So, if you take my suggestion in (which I know NAME doesn't like, but we simply disagree about that), then you can identify the ESNI using a truncated hash that is calculated using the cipher hash because it only appears in the context of a handshake. But that just suggests that this is either not-helpful because we chose not to do anything in , or it is not necessary because we did. I'm OK closing this on that basis.
Checksum is now gone. Closing this issue. NAME thanks for filing it!
I agree that we can now and should make this simplification. The PR looks good to me.

a version they do not understand.  [[NOTE: This means that the RFC will presumably have a nonzero value.]]  The non-empty name of the entity trusted to update these encryption keys.  This is used to repair misconfigurations, as described in handle-server-response. query domain name's canonicalized form.  That is, if a client queries example.com, the ESNI Resource Record might be:  <ins> In the event that ESNIKeys is corrupt in transit or otherwise invalid, servers will initiate the retry mechanism described in server-behavior and deliver valid ESNIKeys to clients. </ins> Note that the length of the ESNIRecord structure MUST NOT exceed 2^16 - 1, as the RDLENGTH is only 16 bits RFC1035. shared used to derive the ESNI key. A cryptographic hash of the ESNIKeys structure from which the ESNI  <ins> key was obtained, i.e., from the first byte of "version" to the </ins> end of the structure.  This hash is computed using the hash function associated with "suite".


"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, <del> as shown here. </del>  3.

I believe it will be helpful to understanding this document to either add "Presentation Language" to this document or link to Presentation Language elsewhere. The TLS/1.3 document has something similar in

"SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals,  <ins> as shown here.  All TLS notation comes from RFC8446; Section 3. </ins> 3.


A random 16-octet value to be echoed by the server in the "encrypted_server_name" extension. <del> The true SNI, that is, the ServerNameList that would have been sent in the plaintext "server_name" extension. </del>  Zero padding whose length makes the serialized PaddedServerNameList struct have a length equal to

[1] URL
Extensibility failed for SNI, no point in repeating that failure. This is less complex:
Are there other ways we expect servers to select certificates? I can imagine a scenario where clients pin server leaf certificates, and hint servers to the right leaf certificate by sending the leaf SPKI hash in the SNI. Would we want to rule something like that out? The Server Name Indication (SNI) extension in TLS has a provision to provide names other than host names[1]. None have even been defined to my knowledge, but it's there. OpenSSL (and possibly others) have had a long-standing bug[2] (fixed in master) that means that different types of names will cause an error. To be clear: I live in a glass house and am not throwing stones; these things happen. However, it means that a huge fraction of the TLS deployment will not be able to accept a different name type should one ever be defined. (This issue might have been caused by the fact that the original[3] spec didn't define the extension in such a way that unknown name types could be skipped over.) Therefore we (i.e. BoringSSL, and thus Google) are proposing to give up on this and implement our parser such that the SNI extension is only allowed to contain a single host name value. (This is compatible with all known clients.) We're assuming that since this is already the de-facto reality that there will be little objection. I'm sending this mostly to record the fact so that, if someone tries to define a new name type in the future, they won't waste their time. If the community wishes to indicate a different type of name in the future, a new extension can be defined. This is already effectively the case because we wouldn't fight this level of incompatibility when there's any other option. (I think the lesson here is that protocols should have a single joint, and that it should be kept well oiled. For TLS, that means that extensions should have minimal extensionality in themselves and that we should generally rely on the main extensions mechanism for these sorts of things.) [1] URL [2] URL – note that the data pointer is not updated. [3] URL Cheers AGL Adam Langley EMAIL URL

A random 16-octet value to be echoed by the server in the "encrypted_server_name" extension.  <ins> The true SNI DNS name, that is, the HostName value that would have been sent in the plaintext "server_name" extension.  (NameType values other than "host_name" are unsupported since SNI extensibility failed SNIExtensibilityFailed). </ins> Zero padding whose length makes the serialized PaddedServerNameList struct have a length equal to


A random 16-octet value to be echoed by the server in the "encrypted_server_name" extension. <del> The true SNI, that is, the ServerNameList that would have been sent in the plaintext "server_name" extension. </del>  Zero padding whose length makes the serialized PaddedServerNameList struct have a length equal to greater.  If not, it MUST abort the connection with a "handshake_failure" alert. <del> If the ClientEncryptedSNI.record_digest value does not match the cryptographic hash of any known ESNIKeys structure, it MUST ignore the extension and proceed with the connection, with the following added behavior: </del>  It MUST include the "encrypted_server_name" extension in EncryptedExtensions message with the "response_type" field set to advertisement (misconfiguration).  Instead, servers can measure occurrences of the "esni_required" alert to detect this case. <del> If the ClientEncryptedSNI.record_digest value does match the cryptographic hash of a known ESNIKeys, the server performs the following checks: </del>  If the ClientEncryptedSNI.key_share group does not match one in the ESNIKeys.keys, it MUST abort the connection with an 7.2.  I-D.ietf-tls-sni-encryption lists several requirements for SNI encryption.  In this section, we re-iterate these requirements and assess the ESNI design against them. <del> 7.2.1. </del>  Since the SNI encryption key is derived from a (EC)DH operation between the client's ephemeral and server's semi-static ESNI key, the Hello, with a different ephemeral key share, as the terminating server will fail to decrypt and verify the ESNI value. <del> 7.2.2. </del>  This design depends upon DNS as a vehicle for semi-static public key distribution.  Server operators may partition their private keys by sending different Resource Records containing ESNIRecord and ESNIKeys values with different keys using a short TTL. <del> 7.2.3. </del>  This design requires servers to decrypt ClientHello messages with ClientEncryptedSNI extensions carrying valid digests.  Thus, it is server.  This attack is bound by the number of valid TCP connections an attacker can open. <del> 7.2.4. </del>  As more clients enable ESNI support, e.g., as normal part of Web browser functionality, with keys supplied by shared hosting ESNI extensions (see grease-extensions), which helps ensure the ecosystem handles the values correctly. <del> 7.2.5. </del>  This design is not forward secret because the server's ESNI key is static.  However, the window of exposure is bound by the key lifetime.  It is RECOMMENDED that servers rotate keys frequently. <del> 7.2.6. </del>  This design permits servers operating in Split Mode to forward connections directly to backend origin servers, thereby avoiding unnecessary MiTM attacks. <del> 7.2.7. </del>  Assuming ESNI records retrieved from DNS are validated, e.g., via DNSSEC or fetched from a trusted Recursive Resolver, spoofing a client validates the server certificate against the public name before retrying. <del> 7.2.8. </del>  This design has no impact on application layer protocol negotiation. It may affect connection routing, server certificate selection, and client certificate verification.  Thus, it is compatible with multiple protocols. <del> 7.3. </del>  Note that the backend server has no way of knowing what the SNI was, but that does not lead to additional privacy exposure because the

Addresses .
NAME can you please take a look?
Yes, adding a trial decryption is a good thing. Two suggestions: 1) in security section describe privacy attack by tracking the crypto ID. 2) also describe the attack by forcing trial decryption. Maybe add an option to publish ESNI record with NULL checksum as a way to signal acceptance of trial decryption ?
I plan to address this in a PR for . Good suggestion! I'll add that here.
NAME please let me know if the latest text works for you!
NAME NAME can you please take a look?
I think you should say that it has to be somehow externally configured.
Good suggestion! Will fix.
If each client receives a unique ESNI key from a DNS provider, it is possible to link every usage of this key to the same client. It seems feasible that online services, as well as passive observers of the network traffic, can exploit such a practice for user tracking. To enhance the privacy protections of this draft, we should describe these privacy risks in the draft. Furthermore, I recommend a clear restriction on the clients’ caching durations of ESNI keys. For example, clients MUST NOT cache ESNI keys longer than 24 hours and as privacy protection, it is RECOMMENDED to cache ESNI keys only for 10 minutes.
To avoid downgrade attacks (by simply filtering out the key DNS response), clients should cache the fact that there is/was an ESNI key significantly longer, perhaps 14 days. During these 14 days the server can authoritatively report that it no longer has a key, and it can change the key. But the client would actively look for ESNI support before falling back to plain SNI for that server. Bug comment 3 contains a proposal that can implicitly handle the case "client thinks server has ESNI, but doesn't know the current keys or if it has been turned off again server side"
I do not believe this will work. In multi-cdn scenarios, clients will sometimes just get an ESNIKeys record sometimes and no record other times and that's normal
I think noting that this can track you within the same origin is a worthwhile thing to note - it gets added to a whole bucket of things with the same property (e.g. AAAA). As its not really adding anything to that problem I'm not in favor of recommending particular cache ceilings which may or may not really address the issue anyhow..
I observe, that TLS has a tradition in providing upper limits for caching durations. I think this is a good practice as it restricts the harm of an extreme configuration. Furthermore, I see added value in recommending a best practice configuration at least for a specific application type such as browsers because it leads to a description of the trade-offs at hand and facilitates the implementation.
The document already sets the maximum TTL to the lifetime of the SNI key. It also recommends that "servers rotate keys frequently" to reduce the harm from compromised keys. So it seems that short-lived keys are good both for security and privacy. A recommended value would be useful. Otherwise "frequently" could be interpreted as months.

A random 16-octet value to be echoed by the server in the "encrypted_server_name" extension.  <ins> The true SNI DNS name, that is, the HostName value that would have been sent in the plaintext "server_name" extension.  (NameType values other than "host_name" are unsupported since SNI extensibility failed SNIExtensibilityFailed). </ins> Zero padding whose length makes the serialized PaddedServerNameList struct have a length equal to greater.  If not, it MUST abort the connection with a "handshake_failure" alert.  <ins> The ClientEncryptedSNI value is said to match a known ESNIKeys if there exists an ESNIKeys that can be used to successfully decrypt ClientEncryptedSNI.encrypted_sni.  This matching procedure should be done using one of the following two checks: Compare ClientEncryptedSNI.record_digest against cryptographic hashes of known ESNIKeys and choose the one that matches. Use trial decryption of ClientEncryptedSNI.encrypted_sni with known ESNIKeys and choose the one that succeeds. Some uses of ESNI, such as local discovery mode, may omit the ClientEncryptedSNI.record_digest since it can be used as a tracking vector.  In such cases, trial decryption should be used for matching ClientEncryptedSNI to known ESNIKeys.  Unless specified by the application using (D)TLS or externally configured on both sides, implementations MUST use the first method. If the ClientEncryptedSNI value does not match any known ESNIKeys structure, it MUST ignore the extension and proceed with the connection, with the following added behavior: </ins> It MUST include the "encrypted_server_name" extension in EncryptedExtensions message with the "response_type" field set to advertisement (misconfiguration).  Instead, servers can measure occurrences of the "esni_required" alert to detect this case.  <ins> If the ClientEncryptedSNI value does match a known ESNIKeys, the server performs the following checks: </ins> If the ClientEncryptedSNI.key_share group does not match one in the ESNIKeys.keys, it MUST abort the connection with an 7.2. <ins> Supporting optional record digests and trial decryption opens oneself up to DoS attacks.  Specifically, an adversary may send malicious ClientHello messages, i.e., those which will not decrypt with any known ESNI key, in order to force decryption.  Servers that support this feature should, for example, implement some form of rate limiting mechanism to limit the damage caused by such attacks. 7.3. ESNI protects only the SNI in transit.  Other ClientHello extensions, such as ALPN, might also reveal privacy-sensitive information to the network.  As such, it might be desirable to encrypt other extensions alongside the SNI.  However, the SNI extension is unique in that non- TLS-terminating servers or load balancers may act on its contents. Thus, using keys specifically for SNI encryption promotes key separation between client-facing servers and endpoints party to TLS connections.  Moreover, the ESNI design described herein does not preclude a mechanism for generic ClientHello extension encryption. 7.4. ESNI requires encrypted DNS to be an effective privacy protection mechanism.  However, verifying the server's identity from the Certificate message, particularly when using the X509 CertificateType, may result in additional network traffic that may reveal the server identity.  Examples of this traffic may include requests for revocation information, such as OCSP or CRL traffic, or requests for repository information, such as authorityInformationAccess.  It may also include implementation- specific traffic for additional information sources as part of verification. Implementations SHOULD avoid leaking information that may identify the server.  Even when sent over an encrypted transport, such requests may result in indirect exposure of the server's identity, such as indicating a specific CA or service being used.  To mitigate this risk, servers SHOULD deliver such information in-band when possible, such as through the use of OCSP stapling, and clients SHOULD take steps to minimize or protect such requests during certificate validation. 7.5. </ins> I-D.ietf-tls-sni-encryption lists several requirements for SNI encryption.  In this section, we re-iterate these requirements and assess the ESNI design against them.  <ins> 7.5.1. </ins> Since the SNI encryption key is derived from a (EC)DH operation between the client's ephemeral and server's semi-static ESNI key, the Hello, with a different ephemeral key share, as the terminating server will fail to decrypt and verify the ESNI value.  <ins> 7.5.2. </ins> This design depends upon DNS as a vehicle for semi-static public key distribution.  Server operators may partition their private keys by sending different Resource Records containing ESNIRecord and ESNIKeys values with different keys using a short TTL.  <ins> 7.5.3. </ins> This design requires servers to decrypt ClientHello messages with ClientEncryptedSNI extensions carrying valid digests.  Thus, it is server.  This attack is bound by the number of valid TCP connections an attacker can open.  <ins> 7.5.4. </ins> As more clients enable ESNI support, e.g., as normal part of Web browser functionality, with keys supplied by shared hosting ESNI extensions (see grease-extensions), which helps ensure the ecosystem handles the values correctly.  <ins> 7.5.5. </ins> This design is not forward secret because the server's ESNI key is static.  However, the window of exposure is bound by the key lifetime.  It is RECOMMENDED that servers rotate keys frequently.  <ins> 7.5.6. </ins> This design permits servers operating in Split Mode to forward connections directly to backend origin servers, thereby avoiding unnecessary MiTM attacks.  <ins> 7.5.7. </ins> Assuming ESNI records retrieved from DNS are validated, e.g., via DNSSEC or fetched from a trusted Recursive Resolver, spoofing a client validates the server certificate against the public name before retrying.  <ins> 7.5.8. </ins> This design has no impact on application layer protocol negotiation. It may affect connection routing, server certificate selection, and client certificate verification.  Thus, it is compatible with multiple protocols.  <ins> 7.6. </ins> Note that the backend server has no way of knowing what the SNI was, but that does not lead to additional privacy exposure because the


The ESNIKeys structure contains the following fields: The version of the structure.  For this specification, that value <del> SHALL be 0xff02.  Clients MUST ignore any ESNIKeys structure with </del>  a version they do not understand.  [[NOTE: This means that the RFC will presumably have a nonzero value.]] where ESNIContents is as specified below and Hash is the hash function associated with the HKDF instantiation.  The salt argument for HKDF-Extract is a string consisting of Hash.length bytes set to <del> zeros. </del>  The client then creates a ClientESNIInner structure: which do not depend on the (possibly updated) KeyShareClientHello, i.e,, ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, and ClientEncryptedSNI.record_digest, MUST NOT change across ClientHello <del> messages.  Moreover, ClientESNIInner.nonce and ClientESNIInner.realSNI MUST not change across ClientHello messages. Informally, the values of all unencrypted extension information, as well as the inner extension plaintext, must be consistent between the first and second ClientHello messages. </del>  5.1.3. If the decrypted value's length is different from the advertised ESNIKeys.padded_length or the padding consists of any value other than 0, then the server MUST abort the connection with an <del> illegal_parameter alert.  Otherwise, the server uses the </del>  PaddedServerNameList.sni value as if it were the "server_name" extension.  Any actual "server_name" extension is ignored, which also means the server MUST NOT send the "server_name" extension to the case, it does not make any changes to the TLS messages, but just blindly forwards them.  5.3. A server operating in Shared Mode uses PaddedServerNameList.sni as if

Since the client's ESNI key share doesn't change across CHs in response to a HRR, the same AEAD IV would be used to encrypt/decrypt two different messages. This is an attempt to fix that, while also specifying the server-side HRR behavior. (Basically, check that the ESNI contents have not changed.)
Nice catch, Would it make more sense to instead use the KeyShare as a salt in the HKDF?
Or you could include the handshake transcript up to, but not including, the ClientHello. That is the empty string before HRR< but something else after.
That is a little iffy with cookie-only HelloRetryRequests. Those don't change the ClientHello key shares list, so the client would derive the same key + nonce pair. The client would also use the same plaintext so it's fine, but it seems an unnecessarily fragility.
Agreed. I think I prefer the "new DH" version.
Thank you for the changes! LGTM.

The ESNIKeys structure contains the following fields: The version of the structure.  For this specification, that value  <ins> SHALL be 0xff03.  Clients MUST ignore any ESNIKeys structure with </ins> a version they do not understand.  [[NOTE: This means that the RFC will presumably have a nonzero value.]] where ESNIContents is as specified below and Hash is the hash function associated with the HKDF instantiation.  The salt argument for HKDF-Extract is a string consisting of Hash.length bytes set to  <ins> zeros.  For a client's first ClientHello, KeyLabel = "esni key" and IVLabel = "esni iv", whereas for a client's second ClientHello, sent in response to a HelloRetryRequest, KeyLabel = "hrr esni key" and IVLabel = "hrr esni iv".  (This label variance is done to prevent nonce re-use since the client's ESNI key share, and thus the value of Zx, does not change across ClientHello retries.) [[TODO: label swapping fixes a bug in the spec, though this may not be the best way to deal with HRR.  See https://github.com/tlswg/ draft-ietf-tls-esni/issues/121 and https://github.com/tlswg/draft- ietf-tls-esni/pull/170 for more details.]] </ins> The client then creates a ClientESNIInner structure: which do not depend on the (possibly updated) KeyShareClientHello, i.e,, ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, and ClientEncryptedSNI.record_digest, MUST NOT change across ClientHello  <ins> messages.  Moreover, ClientESNIInner MUST not change across ClientHello messages.  Informally, the values of all unencrypted extension information, as well as the inner extension plaintext, must be consistent between the first and second ClientHello messages. </ins> 5.1.3. If the decrypted value's length is different from the advertised ESNIKeys.padded_length or the padding consists of any value other than 0, then the server MUST abort the connection with an  <ins> "illegal_parameter" alert.  Otherwise, the server uses the </ins> PaddedServerNameList.sni value as if it were the "server_name" extension.  Any actual "server_name" extension is ignored, which also means the server MUST NOT send the "server_name" extension to the case, it does not make any changes to the TLS messages, but just blindly forwards them. <ins> If the ClientHello is the result of a HelloRetryRequest, servers MUST abort the connection with an "illegal_parameter" alert if any of the ClientEncryptedSNI.suite, ClientEncryptedSNI.key_share, ClientEncryptedSNI.record_digest, or decrypted ClientESNIInner values from the second ClientHello do not match that of the first ClientHello. </ins> 5.3. A server operating in Shared Mode uses PaddedServerNameList.sni as if


7.2.  ESNI requires encrypted DNS to be an effective privacy protection mechanism.  However, verifying the server's identity from the Certificate message, particularly when using the X509 SHOULD take steps to minimize or protect such requests during certificate validation. <del> 7.3. </del>  I-D.ietf-tls-sni-encryption lists several requirements for SNI encryption.  In this section, we re-iterate these requirements and assess the ESNI design against them. <del> 7.3.1. </del>  Since the SNI encryption key is derived from a (EC)DH operation between the client's ephemeral and server's semi-static ESNI key, the Hello, with a different ephemeral key share, as the terminating server will fail to decrypt and verify the ESNI value. <del> 7.3.2. </del>  This design depends upon DNS as a vehicle for semi-static public key distribution.  Server operators may partition their private keys by sending different Resource Records containing ESNIRecord and ESNIKeys values with different keys using a short TTL. <del> 7.3.3. </del>  This design requires servers to decrypt ClientHello messages with ClientEncryptedSNI extensions carrying valid digests.  Thus, it is server.  This attack is bound by the number of valid TCP connections an attacker can open. <del> 7.3.4. </del>  As more clients enable ESNI support, e.g., as normal part of Web browser functionality, with keys supplied by shared hosting ESNI extensions (see grease-extensions), which helps ensure the ecosystem handles the values correctly. <del> 7.3.5. </del>  This design is not forward secret because the server's ESNI key is static.  However, the window of exposure is bound by the key lifetime.  It is RECOMMENDED that servers rotate keys frequently. <del> 7.3.6. </del>  This design permits servers operating in Split Mode to forward connections directly to backend origin servers, thereby avoiding unnecessary MiTM attacks. <del> 7.3.7. </del>  Assuming ESNI records retrieved from DNS are validated, e.g., via DNSSEC or fetched from a trusted Recursive Resolver, spoofing a client validates the server certificate against the public name before retrying. <del> 7.3.8. </del>  This design has no impact on application layer protocol negotiation. It may affect connection routing, server certificate selection, and client certificate verification.  Thus, it is compatible with multiple protocols. <del> 7.4. </del>  Note that the backend server has no way of knowing what the SNI was, but that does not lead to additional privacy exposure because the

Addresses .
This seems to be somewhat discussed in the draft and in issues, but I fail to see the motivation behind not using the ESNI key to encrypt other extensions such as ALPN. The main concern seems to be around entities seeing the value of decrypted ALPN, but that's still better than ALPN being the clear. Another concern is a middlebox blocking this extension, but if the client decides to fail hard, blocking is better than leaking; and if a client falls back to unencrypted then the connection works regardless. If I'm missing something, can that be clarified in the draft?
I think that the goal with ALPN is to ensure that the set of values that are advertised remains small and fixed. That is, everyone can offer h2+http/1.1 and no more. This gives no advantage to a passive observer in terms of distinguishing traffic; the pattern of TLS extensions (order and so forth) gives more away.
The other point is that SNI designates the server the client wants to handshakes with. ALPN (as well as other properties of ClientHello) is a property of the handshake. Consider the split case. SNI is decrypted by the fronting server. ALPN will be a property that will be taken into consideration by the backend server.
I agree that in current usage, ALPN is only used for h2 vs http/1.1. But if we had a way to hide ALPN from censors, we could use it to run a VPN over TLS to evade censorship - I'd like to have a TLS server on port 443 that mostly serves HTTPS but can also serve VPN to select clients. In the split case, having the fronting server decrypt the ALPN and pass it decrypted to the backend server is fine - I'm mostly concerned about threats between the client and the fronting server.
Current draft is designed in a way to allow stock TLS servers to be run as a hidden server. Creating a way to pass the decrypted ALPN (or decrypted SNI) from the client-facing server to hidden server destroys that design. Generally speaking, I am not opposed to protecting more properties. OTOH, I might prefer doing things in small steps; we have the extensions field in ESNIKeys.
NAME if you want to advertise a VPN ALPN on all your connections, then that would work. I'd prefer to establish privacy-preserving usage patterns as the norm so that this is considered acceptable (and not a reason to block a connection). Advertising a willingness to use a VPN connection in addition to HTTP would be analogous to what we're doing here; the observer doesn't know what you ended up using. They could decide to block based on the possibility that you are doing something bad, but that applies to encrypted SNI in equal measure.
This sounds reasonable to me. If we build this solution in a way that allows us to encrypt ALPN later without it being distinguishable from ESNI by a MitM, then I'm happy
NAME this should be fixed by -- please reopen if that's not the case!
NAME works for me, thanks.

7.2. <ins> ESNI protects only the SNI in transit.  Other ClientHello extensions, such as ALPN, might also reveal privacy-sensitive information to the network.  As such, it might be desirable to encrypt other extensions alongside the SNI.  However, the SNI extension is unique in that non- TLS-terminating servers or load balancers may act on its contents. Thus, using keys specifically for SNI encryption promotes key separation between client-facing servers and endpoints party to TLS connections.  Moreover, the ESNI design described herein does not preclude a mechanism for generic ClientHello extension encryption. 7.3. </ins> ESNI requires encrypted DNS to be an effective privacy protection mechanism.  However, verifying the server's identity from the Certificate message, particularly when using the X509 SHOULD take steps to minimize or protect such requests during certificate validation.  <ins> 7.4. </ins> I-D.ietf-tls-sni-encryption lists several requirements for SNI encryption.  In this section, we re-iterate these requirements and assess the ESNI design against them.  <ins> 7.4.1. </ins> Since the SNI encryption key is derived from a (EC)DH operation between the client's ephemeral and server's semi-static ESNI key, the Hello, with a different ephemeral key share, as the terminating server will fail to decrypt and verify the ESNI value.  <ins> 7.4.2. </ins> This design depends upon DNS as a vehicle for semi-static public key distribution.  Server operators may partition their private keys by sending different Resource Records containing ESNIRecord and ESNIKeys values with different keys using a short TTL.  <ins> 7.4.3. </ins> This design requires servers to decrypt ClientHello messages with ClientEncryptedSNI extensions carrying valid digests.  Thus, it is server.  This attack is bound by the number of valid TCP connections an attacker can open.  <ins> 7.4.4. </ins> As more clients enable ESNI support, e.g., as normal part of Web browser functionality, with keys supplied by shared hosting ESNI extensions (see grease-extensions), which helps ensure the ecosystem handles the values correctly.  <ins> 7.4.5. </ins> This design is not forward secret because the server's ESNI key is static.  However, the window of exposure is bound by the key lifetime.  It is RECOMMENDED that servers rotate keys frequently.  <ins> 7.4.6. </ins> This design permits servers operating in Split Mode to forward connections directly to backend origin servers, thereby avoiding unnecessary MiTM attacks.  <ins> 7.4.7. </ins> Assuming ESNI records retrieved from DNS are validated, e.g., via DNSSEC or fetched from a trusted Recursive Resolver, spoofing a client validates the server certificate against the public name before retrying.  <ins> 7.4.8. </ins> This design has no impact on application layer protocol negotiation. It may affect connection routing, server certificate selection, and client certificate verification.  Thus, it is compatible with multiple protocols.  <ins> 7.5. </ins> Note that the backend server has no way of knowing what the SNI was, but that does not lead to additional privacy exposure because the


cipher suite list is orthogonal to the list of keys, so each key may be used with any cipher suite. <del> This structure is placed in the RRData section of a TXT record as encoded above.  The name of each TXT record MUST match the name composed of "_esni" and the query domain name.  That is, if a client queries example.com, the ESNI TXT name is _esni.example.com.  Servers SHOULD configure DNS such that, upon querying a domain name with ESNI support, at most one each of A, AAAA, TXT ESNI, and ALTSVC I- D.schwartz-httpbis-dns-alt-svc Resource Record is returned.  Alt-Svc records may be used to inform the client of the plaintext (fronting) SNI.  Also, servers operating in Fronting Mode SHOULD have DNS </del>  configured to return the same A (or AAAA) record for all hidden <del> servers they service. </del>  The Resource Record TTL determines the lifetime of the published ESNI keys.  Clients MUST NOT use ESNI keys beyond their published

… deal with TXT string limits.
NAME NAME please take a look.
NAME NAME updated based on your feedback -- please take a look!
The text in section 4, Publishing the SNI Encryption Key, specifies that if a client queries URL, the ESNI TXT name is URL That's fine, but suppose that the client queries "URL". The client needs to learn that "URL" is fronted by "URL" -- per PR , the client will do that by obtaining an ALT-SVC record. Should the client get the ESNI key from "URL", or from "URL" ?
NAME I think this is you.
covers this. Mostly. It might pay to observe that the client does not look up and DNS records for the fronting service, it is just the case that all servers in the anonymity set point to the same IP address. I made similar comments on .
I agree with NAME here. I didn't see the client querying URL
That means all servers that share the same IP need to publish the same key. Are we confident that there is no synch issue during key rollover?
Servers can publish multiple ESNI keys with different labels in a record. That way they can retire one key and start using another as needed. Though it might be good (necessary?) to require clients to use one of those keys.
While that is possible, I am not sure if it would be the approach that would generally be used. The issue is identical to the encryption key of the session tickets. In case of session tickets, we encrypt the ticket using one key, and send the identifier of the key along with the encrypted ticket. When we rollover the keys, we first deploy a new key to the server as well as keeping the old one alive for decryption only. And we retire the old key after certain amount of period that we become sure that it is no longer used. I'd assume that we can and will use the same approach for ESNIKeys.
PS. therefore, it is possible to have just one label for the set of keys rather than having labels for each of the keys (assuming that we can remove the "choose one at random" rule). In that approach, a server will identify the key being used by looking at the tuple. The benefit will be that you will save the space of N-1 labels assuming that you are sending N key shares. Identification of the key on the server-side might seem complicated, but I actually think that it simplifies things, because a server operator is anyways expected to deploy the entire set of keys found in ESNIKeys at the same moment.
To me it seems that this is necessary to prevent downgrade attack. Hence .
How do we prevent labels from becoming identifiers?
Labels as identifiers seem problematic in both approaches -- current and .
Would you mind elaborating why label becomes an identifier? We state in the document that the probability of identifying the hidden server is 1/N where N is the number of the hosts belonging to the same set of hidden servers. A label represents that entire set. So I do not think it is an issue.
Now that is merged, which removes the label altogether, and we've added text describing the anonymity set for hidden servers, I think this issue is covered. NAME do you agree?
The label issue is definitely covered.
The proposed DNS publication method for the key is sketched in section 4, Publishing the SNI Encryption Key. The proposed structure is This can be problematic, given the constraints on TXT records. The practical length of the record payload is at most 255 bytes. The payload content is supposed to be text, which would suggest a base64 encoding, further reducing the available payload size to 189 bytes. I would suggest encoding just one key & one ciphersuite per record using base64 encoding, and using multiple records if necessary.
FWIW RFC 4408 allows you to have multiple strings in the same TXT record to get around the limit URL This should probably be one key and all cipher suites, since suites and keys are orthogonal to each other.
We assumed a suitable encoding that would not bump into this bound. Alessandro’s suggestion above seems best.
I really have two concerns, the maximum length and the char requirement. The latter may be an harder issue. For example, can I set a TXT record to contain binary data if I use Amazon's Route 53 service?
I think we can work around the first with the concatenation suggestion. For the second, I assumed (perhaps incorrectly) any binary data was admissible. If we can’t use binary data, then we can encode it easy enough.
NAME Shall we close this?
Closed after merging PR
That's more words than I expected, but they all seem useful. LGTM.The general idea looks good, but I am a bit concerned with the concatenation + reordering process, as in theory servers may return records in random order. On the other hand, RFC 4408 has been out for a long time, so maybe that's not really a problem in practice.

cipher suite list is orthogonal to the list of keys, so each key may be used with any cipher suite.  <ins> This structure is placed in the RRData section of a TXT record as a base64-encoded string.  If this encoding exceeds the 255 octet limit of TXT strings, it must be split across multiple concatenated strings as per Section 3.1.3 of RFC4408. The name of each TXT record MUST match the name composed of _esni and the query domain name.  That is, if a client queries example.com, the ESNI TXT Resource Record might be: Servers SHOULD configure DNS such that, upon querying a domain name with ESNI support, at most one each of A, AAAA, TXT ESNI, and ALTSVC I-D.schwartz-httpbis-dns-alt-svc Resource Record is returned.  Alt- Svc records may be used to inform the client of the plaintext (fronting) SNI.  If present, clients SHOULD use its value in the SNI extension of the subsequent ClientHello. Clients obtain these records by querying DNS for hidden server domains.  Thus, servers operating in Fronting Mode SHOULD have DNS </ins> configured to return the same A (or AAAA) record for all hidden  <ins> servers they service.  This yields an anonymity set of cardinality equal to the number of hidden server domains supported by a given fronting server.  Thus, even with SNI encryption, an attacker which can enumerate the set of hidden server domains supported by a fronting server can guess the correct SNI with probability at least 1/K, where K is the size of this hidden server anonymity set.  This probability may be increased via traffic analysis or other mechanisms. </ins> The Resource Record TTL determines the lifetime of the published ESNI keys.  Clients MUST NOT use ESNI keys beyond their published


In Split Mode, the provider is _not_ the origin server for private domains.  Rather the DNS records for private domains point to the <del> provider, but the provider's server just relays the connection back to the backend server, which is the true origin server.  The provider does not have access to the plaintext of the connection.  In principle, the provider might not be the origin for any domains, but as a practical matter, it is probably the origin for a large set of innocuous domains, but is also providing protection for some private domains.  Note that the backend server can be an unmodified TLS 1.3 server. </del>  3.2. therefore allow clients to detect and recover from this situation (see esni-resolution for more details). <del> Content providers operating in Split Mode SHOULD ensure that the A and AAAA records for ESNI-enabled server names do not allow identifying the server name from the IP address.  This can for example be achieved by always returning the same records for all ESNI-enabled names, or by having the function that picks addresses from a pool not depend on the server name.  This yields an anonymity set of cardinality equal to the number of ESNI-enabled server domains supported by a given client-facing server.  Thus, even with SNI encryption, an attacker which can enumerate the set of ESNI-enabled domains supported by a client-facing server can guess the correct SNI with probability at least 1/K, where K is the size of this ESNI- enabled server anonymity set.  This probability may be increased via traffic analysis or other mechanisms. </del>  The following sections describe a DNS record format that achieve these goals. 7.5.7. <del> Assuming ESNI records retrieved from DNS are validated, e.g., via </del>  DNSSEC or fetched from a trusted Recursive Resolver, spoofing a server operating in Split Mode is not possible.  See cleartext-dns for more details regarding cleartext DNS. <del> Validating the ESNIKeys structure additionally validates the public name.  This validates any retry signals from the server because the client validates the server certificate against the public name before retrying. </del>  7.5.8.

Based on comments in Montreal, I believe that the authors no longer intend to document the partial-split configuration.

In Split Mode, the provider is _not_ the origin server for private domains.  Rather the DNS records for private domains point to the  <ins> provider, and the provider's server relays the connection back to the backend server, which is the true origin server.  The provider does not have access to the plaintext of the connection. </ins> 3.2. therefore allow clients to detect and recover from this situation (see esni-resolution for more details).  <ins> Content providers SHOULD ensure that the A and AAAA records for ESNI- enabled server names do not allow identifying the server name from the IP address.  This can for example be achieved by always returning the same records for all ESNI-enabled names, or by having the function that picks addresses from a pool not depend on the server name.  This yields an anonymity set of cardinality equal to the number of ESNI-enabled server domains supported by a given client- facing server.  Thus, even with SNI encryption, an attacker which can enumerate the set of ESNI-enabled domains supported by a client- facing server can guess the correct SNI with probability at least 1/ K, where K is the size of this ESNI-enabled server anonymity set. This probability may be increased via traffic analysis or other mechanisms. </ins> The following sections describe a DNS record format that achieve these goals. 7.5.7.  <ins> Assuming ESNI records retrieved from DNS are authenticated, e.g., via </ins> DNSSEC or fetched from a trusted Recursive Resolver, spoofing a server operating in Split Mode is not possible.  See cleartext-dns for more details regarding cleartext DNS.  <ins> Authenticating the ESNIKeys structure naturally authenticates the included public name.  This also authenticates any retry signals from the server because the client validates the server certificate against the public name before retrying. </ins> 7.5.8.


serialized ServerNameList is longer than ESNIConfig.padded_length, the client MUST NOT use the "encrypted_server_name" extension. <del> The ClientEncryptedSNI.encrypted_sni value is then computed using the usual TLS 1.3 AEAD: </del>  Where KeyShareClientHello is the "extension_data" field of the "key_share" extension in a Client Hello (Section 4.2.8 of RFC8446)). follows: Select a supported cipher suite, named group, and padded_length <del> value.  The padded_length value SHOULD be 260 or a multiple of 16 less than Set the "suite" field to the selected cipher suite.  These selections SHOULD vary to exercise all supported configurations, but MAY be held constant for successive connections to the same server in the same session. </del>  Set the "key_share" field to a randomly-generated valid public key for the named group. It MAY attempt to use another server from the DNS results, if one is provided.  6.2. A more serious problem is MITM proxies which do not support this

Addresses .
The initial commit for the padding in the spec gave the reason for the "260" figure (maximum domain + TLS struct overhead). There have been many comments mentioning slightly lower numbers (255, 253, etc). It's subtle enough that the spec should probably detail the reason.
Fixed in .
However, the TLS 1.3 definition is: In the ESNI text, it's not clear how maps to TLS 1.3's routine.
I'm not following what the problem is here: AEAD-Encrypt is a function that takes four arguments, the second of which is a nonce. In TLS 1.3 record encryption, this nonce value is set as described in S 5.3. In ESNI, it is derived via HKDF in the fashion described in S 5.1.1..
I don't doubt that there is a right answer. It wasn't clear to me whether I should mix in a sequence number to (maybe zero?). Otherwise, it made sense. Although it might be quite a bit clearer to define each argument in terms of the TLS 1.3 definition.
In other words, the second argument to in TLS 1.3 is "derived from the sequence number and the clientwriteiv or serverwriteiv". As I read, it wasn't clear to me whether I should do nothing to the existing value, or mix in zero or something. This might be really obvious in some implementations, but it wasn't in the one I'm working on.
You don't do either. The function takes a nonce argument. In TLS 1.3, that argument is computed one way, and in ESNI it is computed another way. These are positional functions and the names in scope at the call site are irrelevant. I think your proposed change would confuse rather than illuminating. I agree with you that adding test vectors would be useful, and if you want to supply some -- though I suggest you wait until the next version -- in a PR, that would be great.
OK, maybe my proposed solution is not the best, but I don't think the status quo is great. I get the point of "These are positional functions and the names in scope at the call site are irrelevant", but that's actually not quite true in TLS, afaik. The names tend to imply input/output treatment. For example, things called "*iv" are inputs to in TLS 1.3. In some implementations, the input "Initialization Vector (IV)" [RFC4106] might be a different static type from the in the TLS 1.3 definition. That's why I got confused. maybe adjust like so: and then:
I don't see how this argues your point. Again, the names are irrelevant. I don't really see how the implementation types are relevant here. In any case, given the state of the draft and the reasonable likelihood this will change, I think this decision is well within editor discretion.
The TLS spec and the ESNI spec do not have a type system. They do have a serialization spec, and I am not arguing about that. I do think the names could be clearer without inventing a type system. Well, I think this perspective leads to reverse engineering C/C++ implementations, rather than precisely specifying the inputs to functions like AEAD-Encrypt.
Maybe it could say something like "The ClientEncryptedSNI.encrypted_sni value is then computed using the usual TLS 1.3 AEAD, but note that the second argument, 'iv', is not combined with a sequence number:" The reason I found this confusing was that TLS 1.3 doesn't define the "nonce" argument symbolically, but the ESNI draft does define "iv" symbolically. That's fine, but I then had to plumb a new kind of value into the library to allow for this IV, and I wasn't sure if it was right.
I agree with NAME that AEAD-Encrypt is a 4 positional argument function and it shouldn't matter what they're called in the ESNI spec compared to what they're called in RFC 8446. However, from re-reading RFC 8446, I don't see a good definition of the AEAD-Encrypt function. Perhaps it would be better to describe the encryption using the Authenticated Encryption interface described in ?
"AEAD-Encrypt is a 4 positional argument function and it shouldn't matter what they're called in the ESNI spec compared to what they're called in RFC 8446." This is sort of true, but I noticed that the specs use the name of the second argument to imply its input treatment: IV vs nonce. In that light, I suppose my suggested text might sound redundant, but I think the current document is too concise.
Fixed in .
There is an unstated constraint on deployments. All servers in the same anonymity set need to have the same cryptographic configuration. This means that they choose the same key exchange groups/cipher/etc.. when presented with the same ClientHello. Concretely, servers need to produce the same profile for the ServerHello, because the ServerHello is not encrypted and the form of a ServerHello could be used to split the anonymity set if different servers make different choices.
Discussion in the room in Montreal suggested that this would not be a requirement, but more of the form of an observation and suggestion. That is, the document would note that if cryptographic configuration is not consistent, the anonymity set fractures into as many sets as there are configurations. Then it will recommend (but not require) that uniformity is desirable.

serialized ServerNameList is longer than ESNIConfig.padded_length, the client MUST NOT use the "encrypted_server_name" extension.  <ins> The ClientEncryptedSNI.encrypted_sni value is then computed using AEAD-Encrypt (RFC5116; Section 2.1) with the AEAD corresponding to ClientEncryptedSNI.suite as follows: </ins> Where KeyShareClientHello is the "extension_data" field of the "key_share" extension in a Client Hello (Section 4.2.8 of RFC8446)). follows: Select a supported cipher suite, named group, and padded_length  <ins> value.  The padded_length value SHOULD be 260 (sum of the maximum DNS name length and TLS encoding overhead) or a multiple of 16 less than 260.  Set the "suite" field to the selected cipher suite.  These selections SHOULD vary to exercise all supported configurations, but MAY be held constant for successive connections to the same server in the same session. </ins> Set the "key_share" field to a randomly-generated valid public key for the named group. It MAY attempt to use another server from the DNS results, if one is provided. <ins> Client-facing servers with non-uniform cryptographic configurations across backend origin servers segment the ESNI anonymity set based on these configurations.  For example, if a client-facing server hosts k backend origin servers, and exactly one of those backend origin servers supports a different set of cryptographic algorithms than the other (k - 1) servers, it may be possible to identify this single server based on the contents of the ServerHello as this message is not encrypted. </ins> 6.2. A more serious problem is MITM proxies which do not support this


padded_length is greater than 260. A list of extensions that the client can take into consideration <del> when generating a Client Hello message.  The format is defined in RFC8446; Section 4.2.  The purpose of the field is to provide room for additional features in the future.  An extension may be tagged as mandatory by using an extension type codepoint with the high order bit set to 1.  A client which receives a mandatory extension they do not understand must reject the ESNIConfig content. </del>  Clients MUST parse the extension list and check for unsupported mandatory extensions.  If an unsupported mandatory extension is

Followup on . Looks like ESNIConfig is the only ESNI structure that has extensions, now that we've delegated the key delivery to HTTPSSVC. Should I avoid reflowing the text?
states: same type in a given extension block. The ESNI draft should probably explicitly restate this for both and . I'd be happy to make a PR if need be. Thanks!
NAME if you could propose text that takes the new ESNIConfig and HTTPSSVC change into account, that'd be great!
Fixed by .

padded_length is greater than 260. A list of extensions that the client can take into consideration  <ins> when generating a Client Hello message.  The purpose of the field is to provide room for additional features in the future.  The format is defined in RFC8446; Section 4.2.  The same interpretation rules apply: extensions MAY appear in any order, but there MUST NOT be more than one extension of the same type in the extensions block.  An extension may be tagged as mandatory by using an extension type codepoint with the high order bit set to 1.  A client which receives a mandatory extension they do not understand must reject the ESNIConfig content. </ins> Clients MUST parse the extension list and check for unsupported mandatory extensions.  If an unsupported mandatory extension is