Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server Initial verification for Attacker On The Side defense #2097

Closed
huitema opened this issue Dec 4, 2018 · 7 comments
Closed

Server Initial verification for Attacker On The Side defense #2097

huitema opened this issue Dec 4, 2018 · 7 comments
Labels
-transport design An issue that affects the design of the protocol; resolution requires consensus. future-version An issue that is best addressed in a future version of QUIC, or an extension to it. has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list.

Comments

@huitema
Copy link
Contributor

huitema commented Dec 4, 2018

The more I am watching the long discussion of Pr #2076 and related email thread, the more I believe that the we cannot solve the problem by just requiring parallel evaluation of multiple contexts by the client. Let's start by stating the requirement: we want connection establishment to succeed, even in presence of "attackers on the side" that can forge and send arbitrary packets to client and servers.

@kazuho designed a server side defense, which is the first step in the "attacker on the side" defense. The client attempts to start a connection by sending a "Client Hello" packet to the server. Different client hellos create different contexts on the server, regardless of the contents of headers or of the addresses. To each context corresponds an handshake encryption key. Messages sent with that encryption key can only originate from the sender of the Client Hello. For one of the contexts, that origin will be the actual client. For the other contexts, it might be an attacker.

Protecting the server is not enough, because the attackers can spoof server responses. The client may receive several different "Server Hello" packets in response to a single "Client Hello". By default, the client cannot verify that the Server Hello originated from the intended server -- the server credentials will only arrive much later in the exchange. In the absence of server authentication, the client needs to open a connection context for each different Server Hello. Each context will be associated with an encryption key. Just like in the server case, each context is associated with the actual sender of the Server Hello. One of these contexts will be associated with the intended servers. The client will only find out which one after it processes the server credentials, which will be received in the handshake messages. Until that, the client will have to process all messages in parallel.

This algorithm is hard to implement in QUIC V1, because the identifies its "connection context" with a single Connection Identifier (CID), which it commits to in the Initial packet -- and it has to do that, unless we want to spend an extra RTT in the connection setup. The parallel execution supposes managing several client contexts, each associated with a handshake key. We would get the following flow:

  1. Client sends Client Hello with Dest=ICID, Srce= CCID.
  2. Server receives Client Hello, creates context based on Server Hello content, picks SCID
  3. Server sends Server Hello with Dest= CCID, Source=SCID
  4. Client receives Server Hello, associates context with the tuple (CCID, SCID)
  5. Server sends Handshake messages with Dest= CCID, Source=SCID
  6. Client verifies the messages with Handshake key associated with CCID, SCID. Messages that fail authentication are ignored.
  7. Client sends ACK, etc with Dest=SCID, Srce=CCID
  8. Client validate server credentials. Connection is established.

This works as long as the attacker forges its responses without knowledge of the server's SCID. If the attacker sees the first Server Hello (step 3), it can race a competing Server Hello with the same CCID, SCID. If the attacker wins the race, it will effectively "own" the context (CCID, SCID). To make that work, we need an extra parameter, for example a "Server Token" that would be carried in the Server Initial packets and also in the handshake packets, and that could be verified by the client. For example, the token could be the hash of the "Server Hello", computed with the hash algorithm negotiated for the handshake. The modified algorithm would be:

  1. Client sends Client Hello with Dest=ICID, Srce= CCID.
  2. Server receives Client Hello, creates context based on Server Hello content, picks SCID
  3. Server sends Server Hello with Dest= CCID, Source=SCID, token = hash(Server Hello)
  4. Client receives Server Hello, verifies the token. If the token does not match, the message is ignored. If it matches, client associates context with the tuple (CCID, SCID, Token)
  5. Server sends Handshake messages with Dest= CCID, Source=SCID, Token = hash(Server Hello)
  6. Client verifies the messages with Handshake key associated with (CCID, SCID, Token). Messages that fail authentication are ignored.
  7. Client sends ACK, etc with Dest=SCID, Srce=CCID (No need for the server token there).
  8. Client validate server credentials. Connection is established.

Adding the server token to the server's Initial and Handshake messages would be a significant change in the protocol, and adding speculative evaluation of multiple contexts would be a significant burden to the clients. There are other issues, such as how to handle HRR and stateless Retry, or how to signal that the server is busy without allowing attackers to spoof the busy signal. The Stateless Retry can probably be handled by creating yet another parallel evaluation context on the client. We would need to transport HRR responses in something like a Stateless Retry. And the client that really wants to be immune to DOS attacks should probably just ignore the busy signals, which is of course a tradeoff between robustness and responsiveness.

This creates a big set of changes, somewhat similar to the "stream zero reset" that the WG went through in June. Such a change would likely delay the WG by another 3 or 4 months, and result in a fairly heavy weight connection protocol. So maybe we should explore the other potential defense, "verify that the Server Hello originated from the intended server". The flow would then be:

  1. Client sends Client Hello with Dest=ICID, Srce= CCID.
  2. Server receives Client Hello, creates context based on Server Hello content, picks SCID
  3. Server sends Server Hello with Dest= CCID, Source=SCID
  4. Client receives Server Hello, performs server origin verification, associates context with the tuple (CCID, SCID)
  5. Server sends Handshake messages with Dest= CCID, Source=SCID
  6. Client verifies the messages with Handshake key associated with CCID, SCID. Messages that fail authentication are ignored.
  7. Client sends ACK, etc with Dest=SCID, Srce=CCID
  8. Client validate server credentials. Connection is established.

This is pretty much the same flow as Quic V1, with just an extra authentication added. We can debate what the server authentication should be. I think that we have a potential solution with something like ESNI, which uses a public key published by the "fronting server". The Server Hello could be verified by somehow demonstrating knowledge of that public key. Since ESNI and resistance to censorship go very much hand in hand, reusing the same credential would not be too much of a stretch.

@mikkelfj
Copy link
Contributor

mikkelfj commented Dec 4, 2018

The first scenario can be attacked all the way up to point 8. certificate validation because an attacker seeing only client messages can create its own handshake key that competes with the server. The client will have to process all alternative handshake keys and alternative SCID values until one handshake passes certificate validation.

The second scenario with server token is not an improvement since the attacker can just provide it own fully valid ServerHello with a token. It will also eventually fail certificate, but only after consuming resources.

A fix to the above would be if the client already knows the server public key and the server signs a challenge in the first packet it responds. That challenge could be the ICID. This corresponds to step 4 in the third flow in the above.

If the server knows the clients public key (not usually the case, but can be used server to server), the client can can send a signed nonce.

NOTE: if the ICID is a hash of the ClientHello this prevents an attack where the attacker races a client initial. If the attacker attempts to copy the ICID with its own ClientHello, the handshake key will fail. If the attacker attempts to copy the ICID and the ClientHello, it will just be a retransmission, and the attacker will not have achieved anything. This assumes the initial packet only contains what is hashed in ICID.

@huitema
Copy link
Contributor Author

huitema commented Dec 4, 2018

The first and second scenarios assume parallel processing of multiple contexts at clients and servers. Yes, that creates extra load. The goal of the defense is to sustain thst load until one of the contexts results in a valid connection.

@kazuho
Copy link
Member

kazuho commented Dec 5, 2018

@huitema

This works as long as the attacker forges its responses without knowledge of the server's SCID. If the attacker sees the first Server Hello (step 3), it can race a competing Server Hello with the same CCID, SCID. If the attacker wins the race, it will effectively "own" the context (CCID, SCID).

I disagree with this observation (and the therefore the discussion that follows).

A client does not need to distinguish each "flow of handshake transcripts" based on SCID. What it should do is distinguish each flow by ServerHello that's being contained (for Initial packets) or the handshake key (for Handshake packets) that decrypts successfully.

Therefore, there is no need for a "server token."

@huitema
Copy link
Contributor Author

huitema commented Dec 5, 2018

@kazuho: you are saying that the client does not need an extra ID because it can use trial decryption. That's true, but that's not a very desirable solution, because then attackers can DOS the client.

@MikeBishop MikeBishop added design An issue that affects the design of the protocol; resolution requires consensus. -transport labels Dec 11, 2018
@martinthomson
Copy link
Member

martinthomson commented Dec 21, 2018

@huitema, do you think that this turns into any specific actions for the current drafts, or is that what turned into draft-kazuho-quic-authenticated-handshake?

@huitema
Copy link
Contributor Author

huitema commented Dec 21, 2018

@martinthomson there are two threads. We have been exploring a series of heuristics to make the exchange more robust without changing the protocol. The high level summary is that this works OK on the server side if one creates a context for each set of <hash(Client Initial), address tuple>, but that the complexity on the client is rather stiff. On the other hand, if we assume that there is a way to establish some kind of secret between client and server before the handshake, as with ESNI, then we arrive to a very robust solution as in the authenticated handshake draft.

Which is a long way to say Yes.

@martinthomson
Copy link
Member

Thanks, based on that I'm marking this v2. As in, we might want to consider authentication in a new version. (That might be all we consider, as in the draft :)

@martinthomson martinthomson added the future-version An issue that is best addressed in a future version of QUIC, or an extension to it. label Dec 21, 2018
@mnot mnot added the has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list. label Mar 5, 2019
@mnot mnot closed this as completed Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-transport design An issue that affects the design of the protocol; resolution requires consensus. future-version An issue that is best addressed in a future version of QUIC, or an extension to it. has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list.
Projects
None yet
Development

No branches or pull requests

6 participants