- From: David Benjamin <davidben@chromium.org>
- Date: Fri, 29 Jan 2021 18:38:08 -0500
- To: Cory Benfield <cory@lukasa.co.uk>
- Cc: Victor Vasiliev <vasilvv@google.com>, "<tls@ietf.org>" <tls@ietf.org>, HTTP Working Group <ietf-http-wg@w3.org>
- Message-ID: <CAF8qwaChpjxhBtR9az0C58Qwscv5YM=PPcV3XDYb=1je2j4bdg@mail.gmail.com>
Hi all, Thanks all for the feedback. I’ve tried to address it below, but there's a lot of text, so please let me know if I’ve missed or misunderstood any of your points. Cory commented on SETTINGS_[HQ]PACK_ENABLE_STATIC_TABLES in draft-vvv-httpbis-alps-00. I agree that is odd. We’ve uploaded a draft-01 that drops it. Cory also wrote: > I think the document does a good job laying out the difficulties with > half-RTT data, but it didn't convince me that ALPS is easier for H2. To clarify, are you unconvinced that ALPS is easier than leaving H2 alone, or that ALPS is easier than solving this problem with half-RTT? The document’s aim is the latter. Your comment in Martin’s thread <https://lists.w3.org/Archives/Public/ietf-http-wg/2020OctDec/0273.html> reads to me like you agree with this. Am I interpreting that correctly? (I think draft-thomson-httpbis-h2-0rtt roughly corresponds to Section 2.3 of my document. Something like it would be necessary, but not sufficient, to solve this with half-RTT.) As to leaving H2 alone, doing nothing is indeed generally easier than doing something. But this is perhaps not a useful criteria. :-) The question is what’s the benefit of solving the problem. My interest is in the privacy benefits of rethinking content negotiation <https://tools.ietf.org/html/draft-davidben-http-client-hint-reliability-02>. Victor has use cases around WebTransport. The document cites some other uses <https://tools.ietf.org/html/draft-davidben-tls-alps-half-rtt-00#section-1>. > My biggest concerns are around the need to tightly couple the TLS and > application layer stacks. I agree this adds a non-I/O TLS interaction, but adding interactions isn’t new. Many HTTP mechanisms touch TLS: - RFC8473 <https://tools.ietf.org/html/rfc8473> uses TLS exporters. - RFC5929 <https://tools.ietf.org/html/rfc5929> specifies various TLS channel bindings interfaces for authentication protocols. - RFC8470 <https://tools.ietf.org/html/rfc8470> integrates with the 0-RTT/1-RTT transition point. - ALPN <https://tools.ietf.org/html/rfc7301> itself uses TLS to select variations on HTTP. - Section 9.2.2 of RFC7540 <https://httpwg.org/specs/rfc7540.html#rfc.section.9.2.2> specifies cipher suites for HTTP/2. - HTTP/2 cross-name pooling <https://httpwg.org/specs/rfc7540.html#reuse> and HTTP’s general notion of authority <https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#rfc.section.4.3.3> are tied to the TLS certificate. - Applications using client certificates care about the relation between TLS-level authentication and HTTP messages. The web even has a notion of “uncredentialed” HTTP fetches which shouldn’t send client certificates. - Secondary certificates <https://tools.ietf.org/html/draft-ietf-httpbis-http2-secondary-certs-06> use TLS exported authenticators <https://tools.ietf.org/html/draft-ietf-tls-exported-authenticator-13>. Systems and thus their problems span components. The question is how best to split a solution across those components. The aim with ALPS is to minimize coupling while still getting settings for the first client write. We can build something piecemeal with half-RTT, ticket state, and early data callbacks. Or we can abstract a notion of “protocol settings”, configured and surfaced at well-defined points. I prefer the latter. As to the complexity, I think you may be overestimating it. It sounds like your model has three components: TLS, HTTP/2, and some ALPN dispatcher. And your concern is complexity in HTTP/2. Is that right? ALPS should slot next to ALPN processing at the same points. For example: - The dispatcher already must know which ALPN protocols are supported and how to instantiate them. - Extend it so protocols can optionally be ALPS-aware. An ALPS-aware protocol has a settings parameter in the instantiation function. It also configures settings to send. This all happens at the same time as existing ALPN setup. - The dispatcher runs the TLS handshake and gets an ALPN protocol as before, plus now an ALPS value. - The dispatcher instantiates the protocol as before, but if ALPS was negotiated, also passes a byte string to the ALPS-aware handler. Note the extension ensures this can only happen if the protocol was configured as ALPS-aware above. The protocol acts accordingly. If ALPS was negotiated, HTTP/2 would apply the received settings to the initial peer state. It also knows the initial local state is different and can skip sending some values. This is added logic to HTTP/2, but I think it’s fairly minimal. (And we can certainly figure out the exact details that would work best.) It even has precedent in the HTTP Upgrade path <https://httpwg.org/specs/rfc7540.html#Http2SettingsHeader> for “http” URLs, so it's not even really new. Also note that all this happens before any of the usual application I/O. (I wasn't sure what you meant by "timing issues". Could you elaborate? I read it to mean where the integration points were, so hopefully the example above helps clarify. Also note that all of the logic above is synchronous. We don't need new points in state machines to wait for data.) > It is also different from making the existing logic conditional, as > presumably we wouldn't bother with SETTINGS ACKs for ALPS settings. Our draft currently says to omit it. That matches HTTP2-Settings and seems simplest. I'm not sure I see how that's different from making some logic conditional. > I want to stress: I don't think ALPS is a bad idea, I think it's a > good one! It clearly brings benefits for protocols that can require > its presence. If we want to mint a new ALPN token for HTTP/2 that also > mandates ALPS support I'm open to that, but frankly without it I don't > see that ALPS helps us much for HTTP/2. You’re right that HTTP/2 would need ALPS and non-ALPS codepaths. I think that's unavoidable. The 0.5-RTT version would also need two codepaths since TLS 1.2 lacks 0.5-RTT. If folks feel this is worth an “h2.1” ALPN token, that’s fine by me. I think that’s largely an aesthetics question and doesn't have much practical complexity difference: HTTP/2 and HTTP/2.1 implementations will presumably share code, so this is largely switching if (alps) to if (h2_1). Martin wrote: > The idea of creating a 0.5-RTT -> 1-RTT marker somehow is an odd idea, and one we've talked about maybe using in a new version of TLS, but I hardly see justification for that here. To be clear, I have no interest in a marker. The marker would be needed as part of the 0.5-RTT alternate (so the client knows when to give up waiting for SETTINGS and start the protocol) which I do not favor. I think ALPS is a better rationalization of 0.5-RTT data. > A lot of your reluctance to use half-RTT seems to be based on the buggy IO pattern you identified. Coupling send and receive flow control in the way you describe is - at least in my view - a defect in stacks rather than something to engineer a protocol around. I think you may be conflating send/receive dependencies with application/handshake dependencies. The former is indeed incompatible with HTTP/2 (though more common in simpler protocols like HTTP/1.1). But this is about the latter, which is, in general, a security requirement and part of RFC8446, section 4.4.4 <https://tools.ietf.org/html/rfc8446#section-4.4.4>. Where we’ve relaxed this (False Start, 0-RTT, 0.5-RTT), we’ve needed to work through the implications carefully and usually introduce caveats. Critically, in 0.5-RTT, the client is not yet authenticated. To tie back to Cory’s comments about coupling between HTTP and TLS, these caveats often require a more complex interface to capture them. That’s sometimes necessarily but, here, I think we can make a safer and simpler interface with ALPS. > What is somewhat odd about TLS 1.3 is the way that applications can write to the socket before the handshake is complete. But reads are only possible afterwards. That does create some problems for incoming data, but it is always a modest amount to buffer. A new version of TLS might even allow clients to limit 0.5-RTT data, if this turns into a real problem. I’m not sure I follow where you envision buffering data. Are you saying the client should, in parallel, eagerly decrypt and buffer application data while sending C/CV/Fin, just in case the server is blocking the read of C/CV/Fin on half-RTT write? That seems backwards to me. Either way, one side needs to perform parallel handshake/application I/O. Having the server do it makes more sense since TLS is already responsible for limits on the handshake flight. (It’s also unclear to me if section 4.4.4 of RFC8446 allows the client to decrypt messages early like that.) Either way, it’s a question of how complex the application/TLS interface needs to be. If you say the connection is “ready” earlier, you can use the existing I/O interface, but client certificates assumptions break and the application needs tighter integration for when that’s ready. If you do that with separate write functions, now you need extra integration into the application’s I/O path. If you try to preconfigure the 0.5-RTT data statically, the pre-ready “handshake” state needs to drive parallel transport I/O, which, in non-blocking APIs, means tighter integration between TLS and the application’s event loop. Or if you do a more traditional-looking TLS extension like ALPS or ALPN, you can just follow the existing patterns. Given the integration points a solution needs to hit anyway (ticket integration for 0-RTT), I think this is a worthwhile abstraction to reduce complexity across the TLS/application boundary. How does NSS expose the late client authentication to the application? I thought NSS didn't support half-RTT at all when the server requests client certificates, but perhaps I misunderstood. David
Received on Friday, 29 January 2021 23:38:40 UTC