Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can a client send 0-RTT data when receiving Retry? #1507

Closed
kazuho opened this issue Jun 30, 2018 · 12 comments
Closed

Can a client send 0-RTT data when receiving Retry? #1507

kazuho opened this issue Jun 30, 2018 · 12 comments
Labels
-transport design An issue that affects the design of the protocol; resolution requires consensus. has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list.

Comments

@kazuho
Copy link
Member

kazuho commented Jun 30, 2018

In previous drafts (up to -12), use of 0-RTT was forbidden when the server sends a Retry (due to the restriction of TLS 1.3). The restriction no longer exists in -13, most likely due to the fact that retry no longer involves a TLS handshake that had that restriction.

Hence the question: is a client allowed to send 0-RTT data when receiving a Retry?

My view is that, while there is no need to prohibit that, we should state that:

  • servers might want to reject 0-RTT when under attack, because it is an useful tool for an attacker to consume server CPU / memory (one example of such an attack is to send a copy of ClientHello and 0-RTT data containing idempotent HTTP requests)
  • clients are recommended to NOT send 0-RTT data after seeing a Retry packet because it is a sign of server being under an attack, though such a server might still accept 0-RTT data that has been sent

relates to: #1498

@nibanks
Copy link
Member

nibanks commented Jun 30, 2018

I think that 0-RTT should be allowed. Generally, DDoS mitigation is just trying to prove source address ownership and then everything should continue as normal, including 0-RTT. I don't think we should have a MUST for the server to support it, but I think we should allow it.

@ekr
Copy link
Collaborator

ekr commented Jun 30, 2018

I think the client should be allowed to send 0-RTT.

I wonder if we should have a field in the Retry that says "don't send 0-RTT". Of course, you'd want to somehow protect that, which would be a pain

@martinthomson martinthomson added design An issue that affects the design of the protocol; resolution requires consensus. -transport labels Jul 2, 2018
@martinthomson
Copy link
Member

What does the server do with the 0-RTT packets? Does the server have to keep the same connection ID for the packets to arrive at the right place?

TLS could have allowed 0-RTT to continue after a HelloRetryRequest, but decided not to allow it. For that reason, I'd assumed that we would follow the same design here. If 0-RTT is accepted (and can't see a concrete reason not to allow it), then we need to consider what the consequences are.

@ekr
Copy link
Collaborator

ekr commented Jul 2, 2018

What does the server do with the 0-RTT packets?

This is already an issue with 0-RTT, because the client generates a fresh CID which sends you to a random location

Does the server have to keep the same connection ID for the packets to arrive at the right place?

I don't understand the question. You mean the same CID when it sends the Retry? Why would that be needed?

TLS could have allowed 0-RTT to continue after a HelloRetryRequest, but decided not to allow it. For that reason, I'd assumed that we would follow the same design here. If 0-RTT is accepted (and can't see a concrete reason not to allow it), then we need to consider what the consequences are.

I don't think that's a very good analogy, because a consequence of this design is that the Retry happens entirely below the TLS layer. Saying that 0-RTT is forbidden here is more like saying that it's forbidden if you have a TFO failure.

@martinthomson
Copy link
Member

The point is that if the handshake is successful, then the ClientHello and all the 0-RTT have the same destination connection ID, so they probably end up at the same point. Add Retry and they might not.

I think that the TLS analogy is fine. In TLS, a server could want a different key share, but find the PSK perfectly adequate for the purposes of 0-RTT. There's no reason a server that sends HelloRetryRequest would need to stop accepting 0-RTT.

@ekr
Copy link
Collaborator

ekr commented Jul 2, 2018

The point is that if the handshake is successful, then the ClientHello and all the 0-RTT have the same destination connection ID, so they probably end up at the same point. Add Retry and they might not.

Huh? If you do Retry, you resend initial and this includes resending CH and 0-RTT.

I think that the TLS analogy is fine. In TLS, a server could want a different key share, but find the PSK perfectly adequate for the purposes of 0-RTT. There's no reason a server that sends HelloRetryRequest would need to stop accepting 0-RTT.

Yes, of course, but that creates complexity in the TLS state machine because of the way CH and HRR are intertwined. That is not so for Retry.

@mikkelfj
Copy link
Contributor

mikkelfj commented Jul 2, 2018 via email

@ekr
Copy link
Collaborator

ekr commented Jul 2, 2018

A 0-RTT retry probably should mean try again with a 1-RTT if it should at all respond to retry because as Martin already pointed out, a redirected server likely won’t have the keys whether an endpoint or a middlebox triggers the retry.

I don't see why this would be the case. The original Initial packet is destined to some random server in the server farm. At worst, the retried Initial packet will also be sent to a random server, but at best the server will redirect it. How is that worse?

@mikkelfj
Copy link
Contributor

mikkelfj commented Jul 2, 2018

Ignoring retry, a 0-RTT that is routed to a random location isn't worth very much in the general case. If that is really the case, we should look at how 0-RTT manages the original DCID.

martinthomson added a commit that referenced this issue Jul 3, 2018
After the discussion on #1507, I've been convinced that there is no real
value in preventing a client from attempting 0-RTT after a Retry.  And,
it would seem like Version Negotiation has essentially the same
properties, so excluding it would be inconsistent.

This allows this, explores the consequences for packet numbers (don't
reset them!), and updates the recovery text to include Version
Negotiation.

Closes #1507.
martinthomson added a commit that referenced this issue Jul 9, 2018
After the discussion on #1507, I've been convinced that there is no real
value in preventing a client from attempting 0-RTT after a Retry.  And,
it would seem like Version Negotiation has essentially the same
properties, so excluding it would be inconsistent.

This allows this, explores the consequences for packet numbers (don't
reset them!), and updates the recovery text to include Version
Negotiation.

Closes #1507.
@kazuho
Copy link
Member Author

kazuho commented Jul 18, 2018

Note that since -13, the settings of the previous connection will be retained in the token. There is no longer an extension slot in NewSessionTicket. The conveyer of address validation data and setting information has moved to token.

However, token (which is contained in a Initial that attempts a 0-RTT) is replaced once the server sends a Retry packet.

That makes handling of 0-RTT a bit complicated (when Retry is possibly involved), especially when the information about previous settings is necessary to determine if a server accepts the 0-RTT (see #1541).

@martinthomson
Copy link
Member

I don't think that token handling is all that difficult here. The token doesn't need to be treated any differently than a second Retry: the client replaces the token it has with the token from Retry.

Some text might be necessary though.

@kazuho
Copy link
Member Author

kazuho commented Jul 19, 2018

I don't think that token handling is all that difficult here.

One of the issues here is that an on-path or a man-on-the-side attacker can mount a cut-and-paste attack that replaces token with a different value.

Let me explain one possible attack, that happens in following steps:

  1. attacker connects to the server and obtains a token that says "server-config=A"
  2. client connects to the server and obtains a NST and a token that says "server-config=B". At this
  3. client tries to reconnect to the server using the NST and the token obtained in step 2
  4. an attacker enforces a retry by sending a token obtained in step 1

At this point, client believes that it can send 0-RTT packets based on the negotiated settings in step 2, which is "server-config=B". The server would assume that the 0-RTT packets that it will receive is based on "server-config=C".

I am not sure how scary it sounds right now, however it could become a practical concern when we start adding extension frames to QUIC.

To avoid this type of attack, the server needs to do something like:

  • store the server settings in the session ticket rather than the token. TLS stacks will need to provide an interface for that (if they do not provide one yet), or
  • have a different STEK for every server-config, so that resumption will fail if the client provides tries to resume with a PSK that is not bound to the server-config found in the token

@mnot mnot added the has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list. label Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-transport design An issue that affects the design of the protocol; resolution requires consensus. has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list.
Projects
None yet
Development

No branches or pull requests

6 participants