don't use trial decryption for IETF QUIC

This commit is contained in:
Marten Seemann 2018-03-26 13:17:39 +02:00
parent a298bd01c9
commit 302d2a1715
14 changed files with 333 additions and 130 deletions

View file

@ -31,6 +31,8 @@ type cryptoSetupTLS struct {
handshakeEvent chan<- struct{}
}
var _ CryptoSetupTLS = &cryptoSetupTLS{}
// NewCryptoSetupTLSServer creates a new TLS CryptoSetup instance for a server
func NewCryptoSetupTLSServer(
tls MintTLS,
@ -38,7 +40,7 @@ func NewCryptoSetupTLSServer(
nullAEAD crypto.AEAD,
handshakeEvent chan<- struct{},
version protocol.VersionNumber,
) CryptoSetup {
) CryptoSetupTLS {
return &cryptoSetupTLS{
tls: tls,
cryptoStream: cryptoStream,
@ -57,7 +59,7 @@ func NewCryptoSetupTLSClient(
handshakeEvent chan<- struct{},
tls MintTLS,
version protocol.VersionNumber,
) (CryptoSetup, error) {
) (CryptoSetupTLS, error) {
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveClient, connID, version)
if err != nil {
return nil, err
@ -107,22 +109,18 @@ handshakeLoop:
return nil
}
func (h *cryptoSetupTLS) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) {
func (h *cryptoSetupTLS) OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) {
return h.nullAEAD.Open(dst, src, packetNumber, associatedData)
}
func (h *cryptoSetupTLS) Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) {
h.mutex.RLock()
defer h.mutex.RUnlock()
if h.aead != nil {
data, err := h.aead.Open(dst, src, packetNumber, associatedData)
if err != nil {
return nil, protocol.EncryptionUnspecified, err
}
return data, protocol.EncryptionForwardSecure, nil
if h.aead == nil {
return nil, errors.New("no 1-RTT sealer")
}
data, err := h.nullAEAD.Open(dst, src, packetNumber, associatedData)
if err != nil {
return nil, protocol.EncryptionUnspecified, err
}
return data, protocol.EncryptionUnencrypted, nil
return h.aead.Open(dst, src, packetNumber, associatedData)
}
func (h *cryptoSetupTLS) GetSealer() (protocol.EncryptionLevel, Sealer) {

View file

@ -108,12 +108,11 @@ var _ = Describe("TLS Crypto Setup", func() {
Expect(d).To(Equal([]byte("foobar signed")))
})
It("is accepted initially", func() {
It("is used for opening", func() {
cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("foobar enc"), protocol.PacketNumber(10), []byte{}).Return([]byte("foobar"), nil)
d, enc, err := cs.Open(nil, []byte("foobar enc"), 10, []byte{})
d, err := cs.OpenHandshake(nil, []byte("foobar enc"), 10, []byte{})
Expect(err).ToNot(HaveOccurred())
Expect(d).To(Equal([]byte("foobar")))
Expect(enc).To(Equal(protocol.EncryptionUnencrypted))
})
It("is used for crypto stream", func() {
@ -126,17 +125,8 @@ var _ = Describe("TLS Crypto Setup", func() {
It("errors if the has the wrong hash", func() {
cs.nullAEAD.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("foobar enc"), protocol.PacketNumber(10), []byte{}).Return(nil, errors.New("authentication failed"))
_, enc, err := cs.Open(nil, []byte("foobar enc"), 10, []byte{})
_, err := cs.OpenHandshake(nil, []byte("foobar enc"), 10, []byte{})
Expect(err).To(MatchError("authentication failed"))
Expect(enc).To(Equal(protocol.EncryptionUnspecified))
})
It("is not accepted after the handshake completes", func() {
doHandshake()
cs.aead.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("foobar encrypted"), protocol.PacketNumber(1), []byte{}).Return(nil, errors.New("authentication failed"))
_, enc, err := cs.Open(nil, []byte("foobar encrypted"), 1, []byte{})
Expect(err).To(MatchError("authentication failed"))
Expect(enc).To(Equal(protocol.EncryptionUnspecified))
})
})
@ -150,12 +140,11 @@ var _ = Describe("TLS Crypto Setup", func() {
Expect(d).To(Equal([]byte("foobar forward sec")))
})
It("is used for opening after the handshake completes", func() {
It("is used for opening", func() {
doHandshake()
cs.aead.(*mockcrypto.MockAEAD).EXPECT().Open(nil, []byte("encrypted"), protocol.PacketNumber(6), []byte{}).Return([]byte("decrypted"), nil)
d, enc, err := cs.Open(nil, []byte("encrypted"), 6, []byte{})
d, err := cs.Open1RTT(nil, []byte("encrypted"), 6, []byte{})
Expect(err).ToNot(HaveOccurred())
Expect(enc).To(Equal(protocol.EncryptionForwardSecure))
Expect(d).To(Equal([]byte("decrypted")))
})
})

View file

@ -35,9 +35,7 @@ type MintTLS interface {
SetCryptoStream(io.ReadWriter)
}
// CryptoSetup is a crypto setup
type CryptoSetup interface {
Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error)
type baseCryptoSetup interface {
HandleCryptoStream() error
ConnectionState() ConnectionState
@ -46,6 +44,21 @@ type CryptoSetup interface {
GetSealerForCryptoStream() (protocol.EncryptionLevel, Sealer)
}
// CryptoSetup is the crypto setup used by gQUIC
type CryptoSetup interface {
baseCryptoSetup
Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error)
}
// CryptoSetupTLS is the crypto setup used by IETF QUIC
type CryptoSetupTLS interface {
baseCryptoSetup
OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error)
Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error)
}
// ConnectionState records basic details about the QUIC connection.
// Warning: This API should not be considered stable and might change soon.
type ConnectionState struct {

View file

@ -108,16 +108,23 @@ func tlsToMintConfig(tlsConf *tls.Config, pers protocol.Perspective) (*mint.Conf
// unpackInitialOrRetryPacket unpacks packets Initial and Retry packets
// These packets must contain a STREAM_FRAME for the crypto stream, starting at offset 0.
func unpackInitialPacket(aead crypto.AEAD, hdr *wire.Header, data []byte, version protocol.VersionNumber) (*wire.StreamFrame, error) {
unpacker := &packetUnpacker{aead: &nullAEAD{aead}, version: version}
packet, err := unpacker.Unpack(hdr.Raw, hdr, data)
buf := *getPacketBuffer()
buf = buf[:0]
defer putPacketBuffer(&buf)
decrypted, err := aead.Open(buf, data, hdr.PacketNumber, hdr.Raw)
if err != nil {
return nil, err
}
var frame *wire.StreamFrame
for _, f := range packet.frames {
r := bytes.NewReader(decrypted)
for {
f, err := wire.ParseNextFrame(r, hdr, version)
if err != nil {
return nil, err
}
var ok bool
frame, ok = f.(*wire.StreamFrame)
if ok {
if frame, ok = f.(*wire.StreamFrame); ok || frame == nil {
break
}
}

View file

@ -141,14 +141,6 @@ var _ = Describe("Packing and unpacking Initial packets", func() {
})
Context("packing", func() {
var unpacker *packetUnpacker
BeforeEach(func() {
aeadCl, err := crypto.NewNullAEAD(protocol.PerspectiveClient, connID, ver)
Expect(err).ToNot(HaveOccurred())
unpacker = &packetUnpacker{aead: &nullAEAD{aeadCl}, version: ver}
})
It("packs a packet", func() {
f := &wire.StreamFrame{
Data: []byte("foobar"),
@ -156,9 +148,13 @@ var _ = Describe("Packing and unpacking Initial packets", func() {
}
data, err := packUnencryptedPacket(aead, hdr, f, protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
packet, err := unpacker.Unpack(hdr.Raw, hdr, data[len(hdr.Raw):])
aeadCl, err := crypto.NewNullAEAD(protocol.PerspectiveClient, connID, ver)
Expect(err).ToNot(HaveOccurred())
Expect(packet.frames).To(Equal([]wire.Frame{f}))
decrypted, err := aeadCl.Open(nil, data[len(hdr.Raw):], hdr.PacketNumber, hdr.Raw)
Expect(err).ToNot(HaveOccurred())
frame, err := wire.ParseNextFrame(bytes.NewReader(decrypted), hdr, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(frame).To(Equal(f))
})
})
})

49
mock_gquic_aead_test.go Normal file
View file

@ -0,0 +1,49 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/lucas-clemente/quic-go (interfaces: GQUICAEAD)
// Package quic is a generated GoMock package.
package quic
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
protocol "github.com/lucas-clemente/quic-go/internal/protocol"
)
// MockGQUICAEAD is a mock of GQUICAEAD interface
type MockGQUICAEAD struct {
ctrl *gomock.Controller
recorder *MockGQUICAEADMockRecorder
}
// MockGQUICAEADMockRecorder is the mock recorder for MockGQUICAEAD
type MockGQUICAEADMockRecorder struct {
mock *MockGQUICAEAD
}
// NewMockGQUICAEAD creates a new mock instance
func NewMockGQUICAEAD(ctrl *gomock.Controller) *MockGQUICAEAD {
mock := &MockGQUICAEAD{ctrl: ctrl}
mock.recorder = &MockGQUICAEADMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockGQUICAEAD) EXPECT() *MockGQUICAEADMockRecorder {
return m.recorder
}
// Open mocks base method
func (m *MockGQUICAEAD) Open(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, protocol.EncryptionLevel, error) {
ret := m.ctrl.Call(m, "Open", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(protocol.EncryptionLevel)
ret2, _ := ret[2].(error)
return ret0, ret1, ret2
}
// Open indicates an expected call of Open
func (mr *MockGQUICAEADMockRecorder) Open(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockGQUICAEAD)(nil).Open), arg0, arg1, arg2, arg3)
}

61
mock_quic_aead_test.go Normal file
View file

@ -0,0 +1,61 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/lucas-clemente/quic-go (interfaces: QuicAEAD)
// Package quic is a generated GoMock package.
package quic
import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
protocol "github.com/lucas-clemente/quic-go/internal/protocol"
)
// MockQuicAEAD is a mock of QuicAEAD interface
type MockQuicAEAD struct {
ctrl *gomock.Controller
recorder *MockQuicAEADMockRecorder
}
// MockQuicAEADMockRecorder is the mock recorder for MockQuicAEAD
type MockQuicAEADMockRecorder struct {
mock *MockQuicAEAD
}
// NewMockQuicAEAD creates a new mock instance
func NewMockQuicAEAD(ctrl *gomock.Controller) *MockQuicAEAD {
mock := &MockQuicAEAD{ctrl: ctrl}
mock.recorder = &MockQuicAEADMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockQuicAEAD) EXPECT() *MockQuicAEADMockRecorder {
return m.recorder
}
// Open1RTT mocks base method
func (m *MockQuicAEAD) Open1RTT(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, error) {
ret := m.ctrl.Call(m, "Open1RTT", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Open1RTT indicates an expected call of Open1RTT
func (mr *MockQuicAEADMockRecorder) Open1RTT(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open1RTT", reflect.TypeOf((*MockQuicAEAD)(nil).Open1RTT), arg0, arg1, arg2, arg3)
}
// OpenHandshake mocks base method
func (m *MockQuicAEAD) OpenHandshake(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) ([]byte, error) {
ret := m.ctrl.Call(m, "OpenHandshake", arg0, arg1, arg2, arg3)
ret0, _ := ret[0].([]byte)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// OpenHandshake indicates an expected call of OpenHandshake
func (mr *MockQuicAEADMockRecorder) OpenHandshake(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenHandshake", reflect.TypeOf((*MockQuicAEAD)(nil).OpenHandshake), arg0, arg1, arg2, arg3)
}

View file

@ -11,4 +11,6 @@ package quic
//go:generate sh -c "sed -i '' 's/quic_go.//g' mock_stream_getter_test.go mock_stream_manager_test.go"
//go:generate sh -c "./mockgen_private.sh quic mock_unpacker_test.go github.com/lucas-clemente/quic-go unpacker Unpacker"
//go:generate sh -c "sed -i '' 's/quic_go.//g' mock_unpacker_test.go mock_unpacker_test.go"
//go:generate sh -c "./mockgen_private.sh quic mock_quic_aead_test.go github.com/lucas-clemente/quic-go quicAEAD QuicAEAD"
//go:generate sh -c "./mockgen_private.sh quic mock_gquic_aead_test.go github.com/lucas-clemente/quic-go gQUICAEAD GQUICAEAD"
//go:generate sh -c "goimports -w mock*_test.go"

View file

@ -33,6 +33,12 @@ func (p *packedPacket) ToAckHandlerPacket() *ackhandler.Packet {
}
}
type sealingManager interface {
GetSealer() (protocol.EncryptionLevel, handshake.Sealer)
GetSealerForCryptoStream() (protocol.EncryptionLevel, handshake.Sealer)
GetSealerWithEncryptionLevel(protocol.EncryptionLevel) (handshake.Sealer, error)
}
type streamFrameSource interface {
HasCryptoStreamData() bool
PopCryptoStreamFrame(protocol.ByteCount) *wire.StreamFrame
@ -43,8 +49,8 @@ type packetPacker struct {
connectionID protocol.ConnectionID
perspective protocol.Perspective
version protocol.VersionNumber
cryptoSetup handshake.CryptoSetup
divNonce []byte
cryptoSetup sealingManager
packetNumberGenerator *packetNumberGenerator
getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen
@ -66,7 +72,7 @@ func newPacketPacker(connectionID protocol.ConnectionID,
getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen,
remoteAddr net.Addr, // only used for determining the max packet size
divNonce []byte,
cryptoSetup handshake.CryptoSetup,
cryptoSetup sealingManager,
streamFramer streamFrameSource,
perspective protocol.Perspective,
version protocol.VersionNumber,

View file

@ -13,32 +13,26 @@ type unpackedPacket struct {
frames []wire.Frame
}
type quicAEAD interface {
type gQUICAEAD interface {
Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error)
}
type packetUnpacker struct {
version protocol.VersionNumber
aead quicAEAD
type quicAEAD interface {
OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error)
Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error)
}
func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) {
buf := *getPacketBuffer()
buf = buf[:0]
defer putPacketBuffer(&buf)
decrypted, encryptionLevel, err := u.aead.Open(buf, data, hdr.PacketNumber, headerBinary)
if err != nil {
// Wrap err in quicError so that public reset is sent by session
return nil, qerr.Error(qerr.DecryptionFailure, err.Error())
}
r := bytes.NewReader(decrypted)
type packetUnpackerBase struct {
version protocol.VersionNumber
}
func (u *packetUnpackerBase) parseFrames(decrypted []byte, hdr *wire.Header) ([]wire.Frame, error) {
r := bytes.NewReader(decrypted)
if r.Len() == 0 {
return nil, qerr.MissingPayload
}
fs := make([]wire.Frame, 0, 2)
// Read all frames in the packet
for {
frame, err := wire.ParseNextFrame(r, hdr, u.version)
@ -50,6 +44,84 @@ func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []by
}
fs = append(fs, frame)
}
return fs, nil
}
// The packetUnpackerGQUIC unpacks gQUIC packets.
type packetUnpackerGQUIC struct {
packetUnpackerBase
aead gQUICAEAD
}
var _ unpacker = &packetUnpackerGQUIC{}
func newPacketUnpackerGQUIC(aead gQUICAEAD, version protocol.VersionNumber) unpacker {
return &packetUnpackerGQUIC{
packetUnpackerBase: packetUnpackerBase{version: version},
aead: aead,
}
}
func (u *packetUnpackerGQUIC) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) {
buf := *getPacketBuffer()
buf = buf[:0]
defer putPacketBuffer(&buf)
decrypted, encryptionLevel, err := u.aead.Open(buf, data, hdr.PacketNumber, headerBinary)
if err != nil {
// Wrap err in quicError so that public reset is sent by session
return nil, qerr.Error(qerr.DecryptionFailure, err.Error())
}
fs, err := u.parseFrames(decrypted, hdr)
if err != nil {
return nil, err
}
return &unpackedPacket{
encryptionLevel: encryptionLevel,
frames: fs,
}, nil
}
// The packetUnpacker unpacks IETF QUIC packets.
type packetUnpacker struct {
packetUnpackerBase
aead quicAEAD
}
var _ unpacker = &packetUnpacker{}
func newPacketUnpacker(aead quicAEAD, version protocol.VersionNumber) unpacker {
return &packetUnpacker{
packetUnpackerBase: packetUnpackerBase{version: version},
aead: aead,
}
}
func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.Header, data []byte) (*unpackedPacket, error) {
buf := *getPacketBuffer()
buf = buf[:0]
defer putPacketBuffer(&buf)
var decrypted []byte
var encryptionLevel protocol.EncryptionLevel
var err error
if hdr.IsLongHeader {
decrypted, err = u.aead.OpenHandshake(buf, data, hdr.PacketNumber, headerBinary)
encryptionLevel = protocol.EncryptionUnencrypted
} else {
decrypted, err = u.aead.Open1RTT(buf, data, hdr.PacketNumber, headerBinary)
encryptionLevel = protocol.EncryptionForwardSecure
}
if err != nil {
// Wrap err in quicError so that public reset is sent by session
return nil, qerr.Error(qerr.DecryptionFailure, err.Error())
}
fs, err := u.parseFrames(decrypted, hdr)
if err != nil {
return nil, err
}
return &unpackedPacket{
encryptionLevel: encryptionLevel,

View file

@ -3,7 +3,7 @@ package quic
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/crypto"
"github.com/golang/mock/gomock"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
"github.com/lucas-clemente/quic-go/qerr"
@ -12,63 +12,87 @@ import (
. "github.com/onsi/gomega"
)
type mockAEAD struct {
encLevelOpen protocol.EncryptionLevel
}
func (m *mockAEAD) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) {
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveClient, 0x1337, protocol.VersionWhatever)
Expect(err).ToNot(HaveOccurred())
res, err := nullAEAD.Open(dst, src, packetNumber, associatedData)
return res, m.encLevelOpen, err
}
func (m *mockAEAD) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel) {
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, 0x1337, protocol.VersionWhatever)
Expect(err).ToNot(HaveOccurred())
return nullAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionUnspecified
}
var _ quicAEAD = &mockAEAD{}
var _ = Describe("Packet unpacker", func() {
var _ = Describe("Packet Unpacker (for gQUIC)", func() {
var (
unpacker *packetUnpacker
unpacker *packetUnpackerGQUIC
hdr *wire.Header
hdrBin []byte
data []byte
buf *bytes.Buffer
aead *MockGQUICAEAD
)
BeforeEach(func() {
aead = NewMockGQUICAEAD(mockCtrl)
hdr = &wire.Header{
PacketNumber: 10,
PacketNumberLen: 1,
Raw: []byte{0x04, 0x4c, 0x01},
}
hdrBin = []byte{0x04, 0x4c, 0x01}
unpacker = &packetUnpacker{aead: &mockAEAD{}}
data = nil
buf = &bytes.Buffer{}
unpacker = newPacketUnpackerGQUIC(aead, versionGQUICFrames).(*packetUnpackerGQUIC)
})
setData := func(p []byte) {
data, _ = unpacker.aead.(*mockAEAD).Seal(nil, p, 0, hdrBin)
}
It("errors if the packet doesn't contain any payload", func() {
setData(nil)
_, err := unpacker.Unpack(hdrBin, hdr, data)
data := []byte("foobar")
aead.EXPECT().Open(gomock.Any(), []byte("foobar"), hdr.PacketNumber, hdr.Raw).Return([]byte{}, protocol.EncryptionForwardSecure, nil)
_, err := unpacker.Unpack(hdr.Raw, hdr, data)
Expect(err).To(MatchError(qerr.MissingPayload))
})
It("saves the encryption level", func() {
unpacker.version = versionGQUICFrames
f := &wire.ConnectionCloseFrame{ReasonPhrase: "foo"}
err := f.Write(buf, versionGQUICFrames)
Expect(err).ToNot(HaveOccurred())
setData(buf.Bytes())
unpacker.aead.(*mockAEAD).encLevelOpen = protocol.EncryptionSecure
packet, err := unpacker.Unpack(hdrBin, hdr, data)
aead.EXPECT().Open(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return([]byte{0}, protocol.EncryptionSecure, nil)
packet, err := unpacker.Unpack(hdr.Raw, hdr, nil)
Expect(err).ToNot(HaveOccurred())
Expect(packet.encryptionLevel).To(Equal(protocol.EncryptionSecure))
})
It("unpacks the frames", func() {
buf := &bytes.Buffer{}
(&wire.PingFrame{}).Write(buf, versionGQUICFrames)
(&wire.BlockedFrame{}).Write(buf, versionGQUICFrames)
aead.EXPECT().Open(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return(buf.Bytes(), protocol.EncryptionForwardSecure, nil)
packet, err := unpacker.Unpack(hdr.Raw, hdr, nil)
Expect(err).ToNot(HaveOccurred())
Expect(packet.frames).To(Equal([]wire.Frame{&wire.PingFrame{}, &wire.BlockedFrame{}}))
})
})
var _ = Describe("Packet Unpacker (for IETF QUIC)", func() {
var (
unpacker *packetUnpacker
hdr *wire.Header
aead *MockQuicAEAD
)
BeforeEach(func() {
aead = NewMockQuicAEAD(mockCtrl)
hdr = &wire.Header{
PacketNumber: 10,
PacketNumberLen: 1,
Raw: []byte{0x04, 0x4c, 0x01},
}
unpacker = newPacketUnpacker(aead, versionIETFFrames).(*packetUnpacker)
})
It("errors if the packet doesn't contain any payload", func() {
data := []byte("foobar")
aead.EXPECT().Open1RTT(gomock.Any(), []byte("foobar"), hdr.PacketNumber, hdr.Raw).Return([]byte{}, nil)
_, err := unpacker.Unpack(hdr.Raw, hdr, data)
Expect(err).To(MatchError(qerr.MissingPayload))
})
It("opens handshake packets", func() {
hdr.IsLongHeader = true
aead.EXPECT().OpenHandshake(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return([]byte{0}, nil)
packet, err := unpacker.Unpack(hdr.Raw, hdr, nil)
Expect(err).ToNot(HaveOccurred())
Expect(packet.encryptionLevel).To(Equal(protocol.EncryptionUnencrypted))
})
It("unpacks the frames", func() {
buf := &bytes.Buffer{}
(&wire.PingFrame{}).Write(buf, versionIETFFrames)
(&wire.BlockedFrame{}).Write(buf, versionIETFFrames)
aead.EXPECT().Open1RTT(gomock.Any(), gomock.Any(), hdr.PacketNumber, hdr.Raw).Return(buf.Bytes(), nil)
packet, err := unpacker.Unpack(hdr.Raw, hdr, nil)
Expect(err).ToNot(HaveOccurred())
Expect(packet.frames).To(Equal([]wire.Frame{&wire.PingFrame{}, &wire.BlockedFrame{}}))
})
})

View file

@ -21,9 +21,12 @@ type nullAEAD struct {
var _ quicAEAD = &nullAEAD{}
func (n *nullAEAD) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) {
data, err := n.aead.Open(dst, src, packetNumber, associatedData)
return data, protocol.EncryptionUnencrypted, err
func (n *nullAEAD) OpenHandshake(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) {
return n.aead.Open(dst, src, packetNumber, associatedData)
}
func (n *nullAEAD) Open1RTT(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) {
return nil, errors.New("no 1-RTT keys")
}
type tlsSession struct {

View file

@ -189,7 +189,7 @@ func newSession(
return nil, err
}
s.cryptoStreamHandler = cs
s.unpacker = &packetUnpacker{aead: cs, version: s.version}
s.unpacker = newPacketUnpackerGQUIC(cs, s.version)
s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective)
s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version)
s.packer = newPacketPacker(s.connectionID,
@ -252,7 +252,7 @@ var newClientSession = func(
}
s.cryptoStreamHandler = cs
s.divNonceChan = divNonceChan
s.unpacker = &packetUnpacker{aead: cs, version: s.version}
s.unpacker = newPacketUnpackerGQUIC(cs, s.version)
s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective)
s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version)
s.packer = newPacketPacker(s.connectionID,
@ -314,7 +314,7 @@ func newTLSServerSession(
}
s.peerParams = peerParams
s.processTransportParameters(peerParams)
s.unpacker = &packetUnpacker{aead: cs, version: s.version}
s.unpacker = newPacketUnpacker(cs, s.version)
return s, nil
}
@ -353,7 +353,7 @@ var newTLSClientSession = func(
return nil, err
}
s.cryptoStreamHandler = cs
s.unpacker = &packetUnpacker{aead: cs, version: s.version}
s.unpacker = newPacketUnpacker(cs, s.version)
s.streamsMap = newStreamsMap(s, s.newFlowController, s.config.MaxIncomingStreams, s.config.MaxIncomingUniStreams, s.perspective, s.version)
s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version)
s.packer = newPacketPacker(s.connectionID,

View file

@ -653,23 +653,6 @@ var _ = Describe("Session", func() {
Expect(err).ToNot(HaveOccurred())
Expect(sess.conn.(*mockConnection).remoteAddr).To(Equal(origAddr))
})
It("doesn't change the remote address if authenticating the packet fails", func() {
remoteIP := &net.IPAddr{IP: net.IPv4(192, 168, 0, 100)}
attackerIP := &net.IPAddr{IP: net.IPv4(192, 168, 0, 102)}
sess.conn.(*mockConnection).remoteAddr = remoteIP
// use the real packetUnpacker here, to make sure this test fails if the error code for failed decryption changes
sess.unpacker = &packetUnpacker{}
sess.unpacker.(*packetUnpacker).aead = &mockAEAD{}
p := receivedPacket{
remoteAddr: attackerIP,
header: &wire.Header{PacketNumber: 1337},
}
err := sess.handlePacketImpl(&p)
quicErr := err.(*qerr.QuicError)
Expect(quicErr.ErrorCode).To(Equal(qerr.DecryptionFailure))
Expect(sess.conn.(*mockConnection).remoteAddr).To(Equal(remoteIP))
})
})
})