send entropy in packets, validate entropy in received ACKs

This commit is contained in:
Marten Seemann
2016-04-17 14:21:36 +07:00
parent 922a2975e8
commit 1097698c4b
3 changed files with 57 additions and 7 deletions

View File

@@ -9,6 +9,7 @@ import (
"github.com/lucas-clemente/quic-go/frames" "github.com/lucas-clemente/quic-go/frames"
"github.com/lucas-clemente/quic-go/handshake" "github.com/lucas-clemente/quic-go/handshake"
"github.com/lucas-clemente/quic-go/protocol" "github.com/lucas-clemente/quic-go/protocol"
"github.com/lucas-clemente/quic-go/utils"
) )
// StreamCallback gets a stream frame and returns a reply frame // StreamCallback gets a stream frame and returns a reply frame
@@ -25,7 +26,9 @@ type Session struct {
ServerConfig *handshake.ServerConfig ServerConfig *handshake.ServerConfig
cryptoSetup *handshake.CryptoSetup cryptoSetup *handshake.CryptoSetup
Entropy EntropyAccumulator EntropyReceived EntropyAccumulator
EntropySent EntropyAccumulator
EntropyHistory map[protocol.PacketNumber]EntropyAccumulator // ToDo: store this with the packet itself
lastSentPacketNumber protocol.PacketNumber lastSentPacketNumber protocol.PacketNumber
lastObservedPacketNumber protocol.PacketNumber lastObservedPacketNumber protocol.PacketNumber
@@ -48,6 +51,7 @@ func NewSession(conn *net.UDPConn, v protocol.VersionNumber, connectionID protoc
streamCallback: streamCallback, streamCallback: streamCallback,
lastObservedPacketNumber: 0, lastObservedPacketNumber: 0,
Streams: make(map[protocol.StreamID]*Stream), Streams: make(map[protocol.StreamID]*Stream),
EntropyHistory: make(map[protocol.PacketNumber]EntropyAccumulator),
} }
} }
@@ -77,11 +81,11 @@ func (s *Session) HandlePacket(addr *net.UDPAddr, publicHeaderBinary []byte, pub
if err != nil { if err != nil {
return err return err
} }
s.Entropy.Add(publicHeader.PacketNumber, privateFlag&0x01 > 0) s.EntropyReceived.Add(publicHeader.PacketNumber, privateFlag&0x01 > 0)
s.SendFrames([]frames.Frame{&frames.AckFrame{ s.SendFrames([]frames.Frame{&frames.AckFrame{
LargestObserved: publicHeader.PacketNumber, LargestObserved: publicHeader.PacketNumber,
Entropy: s.Entropy.Get(), Entropy: s.EntropyReceived.Get(),
}}) }})
// read all frames in the packet // read all frames in the packet
@@ -173,10 +177,21 @@ func (s *Session) handleStreamFrame(r *bytes.Reader) error {
} }
func (s *Session) handleAckFrame(r *bytes.Reader) error { func (s *Session) handleAckFrame(r *bytes.Reader) error {
_, err := frames.ParseAckFrame(r) frame, err := frames.ParseAckFrame(r)
if err != nil { if err != nil {
return err return err
} }
expectedEntropy, ok := s.EntropyHistory[frame.LargestObserved]
if !ok {
return errors.New("No entropy value saved for received ACK packet")
}
delete(s.EntropyHistory, frame.LargestObserved)
if byte(expectedEntropy) != frame.Entropy {
return errors.New("Incorrect entropy value in ACK package")
}
return nil return nil
} }
@@ -210,7 +225,16 @@ func (s *Session) handleRstStreamFrame(r *bytes.Reader) error {
// SendFrames sends a number of frames to the client // SendFrames sends a number of frames to the client
func (s *Session) SendFrames(frames []frames.Frame) error { func (s *Session) SendFrames(frames []frames.Frame) error {
var framesData bytes.Buffer var framesData bytes.Buffer
framesData.WriteByte(0) // TODO: entropy entropyBit, err := utils.RandomBit()
if err != nil {
return err
}
if entropyBit {
framesData.WriteByte(1)
} else {
framesData.WriteByte(0)
}
for _, f := range frames { for _, f := range frames {
if err := f.Write(&framesData); err != nil { if err := f.Write(&framesData); err != nil {
return err return err
@@ -220,14 +244,17 @@ func (s *Session) SendFrames(frames []frames.Frame) error {
s.lastSentPacketNumber++ s.lastSentPacketNumber++
var fullReply bytes.Buffer var fullReply bytes.Buffer
responsePublicHeader := PublicHeader{ConnectionID: s.ConnectionID, PacketNumber: s.lastSentPacketNumber} packetNumber := s.lastSentPacketNumber
responsePublicHeader := PublicHeader{ConnectionID: s.ConnectionID, PacketNumber: packetNumber}
if err := responsePublicHeader.WritePublicHeader(&fullReply); err != nil { if err := responsePublicHeader.WritePublicHeader(&fullReply); err != nil {
return err return err
} }
s.EntropySent.Add(packetNumber, entropyBit)
s.EntropyHistory[packetNumber] = s.EntropySent
s.cryptoSetup.Seal(s.lastSentPacketNumber, &fullReply, fullReply.Bytes(), framesData.Bytes()) s.cryptoSetup.Seal(s.lastSentPacketNumber, &fullReply, fullReply.Bytes(), framesData.Bytes())
fmt.Printf("-> Sending packet %d (%d bytes) to %v\n", responsePublicHeader.PacketNumber, len(fullReply.Bytes()), s.CurrentRemoteAddr) fmt.Printf("-> Sending packet %d (%d bytes) to %v\n", responsePublicHeader.PacketNumber, len(fullReply.Bytes()), s.CurrentRemoteAddr)
_, err := s.Connection.WriteToUDP(fullReply.Bytes(), s.CurrentRemoteAddr) _, err = s.Connection.WriteToUDP(fullReply.Bytes(), s.CurrentRemoteAddr)
return err return err
} }

View File

@@ -2,6 +2,7 @@ package utils
import ( import (
"bytes" "bytes"
"crypto/rand"
"io" "io"
) )
@@ -123,6 +124,20 @@ func Min(a, b int) int {
return b return b
} }
// RandomBit returns a cryptographically secure random bit (encoded as true / false)
func RandomBit() (bool, error) {
// ToDo: it's probably more efficient to read a bigger slice of random numbers at once and to cache them somewhere
b := make([]byte, 1)
_, err := rand.Read(b)
if err != nil {
return false, err
}
if uint8(b[0])%2 == 0 {
return false, nil
}
return true, nil
}
// Uint32Slice attaches the methods of sort.Interface to []uint32, sorting in increasing order. // Uint32Slice attaches the methods of sort.Interface to []uint32, sorting in increasing order.
type Uint32Slice []uint32 type Uint32Slice []uint32

View File

@@ -110,6 +110,14 @@ var _ = Describe("Utils", func() {
}) })
}) })
Context("Rand", func() {
It("returns either true or false", func() {
val, err := RandomBit()
Expect(err).ToNot(HaveOccurred())
Expect(val).To(SatisfyAny(Equal(true), Equal(false)))
})
})
Context("ReadUintN", func() { Context("ReadUintN", func() {
It("reads n bytes", func() { It("reads n bytes", func() {
m := map[uint8]uint64{ m := map[uint8]uint64{