Subject: [quicwg/base-drafts] No need to use RCID if the peer requests it (#3550)

From: ianswett <[email-masked]>
Date: Sat, 28 Mar 2020 16:35:40 -0700

If the peer requests CIDs be retired via Retire Prior To in the NEW_CONNECTION_ID frame, there&#39;s no need to send a RETIRE_CONNECTION_ID frame for those, just start using a CID with an index &gt;= Retire Prior To.

Fixes #3509
You can view, comment on, or merge this pull request online at:

  https://github.com/quicwg/base-drafts/pull/3550

-- Commit Summary --

  * No need to use RCID if the peer requests it

-- File Changes --

    M draft-ietf-quic-transport.md (32)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/3550.patch
https://github.com/quicwg/base-drafts/pull/3550.diff

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550

---

From: Kazuho Oku <[email-masked]>
Date: Sat, 28 Mar 2020 16:42:37 -0700

I think that the change by itself would not be a bad idea, though I would point out that an endpoint still needs to restrict the number of CIDs sent using RCID, to protect itself from the other attack that uses migration as the attack vector (#3509 (comment)).

The beauty of #3547 is that it provides a unified way of defending against the attacks (by allowing and endpoint to limit the stack it uses for tracking RCIDs). Compared to that, this PR would require two mitigations: limit the state _and_ special-case for handling RPT.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#issuecomment-605534277

---

From: ianswett <[email-masked]>
Date: Sat, 28 Mar 2020 17:01:38 -0700

@ianswett pushed 1 commit.

d74e2b18b904ac6566f5a36ee6e03cdadc85af1e  Update draft-ietf-quic-transport.md

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550/files/13b461d32201bd02002d3ee64ab3f805aab28486..d74e2b18b904ac6566f5a36ee6e03cdadc85af1e

---

From: ianswett <[email-masked]>
Date: Sat, 28 Mar 2020 17:47:01 -0700

Thanks for reminding me @kazuho I think this text mitigates that issue:
"An endpoint MUST NOT provide more connection IDs than the peer's limit. An endpoint that receives more connection IDs than its advertised active_connection_id_limit MUST close the connection with an error of type CONNECTION_ID_LIMIT_ERROR."

However, if a peer sends a NCID and doesn't increase Retire Prior To in this case, then it's unclear which RETIRE_CONNECTION_ID frame(s) were received.  In that case, is it ever clear which RETIRE_CONNECTION_ID frames were received?  I'm not sure #3547 actually solves this, or just makes it much less likely?

I'm starting to think we need a max_connection_id in RETIRE_CONNECTION_ID(or a separate MAX_CONNECTION_ID frame) as a flow control style mechanism to solve this fully?  I think this PR may be a good change anyway, but I'm not sure it's sufficient.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#issuecomment-605539706

---

From: Kazuho Oku <[email-masked]>
Date: Sat, 28 Mar 2020 18:02:24 -0700

@ianswett 

That text does not mitigate the issue, because te the endpoint that sends RCID, a CID becomes inactive when (or before when) it sends the RCID frame carrying that CID for the first time.

When the peer receives that RCID frame, it peer is allowed to provide a new CID before sending an ACK, or before that ACK is being received by the peer.

> However, if a peer sends a NCID and doesn't increase Retire Prior To in this case, then it's unclear which RETIRE_CONNECTION_ID frame(s) were received. In that case, is it ever clear which RETIRE_C…

IIUC, the defense in #3547 is that the endpoint is allowed (recommended) to cease sending RCID frames carrying some CIDs under extreme circumstances. This approach will work regardless of an attack (at the theoretical cost of having interoperability problems, though it would be unlikely assuming that each endpoint would track sufficient number of CIDs being retired).

> I'm starting to think we need a max_connection_id in RETIRE_CONNECTION_ID(or a separate MAX_CONNECTION_ID frame) as a flow control style mechanism to solve this fully?

I share the view that that is the cleanest way of fixing the issue.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#issuecomment-605540981

---

From: ianswett <[email-masked]>
Date: Sun, 29 Mar 2020 18:19:40 -0700

Fair points, if we think #3547 is sufficient, let's go forward with something along those lines.  If we want to also land this PR, we can, but as you point out it's not sufficient.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#issuecomment-605734882

---

From: Martin Thomson <[email-masked]>
Date: Sun, 29 Mar 2020 18:21:45 -0700

@martinthomson requested changes on this pull request.

This seems like a perfectly good change.  The endpoint is no longer requesting retirement; it is unilaterally declaring that it will not honour the connection IDs.  That's consistent with the existing design.

I do have some problems with the specifics of the proof of receipt structure you describe, however.  It might be sufficient to just keep the existing squishy text about keeping state for "a while" as the only language on the subject.

We should also say something about RETIRE_CONNECTION_ID frames that target sequence numbers before the cutoff.  I think that it is safe to say that they can be ignored.

> @@ -1007,11 +1007,12 @@ initial connection ID.
 When an endpoint issues a connection ID, it MUST accept packets that carry this
 connection ID for the duration of the connection or until its peer invalidates
 the connection ID via a RETIRE_CONNECTION_ID frame
-({{frame-retire-connection-id}}).  Connection IDs that are issued and not
-retired are considered active; any active connection ID is valid for use with
-the current connection at any time, in any packet type.  This includes the
-connection ID issued by the server via the preferred_address transport
-parameter.
+({{frame-retire-connection-id}}) or it invalidates the connection ID by
+increasing the the Retire Prior To field.  Connection IDs that are issued and

If the intent of this PR is to say "I'm retiring these connection IDs, whether you like it or not", then maybe a name change is in order.  As this is a declaration, maybe "Retired Prior To" or "Invalid Prior To".

> @@ -1056,18 +1057,20 @@ An endpoint might need to stop accepting previously issued connection IDs in
 certain circumstances.  Such an endpoint can cause its peer to retire connection
 IDs by sending a NEW_CONNECTION_ID frame with an increased Retire Prior To
 field.  The endpoint SHOULD continue to accept the previously issued connection
-IDs until they are retired by the peer.  If the endpoint can no longer process
-the indicated connection IDs, it MAY close the connection.
+IDs until a connection ID greater than or equal to the Retire Prior To value is
+used by the peer.  If the endpoint can no longer process the indicated

"until a connection ID greater than or equal to the Retire Prior To value" doesn't work.

Say you have 10 active.  You can still issue up to 15  before you send "Retire Prior To" with a value of 10.  So use of connection ID 15 is no good signal that the retirement was accepted.

I think that what you meant to say here is "until the peer uses a connection ID with a sequence number greater than the one included in the NEW_CONNECTION_ID that invalidated the previous connection ID" or some such.  Noting of course that you can send NEW_CONNECTION with seq 16 and RPT of 0 followed by NEW_CONNECTION_ID { seq 16, RPT 10 } totally legitimately; in which case you can't rely on use of CID[16] to mean anything.

It would also not be entirely wise to drop connection IDs at the point that you see the new ones being used, even if your assumption was true.  Though you might have confirmation that a stateless reset won't kill the connection, you would still be dropping perfectly good packets that are still totally usable.

 Upon receipt of an increased Retire Prior To field, the peer MUST stop using the
-corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames
-before adding the newly provided connection ID to the set of active connection
-IDs. This ordering allows an endpoint that has already supplied its peer with as
-many connection IDs as allowed by the active_connection_id_limit transport
-parameter to replace those connection IDs with new ones as necessary.  Failure
-to cease using the connection IDs when requested can result in connection
-failures, as the issuing endpoint might be unable to continue using the
-connection IDs with the active connection.
+corresponding connection IDs.  Use of a newly provided connection ID proves

This is not proof.  See above.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#pullrequestreview-383481495

---

From: martinduke <[email-masked]>
Date: Mon, 30 Mar 2020 09:04:14 -0700

So if the NCID with this information is lost, then there could be a storm of packets with a unilaterally retired CID, no? This seems like a problem, unless we're going to use implicit acks as a state transition, which is fraught..

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#issuecomment-606090101

---

From: Nick Banks <[email-masked]>
Date: Tue, 31 Mar 2020 07:47:32 -0700

@nibanks commented on this pull request.

I definitely prefer this type of change over changing the wire format of the RCID frame. Though I still think this design here is significantly more complicated to implement than using the ACK, as you've got to track the "new CID sequence number" for every CID you force your peer to retire and then for every packet that comes in that changes CID you're going to have to iterate through all your retired CIDs (that you're forced to track for this) and check if the new CID's sequence number is greater.

For the ACK design, when a packet is acknowledged you look at the metadata for the packet. Oh, it retired CID X? Go clean it up now. There are no look ups, extra tracking state or walking any lists of things.

I like the "Retired Prior To". I think we should still consider this as retiring the CID, and not introduce a new term/concept like invalid.

I agree with Martin here. The next needs to be updated to refer to the NCID sequence number instead.

Well, the use of the **newly provided** connection ID is proof but that's not what the text above talks about, as you've pointed out.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/3550#pullrequestreview-384799399