Skip to content

Commit 6705db9

Browse files
neildgopherbot
authored andcommitted
quic: clean up crypto streams when dropping packet protection keys
When dropping packet protection keys for a number space: Check to see if there is unused CRYPTO data received from the peer in the space. If so, close the connection with an error. This can only happen if the peer has sent us data with a gap in it. We can never read the data that fills that gap (because we're dropping the key it would be encrypted with), and this situation cannot happen without the peer sending invalid TLS handshake data. Drop any buffered CRYPTO data being sent to the peer. Under normal operations, we may have data that was sent to the peer but which we haven't received an ACK for yet. The peer has received the data (or we wouldn't be dropping the number space) and we will never see the ACK (because we're dropping the key it would be encrypted with). Fixes golang/go#70704 Change-Id: I53380169cb59a2a6f87e69b38522ba81ad38c2b0 Reviewed-on: https://go-review.googlesource.com/c/net/+/634617 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Jonathan Amsterdam <[email protected]> Auto-Submit: Damien Neil <[email protected]>
1 parent 4ef7588 commit 6705db9

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

quic/conn.go

+3
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ func (c *Conn) confirmHandshake(now time.Time) {
216216
// discardKeys discards unused packet protection keys.
217217
// https://www.rfc-editor.org/rfc/rfc9001#section-4.9
218218
func (c *Conn) discardKeys(now time.Time, space numberSpace) {
219+
if err := c.crypto[space].discardKeys(); err != nil {
220+
c.abort(now, err)
221+
}
219222
switch space {
220223
case initialSpace:
221224
c.keysInitial.discard()

quic/crypto_stream.go

+18
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,21 @@ func (s *cryptoStream) sendData(off int64, b []byte) {
139139
s.out.copy(off, b)
140140
s.outunsent.sub(off, off+int64(len(b)))
141141
}
142+
143+
// discardKeys is called when the packet protection keys for the stream are dropped.
144+
func (s *cryptoStream) discardKeys() error {
145+
if s.in.end-s.in.start != 0 {
146+
// The peer sent some unprocessed CRYPTO data that we're about to discard.
147+
// Close the connetion with a TLS unexpected_message alert.
148+
// https://www.rfc-editor.org/rfc/rfc5246#section-7.2.2
149+
const unexpectedMessage = 10
150+
return localTransportError{
151+
code: errTLSBase + unexpectedMessage,
152+
reason: "excess crypto data",
153+
}
154+
}
155+
// Discard any unacked (but presumably received) data in our output buffer.
156+
s.out.discardBefore(s.out.end)
157+
*s = cryptoStream{}
158+
return nil
159+
}

quic/tls_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,32 @@ func TestConnAEADLimitReached(t *testing.T) {
615615
tc.advance(1 * time.Second)
616616
tc.wantIdle("auth failures at limit: conn does not process additional packets")
617617
}
618+
619+
func TestConnKeysDiscardedWithExcessCryptoData(t *testing.T) {
620+
tc := newTestConn(t, serverSide, permissiveTransportParameters)
621+
tc.ignoreFrame(frameTypeAck)
622+
tc.ignoreFrame(frameTypeNewConnectionID)
623+
tc.ignoreFrame(frameTypeCrypto)
624+
625+
// One byte of excess CRYPTO data, separated from the valid data by a one-byte gap.
626+
tc.writeFrames(packetTypeInitial,
627+
debugFrameCrypto{
628+
off: int64(len(tc.cryptoDataIn[tls.QUICEncryptionLevelInitial]) + 1),
629+
data: []byte{0},
630+
})
631+
tc.writeFrames(packetTypeInitial,
632+
debugFrameCrypto{
633+
data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial],
634+
})
635+
636+
// We don't drop the Initial keys and discover the excess data until the client
637+
// sends a Handshake packet.
638+
tc.writeFrames(packetTypeHandshake,
639+
debugFrameCrypto{
640+
data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake],
641+
})
642+
tc.wantFrame("connection closed due to excess Initial CRYPTO data",
643+
packetType1RTT, debugFrameConnectionCloseTransport{
644+
code: errTLSBase + 10,
645+
})
646+
}

0 commit comments

Comments
 (0)