jiebi/CodeConvo huggingface dataset:
A client could perform a normal subscribe and then either immediately unsubscribe, close the connection, or set MAXSTREAMSUNI=0 avoid receiving any objects. These empty subscribes follow the normal authentication logic, so the mitigation is going to be the same for both.
Individual Comment: Let's retitle this issue to be more specific about what the ask is. Empty subscriptions are possible with draft-01. Their semantics are a bit undefined - eg: a relay or publisher has multiple options - SUBSCRIBEERROR, SUBSCRIBEOK + SUBSCRIBEFIN, SUBSCRIBEOK and no FIN, in case the subscriber wants to do something else? Do we need to mandate a particular behavior for better interoperability? Then there's a separate issue about supporting these use cases: If these are required, then there's other ways to spell that without changing Subscribe - and none of these cases have anything to do with subscribing except maybe 3? A QUERY_TRACK (eg: HEAD) message that doesn't alter the subscribe state seems like a more apt vehicle. How to pre-warm a cache seems out of scope. I think we should open a separate issue about this case, and what the relay requirements are (if any) around backpressure. The same thing can happen if a client runs out of streams and doesn't grant new credit in a timely way. Are there obligations to keep the subscription open and/or cache at the relay for some period of time, or can a relay aggressively drop objects or reset subscriptions? A naive relay is going to get itself in big trouble very quickly.
Now that we have TRACKSTATUSREQUEST, can we close this one? The one use case we haven't completely addressed explicitly is cache pre-warming, which is tracked by
LGTMAfter or equals to? (in case one requests a single object)
See issue Question for reviewers. Do we need the final sentence on how a workload is invoked? If the sentence was not there would it change how we think about a trust domain? Do we need the second sentence as an example? Should we add more examples (e.g. trust domains can be defined as all the applications or workloads that recognise a specific issuer).
The definition of a Trust Domain feels very specific to network segmentation. Is there a industry level Trust Domain definition we can use instead? For example, should we use a definition that defines the trust domain in terms of the shared policies that apply? Something like: "A trust domain refers to a collection of systems, applications, or workloads that share a common security policy".
I'm good with this
This increases the complexity of a minimal server implementation and decreases the complexity of a rich client implementation. Addresses
Another option would be to say that connect-tcp always uses capsules, that would reduce complexity even further
That would reduce the complexity of a rich server implementation, but it would increase the complexity of a minimal client implementation. I don't think that is a wise trade.
Do we think minimal client implementations will exist? I was imagining that they'd use regular CONNECT
The spec probably wants more language to describe what a client should do when a server does not enable the capsule protocol, since thst a failure mode for this optional behaviour.
NAME Template-based configuration is valuable with or without the capsule protocol. Also, if you're not actually using capsules, it adds bandwidth overhead without any benefit. NAME We don't usually say "the server MUST Y". Is there a reason why that is necessary in this case?
It seems weird to me that the server echos something back that the client doesn't check. Since the server has a MUST requirement to process whatever format the client tells it, we could just drop the response header and state that a 2xx is the signal that server accepted connect-tcp with or without capsules.
The response header is for the benefit of intermediaries. Clients don't rely on it. This is also true for CONNECT-UDP.
That's a good point and might be worth saying explicitly in the text. However, we do have a pattern in RFC9298 that levies requirements on request and response message and says "if any of these requirements are not met, the client MUST treat the procying attempt as failed and abort the request". Since connect-tcp levies a MUST about capsule-protocol on the response message, using similar text seems consistent to me.
To move this discussion away from a merged PR and into an issue, I filed
As of draft-ietf-httpbis-connect-tcp-05, connect-tcp now optionally supports the capsule protocol. However, this optionality adds non-trivial complexity to implementations. As currently written, if a client wishes to use capsules, the server can reject the use of capsules, and now the client needs to cache that this server doesn't support them. However it's undefined for how long the client should cache this information, and within what scope.
We could potentially figure out recommendations for all these questions, but fundamentally it might be best to instead make capsules mandatory for connect-tcp, like they are for connect-udp and connect-ip. That would simplify implementations and improve consistency.
Individually, I think it would be interesting to try out this direction — probably based on implementation experience for how easy it is to add. On one hand, this makes connect-tcp less of a trivial drop-in. On the other, it opens up more possible use cases.
I heard a good deal of support for this direction in the HTTPBIS meeting.
Thanks!
For . Note that this makes missing values ; if we like that approach, I think we should do it for missing parameter values too (currently they use , which isn't part of our type system). I used because it aligns with the semantics of current uses nicely.
OK with me.
NAME This is a keen observation. Assuming that we are fine with requiring that knowledge on what the top type is, maybe we should also consider adding support for rule. It has been my understanding that the only reason we do not support rule in SH is because can only be applied for certain top types (but we are now requiring that knowledge).
We've discussed requiring knowledge of top-level types extensively, and I think we have agreement that it's OK. I"m not sure what you want regarding support for ; can you give an example (or open a new issue)?
I'm running my SH implementation against the HTTP Archive dumps (400,000,000+ HTTP requests) to see how the from BSH parse in something like the real world. A number of headers are failing because they have valueless dictionary members; e.g., , , . It should be pretty easy to accommodate these, as we already have optional values on parameters.
PTAL at the PR, especially the note about using True for missing parameter values.
Ping NAME NAME
Seems like a reasonable change. I'm happy to remove the 'null' from parameters too.
(already OK'ed in the PR)
Changed it to a proper normative reference. For
Merging this. Can always clean it up more if it is still a concern.
For example: Usually, we add something like URLPattern to the references, then that.
Sorry, didn't mean to close the issue. Feel free to close this out if the current language looks OK (also happy to update it if it needs some more tweaking).
Going to close this out now. Thanks for taking the time on this.
This error code can be sent by a publisher to a subscriber that is not consuming data fast enough, causing a queue to form at the publisher that exceeds the publisher's limits.
I added text here on when to send Too Far Behind that attempts to clarify the fidelity of subscribe. It ended up in the delivery timeout section, which may not be where it belongs, but we don't have a generic section that explains how subscriptions work, it's spread amongst the relay section, SUBSCRIBE message and Delivery Timeout.
During the interim last week, there seemed to be consensus that SUBSCRIBE's default behavior is a high-fidelity mode (eg all new objects will get to all subscribers, with the exception of DATAGRAM tracks). Based on the FETCH discussion - the status of a cache on any relay in the chain has no impact on new object fidelity. The only parameter that can affect this is the subscriber's , which opt-in. The only other issue to address is - a subscriber falls too far behind live head to sustain the subscription based on sender resource constraints. I recommend we add an error code to such as , include the final queued object ID, and remove the subscriber from the forwarding table so no new data is queued for them. When those objects are delivered, the subscriber can FETCH later objects and/or resubscribe as needed.
I do not think this was the consensus. It has been very clear that one of the main use case for sub groups was temporal scaled video where there was enough bandwidth for one sub group but not enough bandwidth for all the subgroups.
Individual Comment: Here's a clip from the minutes: My understanding of that scenario is that prioritization can deprioritize some subgroups but they are queued indefinitely unless the objects within pass the DELIVERY_TIMEOUT. If the delivery timeout is infinity, how does a relay know which subgroups can be skipped over (or when) and which are critical? Do you have a different mechanism in mind?
Individual Comment: If a publisher doesn't have enough MAXSTREAMDATA, MAXDATA or MAXSTREAM_ID to send objects, it seems to me that it needs to queue until the peer grants these credits, up to the delivery timeout, right?
If the relay is sending data to a subscriber, and the link between the subscriber and the relay cannot sustain the bitrate of the track, eventually the relay will have to buffer more and more data.
At some point, the relay would have to drop the data; we should specify how that happens (lowest priority stream gets dropped first?).
Individual Comment: +1 We need to specify what happens in this case. I think there's two parts: 1) selecting what gets dropped (this is a priority question) 2) the mechanism for dropping (stream resets, etc).
+1 Expanding Alan's list, I think we should determine: (1a?) valid boundaries for dropping data (group? object? byte? bit?) (2a?) under what circumstances the subscriber needs to be informed of the dropped data (do we need different verbs with different semantics in this case, e.g. fetch/subscribe? is dropping data always permitted and something all subscribers must be able to tolerate?) (2b?) the means of informing subscribers of dropped data (implied or explicit)
The AI is to add an error code for SUBSCRIBE_DONE to indicate a subscription was cancelled because the subscription was too far behind.
The spec currently says this about data sent along with a CONNECT request: Is there a demarcation between data "within" a request and data to be sent on the tunnel if it opens successfully? HTTP/2 and HTTP/3 are fairly specific that all DATA frames are data for the tunnel. Do we need to say anything about the client prospectively sending data before the proxy responds?
We should decide what we want to allow. If HTTP/3 is going to send CONNECT data within HTTP/3 frame payloads after (or before) the recipient accepts the CONNECT, then we should specify it differently than how we specified CONNECT in 1.1. I am fine with that.
Hm. Does this imply we special-case 1.1, and require the HTTP/2/3 behaviour for new versions?
I think it is already a special case for 1.1, so that's not a problem.
OK, let me rephrase this then :-). Are we trying to make it consistent for all "new" versions?
Given that CONNECT is specified on a version-by-version basis anyway, I think I'd rephrase it with something like this: CONNECT is one of those weird edges of the protocol where each version will have to respecify its behavior; we don't necessarily need to prescribe what it will be, just make allowances for versions to differ.
This PR makes explicit an already implicit feature of the specification - that it is not possible to rotate the confirmation key. URL) -->
NAME NAME Any reason this can't be merged?
Waiting for NAME approval
Currently section 5.2 states: In the case that the original client attestation JWT has expired, what should happen? If it is acceptable for the client to re-use the same key in the "cnf" field across attestation JWTs, then the client can easily generate a new attestation JWT with the same "cnf" key. But if the client needs to use a fresh "cnf" key, then I can think of three options: Define a flow which endorses the new "cnf" key with the old "cnf" key. Define a field in the client attestation JWT that contains a unique identifier for the client instance, and use that identifier to bind the refresh token to the client instance. Explicitly don't permit this in the specification, add text to the specification that makes it clear that the "cnf" key must stay the same across refreshed client attestations. My preference would be for option 2.
Currently the client instance needs to go back to the client backend and request a new client attestation JWT bound to the same key used in the old JWT. In general because we are effectively using the client instance key to identify the instance at the authorization server this makes key rotation of the client instance key difficult with active refresh tokens. 1 feels too complex, 3 is an option and NAME and I have discussed 2 before. The flip side to consider with option 2 is the privacy implications of formally electing to track client instances, personally i'm not convinced its a bad idea but we should carefully consider the impact.
Do we? I had assumed the AS identifies the client by the value. I don't see a need to identify a client instance.
the forth option is to have long living client attestations, which in my opinion is no problem the client should then use different attestations with different ASs
This just makes explicit the tracking of client instances that already existed through the requirement for the "cnf" key to stay the same over attestations. This is really a decision for the use-case in my opinion.
In the context of software integrity being established through the client attestation, it is trivial to inject malware after the generation of the attestation, so some in some cases it may be a requirement to have fresh attestations.
Isn't the AS identifying the client also by the refresh token itself? I dislike option 2 due to the privacy implications. As any optional fields in the client attestation JWT are valid, profiles could still use this option, but it should not be a good requirement in my opinion. I see two options: A: the wallet initially gets one client attestation and uses the cnf key over a longer period to bind a sequence of refresh tokens to it. -> similar to option 4? B: the Wallet initially gets one client attestation and the AS binds the first refresh token to the cnf key. When it uses the refresh token, it also provides a new client attestation with a new cnf key and the AS binds a new refresh token to this new key. -> similar to option 1?
Well the current language doesn't actually guarantee that the AS can track the client instance (which is a good thing IMO), as the instance can in many common cases, rotate the keys it uses in between fetching tokens. But in the event a client instance is exchanging a refresh token for a fresh access token and potentially another refresh token, the client instance must authenticate using a client attestation JWT with the same key in the cnf claim that was in the original attestation used when the refresh token was obtained. This ensures one client instance can't use another client instances refresh token. So in this case the AS can track that the client instance who obtained the refresh token is the client instance now requesting to exchange it for a new access token, which is desired from a security perspective. As I said above in response to Torsten's point, using the key instead of an explicit claim means a single client instance could actually use multiple keys over time meaning the AS can't track the client instance across all of those interactions. The concern if we make an explicit claim in the client attestation JWT for identifying the client instance, is that implementations won't rotate this identifier over time thus meaning the instance would be tracked.
Ironically if your goal is to reduce the ability of the AS to track the client instance over time, this option will in fact enable that as the attestation itself becomes the tracking vector. Agreed, the additional requirement of requiring the same client authentication method with the same key just means that obtaining the refresh token alone is not enough for another instance to be able to exercise the refresh token, it doesn't materially change the ability for the AS to track the client instance because as you highlight the refresh token itself creates the same possibility for correlation.
I think this is basically my option 3. Unless there is a mechanism to issue a refresh token that I am not aware of, it is not possible to rotate keys according to the current language. The spec states: This is what I mean by "This just makes explicit the tracking of client instances that already existed through the requirement for the "cnf" key to stay the same over attestations."
I don't think rotation of the key within the lifetime of a refresh token is something that needs to be accounted for. So my preference would be for option 3 (which is how it functionally is now but could be made more explicit in the text). Adding an explicit claim in the client attestation JWT which identifies the client instance, i.e. option 2, would be okay too. But I think it'd get complicated/confusing to describe it in the spec.
By saying you can't rotate the key within the lifetime of a refresh token, I think this means that you cannot rotate the key without starting from scratch at the authorization endpoint. I just wanted to make sure that is what you meant?
Basically yeah, I think so. Rotating the the key would mean you'd have to go back to the authorization endpoint. That seems acceptable/reasonable. Maybe it's too narrow of a view but it seems like if there's a reason to rotate that key then reauthorizing is probably needed or at least acceptable anyway.
I'm not sure that's true. IMO authorization is more of a user-identification concern, the rotation of the key is a client-security concern. Saying that, I think I agree that it's probably acceptable to say key-rotation isn't possible without returning to the authorization endpoint. Given this I would suggest we add a sub-section to the Implementation Considerations section, something along the lines of this:
without changing section numbering
implies that a precondition failure is a good safe mode. However, a precondition that isn't recognized by a server will not share this property. A server that does not recognize a header as a precondition will ignore it and likely proceed with handling the request even if the precondition expressed should have failed. Indeed, the same is true if a server ignores preconditions, though the specification effectively . is the only text I could find on defining new preconditions. (One thing I really want to avoid is server's applying special heuristics to headers that start with , because that is one of many poor outcomes if this is left.)
There is also the example in the section above that I suppose we could make a new section on precondition extensions, but they aren't a separate category (like If*). For example, my precondition proposal for 1.1 was an all-inclusive Unless that enclosed a logic bag (structured field value). Note that they have always depended on compliance-when-implemented, since I added the first (If-Modified-Since) in early 1994.
Does this need to be in this specification?
I think we're almost in the extension territory (I like the idea of a header field that lists the applicable precondition fields). As far as this specification goes, simply noting that new preconditions won't share properties of the core preconditions, in particular the expectation that it is understood by servers.
One grammatical nit.
Added the missing 'd' - thanks Neal.
I'm separating AQM from ECN, although ECN relies on AQM design and deployment - ECN can be a force for good when detecting bottlenecks and latency - aka RFC 8087.
Well, yes. ECN, by itself, is one of the signals that can be used by CC algorithms, together with packet loss, delay variation, and packet acks (input to bandwidth measurement). Makes sense to separate it. However, the L4S folks have introduced a tight coupling between a very specific use of ECN in the L4S AQM, and a fine grain mandate of the expected behavior of the CCA. And I cringe each time I read their dual queue formula based on the asymptotic limit of Reno -- but not Cubic. I wish we could walk that back, or describe it in more neutral terms. With L4S, ECT(1) is a signal from the sending host to the network that CE marks should be apply at incipient congestion, instead of waiting for actual loss-generating queue buildup as in RFC 3168. Maybe that should be true even for algorithms that are not described in L4S. Of course, we have to deal with what we have. Maybe we should just quote all the relevant RFCs, and denote the difference between ECT(1)/EC and ECT(0)/EC. Senders using ECT(1) should consider that the rate of CE marking signals the intensity of the congestion, while senders using ECT(0) should consider individual CE marks as denoting actual congestion.
I think the ECN text ought to approach with something very generic like setting ECT can provide nice properties [RFC8087], but comes with requirements for reacting to ECN-CE marking. This reaction to ECN-CE marks needs to be evaluated to ensure this conforms with the style of ECN being used. I'll make a PR.
see Neal's comment
NAME that should already be covered by the last paragraph in this section. In particular the format is the Port is quite explicit there. Are you saying we should mention that strings are in ASCII?
No, sorry, I'm talking about the host name in particular. There was a long back and forth with Paul about the format of this field (is it the thing that appears in the HTTP request authority header, the thing that appears in the TLS SNI, etc), and we ended up being explicit. Just trying to save you some trouble down the road.
Oh, thanks. I agree we should be explicit. Could you point me to the specific text in Privacy Pass for this please?
Found the suggested Privacy Pass text and added to this PR.
I would recommend making the TLS exporter labels specific to the type of algorithm in use. For example, rather than use "EXPORTER-HTTP-Unprompted-Authentication-Signature" for signature-based authenticators, I might use "EXPORTER-HTTP-Unprompted-Authentication-Signature-Ed25519" for authenticators using Ed25519.
This would seem to have the drawback of making it complicated for intermediates to forward the authentication nonce. The alternative being for intermediary to implement the validation itself, which has its own drawbacks. Thinking why would one want to do something like this, I came up with vague ideas about possible cross-key tracking vectors. However, making labels algorithm-specific would not help if both keys happen to have the same type. One idea would be to mix the key id as context input, which would make the nonces be pretty much per-key in a way that is feasible for the first intermediary to calculate with no explicit algorithm support nor configuration.
An alternative proposal would be to just use a single context string for exporting the nonce but then somehow bind additional information into the signature computation at a higher layer. This would address the issue without complicating the intermediary story, I think.
Any case that involves intermediaries forwarding tokens will necessarily involve some amount of trust in the intermediary. The intermediary can provide the exporter output when it forwards the token, which would allow the signature to be verified, but the recipient is going to have to trust that this isn't copied from some other request. I definitely think that the context string is the right place to include origin, key identifier, algorithm choice, and maybe even some context from the request (URL).