Closed kazuho closed 6 years ago
relates to: #1479
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.
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.
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.
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.
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.
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.
@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.
@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.
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.
@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?
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.
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.
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.
It is the client that needs to ensure that it's original DCID was received by the server - how would a bit fix that?
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.
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.
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)
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.
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.
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).
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
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 .
@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.
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 .
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.
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.
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?
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.
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.
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).
@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.
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...
@ad-l sorry, that was also my initial position, and I can't remember what convinced me otherwise. It doesn't seem right.
Closed by #1793.
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.