http-extensions
http-extensions copied to clipboard
Alt-Svc and underlying transports
RFC 7838 defines alternate services in terms of ALPN tokens. However, when the client ends up actually using an alternate service, it needs not only the ALPN, but more importantly the underlying transport (e.g. TLS/TCP, QUICv1, QUICv2, etc.). Additionally, the HTTPS RR draft acknowledges this issue and states ALPN protocol identifiers that do not uniquely identify a protocol suite (e.g. an Identification Sequence that can be used with both TLS and DTLS) are not compatible with this SvcParamKey and MUST NOT be included in the SVCB ALPN set.
Since the QUICv2 draft currently allows using ALPNs such as h3
directly over QUICv2, we're left without a way for a server to advertise that it supports "HTTP/3 over QUICv2". Since we're making changes to Alt-Svc, I think we should solve this issue.
cc @martinthomson @martinduke
I agree -- this needs a solution in one direction or the other. However, the solution might lie in QUICv2 -- it's problematic to specify that a token does uniquely identify a protocol stack, then later say that it doesn't. It makes it impossible to comply with or enforce the MUST NOT, as you don't know what might have changed underneath you.
Actually, let me revise the scope of that: We need to clarify first whether multiple QUIC versions constitute spanning multiple protocol suites. I think it probably shouldn't, but this discussion looks different depending on the answer there.
Yeah, I think "protocol stack" is a bit ill-defined, or at least needs a much more nuanced interpretation. For example, the "h2" ALPN token does not specify the TLS version.
I think the right criteria to think about is in-band vs. out-of-band selection for starting the connection. It is fine to consider TLS versions equivalent because TLS versions are negotiated in-band and roughly interchangeable. (I say roughly because h2 + TLS 1.3 did need a small fixup.) This limits what we can do in new TLS versions, but allows us to transparently upgrade TLS versions without coordination with HTTP/2 implementations. Separate "h2tls12" and "h2tls13" tokens would prevent this.
In contrast, QUIC and TLS/TCP cannot be selected in-band. We intentionally broke compatibility to gain all the benefits of QUIC. Thus, we need a separate out-of-band signal, currently represented as a new ALPN token.
Is that split generalizable? I.e. if QUICv1 and QUICv2 use the same ALPN, is the intent that they're negotiated fully in-band? In that case, we probably don't need an Alt-Svc / HTTPS RR embedding and can just treat it as analogous to TLS versions. Or if they actually need an out-of-band toggle, maybe we should be allocating new ALPNs.
Or is it something in between? That might get a bit more interesting.
(Of course, by this logic, "h2" and "http/1.1" at the Alt-Svc / HTTPS RR are also interchangeable. The distinction only becomes meaningful in the original TLS notion of ALPN. We took a spec convenience in reusing ALPNs here, at cost of making the system a little weird and complicated, hence all these kinda incoherent notions of "protocol stack". Even "http/1.1" is somewhat a misnomer because "in-band" and "out-of-band" are relative terms. The HTTP/1.x family of protocols have their own in-band negotiation relative to the (from their perspective) out-of-band TLS selection of "http/1.1" vs "h2" ALPNs. Which means that, although "http/0.9" and "http/1.0" ALPNs are defined, they're never actually used at the layers where typically we talk about ALPNs.)
They're a little in between, but basically still in-band for this discussion. The QUIC VN document specifies "compatible" and "incompatible" version negotiation; you can move between compatible versions without losing a round-trip, while transitioning to an incompatible version requires the client to re-send its first flight in the selected version. Which means there's advantage in getting the version right-ish on the first flight, even if you can fix it in-band if you must.
In practice, I expect all versions of QUIC which use TLS as a crypto protocol will be compatible (possibly given certain constraints), while hypothetical versions of QUIC which use a different crypto protocol will be incompatible with TLS-based versions.
Would it make sense to say compatible QUIC versions (can) share an ALPN, while incompatible QUIC versions get new ones?
The design team explicitly punted the incompatible VN issue because it was hard and not urgent. But as Mike said, any two QUIC versions are absolutely negotiable, though it might take an RTT to work that out.
On Mon, Feb 14, 2022 at 10:33 AM David Benjamin @.***> wrote:
Would it make sense to say compatible QUIC versions share an ALPN, while incompatible QUIC versions get new ones?
— Reply to this email directly, view it on GitHub https://github.com/httpwg/http-extensions/issues/1922#issuecomment-1039419579, or unsubscribe https://github.com/notifications/unsubscribe-auth/AF2EYEJB4D4EYFPSHOZLQTDU3FDIDANCNFSM5NQDCX3A . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
You are receiving this because you were mentioned.Message ID: @.***>
@martinduke which design team are you referring to?
@martinduke which design team are you referring to?
It's a shorthand for you, me and @martinthomson. It's probably too grandiose of a word to describe what that was. Apologies.
Yeah that chat we had was completely informal and carries no weight whatsoever :)
I like @davidben's proposal of having compatible QUIC version negotiation fit into this somehow, it matches what we do for TLS.
I think that we need something more than compatibility in the sense that the VN draft uses it. "Compatible" in that context means that you can use the handshake of one protocol to negotiate the other. What we are looking for here is a superset of that: the QUIC version is compatible with the version for which the original ALPN was defined AND provides all of the functions necessary for the target protocol. I think we also need to define that the compatible QUIC version was defined as being compatible; it can't rely on compatibility that was defined later, as that means that some endpoints might not know that it is compatible.
All of that qualifies QUICv2:
- It is compatible with v1 in a VN sense
- That compatibility is defined as part of the definition of v2
- v2 provides the necessary functions for any protocol that operates over QUICv1
(I think that this is much of what I said in our conversation, though a clearer formulation helps.)
I like the direction you're going in @martinthomson - though I think we'll need to add one bit to the QUICv2 draft: QUICv2 implementations MUST support QUICv1 and compatible VN from v1 to v2, and QUICv2 clients MUST only send QUICv1 initials and rely on compatible VN to get them to use v2. Otherwise we can end up in situations where the server doesn't understand what the client sends it.
Would this mean that we'd be stuck on v1 initials roughly "forever"? That sounds unfortunate. In particular I think that means we would end up un-greasing the version field and middle boxes would happily ossify on 0x00000001.
I don't think that a MUST-level requirement is what we need.
For MUST support QUICv1, an explanation of the consequences of not supporting it would be sufficient. That is, if you don't support v1, you might get terrible performance (a Version Negotiation packet is basic game over for performance) or even connection failures (because some clients give up if they get a VN packet).
For "MUST only send v1 initials", why? My implementation of QUICv2 attempts v2 if it got v2 in the past (and it is offering a ticket or token).
What Ryan says about v1 initials forever worries me a little here. Maybe over time the odds of v2 success are such that the downside is worth it.
I think we can break the ALPN problem into two parts
- What ALPN value do we put in TLS handshakes for HTTP/3 + QUICv1 vs QUICv2?
- What do we need from Alt-Svc for HTTP/3 + QUICv1 vs QUICv2?
For 1, it seems like using "h3" for both HTTP/3 + QUICv1 and HTTP/3 + QUICv2 seems reasonable. In conjunction with QUIC compatible version negotiation, this gives us a somewhat smooth upgrade path.
For 2, I think we need to have a distinct way of advertising HTTP/3 + QUICv1 and HTTP/3 + QUICv2. I'd be inclined to tweak Alt-Svc so that the "ALPN" field in the Alt-Svc advertisement need not be the same thing as the ALPN field that goes into the handshake. For example we could say that "h3" means HTTP/3 + QUICv1 and (making something up) "h3+quic2" means HTTP/3 + QUICv2.
I don't think that a MUST-level requirement is what we need.
For MUST support QUICv1, an explanation of the consequences of not supporting it would be sufficient. That is, if you don't support v1, you might get terrible performance (a Version Negotiation packet is basic game over for performance) or even connection failures (because some clients give up if they get a VN packet).
Since failure to do this can result in complete protocol failure, a MUST seems adequate? Isn't that what they're for? Or perhaps OUGHT TO.
For "MUST only send v1 initials", why? My implementation of QUICv2 attempts v2 if it got v2 in the past (and it is offering a ticket or token).
How long do you cache "I've seen that this origin supports v2" for? Saving information without communicated lifetimes is bound to cause state mismatch.
What Ryan says about v1 initials forever worries me a little here. Maybe over time the odds of v2 success are such that the downside is worth it.
I'm concerned about this too. But it does seem to be the inevitable conclusion of us keeping the current Alt-Svc design and having "HTTP/3 over QUICv1" and "HTTP/3 over QUICv2" share the same ALPN. As Ryan points out, tweaking the design of Alt-Svc avoids this problem.
The v2 draft currently says:
QUIC version 2 is not intended to deprecate version 1. Endpoints that support version 2 might continue support for version 1 to maximize compatibility with clients. In particular, HTTP clients often use Alt-Svc [RFC7838] to discover QUIC support. As this mechanism does not currently distinguish between QUIC versions, HTTP servers that support multiple versions reduce the probability of incompatibility and the cost associated with QUIC version negotiation or TCP fallback. For example, an origin advertising support for "h3" in Alt-Svc SHOULD support QUIC version 1 as it was the original QUIC version used by HTTP/3 and therefore some clients will only support that version.
IMO this lays out the risks pretty well, but I'll take PRs if someone wants to word that differently. I should probably update to 7838bis!
I concur that the existing v2 text plus a solution for Alt-Svc and HTTPS RRs avoids the Incompatible VN risks and the potential problems with changing the ALPN for each version. There is probably some future world where old v1 clients that don't understand the parameter have incompatible VN with v2-only servers, but IMO that's an unlikely scenario.
It sounds like @MikeBishop would prefer this to be in a separate draft, so if that's the consensus I'll go and write one.
I think we can break the ALPN problem into two parts
- What ALPN value do we put in TLS handshakes for HTTP/3 + QUICv1 vs QUICv2?
- What do we need from Alt-Svc for HTTP/3 + QUICv1 vs QUICv2?
For 1, it seems like using "h3" for both HTTP/3 + QUICv1 and HTTP/3 + QUICv2 seems reasonable. In conjunction with QUIC compatible version negotiation, this gives us a somewhat smooth upgrade path.
For 2, I think we need to have a distinct way of advertising HTTP/3 + QUICv1 and HTTP/3 + QUICv2. I'd be inclined to tweak Alt-Svc so that the "ALPN" field in the Alt-Svc advertisement need not be the same thing as the ALPN field that goes into the handshake. For example we could say that "h3" means HTTP/3 + QUICv1 and (making something up) "h3+quic2" means HTTP/3 + QUICv2.
For fear of kicking the bikeshed, I'm reading 2) a little differently and wonder if it wouldn't be served by something roughly:
_Alt-Svc is a list of supported alternatives
. Each alternative has:
-
protocol-id
- an application protocol idientifier based on ALPN identifier, -
alt-authority
- optional host, port -
secure-transport-token
- a parameter (stt) that desribes the secure transport that this advert applies to. Eachprotocol-id
has a defaultsecure-transport-token
, if the value is omitted on the wire, the default is assumed. If a non-default is desired, thesecure-transport-token
is supplied._
If we think back to gQUIC and then h3 ~ draft -10, they supplied a version array.
Alt-Svc: hq=":49288";quic="1,1abadaba,51303334,0"
My suggestion above is different. Servers send multiple "h3" (so the real ALPN stuff in TLS doesn't get busted) and disambiguates via this new param. Let's say h2's default is tls
and h3's default is quicv1
, there's no need to advertise them. So adverts could look like this
Alt-Svc: h2=":49288", h3=":49288", h3=":49288";"stt=quicv2", h3=":49288";"stt=quicvCustomThing",
@martinduke and I put together https://datatracker.ietf.org/doc/html/draft-duke-httpbis-quic-version-alt-svc as a more formal way to track design. Draft 00 plumps for adding a quicv
parameter that carries a list of hex-encdoded QUIC versions.