Draft: draft-ietf-quic-tls

Commentary: In , suggests that we could allow RESETSTREAM in 0 - RTT . That seems slightly wrong , because why would someone send something then give up without receiving anything in return , but that is actually possible in the presence of packet loss . And changing your mind is perfectly acceptable . But RESETSTREAM does n't really cover it . Streams can get blocked , requests can go out with additional flow control credits , and maybe even STOPSENDING makes sense . And my analysis suggests that the risk from replay is not made worse from any frame type that does n't produce application - visible changes . So this removes the restrictions , aside from the natural restrictions that exist for frames ( for instance , there are no cases where ACK , CRYPTO , and even PATHRESPONSE make sense to send in 0 - RTT ) . 
 Thede rules seem to get more and more complex . As I mentioned in the discussion on the issue , I ’d prefer to allow all frames in 0 - RTT . For example , what ’s the harm of sending a PING in 0 - RTT ? 
 OK , big changes here based on doing more analysis . Please re - review . 
 As notes , there is a reasonable argument on the issue that most frame types should simply be permitted . Would it make more sense to invert the list and instead state only where frames are prohibited ? 
 Proposed shortening of replay section As described in Section 8 of { { ! TLS13 } } , use of TLS early data comes with an exposure to replay attack . The use of 0 - RTT in QUIC is similarly vulnerable to replay attack . Endpoints MUST implement and use the replay protections described in { { ! TLS13 } } , however it is recognized that these protections are imperfect . Therefore , additional consideration of the risk of replay are needed . The QUIC transport protocol is not vulnerable to replay attacks and does tolerate replayed frames because all frames are idempotent and because no state is carried across connections . Applications might carry state across connections and can be confused by STREAM frame content under 0 - RTT keys and also by other content such as flow control credits . Servers can be configured to reject old 0 - RTT packets but it is not perfect nor guaranteed . Only application protocols can define semantics that are acceptable for 0 - RTT sessions , if any . A copied 0 - RTT session is cheap to establish and can be exploited to expend excessive server resources . Applications MUST account for this overhead before accepting 0 - RTT connections . QUIC extensions SHOULD describe how replay attacks affect their operation . Applications MUST prohibit extensions where efficient replay mitigation strategies can not be provided . 
 I am not sure if this is accurate . IIUC their is nothing that mandates the client to switch to using 1 - RTT when it receives ServerFinished . In fact , on a lossy network , a client would benefit from using 0 - RTT packets until it receives an ACK for ClientFinished . In such case , it would be natural to observe these frames in a 0 - RTT packet . I think we should either forbid them or clarify that there are allowed , instead of suggesting ( IMO incorrectly ) that it ’s impossible . Originally posted by in 
 To be clear , this was in reference to text that mentioned that certain frames could n't be sent in 0 - RTT . That would only be true if we made this a requirement . 
 This actually is already addressed in the TLS draft , as pointed out in another thread : , " Though an endpoint might retain older keys , new data MUST be sent at the highest currently - available encryption level . " If you have 1 - RTT keys , you MUST use them . There 's currently no server verification that you do so , however . 
 I think this should be stated in transport as well as TLS , along with a statement that a server MAY / SHOULD / MUST ignore  packets that have higher packet numbers than the first received 1RTT packet . The first is editorial I believe , the latter is borderline design . If we decided it was valid to close the connection if a 0RTT packet was received with a higher packet number than 1RTT , then that 's definitely not editorial , but I think it may be a good way to enforce proper behavior . 
 Agreed . I think that this should be a MAY / SHOULD close the connection with PROTOCOL_VIOLATION rather than " ignore " , because that aligns the handling with how we agreed to handle other misuse of 0 - RTT packets ( see ) . 
 said it right at the  : this is a key update scenario , from 0 - RTT to 1 - RTT key . Treat it the same way as peer continuing using old key after key update . 
 I think the only verifiable requirement is " must not ack 1RTT packet in 0RTT packet " . The server can definitely detect that , and send a connection close with reason PROTOCOL VIOLATION when it happens . This would effectively force the client to switch to 1RTT soon . 
 exceeding the initial flow control /  streams from the remembered TP 's is also detectable . 
 detection with flow control would require special case code in stream processing , as in " check against the current window but if 0 - RTT check against the initial window " . Could be done , but that would be another wart . Also , in many cases the 0 - RTT data sent is well below the initial flow control window , so it will not be a very efficient test . 
 It 's actually something that can be implemented in a clear and concise way . The only thing you need to have are objects representing limits for each type of packets . When processing 0 - RTT packets , the logic would refer to the limits declared by TP of the previous connection . When processing 1 - RTT packets , the logic would refer to the limits declared by current  and the  frames . 
 Since QUIC provides 0 - RTT support , it really should . 
 forbids a RESETSTREAM frame being sent in a 0 - RTT packet . I do not see a reason why we should prohibit that even though we allow FIN to be sent . RESETSTREAM is just another way of closing a stream . I think that we should allow RESETSTERAM to be sent using a 0 - RTT packet . FWIW , my assumption is that we simply missed to clarify that RSTSTREAM is allowed when we split the frame into RST and STOP_SENDING . 
 Do we really need any special rules for allowed frame types in 0 - RTT packets ? I do n't see any justification for treating 0 - RTT and 1 - RTT different in that regard . 
 My understanding is that 0 - RTT is a temporary state that provides less protection ( i.e. not forward - secret and also replay - able ) . It makes sense to require clients to switch to 1 - RTT ASAP . I think that the current approach of limiting the capability to the transmission of stream data is one way of accomplishing that . 
 If RESETSTREAM is to be permitted , should n't it also be permitted to send STOPSENDING on locally initiated bidirectional streams ? 
 I do n't understand why we would consider e.g. flow control updates worthy of higher protection than application data . Note that there 's a real use case for sending flow control updates in 0 - RTT packets : A client might anticipate a large response when it sends a request in 0 - RTT request , and it can save one roundtrip by granting a lot of flow control credit for that response . 
 I 'm not sure if that 's true . A client can always use transport parameters to specify it 's limits ; I doubt if there 's a benefit in updating the limits using a 0 - RTT packet . And in case of anticipating a large response , the anticipation would be that the transmission of the response would span across multiple round - trips ( because of congestion control ) . Everything would work fine if the client 's initial limit is large enough to cover what can be sent in the first round - trip ( or several round - trips ) . Asking for permission to send _ BLOCKED frames in 0 - RTT packets might make sense , though I am not sure if we 'd need that in practice . I think we can expect a server allowing 0 - RTT to provide enough window to let the client actually use 0 - RTT . 
 There 's generally good reason to keep the initial window small , since we do n't have any mechanism to update the transport parameters . That depends very much on the concrete values used . Right , I had n't even thought about BLOCKED . I think it proves my point here : If we do n't allow those frame types in 0 - RTT , we 'll need a lot of special code just for keeping those frames out of 0 - RTT packets ( and to delay transmission until you have 1 - RTT keys ) . Equivalently , on the receiver side , you 'd need to implement checks that the payload of 0 - RTT packets only contain valid frames . I do n't see any reason for special casing anything here , so we should just allow all frame types in 0 - RTT packets . 
 I can imagine an application protocol oriented around using streams as message framing that might have small initial limits to support proportionately large numbers of in - flight streams , but occasionally request large responses by issuing MAXSTREAMDATA alongside the request . Supporting such a pattern in 0 - RTT seems useful . 
 I agree with I think we should just have the same rules for 0 - RTT and 1 - RTT packets . 
 Acks can not be sent in  packets atm , are you proposing changing that as well 
 I ’m on board with all other frame types though . I guess acks can not logically be sent in  naturally , so maybe that ’s not really a big deal 
 I agree that it makes sense to treat 0 - RTT and 1 - RTT the same since all frames the same . I 'd still like to keep the handshake frames to the bare minimum . 
 I agree with loosening the restrictions . As with TLS 1.3 , it 's up to the application layer to restrict what things ca n't be done in 0 - RTT . Those should generally be things which have effects outside the connection itself , and at the QUIC layer , nothing the client sends does . 
 I have been skimming through the QUIC transport and QUIC TLS draft a few times . It is really difficult to decipher which frames can be sent where . Some packet types mention permitted frames in transport , but does not do that for all packet types . QUIC TLS has a list of frames for different packet types , but it is not clear if that cover all frame types . QUIC TLS does suggest that CRYPTO frames can be sent in 1 - RTT by stating that only 0 - RTT can not contain crypto , but is not clear about how or why that would happen , although I suspect it has to do with client auth - which is explicitly not permitted post handshake without any explanation . It could also be rekeying , but I think that is derived locally from session key . 
 This is useful for , for example . 
 Bring the discussion back from . I 'm thinking about comment there and I think that it would be easier if we were able to permit any frame type in 0 - RTT ( except CRYPTO , which has nothing to carry ) . In thinking about this , the main concern is whether there is any replay risk associated with any of these frames . Going through each , I did n't find anything . Though replay does result in spurious state being created , it 's all transient and connection - bound , not application state . In general , all connection - level control messages affect only connection state , which goes away when the connection goes away . And replayed 0 - RTT always results in the connection being thrown out as the full handshake can not successfully complete twice . There might be some application - level significance to resetting streams in addition to carrying stream data , particularly when you consider the potential for selective replay . An attacker with sufficient knowledge of the contents of packets could replay some packets and not others to effect changes . But while the signals that a server application might receive are different , they are not outside of the range of possible signals that a client accepts as possible when sending the 0 - RTT . That is , if the server receives a partial stream rather than a complete stream , that is a potential outcome that the client has to accept as a possibility even when there is no attack . If there are lasting application - layer effects from a RESETSTREAM ( or STOPSENDING ) , then this might cause problems . But the application actively chooses to accept those risks by triggering these actions before the handshake is complete . In addition , RESETSTREAM is a poor carrier for state - changing action because its semantics are better suited to abandoning state - changing effects , not creating them . It would be a poor choice in protocol design to carry any application - layer signal with RESETSTREAM that implied a need for some action . HTTP does this with CONNECT in a way , but that is only to match with a TCP RST and comes with no real expectation of it being reliable . In the end , I conclude that we should permit all frames in 0 - RTT and 1 - RTT . While there is some increased risk here , I think that this is best left to the 0 - RTT profile for the protocol that uses QUIC . For HTTP , where the only application - layer effect RESET_STREAM can have is to cancel requests , the result is to reduce exposure to replay . Other protocols will need to make their own assessment about safety , but I do n't anticipate problems . I 'll adjust to match . 
 I think this is an improvement but I am a bit anxious . What happens to special frames related to connection migration that might affect a server view of a remembered client . What about tokens stored for future use - perhaps when looking towards v2 where things get more symmetrical . What about path migration and validation . What about 100 coalesced 0 - RTT packets forcing 3x amp path validation , or something , in each - is that a possibility ? ( EDIT : no because you should protect against repeat 0 - RTT , but perhaps it gets more important now ) I like the simplicity of all frames - but black listing frames in a 0 - RTT receive handler is not hard either - iff valid frames are clearly document . There could be a lot of hidden complexity in 0 - RTT that we do not fully appreciate yet . 
 The problem with 0 - RTT in QUIC is that , unlike TLS 1.3 ( that has maxearlydatasize ) , there is no limit in the amount of data that the client can send using the 0 - RTT key . IIUC , currently , it 's entirely up to the client to decide when it switches from 0 - RTT to 1 - RTT keys . As we know , Initial and 0 - RTT packets can be replayed against different servers within a server cluster that does not ( can not ) implement the use - only - once rule for the session tickets . I am concerned that widening how 0 - RTT packets can be used might lead to additional exposure to the attack surface . An attack would go like this : attacker creates a legitimate connection and obtains a session ticket attacker reconnects using the session ticket , and exchanges lots of information with the server ( involving MAXDATA , MAX_STREAMS , etc . ) . However , the attacker sticks to using 0 - RTT for packets it emits , even after the handshake is complete . , the attacker creates many QUIC connections using the same Initial packet as that of step 2 , and then sends the copied 0 - RTT packets . The server will handle those and commit state . Because the client never responds with an 1 - RTT ACK , the connection will eventually die . However , a client can create a connection with huge PTO ( by delaying Initial packets ) to have enough time to let the server accept many packets . IMO it is preferable to allow less frames in 0 - RTT packets , because it narrows the attack vector . PS . Anyways I think it 's worth clarifying how to minimize stream - related states being created by 0 - RTT replay attacks ; left my comment 
 QUIC uses for that purpose . You ca n't receive a flow control update , so whatever value you have for that determines how much 0 - RTT you can send . In thinking through this , I realized that the client ca n't send 0 - RTT after receiving 1 - RTT from the server . A client wo n't have the keys until it has the entire handshake flight from the server , at which point it has to switch to 1 - RTT keys . So this all comes down to the same calculus we have in TLS / TCP , after you have spent a little bit of time on the question of RESETSTREAM and its effect on long - term application state . 
 The problem with 0 - RTT in QUIC is that , unlike TLS 1.3 ( that has maxearlydatasize ) , there is no limit in the amount of data that the client can send using the 0 - RTT key . IIUC , currently , it 's entirely up to the client to decide when it switches from 0 - RTT to 1 - RTT keys . My understanding is that an attacker acting as a client can receive flow control updates ( in 1 - RTT packets ) , and use the updated value for emitting additional 0 - RTT packets . Something like following : client obtains to a server and obtains session ticket and TP client reconnects , sends 0 - RTT packets containing a STREAM frame ( id=0 , off = TP.initialmaxdata-1 , len=1 ) server sends handshake messages and a 1 - RTT packet that contains  ( maximumdata = TP.initalmaxdata3 ) , because it observes the client reaching the limit client sends a 0 - RTT packet containing a STREAM frame ( id=0 , off = TP.initialmaxdata3 - 1 , len=1 ) server sends another 1 - RTT packet containing  ... client sends a 0 - RTT packet containing a yet another STREAM frame ... 
 At the point the client has 1 - RTT keys for receiving , it will have the ability to send using 1 - RTT keys . It can ( and should ) send its Finished too . Why would it send with 0 - RTT keys ? 
 Because the client here is an attacker . However , I 'm not seeing as much threat related to this specific change -- this is something the client can do regardless ( generating many connections and causing state to be allocated for each ) . So the attack here is to artificially create a large batch of ( hopefully work - intensive ) 0 - RTT packets which are legitimate given a particular session ticket . Then open a large set of parallel connections using the same session ticket and dump all those 0 - RTT packets into each connection . To guard against this , TLS 1.3 recommends . This defense is the same for QUIC , and lives in the TLS layer . 
 Is the concern here about a denial of service attack on the server ? That is , the extra frames that it might receive , which are n't really limited in any way by flow control or other such limitations , might cause it to do too much work ? This does n't sound that interesting to me . There is always a risk when you accept 0 - RTT that the client or data is bad . As points out , you should n't be accepting the same 0 - RTT multiple times . The recommendations in TLS 1.3 provide some tips on how to avoid that . But even if your server configuration does n't allow you to detect that and stop it , the work you expend on 0 - RTT packets is a cost that you take on . And you take on that work with the understanding of the associated risk of replay . Clients can always send far more stuff than you are prepared to process ; servers just need to make the call . For instance , rejecting 0 - RTT would be my first response to increasing server load . If a client chooses to send 0 - RTT when 1 - RTT keys are available to it , maybe we can allow servers to cut them off . That 's maybe hard to police , but simple things like exceeding initial flow control might be detectable . Even if the server has provided more credit , the client should still be operating within the initial window for 0 - RTT . 
 I like that defense . Just to sanity check , there should n't be a case in which the TLS handshake takes an extra round - trip and 0 - RTT is accepted , right ? Assuming that 's true , saying that 0 - RTT data MUST NOT exceed the initial connection flow control window ( even if MAX_DATA frames are received in 1 - RTT ) and a pointer to the TLS 1.3 anti - replay protections seem like sufficient mitigation here . 
 Correct . TLS only takes an extra round trip with HelloRetryRequest , which results in 0 - RTT being automatically rejected . 
 The difference between a DoS using 1 - RTT packets and 0 - RTT packets is that the latter requires far less CPU cost on the attacker - side . This is because an attacker can just retransmit the same packets from different source tuples , whereas in 1 - RTT case , an attacker needs to do expensive crypto operations ( especially DH ) for each connection it establishes . Therefore my preference goes to limiting the capability of 0 - RTT . I like ( maybe more than the approach I described in ) , because it clearly limits what a client can do using 0 - RTT for streams . The remaining question is what we should do for non - stream - related frames . I still think that it makes sense to disallow the use of any non - stream - related frame in 0 - RTT packets , considering the fact that : the frames allowed by 0 - RTT and 1 - RTT packets are nevertheless going to be different ( CRYPTO , ACK ) in practice there 's no reason to send non - stream - related frames in 0 - RTT packets potential security issues related to replay 
 FWIW , I think that is about formalizing a poorly - enforced constraint that we might have assumed already existed . It 's not directly a solution to the problem were discussing . I personally do n't think that the cost of processing frames is significant enough to build additional defenses for . Generic anti - DoS measures should suffice . But clearly that 's not a universally held viewpoint . I think we should discuss this in Tokyo . 
 If I understand our correctly , this attack is only possible for a limited amount of time , namely 3 PTO after the server received the Client Initial : 
 3 PTO is not going to defend the server here , because an attacker can control the value . It can delay the Initial packets that it sends ( carrying ACKs ) so that PTO becomes huge . 
 If I understand correctly , the server switches to 1 - RTT right after receiving the Client Initial , does n't it ? That means that PTO will have its initial value , and not be client - controlled . Obviously , this could be a problem on long RTT connections , so maybe that rule about dropping packets needs to be changed . 
 In the scenario that we are discussing ( yeah the thread is getting long ) , the attacker sends the Initial packet that contains an ACK to the server 's Initial . That means that if an attacker can for example send the ACK after 3 seconds ( 3 seconds of RTO ! ) to have an open window of additional 9 seconds to perform an attack . 
 I am concerned with the attack in which the 0 - RTT data is replayed by a third party , maybe also with a replayed " retry token " . Do we want more than 3 packets there ? Do we really want to allow sending a large flow control window of data ? Also , 0 - RTT may very well be rejected by the server . Sending something that changes connection state looks weird , because all these frames can be dropped . 
 Tokyo proposal : limit allowed frames to stuff we know are useful . This leaves CONNECTIONCLOSE , NEWCONNECTIONID , PATHCHALLENGE , PATHRESPONSE , PING , and RETIRECONNECTIONID out for the moment , but if we identify a need , we would do the analysis regarding safety under replay attack and make a decision . This means that extensions would need to make their own assessment about safety . Note that ACK , CRYPTO , and NEWTOKEN are not allowed for other , existing reasons . What would be allowed : STREAM , RESETSTREAM , STOPSENDING , MAXDATA , MAXSTREAMDATA ,  , DATABLOCKED , STREAMDATABLOCKED , STREAMIDBLOCKED , and PADDING . Still open debate between taking this and the PR that has been proposed . 
 I think we need a complementary analysis on expected server behavior . For example , if MAX DATA increase , does that mean sending that much data right now , or does that mean sending a small amount now , and wait until handshake complete to send more ? 
 The congestion controller and the limitations on how many bytes can be sent to an unvalidated address are separate from flow control . What frames are permitted in 0 - RTT has no bearing on those limits . 
 to be clear - with , are you referring to the comment from Tokyo above , or the revised ? 
 This is an issue that never really resolved in Tokyo . It is that I was referring to . See also voluminous list discussion on the topic . 
 LGTM , one nit . Generally looks good . Just need to make sure CONNECTION_CLOSE is allowed everywhere .
Paragraph (version A):
CRYPTO frames MAY appear in packets of any encryption level except
0-RTT.
Paragraph (version A):
CONNECTION_CLOSE MAY appear in packets of any encryption level
other than 0-RTT.
Paragraph (version A):
STREAM frames MUST ONLY appear in the 0-RTT and 1-RTT levels.
Paragraph (version A):
All other frame types MUST only appear at the 1-RTT levels.
Paragraph (version B):
All other frame types MUST only be sent in the 0-RTT and 1-RTT
levels.
Paragraph (version B):
Note that it is not possible to send the following frames in 0-RTT
for various reasons: ACK, CRYPTO, NEW_TOKEN, PATH_RESPONSE, and
RETIRE_CONNECTION_ID.
Paragraph (version A):
The keys used for packet protection are computed from the TLS secrets
using the KDF provided by TLS.  In TLS 1.3, the HKDF-Expand-Label
function described in Section 7.1 of TLS13) is used, using the hash
function from the negotiated cipher suite.  Other versions of TLS
MUST provide a similar function in order to be used QUIC.
Paragraph (version A):
The "extension_data" field of the quic_transport_parameters extension
contains a value that is defined by the version of QUIC that is in
use.  The quic_transport_parameters extension carries a
TransportParameters when the version of QUIC defined in QUIC-
TRANSPORT is used.
Paragraph (version B):
As described in Section 8 of TLS13, use of TLS early data comes with
an exposure to replay attack.  The use of 0-RTT in QUIC is similarly
vulnerable to replay attack.
Paragraph (version B):
Endpoints MUST implement and use the replay protections described in
TLS13, however it is recognized that these protections are imperfect.
Therefore, additional consideration of the risk of replay is needed.
Paragraph (version B):
QUIC is not vulnerable to replay attack, except via the application
protocol information it might carry.  The management of QUIC protocol
state based on the frame types defined in QUIC-TRANSPORT is not
vulnerable to replay.  Processing of QUIC frames is idempotent and
cannot result in invalid connection states if frames are replayed,
reordered or lost.  QUIC connections do not produce effects that last
beyond the lifetime of the connection, except for those produced by
the application protocol that QUIC serves.
Paragraph (version B):
A server that accepts 0-RTT on a connection incurs a higher cost than
accepting a connection without 0-RTT.  This includes higher
processing and computation costs.  Servers need to consider the
probability of replay and all associated costs when accepting 0-RTT.
Paragraph (version B):
Ultimately, the responsibility for managing the risks of replay
attacks with 0-RTT lies with an application protocol.  An application
protocol that uses QUIC MUST describe how the protocol uses 0-RTT and
the measures that are employed to protect against replay attack.  An
analysis of replay risk needs to consider all QUIC protocol features
that carry application semantics.
Paragraph (version B):
Disabling 0-RTT entirely is the most effective defense against replay
attack.
Paragraph (version B):
QUIC extensions MUST describe how replay attacks affects their
operation, or prohibit their use in 0-RTT.  Application protocols
MUST either prohibit the use of extensions that carry application
semantics in 0-RTT or provide replay mitigation strategies.