All protocol request messages contain a field, which allows aggregators to service multiple tasks from a single set of endpoints. The exception is : since it is an HTTP GET request, there is no body, and thus no place for the client to indicate the desired to the aggregator. We don't want to introduce a request body to , because then it would have to be a POST instead of a GET, and that would make it harder for implementations to cache HPKE config values. So instead we have clients encode the task ID in RFC 4648 Base16 (a.k.a. hexadecimal) and provide it as a query parameter. See issue
My goal here is to enable our aggregator implementations in the interop target to use one HPKE config per task. The alternative to this would be for us to use aggregator endpoints that somehow incorporate the task ID, as I described , which is already permitted by the spec as written.
The Base64 alphabet includes , and , which means you have to URL encode (a.k.a. percent encode) Base64 strings before you can use them in a URL, which is a chore and yields less readable URLs (not that 64 character hex strings is especially user-friendly). An alternative would be to use RFC 4648's , omitting the padding characters as suggested in since task IDs are of a known length.
Gotcha. I think the main thing is to be consistent. I would either: Change this PR to use base64url; or Tack on a commit that makes all encodings of the taskID (except those that appear in the body, of course) the same (i.e., hexadecimal). I think (2.) would be my preference.
I agree with the consistency argument. I'm leaning towards using everywhere because it's more compact than Base16/hex, and also I think implementations are less likely to be surprised by case requirements in base64url (i.e., it's obvious that base64 is case sensitive, but you have to read RFC 4648 attentively to notice that it mandates uppercase hex strings).
Base64Url sounds good to me. I took a quick look and it appears that most standard base64 libraries also support the URL encoding.
I will clean this up and merge it once I have implemented it in Janus and convinced myself it's sound.
SGTM, but why not base64 encode the taskID for consistency with URL


Justify text after bullets consistenly Make sure all lines break at 80 characters
LGTM, modulo conflicts. It'd be nice if we had a linter that blocked PRs until their formatting was right, since changes like this taint git history.


As of draft-irtf-cfrg-vdaf-05 (not yet published), the random coins used for sharding are an explicit parameter of . Add this parameter and explasin how it is generated.
NAME I believe this is the only API change we need to account for, correct?


All references to "metadata" are now to "report_metadata". References to "CollectReq" are now "CollectionReq". References to "CollectResp" are now "Collection".
The current version of the draft renames field "metadata" to "report_metadata" in the Report structure, but does not do the same renaming in the ReportShare and InputShareAad structures. I think this naming should be consistent, though I don't have a preference between the alternatives.
Thanks for pointing this out! Can you send prepare a PR?
Fixed in
Thanks a bunch NAME


Update the aggregate request text to reflect recent protocol changes. Relax the requirement that all sub-requests use the same key config. Do URL, which was previously merged into the wrong branch.
NAME NAME please have a look when you can.
Per , the first step in the upload protocol is a POST to the leader server which returns information about helpers. In some yet to be specified cases, the response could include a challenge to be incorporated into reports. However I suspect that in most cases, the response will be static and so an idempotent, cacheable GET would be a better fit, especially since it would save clients a roundtrip to the helper on the hot path of submitting reports, and would make it possible for helpers to implement uploadstart by putting some static content in a CDN. HTTP GET requests don't have bodies, so we would have to figure out how to encode all the data in the current into the URI, which could be done as either path fragments in the URI (i.e., ) or as query parameters (i.e., ). We would of course need to make sure that don't preclude proof systems like the one alleged to exist in section 5.2 of "BBCp19".
Also, because the current protocol uses a POST for uploadstart, the implication is that for every report they submit, clients need to hit and then . If we make idempotent and cacheable, then that request can be skipped in the majority of cases. I suppose the significance of this depends on how we expect clients to use PDA: are they going to be continuously streaming hundreds or thousands of reports into the leader as events of interest occur (in which case I think eliminating requests is interesting) or are they expected to accumulate several reports locally before submitting them all in one or a few requests?
I agree this would be a good change, if we can swing it. It's notable that Prio v2 and HH don't require a random challenge from the leader. But as discussed, this is useful for other proof systems one might want to implement for Prio. For example, see the data type implemented here: URL See below for an explanation. There might be other ways to implement the challenge. One possibility is to derive the challenge from the TLS key schedule (or from whatever state the client and leader share for the secure channel). NAME and NAME have both pointed out that adding this dependency on the underlying transport is problematic. Another possibility might be to use some external source of randomness that the leader trusts. comes to mind, though it is somewhat problematic because clients would effectively use the same randomness for some period of time. The security model of BBCp19 would need to be extended to account for this. (I believe this could be done.) Some other solution I'm missing? _ This data type is used to compute the mean and variance of each integer in a sequence of integers. To do so, the client encodes each integer of its input vector as a pair , where is the representation of as a bit vector and is equal to . To prove validity of its input, the proof needs to do two things: verify that (a) is indeed a bit vector, and (b) the integer encoded by is the square root of . In order to check these things efficiently, the proof system uses a random challenge generated by the leader. At a very high level, the client wants to prove that the following boolean conjunction holds: is 1 or 0 AND is 1 or 0 AND ... AND encodes the square root of . In Prio, we need to represent this conjunction as an arithmetic circuit, which the random challenge helps us do. In a bit more detail now: Let's rewrite this expression as w[0] AND w[1] AND ... AND w[s]. As an arithmetic circuit, this expression is actually , where if and only if w[i] is true. If the input is valid, then the expression should evaluate to . But because we're talking about field elements, a malicious client may try to play games like setting and so that the sum is still , but the statement is false. To detect this, we actually compute the following expression: , where is a randomly chosen field element. If the statement is true, then the expression evaluates to . If the statement is false, then with high probability, the expression will evaluate to something other than . (This idea comes from Theorem 5.3)
Thank you for the detailed explanalation NAME Having thought about it more, I suspect an HTTP GET wouldn't be the right way to support proof systems that need a challenge. Assuming that a unique challenge is needed for every report[^1], then intuitively the leader would have to maintain a mapping of reports to issued challenges so that the leader and helper(s) can later use the challenge value when evaluating the client's proof. But now that the leader has to maintain state per-report, I think the upload protocol is missing a notion of a report identifier. The contains a , but IIUC the will be the same across many reports[^2] (e.g., if a browser is sending daily reports on how often users click a button, they use the same every time they submit). So needs to include a report ID, which must be echoed back to the leader in so that the leader can look up the challenge for the report. [^1] Is this true? Or would it suffice for each to use the same challenge across multiple reports? [^2] I notice that the design doc lacks a strong definition of a report and how it relates to tasks, inputs, measurements: because GET should be "safe" in the sense of not changing any server state, and it seems like the server would have to maintain a mapping of reports to issued challenges so that the leader and helper can later use the challenge value when evaluating the client's proof.
Continuing on the assumption that causes a state change on the leader, POST is then the appropriate HTTP method to use. , though it's a little unusual. There may be some big drawback to cacheable POST responses, but I think that might let us support proof systems that require live challenges while also eliminating the majority of requests when the proof system is such that the will change very rarely.
The requirement for the leader to keep state across upload start and upload finish may be avoidable. Suppose the leader has a long-lived PRF key K. It would could choose a random nonce N, compute R = PRF(K, N) as the challenge, and hand (N, R) to the client in its upload start response. The client would then use R to generate the proof and send N to the leader in its upload finish request. The leader could then re-derive R. NAME and I kicked around the idea of having the client generate a report ID. I think this may end up being useful, but we weren't sure if it was better to have the leader choose it or the client. To conform to the security model of BBCp19, each report would need its own challenge. It may be possible to relax this, but this would be risky.
I like this a lot! I'm a big fan of deterministic derivation schemes like this -- besides reintroducing the possibility of an idempotent GET, eliminating storage requirements for challenges makes it much easier to scale up leaders. If the report IDs are big enough (UUIDs?) we could even use them as . I would say the leader, because if you let the client do it, then the leader would have to check for things like collisions with existing report IDs or other malicious ID choices. If the leader chooses it, then all it has to do is generate a few bytes of randomness. I agree.
NAME we'd appreciate your feedback on this issue because it involves security considerations for ZKP systems on secret-shared data [1]. I'll quickly sum up the problem so that you don't need to worry about the conversation above. The problem at hand regards systems like [1, Theorem 5.3] that require interaction between the prover and verifier. Specifically, we're considering a special case of Theorem 5.3 in which the verifier sends the prover a random "challenge" that is used to generate and verify a (non-interactive) FLPCP (call it ): We refer to the prover's first and second messages as "upload start" and "upload finish" respectively. Each message corresponds to an HTTP request made by a web client to a web server. Ideally, the verifier would be able to handle these requests statelessly, i.e., without having to store . Consider the following change. Suppose the verifier has a long-term PRF key . In response to an upload start request, it chooses a unique "upload id" --- maybe this is a 16-byte integer chosen at random --- and computes and sends to the prover. In the upload finish request, the prover sends so that the verifier can re-derive instead of needing to remember it: The (potential) problem with this variant is that a malicious client is able to replay a challenge as many times as it wants. This behavior isn't accounted for in Definition 3.9, so when you try to "compile" this system into a ZKP on secret-shared data as described in Section 6.2 and consider its security with respect to Definition 6.4 (Setting I), you can no longer appeal to Theorem 6.6 to reason about its security. Our question is therefore: What impact do you expect this change to have on the soundness of the system? Can you think of an attack that exploits the fact that challenges can be replayed? My expectation is that the problem is merely theoretical, i.e., we ought to be able to close the gap with an appropriate refinement of Definition of 3.9 and reproving Theorem 5.3. [1] URL
Thanks for looping me in. In the discussion below, I am assuming that the client sends its data vector (called "x" in the paper [1]) at the same time as it sends its proof to the verifier. Even if the client sends its data vector in the first message, it seems that the client can reuse an (R,N) pair from upload request 1 to later submit upload request 2, in which case the client sees (R, N) before it chooses its data vector and proof. So I think we can assume that the client's data vector and proof can depend on the verifier's random value R. (I'll call this value "r" to match the paper.) For soundness: the client/prover must commit to its data vector before it learns the verifier's random value r. If the prover can choose its data value and proof in a way that depends on the verifier's randomness r, the soundness guarantee no longer holds. There is also an efficient attack. So I suspect that the stateless-verifier optimization is unsound. The attack works as follows: given r, the verifier finds a non-satisfying vector x such that sumi ri C(Ai(x)) = 0, again using the notation from Theorem 5.3 in the paper [1]. For the circuits C used in most applications, it will be easy to find such a vector x. Then, the prover constructs a proof that x that sumi ri C(Ai(x)) = 0. The proof is valid, so the verifier will accept always. To remove interaction, the Fiat-Shamir-like technique in Section 6.2.3 is probably the best way to go. We only sketched the idea in the paper (without formal analysis or proof) but if it's going to be important for your application, I'm happy to sanity-check the protocol you come up with. Another idea—the details of which I have not checked carefully—would be to modify your protocol as follows: The prover sends its data vector x to verifiers, split into k shares x1, ..., xk—one for each of the k verifiers. Each verifier holds a PRF key ki computes ri = PRF(ki, xi) and they return r = r1 + ... + rk to the prover. The verifiers store no state. The prover computes the proof pi and sends (x1, pi1), ..., (xk, pik) to the verifiers—again, one for each of the k verifiers. Each verifier computes ri = PRF(ki, xi), they jointly compute r = r1 + ... + r_k, and check the proof using randomness r. The Fiat-Shamir-like approach seems slightly cleaner to me, since it only requires a single prover-to-verifier message. Either way, please let me know if I misunderstood your question or if anything else here is unclear. [1] URL
Thanks for the nice explanation, Henry. It's perfectly clear and answers my question. It also points to something that I, for one, missed the importance of: the need for the prover to "commit" to the input shares before generating the r-dependent proof. I appreciate you pointing this out. The only requirement for making upload start not idempotent is so that the randomness r can be sent to the client. It would be nice to do away with this requirement. I think the way forward is using the Fiat-Shamir technique. NAME I'll get cracking on this and let you know when I have something for you to look at.
NAME I believe the change is something like this. Let be a hash function with range . Suppose there are verifiers. The prover proceeds as follows: Splits its inputs into shares . For each , do: Choose blinding factor from at random. Let . Set . Derive field element from (e.g., seed a PRNG with and map the output to a field element by rejection sampling on chunks of the output). Generate the proof using and . Split into shares . For each send to the -th verifier.
Yes, this looks right to me!
As of URL, the upload start request no longer exists. When we're ready to specify Prio, we'll want to include the Fiat-Shamir approach for protocols that use joint randomness. I've noted this and am closing the issue.


I added a clarification that the nonce is random. IMO the question of who randomly generates the nonce goes with the question of how participants agree upon PDAParams, which is to say it's outside the protocol.
On the 2021/7/7 design call we decided that the ID should be derived deterministically from the serialized PAParam by, for example, hashing it. This solves a few problems simultaneously. This settles the question of whether there should be 1:1 correspondence between a task ID and the parameters used for that task. NAME brought up an interesting question, which is how to make the task ID unique when two different data collection tasks use the same parameters. Thoughts?
The consensus here is to do SHA-256 over the PDAParams structure and use that as the 32 byte PDATaskID. However, hashing a protocol message requires us to decide on a canonical representation of a protocol message, which I think forces us to decide how to encode messages on the wire. I filed for that question. I'll proceed with a PR for this issue on the assumption that we'll pick JSON.
As I mentioned there, the assumption would be that we're adopting TLS' binary encoding. If so, in TLS notation, you would write as the hash of , which itself is a serialized data structure.
All we require is that each PAParam have some unique value, right? A random nonce would probably suffice. r.e. the encoding, yes, let's stick with TLS's wire format as NAME suggests.
Yes, my thinking was that we would just stick 16 bytes of random data in (a UUID's worth). I agree that we should stick with TLS binary encoding.
Approved, with the following suggestion: Let's leave a [TODO: ...] comment under the definition of for clarifying how it should be chosen.


… in diagram. Also fixed "randomized" (was British English before). Signed-off-by: Michael Eckel
An handle mustbe created/generated before it can be distributed. Adding a generateHandle() call would also strengthen understanding by readers.
Based on URL In the sequence diagram, some elements in the bracket are not defined in the “Information Elements” section, such as targetEnvironment, collectedClaims, eventLog. Should these elements be defined?
I totally agree. These elements should either be put into Information elements (preferred), or at least be mentioned in the text. Hi Henk, I've reviewed the reference interaction models I-D recently, I hope the comments below can help improve the draft before the IETF110 draft submission cut-off. Section 3 Disambiguation Comment > This section is talking about the disambiguation of terminology, so I suggest making it a sub-section of Section 2 Terminology. Examples of these types of co-located environments include: a Trusted Execution Environment (TEE), Baseboard Management Controllers (BMCs), as well as other physical or logical protected/isolated/shielded Computing Environments (e.g. embedded Secure Elements (eSE) or Trusted Platform Modules (TPM)). Comment > About "these types of co-located environments", The previous sentences are about the Verifier and Attester don't need to be remote. So "these" is weird here, because here is about the attesting environment and target environment. Section 5 Direct Anonymous Attestation Comment > I think it's better to move this section to the bottom of the draft. DAA doesn't introduce a new information elements, and only augments the scope/definition of Attester Identity and Authentication Secret IDs, describing it after the introduction of all the 3 basic interaction models would be better. Putting DAA in the middle makes me feel the basic interaction models rely upon DAA, but actually it's not. This document extends the duties of the Endorser role as defined by the RATS architecture with respect to the provision of these Attester Identity documents to Attesters. The existing duties of the Endorser role and the duties of a DAA Issuer are quite similar as illustrated in the following subsections. Comment > Without DAA, I think the Endorser also needs to provision the Attester Identity to Attesters. And as I understand, the DAA Issuer is a supply chain entity before the Attester being shipped, so it is the Endorser when DAA is used, right? If yes, then in the next sentence, the comparison between Endorser and DAA Issuer doesn't make sense to me. Section 5.1 Endorsers Comment > Does this section have difference with the definition of Endorser in architecture draft? If not, is it necessary to keep this section? Comment > This section only describes the Layered Attestation, but the scope of Endorsement is more than what's described here. Endorsement indicates the Attester's various capabilities such as Claims collection and Evidence signing. For other situations than Layered Attestation, the Endorser and Endorsement are also needed. So why only mention Layered Attestation here? I don't see any special relationship between DAA and Layered Attestation. Section 5.2 Endorsers for Direct Anonymous Attestation In order to enable the use of DAA, an Endorser role takes on the duties of a DAA Issuer in addition to its already defined duties. DAA Issuers offer zero-knowledge proofs based on public key certificates used for a group of Attesters [DAA]. Effectively, these certificates share the semantics of Endorsements, with the following exceptions: Comment > In the first sentence, I suggest saying that "a DAA Issuer takes on the role of an Endorser". o The associated private keys are used by the DAA Issuer to provide an Attester with a credential that it can use to convince the Verifier that its Evidence is valid. To keep their anonymity the Attester randomizes this credential each time that it is used. Comment > How to understand "Evidence is valid"? Does it mean the Evidence is sent from an authentic Attester and not tampered during the conveyance? Or does it mean the Evidence comes from a RoT and is trustable (although the Evidence can diverge from the Reference Values)? Comment > When saying "Attester randomizes this credential", how many credentials does an Attester have? 1) Can a DAA Issuer have multiple key pairs and use them for one Attester? 2) Can a DAA Issuer use one key pair to generate multiple credentials for one Attester? o A credential is conveyed from an Endorser to an Attester in combination with the conveyance of the public key certificates from Endorser to Verifier. Comment > Is there another way to convey the public key certificate, for example, can the public key certificates be conveyed from Endorser to Attester first and then from Attester to Verifier? The zero-knowledge proofs required cannot be created by an Attester alone - like the Endorsements of RoTs - and have to be created by a trustable third entity - like an Endorser. Due to that semantic overlap, the Endorser role is augmented via the definition of DAA duties as defined below. This augmentation enables the Endorser to convey trustable third party statements both to Verifier roles and Attester roles. Comment > For "the definition of DAA duties as defined below", what is the definition of DAA duties? Comment > In the last sentence, the Endorsement with its original definition is the third party statement for Verifier and Attester, isn't it? So, "augmentation" isn't the correct expression. Section 6 Normative Prerequisites Attester Identity: The provenance of Evidence with respect to a distinguishable Attesting Environment MUST be correct and unambiguous. Comment > The Attester Identity is to identify which Attester the Evidence comes from. But if the Attester has multiple Attesting Environments, what should be the Attester Identity? Comment > The TPM's AIK certificate is one kind of Attester Identity, right? Attestation Evidence Authenticity: Attestation Evidence MUST be correct and authentic. Comment > Is it appropriate to say "correct Evidence"? If saying so, I think it means that the Evidence satisfies the Attestation Policy for Evidence. Authentication Secret: An Authentication Secret MUST be available exclusively to an Attester's Attesting Environment. The Attester MUST protect Claims with that Authentication Secret, thereby proving the authenticity of the Claims included in Evidence. The Authentication Secret MUST be established before RATS can take place. Comment > Does the Authentication Secret represent the identity of the Attesting Environment? Comment > How to understand the Authentication Secret, and is it necessary all the time? For example, in our implementation, during the router booting up, the BIOS measures the BootLoader and records the measured hash value into the TPM, and the BootLoader measures the OS Kernel and records the measured hash value into the TPM as well. From the Layered Attestation perspective, I think (BIOS + TPM) is the Attesting Environment and (BootLoader + TPM) is also the Attesting Environment. But the Claims (measured hash values) aren't protected separately, and they finally becomes the Evidence (TPM Quote) and it's only protected by the TPM's AIK. So, what is the Authentication Secret? Section 7 Generic Information Elements Attester Identity ('attesterIdentity'): mandatory A statement about a distinguishable Attester made by an Endorser without accompanying evidence about its validity - used as proof of identity. Comment > Previous section says "Attester Identity" is about "a distinguishable Attesting Environment", and here says it's about "a distinguishable Attester". Comment > How to understand "without accompanying evidence about its validity"? Attester Identity ('attesterIdentity'): mandatory In DAA, the Attester's identity is not revealed to the verifier. The Attester is issued with a credential by the Endorser that is randomized and then used to anonymously confirm the validity of their evidence. The evidence is verified using the Endorser's public key. Comment > I think here means the DAA credential represents the Attester Identity. Comment > There is ambiguity of "that is randomized", does it mean randomized Endorser or randomized credential? Comment > For "confirm the validity of their evidence", what does "their" refer to? And what does "the validity of evidence" mean? Authentication Secret IDs ('authSecID'): mandatory A statement representing an identifier list that MUST be associated with corresponding Authentication Secrets used to protect Evidence. Comment > Previous section says "Authentication Secret" is used to protect Claims, but here says it's used to protect Evidence. Comment > As I understand, if Authentication Secret represents the identity of Attesting Environment, then it's not mandatory, at least in our implementation. Authentication Secret IDs ('authSecID'): mandatory In DAA, Authentication Secret IDs are represented by the Endorser (DAA issuer)'s public key that MUST be used to create DAA credentials for the corresponding Authentication Secrets used to protect Evidence. In DAA, an Authentication Secret ID does not identify a unique Attesting Environment but associated with a group of Attesting Environments. This is because an Attesting Environment should not be distinguishable and the DAA credential which represents the Attesting Environment is randomised each time it used. Comment > In my understanding, here says that the DAA credential identities the Attesting Environment. Compared with the description in the "Attester Identity" part, what does the DAA credential represent actually? Reference Claims ('refClaims') mandatory Reference Claims are components of Reference Values as defined in [I-D.ietf-rats-architecture]. [Editor's Note: Definition might become obsolete, if replaced by Reference Values. Is there a difference between Claims and Values here? Analogously, why is not named Reference Claims in the RATS arch?] Comment > I suggest using Reference Values to keep consistent with the RATS arch. Reference Claims are used to appraise the Claims received from an Attester via appraisal by direct comparison. Comment > "Direct comparison" isn't the correct expression, the comparison can have other rules. Claim Selection ('claimSelection'): optional A statement that represents a (sub-)set of Claims that can be created by an Attester. Claim Selections can act as filters that can specify the exact set of Claims to be included in Evidence. An Attester MAY decide whether or not to provide all Claims as requested via a Claim Selection. Comment > The "all Claims" may be ambiguous, I'd like to double check, does it refer to all Claims that the Attester can create or refer to all Claims requested in the Claim Selection? Section 8.1 Challenge/Response Remote Attestation Comment > In the sequence diagram, some elements in the bracket are not defined in the "Information Elements" section, such as targetEnvironment, collectedClaims, eventLog. Should these elements be defined? Section 9 Additional Application-Specific Requirements Depending on the use cases covered, there can be additional requirements. An exemplary subset is illustrated in this section. Comment > Here starts to talk about "additional requirements", but I wonder there is no other places in this draft talking about requirement, so what are the basic requirements? Regards & Thanks! Wei Pan


Signed-off-by: Michael Eckel
Based on URL Previous section says “Attester Identity” is about “a distinguishable Attesting Environment”, and here says it’s about “a distinguishable Attester”.
How to understand “without accompanying evidence about its validity”?
I think it means that there is no certificate conveyed along with it which proves its validity.
I think this is related to and should be fixed.
Based on URL The Attester Identity is to identify which Attester the Evidence comes from. But if the Attester has multiple Attesting Environments, what should be the Attester Identity?
The TPM’s AIK certificate is one kind of Attester Identity, right?
"The TPM’s AIK certificate is one kind of Attester Identity, right?": Correct.
"The Attester Identity is to identify which Attester the Evidence comes from. But if the Attester has multiple Attesting Environments, what should be the Attester Identity?" I see the point, too, and agree. So, perhaps it should be renamed to "Attesting Environment identity"!? The Attester Identity then should be something different. It may be the TPM AK/AIK of one of the Attesting Environments, but not necessarily.
As discussed, polish can happen later Hi Henk, I've reviewed the reference interaction models I-D recently, I hope the comments below can help improve the draft before the IETF110 draft submission cut-off. Section 3 Disambiguation Comment > This section is talking about the disambiguation of terminology, so I suggest making it a sub-section of Section 2 Terminology. Examples of these types of co-located environments include: a Trusted Execution Environment (TEE), Baseboard Management Controllers (BMCs), as well as other physical or logical protected/isolated/shielded Computing Environments (e.g. embedded Secure Elements (eSE) or Trusted Platform Modules (TPM)). Comment > About "these types of co-located environments", The previous sentences are about the Verifier and Attester don't need to be remote. So "these" is weird here, because here is about the attesting environment and target environment. Section 5 Direct Anonymous Attestation Comment > I think it's better to move this section to the bottom of the draft. DAA doesn't introduce a new information elements, and only augments the scope/definition of Attester Identity and Authentication Secret IDs, describing it after the introduction of all the 3 basic interaction models would be better. Putting DAA in the middle makes me feel the basic interaction models rely upon DAA, but actually it's not. This document extends the duties of the Endorser role as defined by the RATS architecture with respect to the provision of these Attester Identity documents to Attesters. The existing duties of the Endorser role and the duties of a DAA Issuer are quite similar as illustrated in the following subsections. Comment > Without DAA, I think the Endorser also needs to provision the Attester Identity to Attesters. And as I understand, the DAA Issuer is a supply chain entity before the Attester being shipped, so it is the Endorser when DAA is used, right? If yes, then in the next sentence, the comparison between Endorser and DAA Issuer doesn't make sense to me. Section 5.1 Endorsers Comment > Does this section have difference with the definition of Endorser in architecture draft? If not, is it necessary to keep this section? Comment > This section only describes the Layered Attestation, but the scope of Endorsement is more than what's described here. Endorsement indicates the Attester's various capabilities such as Claims collection and Evidence signing. For other situations than Layered Attestation, the Endorser and Endorsement are also needed. So why only mention Layered Attestation here? I don't see any special relationship between DAA and Layered Attestation. Section 5.2 Endorsers for Direct Anonymous Attestation In order to enable the use of DAA, an Endorser role takes on the duties of a DAA Issuer in addition to its already defined duties. DAA Issuers offer zero-knowledge proofs based on public key certificates used for a group of Attesters [DAA]. Effectively, these certificates share the semantics of Endorsements, with the following exceptions: Comment > In the first sentence, I suggest saying that "a DAA Issuer takes on the role of an Endorser". o The associated private keys are used by the DAA Issuer to provide an Attester with a credential that it can use to convince the Verifier that its Evidence is valid. To keep their anonymity the Attester randomizes this credential each time that it is used. Comment > How to understand "Evidence is valid"? Does it mean the Evidence is sent from an authentic Attester and not tampered during the conveyance? Or does it mean the Evidence comes from a RoT and is trustable (although the Evidence can diverge from the Reference Values)? Comment > When saying "Attester randomizes this credential", how many credentials does an Attester have? 1) Can a DAA Issuer have multiple key pairs and use them for one Attester? 2) Can a DAA Issuer use one key pair to generate multiple credentials for one Attester? o A credential is conveyed from an Endorser to an Attester in combination with the conveyance of the public key certificates from Endorser to Verifier. Comment > Is there another way to convey the public key certificate, for example, can the public key certificates be conveyed from Endorser to Attester first and then from Attester to Verifier? The zero-knowledge proofs required cannot be created by an Attester alone - like the Endorsements of RoTs - and have to be created by a trustable third entity - like an Endorser. Due to that semantic overlap, the Endorser role is augmented via the definition of DAA duties as defined below. This augmentation enables the Endorser to convey trustable third party statements both to Verifier roles and Attester roles. Comment > For "the definition of DAA duties as defined below", what is the definition of DAA duties? Comment > In the last sentence, the Endorsement with its original definition is the third party statement for Verifier and Attester, isn't it? So, "augmentation" isn't the correct expression. Section 6 Normative Prerequisites Attester Identity: The provenance of Evidence with respect to a distinguishable Attesting Environment MUST be correct and unambiguous. Comment > The Attester Identity is to identify which Attester the Evidence comes from. But if the Attester has multiple Attesting Environments, what should be the Attester Identity? Comment > The TPM's AIK certificate is one kind of Attester Identity, right? Attestation Evidence Authenticity: Attestation Evidence MUST be correct and authentic. Comment > Is it appropriate to say "correct Evidence"? If saying so, I think it means that the Evidence satisfies the Attestation Policy for Evidence. Authentication Secret: An Authentication Secret MUST be available exclusively to an Attester's Attesting Environment. The Attester MUST protect Claims with that Authentication Secret, thereby proving the authenticity of the Claims included in Evidence. The Authentication Secret MUST be established before RATS can take place. Comment > Does the Authentication Secret represent the identity of the Attesting Environment? Comment > How to understand the Authentication Secret, and is it necessary all the time? For example, in our implementation, during the router booting up, the BIOS measures the BootLoader and records the measured hash value into the TPM, and the BootLoader measures the OS Kernel and records the measured hash value into the TPM as well. From the Layered Attestation perspective, I think (BIOS + TPM) is the Attesting Environment and (BootLoader + TPM) is also the Attesting Environment. But the Claims (measured hash values) aren't protected separately, and they finally becomes the Evidence (TPM Quote) and it's only protected by the TPM's AIK. So, what is the Authentication Secret? Section 7 Generic Information Elements Attester Identity ('attesterIdentity'): mandatory A statement about a distinguishable Attester made by an Endorser without accompanying evidence about its validity - used as proof of identity. Comment > Previous section says "Attester Identity" is about "a distinguishable Attesting Environment", and here says it's about "a distinguishable Attester". Comment > How to understand "without accompanying evidence about its validity"? Attester Identity ('attesterIdentity'): mandatory In DAA, the Attester's identity is not revealed to the verifier. The Attester is issued with a credential by the Endorser that is randomized and then used to anonymously confirm the validity of their evidence. The evidence is verified using the Endorser's public key. Comment > I think here means the DAA credential represents the Attester Identity. Comment > There is ambiguity of "that is randomized", does it mean randomized Endorser or randomized credential? Comment > For "confirm the validity of their evidence", what does "their" refer to? And what does "the validity of evidence" mean? Authentication Secret IDs ('authSecID'): mandatory A statement representing an identifier list that MUST be associated with corresponding Authentication Secrets used to protect Evidence. Comment > Previous section says "Authentication Secret" is used to protect Claims, but here says it's used to protect Evidence. Comment > As I understand, if Authentication Secret represents the identity of Attesting Environment, then it's not mandatory, at least in our implementation. Authentication Secret IDs ('authSecID'): mandatory In DAA, Authentication Secret IDs are represented by the Endorser (DAA issuer)'s public key that MUST be used to create DAA credentials for the corresponding Authentication Secrets used to protect Evidence. In DAA, an Authentication Secret ID does not identify a unique Attesting Environment but associated with a group of Attesting Environments. This is because an Attesting Environment should not be distinguishable and the DAA credential which represents the Attesting Environment is randomised each time it used. Comment > In my understanding, here says that the DAA credential identities the Attesting Environment. Compared with the description in the "Attester Identity" part, what does the DAA credential represent actually? Reference Claims ('refClaims') mandatory Reference Claims are components of Reference Values as defined in [I-D.ietf-rats-architecture]. [Editor's Note: Definition might become obsolete, if replaced by Reference Values. Is there a difference between Claims and Values here? Analogously, why is not named Reference Claims in the RATS arch?] Comment > I suggest using Reference Values to keep consistent with the RATS arch. Reference Claims are used to appraise the Claims received from an Attester via appraisal by direct comparison. Comment > "Direct comparison" isn't the correct expression, the comparison can have other rules. Claim Selection ('claimSelection'): optional A statement that represents a (sub-)set of Claims that can be created by an Attester. Claim Selections can act as filters that can specify the exact set of Claims to be included in Evidence. An Attester MAY decide whether or not to provide all Claims as requested via a Claim Selection. Comment > The "all Claims" may be ambiguous, I'd like to double check, does it refer to all Claims that the Attester can create or refer to all Claims requested in the Claim Selection? Section 8.1 Challenge/Response Remote Attestation Comment > In the sequence diagram, some elements in the bracket are not defined in the "Information Elements" section, such as targetEnvironment, collectedClaims, eventLog. Should these elements be defined? Section 9 Additional Application-Specific Requirements Depending on the use cases covered, there can be additional requirements. An exemplary subset is illustrated in this section. Comment > Here starts to talk about "additional requirements", but I wonder there is no other places in this draft talking about requirement, so what are the basic requirements? Regards & Thanks! Wei Pan


Addressed the following comments: [Per IETF 110] Add text on the order of native CDDL approach for handling version is used. If a future version of SWID is published which alters the semantics of exists fields, a future version of CoSWID SHOULD (MUST?) use a different tag to represent it. [daw: A new paragraph was added to section 2 detailing how index values are used to support revisions and extensions.] [Per IETF 110] see -16. Use ISO SWID reference for the IANA registry and if desired, used [SEMVER] as an informal reference in the text [daw: This has been done in section 4.1.] [daw: The FIXME markers have been replaced with actual text.] [daw: Section 7 now details the construction of a signed CoSWID. A SHOULD sign requirement was also added to section 7.] [Per IETF 110] We discussed adding language on the order of "This document specifies a data format and an associated integrity mechanism agnostic of a deployment. Application which choose to use CoSWID will need to specify explicit guidance which security properties are needed and under which circumstances." > ** [-15] Section 6. Per "When an authoritative tag is signed, the software [daw: Authenticating the signer is the software provider will require a match between a CoSWID entity and the signer. We are working out a means to do this.] 2 [daw: Not sure which tags this applies to? Signing? All of section 2?] [daw: done.] [daw: This confusing text has been removed.] [daw: done.] [daw: We added a note about this.] [daw: Done.] [daw: Added signature validation as a way.] Regards, Roman


Completes
We collapsed IKEv2 and ESP into IPsec. Should we remove ESP from feature lists, e.g., the list of protocols that support PSK import?
Agreed, we should make sure this is consistent. One of our features, Key Expiration, currently only mentions ESP though. Is this actually an IPsec feature now, do we remove the feature, or is there another solution?


…/security and security/transport dependencies.
NAME can you please take a look before Wednesday?
Yep, I will review Monday morning.
I think this is fine. We can do further tweaks in subsequent PRs.


This PR looks good to me.
cTLS enumerates keys in the template, but does not explain how templates can be extended. Suggestion: Clients must reject the whole template if it contains any key they do not understand. The “optional” key holds a map of optional extensions that are safe to ignore.
Thanks for addressing your own issue with a PR. Creating an IANA registry for the keys used in the configuration data makes sense. I would, however, like to point out (and maybe we need to make this explicit) that the configuration information is defined for convenience but is not a mandatory-to-implement functionality for a stack.
Sure, some use cases can pre-arrange, or even hardcode, a specific configuration through a nonstandard channel. Some use cases (where the client and server are developed separately) obviously cannot.


FYI, this PR now moves out of the ClientHello back into (now called ). This avoids confusing questions about how to demultiplex profiles that use different modes.
LGTM.
This would allow recipients to detect the end of a handshake message from the CTLSPlaintext header alone, allowing the recipient to reconstruct the entire handshake message before parsing it. Currently, a streaming parser is required in order to detect the end. Suggested implementation: Senders set contenttype = ctlshandshake_end for a message’s final fragment.
I can see why you want that, but it's not generally a TLS property, and I'm reluctant to change things.
AFAIK, TLS does not require a streaming ClientHello parser. The recipient can read (uint24) and then buffer the remainder before parsing. cTLS, as currently specified, does not have . This means that the recipient has to cross all the way down into the extension parsing code before it finds out that the ClientHello is still incomplete. Given the complex template-driven handshake parsing code, I think making a streaming parser required is ill-advised. Given the desire for compactness, I think a flag of some kind on the final handshake message record seems like a reasonable solution, replacing the uint24 length. It would also simplify Pseudorandom cTLS. However, if that's not appealing, you could simply reintroduce .
NAME proposed a solution on slide 5 : I'm fine with that, so long as it doesn't end up requiring recipients to do something heroic to reconstruct the ClientHello. Thus, "framing = none" should imply that messages cannot be fragmented at all (max size limited to 2^14-1). I'm not sure I see the utility of the explicit distinction between "length" and "full". Surely "length" is not usable with DTLS due to reordering, and "full" is redundant in TLS/TCP. Perhaps we only need a single bit to enable/disable framing, and length-vs-full can be implicit from the transport.
I could live with this. Objections?
Solved by
The current text doesn’t mention this, although it seems relatively clear how it’s expected to work (using the DTLS Handshake struct).


We have decided to moved the compressed elliptic curve representations to an external draft since the issue is equally applicable to regular TLS/DTLS and does not need to be cTLS specific.
NAME It looks like you need to run .
It seems that we have consensus to move compressed representations into new IANA codepoints, rather than try to reuse the existing codepoints with a template-driven encoding. That would make the question of compressed representations orthogonal to cTLS, so this topic can be removed from the draft.
Fixed by


NAME NAME please have a look.
We also need to specify server-side HRR behavior, right? Specifically, the server MUST recheck the second ClientHello's ESNI extension before sending the server certificate, otherwise putting the key share into the AD field doesn't really mean anything. The attacker would be able to do a cut-and-paste thing. (We could also incorporate the nonce into key schedule, but that upsets the document's split mode use case.)
Yep! Thanks for bringing that up. I'll prepare text.
Thank you for the text. LGTM.


Because this document now delegates the way the keys are advertised from the RRType ESNI to HTTPSSVC shouldn't the RRType Considerations be removed from this document.


I've tried to capture what I think is a reasonable way to handle padding now we've changed from ESNI->ECHO. If we could do something like this, that'd be better than what's in -06. Note that I'd be even happier if we entirely eliminated ECHOConfig.minimuminnerlength - I don't think it actually adds any value and it represents yet another way to get a configuration wrong.
Thanks for the fixes. On the general point, I think that if we keep the flexibility for the client to vary the inner/outer CH however it chooses, then we will also have to depend on clients to figure out how to pad well for whatever they do. If we constrain the inner/outer variance a lot, then we could do better. It also strikes me that the minimuminnerlength is sort of in tension with the idea of compression - if a server has to set the minimuminnerlength to 300ish to handle clients that don't compress, then clients that do compress either don't get the benefit or have to ignore the minimuminnerlength.
I don't think this PR works. The server does not have enough information to report a useful value, and the value the server reports is not useful to maintain good anonymity sets. The server does not know that the client supports some large extension or key share type (or lots of cipher suites, ALPN protocols, etc). are especially fun. It also doesn't know which extensions the client will compress from the outer ClientHello and which it will reencode. Conversely, the value the server sets isn't useful. If the client implementation has a smaller baseline compression and extensions, we waste bytes without much benefit. Worse, if the client implementation has a larger baseline compression and extensions, this PR regresses anonymity. The ClientHello will then exceed and we don't hide the lengths of the sensitive bits. Stepping back, we want to hide the distribution of ClientHelloInner lengths within some anonymity set. Most of the contributors to that length come from local client configuration: how many ciphers you support, what ALPN protocols, etc. The client is the one that knows, e.g., it sometimes asks servers for protocols A and B and sometimes for A and C. It largely has enough information to pad itself. The main exception is the server name. Realistically we need to trim anonymity sets down to colocated services, and the client doesn't know that distribution of names. Thus, we want servers to report the value in ECHOConfig. Maybe we'll need more such statistics later, which is what extensions are for. It's annoying this is a bit complicated, but we've signing up to encrypt far more things now. I should note this presumes an anonymity set of similarly-configured clients. I think, realistically, that's all we can say rigorous things about. It's nice to reduce visible artifacts of configuration, which is why we additionally round up to multiples of 16, but that's something we can burn into the protocol without ECHOConfig support.
Hiya, Sorry, not seeing that last. The PR just says (or was meant to say) to pad to some multiple of 16 in that case which I agree isn't much guidance, but does allow doing something that works. (As well as allowing things that don't work well;-) I agree that all this really needs to be driven by the client. Well, yes and no. I don't believe a server config is useful for that, (as I've argued before and still do;-) ISTM the max server name value will almost always be set to 254. May as well tell the client to pad as do that IMO. Not quite sure if I agree with that last para or not TBH! S.
Well, if we were satisfied just padding names to a multiple of 16, we wouldn't need any of this. We'd just say to pad to a multiple 16 and move on. :-) In the current name-focused spelling, the client is always able to apply a smarter padding decision based on the server's knowledge of the name distribution. With this PR, clients whose local configuration exceeds or is near lose this and hit the baseline multiple of 16 behavior. Clients whose local configuration is decently below do hide the name distribution, but using many more bytes than they would with the current text. We have some metrics in Chrome on the distribution of DNS names. It's nowhere near 254. But, regardless, if you don't believe a server config is even useful for the name and agree with me that other extensions ought to be client-driven, I'm confused, why this PR? This PR seems to go in the opposite direction. Hehe. Which part?
HIya, Yes. That's IMO the downside of having any server config. (To answer your question below, I prefer not having any server config at all but proposed this as I think it's better than draft-06.) Having also looked at some passive DNS stuff, I fully agree. But ISTM for many scenarios the entity that generates the ECHOConfig won't know the distribution of names in use (e.g. whoever configures OpenSSL won't, same with Apache etc.) so it's likely they'll have to go for whatever is the max (i.e. 254). Same is true for anyone with a wild-card server cert in play somewhere. See above. I'm trying for either a modest improvement over draft-06 or for us all to arrive at a real improvement by ditching the server config entirely:-) I like the last sentence. I think I dislike the 1st:-) Cheers, S.
It's not a downside of the draft-06 formulation, is it? The client learns something targeted to the name and can pad accordingly. Even with a wildcard server cert, the server should still know the distribution. For instance, isn't going to see anything terribly long most of the time. (Looks like the registration limit is 39 characters.) For reference, this is how long a 254-character hostname is: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa In order to enjoy wide adoption, ECHO can't be too much of a waste of resources. I think it thus makes sense to target a different maximum here. I guess my view is that, because of this issue above, this is a regression over the draft-06 formulation, even though it looks more general.
Hiya, Draft-06 assumes that no other inner CH content has the property that server guidance will help. My claim is that that guidance is useless in practice, and therefore unnecessary. I think the server config'd length in the PR is a little less useless:-) Some servers will. Some will not. Many (most?) server ECHOConfig instances will make use of default settings. Those'll pick 254 because adding a new VirtualHost to an apache instance (or similar) won't be co-ordinated with making a new ECHOConfig in general. And even it it were, (but it won't!) we get a TTL's worth of mismatch. If we don't provide a way for clients to handle the case where the server config is too short, again servers will publish 254. I am more interested in random smaller web sites/hosters myself. I think ECHO should work for those as well as we can make it, (albeit with smaller anonymity sets), and this tie between web server config and ECHOConfig is just a bad plan for such. AFAIK, all current deployments do just that. To be fair, that's largely driven by CF's draft-02 deployment, but I think that backs up my argument that if there's a max, that'll almost always be chosen, which implies it's a useless field that leads to the inefficiency you note. Then it can't be the max:-) The 254 value matches the max for servername IIRC. Ok. We disagree. But what do you think the client should do? Draft-06 is IMO plainly incorrect in that it says to pad in a way that'd expose other lengths should those be sensitive. If your answer were pad the SNI to at least ECHOConfig.maximumname_length and then make the overall a multiple of 16, with as many added 16 octets blocks as the client chooses, then a) that's != draft-06 and b) is quite close to this PR and c) just failing if the actual SNI in the inner CH is longer than the config setting seems quite wrong to me and d) hardcodes the assumption that SNI is the only thing where the server may know better. Cheers, S.
If we come up with other places where server guidance is useful, that can be addressed with extensions. But, gotcha, I suppose that is where we disagree. I think server guidance on the overall ClientHello size is entirely useless, while server guidance on the name is may be useful. Agreed that it should also work for smaller things. I don't follow how this PR helps in that regard. It seems they still need to come up with a random value or a default, but now it's even less clear how to set it well. Er, yes, sorry I meant to say target a different public length. That is, 254 is so far from the maximum domain name in practice (As it should be! Hard length limits ought to be comfortably away from the actual requirement.), so padding up to it is wasteful. I think it would be better to pad up to a tighter value and, if we exceed it, accept that we only have the fallback multiple of 16 padding. (Or maybe a different strategy.) It does result in smaller anonymity sets in edge cases, but I think that a reasonable default tradeoff given other desires like broader deployment and not wasting too much of users' data. I'm thinking something along the lines of: For each field, determine how much it makes sense to pad given what kinds of things it sends. If it varies ALPN, maybe round up to the largest of those. Most of this can be determined without server help. For fields where server help is useful, like the name, apply that help. Right now it's simply a function. I'm also open to other strategies. Sum all that padding together. In order to generally reduce entropy across different kinds of clients, maybe apply some additional overall padding, like rounding up to a multiple of 16, which cuts down the state space by 16x and doesn't cost much. (Or maybe we should round up to the nearest ? That avoids higher resolution on longer values while bounding the fraction of bytes wasted by this step.) That said, it's worth keeping in mind that clients already vary quite a bit in the cleartext portions of the ClientHello. There's a bit of tension between wanting to look like the other clients and wanting to ship new security improvements. This is different from this PR because this PR asks the server to report a value including things it doesn't know anything about (how large the client-controlled parameters are). I don't quite follow (c). It seems this PR and the above proposal has roughly the same failure modes when something is too long. The difference is that 's failure mode is only tripped on particular long names (something the server knows the distribution of), while this PR's equivalent failure mode is based on factors outside the server control, yet the server is responsible for the value.
Clarification: this is for each field where the client doesn't reference the outer ClientHello. If the client wishes to do that, it means the client doesn't consider that field secret so there isn't anything to pad.
I like NAME suggested algorithm, as an ideal padding function requires input from both the client and server. (Ideally, servers would send padding recommendations for each extension that might vary specifically for them, such as the server name. They don't have insight into anything else, so clients need to make padding decisions based on local configuration.) NAME what do you think?
Could live with it, but still prefer no server config. I'm looking a bit at some numbers and will try make a concrete suggestion later today. If I don't get that done, it seems fair to accept NAME algo and move on. Cheers, S.
If we can get away with no server config, I'm also entirely happy with that. Fewer moving parts is always great. We certainly could do that by saying names are padded up to 254, but I think that's too wasteful. But if we're happy with some global set of buckets that makes everyone happy (be it multiples of 16, some funny exponential thing), great!
(trimming violently and responding slowly:-) So your steps 1-6 is a better scheme than draft-06. I still think step 2 would be better as something like: ECHOConfig contains maxnamelen as before but we RECOMMEND it be zero and a) if the name to be padded is longer than maxnamelen, then names will be padded as follows: P=32-(len(name)%32)+headsortails*32, or b) if the name to be padded is shorter than maxnamelen then we just do as the server asked and pad to that length. That (hopefully:-) means a default of "pad out to the next multiple of 32, then toss a coin and add another 32 if the coin landed as heads." If we landed somewhere there, I'd be happy to make this PR say that or to make a new one or whatever. According to some data I have the CDFs for names and for these padded lengths would be as follows: Len, CDF, Padded-CDF 32, 81.28, 40.64 64, 97.87, 89.57 96, 99.31, 98.59 128, 99.87, 99.59 That means that 81.28 of names are <32 octets long and 40.64% of name+namepadding will be 32 octets long. 97.87% of names are <64 octets and 89.57% of name+namepadding are 64 octets long. I think we should RECOMMEND setting maxnamelen to zero unless an ESNI key generator has a specific reason to set it to a non-zero value. ISTM the use-case for non-zero values is where the anonymity set has only a few very long names that with length differences of ECHO. I'm basically fine that we default to not serving that use-case wellmby default, as I don't believe it's real. (But I could be wrong;-) Cheers, S.
Could the sender always pad their packets to at least 1200 bytes or something, using an encrypted extension in the ClientHello? I don't understand the focus on server input to a padding function that would ideally fill out one packet.
NAME what's the value in adding zero or one 32B blocks after rounding? Why not just stick with what was done, say, in RFC8467? (We could make it read something like, "clients may add zero or one blocks." Either way, I'm more or less fine with the suggested change. Would you mind updating this PR to match?)
Per above, clients could use help from servers in choosing appropriate padding lengths. (Only servers know their name anonymity set.)
Hiya, Say if the anonymity set has lots of names <32 length (~81% of names in the data I have) but a small number between 32 and 64 (~16% in my data). Then this should disguise the use of the longer names at the expense of sending more octets. Would be v. happy to know if that made sense to others. Cheers, S.
A friendly amendment below (but one I think is important)... I think that last really needs to be "Only servers can know their name anonymity set. But many servers will not know that, either due to wildcard certs or because names/vhosts are added and removed all the time independent of whatever is in the DNS." Cheers, S.
It makes sense, I'm just not not sure it's worth the cost. That said, this will always be an imperfect solution, so I'm happy either way.
Yep. Me neither. It is cheaper than padding to 254 octets for everyone though;-) Partly, I'm not that sympathetic towards anyone who wants to hide a crazily-long server_name. OTOH, I guess there may be a few who can't easily change names so we probably ought try do something for 'em. Cheers, S.
Agree that only servers could know their name anonymity set. But what is the cost of always padding out the ClientHello so it approaches the MTU? Just trying to understand why the spec attempts to economize on the number of bytes in the ClientHello packet.
As far as I know, there's no reason other than folks might not want to always "waste" these bytes.
Padding the ClientHello up to an MTU isn't free. See the numbers here on what a 400-byte increase costs. URL Likewise, also from that post and a , post-quantum key shares will likely exceed a packet anyway. I think our padding scheme should be designed with that expectation in mind (e.g., the mechanism fails this because a PQ key share in the inner ClientHello will blow past the built-in server assumptions on client behavior). Canary builds of Chrome already have code for such a thing behind a flag. Edit: Added a link to the later experiment, which I'd forgotten was a separate post.
It's not quite clear what's going on in those results. For example, the mobile results are close to zero. Without seeing confidence intervals, and the distributions of the full packet sizes, I don't think this experiment settles this issue (although it could, with more detail). Also, is there a theory on /why/ 400 bytes might add latency? If we're going to design the padding mechanism with PQ key shares in mind, but not conventional ones, that should be in the document.
NAME would know the details of that experiment, but I don't think the idea that sending more bytes takes more time would be terribly surprising! :-P I don't think anyone's suggested designing without conventional key shares in mind. They are what's deployed today, after all. However, we shouldn't design only for a small unpadded ClientHello. PQ key shares will need larger ones. Session tickets also go in the ClientHello, and it's common for TLS servers to stick client certificates inside tickets, so you can already get large ones today already.
Let's assume the results for "SI" in the first link actually do show a significant delta. The question is whether per-packet costs dominate or per-byte costs do, and whether the experiment sometimes increased the number of packets (e.g. by sometimes bumping the ultimate ClientHello size above 1280). See Section 5.1 in URL for device performance metrics on bytes vs packets. Looking at the ClientHello traffic on my computer, I can see that Safari is sending ClientHello messages that are about 500-600 bytes. My copy of Chrome seems to be sending CurveCECPQ2 (16696?) shares, and its ClientHello messages are fragmented.
NAME will you be able to update this as above?
would the spec allow me to put an arbitrarily-sized extension in the encrypted part of the ClientHello? if so, I don't care about the padding schemes.
Yes, of course! The padding policies described here are guidance at best.
I've updated the PR to try reflect the discussion above. Please take a peek and see if it seems useful now.
This looks like the right idea. I'll review this again as well, but it's probably better to wait for NAME suggestions to be addressed.
Thanks for all the changes Chris. I think I've actioned all those as requested. If not, I tried, but failed:-)
NAME do you need any help moving this forward?
Doing other stuff today but feel free to take the text and then do more edits. Or I can look at it tomorrow. Either's fine by me. S.
Thanks for taking the time. None of my comments are strongly-held opinions (meaning they only need to be addressed at all if others agree that the issues are important).
Strong +1 to NAME -- thank you for the work here, NAME
NAME can you please resolve conflicts? NAME NAME can you please review?
Fair point. The argument I'd make for keeping this is that if an anonymity set has ~80% of names <32 octets, then if we do nothing, passive observation will probably reveal when the server name is in the longest ~20%. And I'd guess that only a few names in that set would be popular/common, so we could be giving away the game whenever an ECHO is 32 octets longer than the usual. The random padding could mitigate that passive attack but yes would be vulnerable to an active reset based counter. I'd also be fine with just living with the issue in which case we might want to note that using ECHO with uncommonly long names is a bad idea.
Let's just drop the random addition. Servers don't (can't) do a padding check anyway, so clients can always choose to make this longer if desired.
NAME can you update this PR and resolve the conflicts?
"Fair point. The argument I'd make for keeping this is that if an anonymity set has ~80% of names <32 octets, then if we do nothing, passive observation will probably reveal when the server name is in the longest ~20%. " Which is precisely why we want the server to provide the longest name, so the client can pad to it.
As discussed on today's call, let's do the following: Resolve merge conflicts. Drop random padding for the SNI. And add text which says that if the client's name is larger than maxnamelength, it rounds up to the nearest 32B or 64B boundary. NAME do you need, or would you like, any help with this?
I think that this approach is generally better, but it runs afoul of divergence in client configuration that could dominate the calculation. For instance, a client that sends two key shares will have very different padding requirements to one that sends only one. For that to work, we need to assume that implementation-/deployment-specific variation of the inner CH is largely eliminated as a result of the compression scheme we adopt. That also assumes that these variations in client behaviour are not privacy-sensitive. I think that we should be directly acknowledging those assumptions if that is indeed the case. If there is a significant variation in size due to client-specific measures, then we're in a bit of an awkward position. That might render any similarly simple scheme ineffective. For instance, a client that later supports a set of ALPN identifiers that could vary in length depending on context cannot use this signal directly. It has to apply its own logic about the padding of that extension. That a client is doing this won't be known to a server that deploys this today. In that case, the advice from the server (which knows most about the anonymity set across which it is hoping to spread the resulting CH), isn't going to be forced through an additional filter at the client. The results are unlikely to be good without a great deal of care.I am generally fine with this, with the exception of the random padding, which I think should be omitted. It's hard to analyze and the value is unclear. In particular, many clients will retry if they receive TCP errors, and so the attacker can learn information about the true minimum value by forging TCP RSTs and looking at the new CH.


This addresses . cc NAME NAME NAME NAME NAME
This looks fine, though I'll note that since an HTTPSSVC record is public and the outer ClientHello record is public, it's not unreasonable to pull values from there to put in the public fields since the observer already knows (or can get) them. Restricting them to come only from the ECHOConfig seems unnecessary. I think the key observation in this PR is that the outer ClientHello isn't really offering to establish a TLS connection -- it's a not-crazy-looking wrapper for the actual ClientHello inside the ECHO extension, and the vehicle for the recovery flow. The only things a server can legitimately do are respond to the inner ClientHello or do a recovery handshake. Thus, most of the things you might set on the outer ClientHello are irrelevant; they can be chosen to look innocuous, chosen at random, or copied from the inner ClientHello as the implementation chooses.
NAME does this seem reasonable to you?
Seems reasonable.


Per NAME suggestion, this replaces computations involving the "hash underlying the KDF" with evaluation of the KDF itself. This respects the API defined in the HPKE draft. This supersedes .
Hey NAME and NAME I rolled up your changes! Please have another look before merging.
Rebased and rolled up.
Thanks -- let's let this stew until Friday, at which point we can merge.
Rebased.
Field is computed as "digest of the complete ClientHelloInner" (including presumably, the "outer_extensions" extension). I don't understand the analytical value of this hash. Can anyone explain its reasoning?
The hash is intended to prevent the attacker from influencing the reconstructed CHInner by manipulating CHOuter. Consider the contrived example of an extension which is separately protected but only works for SNI-A and not SNI-B. E.g., it's constructed by doing E(K_sni, SNI). If that extension were included in CHOuter and then imported into CHInner via this mechanism, then an attacker could substitute it and use a reaction attack to determine whether the CH referred to A or B. However, with the hash (which may be not well-specified), this attack gets caught by the client-facing server and the handshake is rejected without leaking information.
My initial understanding of this mechanism was incorrect. What happens is that the hash is computed over the ClientHelloInner that is consumed by the backend server. This is intended to ensure that if ECH accepts, then the backend server consumes the CH intended by the client. (PR URL makes this more clear, I think.) I wonder if this mechanism is redundant. Agreement on the CH between the client and backend server is provided by the binding of the transcript hash to the handshake traffic secret, so any attempt to manipulate the ClientHelloInner by fiddling with the ClientHelloOuter should be detected. On the other hand, the binding of the outer extensions to ClientHelloInner ensures agreement on the CH prior to the backend server consuming it. This is a strictly stronger property, which may or may not be useful. I agree that the attack works, but the example seems really contrived :) I'd be interested if there are more natural extensions for which this extra layer of security would be useful.
From the interim meeting, the consensus seems to be that we should err on the conservative side.
Let's close this issue and leave the mechanism as is.
Hrm, before closing I think it might be worth noting, in the spec, the stronger security property this provides.
I think we should also consider binding the CHInner to a hash of the whole CHOuter (minus the ClientEncryptedCH extension). That would have the same size overhead, but would give us a stronger property: modifying anything in CHOuter (not just one of the copied extensions) invalidates the whole thing.
The point of hashing outer extensions is to provide integrity of the ClientHelloInner. What would be the point in hashing more of the ClientHelloOuter? (Not a rhetorical question :) It seems conceptually different, and I'm curious what the security benefit might be.)
If we authenticate the ClientHelloOuter, we'd be authenticating all the inputs that go into the ClientHelloInner, so I think that would also provide integrity. I expect Ben is suggesting this in the context of URL, where GREASE can additionally be made a little stronger if we did that. Getting that to interact well with any PSK binders in ClientHelloOuter is tricky though, unless we decide to ban resumption attempts in outer ClientHellos. (Probably best to keep the GREASE-related conversation in one place. Though I see I didn't help on that front because some discussion is also in . Ah, GitHub.)
Yep, I'm just echoing NAME observation. See also URL
Today, the only thing that gets copied into ClientHelloInner is extensions, so I don't see how it's an improvement in terms of our primary security goal. (Not sure about the "don't stick out" benefit.)
I don't understand how hashing all of CHOuter is going to work. In split mode, the server never sees any of CHOuter.
Yes, the hash would be checked when reconstructing the inner ClientHello (as here), and would not be present in the reconstructed ClientHello.
There's not much discussion here. Unless there's objection, shall we leave the mechanism as-is and close out this issue? cc/ NAME
Works for me.
From Section 6.1: This assumes that the KDF specifies some underlying hash function. From the HPKE spec, it seems like all that's required of the KDF is that it's an "extract-then-expand" KDF: URL In fact, the currently assigned code points are all for HKDF: URL But there's no requirement that the KDF always have some underlying hash function. As an alternative to HKDF, one can imagine a dedicated primitive that satisfies the extract-then-expand API but is not constructed from a hash function.
Impacted fields: ClientEncryptedCH.record_digest URL
We can probably replace with and be done with it.
Putting on my theorist hat, I'd say that the extract function is a "randomness extractor" and not a collision resistant hash function. We want the latter in this context. From a practical stand point, using the extract function is more hashing than we need. I'd suggest doing away with (see ) and figuring something else out for . Could we simply require HKDF be used with HPKE?
Sure, but in practice randomness extractors use a collision resistant hash or PRF (CBC) under the hood. I don't think we can require HKDF for HPKE. That seems too restrictive. We might just say that ECH requires HKDF-based HPKE ciphersuites, as HKDF is already paramount for TLS 1.3, and then just reference HKDF's hash function.
addresses this issue.
As I mentioned on the list, we can use the KDF in place of a hash.
I tend to agree. I'll create a new PR.
Have a look at , NAME
Resolved in . Closing.


In places, the current draft doesn't make a clear distinction between rejection and decryption failure. In particular "cannot decrypt" can be interpreted either: "the client-facing server doesn't recognize the configuration specified by the client"; or "the client-facing server recognizes the configuration but decryption fails". This change resolves this ambiguity. Addresses issue .
Two sections suggest to ignore the extension on decryption failure, but one suggests to send an alert. What should happen? Ignoring the extension on unrecognized failures sounds reasonable in order to "not stick out". However, it is not entirely unambiguous what to do if a valid ECHConfig is found but decryption fails. says: says: says:
I think the first two statements apply when the config_digest doesn't correspond to a known ECHConfig (i.e., "I can't decrypt this"); the last is when the ECHConfig is known, but decryption fails ("I should be able to decrypt this, but the ciphertext is invalid"). The text could be a lot clearer here.
NAME Yes, your interpretation is correct. I think this is the result of a number of uncoordinated changes.
Closing as resolved.


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.)


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.)


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 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.


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


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.


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.


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..."