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

define compound packets #1262

Merged
merged 19 commits into from Apr 11, 2018
Merged

Conversation

kazuho
Copy link
Member

@kazuho kazuho commented Apr 4, 2018

In #630 (comment) @janaiyengar wrote:

Discussed at editors' meeting. We seemed to agree on something like option 4, with some specific rules: create "compound packet types" which have a length, and encode HS+0RTT and HS+1RTT long header packet types. To keep packet processing simple, the long header can be repeated so that a receiver can process parts of the packet under different keys in a straightforward manner.

This doesn't have to be the final resolution, but we should drive this issue to an end.

@kazuho : Would you be interested in driving this? Would you be able to write up a PR with a proposed design (use the one above if you like that design) and propose to the wg?

Thank you for your patience. This is the PR that does what is being suggested. Please take a look.

Some notes:

  • a Compound-Initial packet is sent by client

  • a Compound-Handshake packet is sent by both endpoints

    • a client can use it to send 0-RTT data along with packets ACKing the server's handshake packets prior to ServerFinished
    • a server can use it to send 0.5-RTT data along with ServerFinished
    • a client can use it to send 1-RTT data along with ClientFinished
  • an endpoint is required to process the handshake portion of a compound packet even if the protected part is broken

    • the rationale behind is to not give an on-path attacker the chance of terminating the handshake simply by appending several bytes to the packet (currently, we require an on-path attacker to do AES based on the handshake protection key)

Copy link
Contributor

@MikeBishop MikeBishop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start -- a few comments, but I think this is the right general outline.

@@ -364,6 +364,8 @@ keys are established.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Number (32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Payload Length (16)] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Payload (*) ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally editorial: You could put Payload in the second half of the previous line to avoid having a jagged illustration. Variable-length fields like Payload don't have to have any particular width.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for the review. I've fixed this in a52715a. I will address other issues later (hopefully tomorrow).

@@ -678,6 +687,34 @@ packet protection in detail. After decryption, the plaintext consists of a
sequence of frames, as described in {{frames}}.


## Compound Packets {#packet-compound}

Compound packets allow the sender to assemble an Initial ({{packet-initial}})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might use a different verb than "assemble"; perhaps "combine"?

or a Handshake ({{packet-handshake}}) packet and a Protected
({{packet-protected}}) packet into one UDP packet, thereby reducing the number
of packets required to be emitted when application data can be sent during the
handshake.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question, and important to discuss either way: When sending Compound Initial + 0-RTT, does the minimum packet size apply to the entire compound and not just the Initial section? If so, might be worth mentioning that one intended use-case of this is to meet the minimum with 0-RTT data instead of PADDING.

exception being that it has the Payload Length field. The field designates the
length of the payload of the Handshake packet. The remainder of the UDP packet
contains either a 0-RTT Protected packet or a short header packet
({{short-header}}).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth explaining or giving an example that all the packet header fields are there for the subsequent packet. If that includes the type, by the way, you probably don't actually have to specify what type will be there, since the packet will declare it.

The receiver of a Compound packet MUST individually process the Cryptographic
Handshake packet and the Protected packet being contained. It MUST process the
Cryptographic Handshake packet of a Compound packet even when the Protected
packet being contained is deemed invalid.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd simplify away these terms for the sections of the packet. Simply say that the thing which follows is processed as a separate packet, which might be discarded, buffered, or processed depending on the receiver's current state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and contains its own packet number, and therefore gets acknowledged separately.

Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the name is wrong. Compound implies that there are multiple packets in the one packet. Which is true, but not from the perspective of the Initial or Handshake packet that is included, which is where the label is applied.

That is, rename the packet types to something like Initial-With-Length. The section title is fine.

A Compound-Initial packet is identical to an Initial packet with the exception
being that it has the Payload Length field. The field designates the length of
the payload of the Initial packet. The remainder of the UDP packet contains a
0-RTT Protected packet.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the remainder of the packet doesn't contain a 0-RTT packet?

@kazuho
Copy link
Member Author

kazuho commented Apr 9, 2018

@MikeBishop @martinthomson Thank you for your comments. I think I have addressed all of them. Please take a look.

And I think that the text has become clearer by saying that a compound UDP packet is something that consists of a *-with-Length packet and a protected packet. Thank you to @martinthomson for the suggestion.

Copy link
Contributor

@ianswett ianswett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this, though it reminds me that 32 bit packet numbers in the long header is almost certainly overkill.

@@ -364,7 +364,7 @@ keys are established.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Packet Number (32) |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me think we should move to 2 byte packet numbers.

@ekr
Copy link
Collaborator

ekr commented Apr 9, 2018

This seems OK, but why bother to have extra packet types. We've already expanded the long header quite a bit to make room for the two directional CIDs. Why not just add a length varint and have only one header form

Copy link
Contributor

@MikeBishop MikeBishop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@ianswett
Copy link
Contributor

ianswett commented Apr 9, 2018

In regards to @ekr. If we're going to make the length varint and always present(which I'm happy with), can we make the packet number varint(but not relative) too for consistency?

@mikkelfj
Copy link
Contributor

mikkelfj commented Apr 9, 2018

Note that varint packet numbers has an effect on my proposed variation of #1079 PNE because it is not immediately obvious where the PN begins if you encrypt and attach to the end. This is not an argument against, but a note to consider exposing length info elsewhere +/- privacy concerns.

@ianswett
Copy link
Contributor

ianswett commented Apr 9, 2018

For the context of this PR, I'd slightly favor adding a varint length to all long headers, as EKR suggested.

We can discuss packet numbers elsewhere, because as you said @mikkelfj, it may be complicated.

@mikkelfj
Copy link
Contributor

mikkelfj commented Apr 9, 2018

EDIT: removed longwinded PNE concern - placed here by mistake, moved to 1079.

@kazuho
Copy link
Member Author

kazuho commented Apr 9, 2018

@MikeBishop @ianswett @ekr @mikkelfj Thank you all.

Why not just add a length varint and have only one header form?

I will do this.

OTOH, I agree with @ianswett that how PN of a long header is encoded should better be discussed separately. Reasons: i) they can be discussed separately ii) representation of a PN depends on #1079 iii) representation of a PN may depend on the outcome of the stream 0 redesign.

@mikkelfj
Copy link
Contributor

mikkelfj commented Apr 9, 2018

Oh sorry, I meant to post this PN scheme elsewhere - completely ignoring Ians request by mistake.

@martinthomson
Copy link
Member

Yes, let's solve one problem at a time. The idea of a varint packet number is pretty appealing to me, and I don't think that the stream 0 changes will necessarily change it, but we should probably wait and see.

Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a good change. Nits only, the structure and content is basically fine.

@@ -552,7 +552,7 @@ older than 1.3 is negotiated.

QUIC requires that the initial handshake packet from a client fit within the
payload of a single packet. The size limits on QUIC packets mean that a record
containing a ClientHello needs to fit within 1171 octets.
containing a ClientHello needs to fit within 1170 octets.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An 1170 octet ClientHello will have a two octet length, so this needs to be 1169.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment the PR states that Payload Length field is a varint, and therefore the minimum overhead is 1 octet. Do you think that we should change it to a fix length of 2 octets?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the packet is this big, then the length will be 2 octets. You can't have encode 1170 (or 1169) in one octet. Obviously, if the ClientHello is smaller, then the length might only be 1 octet, but I think that one octet is impossible. ClientHello.random is 32 octets and either a shares is at least 32 octets or a PSK binder is that big too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! Thank you for very much for the clarification.

@@ -403,10 +405,13 @@ Packet Number:
: Octets 13 to 16 contain the packet number. {{packet-numbers}} describes the
use of packet numbers.

Payload Length:

: The length of the Payload field in octets.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...encoded as a variable-length integer.

## Compound Packets {#packet-compound}

A sender can combine multiple QUIC packets (typically a Cryptographic Handshake
packet and a Protected packet) into one UDP packet, thereby reducing the number
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/UDP packet/UDP datagram/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4504fdc.


A sender can combine multiple QUIC packets (typically a Cryptographic Handshake
packet and a Protected packet) into one UDP packet, thereby reducing the number
of UDP packets required to be emitted when application data can be sent during
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

End the sentence at the comma. Then "This can reduce the number of UDP datagrams that are needed to complete the handshake when multiple types of packets are sent at the same time."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5ed67ea.

A sender can combine multiple QUIC packets (typically a Cryptographic Handshake
packet and a Protected packet) into one UDP packet, thereby reducing the number
of UDP packets required to be emitted when application data can be sent during
the handshake.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add: "A packet with a short header doesn't include a length, so it has to be the last packet included in a UDP datagram."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 9dd629e.

always starts at an offset of 0 (see {{stateless-retry}}) and the complete
cryptographic handshake message MUST fit in a single packet (see {{handshake}}).

The payload of a UDP packet carrying the Initial packet MUST be expanded to at
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UDP datagram.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4504fdc.

The payload of a UDP packet carrying the Initial packet MUST be expanded to at
least 1200 octets (see {{packetization}}), by adding PADDING frames to the
Initial packet and/or by combining the Initial packet with a Protected packet
(see {{packet-compound}}).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/Protected packet/0-RTT packet/

No point in being any less precise than needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in d5b7312.

the handshake.

The sender MUST NOT combine QUIC packets belonging to different QUIC
connections into a single UDP packet.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

datagram

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4504fdc.

Every QUIC packet that is being conveyed in a compound UDP packet is a complete
QUIC packet. No fields in the packet header are omitted. The receiver of a
compound UDP packet MUST individually process each QUIC packet and separately
acknowledge them, as if they were received as distinct UDP packets.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/as distinct UDP packets/as the payload of different UDP datagrams/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 49d6f96.

@kazuho
Copy link
Member Author

kazuho commented Apr 10, 2018

@martinthomson Thank you for the super quick feedback. I think that I have addressed all your comments (as well as merging master) with the exception of #1262 (comment). Please take a look.

@kazuho
Copy link
Member Author

kazuho commented Apr 10, 2018

I believe that all known issues have been fixed in commits up to 93fe0be.

Copy link
Contributor

@ianswett ianswett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small editorial suggestions, but looks great, thanks for the fast updates.

The sender MUST NOT combine QUIC packets belonging to different QUIC
connections into a single UDP datagram.

Every QUIC packet that is being conveyed in a compound UDP datagram is a
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd drop "that is being"


A sender can combine multiple QUIC packets (typically a Cryptographic Handshake
packet and a Protected packet) into one UDP datagram. This can reduce the
number of UDP datagrams required to be emitted when application data can be sent
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clarity, how about "number of UDP datagrams sent when application data is sent during the handshake."?

Copy link
Member

@nibanks nibanks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like how clean this design is. Good improvement!


The sender MUST NOT combine QUIC packets belonging to different QUIC
connections into a single UDP datagram.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about packets in the gray zone such as version negotiation and resets?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will address those in a follow-up.


: The length of the Payload field in octets, encoded as a variable-length
integer ({{integer-encoding}}).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came to think a bit about the variable payload length:

It makes it difficult to build a packet when you don't know the length in advance. Of course you can always just start with enough space. The intial packet starts with 1200 bytes (not sure about 0-RTT), and I don't think it can be more than 64K? So wouldn't a fixed 2 byte length field make more sense here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable length is primarily for consistency. There are a few cases where packets will be small enough to benefit from the 6-bit length (Finished primarily), but the main benefit is that this is the same code throughout. Better if we can manage to make the packet number encoding variable length as well (but that interacts in interesting ways with #1079, so that's not as clear a win as this).

@martinthomson martinthomson merged commit 0d1a97c into quicwg:master Apr 11, 2018
martinthomson added a commit that referenced this pull request Apr 11, 2018
@janaiyengar
Copy link
Contributor

Coming in late, but I like the final shape of this. Thanks, @kazuho, for driving this quickly!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants