suite it will use for encryption.  It MUST NOT choose a cipher suite not advertised by the configuration. <del> Next, the client constructs the ClientHelloOuter message just as it </del>  does a standard ClientHello, with the exception of the following rules: <del> It MUST offer to negotiate TLS 1.3 or above. It MUST include an "encrypted_client_hello" extension with a payload constructed as described below. </del>  <del> The value of "ECHConfig.public_name" MUST be placed in the "server_name" extension. </del>  <del> It MUST NOT include the "pre_shared_key" extension.  (See flow- clienthello-malleability.) </del>  <del> The client then constructs the ClientHelloInner message just as it </del>  does a standard ClientHello, with the exception of the following rules: <del> It MUST NOT offer to negotiate TLS 1.2 or below.  Note this is necessary to ensure the backend server does not negotiate a TLS version that is incompatible with ECH. It MUST NOT offer to resume any session for TLS 1.2 and below. </del>  <del> It MAY offer any other extension in the ClientHelloOuter except those that have been incorporated into the ClientHelloInner as described in outer-extensions. </del>  <del> It MAY copy any other field from the ClientHelloOuter except ClientHelloOuter.random.  Instead, It MUST generate a fresh ClientHelloInner.random using a secure random number generator. </del>  (See flow-client-reaction.) <del> It SHOULD contain TLS padding RFC7685 as described in padding. </del> If implementing TLS 1.3's compatibility mode (see Appendix D.4 of RFC8446), it MUST copy the legacy_session_id field from <del> ClientHelloOuter.  This allows the server to echo the correct </del>  session ID when ECH is negotiated.  The client might duplicate non-sensitive extensions in both messages. However, implementations need to take care to ensure that sensitive extensions are not offered in the ClientHelloOuter.  [[OPEN ISSUE: We

There are two ClientHelloInners, the actual one used in the handshake, and the encoded one with outerextensions substituted in. Both are described as ClientHelloInner, but this makes it slightly ambiguous which goes into, say, the handshake transcript. (It's late now, so I'll leave this as an issue without a PR. If we don't end up resolving this separately, I'll probably fix this as part of . If we decide to implicitly copy over legacysession_id, the encryption payload becomes less and less defensibly an actual ClientHelloInner.)
In my own implementation, I've been referring to the plaintext payload as CompressedClientHelloInner. Which is terrible, but unambiguous.
Works for me. I was thinking EncodedClientHelloInner because it's shorter and still works even if you choose not to compress anything. (A no-op encoding is still an encoding.)
+1 to EncodedClientHelloInner, given that compression is optional. NAME if you have time, could you whip up a PR?
I noticed this while drafting a PR for . We're a little inconsistent about whether the ClientHelloInner or ClientHelloOuter is constructed first. Section 4 says inner before outer: Section 5.1 implies inner before outer: But section 6.1 says outer before inner: I think inner before outer makes more sense. You certainly can't finish the outer one before you've computed the inner one. (Of course, an implementation can pick whatever order is most convenient, but I think the spec should be consistent with itself.)

suite it will use for encryption.  It MUST NOT choose a cipher suite not advertised by the configuration.  <ins> Next, the client constructs the ClientHelloInner message just as it </ins> does a standard ClientHello, with the exception of the following rules:  <ins> It MUST NOT offer to negotiate TLS 1.2 or below.  Note this is necessary to ensure the backend server does not negotiate a TLS version that is incompatible with ECH. </ins>  <ins> It MUST NOT offer to resume any session for TLS 1.2 and below. </ins>  <ins> It SHOULD contain TLS padding RFC7685 as described in padding. </ins>  <ins> The client then constructs the ClientHelloOuter message just as it </ins> does a standard ClientHello, with the exception of the following rules:  <ins> It MUST offer to negotiate TLS 1.3 or above. </ins>  <ins> Any extensions compressed as described in outer-extensions must match the ClientHelloInner.  [[OPEN ISSUE: When #331 and compression ordering is resolved, be a bit more precise here.]] </ins>  <ins> It MAY copy any other field from the ClientHelloInner except ClientHelloInner.random.  Instead, It MUST generate a fresh ClientHelloOuter.random using a secure random number generator. </ins> (See flow-client-reaction.)  If implementing TLS 1.3's compatibility mode (see Appendix D.4 of RFC8446), it MUST copy the legacy_session_id field from  <ins> ClientHelloInner.  This allows the server to echo the correct </ins> session ID when ECH is negotiated. <ins> It MUST include an "encrypted_client_hello" extension with a payload constructed as described below. The value of "ECHConfig.public_name" MUST be placed in the "server_name" extension. It MUST NOT include the "pre_shared_key" extension.  (See flow- clienthello-malleability.) </ins> The client might duplicate non-sensitive extensions in both messages. However, implementations need to take care to ensure that sensitive extensions are not offered in the ClientHelloOuter.  [[OPEN ISSUE: We


If sending a second ClientHello in response to a HelloRetryRequest, the client copies the entire "encrypted_client_hello" extension from <del> the first ClientHello. </del>  If the server sends an "encrypted_client_hello" extension in either HelloRetryRequest or EncryptedExtensions, the client MUST check the

But that is just how it is. We get to choose between that leakage and a known large amount of bustage.
This solution admits a straightforward, active distinguisher: just intercept CH1, respond with a fake HRR, and look at CH2. It's true that we "give up" on making HRR not stick out in . However, one of the design goals there is to prevent active attacks that trigger the HRR code path when it otherwise would not have happened. What we give up on is ensuring "don't stick out" when HRR is inevitable for the given client and server.
Ah, are you saying that this conflicts with (and thus would have to be removed if is merged)?
I believe resolves the same "OPEN ISSUE", yes.
I just noticed this as I was pondering our various HRR issues. RFC8446, section 4.1.2 says: URL The "and present in the HelloRetryRequest" portion is fun. In RFC8446 as written, we're not allowed to change the extension on the second ClientHello unless the server sent in HelloRetryRequest, which it doesn't. With the protocol as-is, it seems we'll at least need some text to deal with the contradiction. The impact is practice is thankfully limited. If the servers does not enforce consistency between the two ClientHellos, it doesn't matter. (They're not required to, but they're not explicitly forbidden from it either, and a stateless server may need to enforce some minimum consistency to avoid getting into a broken state.) If a server does, ECH's behavior on HRR will break it. Such a server is supposed to handshake with ClientHelloOuter, so it just affects the retry flow. That's maybe okay, but mildly annoying. Administrators using server software that checks need to know to first upgrade to a version that doesn't check before trying to deploy ECH. We can also add an ECH extension to HRR. Then, on ECH-reject + HRR, the server perhaps wouldn't send the extension and the client would be required to replay the extension. This is a waste in many ways, but would work. This would break don't stick out, but some threat models, don't stick out with HRR is hopeless anyway. (See URL) It would also be weirdly asymmetric between ECH and SH. That said, this constraint is also pretty obnoxious. For instance, currently adds a new padding extension codepoint, because the old one isn't defined for other messages. However, the RFC8446 allowance only works for the existing padding code point, so you don't want to send any other code points in ClientHello, lest the server force you to keep it unchanged in ClientHello2. So maybe we should confirm no servers did the fully strict check and undo that constraint? (Although, for , I personally favor the padding message strategy anyway.)
NAME points out the Go implementation does check CH1 and CH2 consistency. Fortunately, it only checks known extensions, so it's still compatible with the ECH draft. URL Checking only know extensions is basically saying we should strike "and present in the HelloRetryRequest" in rfc8446bis and make sure everyone knows not to check this.
I don't think we can just strike this text because the point of that text was that you couldn't like change your KeyShares if the HRR didn't tell you to. But I agree we can sharpen this in some sensible way.
I figured that case was covered by "defined in the future", which I'm not proposing we delete. keyshare isn't defined in the future, so it falls under existing rules. The existing rules (bullet points over that one) only let you change keyshare "[i]f a "key_share" extension was supplied in the HelloRetryRequest". But perhaps that's a little roundabout. The rules I'm thinking of are (changes emphasized): Each extension gets to define how it reacts to HRR. It typically is sensitive the corresponding HRR extension, but doesn't have to be. RFC8446(bis) defines the rules for all existing extensions. Future extensions define their own rules. (And probably if they don't say anything, we assume they don't get to change.) As a server, you can make assumptions based on the rules for extensions you know about. You have to tolerate random changes in extensions you don't know about, because you don't know their rules.* I'm running a probe on a bunch of servers to see how they react to changes in cipher suites, curves, and a random extension. It seems most don't notice. Some (I'm guessing Go) notice cipher suites and curves. None notice a random extension. That suggests the change will be compatible.
I spoke too soon. LibreSSL breaks if you change an extension they don't recognize. :-(
So draft-09 isn't tied up with this, I've uploaded URL as a bandaid for the potential compatibility issue. (I say potential because it's only a problem if the server checks unknown extensions and has different enough key share preferences from the client that it needs HRR. HRR is pretty rare, so it may not actually be an issue. For Chrome, at least, I don't think the particular servers I found actually trigger HRR. But it is still a risk for clients or servers with different configurations.)

If sending a second ClientHello in response to a HelloRetryRequest, the client copies the entire "encrypted_client_hello" extension from  <ins> the first ClientHello.  The identical value will reveal to an observer that the value of "encrypted_client_hello" was fake, but this only occurs if there is a HelloRetryRequest. </ins> If the server sends an "encrypted_client_hello" extension in either HelloRetryRequest or EncryptedExtensions, the client MUST check the


extension.  It MUST NOT save the "retry_config" value in EncryptedExtensions. <del> [[OPEN ISSUE: Depending on what we do for issue#450, it may be appropriate to change the client behavior if the HRR extension is present.]] </del> Offering a GREASE extension is not considered offering an encrypted ClientHello for purposes of requirements in real-ech.  In particular, the client MAY offer to resume sessions established without ECH.

extension.  It MUST NOT save the "retry_config" value in EncryptedExtensions.  Offering a GREASE extension is not considered offering an encrypted ClientHello for purposes of requirements in real-ech.  In particular, the client MAY offer to resume sessions established without ECH.


The backend server begins by generating a message ServerHelloECHConf, which is identical in content to a ServerHello message with the exception that ServerHelloECHConf.random is equal to 24 random bytes <del> followed by 8 zero bytes.  It then computes a string where Derive-Secret and Handshake Secret are as specified in RFC8446, Section 7.1, and ClientHelloInner...ServerHelloECHConf refers to the sequence of handshake messages beginning with the first ClientHello and ending with ServerHelloECHConf.  Finally, the backend server constructs its ServerHello message so that it is equal to </del>  ServerHelloECHConf but with the last 8 bytes of ServerHello.random <del> set to the first 8 bytes of accept_confirmation. </del>  The backend server MUST NOT perform this operation if it negotiated TLS 1.2 or below.  Note that doing so would overwrite the downgrade

We previously derived the acceptance signal from the handshake secret. This meant that clients which used the wrong ECHConfig might need to process ServerHello extensions twice before computing the signal, which can be problematic for some libraries. Given that the signal's secrecy is entirely dependent on URL, we can relax the signal computation and base it on the transcript alone, which includes URL, rather than a secret derived from that transcript. cc NAME NAME NAME
Yep, good change. Thanks, S.
Encoding the "ECH worked" signal in the URL lower octets is, at best, ugly. It also arguably causes violation of internal API designs in at least the OpenSSL code. And I'm not sure if there might be some interaction between that and ticket handling (just from the look of some code I've yet to understand really.) Do we really need such a hacky solution? Given the ECH sticks out in the CH, we could just define a non-encrypted extension in the SH to include the confirmation value maybe (though even that is pretty hacky).
I have some sympathy for this, but the point of this signal design was to make it difficult to distinguish GREASE from non-GREASE ECH.
Could you elaborate on the concern with ticket handling? I'm not sure I see how tickets would relate to this.
Sorry for being slow - should get to looking again at that bit of code in a few days. S
Just to synchronize the discussion across list/GitHub a bit, this was discussed a bit in URL I agree with NAME now that there's some fiddly interactions from two ClientHellos and ServerHello. I sketched out a possible change sketched out in URL We could compute ClientHelloInner...ServerHelloECHConf as in the draft right now. But then rather than feed that into the handshake secret computation, just rely on that transcript containing a secret URL and computing F(transcript). (Hash it down, KDF it with zero secret, whatever.) One observation is that, while this relies oddly on a secret URL, the existing construction does too. An attacker constructing a ServerHello gets to pick ServerHello.keyshare and, with knowledge of ClientHello.keyshare, compute the resulting shared secret.
One further observation here is that if the client uses the same shares for CHInner and CHOuter, the double key derivation piece doesn't really need to apply.
For my own reference, I just wanted to flag something that we've discussed on the list: the current acceptance signal interacts with PSK in a way that could easily cause a bug in an implementation that hasn't carefully vetted this interaction.
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 .
Seems fine to me. Christian Huitema wrote: computation per se. Actually doing trial decryption with the secret requires reaching down into the record layer. This is especially onerous for QUIC, where the record layer is offloaded to another protocol (often outside the TLS library). I think going back to full trial decryption would still considerably increase the cost of implementing ECH over the current draft. That said, I do agree that even the first part seems more onerous than expected and it's worth reconsidering things. We switched using just the randoms to the full handshake secret to mitigate some issues. Perhaps there's an intermediate point that still mitigates those issues but avoids the expensive part of the secret computation? What if we kept the ClientHelloInner...ServerHelloECHConf transcript as in the current draft, but derived the signal exclusively from that? (Or from the client random and that transcript, though the transcript includes the client random anyway.) We'll still bind in the ServerHello extensions, and it still includes the encrypted inner ClientHello random, as in the randoms formulation. It doesn't do the job as clearly as the handshake secret did, but maybe it'll work? Implementation-wise, this variant would not require actually processing the ServerHello extensions. David
Hi all, I raised a github issue [1] related to (but different from) this but would prefer a discussion via email if that's ok. Depending how this goes, I can create a new GH issue I guess. ECH draft-09 (and -10) requires the client to verify that the server has processed ECH by comparing 8 octets in the URL with a value one can only know if you know the inner CH octets and (pretty much all) the rest of the h/s so far. That seemingly removes the need for the client to maybe decrypt twice (once based on inner CH, once based on outer) to see what works. That can be implemented ok for the nominal case. As far as I can see that was the result of github issue [2] back in Aug/Sep 2020. But in error cases that seems to require the client to possibly process the same ServerHello extensions twice, which could have side effects, is generally ickky and I think shows that this aspect of the design maybe needs a change. That's not much different from trial decryption really. In my current, (and still horrible;-), OpenSSL code the minimal effect is memory leaks for error cases that are tricky to handle, but can be handled, although at the expense of probably making the code even more brittle. (Note: I'm neither defending nor attacking the way OpenSSL handles extensions here:-) The specific problem is one needs the handshake secret to calculate the 8 octets one expects in the URL, but generating the handshake secret typically involves a key share ServerHello extension and might in future involve some PQC stuff, so I think we can't say for sure which subset of extensions are needed for the calculation. And if the first time doesn't give the right answer (e.g. if the client used the wrong ECHConfig) then you gotta process the ServerHello incl. its extensions a 2nd time. I think the requirement we ought try meet here is that any confirmation value needs to be something the client can calculate using values known before the SH is rx'd plus the ServerHello as a (mostly) unprocessed buffer. That could be e.g. some hash of the encoded inner CH, ECHConfig and the ServerHello maybe. Some of those issues were discussed in [2] already and in an interim meeting I missed but I reckon it might be worthwhile thinking again. Thanks, S. [1] URL [2] URL

The backend server begins by generating a message ServerHelloECHConf, which is identical in content to a ServerHello message with the exception that ServerHelloECHConf.random is equal to 24 random bytes  <ins> followed by 8 zero bytes.  It then computes an 8-byte string where HKDF-Expand-Label and Transcript-Hash are as defined in RFC8446, Section 7.1, "0" indicates a string of Hash.length bytes set to zero, and ClientHelloInner...ServerHelloECHConf refers to the sequence of handshake messages beginning with the first ClientHelloInner and ending with ServerHelloECHConf.  (Note that ClientHelloInner and ServerHelloECHConf messages replace the ClientHello and ServerHello messages in the transcript hash sequence as specified in Section 4.1.1 of RFC8446.  Finally, the backend server constructs its ServerHello message so that it is equal to </ins> ServerHelloECHConf but with the last 8 bytes of ServerHello.random  <ins> set to "accept_confirmation". </ins> The backend server MUST NOT perform this operation if it negotiated TLS 1.2 or below.  Note that doing so would overwrite the downgrade


3.2. <del> ECH allows the client to encrypt sensitive ClientHello extensions, e.g., SNI, ALPN, etc., under the public key of the client-facing server.  This requires the client-facing server to publish the public key and metadata it uses for ECH for all the domains for which it serves directly or indirectly (via Split Mode).  This document defines the format of the ECH encryption public key and metadata, referred to as an ECH configuration, and delegates DNS publication details to HTTPS-RR, though other delivery mechanisms are possible. In particular, if some of the clients of a private server are applications rather than Web browsers, those applications might have the public key and metadata preconfigured. When a client wants to establish a TLS session with the backend server, it constructs its ClientHello as indicated in real-ech.  We will refer to this as the ClientHelloInner message.  The client encrypts this message using the public key of the ECH configuration. It then constructs a new ClientHello, the ClientHelloOuter, with innocuous values for sensitive extensions, e.g., SNI, ALPN, etc., and with an "encrypted_client_hello" extension, which this document defines (encrypted-client-hello).  The extension's payload carries the encrypted ClientHelloInner and specifies the ECH configuration used for encryption.  Finally, it sends ClientHelloOuter to the server. Upon receiving the ClientHelloOuter, a TLS server takes one of the following actions: If it does not support ECH, it ignores the "encrypted_client_hello" extension and proceeds with the handshake as usual, per RFC8446, Section 4.1.2. If it is a client-facing server for the ECH protocol, but cannot decrypt the extension, then it terminates the handshake using the ClientHelloOuter.  This is referred to as "ECH rejection".  When ECH is rejected, the client-facing server sends an acceptable ECH configuration in its EncryptedExtensions message. If it supports ECH and decrypts the extension, it forwards the ClientHelloInner to the backend server, who terminates the connection.  This is referred to as "ECH acceptance". </del>  Upon receiving the server's response, the client determines whether <del> or not ECH was accepted and proceeds with the handshake accordingly. (See client-behavior for details.) </del>  The primary goal of ECH is to ensure that connections to servers in the same anonymity set are indistinguishable from one another.

The overview was a bit long, and slightly inaccurate. The ClientHelloInner is encrypted after (most) of the ClientHelloOuter is constructed. I've also merged the ECH-naive server case with the ECH rejection case. This is more consistent with the client text, and most other TLS extensions, where we do not distinguish between reasons why the extension could not be negotiated. I've also generally tightened up the wording to make it shorter. As part of that, I'm trimmed the repeated list of sensitive ClientHello extensions. ECH itself is (mostly) agnostic to which extensions you believe are sensitive, and we already gave examples in the introduction.

3.2.  <ins> A client-facing server enables ECH by publishing an ECH configuration, which is an encryption public key and associated metadata.  The server must publish this for all the domains it serves via Shared or Split Mode.  This document defines the ECH configuration's format, but delegates DNS publication details to HTTPS-RR.  Other delivery mechanisms are also possible.  For example, the client may have the ECH configuration preconfigured. When a client wants to establish a TLS session with some backend server, it constructs a private ClientHello, referred to as the ClientHelloInner.  The client then constructs a public ClientHello, referred to as the ClientHelloOuter.  The ClientHelloOuter contains innocuous values for sensitive extensions and an "encrypted_client_hello" extension (encrypted-client-hello), which carries the encrypted ClientHelloInner.  Finally, the client sends ClientHelloOuter to the server. The server takes one of the following actions: If it does not support ECH or cannot decrypt the extension, it completes the handshake with ClientHelloOuter.  This is referred to as rejecting ECH. If it successfully decrypts the extension, it forwards the ClientHelloInner to the backend server, which completes the handshake.  This is referred to as accepting ECH. </ins> Upon receiving the server's response, the client determines whether  <ins> or not ECH was accepted (handle-server-response) and proceeds with the handshake accordingly.  When ECH is rejected, the resulting connection is not usable by the client for application data. Instead, ECH rejection allows the client to retry with up-to-date configuration (rejected-ech). </ins> The primary goal of ECH is to ensure that connections to servers in the same anonymity set are indistinguishable from one another.


extension and MUST NOT use the retry keys. Offering a GREASE extension is not considered offering an encrypted <del> ClientHello for purposes of requirements in client-behavior.  In particular, the client MAY offer to resume sessions established without ECH. </del>  7.

extension and MUST NOT use the retry keys. Offering a GREASE extension is not considered offering an encrypted  <ins> ClientHello for purposes of requirements in real-ech.  In particular, the client MAY offer to resume sessions established without ECH. </ins> 7.


First four (4) octets of the SHA-256 message digest RFC6234 of the ESNIKeys structure starting from the first octet of "keys" to the <del> end of the stucture. </del>  The list of keys which can be used by the client to encrypt the SNI.  Every key being listed MUST belong to a different group. The length to pad the ServerNameList value to prior to encryption. This value SHOULD be set to the largest ServerNameList the server <del> expects to support rounded up the nearest multiple of 16. [[OPEN ISSUE: An alternative to padding is to instead send a hash of the server name.  This would be fixed-length, but have the disadvantage that the server has to retain a table of all the server names it supports, and will not work if the mapping between the client-facing server and hidden server uses wildcards.]] </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

Current text says: the "encryptedservername" extension. However, I am not sure if this is the desired behavior. I would rather suggest encrypting even when the hostname exceeds the padded_length. Having some protection is better than none. The issue is that in certain deployments it is impossible to guess what the maximum length of the hostname will be. Consider . It uses a wildcard certificate. Anybody can add a new hostname of any length by creating a new Github account (it might be true that Github some limitation on the length, but that does not necessarily mean that Github shares the maximum length information with the fronting CDN, assuming that it uses a CDN).
I have filed that fixes another issue (it's just a clarification of an open issue) related to wildcard delegation.
Technically, it is possible to guess the maximum length of the hostname, as that maximum textual representation length is defined as 253 bytes per RFC 1034.
Yes. So the question is if a CDN that has a wildcard mapping needs to set to 253 (since current text is a MUST NOT for sending a server name longer than the paddedlength), or if we should introduce a different rule.
How about something like: padded_length : The length to pad the ServerNameList value to prior to encryption. This value SHOULD be set to the largest ServerNameList the fronting server expects to support rounded up the nearest multiple of 16. If the fronting server supports wildcard names, it SHOULD set this value to 256.
NAME Thank you for the suggestion. I was feeling uneasy (and am still feeling a bit) about requiring the client to send an ESNI extension as large as ~300 bytes, assuming that CDN's would have at least one wildcard mappings. But it's about the first packet sent from the client, and we typically have enough room even when 0-RTT data is involved. So I think that we can live with that.
To be
Thank you for working on this! LGTM aside from the two comments shown below.Sorry, I missed the padding thing, so you'll need to adjust

First four (4) octets of the SHA-256 message digest RFC6234 of the ESNIKeys structure starting from the first octet of "keys" to the  <ins> end of the structure. </ins> The list of keys which can be used by the client to encrypt the SNI.  Every key being listed MUST belong to a different group. The length to pad the ServerNameList value to prior to encryption. This value SHOULD be set to the largest ServerNameList the server  <ins> expects to support rounded up the nearest multiple of 16.  If the server supports wildcard names, it SHOULD set this value to 256. </ins> 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


5.2. <del> Upon receiving an "encrypted_server_name" extension, the server MUST first perform the following checks: </del>  If it is unable to negotiate TLS 1.3 or greater, it MUST abort the connection with a "handshake_failure" alert.

5.2.  <ins> Upon receiving an "encrypted_server_name" extension, the client- facing server MUST first perform the following checks: </ins> If it is unable to negotiate TLS 1.3 or greater, it MUST abort the connection with a "handshake_failure" alert.


expansion) the server MAY abort the connection with an "illegal_parameter" alert without attempting to decrypt. <del> Assuming that these checks succeed, the server then computes K_sni and decrypts the ServerName value.  If decryption fails, the server MUST abort the connection with a "decrypt_error" alert. </del>  If the decrypted value's length is different from the advertised padding_length or the padding consists of any value other than 0,

expansion) the server MAY abort the connection with an "illegal_parameter" alert without attempting to decrypt.  <ins> Assuming these checks succeed, the server then computes K_sni and decrypts the ServerName value.  If decryption fails, the server MUST abort the connection with a "decrypt_error" alert. </ins> If the decrypted value's length is different from the advertised padding_length or the padding consists of any value other than 0,


5.3.  The Hidden Server ignores both the "encrypted_server_name" and the "server_name" (if any) and completes the handshake as usual.  If in Shared Mode, the server will still know the true SNI, and can use it for certificate selection.  In Split Mode, it may not know the true <del> SNI and so will generally be configured to use a single certificate </del>  communicating-sni describes a mechanism for communicating the true <del> SNI to the hidden server.  [[OPEN ISSUE: Do we want "encrypted_server_name" in EE?  It's clearer communication, but gets in the way of stock servers.]] </del>  6.

5.3. <ins> A server operating in Shared Mode uses PaddedServerNameList.sni as if it were the "server_name" extension to finish the handshake.  It SHOULD pad the Certificate message, via padding at the record layer, such that its length equals the size of the largest possible Certificate (message) covered by the same ESNI key. 5.4. </ins> The Hidden Server ignores both the "encrypted_server_name" and the "server_name" (if any) and completes the handshake as usual.  If in Shared Mode, the server will still know the true SNI, and can use it for certificate selection.  In Split Mode, it may not know the true  <ins> SNI and so will generally be configured to use a single certificate. </ins> communicating-sni describes a mechanism for communicating the true  <ins> SNI to the hidden server. Similar to the Shared Mode behavior, the hidden server in Split Mode SHOULD pad the Certificate message, via padding at the record layer such that its length equals the size of the largest possible Certificate (message) covered by the same ESNI key. [[OPEN ISSUE: Do we want "encrypted_server_name" in EE?  It's clearer communication, but gets in the way of stock servers.]] </ins> 6.


Records are signed via a server private key, ESNIKeys have no authenticity or provenance information.  This means that any attacker which can inject DNS responses or poison DNS caches, which is a <del> common scenario in client access netowrks, can supply clients with </del>  fake ESNIKeys (so that the client encrypts SNI to them) or strip the ESNIKeys from the response.  However, in the face of an attacker that controls DNS, no SNI encryption scheme can work because the attacker

Records are signed via a server private key, ESNIKeys have no authenticity or provenance information.  This means that any attacker which can inject DNS responses or poison DNS caches, which is a  <ins> common scenario in client access networks, can supply clients with </ins> fake ESNIKeys (so that the client encrypts SNI to them) or strip the ESNIKeys from the response.  However, in the face of an attacker that controls DNS, no SNI encryption scheme can work because the attacker


for the "encrypted_client_hello" extension.  Clients MUST ignore any "ECHConfig" structure with a version they do not support. <del> The length, in bytes, of the next field. </del>  An opaque byte string whose contents depend on the version.  For this specification, the contents are an "ECHConfigContents"

The goal here is really to provide more clarify about cardinality, if there's a better way or place to do that, that'd be fine.
I don't believe this is necessary. This idiom is well understood in TLS and this just appears to be excess verbiage.
Hiya, (As with all these PRs, I'm ok if they're not accepted...) For me, that is better than the original, but I do think we ought state the expected cardinality that implementers need to handle somewhere. I reckon it's better to not assume implementers are very familiar with SVCB as for libraries at least, the DNS stuff happens elsewhere. They will have to figure that out eventually, but better to say it somewhere explicitly I think, or we may face some important code base that doesn't handle >1 public key when it ought. Cheers, S.

for the "encrypted_client_hello" extension.  Clients MUST ignore any "ECHConfig" structure with a version they do not support.  <ins> The length, in bytes, of the next field.  This length field allows implementations to skip over the elements in such a list where they cannot parse the specific version of ECHConfig. </ins> An opaque byte string whose contents depend on the version.  For this specification, the contents are an "ECHConfigContents"


ECHClientHello.config_id since it can be used as a tracking vector. In such cases, the second method should be used for matching the ECHClientHello to a known ECHConfig.  See optional-configs.  Unless <del> specified by the application using (D)TLS or externally configured, implementations MUST use the first method. </del>  The server then iterates over the candidate ECHConfig values, attempting to decrypt the "encrypted_client_hello" extension:

As previously written, the wording could be understood as referring to an application using some other (D)TLS mechanism to indicate which ECHConfig candidate value selection method to use.

ECHClientHello.config_id since it can be used as a tracking vector. In such cases, the second method should be used for matching the ECHClientHello to a known ECHConfig.  See optional-configs.  Unless  <ins> specified by the application profile or otherwise externally configured, implementations MUST use the first method. </ins> The server then iterates over the candidate ECHConfig values, attempting to decrypt the "encrypted_client_hello" extension:


Abstract <del> This document describes an interface for importing external PSK (Pre- Shared Key) into TLS 1.3. </del>  1. <del> TLS 1.3 RFC8446 supports pre-shared key (PSK) authentication, wherein </del>  PSKs can be established via session tickets from prior connections or externally via some out-of-band mechanism.  The protocol mandates that each PSK only be used with a single hash function.  This was

This is mainly editorial, so there should be nothing surprising here. Please let me if that's not the case! It also includes clarifying text per NAME recommendation raised during WGLC. cc NAME NAME
From Rob Sayre: We should note the latter is a requirement from Section 4.2.11 of RFC8446. Let's also fix the typo "import external keys for TLS..."

Abstract  <ins> This document describes an interface for importing external Pre- Shared Keys (PSKs) into TLS 1.3. </ins> 1.  <ins> TLS 1.3 RFC8446 supports Pre-Shared Key (PSK) authentication, wherein </ins> PSKs can be established via session tickets from prior connections or externally via some out-of-band mechanism.  The protocol mandates that each PSK only be used with a single hash function.  This was


key derivation.  Moreover, it requires external PSKs to be provisioned for specific hash functions. <del> To mitigate these problems, external PSKs can be bound to a specific KDF and hash function when used in TLS 1.3, even if they are associated with a different hash function when provisioned.  This document specifies an interface by which external PSKs may be imported for use in a TLS 1.3 connection to achieve this goal.  In particular, it describes how KDF-bound PSKs can be differentiated by the target (D)TLS protocol version and KDF for which the PSK will be used.  This produces a set of candidate PSKs, each of which are bound to a specific target protocol and KDF.  This expands what would normally have been a single PSK identity into a set of PSK identities. </del>  2.

key derivation.  Moreover, it requires external PSKs to be provisioned for specific hash functions.  <ins> To mitigate these problems, this document specifies a PSK Importer interface by which external PSKs may be imported and subsequently bound to a specific KDF and hash function for use in TLS 1.3.  In particular, it describes a mechanism for differentiating external PSKs by the target KDF, (D)TLS protocol version, and an optional context string.  This process yields a set of candidate PSKs, each of which are bound to a target KDF and protocol.  This expands what would normally have been a single PSK and identity into a set of PSKs and identities. </ins> 2.


3. <del> Key importers mirror the concept of key exporters in TLS in that they diversify a key based on some contextual information before use in a connection.  In contrast to key exporters, wherein differentiation is done via an explicit label and context string, the key importer defined herein diversifies external one PSK into one or more PSKs for use via a target protocol, KDF identifier, and optional context string.  Additionally, the resulting PSK binder key is modified with a new derivation label to prevent confusion with non-imported PSKs. Imported keys do not require negotiation for use, as a client and server will not agree upon identities if not imported correctly. Endpoints may incrementally deploy PSK importer support by offering </del>  non-imported keys for TLS versions prior to TLS 1.3.  Non-imported and imported PSKs are distinct since their identities are different on the wire.  See rollout for more details. <del> Clients which import external keys TLS MUST NOT use these keys for any other purpose.  Moreover, each external PSK MUST be associated with at most one hash function. </del>  3.1.

3.  <ins> The PSK Importer interface mirrors that of the TLS Exporters interface in that it diversifies a key based on some contextual information.  In contrast to the Exporters interface, wherein differentiation is done via an explicit label and context string, the PSK Importer interface defined herein takes an external PSK and identity and "imports" it into TLS, creating a set of "derived" PSKs and identities.  Each of these derived PSKs are bound a target protocol, KDF identifier, and optional context string.  Additionally, the resulting PSK binder keys are modified with a new derivation label to prevent confusion with non-imported PSKs. Imported keys do not require negotiation for use since a client and server will not agree upon identities if imported incorrectly. Endpoints may incrementally deploy PSK Importer support by offering </ins> non-imported keys for TLS versions prior to TLS 1.3.  Non-imported and imported PSKs are distinct since their identities are different on the wire.  See rollout for more details.  <ins> Clients which import external keys MUST NOT use either the external keys or the derived keys for any other purpose.  Moreover, each external PSK MUST be associated with at most one hash function, as per the rules in Section 4.2.11 from RFC8446.  See security- considerations for more discussion. </ins> 3.1.


Target KDF: The KDF for which a PSK is imported for use. <del> Imported PSK (IPSK): A PSK derived from an EPSK, external identity, optional context string, and target protocol and KDF. </del>  Imported Identity: A sequence of bytes used to identify an IPSK. 4. <del> A key importer diversifies an input EPSK into one or more PSKs advertised on the wire via a target protocol, KDF identifier, and optional context string.  Additionally, the resulting PSK binder key is modified with a new derivation label to prevent confusion with non-imported PSKs.  This section describes the diversification mechanism and binder key computation change. </del>  4.1. <del> A key importer takes as input an EPSK with external identity "external_identity" and base key "epsk", as defined in terminology, along with an optional context, and transforms it into a set of PSKs and imported identities for use in a connection based on supported (target) protocols and KDFs.  In particular, for each supported target protocol "target_protocol" and KDF "target_kdf", the importer </del>  constructs an ImportedIdentity structure as follows: The list of "target_kdf" values is maintained by IANA as described in

Target KDF: The KDF for which a PSK is imported for use.  <ins> Imported PSK (IPSK): A PSK derived from an EPSK, External Identity, optional context string, and target protocol and KDF. </ins> Imported Identity: A sequence of bytes used to identify an IPSK. 4.  <ins> This section describes the PSK Importer interface and its underlying diversification mechanism and binder key computation modification. </ins> 4.1.  <ins> The PSK Importer interface takes as input an EPSK with External Identity "external_identity" and base key "epsk", as defined in terminology, along with an optional context, and transforms it into a set of PSKs and imported identities for use in a connection based on target protocols and KDFs.  In particular, for each supported target protocol "target_protocol" and KDF "target_kdf", the importer </ins> constructs an ImportedIdentity structure as follows: The list of "target_kdf" values is maintained by IANA as described in


and QUICv1 QUIC use 0x0304.  Note that this means future versions of TLS will increase the number of PSKs derived from an external PSK. <del> An Imported PSK derived from an EPSK with base key 'epsk' bound to this identity is then computed as follows: </del>  <del> L is corresponds to the KDF output length of ImportedIdentity.target_kdf as defined in IANA.  For hash-based KDFs, such as HKDF_SHA256(0x0001), this is the length of the hash function output, i.e., 32 octets.  This is required for the IPSK to be of length suitable for supported ciphersuites. </del>  <del> The identity of 'ipskx' as sent on the wire is ImportedIdentity, </del>  i.e., the serialized content of ImportedIdentity is used as the <del> content of PskIdentity.identity in the PSK extension. </del>  The hash function used for HKDF RFC5869 is that which is associated with the EPSK.  It is not the hash function associated with

and QUICv1 QUIC use 0x0304.  Note that this means future versions of TLS will increase the number of PSKs derived from an external PSK.  <ins> Given an ImportedIdentity and corresponding EPSK with base key "epsk", an Imported PSK IPSK with base key "ipskx" is computed as follows: </ins>  <ins> L corresponds to the KDF output length of ImportedIdentity.target_kdf as defined in IANA.  For hash-based KDFs, such as HKDF_SHA256(0x0001), this is the length of the hash function output, i.e., 32 octets.  This is required for the IPSK to be of length suitable for supported ciphersuites. </ins>  <ins> The identity of "ipskx" as sent on the wire is ImportedIdentity, </ins> i.e., the serialized content of ImportedIdentity is used as the  <ins> content of PskIdentity.identity in the PSK extension.  The corresponding TLS 1.3 binder key is "ipskx". </ins> The hash function used for HKDF RFC5869 is that which is associated with the EPSK.  It is not the hash function associated with


SHA-256 MUST be used.  Diversifying EPSK by ImportedIdentity.target_kdf ensures that an IPSK is only used as input keying material to at most one KDF, thus satisfying the <del> requirements in RFC8446. Endpoints generate a compatible ipskx for each target ciphersuite they offer.  For example, importing a key for TLS_AES_128_GCM_SHA256 and TLS_AES_256_GCM_SHA384 would yield two PSKs, one for HKDF-SHA256 and another for HKDF-SHA384.  In contrast, if TLS_AES_128_GCM_SHA256 and TLS_CHACHA20_POLY1305_SHA256 are supported, only one derived key is necessary. The resulting IPSK base key 'ipskx' is then used as the binder key in TLS 1.3 with identity ImportedIdentity.  With knowledge of the supported KDFs, one may import PSKs before the start of a connection. EPSKs may be imported for early data use if they are bound to protocol settings and configurations that would otherwise be required for early data with normal (ticket-based PSK) resumption.  Minimally, that means ALPN, QUIC transport settings, etc., must be provisioned alongside these EPSKs. </del>  4.2. <del> To prevent PSK Importers from being confused with standard out-of- band PSKs, imported PSKs change the PSK binder key derivation label. In particular, the standard TLS 1.3 PSK binder key computation is defined as follows: </del>  Imported PSKs replace the string "ext binder" with "imp binder" when <del> deriving "binder_key".  This means the binder key is now computed as </del>  follows: <del> This new label differentiates non-imported and imported external PSKs.  Specifically, a client and server will negotiate use of an </del>  external PSK if and only if (a) both endpoints import the PSK or (b) neither endpoint imports the PSK.  As "binder_key" is a leaf key, changing its computation does not affect any other key.

SHA-256 MUST be used.  Diversifying EPSK by ImportedIdentity.target_kdf ensures that an IPSK is only used as input keying material to at most one KDF, thus satisfying the  <ins> requirements in RFC8446.  See security-considerations for more details. Endpoints SHOULD generate a compatible "ipskx" for each target ciphersuite they offer.  For example, importing a key for TLS_AES_128_GCM_SHA256 and TLS_AES_256_GCM_SHA384 would yield two PSKs, one for HKDF-SHA256 and another for HKDF-SHA384.  In contrast, if TLS_AES_128_GCM_SHA256 and TLS_CHACHA20_POLY1305_SHA256 are supported, only one derived key is necessary. EPSKs may be imported before the start of a connection if the target KDFs, protocols, and context string(s) are known a priori.  EPSKs may also be imported for early data use if they are bound to protocol settings and configurations that would otherwise be required for early data with normal (ticket-based PSK) resumption.  Minimally, that means ALPN, QUIC transport parameters (if used for QUIC), etc., must be provisioned alongside these EPSKs. </ins> 4.2.  <ins> To prevent confusion between imported and non-imported PSKs, imported PSKs change the PSK binder key derivation label.  In particular, the standard TLS 1.3 PSK binder key computation is defined as follows: </ins> Imported PSKs replace the string "ext binder" with "imp binder" when  <ins> deriving "binder_key".  This means the binder key is computed as </ins> follows:  <ins> This new label ensures a client and server will negotiate use of an </ins> external PSK if and only if (a) both endpoints import the PSK or (b) neither endpoint imports the PSK.  As "binder_key" is a leaf key, changing its computation does not affect any other key.


algorithm and PSK.  Thus, an EPSK may be used with the same KDF (and underlying HMAC hash algorithm) as TLS 1.3 with importers.  However, critically, the derived PSK will not be the same since the importer <del> differentiates the PSK via the identity, target protocol, and target KDF.  Thus, PSKs imported for TLS 1.3 are distinct from those used in TLS 1.2, and thereby avoid cross-protocol collisions.  Note that this </del>  does not preclude endpoints from using non-imported PSKs for TLS 1.2. Indeed, this is necessary for incremental deployment. 7. <del> The Key Importer security goals can be roughly stated as follows: </del>  avoid PSK re-use across KDFs while properly authenticating endpoints. When modeled as computational extractors, KDFs assume that input keying material (IKM) is sampled from some "source" probability

algorithm and PSK.  Thus, an EPSK may be used with the same KDF (and underlying HMAC hash algorithm) as TLS 1.3 with importers.  However, critically, the derived PSK will not be the same since the importer  <ins> differentiates the PSK via the identity and target KDF and protocol. Thus, PSKs imported for TLS 1.3 are distinct from those used in TLS 1.2, and thereby avoid cross-protocol collisions.  Note that this </ins> does not preclude endpoints from using non-imported PSKs for TLS 1.2. Indeed, this is necessary for incremental deployment. 7.  <ins> The PSK Importer security goals can be roughly stated as follows: </ins> avoid PSK re-use across KDFs while properly authenticating endpoints. When modeled as computational extractors, KDFs assume that input keying material (IKM) is sampled from some "source" probability


authentication protocols, wherein at least one is uncompromised, jointly authenticates all protocols.  Authenticating with an externally provisioned PSK, therefore, should ideally authenticate <del> both the TLS connection and the external provision process. </del>  Typically, the external provision process produces a PSK and corresponding context from which the PSK was derived and in which it <del> should be used.  We refer to an external PSK without such context as "context free". </del>  Thus, in considering the source-independence and compound <del> authentication requirements, the Key Import API described in this document aims to achieve the following goals: </del>  <del> Externally provisioned PSKs imported into TLS achieve compound authentication of the provision step(s) and connection. </del>  Context-free PSKs only achieve authentication within the context of a single connection. <del> Imported PSKs are used as IKM for two different KDFs. </del>  Imported PSKs do not collide with existing PSKs used for TLS 1.2 and below.

authentication protocols, wherein at least one is uncompromised, jointly authenticates all protocols.  Authenticating with an externally provisioned PSK, therefore, should ideally authenticate  <ins> both the TLS connection and the external provisioning process. </ins> Typically, the external provision process produces a PSK and corresponding context from which the PSK was derived and in which it  <ins> should be used.  If available, this is used as the ImportedIdentity.context value.  We refer to an external PSK without such context as "context-free". </ins> Thus, in considering the source-independence and compound  <ins> authentication requirements, the PSK Import interface described in this document aims to achieve the following goals: </ins>  <ins> Externally provisioned PSKs imported into a TLS connection achieve compound authentication of the provisioning process and connection. </ins> Context-free PSKs only achieve authentication within the context of a single connection.  <ins> Imported PSKs are not used as IKM for two different KDFs. </ins> Imported PSKs do not collide with existing PSKs used for TLS 1.2 and below.


way in which the same external PSK might produce related output in TLS 1.3 and prior versions, only limited analysis has been done. Applications SHOULD provision separate PSKs for TLS 1.3 and prior <del> versions. </del>  <del> To mitigate against any interference, this document specifies a PSK </del>  Importer interface by which external PSKs may be imported and subsequently bound to a specific key derivation function (KDF) and hash function for use in TLS 1.3 RFC8446 and DTLS 1.3 DTLS13.  In

I don't love a couple of the ways I phrased things here, so feel free to offer suggestions to improve it! modulo test vectors. (NAME it'll likely take some time to get those vectors. Do you think we should hold this document until that's done?)
This looks good modulo the open issue about incremental deployment. I don't think we need to hold the document up in order to get test vectors. Benjamin Kaduk has entered the following ballot position for draft-ietf-tls-external-psk-importer-06: Yes When responding, please keep the subject line intact and reply to all email addresses included in the To and CC lines. (Feel free to cut this introductory paragraph, however.) Please refer to URL for more information about IESG DISCUSS and COMMENT positions. The document, along with other ballot positions, can be found here: URL COMMENT: Sorry about the large volume of comments; this document is actually in pretty good shape, there are just a bunch of details that can be subtle to get exactly right. I specifically call out the note in Section 4.1 about which HKDF-Expand-Label is to be used, since that would affect the actual derived keys for DTLS 1.3 (and any hypothetical future TLS versions). Section 1 While there is no known way in which the same external PSK might produce related output in TLS 1.3 and prior versions, only limited analysis has been done. Applications SHOULD provision separate PSKs for TLS 1.3 and prior versions. To mitigate against any interference, this document specifies a PSK Importer interface by which external PSKs may be imported and subsequently bound to a specific key derivation function (KDF) and hash function for use in TLS 1.3 [RFC8446] and DTLS 1.3 [DTLS13]. [...] IIRC the main target use cases for this mechanism are for existing external PSKs (violating the "SHOULD" from the first quoted paragraph), as well as deployments that are simplified by only needing to provision a single PSK. Does it make sense to include such clarifying description here? (Similarly, is it accurate to say that "[a]pplications SHOULD provision separate PSKs [...], but the mechanism defined in this document provides a partial mitigation for use when that is not possible"? Also, we only use the word "interference" twice in this document (this is the first instance), so it might be worth a couple more words to clarify the nature of the potential interference. Section 3 non-imported keys for TLS versions prior to TLS 1.3. Non-imported and imported PSKs are distinct since their identities are different on the wire. See Section 6 for more details. (side note?) I think the precise story here is a little subtle -- for any given key, the imported and non-imported identities are distinct, but in principle one could construct a non-imported identity that overlaps with an imported identity for a different key (and we say as much at the end of Section 7). This is vanishingly rare to happen by chance, but makes the statement as written not quite categorically true. That said, the change to the binder key derivation (§ 4.2) seems to obviate any potential consequences to such a collision (though the connection attempt would presumably fail). Endpoints which import external keys MUST NOT use either the external keys or the derived keys for any other purpose. Moreover, each IIUC, this is "MUST NOT use the keys that are input to the import process for any purpose other than the importer, and MUST NOT use the derived keys for any purpose other than TLS PSKs". Is it worth spelling it out explicitly like that? external PSK MUST be associated with at most one hash function, as per the rules in Section 4.2.11 from [RFC8446]. See Section 7 for more discussion. Does this requirement apply to the inputs to the importer process, the outputs, or both? Section 3.1 Imported PSK (IPSK): A PSK derived from an EPSK, External Identity, optional context string, target protocol, and target KDF. There is an "External Identity" that is contained within the EPSK itself; is the "External Identity" listed here distinct from that? Section 4.1 The PSK Importer interface takes as input an EPSK with External Identity "externalidentity" and base key "epsk", as defined in Section 3.1, along with an optional context, and transforms it into a set of PSKs and imported identities for use in a connection based on target protocols and KDFs. In particular, for each supported target protocol "targetprotocol" and KDF "targetkdf", the importer constructs an ImportedIdentity structure as follows: If I understand correctly the "targetkdf" is supposed to be the KDF associated with the cipher suite(s) the derived PSK will be usable for. This is something of a divergence from RFC 8446, where we assume that the KDF will be HKDF and associate only a hash function with the cipher suite. While discussing a more generic KDF concept seems reasonable (and is directly in line with the cryptographic principles that motivate this work), I'd recommend adding a few more words somewhere in this section to clarify the relationship between the targetkdf and the cipher suite(s), probably in the paragraph that starts "[e]ndpoints SHOULD generate a compatible 'ipskx' for each target ciphersuite they offer". struct { opaque externalidentity; opaque context; uint16 targetprotocol; uint16 targetkdf; } ImportedIdentity; Should we say that this is using the TLS presentation language? ImportedIdentity.context MUST include the context used to derive the EPSK, if any exists. For example, ImportedIdentity.context may (nit?) "derive" suggests a cryptographic key derivation process, but the rest of the prose suggests that this is more a process of "identification" or "determination". Is there a more appropriate word to use? Given an ImportedIdentity and corresponding EPSK with base key "epsk", an Imported PSK IPSK with base key "ipskx" is computed as follows: epskx = HKDF-Extract(0, epsk) ipskx = HKDF-Expand-Label(epskx, "derived psk", Hash(ImportedIdentity), L) I think we need to say that the HKDF-Expand-Label used (i.e., the URL prefix) is the one corresponding to ImportedIdentity.targetprotocol. L corresponds to the KDF output length of ImportedIdentity.targetkdf as defined in Section 9. For hash-based KDFs, such as HKDFSHA256(0x0001), this is the length of the hash function output, i.e., 32 octets. This is required for the IPSK to be of length (32 octets for SHA256, not all hash-based KDFs) The identity of "ipskx" as sent on the wire is ImportedIdentity, i.e., the serialized content of ImportedIdentity is used as the content of PskIdentity.identity in the PSK extension. The corresponding TLS 1.3 binder key is "ipskx". In RFC 8446, the "binderkey" is the output of the key schedule, but ipskx is an input to the key schedule. So I think we want to say something like "the corresponding PSK input for the TLS 1.3 key schedule is 'ipskx'". The hash function used for HKDF [RFC5869] is that which is associated with the EPSK. It is not the hash function associated with ImportedIdentity.targetkdf. If no hash function is specified, I predict that someone will mess up the hash function selection while implementing this. Perhaps we could provide test vectors for the full matrix of (EPSK Hash, targetkdf hash) pairs using SHA256/SHA384? SHA-256 [SHA2] MUST be used. Diversifying EPSK by I think we might be able to tolerate the protocol* having a strict requirement that the associated hash function is specified, and provide a recommended value that would be used by people deploying the protocol in the absence of other information. This might in some sense help future-proof the document for the scenario where SHA256 weakens or is broken and the default should change. KDFs, protocols, and context string(s) are known a priori. EPSKs MAY also be imported for early data use if they are bound to protocol settings and configurations that would otherwise be required for early data with normal (ticket-based PSK) resumption. Minimally, that means Application-Layer Protocol Negotiation [RFC7301], QUIC RFC 8446 does not limit 0-RTT data to resumption, so I think we just want "if they are bound to the protocol settings and configuration that are required for sending early data". Also, nit: I think we usually refer to the "ALPN value" instead of just "ALPN" being configured. Section 5 If a client or server wish to deprecate a hash function and no longer use it for TLS 1.3, they remove the corresponding KDF from the set of target KDFs used for importing keys. This does not affect the KDF operation used to derive Imported PSKs. Should we also include a paragraph about how to deprecate the Hash used in deriving Imported PSKs? (It's fixed per EPSK, so, "configure a new EPSK", basically.) Section 6 Recall that TLS 1.2 permits computing the TLS PRF with any hash algorithm and PSK. Thus, an EPSK may be used with the same KDF (and underlying HMAC hash algorithm) as TLS 1.3 with importers. However, critically, the derived PSK will not be the same since the importer differentiates the PSK via the identity and target KDF and protocol. Thus, PSKs imported for TLS 1.3 are distinct from those used in TLS 1.2, and thereby avoid cross-protocol collisions. [...] As I read this I recalled that up in Section 1 we say that applications "SHOULD provision separate PSKs for TLS 1.3 and prior versions". The scenario being described here sounds like it can only occur if that SHOULD is ignored, which might be worth reiterating. We also say in § 4.1 that "external PSKs MUST NOT be imported for (D)TLS or prior versions". In light of these two observations, my best interpretation of the quoted text is that it should be equivalent to: NEW: Recall that TLS 1.2 permits computing the TLS PRF with any hash algorithm and PSK. Accordingly, a given EPSK might be both used directly as a TLS 1.2 PSK and used with TLS 1.3 via the importer mechanism (noting that this configuration is not recommended, per Section 1), using the same KDF algorithm. However, because the TLS 1.3 importer mechanism includes an additional key-derivation step, the actual PSK used in the TLS 1.3 key schedule will be distinct from the one used in the TLS 1.2 key schedule, so there are no cross-protocol collisions possible. Note that this does not preclude endpoints from using non-imported PSKs for TLS 1.2. For some reason this line implies to me that endpoints might use imported PSKs for TLS 1.2, but this is forbidden by Section 4.1 (as quoted above). Perhaps "does not preclude endpoints from continuing to use TLS 1.2 and the non-imported PSKs it requires"? Section 7 We should probably note that any information placed in ImportedIdentity.context will be visible on the wire in cleartext, and thus that confidential identifiers from other protocols should either not be used or should be protected (e.g., by hashing) prior to use. Externally provisioned PSKs imported into a TLS connection achieve compound authentication of the provisioning process and connection. Context-free PSKs only achieve authentication within the context of a single connection. Do we need to use pskdhke to get the strong compound authentication property, or is it attainable with pskke as well? Section 10.1 I'm not sure why [QUIC] and RFC 5246 are listed as normative references. Appendix B The Selfie attack [Selfie] relies on a misuse of the PSK interface. The PSK interface makes the implicit assumption that each PSK is known only to one client and one server. If multiple clients or multiple servers with distinct roles share a PSK, TLS only authenticates the entire group. A node successfully authenticates its peer as being in the group whether the peer is another node or itself. I think it may be useful to call out that the "multiple clients" and "multiple servers" case can occur even when there are only two endpoints that know the key (that is, when they do not have predetermined client/server roles). struct { opaque clientmac; opaque server_mac; } Context; We may not need the whole 16k to hold a MAC address, especially since this is just an example. If an attacker then redirects a ClientHello intended for one node to a different node, the receiver will compute a different context string and the handshake will not complete. Similarly to the above, this could be "a different node (including the node that generated the ClientHello)".

way in which the same external PSK might produce related output in TLS 1.3 and prior versions, only limited analysis has been done. Applications SHOULD provision separate PSKs for TLS 1.3 and prior  <ins> versions.  In cases where this is not possible, e.g., there are already deployed external PSKs or provisioning is otherwise limited, re-using external PSKs across different versions of TLS may produce related outputs, which may in turn lead to security problems; see RFC8446, Section E.7. </ins>  <ins> To mitigate against such problems, this document specifies a PSK </ins> Importer interface by which external PSKs may be imported and subsequently bound to a specific key derivation function (KDF) and hash function for use in TLS 1.3 RFC8446 and DTLS 1.3 DTLS13.  In


and imported PSKs are distinct since their identities are different on the wire.  See rollout for more details. <del> Endpoints which import external keys MUST NOT use either the external keys or the derived keys for any other purpose.  Moreover, each external PSK MUST be associated with at most one hash function, as per the rules in Section 4.2.11 from RFC8446.  See security- considerations for more discussion. </del>  3.1.  External PSK (EPSK): A PSK established or provisioned out-of-band, i.e., not from a TLS connection, which is a tuple of (Base Key, External Identity, Hash).

and imported PSKs are distinct since their identities are different on the wire.  See rollout for more details.  <ins> Endpoints which import external keys MUST NOT use the keys that are input to the import process for any purpose other than the importer, and MUST NOT use the derived keys for any purpose other than TLS PSKs.  Moreover, each external PSK fed to the importer process MUST be associated with at most one hash function.  This is analogous to the rules in Section 4.2.11 of RFC8446.  See security-considerations for more discussion. </ins> 3.1. <ins> The following terms are used throughout this document: </ins> External PSK (EPSK): A PSK established or provisioned out-of-band, i.e., not from a TLS connection, which is a tuple of (Base Key, External Identity, Hash).


Target KDF: The KDF for which a PSK is imported for use. <del> Imported PSK (IPSK): A PSK derived from an EPSK, External Identity, optional context string, target protocol, and target KDF. </del>  Imported Identity: A sequence of bytes used to identify an IPSK.  4. This section describes the PSK Importer interface and its underlying

Target KDF: The KDF for which a PSK is imported for use.  <ins> Imported PSK (IPSK): A PSK derived from an EPSK, optional context string, target protocol, and target KDF. </ins> Imported Identity: A sequence of bytes used to identify an IPSK. <ins> This document uses presentation language from RFC8446, Section 3. </ins> 4. This section describes the PSK Importer interface and its underlying


PSKs for TLS 1.3 and non-imported PSKs for earlier versions co-exist for incremental deployment. <del> ImportedIdentity.context MUST include the context used to derive the EPSK, if any exists.  For example, ImportedIdentity.context may </del>  include information about peer roles or identities to mitigate Selfie-style reflection attacks Selfie.  See mitigate-selfie for more details.  If the EPSK is a key derived from some other protocol or

PSKs for TLS 1.3 and non-imported PSKs for earlier versions co-exist for incremental deployment.  <ins> ImportedIdentity.context MUST include the context used to determine the EPSK, if any exists.  For example, ImportedIdentity.context may </ins> include information about peer roles or identities to mitigate Selfie-style reflection attacks Selfie.  See mitigate-selfie for more details.  If the EPSK is a key derived from some other protocol or


L corresponds to the KDF output length of ImportedIdentity.target_kdf as defined in IANA.  For hash-based KDFs, such as HKDF_SHA256(0x0001), this is the length of the hash function output, <del> i.e., 32 octets.  This is required for the IPSK to be of length suitable for supported ciphersuites. </del>  The identity of "ipskx" as sent on the wire is ImportedIdentity, i.e., the serialized content of ImportedIdentity is used as the content of PskIdentity.identity in the PSK extension.  The <del> corresponding TLS 1.3 binder key is "ipskx". </del>  As the maximum size of the PSK extension is 2^16 - 1 octets, an Imported Identity that exceeds this size is likely to cause a

L corresponds to the KDF output length of ImportedIdentity.target_kdf as defined in IANA.  For hash-based KDFs, such as HKDF_SHA256(0x0001), this is the length of the hash function output,  <ins> e.g., 32 octets for SHA256.  This is required for the IPSK to be of length suitable for supported ciphersuites.  Internally, HKDF-Expand- Label uses a label corresponding to ImportedIdentity.target_protocol, e.g., "tls13" for TLS 1.3, as per RFC8446, Section 7.1, or "dtls13" for DTLS 1.3, as per I-D.ietf-tls-dtls13, Section 5.10. </ins> The identity of "ipskx" as sent on the wire is ImportedIdentity, i.e., the serialized content of ImportedIdentity is used as the content of PskIdentity.identity in the PSK extension.  The  <ins> corresponding PSK input for the TLS 1.3 key schedule is 'ipskx'. </ins> As the maximum size of the PSK extension is 2^16 - 1 octets, an Imported Identity that exceeds this size is likely to cause a


The hash function used for HKDF RFC5869 is that which is associated with the EPSK.  It is not the hash function associated with ImportedIdentity.target_kdf.  If no hash function is specified, <del> SHA-256 SHA2 MUST be used.  Diversifying EPSK by </del>  ImportedIdentity.target_kdf ensures that an IPSK is only used as input keying material to at most one KDF, thus satisfying the requirements in RFC8446.  See security-considerations for more

The hash function used for HKDF RFC5869 is that which is associated with the EPSK.  It is not the hash function associated with ImportedIdentity.target_kdf.  If no hash function is specified,  <ins> SHA-256 SHA2 SHOULD be used.  Diversifying EPSK by </ins> ImportedIdentity.target_kdf ensures that an IPSK is only used as input keying material to at most one KDF, thus satisfying the requirements in RFC8446.  See security-considerations for more


TLS_AES_128_GCM_SHA256 and TLS_AES_256_GCM_SHA384 would yield two PSKs, one for HKDF-SHA256 and another for HKDF-SHA384.  In contrast, if TLS_AES_128_GCM_SHA256 and TLS_CHACHA20_POLY1305_SHA256 are <del> supported, only one derived key is necessary. </del>  EPSKs MAY be imported before the start of a connection if the target KDFs, protocols, and context string(s) are known a priori.  EPSKs MAY <del> also be imported for early data use if they are bound to protocol settings and configurations that would otherwise be required for early data with normal (ticket-based PSK) resumption.  Minimally, that means Application-Layer Protocol Negotiation RFC7301, QUIC transport parameters (if used for QUIC), and any other relevant parameters that are negotiated for early data MUST be provisioned alongside these EPSKs. </del>  4.2.

TLS_AES_128_GCM_SHA256 and TLS_AES_256_GCM_SHA384 would yield two PSKs, one for HKDF-SHA256 and another for HKDF-SHA384.  In contrast, if TLS_AES_128_GCM_SHA256 and TLS_CHACHA20_POLY1305_SHA256 are  <ins> supported, only one derived key is necessary.  Each ciphersuite uniquely identifies the target KDF.  Future specifications that change the way the KDF is negotiated will need to update this specification to make clear how target KDFs are determined for the import process. </ins> EPSKs MAY be imported before the start of a connection if the target KDFs, protocols, and context string(s) are known a priori.  EPSKs MAY  <ins> also be imported for early data use if they are bound to the protocol settings and configuration that are required for sending early data. Minimally, that means Application-Layer Protocol Negotiation value RFC7301, QUIC transport parameters (if used for QUIC), and any other relevant parameters that are negotiated for early data MUST be provisioned alongside these EPSKs. </ins> 4.2.


6. <del> Recall that TLS 1.2 permits computing the TLS PRF with any hash algorithm and PSK.  Thus, an EPSK may be used with the same KDF (and underlying HMAC hash algorithm) as TLS 1.3 with importers.  However, critically, the derived PSK will not be the same since the importer differentiates the PSK via the identity and target KDF and protocol. Thus, PSKs imported for TLS 1.3 are distinct from those used in TLS 1.2, and thereby avoid cross-protocol collisions.  Note that this does not preclude endpoints from using non-imported PSKs for TLS 1.2. Indeed, this is necessary for incremental deployment.  Specifically, existing applications using TLS 1.2 with non-imported PSKs can safely enable TLS 1.3 with imported PSKs in clients and servers without interoperability risk. </del>  7.

6.  <ins> The mechanism defined in this document requires that an EPSK is only ever used as an EPSK and not for any other purpose.  In particular, this requirement disallows direct use of the EPSK as a PSK in TLS 1.2.  The importer process produces distinct IPSKs derived from the target protocol and KDF, which in turn protects against cross- protocol collisions for protocol versions using this process by ensuring that each IPSK can only be used with one protocol and KDF. This is a distinct contrast to TLS 1.2, where a given PSK might be used with multiple KDFs in different handshakes, and importers are not available.  Furthermore, the KDF used in TLS 1.2 might be the same KDF used by the importer mechanism itself. In deployments that already have PSKs provisioned and in use with TLS 1.2, attempting to incrementally deploy the importer mechanism would then result in concurrent use of the already provisioned PSK both directly as a TLS 1.2 PSK and as an EPSK, which in turn could mean that the same KDF and key would be used in two different protocol contexts.  There are no known related outputs or security issues that would arise from this arrangement.  However, only limited analysis has been done, and as such is not a recommended configuration. However, the benefits of using TLS 1.3 and of using PSK importers may prove sufficiently compelling that existing deployments choose to enable this noncompliant configuration for a brief transition period while new software (using TLS 1.3 and importers) is deployed. Operators are advised to make any such transition period as short as possible. </ins> 7.


Imported PSKs do not collide with future protocol versions and KDFs. <del> There is no known interference between the process for computing Imported PSKs from an external PSK and the processing of existing external PSKs used in (D)TLS 1.2 and below.  However, only limited analysis has been done, which is an additional reason why applications SHOULD provision separate PSKs for (D)TLS 1.3 and prior versions, even when the importer interface is used in (D)TLS 1.3. </del>  The PSK Importer does not prevent applications from constructing non- importer PSK identities that collide with imported PSK identities.

Imported PSKs do not collide with future protocol versions and KDFs.  <ins> There are no known related outputs or security issues caused from the process for computing Imported PSKs from an external PSK and the processing of existing external PSKs used in (D)TLS 1.2 and below, as noted in rollout.  However, only limited analysis has been done, which is an additional reason why applications SHOULD provision separate PSKs for (D)TLS 1.3 and prior versions, even when the importer interface is used in (D)TLS 1.3. </ins> The PSK Importer does not prevent applications from constructing non- importer PSK identities that collide with imported PSK identities.


systems and use cases, this identity may become a persistent tracking identifier.  9. This specification introduces a new registry for TLS KDF identifiers,

systems and use cases, this identity may become a persistent tracking identifier. <ins> Note also that ImportedIdentity.context is visible in cleartext on the wire as part of the PSK identity.  Unless otherwise protected by a mechanism such as TLS Encrypted ClientHello ECH, applications SHOULD not put sensitive information in this field. </ins> 9. This specification introduces a new registry for TLS KDF identifiers,


track documents need to be marked as recommended. If an item is marked as not recommended it does not necessarily mean <del> that it is flawed, rather, it indicates that either the item has not </del>  been through the IETF consensus process, has limited applicability, or is intended only for specific use cases.

NAME PTAL
LGTM - ‘twas just a comment anyway. W I don't think the execution is relevant when it was obviously a bad idea in the first place. This is like putting rabid weasels in your pants, and later expressing regret at having chosen those particular rabid weasels and that pair of pants. ---maf

track documents need to be marked as recommended. If an item is marked as not recommended it does not necessarily mean  <ins> that it is flawed; rather, it indicates that either the item has not </ins> been through the IETF consensus process, has limited applicability, or is intended only for specific use cases.


Update the "Reference" to also refer to this document. <del> Add the following notes: Experts are to verify that there is in fact a publicly available standard.  An Internet Draft that is posted and never published or a standard in another standards body, industry consortium, university site, etc. suffices. As specified in RFC8126, assignments made in the Private Use space are not generally useful for broad interoperability.  It is the responsibility of those making use of the Private Use range to ensure that no conflicts occur (within the intended scope of use). For widespread experiments, temporary reservations are available. </del> See expert-pool for additional information about the designated expert pool.

Update the "Reference" to also refer to this document.  See expert-pool for additional information about the designated expert pool.


extension with the value "Yes", a Standards Track document RFC8126 is REQUIRED.  IESG Approval is REQUIRED for a Yes->No transition.  The following is from I-D.ietf-tls-tls13 and is included here to ensure alignment between these specifications.

extension with the value "Yes", a Standards Track document RFC8126 is REQUIRED.  IESG Approval is REQUIRED for a Yes->No transition. <ins> IANA [SHALL update/has added] the following notes: Experts are to verify that there is in fact a publicly available specification.  An Internet Draft that is posted and never published or a specification in another standards body, industry consortium, university site, etc. suffices. As specified in RFC8126, assignments made in the Private Use space are not generally useful for broad interoperability.  It is the responsibility of those making use of the Private Use range to ensure that no conflicts occur (within the intended scope of use). For widespread experiments, temporary reservations are available. Extensions marked as "Yes" are those allocated via Standards Track RFCs.  Extensions marked as "No" are not. If an item is not marked as recommended it does not necessarily mean that it is flawed; rather, it indicates that either the item has not been through the IETF consensus process, has limited applicability, or is intended only for specific use cases. </ins> The following is from I-D.ietf-tls-tls13 and is included here to ensure alignment between these specifications.


represents a security trade-off that may not be appropriate for general environments.  IANA [SHALL add/has added] the following notes for additional information:

represents a security trade-off that may not be appropriate for general environments. <ins> If an item is not marked as recommended it does not necessarily mean that it is flawed; rather, it indicates that either the item has not been through the IETF consensus process, has limited applicability, or is intended only for specific use cases. </ins> IANA [SHALL add/has added] the following notes for additional information:


groups marked "No" range from "good" to "bad" from a cryptographic standpoint.  The designated expert RFC8126 only ensures that the specification is publicly available.  An Internet Draft that is posted and never published or a standard in another standards body, industry

groups marked "No" range from "good" to "bad" from a cryptographic standpoint. <ins> If an item is not marked as recommended it does not necessarily mean that it is flawed; rather, it indicates that either the item has not been through the IETF consensus process, has limited applicability, or is intended only for specific use cases. </ins> The designated expert RFC8126 only ensures that the specification is publicly available.  An Internet Draft that is posted and never published or a standard in another standards body, industry


allocated via Standards Track RFCs.  ClientCertificateTypes marked as "No" are not.  12. To align with TLS implementations and to align the naming

allocated via Standards Track RFCs.  ClientCertificateTypes marked as "No" are not. <ins> If an item is not marked as recommended it does not necessarily mean that it is flawed; rather, it indicates that either the item has not been through the IETF consensus process, has limited applicability, or is intended only for specific use cases. </ins> 12. To align with TLS implementations and to align the naming


Exporters Labels marked as "Yes" are those allocated via Standards Track RFCs.  Exporter Labels marked as "No" are not.  IANA [SHALL update/has updated] the reference for this registry to also refer to this document.

Exporters Labels marked as "Yes" are those allocated via Standards Track RFCs.  Exporter Labels marked as "No" are not. <ins> If an item is not marked as recommended it does not necessarily mean that it is flawed; rather, it indicates that either the item has not been through the IETF consensus process, has limited applicability, or is intended only for specific use cases. </ins> IANA [SHALL update/has updated] the reference for this registry to also refer to this document.


Certificate Types marked as "Yes" are those allocated via Standards Track RFCs.  Certificate Types marked as "No" are not.  IANA [SHALL update/has updated] the reference for this registry to also refer this document.

Certificate Types marked as "Yes" are those allocated via Standards Track RFCs.  Certificate Types marked as "No" are not. <ins> If an item is not marked as recommended it does not necessarily mean that it is flawed; rather, it indicates that either the item has not been through the IETF consensus process, has limited applicability, or is intended only for specific use cases. </ins> IANA [SHALL update/has updated] the reference for this registry to also refer this document.


SignatureAlgorithm registries to also refer to this document. [SHALL update/has updated] the TLS HashAlgorithm Registry to list <del> values 7-223 as "Reserved" and the TLS SignatureAlgorithm registry to list values 4-223 as "Reserved". </del>  Despite the fact that the HashAlgorithm and SignatureAlgorithm registries are orphaned, it is still important to warn implementers

4492bis includes some values we were marking as reserved and that's wrong. We also have 224-255 that we might also mark as reserved. Effectively, this closes these two registries.
NAME PTAL
NAME -- This looks good. I have a quick comment on: I presume this will or won't happen as the result of conversations in the WG? Also, I'll note -- for the (only) -- that only 224-253 are necessary to mark as reserved (or, really, since they were previously okay for private use, I think the term to use is "deprecated"), since 254 and 255 are in the TLS 1.3 "reserved for private use" range of 0xfe00-0xffff
I'm planning to forward the PR to the WG after I heard from you. I'll add in "deprecated" for those other values before sending it along.

SignatureAlgorithm registries to also refer to this document. [SHALL update/has updated] the TLS HashAlgorithm Registry to list  <ins> values 7 and 9-223 as "Reserved" and the TLS SignatureAlgorithm registry to list values 4-6 and 9-223 as "Reserved". </ins> Despite the fact that the HashAlgorithm and SignatureAlgorithm registries are orphaned, it is still important to warn implementers


4. Servers MUST NOT include MD5 and SHA-1 in ServerKeyExchange messages. <del> If no other signature algorithms are available (for example, if the client does not send a signature_algorithms extension), the server MUST abort the handshake with a handshake_failure alert or select a different cipher suite. </del>  5. Clients MUST NOT include MD5 and SHA-1 in CertificateVerify messages. If a server receives a CertificateVerify message with MD5 or SHA-1 it <del> MUST abort the connection with handshake_failure or insufficient_security alert. </del>  6.

Addressing this . NAME NAME PTAL
I am really growing to dislike these "here is the alert you must use" constructions. Are they necessary? A lot of this was born out of the deprecate TLS 1/1.1 RFC that spun this I-D off. I believe this is the thread back in mid-2019: URL spt

4. Servers MUST NOT include MD5 and SHA-1 in ServerKeyExchange messages.  <ins> If the client receives a ServerKeyExchange message indicating MD5 or SHA-1, then it MUST abort the connection with an illegal_parameter alert. </ins> 5. Clients MUST NOT include MD5 and SHA-1 in CertificateVerify messages. If a server receives a CertificateVerify message with MD5 or SHA-1 it  <ins> MUST abort the connection with an illegal_parameter alert. </ins> 6.


Connection racing: Happy Eyeballs V2 RFC8305 describes techniques for performing connection racing.  The Transport Services <del> Architecture implementation from I-D.ietf-taps-impl also describes how connections may race across interfaces and address families. In cases where clients have early data to send and want to minimize or avoid ticket re-use, unique tickets for each unique connection attempt are useful.  Moreover, as some servers may implement single-use tickets (and even session ticket encryption keys), distinct tickets will be needed to prevent premature ticket </del>  invalidation by racing. Connection priming: In some systems, connections may be primed or

Good catch -- will fix. Good suggestion! We can certainly add this. As the extension is merely a hint to servers when deciding how many tickets to vend, I think this is out of scope for the document. It's intended to be once per session, and we'll add that. Also a good catch. Like other extensions that are not affected by the possibly updated ClientHello, it must not change. We need to specify the server side behavior, too. That seems reasonable to me.
Thanks! Approved pending

Connection racing: Happy Eyeballs V2 RFC8305 describes techniques for performing connection racing.  The Transport Services  <ins> Architecture implementation from TAPS also describes how connections may race across interfaces and address families.  In cases where clients have early data to send and want to minimize or avoid ticket re-use, unique tickets for each unique connection attempt are useful.  Moreover, as some servers may implement single-use tickets (and even session ticket encryption keys), distinct tickets will be needed to prevent premature ticket </ins> invalidation by racing. Connection priming: In some systems, connections may be primed or


e.g., public key cryptographic operations, avoiding waste is desirable.  3. <del> Clients may indicate to servers their desired number of tickets via the following "ticket_request" extension: </del>  Clients may send this extension in ClientHello.  It contains the following structure:

e.g., public key cryptographic operations, avoiding waste is desirable. <ins> Decline resumption: Clients may indicate they have no intention of resuming connections by sending a ticket request with count of zero. </ins> 3.  <ins> Clients may indicate to servers their desired number of tickets for a single connection via the following "ticket_request" extension: </ins> Clients may send this extension in ClientHello.  It contains the following structure:


send more than 255 tickets to clients. Servers that support ticket requests MUST NOT echo "ticket_request" <del> in the EncryptedExtensions. </del>  4.

send more than 255 tickets to clients. Servers that support ticket requests MUST NOT echo "ticket_request"  <ins> in the EncryptedExtensions message.  A client MUST abort the connection with an "illegal_parameter" alert if the "ticket_request" extension is present in the EncryptedExtensions message. Clients MUST NOT change the value of TicketRequestContents.count in second ClientHello messages sent in response to a HelloRetryRequest. </ins> 4.


meaning that the server is not willing to receive any WebTransport sessions.  3.2. RFC8441 defines an extended CONNECT method in Section 4, enabled by

Require SETTINGSH3DATAGRAM and maxdatagramframe_size TP
Interesting thought. One way to do that replaces the entire section with this: This is certainly more concise, although it does also remove some of the explanations that help people understand the various layers involved. Or perhaps we should include those same additional details but just turn those paragraphs into bullets?
While technically true, I thought we'd said that we wanted to require all the features all of the time, but agreed, let's take that to an editorial issue if needed.
My point is that the server could support both regular HTTP and WebTransport. If a client comes in without webtransport settings and only sends GETs, that's fine. If a client comes in with webtransport settings and makes a webtransport request, that's fine. If a client comes in without webtransport settings and makes a webtransport request, that's not fine. In that case the server needs to reject the webtransport request, not kill the connection.
Ah, that makes more sense, thank you
Per discussion at IETF 114, we should explicitly require support for each layer of capabilities that are needed. There was also a discussion about whether or not we needed to require datagram support, since requiring capsules technically means that you could use a datagram capsule and implementations may exist that do not want to have datagram support at all. Documenting some of that discussion in replies to this issue, as well.
Specific to datagrams and capsules: WT supported means that capsule protocol is supported, thus you must always support capsules. Proposal: You need to have datagrams in order to do WT over HTTP/3 Adding additional signaling to negotiate datagram support introduces a lot of additional complexity and different configurations that may harm interoperability. Dropping a datagram is about as easy as doing any other error path HTTP Datagrams must already be supported in the receive direction for capsules (and you need capsules for WT) either way Intermediaries will need to be able to either translate for upstream or ensure that upstream can provide an equivalent feature set More generally: We want to explicitly call out dependencies/prerequisites so that we don't need to teach layers about other layers. For example, WT being supported doesn't mean that the layers that implement capsules, H3 datagrams, or QUIC datagrams should have any idea about the existence of WebTransport
Discussed at IETF 115, consensus in room to require all the relevant settings and transport parameters to be sent individually
So we need: HTTP Setting: SETTINGSH3DATAGRAM (0x33) with a value of 1 for HTTP datagrams QUIC TP: maxdatagramframesize with a value greater than 0 for QUIC datagrams Capsule protocol support is implicit in the upgrade token, as explicitly called out by RFC 9297 or we can require to be sent on every extended connect request as well. to be added to the existing HTTP Setting: SETTINGSENABLEWEBTRANSPORT = 1 HTTP Setting: SETTINGSWEBTRANSPORTMAXSESSIONS > 0 (although we may be removing SETTINGSENABLEWEBTRANSPORT)
SGTM I think we can skip mentioning Capsule-Protocol to match CONNECT-UDP
Would this be easier to process as a list rather than multiple separate requirements?The list text in that comment isn't correct - the server shouldn't close the connection because it's legal for the client to not support datagrams if it only sends GETs and POSTs. However, the text in this PR is correct. I propose we land the PR as-is and can make editorial changes later.

meaning that the server is not willing to receive any WebTransport sessions. <ins> Because WebTransport over HTTP/3 requires support for HTTP/3 datagrams and the Capsule Protocol, both the client and the server MUST indicate support for HTTP/3 datagrams by sending a SETTINGS_H3_DATAGRAM value set to 1 in their SETTINGS frame (see Section 2.1.1 of HTTP-DATAGRAM). WebTransport over HTTP/3 also requires support for QUIC datagrams. To indicate support, both the client and the server MUST send a max_datagram_frame_size transport parameter with a value greater than 0 (see Section 3 of QUIC-DATAGRAM). </ins> 3.2. RFC8441 defines an extended CONNECT method in Section 4, enabled by


From the client's perspective, a WebTransport session is established when the client receives a 200 response.  From the server's perspective, a session is established once it sends a 200 response. <del> Both endpoints MUST NOT open any streams or send any datagrams on a given session before that session is established.  WebTransport over HTTP/3 does not support 0-RTT. </del>  3.4.

.
cc NAME NAME
Looks great!
For a simple application that wants to send "hello world" over a WebTransport stream, it would take a minimum of 2.5 round trips for the data to arrive on the server. This is still an improvement over WebSockets but I'm wondering if we could do better. If the client is able to create streams prior to receiving the CONNECT response, then it would remove a round trip. The server would need to buffer any data received on streams associated with an unknown WebTransport session. If the server responds with a non-200 status code, then these streams are discarded. I believe 0-RTT is disabled for WebTransport because CONNECT is not idempotent and would be subject to replay attacks. An idempotent CONNECT would remove a round trip when 0-RTT is used... although I'm not sure this is a good idea.
I think this is a reasonable optimization
The client requirement is odd in comparison to MASQUE / CONNECT-UDP which says "client can risk sending datagrams before getting a 200 response, a different response means that datagrams will be discarded". What is the motivation for the requirement in WebTransport? If you need some kind of ordering guarantees, then stream IDs provide that.
Discussed at IETF 110. There were no objections to buffering (with some limits), so I think we should go ahead and add it.
After the client initiates the WebTransport session by sending a CONNECT request, the server sends a 200 response and is free to create streams. This means that a server-initiated stream may arrive prior to the CONNECT response. Is the client able to infer that the session was successfully established, or does the client need to buffer this stream until it receives a proper response?
Since there are no ordering guarantees across streams on the receiver side, I'd say you have to buffer until the 200 is processed.
I agree with Lucas here. We also had a similar problem in QuicTransport (server has to buffer streams before checking the origin), and we handled it by buffering.
Discussed at IETF 110. There were no objections to buffering (with some limits), so I think we should go ahead and add it.

From the client's perspective, a WebTransport session is established when the client receives a 200 response.  From the server's perspective, a session is established once it sends a 200 response.  <ins> WebTransport over HTTP/3 does not support 0-RTT. </ins> 3.4.