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

Version Negotiation DoS #522

Closed
janaiyengar opened this issue May 12, 2017 · 13 comments
Closed

Version Negotiation DoS #522

janaiyengar opened this issue May 12, 2017 · 13 comments
Labels
-transport design An issue that affects the design of the protocol; resolution requires consensus. has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list.

Comments

@janaiyengar
Copy link
Contributor

A Version Negotiation (VN) packet now contains a server-chosen connection ID and echoes the client's packet number, for a client to be able to validate that the server did see the client's packet.

There are no rules around what a client should do on receiving VN packets with random IDs and packet numbers that do not match. If the client just drops them on the floor, an attacker can send a bunch of VN packets with an arbitrary connection ID and with random packet numbers, hoping to kill the client's ongoing handshake.

Is 4 bytes of entropy enough to prevent this DoS?

@marten-seemann
Copy link
Contributor

An attacker would also have to guess the right port number, which should be close to 2 bytes of entropy in itself.

@janaiyengar
Copy link
Contributor Author

Yeah, good point. But OSes are bad at handing out port numbers randomly -- I could be wrong, but I believe OSes hand these out sequentially to sockets. There may be far fewer than 2 bytes of entropy there.

@martinthomson
Copy link
Member

I said this over here, but I'll add it here for the benefit of this thread.

I don't assume that Version Negotiation gives any indication of consent to receive, though the echo of a 31-bit value might suffice (TCP is 32). It doesn't need to really, because the client is only going to send the same packet that it would have sent without seeing any packets from the server.

But I don't think that addresses the issue here. The issue here is that a client might want to validate a Version Negotiation packet. I separately opened #523 on that point, but this seems like it is asking the question about whether we have enough entropy to ensure that the Version Negotiation packet is OK.

BTW, it's only 31-bits of entropy. Port number might be close to zero entropy, though in practice it's a fair bit better than that (maybe as much as 14 bits) and we might assume that the IP address is known, so zero entropy. If the benchmark is TCP, then we're 1 bit worse off. On the other hand, if the benchmark is DNS, things don't look too bad.

Modern operating systems generate ephemeral addresses randomly. But it's usually from a small-ish slice of ports. Test that if you like:

node -e 'var s = require("dgram").createSocket("udp6");s.bind(function(){console.log(s.address().port);s.close();});'

@mikkelfj
Copy link
Contributor

... which goes back to my request to linking client chosen id to the server chosen id - in this case it would reduce attacks to those on path.

@martinthomson
Copy link
Member

Oh, so that I don't forget, we only use 31-bits because of the need to increment this number. If we randomize for every Client Initial packet, which seems perfectly doable now, then we can use the entire 32-bit space. That's all assuming that 32 is enough but 31 isn't...

@martinthomson
Copy link
Member

I just tested Windows 10 and it doesn't randomize the source port for ephemeral UDP. So no entropy there :( Back down to 31.

@ekr
Copy link
Collaborator

ekr commented May 13, 2017

This seems like a more generic issue in that it's possible to create a DOS attack essentially by sending any packet that appears to be from the server to the client that passes the QUIC packet checks but is bogus at an upper layer. For instance, one could send an SH that had a cipher suite
that the client did not offer.

Implicitly, this issue assumes that we want (or will live with)

  • On-path attackers to be able to terminate a connection during the handshake phase
  • Off-path attackers not to be able to do so.

It seems like it would be easiest to address this problem generically rather than
as a side effect of other designs. We've already agreed that we are going to have
an integrity check on packets, so it seems like the easiest thing to do would be
to have it be keyed with the conn-id.

Specifically:
Client initial packets are either HMAC(0, ) or HMAC(conn_id, ), depending on what's convenient.
Server initial packets are HMAC(conn_id, packet).

This will prevent injection attacks by any attacker who hasn't seen the client initial packet, this fixing both this issue and others.

@mikkelfj
Copy link
Contributor

This almost makes sense to me except

  • the HMAC cannot trivially be version dependent then.
  • the HMAC key is public, so you don't gain much compared to returning the initial connection id as I suggested earlier.

@ekr
Copy link
Collaborator

ekr commented May 13, 2017

the HMAC cannot trivially be version dependent then.

I don't understand this. The HMAC is just replacing FNV-1a, so we'll pick an algorithm and stick with it.

the HMAC key is public, so you don't gain much compared to returning the initial connection id as I suggested earlier.

What you gain is having something that's generic rather than something that requires specific intervention and analysis for each case.

@mikkelfj
Copy link
Contributor

the HMAC cannot trivially be version dependent then.

I don't understand this. The HMAC is just replacing FNV-1a, so we'll pick an algorithm and stick with it.

Yes, exactly - if 22 years from now, HMAC-SHA256 is trivially broken, you cannot replace it. FNV-1a does not attempt to be cryptographically strong, so it cannot break in the same way, but offer fewer guarantees in return. Note that I am not against using HMAC because it is a stronger defence againts obnoxious middleware, and since unencrypted payload is not bottleneck, there isn't much gain in choosing a cheaper solution. However, FNV-1a is simpler to specify as universally true which is probably why it was chosen.

the HMAC key is public, so you don't gain much compared to returning the initial connection id as I suggested earlier.
What you gain is having something that's generic rather than something that requires specific intervention and analysis for each case.

Well, yes I do not disagree, I am just pointing out the the generic solution could also be just returning the initial Connection ID because the HMAC in this setup provides not stronger guarantees as far as I can tell. The only guarantee it provides is that that payload has not been tampered with, but that is for the handshake to decide, and the handshake goes to great lengths to support extensible cryptography (for better or worse). Alas, I wouldn't mind a much simpler QUIC version that just decided on CURVE25519 and be done with it, then change version if needed. And this is indeed possible to do. But for a generic version 1 of QUIC, you need to consider all this crypto replacability, I'm afraid.

But, even before you wrote this, I was also thinking why not use a HMAC instead of FNV-1a, so I largely follow what you say.

@ekr
Copy link
Collaborator

ekr commented May 13, 2017 via email

@mikkelfj
Copy link
Contributor

I'm just going to throw this CLMUL hash into the equation, just for reference:

Faster 64-bit universal hashing using carry-less multiplications
https://arxiv.org/pdf/1503.03465.pdf

@mnot mnot added design An issue that affects the design of the protocol; resolution requires consensus. -transport labels May 22, 2017
@martinthomson martinthomson added this to Handshake in QUIC Jun 5, 2017
@martinthomson
Copy link
Member

I believe that we fixed this with the change to encryption for all packets.

@martinthomson martinthomson removed this from Handshake in QUIC Oct 19, 2017
@mnot mnot added the has-consensus An issue that the Chairs have determined has consensus, by canvassing the mailing list. label 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. 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