drop packets for new gQUIC connections that are too small

This commit is contained in:
Marten Seemann
2017-12-08 12:34:59 +07:00
parent 6019634286
commit 23ce5a8554
7 changed files with 25 additions and 27 deletions

View File

@@ -458,7 +458,7 @@ func (h *cryptoSetupClient) addPadding(tags map[Tag][]byte) {
for _, tag := range tags {
size += 8 + len(tag) // 4 bytes for the tag + 4 bytes for the offset + the length of the data
}
paddingSize := protocol.ClientHelloMinimumSize - size
paddingSize := protocol.MinClientHelloSize - size
if paddingSize > 0 {
tags[TagPAD] = bytes.Repeat([]byte{0}, paddingSize)
}

View File

@@ -465,14 +465,14 @@ var _ = Describe("Client Crypto Setup", func() {
It("is longer than the miminum client hello size", func() {
err := cs.sendCHLO()
Expect(err).ToNot(HaveOccurred())
Expect(cs.cryptoStream.(*mockStream).dataWritten.Len()).To(BeNumerically(">", protocol.ClientHelloMinimumSize))
Expect(cs.cryptoStream.(*mockStream).dataWritten.Len()).To(BeNumerically(">", protocol.MinClientHelloSize))
})
It("doesn't overflow the packet with padding", func() {
tagMap := make(map[Tag][]byte)
tagMap[TagSCID] = bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize*6/10)
tagMap[TagSCID] = bytes.Repeat([]byte{0}, protocol.MinClientHelloSize*6/10)
cs.addPadding(tagMap)
Expect(len(tagMap[TagPAD])).To(BeNumerically("<", protocol.ClientHelloMinimumSize/2))
Expect(len(tagMap[TagPAD])).To(BeNumerically("<", protocol.MinClientHelloSize/2))
})
It("saves the last sent CHLO", func() {

View File

@@ -301,10 +301,6 @@ func (h *cryptoSetupServer) acceptSTK(token []byte) bool {
}
func (h *cryptoSetupServer) handleInchoateCHLO(sni string, chlo []byte, cryptoData map[Tag][]byte) ([]byte, error) {
if len(chlo) < protocol.ClientHelloMinimumSize {
return nil, qerr.Error(qerr.CryptoInvalidValueLength, "CHLO too small")
}
token, err := h.scfg.cookieGenerator.NewToken(h.remoteAddr)
if err != nil {
return nil, err

View File

@@ -251,7 +251,7 @@ var _ = Describe("Server Crypto Setup", func() {
It("reads the transport parameters sent by the client", func() {
sourceAddrValid = true
fullCHLO[TagICSL] = []byte{0x37, 0x13, 0, 0}
_, err := cs.handleMessage(bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize), fullCHLO)
_, err := cs.handleMessage(bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), fullCHLO)
Expect(err).ToNot(HaveOccurred())
var params TransportParameters
Expect(paramsChan).To(Receive(&params))
@@ -260,7 +260,7 @@ var _ = Describe("Server Crypto Setup", func() {
It("generates REJ messages", func() {
sourceAddrValid = false
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize), nil)
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), nil)
Expect(err).ToNot(HaveOccurred())
Expect(response).To(HavePrefix("REJ"))
Expect(response).To(ContainSubstring("initial public"))
@@ -271,7 +271,7 @@ var _ = Describe("Server Crypto Setup", func() {
It("REJ messages don't include cert or proof without STK", func() {
sourceAddrValid = false
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize), nil)
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), nil)
Expect(err).ToNot(HaveOccurred())
Expect(response).To(HavePrefix("REJ"))
Expect(response).ToNot(ContainSubstring("certcompressed"))
@@ -281,7 +281,7 @@ var _ = Describe("Server Crypto Setup", func() {
It("REJ messages include cert and proof with valid STK", func() {
sourceAddrValid = true
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize), map[Tag][]byte{
response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize), map[Tag][]byte{
TagSTK: validSTK,
TagSNI: []byte("foo"),
})
@@ -337,7 +337,7 @@ var _ = Describe("Server Crypto Setup", func() {
Data: map[Tag][]byte{
TagSNI: []byte("quic.clemente.io"),
TagSTK: validSTK,
TagPAD: bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize),
TagPAD: bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize),
TagVER: versionTag,
},
}.Write(&stream.dataToRead)
@@ -419,11 +419,6 @@ var _ = Describe("Server Crypto Setup", func() {
Expect(cs.isInchoateCHLO(fullCHLO, cert)).To(BeFalse())
})
It("errors on too short inchoate CHLOs", func() {
_, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize-1), nil)
Expect(err).To(MatchError("CryptoInvalidValueLength: CHLO too small"))
})
It("rejects CHLOs without the version tag", func() {
HandshakeMessage{
Tag: TagCHLO,
@@ -719,7 +714,7 @@ var _ = Describe("Server Crypto Setup", func() {
It("requires STK", func() {
sourceAddrValid = false
done, err := cs.handleMessage(
bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize),
bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize),
map[Tag][]byte{
TagSNI: []byte("foo"),
TagVER: versionTag,
@@ -733,7 +728,7 @@ var _ = Describe("Server Crypto Setup", func() {
It("works with proper STK", func() {
sourceAddrValid = true
done, err := cs.handleMessage(
bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize),
bytes.Repeat([]byte{'a'}, protocol.MinClientHelloSize),
map[Tag][]byte{
TagSNI: []byte("foo"),
TagVER: versionTag,

View File

@@ -74,8 +74,8 @@ const MaxReceivePacketSize ByteCount = 1452
// Used in QUIC for congestion window computations in bytes.
const DefaultTCPMSS ByteCount = 1460
// ClientHelloMinimumSize is the minimum size the server expects an inchoate CHLO to have.
const ClientHelloMinimumSize = 1024
// MinClientHelloSize is the minimum size the server expects an inchoate CHLO to have (in gQUIC)
const MinClientHelloSize = 1024
// MinInitialPacketSize is the minimum size an Initial packet (in IETF QUIC) is requried to have.
const MinInitialPacketSize = 1200

View File

@@ -328,7 +328,7 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
// since the client send a Public Header (only gQUIC has a Version Flag), we need to send a gQUIC Version Negotiation Packet
if hdr.VersionFlag && !protocol.IsSupportedVersion(s.config.Versions, hdr.Version) {
// drop packets that are too small to be valid first packets
if len(packet) < protocol.ClientHelloMinimumSize+len(hdr.Raw) {
if len(packet) < protocol.MinClientHelloSize+len(hdr.Raw) {
return errors.New("dropping small packet with unknown version")
}
utils.Infof("Client offered version %s, sending VersionNegotiationPacket", hdr.Version)
@@ -337,6 +337,12 @@ func (s *server) handlePacket(pconn net.PacketConn, remoteAddr net.Addr, packet
}
}
// This is (potentially) a Client Hello.
// Make sure it has the minimum required size before spending any more ressources on it.
if !sessionKnown && len(packet) < protocol.MinClientHelloSize+len(hdr.Raw) {
return errors.New("dropping small packet for unknown connection")
}
if !sessionKnown {
version := hdr.Version
if !protocol.IsSupportedVersion(s.config.Versions, version) {

View File

@@ -123,6 +123,7 @@ var _ = Describe("Server", func() {
utils.BigEndian.WriteUint32(b, uint32(protocol.SupportedVersions[0]))
firstPacket = []byte{0x09, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}
firstPacket = append(append(firstPacket, b.Bytes()...), 0x01)
firstPacket = append(firstPacket, bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)...) // add padding
})
It("returns the address", func() {
@@ -340,7 +341,7 @@ var _ = Describe("Server", func() {
PacketNumberLen: protocol.PacketNumberLen2,
}
hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */)
b.Write(bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize-1)) // this packet is 1 byte too small
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize-1)) // this packet is 1 byte too small
err := serv.handlePacket(conn, udpAddr, b.Bytes())
Expect(err).To(MatchError("dropping small packet with unknown version"))
Expect(conn.dataWritten.Len()).Should(BeZero())
@@ -411,7 +412,7 @@ var _ = Describe("Server", func() {
PacketNumberLen: protocol.PacketNumberLen2,
}
hdr.Write(b, protocol.PerspectiveClient, 13 /* not a valid QUIC version */)
b.Write(bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize)) // add a fake CHLO
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)) // add a fake CHLO
conn.dataToRead <- b.Bytes()
conn.dataReadFrom = udpAddr
ln, err := Listen(conn, nil, config)
@@ -446,7 +447,7 @@ var _ = Describe("Server", func() {
}
err := hdr.Write(b, protocol.PerspectiveClient, protocol.VersionTLS)
Expect(err).ToNot(HaveOccurred())
b.Write(bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize)) // add a fake CHLO
b.Write(bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize)) // add a fake CHLO
conn.dataToRead <- b.Bytes()
conn.dataReadFrom = udpAddr
ln, err := Listen(conn, testdata.GetTLSConfig(), config)
@@ -484,7 +485,7 @@ var _ = Describe("Server", func() {
}
err := hdr.Write(b, protocol.PerspectiveClient, protocol.VersionTLS)
Expect(err).ToNot(HaveOccurred())
b.Write(bytes.Repeat([]byte{0}, protocol.ClientHelloMinimumSize)) // add a fake CHLO
b.Write(bytes.Repeat([]byte{0}, protocol.MinClientHelloSize)) // add a fake CHLO
conn.dataToRead <- b.Bytes()
conn.dataReadFrom = udpAddr
ln, err := Listen(conn, testdata.GetTLSConfig(), config)