Change:
We really REALLY mean it. The effect of has been to shame some implementations into the right behaviour, but on reviewing this section, it really was unambiguous. This tweaks the text slightly and adds a cautionary note, but it is otherwise unchanged other than a few editorial tweaks.
I know this has been discussed before - but reading the text as it is I wonder: the text mixes several different terms, seeming arbitrarily: decryption of 1-RTT, processing of 1-RTT, and reading 1-RTT packets, and not using the 1-RTT keys at all. I can see how packets MUST not be processed ahead of time, but I don't see why the keys cannot be used to qualify the packets. In fact the text says you can store 1-RTT packets until ready, but how do you know they are indeed 1-RTT packets if you cannot use the keys in some form? There is a related concern about timing attacks if you do not both decrypt and verify but if that is not topic here, and if it is a concern it should probably be mentioned or referenced.
In it's becoming clear that some QUIC server implementations are using their 1RTT receive keys before getting CFIN, which is not supposed to happen. IMO, there are going to be plenty of hacky QUIC implementations but only a handful of TLS implementations, especially TLS implementations that have the special APIs required for QUIC. This is the narrow waist where we should enforce good behavior. Figure 5 of quic-tls shows that we shouldn't deliver the keys that early, but there's no normative language. I will file a PR shortly for quic-tls that imposes this requirement, so that QUIC implementations can't possibly mess this up.
I like that this class of problem is naturally assumed to require some sort of protocol change. As I said on , maybe those implementations can fix their bug. is a pragmatic sort of fix that would make this an editorial issue. I'd like that, but it sounds like there is a strong desire to go all nuclear on this. We should discuss that, or its spectre will haunt us.
I think it's worth noting this, though I tend to agree with NAME that we cannot write this down using a normative language because that is a requirement of TLS. That said, I actually wonder if we can have a section discussing Implementation Pitfalls. TLS 1.3 has an appendix dedicated to that (see ), and it has been extremely helpful to me. I think it would be nice to have something like that in the QUIC drafts.
I'm not sure of the rules here, but this requirement is on the QUIC-specific interfaces. People already have to modify TLS to comply with quic-tls.
IIUC, This requirement comes from the TLS handshake protocol defined in section 4 of RFC 8446 (specifically, ). TLS 1.3, DTLS 1.3, and QUIC all share the same handshake protocol.
Wouldn't this prevent the server from sending 0.5 RTT responses to 0-RTT?
Or, well, sending 0.5 RTT at all, not just for 0-RTT.
NAME Regardless of if we should use the normative language in QUIC-TLS, I think that RFC 8446, Section 4.4.4 clarifies what the requirements are, i.e.: do not use the 1-RTT keys until the Finished is received with the exception of 0-RTT and also with the exception of 0.5-RTT, while keeping in mind that the peer's identity or liveness has not been asserted.
NAME yeah, that makes sense thanks.
NAME No, just the receive keys.
NAME I understand that the key applicability is a general property of TLS1.3; however QUIC is the only one where the secret is actually consumed outside of TLS. quic-tls defines this interface and we have the right to impose constraints on it.
NAME As said, it is not only QUIC. DTLS 1.3 also uses the TLS 1.3 handshake protocol while having a different packetization layer ("records" in TLS term). That said, I am fine with letting the editors of the QUIC-TLS draft decide.
Calling this editorial, since it looks like it can be addressed without adding requirements.
Closing now that we have merged .
In TLS 1.3, 1-RTT secrets can be derived once the server finished is computed, when the handshake is half-complete. This allows the server to send application data without waiting for the client finished flight (a feature sometimes called 0.5-RTT in the TLS WG). This is safe because checking the peer's finished message is only required for receiving, and the finished must be received before any application traffic when using the TLS record layer. In QUIC, the server may receive 1-RTT packets before the client finished. This can happen because of packet loss, or an active adversary deliberately dropping handshake packets from the client, or because the client is malicious and does not send its finished flight at all. As far as I understand, the current QUIC spec allows the server to process the 1-RTT packets and hand them to the application without waiting for the client finished. Doing this falls outside the scope of what is currently proved secure about the TLS handshake, and it leads to multiple problems: Deadlock when the network drops the client finished flight: see Potential to bypass client authentication requirements: if a server is configured with required client certificate authentication during the handshake (e.g. for access control to a service), a client may send the request before the client finished flight. If QUIC passes the request to the application, it may incorrectly believe that the client has been authenticated. Potential for downgrade attacks: the client finished is used to explicitly authenticate the negotiation of algorithms in the handshake. Due to its defensive design, TLS 1.3 also implicitly authenticates the transcript in the transport secret derivation. However, the implicit authentication only holds for strong AEAD algorithms, whereas the explicit authentication relies on strong hash algorithms (and/or signature, depending on the mode). A reliable way to prevent all of these issues is to mandate that every 1-RTT packet sent by the client before the client finished frame is acknowledged by the server must include in the same datagram a copy of the finished packet (the same handshake packet may be sent in multiple datagrams). The overhead is limited because finished messages are short, so even with the overhead of the long packet headers and AEAD tag, less than 100 bytes are used in the datagram (leaving the rest for the 1-RTT short packet). If this is done, it is possible to enforce that a server must have checked the client finished before processing 1-RTT packets from the client. Adding a new transport-level signal for handshake confirmation (as proposed in ) is a bad idea - in TLS, receiving the peer's finished message IS the the explicit handshake confirmation signal (which is why CCS is removed in 1.3). Instead, QUIC should simply ensure that the signal has been received. It's only an issue on the server side, because clients cannot decrypt 1-RTT packets without processing the server finished.
While this is true, I wonder if we have the issues you point out, because we prohibit the use of such packets until the server receives Client Finished. states that a server MUST NOT process data from incoming 1-RTT protected packets before the TLS handshake is complete, where "handshake complete" is defined as when the TLS stack has both sent a Finished message and verified the peer’s Finished message ().
Yes, I agree that this spec is correct in that respect. However, it is clear that several implementations are not implementing this restriction correctly, which is understandable given that it requires server to actively delay processing buffered packets (i.e. use memory resources). I think it is much better to enforce the correct behavior by requiring that the finished is repeated in every datagram until the handshake is confirmed by the server, because the server is guaranteed that it does not need a logic for received data that cannot be passed to the application.
This recommendation has been made a few times, but we have thus far resisted it on the basis of it not working with client authentication. The suggestion that the server might offer proof that it didn't do something bad is new. If I were inclined to take that suggestion seriously, I would instead say that the server should use an exporter to generate something. You could even see how this might make its way into the proposed HANDSHAKE_DONE frame. But I don't think that this needs this level of mechanism. This is something that servers just need to do on their own. Just like having a good source of randomness for their key generation, the consequences of failure here are that they might be open to attack. I have no problem with test suites that purposefully "drop" critical packets to reveal misbehaving servers. That might be better than adding mechanism. That said, the server can just withhold ACK frames until it sees the whole handshake, even if it processes the entire handshake. A server could answer requests from 1-RTT until clients start looking for that happening. Ultimately, we can't stop the server from performing processing if it offers no reliable proof of that happening. And I don't think that it's worth trying.
To help decide whether this is likely to be a problem, I decided to run an experiment. I wrote a very simple patch to OpenSSL to disable sending a finished: I checked with to check that the patch works as expected. Then, I tried to connect to various public h3-23 endpoints listed on URL using the ngtcp2 client built with my patched OpenSSL. The point of the experiment is to check which servers would acknowledge the short packets that I sent. Note that there can be false negatives in this experiment if the server is passing the 1-RTT data to the application but withholding the ACKS (this is insecure because the application may make unsafe side effects based on the received data, e.g. a POST/DELETE request). Two servers on the list clearly implement a wrong behavior: URL straight up acknowledged the 1-RTT packet in a short packethttp3-URL acknowledges the client 1-RTT packet, but does that in an handshake packet (!) It seems very likely that some implementations will ignore this requirement in practice (and understandably so, as buffering the 1-RTT packets is expensive), to the point that I think it is worth making the correct behavior verifiable by the client (as it somewhat exposes the client in the downgrade case, although a complete exploit seems unlikely with a signature, and difficult with a PSK binder)
In hindsight, the keyschedule for TLS 1.3 might have derived clientapplicationtrafficsecret0 from the same handshake context as resumptionmastersecret. Maybe in TLS 1.4? ;)
Yes... the reason it can't (currently) is because finished keys are derived from traffic secrets (which is also a mistake, especially when different transports use separate traffic secrets). Without changing the 1.3 key schedule QUIC could use the exporter MS to derive the client 1-RTT traffic secret.
NAME Thank you for sharing the results. This is very interesting. FWIW, I do not think QUIC stacks using picotls would have the issue, as picotls hands out the 1-RTT read key only after processing ClientFinished... but I can see that the API might vary between the TLS stacks. Though, if we are to have a protocol design that enforces the server to wait for CF, just bundling CF in every 1-RTT packet is not enough. I'd argue that CF should include some bits that is unpredictable by the server.
Like NAME our TLS doesn't even deliver the receive keys until it gets Finished. Rather than mess with the spec or rely on various QUIC implementations to do it right, I think it's best to fix the various TLS implementations (or, more specifically, their QUIC-facing secret export API) to do this correctly. There are relatively few of these and it's a problem specific to TLS 1.3. The ability to coalesce sent packets is optional and the spec goes to great pains to not require sending them at any point, which has caused much suffering for NAME Moreover, I am not at all convinced that coalescing Finished solves the problem.
This might be receptive to an interop-level test. Dropping Handshake packets from the client should lead to a situation where the client provides ample temptation for the server to break this rule.
NAME How does this help? Can't the exporter MS derived at the same time as the traffic secrets?
My bad for leading you astray there. I forgot that only the resumption secret is spun off after the client Finished. Yes, an exporter doesn't help. (As an aside, I'm fairly made exporters that way to allow them to be used with QUIC. Bit of a fail there in retrospect.)
Sorry, for some reason I was convinced that exporter master includes client finished, but after double checking, this is only the case of resumption master (honestly I think this is wrong because exporter are used for binding authentication and they pretty much fail at binding client authentication. I would suggest this is fixed in future TLS).
I agree, coalescing Finished is just a way to avoid server being blocked. The proper fix to the problem is to ensure that the client traffic secret for 1-RTT is derived from a transcript that includes client finished, as Subodh suggests. Unfortunately, only the TLS resumption master secret includes it.
Would it be unreasonable to derive the client's 1-RTT send key from the resumption master secret then? I guess one downside of this approach is that we'd be using different key derivation paths for server and client, since the server needs to be able to send 0.5-RTT data.
I'd advise against doing anything like that. A change to the key schedule is very disruptive.
Is it disruptive because we'd all have to update our implementations (I imagine it would just be one more HKDF call a QUIC stack would perform when the TLS stacks hands it the 1-RTT keys, wouldn't it?), or are there any cryptographic reasons not to do this? I'm just trying to understand the issue here better, not advocating for one way or the other at this point.
My feeble crypto brain says it would be fine, but it feels like enough of a deviation from TLS1.3 to need a formal security analysis.
Figure 5 of quic-tls is pretty clear on what should happen, but I think that section could use some normative text.
If we did something like this, it would likely trigger completely new analysis of the protocol. The thing that concerns me is that it would reduce or eliminate key separation between resumption keys and traffic keys, which is a concern. We'd be better off creating a new "secret" with the same transcript being input to its expansion. But that smells a lot like defining TLS 1.4 to me.
NAME it's disruptive also because of possible ongoing hardware design. That said, if it is important enough to fix ...
This is on purpose btw. We process the 1-RTT packet (as in, we decrypt it), but do not process the frames it contains until the handshake is complete. The reasoning behind this was to avoid having to buffer potentially invalid 1-RTT packets.
If you don't look at the frames but acknowledge the packets when do you stop buffering them? When the server is out of memory?
There's a limit on the number of packets buffered, something like "initial congestion window"-amount of packets.
NAME the transport spec says you MUST not acknowledge a packet until it's been processed. Given you're limiting the number of buffered packets, I don't see any obvious gain from trying to decrypt them before buffering them. The buffer will be cleared when the handshake completes no matter what.
Yeah, but that doesn't mean I should still buffer junk packets if I can avoid it....
As for the not ackng, sure, but that's a separate problem.
Agree it's off topic, but it's still very interesting for security research. I would never have expected implementations to do this and the security implications for stream integrity can be very surprising in some scenarios (such as compromised PSK), so thanks for clarifying that.
NAME can you point me where the draft says that? I can't seem to be able to find it in URL
It's the first sentence in 13.1: "A packet MUST NOT be acknowledged until packet protection has been successfully removed and all frames contained in the packet have been processed."
Sure, you can't ACK or process a packet before the key space is valid, but you can buffer them. There is not point in buffering garbage. Forcing keys to only be available after the key space is confirmed amounts to babysitting and there are plenty other things any endpoint can do wrong. Receiving an early ACK is ofcourse a protocol violation.
In interesting aside: how do you deal with max ack delay when you buffer packets that cannot be processed yet?
This feels like a great idea for Quic V2. Instead of just having 0-RTT and 1-RTT packets, also define 0.5-RTT packets that the sender can emit before the handshake is complete. (Or maybe call them sender side 0-RTT.) Use different key derivations for 0.5-RTT and for 1-RTT, and make the 1RTT key dependent on some nonce carried with the client finished message. Add parameters somewhere (TLS or Quic TP) explaining whether the client will accept 0.5RTT packets or discard them. But no, not today please, not when we are finishing V1. For V1, we should just stick with the spec we have.
Discussed in Singapore; .
I agree that this solves the issue IF implementations adhere to the spec. A change of the key schedule that would make it impossible to use 1-RTT keys before the completion of the handshake would still be my preferred solution of this issue. I'm not sure if this isn't out of scope though.Looks good. I like the idea of having normative text (MUST NOT) for 1-RTT packets, because that is a QUIC-specific requirement.

Discussion:
endpoint before the final TLS handshake messages are received.  A client will be unable to decrypt 1-RTT packets from the server, whereas a server will be able to decrypt 1-RTT packets from the <del> client. </del> <ins> client.  Endpoints in either role MUST NOT decrypt 1-RTT packets from their peer prior to completing the handshake. </ins> Even though 1-RTT keys are available to a server after receiving the first handshake messages from a client, it is missing assurances on

Any received 0-RTT data that the server responds to might be due to a replay attack. <del> Therefore, the server's use of 1-RTT keys is limited before the handshake is complete.  A server MUST NOT process data from incoming 1-RTT protected packets before the TLS handshake is complete. Because sending acknowledgments indicates that all frames in a packet have been processed, a server cannot send acknowledgments for 1-RTT packets until the TLS handshake is complete.  Received packets protected with 1-RTT keys MAY be stored and later decrypted and used once the handshake is complete. </del> <ins> Therefore, the server's use of 1-RTT keys MUST be limited to sending data before the handshake is complete.  A server MUST NOT process incoming 1-RTT protected packets before the TLS handshake is complete.  Because sending acknowledgments indicates that all frames in a packet have been processed, a server cannot send acknowledgments for 1-RTT packets until the TLS handshake is complete.  Received packets protected with 1-RTT keys MAY be stored and later decrypted and used once the handshake is complete. TLS implementations might provide all 1-RTT secrets prior to handshake completion.  Even where QUIC implementations have 1-RTT read keys, those keys cannot be used prior to completing the handshake. </ins> The requirement for the server to wait for the client Finished message creates a dependency on that message being delivered.  A