From 59e9142426bbcbb5f5096d4bed90d3563416bc40 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 1 Mar 2019 10:47:52 +0900 Subject: [PATCH] retrieve the TLS alert from qtls when the handshake fails --- go.mod | 4 +-- go.sum | 13 ++++---- internal/handshake/crypto_setup.go | 42 ++++++++++++------------- internal/handshake/crypto_setup_test.go | 11 +++++-- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index ec55c73c..c550b428 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.12 require ( github.com/cheekybits/genny v1.0.0 github.com/golang/mock v1.2.0 - github.com/marten-seemann/qtls v0.1.0 + github.com/marten-seemann/qtls v0.2.0 github.com/onsi/ginkgo v1.7.0 github.com/onsi/gomega v1.4.3 - golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b + golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd ) diff --git a/go.sum b/go.sum index e5bcc9e6..d979e29e 100644 --- a/go.sum +++ b/go.sum @@ -8,22 +8,23 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/marten-seemann/qtls v0.1.0 h1:rU4tM4KsiR4uEL15U7roq5B6IzFJyQdP6po0tCN08mE= -github.com/marten-seemann/qtls v0.1.0/go.mod h1:F6kuCIZ1zxAmETSSJGN/5VENU7NZBXg9zqnA6dYZrgA= +github.com/marten-seemann/qtls v0.2.0 h1:SnGwbmSUjODZ3PPCG6N0GX0w30yvndyFmoNY2pbgW+s= +github.com/marten-seemann/qtls v0.2.0/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b h1:+/WWzjwW6gidDJnMKWLKLX1gxn7irUTF1fLpQovfQ5M= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25 h1:jsG6UpNLt9iAsb0S2AGW28DveNzzgmbXR+ENoPjUeIU= +golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9 h1:N26gncmS+iqc/W/SKhX3ElI5pkt72XYoRLgi5Z70LSc= -golang.org/x/sys v0.0.0-20190226215855-775f8194d0f9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/handshake/crypto_setup.go b/internal/handshake/crypto_setup.go index e30e4240..6bcf6ef7 100644 --- a/internal/handshake/crypto_setup.go +++ b/internal/handshake/crypto_setup.go @@ -64,11 +64,7 @@ type cryptoSetup struct { handleParamsCallback func([]byte) - // There are two ways that an error can occur during the handshake: - // 1. as a return value from qtls.Handshake() - // 2. when new data is passed to the crypto setup via HandleData() - // handshakeErrChan is closed when qtls.Handshake() errors - handshakeErrChan chan struct{} + alertChan chan error // HandleData() sends errors on the messageErrChan messageErrChan chan error // handshakeDone is closed as soon as the go routine running qtls.Handshake() returns @@ -190,7 +186,7 @@ func newCryptoSetup( logger: logger, perspective: perspective, handshakeDone: make(chan struct{}), - handshakeErrChan: make(chan struct{}), + alertChan: make(chan error), messageErrChan: make(chan error, 1), clientHelloWrittenChan: make(chan struct{}), messageChan: make(chan []byte, 100), @@ -215,12 +211,11 @@ func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) error { func (h *cryptoSetup) RunHandshake() error { // Handle errors that might occur when HandleData() is called. - handshakeErrChan := make(chan error, 1) handshakeComplete := make(chan struct{}) go func() { defer close(h.handshakeDone) if err := h.conn.Handshake(); err != nil { - handshakeErrChan <- err + h.logger.Debugf("qlts.Handshake error: %s", err) return } close(handshakeComplete) @@ -230,13 +225,11 @@ func (h *cryptoSetup) RunHandshake() error { case <-h.closeChan: close(h.messageChan) // wait until the Handshake() go routine has returned - <-handshakeErrChan return errors.New("Handshake aborted") case <-handshakeComplete: // return when the handshake is done return nil - case err := <-handshakeErrChan: - // if handleMessageFor{server,client} are waiting for some qtls action, make them return - close(h.handshakeErrChan) + case err := <-h.alertChan: + <-h.handshakeDone return err case err := <-h.messageErrChan: // If the handshake errored because of an error that occurred during HandleData(), @@ -304,25 +297,25 @@ func (h *cryptoSetup) handleMessageForServer(msgType messageType) bool { select { case data := <-h.extHandler.TransportParameters(): h.handleParamsCallback(data) - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } // get the handshake read key select { case <-h.receivedReadKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } // get the handshake write key select { case <-h.receivedWriteKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } // get the 1-RTT write key select { case <-h.receivedWriteKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } return true @@ -333,7 +326,7 @@ func (h *cryptoSetup) handleMessageForServer(msgType messageType) bool { // get the 1-RTT read key select { case <-h.receivedReadKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } return true @@ -348,13 +341,13 @@ func (h *cryptoSetup) handleMessageForClient(msgType messageType) bool { // get the handshake write key select { case <-h.receivedWriteKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } // get the handshake read key select { case <-h.receivedReadKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } return true @@ -362,7 +355,7 @@ func (h *cryptoSetup) handleMessageForClient(msgType messageType) bool { select { case data := <-h.extHandler.TransportParameters(): h.handleParamsCallback(data) - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } return false @@ -373,13 +366,13 @@ func (h *cryptoSetup) handleMessageForClient(msgType messageType) bool { // get the 1-RTT read key select { case <-h.receivedReadKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } // get the handshake write key select { case <-h.receivedWriteKey: - case <-h.handshakeErrChan: + case <-h.handshakeDone: return false } return true @@ -467,6 +460,11 @@ func (h *cryptoSetup) WriteRecord(p []byte) (int, error) { } } +func (h *cryptoSetup) SendAlert(alert uint8) { + // TODO(#1567): send the correct IETF QUIC error code + h.alertChan <- fmt.Errorf("TLS alert: %d", alert) +} + func (h *cryptoSetup) GetSealer() (protocol.EncryptionLevel, Sealer) { if h.sealer != nil { return protocol.Encryption1RTT, h.sealer diff --git a/internal/handshake/crypto_setup_test.go b/internal/handshake/crypto_setup_test.go index 7d09b22b..c2390fd6 100644 --- a/internal/handshake/crypto_setup_test.go +++ b/internal/handshake/crypto_setup_test.go @@ -128,13 +128,18 @@ var _ = Describe("Crypto Setup TLS", func() { go func() { defer GinkgoRecover() err := server.RunHandshake() - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("received unexpected handshake message")) + Expect(err).To(MatchError("TLS alert: 10")) close(done) }() fakeCH := append([]byte{byte(typeClientHello), 0, 0, 6}, []byte("foobar")...) - server.HandleMessage(fakeCH, protocol.EncryptionInitial) + handledMessage := make(chan struct{}) + go func() { + defer GinkgoRecover() + server.HandleMessage(fakeCH, protocol.EncryptionInitial) + close(handledMessage) + }() + Eventually(handledMessage).Should(BeClosed()) Eventually(done).Should(BeClosed()) })