quicwg / base-drafts

Internet-Drafts that make up the base QUIC specification
https://quicwg.org
1.63k stars 204 forks source link

Client's initial destination CID is unauthenticated #1486

Closed kazuho closed 6 years ago

kazuho commented 6 years ago

With the merger of stream 0 DT proposal, we now allow uncoordinated middleboxes to change the server's CID.

While I understand that it is beneficial to allow the existence of such middleboxes on certain deployments, I think that we should require (or provide a way for) other deployments to check that the client's initially chosen DCID field has not been tampered by a middlebox.

Below is a copy of https://github.com/quicwg/base-drafts/issues/1451#issuecomment-399317602 discussing the possible security and ossification concerns behind the issue.

The issue about simply allowing the existence of an uncoordinated middlebox is that it becomes impossible for any server to detect somebody on-path altering the handshake traffic.

For example, a middlebox can alter the server CID by sending a Retry, and the server will not notice the alternation if the middlebox also drops the token field of the 2nd Initial packet sent from the client that traverses through the middlebox to the server.

While I understand that you cannot care about the issue in the deployments that you are interested in, I think that others would be worried about the possible impact on security as well as the ossification concern including the one that I have described in #1451 (comment).

Fortunately, there are ways to define a signal for detecting tampering that can be implemented by server operators who will not have uncoordinated DOS detection devices.

One way is to add an "Original_DCID" field to Transport Parameters, and state that "a server SHOULD check that the value of the Original_DCID field matches that of the packet that it saw in the first packet that belonged to the connection". Servers running behind an uncoordinated middlebox will turn this check off.

Note that having a configuration knob is mandatory for servers running behind such a middlebox, even if we do not introduce the "Original_DCID" field. This is because Retry is version-specific (which means that uncoordinated DOS mitigation devices might need to send a Version Negotiation packet). To support that, the servers need to have a knob that changes how the downgrade protection logic works (FWIW, end-to-end version downgrade protection is currently a MUST; we need to change it as well to allow the existence of uncoordinated DOS mitigation devices).

kazuho commented 6 years ago

relates to: #1479

martinthomson commented 6 years ago

The current design allows for considerable flexibility in routing up until the point that the first Handshake packet commits to a set of connection IDs. Part of that flexibility allows for changing the connection ID.

A server could decide to validate changes using the token it passes to clients in Retry packets, if it chose to do so. This could validate the entire sequence of changes, at a modest cost in bytes.

The only protection a client has is that packets from Handshake on are authenticated with end-to-end keys. An attacker can't modify these packets. If the client doesn't change its opinion about its connection ID - and it has no reason to do so that I'm aware of - then an attacker can't change the client connection ID value without causing packets to be dropped eventually.

The server has the same protection available, though our design allows multiple options for a server to change connection IDs. So the only value that is authenticated is the final value, which might not have been reached honestly if - for example - an attacker has used spoofed Retry packets to route the client to a sub-optimal server instance.

If the goal here is to authenticate the chain of connection IDs that are used, starting from the randomized value selected by the client, then it needs to cover more than a single value.

kazuho commented 6 years ago

The current design allows for considerable flexibility in routing up until the point that the first Handshake packet commits to a set of connection IDs. Part of that flexibility allows for changing the connection ID.

A server could decide to validate changes using the token it passes to clients in Retry packets, if it chose to do so.

My point is that it cannot.

Consider the following case:

The initial packet being altered by a middlebox will look as if it was a Initial packet without a token sent from a client. A server cannot tell if the Destination CID field of the Initial packet was generated by the client or by a middlebox.

martinthomson commented 6 years ago

Ahh, though it's only the first one, that might be enough. Not sure how much this matters, but we should do something, even if that is only write this down.

kazuho commented 6 years ago

Ahh, though it's only the first one, that might be enough. Not sure how much this matters, but we should do something, even if that is only write this down.

Yes.

Consider you want to build a "gateway" that verifies Client Hello. What you might do is:

By doing these, a middlebox can skip the cost of AES for decrypting the Initial packet, because the every Initial packet that it forwards will be encrypted using the same bitstream.

I think we should permit the use of zero-length token, because it would be useful for stateful path validation.

OTOH, I would like to prevent seeing these kind of hacks being applied by middleboxes (since it is an ossification concern), if the cost of preventing it is marginal. IMO, including initial DCID in TP and requiring the servers to validate the value when possible meets that goal.

janaiyengar commented 6 years ago

There's a simple DoS attack here. This is a way for a MITM to force specific CIDs towards the server. If the attacker replied to every outgoing Initial with the same CID in a Retry packet, the new Initial from the client would have a CID that collides with an existing connection at the server and get dropped. I don't this is an interesting attack, but I wonder if the ability to have all connections target specific CIDs might allow some sort of interesting attacks via steering the server's load balancing infrastructure.

mikkelfj commented 6 years ago

but I wonder if the ability to have all connections target specific CIDs might allow some sort of interesting attacks via steering the server's load balancing infrastructure.

Yes, this is what I've trying to say. This is why I suggest the original DCID is empty and leave the routing decision to LB and instead have a separate token that can used in retry, and chains of retries.

However, the LB can also today choose to route randomly be detecting the packet is initial and ignore the DCID routing logic in this case. So maybe the current ODCID does work like a token in that sense.

kazuho commented 6 years ago

@janaiyengar

but I wonder if the ability to have all connections target specific CIDs might allow some sort of interesting attacks via steering the server's load balancing infrastructure.

I do not think that providing middleboxes the ability change the DCID opens up a new attack vector, because load balancers need to take care of DoS attacks mounted by clients using specific DCID (or set of specific DCIDs) anyways.

martinthomson commented 6 years ago

@kazuho got it in one. It is cheaper by far for the attacker to act as a client if this is their goal. @mikkelfj's defense is probably best. Don't bother applying normal routing rules to Initial packets.

mikkelfj commented 6 years ago

I would feel more comfortable if the original DCID were in TP, but I do not have a solid argument. I feels wrong that a handshake can complete with something other than what startet it. Like 2 years from now some unforseen attack could be mounted based on bad assumptions somewhere along the path.

kazuho commented 6 years ago

@mikkelfj

I would feel more comfortable if the original DCID were in TP, but I do not have a solid argument. I feels wrong that a handshake can complete with something other than what startet it.

+1

While I do not think that allowing a middlebox to change Initial DCID opens a new DoS attack vector against the server, I do share the concern that it might have other implications.

At the very least, I see a theoretical ossification concern as I have described in https://github.com/quicwg/base-drafts/issues/1486#issuecomment-400568727.

Should we create a PR that adds the original DCID to TP?

mikkelfj commented 6 years ago

For example, someone might get the idea that having a (trusted) client set ODCID bit 2 could encode priority 0 connectivity. Someone else might then think it would be a good idea to create a middle box that always sets bit 2 so all its connections get through before the competitors equipment.

mikkelfj commented 6 years ago

More generally, the initial AEAD tag could be verified in the handshake instead of overloading TP. Since TP is covered by the tag, it cannot contain it.

igorlord commented 6 years ago

If a "retry-initial" packet can be distinguished from a "non-retry-initial" (bit in the header that is later verified through AEAD, for example), a server that would never send a zero-length token could see that tampering has taken place right away.

mikkelfj commented 6 years ago

It is the client that needs to ensure that it's original DCID was received by the server - how would a bit fix that?

igorlord commented 6 years ago

The proposal is for handshake AD to include the "retried initial" bit in addition to the client's DCID in the handshake initial secret derivation.

If the middlebox executes "inject retry and then drop token from the retired initial" and bleaches the "retried initial" bit from the retired initial packet, handshake will fail. But if the middlebox allows the "retried initial" bit through, the server will be able to tell that the token is not the one it sent.

mikkelfj commented 6 years ago

But there is a (perceived) issue even without considering retry at all: a middlebox might detect a pattern in the initial packet and modify content in a non-observerable manner, pehaps just to be "helpful". This could include swapping bits in ODCID. Only a full tag verification would prevent this.

If the server adds the clients initial tag as a server TP, the client can reject the handshake trivially if manipulated. This might extend to retry handling, but the concern is not retry here.

igorlord commented 6 years ago

I am realizing that I am not the best person here to assess what exactly crypto protects against. The TLS draft states the following, so I am (mis-?) reading it to mean that if client and server do not see the same original client's DCID, the handshake will fail. (And the proposal is to include the "retry-initial" bit in the initial_secret computation.

initial_salt = 0x9c108f98520a5c5c32968e950e8a2c5fe06d6c38
initial_secret =
    HKDF-Extract(initial_salt, client_dst_connection_id)

client_initial_secret =
   HKDF-Expand-Label(initial_secret, "client in", Hash.length)
server_initial_secret =
   HKDF-Expand-Label(initial_secret, "server in", Hash.length)
mikkelfj commented 6 years ago

Yeah, it looks like it is protected - from what you have extracted. If the client_dst_connect_id is replaced with a client_initial_aead_tag, it would be a stronger proof. Historically initial packets were not AEAD protected, so that might be part of it, but they are now. The tag is is not trustworthy in itself - but it is very hard to create a forged initial packet with the same tag.

MikeBishop commented 6 years ago

But the protection on the Initial packets doesn't have a shared key yet. That means an on-path attacker could decrypt, modify bytes, and re-encrypt. (It would need to do the transformation in the reverse direction as well, of course.) The question here is whether we want to attempt to detect such tampering.

mikkelfj commented 6 years ago

Well, yes - it won't work. That ODCID state will get into the handshake, but only in a hashed form that the client cannot verify, so it doesn't matter. In fact, an on path attacker could weaken the integrity by make the ODCID non-random.

If the server stored the ODCID in TP explicitly, or better, the initial AEAD tag, and if the client is required to verify it. then it all is good. (As I already suggested earlier).

mikkelfj commented 6 years ago

If the server sent something back encrypted with the initial server secret and verified by the client, then that would also work. But the QUIC TLS doc is hard to read. It is not very clear what kind of key is used in the servers initial response - is that already 1-RTT, or is there a first flight with initial keys. If it is the initial key, then the client can only verify the tag if the ODCID matches. If it is hashed into the 1-RTT context, it doesn't matter.

this makes little sense to me: what key is used after GetHandshake server side? https://quicwg.org/base-drafts/draft-ietf-quic-tls.html#rfc.section.4.1.3

ekr commented 6 years ago

On Mon, Jul 9, 2018 at 1:13 PM, MikkelFJ notifications@github.com wrote:

If the server sent something back encrypted with the initial server secret and verified by the client, then that would also work. But the QUIC TLS doc is hard to read. It is not very clear what kind of key is used in the servers initial response - is that already 1-RTT,

It clearly can't be the 1-RTT key because it contains the DH share that le used to generate the 1-RTT key. But after that in the same flight there is data that is in epoch 2.

This should be fairly clear in: https://tools.ietf.org/html/draft-ietf-quic-transport-13#section-6.5

or is there a first flight with initial keys. If it is the initial key,

then the client can only verify the tag if the ODCID matches. If it is hashed into the 1-RTT context, it doesn't matter.

this makes little sense to me: what key is used after GetHandshake server side? https://quicwg.org/base-drafts/draft-ietf-quic-tls.html#rfc.section.4.1.3

Initial keys.

You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/quicwg/base-drafts/issues/1486#issuecomment-403605280, or mute the thread https://github.com/notifications/unsubscribe-auth/ABD1od32gfZqnuhqKo3Wqv-iqJPm14SAks5uE7lcgaJpZM4U5BQ4 .

mikkelfj commented 6 years ago

@ekr - yes I was just about to post the below as you wrote. I was confused by thinking that you only need 1 roundtrip to have a secret - the DH secret - but that is the inner layer of TLS.

Still hard to follow - but as I read it, the initial keys are used for a few roundtrips. Full encryption with DH exhanged keys would be possible at servers response, but that is not what happens. The outer layer stays weakly encrypted, but the TLS messages are protected until a solid 1-RTT key is forged, which is more production safe than the early DH exchange. Therefore the client is forced to verify that ODCID was received if it wants to complete the handshake.

The AEAD tag cannot be used to strengthen that verification further because the AEAD tag depends on the initial secret and cannot depend on itself.

It would still be safer if the clients AEAD tag were to be stored in the servers TP as an extra precaution because on path attacker could otherwise spoof the initial packet contents knowing the ODCID from plain text. QUIC doesn't generally try to protect from on-path attacks, but that is in regards to service disruption, not loss of integrity. This is worse.

ekr commented 6 years ago

On Mon, Jul 9, 2018 at 1:30 PM, MikkelFJ notifications@github.com wrote:

@ekr https://github.com/ekr - yes I was just about to post the below as you wrote. I was confused by thinking that you only need 1 roundtrip to have a secret - the DH secret - but that is the inner layer of TLS.

Still hard to follow - but as I read it, the initial keys are used for a few roundtrips. Full encryption with DH exhanged keys would be possible at servers response, but that is not what happens. The outer layer stays weakly encrypted, but the TLS messages are protected until a solid 1-RTT key is forged, which is more production safe than the early DH exchange

Huh? No. The server starts sending using the Handshake keys in its first flight. This is clearly shown in the diagram I linked to.

Therefore the client is forced to verify that ODCID was received if it

wants to complete the handshake.

The AEAD tag cannot be used to strengthen that verification further because the AEAD tag depends on the initial secret and cannot depend on itself.

It would still be safer if the clients AEAD tag were to be stored in the servers TP as an extra precaution because on path attacker could otherwise spoof the initial packet contents knowing the ODCID from plain text. QUIC doesn't generally try to protect from on-path attacks, but that is in regards to service disruption, not loss of integrity. This is worse.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/quicwg/base-drafts/issues/1486#issuecomment-403609915, or mute the thread https://github.com/notifications/unsubscribe-auth/ABD1ofsvpnfnyzxDOhgWZJ-cMTAId61Rks5uE71LgaJpZM4U5BQ4 .

mikkelfj commented 6 years ago

Huh? No. The server starts sending using the Handshake keys in its first flight. This is clearly shown in the diagram I linked to.

Yes - in the subsequent packet, not in a few more roundtrips.

ekr commented 6 years ago

In a subsequent QUIC packet but in the same UDP datagram if you are coalescing. This is just the physics of the situation: you can't start encrypting until the client has the server's DH share.

mikkelfj commented 6 years ago

But to the main point:

The ODCID is verified. But that header and non-crypto parts can be manipulated / ossified. Is it worth storing the clients initial AEAD tag in the servers TP to protect against this?

igorlord commented 6 years ago

That means an on-path attacker could decrypt, modify bytes, and re-encrypt.

Ok, but if you make initial secret (or ODCID) a part of AD for 1-rtt encryption, you could ensure that while the tampering would allow the handshake to succeed, it would but not allow transmission past the handshake.

mikkelfj commented 6 years ago

Ok, but if you make initial secret (or ODCID) a part of AD for 1-rtt encryption, ...

That already happens because the handshake needed to construct the clients 1-RTT key is protected by the servers initial secret. If the servers initial secret is not based on the correct ODCID, the client cannot proceed.

The surface of the clients initial packet can be manipulated, likel header flags, but the TLS layer eventually verifies the clients TP too.

ad-l commented 6 years ago

I noticed another problem caused by the fact that ConnectionID is not authenticated.

In short header packets, the connection ID is followed by the encrypted packet number. The encryption of the PN is only indirectly authenticated by the QUIC headers appearing in the additional authenticated data of the AEAD encryption. However, if a network attacker is given the capability to alter the Connection ID, he can use this capability to truncate or extend the encrypted packet number. This is very easy to do - for instance, if the attacker wants to truncate one byte off the encrypted PN he can set the connection ID to be one byte longer and ensure that the headers remain the same.

Unfortunately, this is an effective attack against the confidentiality of packet number encryption (e.g. successful PN extension is a trivial distinguisher for the most significant bits of the PN being 0). PN truncation also puts worrying pressure on AEAD - replayability is no longer prevented by AAD (which is provably authenticated in AEAD) but by implicit nonce authentication (which is not typically proved).

mikkelfj commented 6 years ago

@ad-l Why do you say the CID it is not authenticated?

In early handshake where AEAD is not safe, the question was if the original CID is authenticated, and we have established that it is, eventually - because if the first packet is forged, the traffic keys come out wrong preventing the connection from being established.

In short headers where full traffic keys are available, the AEAD tag protects the CID, so it cannot change length by anyone on path, except for the end-points with the traffic keys.

ad-l commented 6 years ago

In early handshake where AEAD is not safe, the question was if the original CID is authenticated, and we have established that it is, eventually - because if the first packet is forged, the traffic keys come out wrong preventing the connection from being established.

Where is this established? This is completely wrong - the fact that the CID goes into the initial secret derivation does not matter at all. Only what goes into the QTP is strongly authenticated - everything else is as good as plaintext from an active attacker perspective...

mikkelfj commented 6 years ago

@ad-l sorry, that was also my initial position, and I can't remember what convinced me otherwise. It doesn't seem right.

MikeBishop commented 6 years ago

Closed by #1793.