Subject: Fwd: New Version Notification for draft-kazuho-quic-authenticated-handshake-00.txt

From: Kazuho Oku <[email-masked]>
Date: Fri, 14 Dec 2018 11:33:50 +0900

TL;DR: Christian and I have submitted an I-D that proposes a flavor of
QUIC v1 that uses the Encrypted SNI key to authenticate Initial
packets. Initial packets are no longer vulnerable to man-on-the-side
attacks; the entire handshake process becomes tamper-proof.

https://datatracker.ietf.org/doc/draft-kazuho-quic-authenticated-handshake/

## Background

So far, we have spent multiple efforts to make QUIC resistant to
man-on-the-side attacks. Among them, mitigating injection attacks of
Initial packets has been the biggest head-ache.

There have been various proposals (including #2045, #2053, #2076), but
the question has always been if it's worth the effort, because there
are so many attack vectors (e.g. injection of a packet carrying a
corrupt header, invalid or unknown frames, ACKs with unsent PNs,
crafted TLS Hellos, HelloRetryRequests, crafted Version Negotiation or
Retry packets) and it is doubtful if having mitigations for just one
or few types of attacks are meaningful. We want to close all the
attack vectors, however it is like building house of cards.

## The Proposed Approach

The draft introduces a different approach. It relies on the Encrypted
SNI [1]. For people not familiar with Encrypted SNI, it is an
extension of TLS 1.3 that uses a public key distributed using DNS to
encrypt the SNI. Encrypted SNI is currently a TLS WG draft, has
multiple implementations, and it is already deployed by Cloudflare and
Mozilla.

The approach proposed by the draft is to use a shared secret that is
derived from the Encrypted SNI key to authenticate the Initial
packets, using HMAC. Because the shared key can only be calculated by
the endpoints, an attacker cannot spoof the Initial packets. Spoofed
packets will be detected by HMAC and will be to dropped.

The draft disables Version Negotiation (because the DNS record of
Encrypted SNI can carry a list of QUIC versions supported by the
server), a different client-side behavior for handling Retry packets,
and also introduces a CONNECTION_CLOSE packet to communicate handshake
failures without affecting the transport state.

And of course, it also uses a different QUIC version number in the
long packet header field so that the Initial packets of QUIC v1 and
the authenticated Initial packets of the proposal can be handled
differently.

Other than that, the protocol is identical to QUIC v1, including the
handling of 0-RTT, Handshake, 1-RTT packets and the frames being
contained by them. IMO, the differences are small and isolated well
enough that QUIC v1 stacks can easily add support for the flavor
proposed by the I-D.

There are other benefits too. We have always hoped to have multiple
versions of QUIC being deployed from early days in order to prevent
ossification. The proposal makes that happen. Besides, one interesting
aspect of the proposed protection of Initial packets is that MITM
boxes (with root certificates) would not be possible to terminate the
connection _unless_ they also block the distribution of Encrypted SNI
DNS records, and that even then, the existence of such MITM boxes is
detectable. Raising the bar of implementing and deploying MITM boxes
as well as detecting them is beneficial for the evolution of the
protocol.

The downside of the proposal is that it only protects QUIC connections
going to servers that provide the Encrypted SNI DNS records. But
considering our failing attempts to address the Initial packet
injection attacks, and considering the amount of interest we have seen
for Encrypted SNI, I think that the proposed approach is the way
forward.

Please let us know what you think. Thank you in advance.

PS. The GitHub repository of the I-D is:
https://github.com/kazuho/draft-kazuho-quic-authenticated-handshake

---------- Forwarded message ---------
From: <[email-masked]>
Date: 2018年12月14日(金) 11:30
Subject: New Version Notification for
draft-kazuho-quic-authenticated-handshake-00.txt
To: Kazuho Oku <[email-masked]>, Christian Huitema <[email-masked]>

A new version of I-D, draft-kazuho-quic-authenticated-handshake-00.txt
has been successfully submitted by Kazuho Oku and posted to the
IETF repository.

Name:           draft-kazuho-quic-authenticated-handshake
Revision:       00
Title:          Authenticated Handshake for QUIC
Document date:  2018-12-14
Group:          Individual Submission
Pages:          9
URL:
https://www.ietf.org/internet-drafts/draft-kazuho-quic-authenticated-handshake-00.txt
Status:
https://datatracker.ietf.org/doc/draft-kazuho-quic-authenticated-handshake/
Htmlized:
https://tools.ietf.org/html/draft-kazuho-quic-authenticated-handshake-00
Htmlized:
https://datatracker.ietf.org/doc/html/draft-kazuho-quic-authenticated-handshake

Abstract:
   This document explains a variant of QUIC protocol version 1 that uses
   the ESNI Keys to authenticate the Initial packets thereby making the
   entire handshake tamper-proof.

Please note that it may take a couple of minutes from the time of submission
until the htmlized version and diff are available at tools.ietf.org.

The IETF Secretariat

-- 
Kazuho Oku

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Fri, 14 Dec 2018 05:04:59 -0800

Some thoughts:

1. this is the only way to go both due to SNI privacy / censoring, and
injection attacks.
2. if this is not v1, we risk a split similar to http vs https, which could
defer acceptance for a decade - but OTOH there are is complexity to discuss
- maybe consider a simple v1 and a better v2.
3. depending on an external DNS service and signature design, this might be
more vulnerable to gov. coercion than TLS records alone. Does this matter?
4. text should consider alternative key distribution mechanisms for private
networks over public networks. I.e. I don’t trust/bother with DNS, but I
can install public keys at all clients, or shared symmetric keys.
5. I am concerned about DoS attacks on public key crypto - it may take time
to verify tag.
6. I don’t understand the initial crypto being the same as v1 - does this
mean that client TP is still externally visible - shouldn’t that be avoided?
7. is this tied too heavily in with TLS considering other versions that
might want to use more light weight crypto - e.g. version negotiation is
now after public crypto, and public crypto flavour might be unfriendly to
constrained devices.
8. The entire DNS infrastructure is in need of an overhaul, including
possibly DNS over QUIC. How does that work?
9. HMAC - what about new hashes like SHA-3? Yes - QUIC v1 also uses HMAC
same question, same answer.
10. This still doesn’t address rewriting source/target IP addresses either
as a replacement, or a race, in handshake and migration, so some analysis
is needed to state this is a significant improvement despite of this.

Mikkel

On 14 December 2018 at 03.34.20, Kazuho Oku ([email-masked]) wrote:

## Background

## The Proposed Approach

---------- Forwarded message ---------
From: <[email-masked]>
Date: 2018年12月14日(金) 11:30
Subject: New Version Notification for

Abstract:

Please note that it may take a couple of minutes from the time of
submission
until the htmlized version and diff are available at tools.ietf.org.

The IETF Secretariat

-- 
Kazuho Oku

---

From: Mike Bishop <[email-masked]>
Date: Sat, 15 Dec 2018 00:07:27 +0000

I had to puzzle through a few pieces of this, but this approach seems promising.  However, I would be very sad to tie the use of QUICv1 to the successful deployment of ESNI keys (particularly for the reasons we're already concerned about ESNI's current structure in a multi-CDN context).  For that reason, I think a separate version (either v2 or an alternative to v1) is the right choice.

I'm also wondering whether this actually *needs* to use ESNI as the publication mechanism.  For example, an extension to QUICv1 could be defined to relay the server’s keyshare for use on future connections.  However, ESNI permits you to delegate issues of lifetime, pinning, revocation, etc. to the DNS, which is certainly attractive.

-----Original Message-----
From: QUIC <[email-masked]> On Behalf Of Kazuho Oku
Sent: Thursday, December 13, 2018 6:34 PM
To: IETF QUIC WG <[email-masked]>
Cc: Christian Huitema <[email-masked]>
Subject: Fwd: New Version Notification for draft-kazuho-quic-authenticated-handshake-00.txt

TL;DR: Christian and I have submitted an I-D that proposes a flavor of QUIC v1 that uses the Encrypted SNI key to authenticate Initial packets. Initial packets are no longer vulnerable to man-on-the-side attacks; the entire handshake process becomes tamper-proof.

## Background

So far, we have spent multiple efforts to make QUIC resistant to man-on-the-side attacks. Among them, mitigating injection attacks of Initial packets has been the biggest head-ache.

There have been various proposals (including #2045, #2053, #2076), but the question has always been if it's worth the effort, because there are so many attack vectors (e.g. injection of a packet carrying a corrupt header, invalid or unknown frames, ACKs with unsent PNs, crafted TLS Hellos, HelloRetryRequests, crafted Version Negotiation or Retry packets) and it is doubtful if having mitigations for just one or few types of attacks are meaningful. We want to close all the attack vectors, however it is like building house of cards.

## The Proposed Approach

The draft introduces a different approach. It relies on the Encrypted SNI [1]. For people not familiar with Encrypted SNI, it is an extension of TLS 1.3 that uses a public key distributed using DNS to encrypt the SNI. Encrypted SNI is currently a TLS WG draft, has multiple implementations, and it is already deployed by Cloudflare and Mozilla.

The approach proposed by the draft is to use a shared secret that is derived from the Encrypted SNI key to authenticate the Initial packets, using HMAC. Because the shared key can only be calculated by the endpoints, an attacker cannot spoof the Initial packets. Spoofed packets will be detected by HMAC and will be to dropped.

The draft disables Version Negotiation (because the DNS record of Encrypted SNI can carry a list of QUIC versions supported by the server), a different client-side behavior for handling Retry packets, and also introduces a CONNECTION_CLOSE packet to communicate handshake failures without affecting the transport state.

And of course, it also uses a different QUIC version number in the long packet header field so that the Initial packets of QUIC v1 and the authenticated Initial packets of the proposal can be handled differently.

Other than that, the protocol is identical to QUIC v1, including the handling of 0-RTT, Handshake, 1-RTT packets and the frames being contained by them. IMO, the differences are small and isolated well enough that QUIC v1 stacks can easily add support for the flavor proposed by the I-D.

There are other benefits too. We have always hoped to have multiple versions of QUIC being deployed from early days in order to prevent ossification. The proposal makes that happen. Besides, one interesting aspect of the proposed protection of Initial packets is that MITM boxes (with root certificates) would not be possible to terminate the connection _unless_ they also block the distribution of Encrypted SNI DNS records, and that even then, the existence of such MITM boxes is detectable. Raising the bar of implementing and deploying MITM boxes as well as detecting them is beneficial for the evolution of the protocol.

The downside of the proposal is that it only protects QUIC connections going to servers that provide the Encrypted SNI DNS records. But considering our failing attempts to address the Initial packet injection attacks, and considering the amount of interest we have seen for Encrypted SNI, I think that the proposed approach is the way forward.

---------- Forwarded message ---------

From: <[email-masked]<mailto:[email-masked]>>

To: Kazuho Oku <[email-masked]<mailto:[email-masked]>>, Christian Huitema <[email-masked]<mailto:[email-masked]>>

has been successfully submitted by Kazuho Oku and posted to the IETF repository.

Revision:       00

Pages:          9

URL:

Status:

Htmlized:

Htmlized:

Abstract:

Please note that it may take a couple of minutes from the time of submission until the htmlized version and diff are available at tools.ietf.org.

The IETF Secretariat

--

Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Sat, 15 Dec 2018 14:23:41 +0900

Hi Mikkel,

Thank you for your comments. My responses inline.

2018年12月14日(金) 22:05 Mikkel Fahnøe Jørgensen <[email-masked]>:
>
> Some thoughts:
>
> 1. this is the only way to go both due to SNI privacy / censoring, and injection attacks.
> 2. if this is not v1, we risk a split similar to http vs https, which could defer acceptance for a decade - but OTOH there are is complexity to discuss - maybe consider a simple v1 and a better v2.

Yeah. I think we should better not delay the standardization process
of QUIC for having authenticated Initials. There is no guarantee that
ESNI would be standardized the way it is now, or if it would be
standardized in time.

> 3. depending on an external DNS service and signature design, this might be more vulnerable to gov. coercion than TLS records alone. Does this matter?

Would you mind elaborating a bit more?

I'm not sure I'm following, but I do not see the difference in terms
of vulnerability, because spoofing (or dropping) ESNI Resource Records
are as easy as attacking A (and AAAA) records.

> 4. text should consider alternative key distribution mechanisms for private networks over public networks. I.e. I don’t trust/bother with DNS, but I can install public keys at all clients, or shared symmetric keys.

Agreed. TLS 1.3 allows not only X. 509 certificates but also the use
of pre-shared keys for the handshake. QUIC supports that. Therefore,
it would make sense to define how you can extract the HMAC key from
the pre-shared keys.

> 5. I am concerned about DoS attacks on public key crypto - it may take time to verify tag.

The proposal (hereafter referred to as QUIC-AH (i.e., authenticated
handshake)) supports Retry. So the server can postpone the public key
crypto operations until validating the client address.

After that, the issue is not about the proposal, but about ESNI
requiring an additional public key operation. Servers would be
required to do that even with QUICv1 + ESNI. But anyways, I do not
think requiring three public key operations (ESNI, TLS 1.3 key
exchange, signing the CertificateVerify message) instead of two is a
security concern.

> 6. I don’t understand the initial crypto being the same as v1 - does this mean that client TP is still externally visible - shouldn’t that be avoided?

Initial crypto needs to be the same as v1 (or to be precise, it needs
to be decryptable without any key), because the the values of ESNI
extension is used for calculating the secret used for validating the
HMAC.

Regarding if other extension should be protected by the ESNI shared
secret, referring to the appendix of ESNI draft [1] might be a good
idea. Though, admittedly, some of the advantages and disadvantages
being listed in the appendix are not applicable to QUIC-AH.

[1] https://tools.ietf.org/html/draft-ietf-tls-esni-02#appendix-D

> 7. is this tied too heavily in with TLS considering other versions that might want to use more light weight crypto - e.g. version negotiation is now after public crypto, and public crypto flavour might be unfriendly to constrained devices.

Yeah my view is that for QUIC using TLS (that's what we are working
on), using ESNI keys to protect Initial packets is the correct thing
to do, because ESNI is the only pre-shared keys that are actually used
in the HTTPS use case. I do not think that QUIC-AH is more tied to TLS
than that.

> 8. The entire DNS infrastructure is in need of an overhaul, including possibly DNS over QUIC. How does that work?

The semantics of DNS is not changing. DoT, DoH, DoQ, they are all
conveyers of DNS messages that use different encodings than DNS over
UDP.

> 9. HMAC - what about new hashes like SHA-3? Yes - QUIC v1 also uses HMAC same question, same answer.
> 10. This still doesn’t address rewriting source/target IP addresses either as a replacement, or a race, in handshake and migration, so some analysis is needed to state this is a significant improvement despite of this.

I am not sure if we have an issue in relation no QUIC-AH.

My understanding is that we are mitigating post-handshake address
rewriting attacks in QUIC v1. IIUC, address rewriting attacks during
handshake is not an issue because we do not allow the peers to change
the address.

-- 
Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Sat, 15 Dec 2018 14:49:04 +0900

Hi Mike,

> I had to puzzle through a few pieces of this, but this approach seems promising.  However, I would be very sad to tie the use of QUICv1 to the successful deployment of ESNI keys (particularly for t…

I share the same view. QUIC v1 should not rely on the standardization of ESNI.

In fact, one of the reasons I started working on QUIC-AH (the proposed
I-D) is to spin off the attempts to have mitigations against
man-on-the-side attacks during handshake in QUIC v1.

Let's ship v1 knowing that it does not mitigate the attack (by having
post-handshake MOTS attack resistance, QUICv1 is already much better
than TLS over TCP), then close the remaining attack vector, possibly
by using ESNI.

FWIW, regarding ESNI in multi-CDN context, my understanding is that we
are trying to fix problem in TLS WG.

> I'm also wondering whether this actually *needs* to use ESNI as the publication mechanism.  For example, an extension to QUICv1 could be defined to relay the server’s keyshare for use on future con…

That's an interesting idea.

Actually, ESNI records can be published by something other than DNS. I
think that a server can send it's ESNI record as a post-handshake
message of TLS. The record would be considered valid for the server's
IP address for the validity period expressed in the record itself (we
have not_before and not_after fields).

OTOH, I would like to point out that the risk of relying on a
pre-shared public key to protect the handshake is that loss of the
public key results in service disruption. I am not sure having a
"casual" method of distributing such pre-shared key raises the risk.

-- 
Kazuho Oku

---

From: Eric Rescorla <[email-masked]>
Date: Sat, 15 Dec 2018 10:50:16 -0800

Kazuho,

Thanks for sending this. I think it's a very interesting direction. I have
some comments below.

DEPLOYMENT MODEL
It seems to me that there are two models to consider here. In the
first, the server *only* supports authenticated handshakes (AH) and in
the second, it supports both authenticated and unauthenticated
handshakes. In general, I think the second case is far more likely,
because in general we can't assume that clients can receive the
ESNIKeys records, and that means that some clients will not use AH.

THREAT MODEL
This leads us directly to the question of the threat model. I assume
that we have what I termed a Class (3) attacker, which can inject
packets and will always win the race but cannot delete packets.
With that, you get the following pattern:

Client                  Attacker                Server

CInitial ->
                        CInitial' ->
                        CInitial  ->
                                           <- SInitial
                        <- SInitial'
                        <- SInitial

CHandshake ->
                        CHandshake ->

Our objective is to have the handshake survive this treatment. In an
ideal world, we would cause the server and client to reject X' and
process X but this isn't possible, with the design you suggest,
because the attacker can always take CInitial, replace the CRYPTO
frames with his own and then send it to the server, computing
a new MAC based on *his* Zx. Note that this won't necessarily have
the right ESNI but that doesn't matter, because it will have
the same [SC]CID, and so will cause cause CInitial to be discarded
when it is received. As far as I can tell, your current design
does not prevent this. If I'm missing something here, let me
know [0]

FIRST CLIENT INITIAL
It seems like the obvious defense is the one you suggest in S 3.2.2,
namely to treat each distinct CInitial as its own handshake and create
separate state on the server for each one. Then this will cause the
server to send two SInitials, one in response to CInitial and one
in response to CInitial'. This gives us the diagram below.

Client                  Attacker                Server

CInitial ->
                        CInitial' ->
                                           <- SInitialX   // Corresponds to
CInitial'

                        <- SInitialX'
                        <- SInitialX

                        CInitial  ->
                                            <- Sinitial   // Corresponds to
CInitial
                        <- Sinitial'
                        <- SInitial

CHandshake ->
                        CHandshake ->

Note that the attacker can duplicate and tamper with any message
either side sends so because the server sends two SInitials, the
attacker ends up potentially sending 4.

SERVER INITIAL FLIGHT
So, what we need at this point is to ensure that the client rejects
(a) SInitial', SInitialX' and (b) SInitialX, and accepts SInitial (I'm
ignoring subsequent Initial packets from the Client at this point),
but I'll get there shortly. Rejecting SInitial' happens automatically
in your design. The attacker doesn't have Zx and so SInitial' will not
deprotect correctly.

Rejecting SInitialX is harder, but I think can be fixed by mixing CInitial1
into the the key schedule. I.e., the initial key would be something
like:

  IS = HKDF-Extract(0xef4fb0abb47470c41befcf8031334fae485e09a0,
                    Zx)

  initial_secret = HKDF-Extract(HKDF-Expand(IS, ...),
                                F(CInitial))

Where F(CInitial is some sanitized version of CInitial, that is
invariant under retransmission, perhaps the payload + the CIDs.

The result of this is that SInitialX and SInitial will be encrypted
with separate keys (with only the one for SInitial being the one
that the client expects) and the client will discard SInitialX
after it fails to decrypt.

SUBSEQUENT CLIENT INITIALS
The diagram looks like this

Client                  Attacker                Server

CInitial ->
                        CInitial' ->
                                           <- SInitialX   // Corresponds to
SInitial'
                        CInitial  ->
                                            <- Sinitial

                        <- SInitialX'
                        <- SInitialX
                        <- SInitial
                        <- Sinitial'

CInitial2 ->
                        CInitial2' ->
                        CInitial2 ->

There are actually two types of subsequent client Initials

1. Those after SH that contain ACKs (and the like) for server
   Initial.
2. Those after HRR

With case (1), we should just rekey off of Initial secret. The server
can sort out which keys to use based on trial decryption or perhaps
some extra flag in the packet (probably the second is better).

Case (2) (HRR) is more complicated. Trying to use data in the ESNI
extension when you're not going to use g^x is tricky (though maybe
possible), so we could potentially handle this as in case (1). Another
alternative is to use the same general strategy we used for the
first Initial and bucket the CInitial1/CInitial2 pairs. This is easiest done
if we force each CInitial2 to commit to a specific CInitial1 (thus avoiding
the need to do combinatoric explosion on the server). You could
do this by including a hash of CInitial1 in CInitial2. The attacker
can obviously bind CInitial2' to any CInitial he wants, but he has
to transmit one message for each, so the result is the same as
sending N CInitial1s.

VERSION NEGOTIATION
In your design you move version negotiation to the client and forbid
VN:

   A client MUST ignore Version Negotiation packets.  When the client
   gives up of establishing a connection, it MAY report the failure
   differently based on the receipt of (or lack of) Version Negotiation
   packets.

More concerning, this moves the QUIC version negotiation to the ESNI
record, which permits downgrade attacks by that server (or anyone who
controls DNS). We've generally avoided this in TLS ESNI. It could
be solved by having the true origin sign the ESNIKeys structure
(as we have discussed for semi-static).

It's worth noting that this is a consequence of QUIC's VN design. With
the simplified VN design I suggested in PR #2113, you wouldn't have
this problem: the server would commit to its *minimum* version (this
is implicit in ESNIKeys already, as it requires TLS 1.3) and then you
could upward negotiate as expected.

[0] Another possibility with your current design is for the attacker
to tamper with CH, for instance by adding a dummy extension, because
the ESNI extension doesn't protect all of CH, just g^x. This will
cause the server's Handshake messages to deprotect incorrectly. One
could imagine a fix for this if the ESNI extensions covered more
of the CH.

---

From: Christian Huitema <[email-masked]>
Date: Sat, 15 Dec 2018 16:44:47 -0800

Quoting the whole message, because it is a nice analysis.

> does not prevent this. If I'm missing something here, let me

Agreed.

>                                            <- SInitialX   //
> Corresponds to CInitial'
>                                             <- Sinitial   //
> Corresponds to CInitial

The suggestion is S 3.2.2. is basically the same as PR 2706: create a
separate server context for each separate CH. Like Kazuho, I think it is
pretty much required for any good defense.

> after it fails to decrypt.

We tried to not have rekeying at the client, i.e. keep the same hmac key
throughout the session. The assumption is that the data incorporated in
the "hmac_key" contains something that client and server know, but the
attacker cannot guess. The structure "ClientESNIInner" has that
property, as long as the nonce really is unguessable. Caveats about
random number generation seem to apply. Now it may well be that our
draft refers to "ESNIContents" when in fact it should refer to
"ClientESNIInner". That would be a simple fix.

>                                            <- SInitialX   //
> Corresponds to SInitial'

This gets better if the client switches to using the server chosen SCID
instead of the ICID in the subsequent initials. If we do that, then
there is no ambiguity: Clinitial2 arrives with the SCID chosen by the
server when sending SInitial, and is authenticated using the HMAC key
derived from CInitial.

If we insist that all Initial packets shall have Dest=ICID, then we do
indeed have a problem, and we need to put a unique token somewhere in
the payload. Hash(CInitial) would work.

> to transmit one message for each, so the result is the same as

That, or sending the messages with dest=SCID instead of dest=ICID.

I think we went back and forth with that idea. I don't quite remember
why we nixed it. Is there a potential deployment issue?

> could upward negotiate as expected.

And maybe we should specify that. After all, we are creating a new QUIC
version, so we can just as well have a couple of extra transport parameters.

> could imagine a fix for this if the ESNI extensions covered more

If the attacker did that, wouldn't the HMAC fail at the server? Also,
isn't that just a variant of CInitial' ?

-- Christian Huitema

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 16 Dec 2018 11:49:51 +0900

Hi Eric,

Thank you for your comments. My responses below.

2018年12月16日(日) 3:50 Eric Rescorla <[email-masked]>:
> process X but this isn't possible,

I agree about the deployment model and the threat model. Models help a
lot; thank you for clarifying them.

> with the design you suggest,
> in response to CInitial'.

Thank you for pointing out the attack vector. I do not know why I
missed that even though we knew the existence of it in #2076.

IMO, the most straightforward defense would be to require clients to
derive the initial DCID from the value of ClientHello, for example by
using a hash function (i.e. DCID = Hash(ClientHello)).

Then, we can ensure by design that each Initial carrying a different
ClientHello would be considered as a different connection
establishment attempt. QUIC-AH already requires implementations to
check the tag after processing ClientHello, therefore additionally
requiring to check the value of the DCID field is fine.

To handle Retry that changes the server CID, we need to add ODCID
field to the Initial packet. A client that receives a Retry that
updates the server CID will set the DCID field of the resent Initial
to the updated value, and set the original value to the ODCID field. A
server that receives an Initial containing a token that it does not
understand would process the packet as if the token was missing and as
if the value of the ODCID field was present in the DCID field.

> This gives us the diagram below.
>
> Client                  Attacker                Server
>
> CInitial ->
>                         CInitial' ->
>                                            <- SInitialX   // Corresponds to CInitial'
>
>                         <- SInitialX'
>                         <- SInitialX
>
>                         CInitial  ->
>                                             <- Sinitial   // Corresponds to CInitial
>                         <- Sinitial'
>                         <- SInitial
>
> CHandshake ->
>                         CHandshake ->
>

I acknowledge that the attack vector exists.

I think the easiest way to mitigate the attack is to mix ClientHello
(or a value derived from ClientHello) into the HMAC key used for
authenticating the Initial packets. Then, we would not be required to
rekey during the exchange of Initial packets.

    hmac_key = HKDF-Expand-Label(
        Zx,
        "quic initial auth",
        Hash(ESNIContents) || ODCID, // ODCID == Hash(ClientHello)
        digest_size
    )

>                                            <- SInitialX   // Corresponds to SInitial'
>                         CInitial  ->
>                                             <- Sinitial
>
>                         <- SInitialX'
>                         <- SInitialX
>                         <- SInitial
>                         <- Sinitial'
>
> CInitial2 ->
>                         CInitial2' ->
>                         CInitial2 ->
>

I am not sure if rekeying is necessary, because client is sending a
value that is only known by the server in it's Initial and the server
is authenticating it's responses using that.

I do not think it is possible for an attacker to spoof the Initial
packets sent by the server.

> possible), so we could potentially handle this as in case (1).

I am not sure if we need to consider that.

My understanding is that ESNI expects the server to process the ESNI
extension of the first ClientHello, even when it responds with an HRR.
Because HRR is something that a hidden server (in the split-server
model) might send. And though I admit that the a non-split server can
delay the processing of ESNI extension until it receives the second
ClientHello, I do not think we need that in QUIC, because we have
Retry.

> Another
> controls DNS).

I do not think that the attack vector exists. Downgrade protection of
QUIC v1 would prevent that.

It's just that the `supported_versions` field of the QUIC_ESNI
extension replaces the role of the Version Negotiation packet. Neither
of them are protected. However, an attacker spoofing the value gets
detected at the end of the handshake.

> We've generally avoided this in TLS ESNI. It could

-- 
Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 16 Dec 2018 12:21:17 +0900

> pretty much required for any good defense.

Yeah. As I suggested in my response to EKR, it might be worth
considering going one step further; i.e. derive DCID from ClientHello.

> throughout the session.

Agreed. I think that that would be a nice property to have (for
simplicity). And IMO there's no downside in doing that, because an
attacker cannot generate a spoofed packet that would be processed by
either of the endpoints, assuming that we address the issue of server
not rejecting spoofed Initial packets carrying legitimate a ESNI
extension (discussed above).

> The assumption is that the data incorporated in

Zx is the shared secret between the client and server, therefore
hmac_key cannot be calculated by an attacker.

Hash(ESNIContents) is the equivalent of AAD. Therefore I am not sure
if ClientESNIInner is the correct thing to do. Instead we should
expand that to cover the entire ClientHello, to ensure that HMAC key
would be unique to ClientHello.

> the payload. Hash(CInitial) would work.

I think deriving DCID from Hash(ClientHello) would also fix the issue.

-- 
Kazuho Oku

---

From: Christian Huitema <[email-masked]>
Date: Sat, 15 Dec 2018 20:22:04 -0800

> considering going one step further; i.e. derive DCID from ClientHello.

Do you mean "the Initial CID that the client uses as Destination CID in
the Initial Packet"? Yes, that can work. The ICID is an unconstrained
random number, at least 8 byte long, but very possibly 16 bytes.
Specifying that ICID = hash(Initial Payload) would pretty much seal that
payload and prevent lots of games. It might be a good idea regardless of
what we do, because then attackers would have a very hard time creating
faked CInitial. If the content changes, the ICID also changes.

> hmac_key cannot be calculated by an attacker.

You mean the shared secret derived from the ESNI and used to encrypt the
original SNI?

We may need to make that a bit more explicit in the draft.

> would be unique to ClientHello.

If we make ICID = hash(ClientHello), then we make the Initial AEAD key
dependent on the content of the Client Hello. The more I think of it,
the more it looks like a good idea.

> I think deriving DCID from Hash(ClientHello) would also fix the issue.

Yes. The entire exchange then get tied to the Client Hello.

>> why we nixed it. Is there a potential deployment issue?

Having one ICID per client hello feels better. There is always a risk
that having some Initial packets routed by ICID and others routed by
SCID would confuse firewalls or load balancers.

>> isn't that just a variant of CInitial' ?

I think we are making progress. We should write the ICID = hash(Client
Hello) requirement in the next version of the draft. My only question is
whether this hash should be some plain SHA256 hash, or instead an HMAC
using the ESNI-derived key. I am leaning towards the simpler solution,
because clients could do it in a version independent way.

-- Christian Huitema

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 16 Dec 2018 17:58:14 +0900

2018年12月16日(日) 13:22 Christian Huitema <[email-masked]>:
> the Initial Packet"?

Yes.

> Yes, that can work. The ICID is an unconstrained

I've added clarification that says that "Zx is the extracted DH shared
secret of Encrypted SNI".

> because clients could do it in a version independent way.

I also prefer using a hash function rather than exposing a value
derived from the secret (even though doing that should be safe). OTOH,
I prefer having agility instead of hard-coding the algorithm.

I've filed https://github.com/kazuho/draft-kazuho-quic-authenticated-handshake/pull/8
based on my preference, I'd appreciate it if you could take a look. I
hope that having a PR will help us confirm that we are talking about
the same idea.

-- 
Kazuho Oku

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 16 Dec 2018 18:07:18 +0900

> I acknowledge that the attack vector exists.

Sorry for the confusion, but I am starting to wonder if the attack
vector really exists.

The attacker cannot create CInitial' that contains the same ESNI
extension as CInitial, because the Initial packets are authenticated
by the ESNI shared secret. Therefore, we can be certain CInitial' that
triggers a SInitialX would be based on a different by a different ESNI
shared secret, which in turn means that SInitialX would never be
accepted by the client. Am I missing something?

-- 
Kazuho Oku