Subject: [quicwg/base-drafts] Encrypt key phase (#1339)

From: Martin Thomson <[email-masked]>
Date: Mon, 07 May 2018 07:08:12 +0000 (UTC)

This is what encrypting the KEY_PHASE might look like, at least to start with.  This builds on #1334.  It's not intended to be merged, just to serve as a discussion point.

@kazuho suggested that we extend the encrypted portion into the type byte.  That's a natural extension of this.  One potential advantage of that is that we might get more bits for packet numbers.

There's also the possibility of making the long and short headers use the same encoding and to use the KEY_PHASE in the long header to indicate use of 0-RTT, which would eliminate the differences I had to introduce here.  I'm sure that there are other options there as well.
You can view, comment on, or merge this pull request online at:

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

-- Commit Summary --

  * First pass at varint packet numbers
  * tweaks, thanks Martin and Ian
  * long headers too
  * Both long and short have varint PN
  * TLS draft changes for protecting key phase with PN
  * Move the KEY_PHASE into the short header packet number encoding
  * Update examples for shorter encodings
  * Superficial only
  * Merge branch 'fix-pn-example' into encrypt-key-phase
  * Update examples for varying sizes

-- File Changes --

    M draft-ietf-quic-tls.md (51)
    M draft-ietf-quic-transport.md (107)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/1339.patch
https://github.com/quicwg/base-drafts/pull/1339.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/1339

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 07 May 2018 13:59:46 +0000 (UTC)

Thank you for working on the PR.

> @kazuho suggested that we extend the encrypted portion into the type byte. That's a natural extension of this. One potential advantage of that is that we might get more bits for packet numbers.

Current form of this PR proposes of moving the key-phase bit and the PN lengths bits into the encrypted PN field. It means that the range that can be expressed with certain lengths of the encrypted PN field becomes 2 to 3 bits less than what we have in current draft.

OTOH, if we extend the encrypted portion to the type byte and continue to have the bits there, the range does not change.

So let's consider the numbers. The following is the maximum bandwidth that can be covered with certain lengths of the encrypted PN field for both approaches (see [section 4.8](https://quicwg.github.io/base-drafts/draft-ietf-quic-transport.html#rfc.section.4.8) for the relation between the maximum numbers of packets in-flight and the length of the PN field) under the following condition: RTT 100ms, MTU 1400 octets. Note that the calculation depends on BDP, so the bandwidth increases as latency decreases.

|location \ size of encrypted PN|1 octet|2 octets|4 octets|
|:---:|---:|---:|---:|
|bits in encrypted PN field|1.71Mbps|438Mbps|28.7Tbps|
|bits in type|427Kbps|54.7Mbps|3.58Tbps|

Looking at these numbers, I am inclined to having the bits in the type octet, assuming that we care about spending one or two less octet per packet when possible, because IMO we would have certain amount of connections between 427Kbps and 1.71Mbps, or between 54.7Mbps and 438Mbps. (Or if we do not care about spending one less octet, how about removing 1-octet PN from the specification?)

> There's also the possibility of making the long and short headers use the same encoding and to use the KEY_PHASE in the long header to indicate use of 0-RTT, which would eliminate the differences I…

I haven't thought of it, but that sounds like an interesting idea. I think it would be great if we could reduce the complexity by adjusting how the bits of the long header are used.

-- 
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/1339#issuecomment-387073720

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 07 May 2018 14:37:18 +0000 (UTC)

PS. The bandwidth of the chart is calculated based on the statement in section 4.8 stating that
> The sender MUST use a packet number size able to represent more than twice as large a range than the difference between the largest acknowledged packet and packet number being sent.

The thresholds will become smaller (by same proportion) if we consider the following SHOULD:
> An endpoint SHOULD use a large enough packet number encoding to allow the packet number to be recovered even if the packet arrives after packets that are sent afterwards.

-- 
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/1339#issuecomment-387085377

---

From: MikkelFJ <[email-masked]>
Date: Mon, 07 May 2018 14:41:02 +0000 (UTC)

I'm not sure how you get that bandwidth. I would compute it as:

If 1 octet PN has the range 0..127, we can have nearly half that in flight, so roughly 63 packets. Since RTT is 100ms we have 630 packets per second. Each packet has 1400 bytes totalling 630 * 1400 bytes / sec = 882,000 bytes per second or 8 times than in bits per second so 8 * 882,000 bps = 7.056 Mbps. And for actual bandwidth, headers must be accomodated for.

I'm not really sure that using RTT is correct because once the peer gets the packet the number is known and ACK's do not use truncated PN's. So we could actually have twice the above bandwidth or about 14Mbps

-- 
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/1339#issuecomment-387086652

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 07 May 2018 14:54:46 +0000 (UTC)

@mikkelfj Thank you for checking the numbers.

> If 1 octet PN has the range 0..127, we can have nearly half that in flight, so roughly 63 packets.

My interpretation of the current draft is that 1 octet PN has the range between -128..127, and that we can send 128 (it might be 127) packets per RTT. Which ends up having 13.7Mbps for 1 octet PN.

Considering the fact that you seem to reach the same number, could it be the case that your confusion is related to how we interpret the draft?

-- 
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/1339#issuecomment-387091351

---

From: MikkelFJ <[email-masked]>
Date: Mon, 07 May 2018 15:14:12 +0000 (UTC)

mm possibly. In the long header there are 7 bits for PN, so you don't have -128..+127, but half that.
For the short headers it is actuall half that again (6 bits) due to the key phase. So bandwidth again halves. Now down to 3.5 Mbps which is, well, you number.

-- 
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/1339#issuecomment-387098162

---

From: Martin Thomson <[email-masked]>
Date: Mon, 07 May 2018 17:35:20 -0700

Yes, as I pointed out, moving some of the bits back to the type byte increases these values by the same amount.  But I want to wait to do that until we've sorted out the allocation of bits in that octet.  

Right now we have bits reserved for experimentation (spin bit), bits reserved for migration from Google QUIC, and bits reserved for ease of multiplexing with RT protocols.  That's a thicket we need to navigate before we have any hope of getting more bits back.

FWIW, 3.5Mbps is a fairly generous throughput for a lot of use cases, on no more than one octet of PN.  As mentioned, salvaging just 2 more bits quadruples the usefulness of that single octet, which is a nice gain.

-- 
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/1339#issuecomment-387247821

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 07 May 2018 17:57:49 -0700

kazuho commented on this pull request.

> +secrets.  A packet protection key is used to protect the packet number from
+casual observation.  The packet number protection key is derived from the first
+packet protection secret using the label "pn".  This key is produced using the
+same process as the AEAD key and IV, but the value is not updated with each key
+update ({{key-update}}).
+
+~~~
+pn_key = QHKDF-Expand(pp_secret<0>, "pn", pn_key_length)
+~~~
+
+That is, for the algorithms defined in this document, the packet protection key
+is determined to be:
+
+~~~
+client_pn_key  = QHKDF-Expand(client_pp_secret<0>, "pn", 16)
+server_pn_key  = QHKDF-Expand(server_pp_secret<0>, "pn", 16)

My understanding is that `pp_secret` only exists for 1-RTT. Do we need to define similar constructs for handshake secret and 0-RTT secret?

-- 
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/1339#pullrequestreview-118200510

---

From: Martin Thomson <[email-masked]>
Date: Mon, 07 May 2018 18:04:29 -0700

martinthomson commented on this pull request.

These are examples.  The same secret that you would use for getting a key or IV should work for 0-RTT and the handshake.  That probably needs work though.

-- 
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/1339#discussion_r186593086

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 07 May 2018 18:05:45 -0700

+1 to what @martinthomson says.

So let's my propose a straw-man. How about something like below? The bits marked as "encrypt here" gets XORed by the CTR output.

```
long header:
+-+-+-+-+-+-+-+-+
|1|P P|0|0|T T T|
+-+-+-+-+-+-+-+-+
  |<----->|
 encrypt here

short header:
+-+-+-+-+-+-+-+-+
|0|P P|K|0|R R R|
+-+-+-+-+-+-+-+-+
  |<----->|
 encrypt here

T - long header types
P - PN length bits
K - key-phase bit
R - the reserved bits (e.g. spin bit)
```

Some notes:
* Currently, we have only four long header types, so we might want to steal one bit from `T` and encrypt it for greasing. The downside is that the region which we encrypt becomes different between the two header types.
* Whether a packet is a handshake packet or a 0-RTT protected packet has been left in clear (as the type bits), under the assumption that we would have different pn-keys for the two contexts (see my review comment).
* I haven't changed the demux bit being the 3rd bit (from LSB) of the short header, which is part of the reserved bit.

-- 
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/1339#issuecomment-387252741

---

From: Martin Thomson <[email-masked]>
Date: Mon, 07 May 2018 18:08:22 -0700

That sounds reasonable.  I hope that we don't lose it by the time that the opportunity to come back to this comes around :)

-- 
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/1339#issuecomment-387253148

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 07 May 2018 18:35:51 -0700

FWIW, I think that we have fair chance of adopting the encoding now and staying with it until very late of the standardization process (since it preserves the three reserved bits and have some extra room in the long header type bits). But I won't push strongly.

-- 
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/1339#issuecomment-387257077

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 08 May 2018 18:38:10 -0700

Thank you for the clarification. I think my confusion came from the statement saying
> The packet number protection key is derived from **the first packet protection secret** using the label "pn".

which seem to imply a 1-RTT secret, since section 5.3.4 (1-RTT secrets) has the following sentence:
> **The initial client packet protection secret** is exported from TLS using the exporter label “EXPORTER-QUIC client 1rtt”.

-- 
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/1339#discussion_r186911678

---

From: Mike Bishop <[email-masked]>
Date: Wed, 09 May 2018 12:29:15 -0700

> > There's also the possibility of making the long and short headers use the same encoding[....]
>

Just to comment on this particular piece:  The first byte of the long header is version-independent.  The first byte of the short header is version-specific, except for the first bit.  Attempting to keep them quasi-identical might be feasible for v1, but feels like it's somewhere between a bad precedent and wasted effort, since we likely will want to change something here in future versions.

-- 
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/1339#issuecomment-387849419

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 09 May 2018 19:44:13 -0700

@MikeBishop:
> Just to comment on this particular piece: The first byte of the long header is version-independent. The first byte of the short header is version-specific, except for the first bit.

Would you mind elaborating why it is? By looking at the charts of [section 4 of the Invariants draft](https://quicwg.github.io/base-drafts/draft-ietf-quic-invariants.html#rfc.section.4), my understanding is that only the most significant bit is an invariant for both the long and the short header.

-- 
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/1339#issuecomment-387935081

---

From: Martin Thomson <[email-masked]>
Date: Wed, 09 May 2018 21:47:54 -0700

@martinthomson pushed 1 commit.

50fab43  Merge branch 'master' into encrypt-key-phase

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/1339/files/129d1201a5fdf4f38f3378c675a7b695a588c607..50fab43885fcc97792b0e65509825f86b5632562

---

From: Mike Bishop <[email-masked]>
Date: Thu, 10 May 2018 11:19:57 -0700

@kazuho, you're correct.  I was misremembering.  Don't mind me....

-- 
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/1339#issuecomment-388140006

---

From: Martin Thomson <[email-masked]>
Date: Sun, 20 May 2018 18:49:20 -0700

Closed #1339.

-- 
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/1339#event-1636156952

---

From: Martin Thomson <[email-masked]>
Date: Sun, 20 May 2018 18:49:19 -0700

Because open pull requests are a liability.

-- 
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/1339#issuecomment-390532031