Skip to content

Commit

Permalink
don't use trial decryption for IETF QUIC
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Mar 31, 2018
1 parent a298bd0 commit 302d2a1
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 126 deletions.
26 changes: 12 additions & 14 deletions internal/handshake/crypto_setup_tls.go
Expand Up @@ -31,14 +31,16 @@ type cryptoSetupTLS struct {
handshakeEvent chan<- struct{}
}

var _ CryptoSetupTLS = &cryptoSetupTLS{}

// NewCryptoSetupTLSServer creates a new TLS CryptoSetup instance for a server
func NewCryptoSetupTLSServer(
tls MintTLS,
cryptoStream *CryptoStreamConn,
nullAEAD crypto.AEAD,
handshakeEvent chan<- struct{},
version protocol.VersionNumber,
) CryptoSetup {
) CryptoSetupTLS {
return &cryptoSetupTLS{
tls: tls,
cryptoStream: cryptoStream,
Expand All @@ -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
Expand Down Expand Up @@ -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
}
data, err := h.nullAEAD.Open(dst, src, packetNumber, associatedData)
if err != nil {
return nil, protocol.EncryptionUnspecified, err
if h.aead == nil {
return nil, errors.New("no 1-RTT sealer")
}
return data, protocol.EncryptionUnencrypted, nil
return h.aead.Open(dst, src, packetNumber, associatedData)
}

func (h *cryptoSetupTLS) GetSealer() (protocol.EncryptionLevel, Sealer) {
Expand Down
21 changes: 5 additions & 16 deletions internal/handshake/crypto_setup_tls_test.go
Expand Up @@ -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() {
Expand All @@ -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{})
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{})
_, err := cs.OpenHandshake(nil, []byte("foobar enc"), 10, []byte{})
Expect(err).To(MatchError("authentication failed"))
Expect(enc).To(Equal(protocol.EncryptionUnspecified))
})
})

Expand All @@ -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")))
})
})
Expand Down
19 changes: 16 additions & 3 deletions internal/handshake/interface.go
Expand Up @@ -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

Expand All @@ -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 {
Expand Down
17 changes: 12 additions & 5 deletions mint_utils.go
Expand Up @@ -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
}
}
Expand Down
16 changes: 6 additions & 10 deletions mint_utils_test.go
Expand Up @@ -141,24 +141,20 @@ 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"),
FinBit: true,
}
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())
decrypted, err := aeadCl.Open(nil, data[len(hdr.Raw):], hdr.PacketNumber, hdr.Raw)
Expect(err).ToNot(HaveOccurred())
Expect(packet.frames).To(Equal([]wire.Frame{f}))
frame, err := wire.ParseNextFrame(bytes.NewReader(decrypted), hdr, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(frame).To(Equal(f))
})
})
})
49 changes: 49 additions & 0 deletions mock_gquic_aead_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions mock_quic_aead_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions mockgen.go
Expand Up @@ -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"
10 changes: 8 additions & 2 deletions packet_packer.go
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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,
Expand Down

0 comments on commit 302d2a1

Please sign in to comment.