Subject: [quicwg/base-drafts] token-based greasing (#3166)

From: Kazuho Oku <[email-masked]>
Date: Mon, 28 Oct 2019 21:10:27 -0700

Based on the discussion in #3111, this PR implements greasing using the NEW_TOKEN frame as the conveyor.

It defines defines three properties: Alternative Version Number, Packet Type Modifier, Initial Salt, for obfuscating the version number field and the long header packet type, as well as encrypting the Initial packet payload.

Those three properties are carried by a NEW_TOKEN frame, and a client uses those &quot;alternative initial sets&quot; when resuming a connection using a NEW_TOKEN token. A server that is not interested in greasing or encrypting the Initial packets can advertise the values defined in the specification as the &quot;alternative initial sets,&quot; and the client behavior would be the same as it is now (with the only difference being that the format of NEW_TOKEN frame has changed).

Closes #2496, closes #3111, an alternative to #2573.
You can view, comment on, or merge this pull request online at:

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

-- Commit Summary --

  * first cut

-- File Changes --

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

-- Patch Links --

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

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 28 Oct 2019 21:33:17 -0700

@kazuho pushed 1 commit.

5067498c146c1f1f4f1bbd423c6c755d82e831a9  editorial

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/048788ca364c744727bea13e46e6a3408215dcbd..5067498c146c1f1f4f1bbd423c6c755d82e831a9

---

From: Marten Seemann <[email-masked]>
Date: Mon, 28 Oct 2019 22:21:53 -0700

marten-seemann commented on this pull request.

I like this approach, thanks for writing this up @kazuho.

While greasing helps against a passive attacker, it only helps against an active attacker if the set of of alternative version numbers is large, so large that the attacker can't obtain all alternatives by connecting to the server (a reasonable number of times).

An easy way to do this is to derive alternative version numbers by applying a transformation on the version number, e.g. use every number that fulfils `hash(salt || alternative version number) mod 4 == 0` as an alternative. This would generate a huge set of alternative version numbers. In that case, the server would probably also want to encode the initial salt into the token.

-- 
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/3166#pullrequestreview-308280093

---

From: Kazuho Oku <[email-masked]>
Date: Mon, 28 Oct 2019 23:53:27 -0700

@marten-seemann I'm not sure if that actually works.

Because how a token is embedded in an Initial packet depends on the actual version of the QUIC packet that the server is processing. Therefore, I think that the server needs to first consult the version number on the wire, then use that to determine where the token is to decrypt the initial salt contained in the token.

Or are you suggesting something different?

-- 
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/3166#issuecomment-547282565

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 02:09:34 -0700

@kazuho pushed 1 commit.

58468c5c0b6dde5581a36e63826a035dead1fc4b  define downgrade prevention

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/5067498c146c1f1f4f1bbd423c6c755d82e831a9..58468c5c0b6dde5581a36e63826a035dead1fc4b

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 02:15:00 -0700

@kazuho pushed 1 commit.

42a73875e83f4ab9259f9c7f1e539d1f043d1afa  clarify the requirement when building a token

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/58468c5c0b6dde5581a36e63826a035dead1fc4b..42a73875e83f4ab9259f9c7f1e539d1f043d1afa

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 02:19:04 -0700

@kazuho pushed 1 commit.

81dc3d9ea9b3988c97f1055df176e684f2ef2c15  editorial

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/42a73875e83f4ab9259f9c7f1e539d1f043d1afa..81dc3d9ea9b3988c97f1055df176e684f2ef2c15

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 02:32:31 -0700

@kazuho pushed 1 commit.

2553793365eab1a49b4ae9b8d630777306e5b16f  protect token using checksum (reusing text from #3120 by @DavidSchinazi)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/81dc3d9ea9b3988c97f1055df176e684f2ef2c15..2553793365eab1a49b4ae9b8d630777306e5b16f

---

From: David Schinazi <[email-masked]>
Date: Tue, 29 Oct 2019 10:41:27 -0700

DavidSchinazi commented on this pull request.

Thanks for writing this up! I like the token approach but we might need to tighten how this interacts with version negotiation.

> @@ -2721,6 +2721,66 @@ between endpoints.  Application protocols SHOULD define rules for handling
 streams that are prematurely cancelled by either endpoint.

+# Alternative Initial Set {#alternative-initial}
+
+In order to avoid ossification of the cleartext and obfuscated fields of QUIC
+packets, a server can announce an alternative set of initial values to be used,
+which is comprised of:
+
+* Alternative version number; a 32-bit unsigned number that is to be presented
+  on wire in place of the version number specified in this document.  This value
+  MUST NOT be a reserved version ({{versions}}).
+
+* Packet type modifier; a two-bit value that is to be applied as a bit-wise
+  exclusive or (XOR) to the most significant bits of the Initial, Handshake,

Shouldn't this be `to the Long Packet Type field of` instead of `to the most significant bits of` ?

> +  0-RTT, and Retry packets. This XOR is applied after the packets are encrypted
+  and before they are decrypted.
+
+* Alternative initial salt; a 16-byte binary blob that is to be used in place of
+  the initial salt defined in section 5.2 of {{QUIC-TLS}}.
+
+A server advertises these values using a NEW_TOKEN frame {{frame-new-token}}.
+The token MUST include or associated with the alternative version number with
+which it can be used.
+
+Typically, a server would pre-allocate a set of unused version numbers as the
+alternative version numbers, associating each of those version numbers with a
+packet type modifier chosen at random.  Then, when issuing a token using a
+NEW_TOKEN frame, the server generates the alternative initial salt by calling a
+pseudo-random function, embeds that initial salt into the token which is then
+encrypted, and sends a NEW_TOKEN frame that comprises of the generated token and

I might be worth adding a bit more detail to how the token is encrypted, perhaps `which is then encrypted using a key only known to the server`

> +NEW_TOKEN frame, the server generates the alternative initial salt by calling a
+pseudo-random function, embeds that initial salt into the token which is then
+encrypted, and sends a NEW_TOKEN frame that comprises of the generated token and
+the alternative initial set.
+
+When the client reconnects to the server by using the provided token and the
+alternative initial set, the server first checks if the version number field of
+the incoming packet contains one of the alternative version numbers it
+advertises, then if that is the case, applies the corresponding packet type
+modifier to recover the correct packet type.  If the recovered packet type is an
+Initial packet and that packet contains a NEW_TOKEN token, the server decrypts
+the embedded token and recovers the alternative initial salt, uses that to
+decrypt the payload of the Initial packet.
+
+When the server is incapable of determining the alternative initial salt, it can
+send a Version Negotiation packet that instructs the client to use the default

In the current spec, the client fails the connection upon receipt of a Version Negotiation packet. So this has a dependency on the version downgrade prevention extension.

But assuming the presence of a version negotiation mechanism with downgrade prevention, I think we have an issue here. If the server rotates the key it uses to encrypt the alternative initial salt, and then receives a token it can no longer decrypt, it sends a version negotiation packet, and the client tries again with QUICv1. This is likely to trip the version downgrade prevention mechanism - how do we distinguish between a server that has forgotten their key and an attacker that is trying to force a downgrade to QUICv1?

> @@ -3940,6 +4007,19 @@ described in {{QUIC-TLS}}.  This protection does not provide confidentiality or
 integrity against on-path attackers, but provides some level of protection
 against off-path attackers.
 
+Additionally, the token is accompanied by a checksum.  This is because when a

Seeing a checksum here makes me uncomfortable. We're adding a checksum to retry packets because they have no other mechanism to detect corruption. Initial packets on the other hand have an auth tag, so a corrupted token will cause the deprotection to fail. In an ideal world we should handle that like any other corruption on the initial packet. But I think this goes back to my other question about version negotiation, I think there be dragons.

-- 
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/3166#pullrequestreview-308689911

---

From: Mike Bishop <[email-masked]>
Date: Tue, 29 Oct 2019 12:02:22 -0700

MikeBishop commented on this pull request.

This direction is starting to sound reasonable.

+which it can be used.

At a minimum, "be associated with."  But better, I think, to say that the token MUST permit the server to recover the base version number associated with the obfuscated version, the salt, and the mask.  Exactly how the server arranges that is an implementation detail.

```suggestion
encrypted, and sends a NEW_TOKEN frame that contains the generated token and
```

I second the question here; the checksum doesn't appear to serve a purpose not already covered here.

-- 
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/3166#pullrequestreview-308759320

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 14:47:37 -0700

kazuho commented on this pull request.

Definitely Yes! I missed the fact that we had a name for the two bits. Thank you.

-- 
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/3166#discussion_r340342083

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 14:52:42 -0700

This PR has a built-in downgrade prevention mechanism.

The requirement we have in this PR is that each NEW_TOKEN token that the server issues is linked to a particular alternative version number.

When a server receives an Initial packet with an alternative version number it recognizes but with a token it cannot use, the server sends a VN. The client reconnects using V1, but the text in the PR requires the client to continue using the token. Then, when the server receives the V1 packet with the token, and can in fact use the token and finds out that the token was in fact being issued for a version other than V1, the server generates a VERSION_NEGOTIATION_ERROR.

In short, it is a downgrade attack if VN was issued while the token was usable.

-- 
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/3166#discussion_r340344021

---

From: Martin Thomson <[email-masked]>
Date: Tue, 29 Oct 2019 15:39:20 -0700

martinthomson commented on this pull request.

What is the TTL on this information?

-- 
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/3166#pullrequestreview-308876823

---

From: David Schinazi <[email-masked]>
Date: Tue, 29 Oct 2019 16:04:09 -0700

Let's assume the presence of an on-path attacker that can drop, forge and rewrite packets. This attacker is interested in parsing the SNI and ALPN. The attacker lets the client's first QUICv1 connection through, and the client gets a token with alternate version and salts, under the cover of encryption. Some time later, the client wants to open a second connection and sends an obfuscated initial with the new version and salt. The attacker can pretty easily figure out that the first packet is an Initial even with the 2bit XOR. The attacker modifies some bits in the token, and recomputes the checksum then sends the modified packet to the server, leaving the version intact. The server verifies the checksum then fails to decrypt the token. The server sends VN. The client then retries with QUICv1 using its original token. The attacker performs the same modification on that token, and recomputes the checksum and initial auth tag, then sends the packet to the server. The server will again fail to decrypt the token, it sends a retry, the client tries again with the retry token, which the attacker leaves alone, and the connection successfully establishes with QUICv1. The **attacker has successfully forced a downgrade** to QUICv1 and was able to extract SNI and ALPN.

-- 
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/3166#discussion_r340366571

---

From: Martin Thomson <[email-masked]>
Date: Tue, 29 Oct 2019 16:36:38 -0700

Yes, this offers an almost trivial downgrade attack, but this isn't a scenario that we agreed to cover.  It does seem to be a little bit *too* trivial an attack 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/3166#discussion_r340374998

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 18:25:07 -0700

@DavidSchinazi That's obviously the case. Thank you for pointing that out.

I think what the PR fails to state that a Retry token needs to inherit the properties of the NEW_TOKEN token included in the Initial packet that trigerred the Retry. One way doing that is to embed the NEW_TOKEN token in the Retry token.

The reason why we need the NEW_TOKEN token to be embedded in the Retry token is not only because there is an attack that you describe. It is necessary because when the server receives the first Initial packet from client that carries the alternative version, and responds with a Retry packet that carries that alternative version, and the client in response sends an Initial packet that carries the Retry token using an Initial packet with the alternative version, the server needs to extract the alternative initial salt (and other information) from the Retry token.

I'd update the PR to clarify that.

-- 
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/3166#discussion_r340396154

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 19:30:54 -0700

@martinthomson I think the design principle behind this PR that I have are:
* passive attack does not reveal the payload
* active attack can lead to the payload being revealed, but is detectable by the endpoints and thereby disrupts the handshake
* handshake falls back to v1 when the server forgets the token encryption key

As I think the issue pointed out by @DavidSchinazi is addressable (see my comment above), I think we might stick to the principle and how it evolves. If we conclude that the design based on the principle is simple enough, then we'd be fine. If not, we can consider the alternatives.

-- 
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/3166#discussion_r340407134

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:44:25 -0700

@kazuho pushed 2 commits.

d16700d1960105441af2941c859ce78c9fe9d206  use list for implementation guidance, applying @DavidSchnazi's suggestions
06bd1083927a9580d891aeef1992f05516142561  clarify what can be associated with the token, adopting @MikeBishop's suggestion

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/2553793365eab1a49b4ae9b8d630777306e5b16f..06bd1083927a9580d891aeef1992f05516142561

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:45:53 -0700

Thanks. Makes sense. Adopted in d16700d.

-- 
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/3166#discussion_r340420228

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:47:01 -0700

@kazuho pushed 1 commit.

6158bd9dbbb7a33953680f77c66918d623de39f6  s/comprises of/contains/ (@MikeBishop)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/06bd1083927a9580d891aeef1992f05516142561..6158bd9dbbb7a33953680f77c66918d623de39f6

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:47:08 -0700

Applied in 6158bd9.

-- 
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/3166#discussion_r340420458

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:47:54 -0700

+which it can be used.

Thank you for the suggestions. Make sense. Applied in 06bd108.

-- 
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/3166#discussion_r340420576

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:52:14 -0700

@kazuho pushed 1 commit.

7eded0ac1809b8c99be338129f63bbf3b45a56d2  use "Long Packet Type" (@DavidSchinazi)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/6158bd9dbbb7a33953680f77c66918d623de39f6..7eded0ac1809b8c99be338129f63bbf3b45a56d2

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 20:52:33 -0700

Fixed in 7eded0a.

-- 
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/3166#discussion_r340421294

---

From: Martin Thomson <[email-masked]>
Date: Tue, 29 Oct 2019 20:55:53 -0700

I'm concerned about the lack of any sort of commitment here.

Let's say that I pack some entropy into my tokens.  Using that along with a static key that I have configured I can regenerate the 21 bytes I need to decode the Initial packet that I receive.  I advertise any version (maybe except for v1, but in practice you can provide a different salt for v1 off the NEW_TOKEN salt).  The same static key (in reality, something derived from it, my key hygiene isn't that poor) is used to remove protection from tokens.

That works, but only until I lose the key.  When that happens, I will start to receive packets with tokens that I can't parse.

But now I have a packet that I can't process, is that a version that I don't understand, or a packet that I can't decrypt?  The natural path here is toward the latter, because the server likely has a new key that is used to create new salts for all those versions.

This is a whole lot easier if we force the server to commit, because then the server has to manage the fallback case.  It makes this more brittle, in the sense that you need to make the static key more durable, but I think that it would be reasonable to expect a server to do that.  They probably have to manage session ticket keys in this way.

We have two choices for the placement of these bits in the NEW_TOKEN.  0bXXTTXXXX or 0bXXXXXXTT.  The former might be easier to apply, the latter might be easier to explain.

So... This isn't totally clear.  There are two "encryption" or "decryption" operations that might apply: the AEAD for packet protection and the masking for header protection.

I think that you mean to say that the value you feed into the AAD for packet protection is unmodified and this alteration only applies afterwards.

However, I would prefer it if were applied to the raw values so that the XOR is also authenticated by packet protection.  Then you have a clear order of operations for applying this information that matches the order of fields:

0. encode the packet
1. replace the version
2. mask the type (if long header)
3. apply packet and header protection using the new salt

-- 
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/3166#pullrequestreview-308948794

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 22:07:56 -0700

We need Token Checksum so that the server can easily determine if there was a bit flip on the wire when it receives an invalid token.

The PR (up until of 7eded0a) requires the server to drop the packet if there was a bit flip on the wire. OTOH, if it was an unusable token (rather than a bit flip), the server responds with a VN. This distinction is necessary to prevent bit flips from being mis-detected as an downgrade attack (see https://github.com/quicwg/base-drafts/pull/3166#discussion_r340344021).

That said, I agree that this change is intrusive. Considering that we need to require certain properties for the token (see https://github.com/quicwg/base-drafts/pull/3166#discussion_r340396154), we might as well state that a NEW_TOKEN token should be generated in a way that the server can detect bit flips even it has lost the keys to decrypt the token. In practice, that can be easily achieved by attaching CRC32 (or zero-key GMAC).

But finally, this entire discussion is based on the assumption that we need a downgrade path, which @martinthomson disputes in https://github.com/quicwg/base-drafts/pull/3166#pullrequestreview-308948794.

-- 
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/3166#discussion_r340432382

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 22:13:00 -0700

@kazuho pushed 1 commit.

0720ef3c93098dbc201f0a332a67e427b91e8c82  swap reserved bits and packet type modifier (suggested by @martinthomson)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/7eded0ac1809b8c99be338129f63bbf3b45a56d2..0720ef3c93098dbc201f0a332a67e427b91e8c82

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 22:24:30 -0700

@kazuho pushed 1 commit.

14469beaa321626a39c03ba501f5b4a497830c61  long packet types when encoded in a long header packet is an XOR (@martinthomson)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/0720ef3c93098dbc201f0a332a67e427b91e8c82..14469beaa321626a39c03ba501f5b4a497830c61

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 22:25:20 -0700

Thanks for arguing for that. I had somehow thought that that's impossible, but I do not know why. Addressed in 14469be.

-- 
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/3166#discussion_r340434991

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 22:35:35 -0700

@martinthomson 
> This is a whole lot easier if we force the server to commit, because then the server has to manage the fallback case. It makes this more brittle, in the sense that you need to make the static key m…

I agree that it would be a much easier if we require the servers to commit.

At the same time, I think session ticket encryption keys are not something we should compare with. This is because the impact of losing access to alternative initial salt leads to handshake timeout, while the loss of session ticket encryption key merely leads to a full handshake. We have had this discussion in ESNI, and we ended up adding a fallback (i.e. esni_retry_request) due to a request from one of the largest deployments of TLS. That's why I have so far thought that a fallback is necessary.

That said, it might be possible that we have different requirements than ESNI.

After all, this alternative set thing is about giving the servers the *option* to issue different initial salts to every recurring connection. A server that advertises an alternative set does not need to work that way; deployments that might lose the key can issue a static initial salt that works across all the connections, and that would still be a win for us.

Considering these aspects, I am tempted to drop downgrade from this PR and see how it goes.

-- 
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/3166#issuecomment-547745701

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 23:56:53 -0700

@kazuho pushed 4 commits.

4e95ee66c77c7e77b0f8dfae4f5cba5fb688d664  clarify how a server can opt-out
bacab506eff750a2a93d070c00bc980bb6828006  Revert "protect token using checksum (reusing text from #3120 by @DavidSchinazi)"
d9ec32475380c331f962e63091d1dabc02cdfe1c  no more downgrade
3f4e7cc8550021a16ab880c5fce3b26051afd247  server always announce (though it can effectively opt-out)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/14469beaa321626a39c03ba501f5b4a497830c61..3f4e7cc8550021a16ab880c5fce3b26051afd247

---

From: Kazuho Oku <[email-masked]>
Date: Tue, 29 Oct 2019 23:57:59 -0700

@kazuho pushed 1 commit.

69d996984b27ff7ad162398cacb680aa8dd3ee59  delete VERSION_NEGOTIATION_ERROR (once again)

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/3f4e7cc8550021a16ab880c5fce3b26051afd247..69d996984b27ff7ad162398cacb680aa8dd3ee59

---

From: MikkelFJ <[email-masked]>
Date: Wed, 30 Oct 2019 00:02:49 -0700

mikkelfj commented on this pull request.

The checksum is very useful in situations where a bridge forwards a connection over an alternative medium such as USB or Bluetooth. The Retry and VN packets are the only packets that don't have self-integrity checks and such a bridge would be forced to provide additional framing. This framing is tolerable for VN because it is universal, but for Retry it requires version knowledge. It is much simpler if packets can just be forwarded with no knowledge other than length.

-- 
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/3166#discussion_r340454498

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 00:14:16 -0700

@kazuho pushed 1 commit.

373257b7b105ec5fff5251e0dcec0944970c0076  clarify how to handle Retry, as well as stating that a fixed mapping bet. versions and salts is better than nothing

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/69d996984b27ff7ad162398cacb680aa8dd3ee59..373257b7b105ec5fff5251e0dcec0944970c0076

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 00:21:08 -0700

@kazuho pushed 1 commit.

94a5a1bdf6ca925a134676d1b9354eaa4bc7e729  add Lifetime field

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/373257b7b105ec5fff5251e0dcec0944970c0076..94a5a1bdf6ca925a134676d1b9354eaa4bc7e729

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 00:30:51 -0700

@DavidSchinazi @marten-seemann @martinthomson @MikeBishop @mikkelfj Thank you all for your feedback. I think that the PR is ready for a new round of review.

I've removed downgrade as well as the token checksum field (https://github.com/quicwg/base-drafts/pull/3166#discussion_r340432382 clarifies why it is no longer necessary), and added a Lifetime field to the NEW_TOKEN frame.

I'm still unsure if having no downgrade is a good idea, though I agree that this is much simpler to analyze.

-- 
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/3166#issuecomment-547772117

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 00:33:22 -0700

373257b clarifies that the alternative initial set would (or should) be available through the Retry token. The text is kept informative, as the PR no longer allows a downgrade.

-- 
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/3166#discussion_r340461930

---

From: Martin Thomson <[email-masked]>
Date: Wed, 30 Oct 2019 02:11:42 -0700

The checksum can be provided by the server on its own.  The only reason you would provide a separate field for one is so that the client can validate it.  But the client can ensure that the NEW_TOKEN was not modified through packet protection.  Good to see this was removed :)

-- 
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/3166#discussion_r340497714

---

From: Mike Bishop <[email-masked]>
Date: Wed, 30 Oct 2019 12:43:36 -0700

> @@ -2740,8 +2740,10 @@ which is comprised of:
   the initial salt defined in section 5.2 of {{QUIC-TLS}}.
 
 A server advertises these values using a NEW_TOKEN frame {{frame-new-token}}.
-The token MUST include or associated with the alternative version number with
-which it can be used.
+The token MUST permit the server to recover at least the alternative version
+number being associated to the token.  This property can be achieved for example

It MUST be able to recover the salt as well, I think.  It's possible that version number maps directly to salt -- but then, that's one implementation of being able to recover it.

-- 
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/3166#pullrequestreview-309473856

---

From: Mike Bishop <[email-masked]>
Date: Wed, 30 Oct 2019 12:56:54 -0700

I can see both sides with regard to a fallback path.  A MitM that wanted to force you back to v1 could manufacture a VN packet in response to versions it doesn't understand, swallowing the Initial or the server's actual reply.  Prohibiting fallback means that such a MitM can only prevent connections, not inspect the ClientHello.

That said, I'm dubious that most clients will not fall back at all.  The alternative is falling back to TCP, which is even more inspectable, or total connection failure.  History shows that total connection failure is not an outcome most clients or servers are comfortable with.

I think what we really want is a fallback path where an intermediary's attempt at interference becomes visible; endpoints can decide how to proceed in that situation without the spec telling them.  But then we're back to designing QUIC's version negotiation and downgrade protection mechanism, something we said we weren't going to do in v1.

> @@ -4970,6 +5080,30 @@ The NEW_TOKEN frame is as follows:
 
 NEW_TOKEN frames contain the following fields:
 
+Lifetime:
+
+: Indicates the lifetime of the values contained in this frame in milliseconds.
+  An endpoint MUST NOT use the values provided by this frame, once the time that

```suggestion
  An endpoint MUST NOT use the values provided by this frame once the time that
```

-- 
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/3166#pullrequestreview-309480916

---

From: MikkelFJ <[email-masked]>
Date: Wed, 30 Oct 2019 13:06:08 -0700

I don't think we should weaken the core protocol just because H3 (usually) needs TCP fallback.

-- 
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/3166#issuecomment-548089391

---

From: David Schinazi <[email-masked]>
Date: Wed, 30 Oct 2019 16:38:06 -0700

If I understand the latest text correctly, it's saying:
- NEW_TOKEN carries a lifetime
- if a server wants to use alternative salts, it MUST ensure that it has access to its decryption key for the lifetime of that token, otherwise handshake timeouts could occur

I don't think that'll work for our deployment. We're interested in deploying alternative salts, but our mechanism to share keys across our fleet of servers isn't infallible: it's possible that one server gets a new key before another server, and if a client hits these two servers in the wrong order, they could end up in a state where the server cannot decrypt the token. This is fine for the current uses of QUIC NEW_TOKENs and TLS session tickets, because both of those will resolve themselves in-band (via RETRY, or full handshake).

Therefore I really think we need a graceful mechanism to handle this, similar to what was added to ESNI. The question then becomes: can we design a fallback mechanism that isn't vulnerable to a simple downgrade attack.

Here's a straw-man:
- when the server sees an initial token (the one from NEW_TOKEN, not from retry) that it cannot decrypt, it sends a RETRY.
- the server takes the non-decryptable token it received from the client, and sends it encrypted inside the retry token in the server's RETRY 
- the client tries again, but this time with QUICv1 (no obfuscation) and the retry token, but we add a new transport parameter where the client sends the first token it used on this connection

This would allow the server to detect when someone messed with the token in flight, and would then close the connection. So it mitigates the downgrade attack I described [earlier](https://github.com/quicwg/base-drafts/pull/3166#discussion_r340366571).

This straw-man has many downsides, including:
- we're back to needing a checksum on the token
- an attacker can still see the SNI, but they can't do so without it being detected. This might be acceptable because the attacker can still force a downgrade to TLS/TCP today

Anyway, I'm not sure this straw-man is the way to go, but perhaps the idea of repeating tokens in transport parameters might be worth exploring to help detect this class of attack.

-- 
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/3166#issuecomment-548156716

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 17:01:36 -0700

@DavidSchinazi Re downgrade prevention, I think we are converging on the same design (my design being the one that I had on this PR before dropping the downgrade).

Regarding the attack, I do not think we need to require the original token to be sent in a TP. Let me explain why:
* This PR requires the server that sends a Retry token to embed the the alternative sets of a NEW_TOKEN token in the Retry token (i.e. typically, NEW_TOKEN token found in an Initial packet that triggered the Retry would be embedded as-is in the Retry token).
* This PR used to require the client to continue sending the NEW_TOKEN token when downgrade happens. We can resurrect that requirement.

If we combine these two requirements, it would be possible for the server to detect a downgrade even if Retry was sent after downgrade, as the Retry token would convey the NEW_TOKEN token that the client originally submitted.

Re checksum, one way to solve this is to suggest servers advertising alternatives sets to embed a checksum to the tokens, using an key-less algorithm. For example, a server can build a NEW_TOKEN token as a combination of AES-CBC (encryption) and SHA256 (checksum).

Anyways, I think I might open a separate PR that describes the design with downgrade prevention, as having a PR would help us discuss the issues.

-- 
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/3166#issuecomment-548161732

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 18:54:19 -0700

@kazuho pushed 1 commit.

5f853add3696ee8469848d3e46c5d0074e89293b  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/3166/files/94a5a1bdf6ca925a134676d1b9354eaa4bc7e729..5f853add3696ee8469848d3e46c5d0074e89293b

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 22:51:57 -0700

@kazuho pushed 1 commit.

75735e0458f44f592cad1698b971118d78f35d2e  @MikeBishop's suggestions; https://github.com/quicwg/base-drafts/pull/3166#discussion_r340822271

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/5f853add3696ee8469848d3e46c5d0074e89293b..75735e0458f44f592cad1698b971118d78f35d2e

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 22:52:25 -0700

Good point! Fixed in 757e5e0.

-- 
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/3166#discussion_r340969502

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 22:56:28 -0700

@kazuho pushed 1 commit.

44c2b1d465033ce635617f5991c8a6da5e241bb5  oops, amend the previous commit

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/75735e0458f44f592cad1698b971118d78f35d2e..44c2b1d465033ce635617f5991c8a6da5e241bb5

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 22:56:53 -0700

@kazuho pushed 1 commit.

d557fb77ef4ea5f59f20dd0e1e8fe462a97858fc  fix typo, emphasize that this is just an example

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/44c2b1d465033ce635617f5991c8a6da5e241bb5..d557fb77ef4ea5f59f20dd0e1e8fe462a97858fc

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 30 Oct 2019 23:16:40 -0700

@kazuho pushed 1 commit.

7d0fa47865da93316b9e818954920e7c769ccc1a  Rephrase as "seeding"; The default of "alternative" being the standard values has been confusing

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/d557fb77ef4ea5f59f20dd0e1e8fe462a97858fc..7d0fa47865da93316b9e818954920e7c769ccc1a

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 00:15:53 -0700

So I've created #3178 that adds downgradability on top of this PR, hoping that we can figure out a downgradable design that works and consider the costs.

-- 
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/3166#issuecomment-548244209

---

From: MikkelFJ <[email-masked]>
Date: Thu, 31 Oct 2019 01:25:03 -0700

> @@ -2721,6 +2724,96 @@ between endpoints.  Application protocols SHOULD define rules for handling

+# Seeding {#seeding}
+
+In order to avoid ossification of the cleartext and obfuscated fields of QUIC
+packets, a server can announce a set of alternative initial values to be used,
+which is comprised of:
+
+* Version number; a 32-bit unsigned number that is to be presented on wire in
+  place of the version number specified in this document.  This value MUST NOT
+  be a reserved version ({{versions}}).
+
+* Packet type modifier; a two-bit value that obfuscates the Long Packet Type of
+  a long header packet ({{long-header}}).  The long packet type bits of a long
+  header packet is encoded as an bti-wise exclusive or (XOR) of the packet type

```suggestion
  header packet is encoded as an bit-wise exclusive or (XOR) of the packet type
```

+The rest of this section applies to the servers that advertise non-default
+values as their seeds.
+
+
+## Server Behavior
+
+Typically, a server that advertises the alternative seeds would act in the
+following steps:
+
+* The server pre-allocates a set of unused version numbers as the alternative
+  version numbers, associating each of those version numbers with a packet type
+  modifier chosen at random.
+
+* When issuing a NEW_TOKEN token, the server generates the alternative initial
+  salt by calling a pseudo-random function.  Then it builds a token that

There is no need to use a pseudo-random function if the server has access to better randomness (but to be fair this is for a typical implementation). I would just say it generates a cryptographically secure random number.

> +values as their seeds.
+
+
+## Server Behavior
+
+Typically, a server that advertises the alternative seeds would act in the
+following steps:
+
+* The server pre-allocates a set of unused version numbers as the alternative
+  version numbers, associating each of those version numbers with a packet type
+  modifier chosen at random.
+
+* When issuing a NEW_TOKEN token, the server generates the alternative initial
+  salt by calling a pseudo-random function.  Then it builds a token that
+  embeds the alternative seeds including the initial salt being generated.  The
+  token will be encrypted using a key known only to the server, thereby

```suggestion
  token will be encrypted using a key known only to the server, or server cluster, thereby
```

> +## Server Behavior
+
+Typically, a server that advertises the alternative seeds would act in the
+following steps:
+
+* The server pre-allocates a set of unused version numbers as the alternative
+  version numbers, associating each of those version numbers with a packet type
+  modifier chosen at random.
+
+* When issuing a NEW_TOKEN token, the server generates the alternative initial
+  salt by calling a pseudo-random function.  Then it builds a token that
+  embeds the alternative seeds including the initial salt being generated.  The
+  token will be encrypted using a key known only to the server, thereby
+  conforming to the requirements in {{validate-future}}. After that, the server
+  sends a NEW_TOKEN frame that contains the generated token and the seeds that
+  have been embedded to that token.

```suggestion
  have been embedded into that token.
```

> +  have been embedded to that token.
+
+* When the client reconnects to the server by using the provided token and the
+  seeds, the server first checks if the version number field of the incoming
+  packet contains one of the alternative version numbers it advertises, then if
+  that is the case, applies the corresponding packet type modifier to recover
+  the correct packet type.  If the recovered packet type is an Initial packet
+  and that packet contains a NEW_TOKEN token, the server decrypts the embedded
+  token and recovers the initial salt, uses that to decrypt the payload of the
+  Initial packet.
+
+* When sending a Retry in response to an Initial packet carrying an alternative
+  version number, the server embeds the NEW_TOKEN token found in the Initial
+  packet within the retry token it issues.  Once the server receives a response
+  from the client carrying that retry token and the path is validated, it
+  decrypts the NEW_TOKEN token embedded in the retry token to recover the

```suggestion
  decrypts the NEW_TOKEN token embedded within the retry token to recover the
```

> +  packet contains one of the alternative version numbers it advertises, then if
+  that is the case, applies the corresponding packet type modifier to recover
+  the correct packet type.  If the recovered packet type is an Initial packet
+  and that packet contains a NEW_TOKEN token, the server decrypts the embedded
+  token and recovers the initial salt, uses that to decrypt the payload of the
+  Initial packet.
+
+* When sending a Retry in response to an Initial packet carrying an alternative
+  version number, the server embeds the NEW_TOKEN token found in the Initial
+  packet within the retry token it issues.  Once the server receives a response
+  from the client carrying that retry token and the path is validated, it
+  decrypts the NEW_TOKEN token embedded in the retry token to recover the
+  alternative initial salt that is to be used for unprotecting the packet
+  payload.
+
+Instead of associating a new alternative initial salt to every NEW_TOKEN token,

```suggestion
Instead of associating a new alternative initial salt with every NEW_TOKEN token,
```

> +* When sending a Retry in response to an Initial packet carrying an alternative
+  version number, the server embeds the NEW_TOKEN token found in the Initial
+  packet within the retry token it issues.  Once the server receives a response
+  from the client carrying that retry token and the path is validated, it
+  decrypts the NEW_TOKEN token embedded in the retry token to recover the
+  alternative initial salt that is to be used for unprotecting the packet
+  payload.
+
+Instead of associating a new alternative initial salt to every NEW_TOKEN token,
+a server might map a fixed salt to each of the alternative version numbers it
+issues.  Such design is not recommended, as an active attacker might build a
+list of known alternative version numbers and their initial salts and use that
+list to decrypt the payload of Initial packets using those alternative version
+numbers.  But still, having a set of version numbers and initial salts used
+concurrently is considered better than just using the default values of QUIC in
+terms of preventing ossification.

I am not comfortable with the slack given here. While it does improve things when salt is reused, it also gives the client a false sense of security. It would be better if the client could be certain that it does indeed sent private information on the wire.

For example it might create an initial connection to bootstrap safety, similar to if it connected to a secure DNS with crypto keys (TBD), and then reconnects to send confidential informational information. 

Taking this one further, it would be advantageous if a token could be used across different server certificates so the initial certificate could be "harmless" in order to enhance privacy.

> +issues.  Such design is not recommended, as an active attacker might build a
+list of known alternative version numbers and their initial salts and use that
+list to decrypt the payload of Initial packets using those alternative version
+numbers.  But still, having a set of version numbers and initial salts used
+concurrently is considered better than just using the default values of QUIC in
+terms of preventing ossification.
+
+A server MUST NOT send a Version Negotitation packet in response to a long
+header packet with an alternative version number it has advertised.
+
+
+## Distributing the Seeds
+
+This specification defines how the seeds are used as well as how they are
+advertised using a NEW_TOKEN frame.  Other specifications MAY define other
+methods for distributing or deducing these seeds.

What are "other specifications"? Another QUIC version?

> @@ -2721,6 +2724,96 @@ between endpoints.  Application protocols SHOULD define rules for handling

+# Seeding {#seeding}
+
+In order to avoid ossification of the cleartext and obfuscated fields of QUIC
+packets, a server can announce a set of alternative initial values to be used,
+which is comprised of:
+
+* Version number; a 32-bit unsigned number that is to be presented on wire in
+  place of the version number specified in this document.  This value MUST NOT
+  be a reserved version ({{versions}}).

It is not very clear from this text if the intention is to generate a new representation of the same version in which the token was generated, or there is indeed a new version. Since this does not cover version negotiation, it presumably refers to the same version. But that could change as versions get added and perhaps V1 should be prepared for that (I'm not sure I am getting this right). @MikeBishop alluded to something similar in an earlier comment AFAIR.

-- 
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/3166#pullrequestreview-309698002

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 01:28:01 -0700

@kazuho pushed 1 commit.

3caa73ef9279f8ff867c12943415f006a5fd41da  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/3166/files/7d0fa47865da93316b9e818954920e7c769ccc1a..3caa73ef9279f8ff867c12943415f006a5fd41da

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 01:29:22 -0700

@kazuho pushed 1 commit.

ead19c004bd4ba063eeb9dcef0217f1322dff7d7  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/3166/files/3caa73ef9279f8ff867c12943415f006a5fd41da..ead19c004bd4ba063eeb9dcef0217f1322dff7d7

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 08:29:46 +0000 (UTC)

@kazuho pushed 1 commit.

bd45b3740c8323bdbe9a2a31fe600a8a23c122ee  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/3166/files/ead19c004bd4ba063eeb9dcef0217f1322dff7d7..bd45b3740c8323bdbe9a2a31fe600a8a23c122ee

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 01:29:54 -0700

@kazuho pushed 1 commit.

0a45df175f7a3cdb8a58bdbe2fceede5c3f11f05  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/3166/files/bd45b3740c8323bdbe9a2a31fe600a8a23c122ee..0a45df175f7a3cdb8a58bdbe2fceede5c3f11f05

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 02:07:53 -0700

+
+
+## Server Behavior
+

Thank you for the suggestions. All the proposed editorial changes made sense except this one, I've applied them.

Regarding this suggestion, I think we do not need to be general here, as this is about how a "typical server" would behave.

-- 
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/3166#discussion_r341022849

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 02:11:00 -0700

> It would be better if the client could be certain that it does indeed sent private information on the wire.

At the moment, we never provide that certainty. The only way to provide that is to send a public key in the NEW_TOKEN frame and do a DH to determine the initial salt.

We can do that, but that's essentially about porting ESNI to QUIC. My assumption has so far been that such an effort would require time, and it would be better to do that as a separet draft (e.g., https://datatracker.ietf.org/doc/draft-kazuho-quic-authenticated-handshake/).

-- 
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/3166#discussion_r341024178

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 02:11:42 -0700

HTTP/3 defining Alt-Svc, SVCB / HTTPSSVC DNS records, ESNI, to name a few.

-- 
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/3166#discussion_r341024430

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 02:14:54 -0700

@kazuho pushed 1 commit.

d683da83643b996412c7852beaf0e8da6427bfc9  wordwrap

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/0a45df175f7a3cdb8a58bdbe2fceede5c3f11f05..d683da83643b996412c7852beaf0e8da6427bfc9

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 02:17:57 -0700

@kazuho pushed 1 commit.

febd89944d6481428987be6122b9299b8e686da0  s/PRF/CSPRNG/ for clarification

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/3166/files/d683da83643b996412c7852beaf0e8da6427bfc9..febd89944d6481428987be6122b9299b8e686da0

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 31 Oct 2019 02:18:38 -0700

Yes, the intent here is to recommend CSPRNG. Applied in febd899.

-- 
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/3166#discussion_r341027246