Skip to content

Commit

Permalink
use tls-tris instead of mint
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Oct 26, 2018
1 parent 5102294 commit 82508f1
Show file tree
Hide file tree
Showing 144 changed files with 20,077 additions and 10,110 deletions.
59 changes: 21 additions & 38 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"net"
"sync"

"github.com/bifurcation/mint"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
Expand All @@ -33,9 +32,8 @@ type client struct {
receivedVersionNegotiationPacket bool
negotiatedVersions []protocol.VersionNumber // the list of versions from the version negotiation packet

tlsConf *tls.Config
mintConf *mint.Config
config *Config
tlsConf *tls.Config
config *Config

srcConnID protocol.ConnectionID
destConnID protocol.ConnectionID
Expand Down Expand Up @@ -304,27 +302,10 @@ func (c *client) dialGQUIC(ctx context.Context) error {
}

func (c *client) dialTLS(ctx context.Context) error {
params := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: c.config.IdleTimeout,
OmitConnectionID: c.config.RequestConnectionIDOmission,
MaxBidiStreams: uint16(c.config.MaxIncomingStreams),
MaxUniStreams: uint16(c.config.MaxIncomingUniStreams),
DisableMigration: true,
}
extHandler := handshake.NewExtensionHandlerClient(params, c.initialVersion, c.config.Versions, c.version, c.logger)
mintConf, err := tlsToMintConfig(c.tlsConf, protocol.PerspectiveClient)
if err != nil {
if err := c.createNewTLSSession(c.version); err != nil {
return err
}
mintConf.ExtensionHandler = extHandler
c.mintConf = mintConf

if err := c.createNewTLSSession(extHandler.GetPeerParams(), c.version); err != nil {
return err
}
err = c.establishSecureConnection(ctx)
err := c.establishSecureConnection(ctx)
if err == errCloseSessionForRetry || err == errCloseSessionForNewVersion {
return c.dial(ctx)
}
Expand Down Expand Up @@ -401,15 +382,9 @@ func (c *client) handlePacketImpl(p *receivedPacket) error {
}
}

if p.header.IsLongHeader {
switch p.header.Type {
case protocol.PacketTypeRetry:
c.handleRetryPacket(p.header)
return nil
case protocol.PacketTypeHandshake, protocol.PacketType0RTT:
default:
return fmt.Errorf("Received unsupported packet type: %s", p.header.Type)
}
if p.header.Type == protocol.PacketTypeRetry {
c.handleRetryPacket(p.header)
return nil
}

// this is the first packet we are receiving
Expand Down Expand Up @@ -526,10 +501,17 @@ func (c *client) createNewGQUICSession() error {
return nil
}

func (c *client) createNewTLSSession(
paramsChan <-chan handshake.TransportParameters,
version protocol.VersionNumber,
) error {
func (c *client) createNewTLSSession(version protocol.VersionNumber) error {
params := &handshake.TransportParameters{
StreamFlowControlWindow: protocol.ReceiveStreamFlowControlWindow,
ConnectionFlowControlWindow: protocol.ReceiveConnectionFlowControlWindow,
IdleTimeout: c.config.IdleTimeout,
OmitConnectionID: c.config.RequestConnectionIDOmission,
MaxBidiStreams: uint16(c.config.MaxIncomingStreams),
MaxUniStreams: uint16(c.config.MaxIncomingUniStreams),
DisableMigration: true,
}

c.mutex.Lock()
defer c.mutex.Unlock()
runner := &runner{
Expand All @@ -543,8 +525,9 @@ func (c *client) createNewTLSSession(
c.destConnID,
c.srcConnID,
c.config,
c.mintConf,
paramsChan,
c.tlsConf,
params,
c.initialVersion,
1,
c.logger,
c.version,
Expand Down
35 changes: 9 additions & 26 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"os"
"time"

"github.com/bifurcation/mint"
"github.com/golang/mock/gomock"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
Expand Down Expand Up @@ -524,8 +523,9 @@ var _ = Describe("Client", func() {
_ protocol.ConnectionID,
_ protocol.ConnectionID,
configP *Config,
_ *mint.Config,
paramsChan <-chan handshake.TransportParameters,
_ *tls.Config,
params *handshake.TransportParameters,
_ protocol.VersionNumber, /* initial version */
_ protocol.PacketNumber,
_ utils.Logger,
versionP protocol.VersionNumber,
Expand Down Expand Up @@ -585,8 +585,9 @@ var _ = Describe("Client", func() {
_ protocol.ConnectionID,
_ protocol.ConnectionID,
_ *Config,
_ *mint.Config,
_ <-chan handshake.TransportParameters,
_ *tls.Config,
_ *handshake.TransportParameters,
_ protocol.VersionNumber, /* initial version */
_ protocol.PacketNumber,
_ utils.Logger,
_ protocol.VersionNumber,
Expand Down Expand Up @@ -644,8 +645,9 @@ var _ = Describe("Client", func() {
_ protocol.ConnectionID,
_ protocol.ConnectionID,
_ *Config,
_ *mint.Config,
_ <-chan handshake.TransportParameters,
_ *tls.Config,
_ *handshake.TransportParameters,
_ protocol.VersionNumber, /* initial version */
_ protocol.PacketNumber,
_ utils.Logger,
_ protocol.VersionNumber,
Expand Down Expand Up @@ -861,25 +863,6 @@ var _ = Describe("Client", func() {
Expect(cl.GetVersion()).To(Equal(cl.version))
})

It("ignores packets with the wrong Long Header Type", func() {
cl.config = &Config{}
hdr := &wire.Header{
IsLongHeader: true,
Type: protocol.PacketTypeInitial,
PayloadLen: 123,
SrcConnectionID: connID,
DestConnectionID: connID,
PacketNumberLen: protocol.PacketNumberLen1,
Version: versionIETFFrames,
}
err := cl.handlePacketImpl(&receivedPacket{
remoteAddr: addr,
header: hdr,
data: make([]byte, 456),
})
Expect(err).To(MatchError("Received unsupported packet type: Initial"))
})

It("ignores packets without connection id, if it didn't request connection id trunctation", func() {
cl.version = versionGQUICFrames
cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls
Expand Down
67 changes: 45 additions & 22 deletions crypto_stream.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,65 @@
package quic

import (
"fmt"
"io"

"github.com/lucas-clemente/quic-go/internal/flowcontrol"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
)

type cryptoStream interface {
StreamID() protocol.StreamID
io.Reader
// for receiving data
HandleCryptoFrame(*wire.CryptoFrame) error
GetCryptoData() []byte
// for sending data
io.Writer
handleStreamFrame(*wire.StreamFrame) error
hasData() bool
popStreamFrame(protocol.ByteCount) (*wire.StreamFrame, bool)
closeForShutdown(error)
setReadOffset(protocol.ByteCount)
// methods needed for flow control
getWindowUpdate() protocol.ByteCount
handleMaxStreamDataFrame(*wire.MaxStreamDataFrame)
HasData() bool
PopCryptoFrame(protocol.ByteCount) *wire.CryptoFrame
}

type cryptoStreamImpl struct {
*stream
queue *frameSorter

writeOffset protocol.ByteCount
writeBuf []byte
}

func newCryptoStream() cryptoStream {
return &cryptoStreamImpl{
queue: newFrameSorter(),
}
}

func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
if maxOffset := f.Offset + protocol.ByteCount(len(f.Data)); maxOffset > protocol.MaxCryptoStreamOffset {
return fmt.Errorf("received invalid offset %d on crypto stream, maximum allowed %d", maxOffset, protocol.MaxCryptoStreamOffset)
}
return s.queue.Push(f.Data, f.Offset, false)
}

// GetCryptoData retrieves data that was received in CRYPTO frames
func (s *cryptoStreamImpl) GetCryptoData() []byte {
data, _ := s.queue.Pop()
return data
}

var _ cryptoStream = &cryptoStreamImpl{}
// Writes writes data that should be sent out in CRYPTO frames
func (s *cryptoStreamImpl) Write(p []byte) (int, error) {
s.writeBuf = append(s.writeBuf, p...)
return len(p), nil
}

func newCryptoStream(sender streamSender, flowController flowcontrol.StreamFlowController, version protocol.VersionNumber) cryptoStream {
str := newStream(version.CryptoStreamID(), sender, flowController, version)
return &cryptoStreamImpl{str}
func (s *cryptoStreamImpl) HasData() bool {
return len(s.writeBuf) > 0
}

// SetReadOffset sets the read offset.
// It is only needed for the crypto stream.
// It must not be called concurrently with any other stream methods, especially Read and Write.
func (s *cryptoStreamImpl) setReadOffset(offset protocol.ByteCount) {
s.receiveStream.readOffset = offset
s.receiveStream.frameQueue.readPos = offset
func (s *cryptoStreamImpl) PopCryptoFrame(maxLen protocol.ByteCount) *wire.CryptoFrame {
f := &wire.CryptoFrame{Offset: s.writeOffset}
n := utils.MinByteCount(f.MaxDataLen(maxLen), protocol.ByteCount(len(s.writeBuf)))
f.Data = s.writeBuf[:n]
s.writeBuf = s.writeBuf[n:]
s.writeOffset += n
return f
}
55 changes: 55 additions & 0 deletions crypto_stream_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package quic

import (
"fmt"

"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
)

type cryptoDataHandler interface {
HandleData([]byte, protocol.EncryptionLevel) error
}

type cryptoStreamManager struct {
cryptoHandler cryptoDataHandler

initialStream cryptoStream
handshakeStream cryptoStream
}

func newCryptoStreamManager(
cryptoHandler cryptoDataHandler,
initialStream cryptoStream,
handshakeStream cryptoStream,
) *cryptoStreamManager {
return &cryptoStreamManager{
cryptoHandler: cryptoHandler,
initialStream: initialStream,
handshakeStream: handshakeStream,
}
}

func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) error {
var str cryptoStream
switch encLevel {
case protocol.EncryptionInitial:
str = m.initialStream
case protocol.EncryptionHandshake:
str = m.handshakeStream
default:
return fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
}
if err := str.HandleCryptoFrame(frame); err != nil {
return err
}
for {
data := str.GetCryptoData()
if data == nil {
return nil
}
if err := m.cryptoHandler.HandleData(data, encLevel); err != nil {
return err
}
}
}
65 changes: 65 additions & 0 deletions crypto_stream_manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package quic

import (
"errors"

"github.com/golang/mock/gomock"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Crypto Stream Manager", func() {
var (
csm *cryptoStreamManager
cs *MockCryptoDataHandler
)

BeforeEach(func() {
initialStream := newCryptoStream()
handshakeStream := newCryptoStream()
cs = NewMockCryptoDataHandler(mockCtrl)
csm = newCryptoStreamManager(cs, initialStream, handshakeStream)
})

It("handles in in-order crypto frame", func() {
f := &wire.CryptoFrame{Data: []byte("foobar")}
cs.EXPECT().HandleData([]byte("foobar"), protocol.EncryptionInitial)
Expect(csm.HandleCryptoFrame(f, protocol.EncryptionInitial)).To(Succeed())
})

It("errors for unknown encryption levels", func() {
err := csm.HandleCryptoFrame(&wire.CryptoFrame{}, protocol.Encryption1RTT)
Expect(err).To(MatchError("received CRYPTO frame with unexpected encryption level: 1-RTT"))
})

It("handles out-of-order crypto frames", func() {
f1 := &wire.CryptoFrame{Data: []byte("foo")}
f2 := &wire.CryptoFrame{
Offset: 3,
Data: []byte("bar"),
}
gomock.InOrder(
cs.EXPECT().HandleData([]byte("foo"), protocol.EncryptionInitial),
cs.EXPECT().HandleData([]byte("bar"), protocol.EncryptionInitial),
)
Expect(csm.HandleCryptoFrame(f1, protocol.EncryptionInitial)).To(Succeed())
Expect(csm.HandleCryptoFrame(f2, protocol.EncryptionInitial)).To(Succeed())
})

It("handles handshake data", func() {
f := &wire.CryptoFrame{Data: []byte("foobar")}
cs.EXPECT().HandleData([]byte("foobar"), protocol.EncryptionHandshake)
Expect(csm.HandleCryptoFrame(f, protocol.EncryptionHandshake)).To(Succeed())
})

It("returns the error if handling crypto data fails", func() {
testErr := errors.New("test error")
f := &wire.CryptoFrame{Data: []byte("foobar")}
cs.EXPECT().HandleData([]byte("foobar"), protocol.EncryptionHandshake).Return(testErr)
err := csm.HandleCryptoFrame(f, protocol.EncryptionHandshake)
Expect(err).To(MatchError(testErr))
})
})
Loading

0 comments on commit 82508f1

Please sign in to comment.