diff --git a/handshake/crypto_setup_server.go b/handshake/crypto_setup_server.go index f639f5144..35dd6f05d 100644 --- a/handshake/crypto_setup_server.go +++ b/handshake/crypto_setup_server.go @@ -54,11 +54,15 @@ type cryptoSetupServer struct { var _ CryptoSetup = &cryptoSetupServer{} -// ErrHOLExperiment is returned when the client sends the FHL2 tag in the CHLO -// this is an expiremnt implemented by Chrome in QUIC 36, which we don't support +// ErrHOLExperiment is returned when the client sends the FHL2 tag in the CHLO. +// This is an experiment implemented by Chrome in QUIC 36, which we don't support. // TODO: remove this when dropping support for QUIC 36 var ErrHOLExperiment = qerr.Error(qerr.InvalidCryptoMessageParameter, "HOL experiment. Unsupported") +// ErrNSTPExperiment is returned when the client sends the NSTP tag in the CHLO. +// This is an experiment implemented by Chrome in QUIC 38, which we don't support at this point. +var ErrNSTPExperiment = qerr.Error(qerr.InvalidCryptoMessageParameter, "NSTP experiment. Unsupported") + // NewCryptoSetup creates a new CryptoSetup instance for a server func NewCryptoSetup( connID protocol.ConnectionID, @@ -120,6 +124,9 @@ func (h *cryptoSetupServer) handleMessage(chloData []byte, cryptoData map[Tag][] if _, isHOLExperiment := cryptoData[TagFHL2]; isHOLExperiment { return false, ErrHOLExperiment } + if _, isNSTPExperiment := cryptoData[TagNSTP]; isNSTPExperiment { + return false, ErrNSTPExperiment + } sniSlice, ok := cryptoData[TagSNI] if !ok { diff --git a/handshake/crypto_setup_server_test.go b/handshake/crypto_setup_server_test.go index b26b83958..d6662ba1d 100644 --- a/handshake/crypto_setup_server_test.go +++ b/handshake/crypto_setup_server_test.go @@ -264,6 +264,17 @@ var _ = Describe("Server Crypto Setup", func() { Expect(err).To(MatchError(ErrHOLExperiment)) }) + It("doesn't support Chrome's no STOP_WAITING experiment", func() { + HandshakeMessage{ + Tag: TagCHLO, + Data: map[Tag][]byte{ + TagNSTP: []byte("foobar"), + }, + }.Write(&stream.dataToRead) + err := cs.HandleCryptoStream() + Expect(err).To(MatchError(ErrNSTPExperiment)) + }) + It("generates REJ messages", func() { sourceAddrValid = false response, err := cs.handleInchoateCHLO("", bytes.Repeat([]byte{'a'}, protocol.ClientHelloMinimumSize), nil) diff --git a/handshake/tags.go b/handshake/tags.go index 2b3783f64..19ec78d3c 100644 --- a/handshake/tags.go +++ b/handshake/tags.go @@ -54,6 +54,9 @@ const ( // Chrome experiment (see https://codereview.chromium.org/2115033002) // unsupported by quic-go TagFHL2 Tag = 'F' + 'H'<<8 + 'L'<<16 + '2'<<24 + // TagNSTP is the no STOP_WAITING experiment + // currently unsupported by quic-go + TagNSTP Tag = 'N' + 'S'<<8 + 'T'<<16 + 'P'<<24 // TagSTK is the source-address token TagSTK Tag = 'S' + 'T'<<8 + 'K'<<16 diff --git a/session.go b/session.go index be40504d0..88d8ba565 100644 --- a/session.go +++ b/session.go @@ -578,7 +578,9 @@ func (s *session) handleCloseError(closeErr closeError) error { return nil } - if quicErr.ErrorCode == qerr.DecryptionFailure || quicErr == handshake.ErrHOLExperiment { + if quicErr.ErrorCode == qerr.DecryptionFailure || + quicErr == handshake.ErrHOLExperiment || + quicErr == handshake.ErrNSTPExperiment { return s.sendPublicReset(s.lastRcvdPacketNumber) } return s.sendConnectionClose(quicErr) diff --git a/session_test.go b/session_test.go index 74adaa192..edde1aec5 100644 --- a/session_test.go +++ b/session_test.go @@ -804,6 +804,13 @@ var _ = Describe("Session", func() { Expect(sess.Context().Done()).To(BeClosed()) }) + It("sends a Public Reset if the client is initiating the no STOP_WAITING experiment", func() { + sess.Close(handshake.ErrHOLExperiment) + Expect(mconn.written).To(HaveLen(1)) + Expect(mconn.written[0][0] & 0x02).ToNot(BeZero()) // Public Reset + Expect(sess.Context().Done()).To(BeClosed()) + }) + It("cancels the context when the run loop exists", func() { returned := make(chan struct{}) go func() {