create CryptoSetup for the client, use it in the Session

This commit is contained in:
Marten Seemann
2016-11-07 16:45:00 +07:00
parent f662ce0705
commit 23435253db
4 changed files with 157 additions and 31 deletions

View File

@@ -0,0 +1,91 @@
package handshake
import (
"bytes"
"io"
"github.com/lucas-clemente/quic-go/crypto"
"github.com/lucas-clemente/quic-go/protocol"
"github.com/lucas-clemente/quic-go/qerr"
"github.com/lucas-clemente/quic-go/utils"
)
type cryptoSetupClient struct {
connID protocol.ConnectionID
version protocol.VersionNumber
cryptoStream utils.Stream
hasServerConfig bool
}
var _ crypto.AEAD = &cryptoSetupClient{}
var _ CryptoSetup = &cryptoSetupClient{}
// NewCryptoSetupClient creates a new CryptoSetup instance for a client
func NewCryptoSetupClient(
connID protocol.ConnectionID,
version protocol.VersionNumber,
cryptoStream utils.Stream,
) (CryptoSetup, error) {
return &cryptoSetupClient{
connID: connID,
version: version,
cryptoStream: cryptoStream,
}, nil
}
func (h *cryptoSetupClient) HandleCryptoStream() error {
h.sendInchoateCHLO()
for {
var chloData bytes.Buffer
messageTag, cryptoData, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &chloData))
_ = cryptoData
utils.Debugf("Received message on Crypto Stream. MessageTag: %#v", messageTag)
if err != nil {
return qerr.HandshakeFailed
}
}
}
func (h *cryptoSetupClient) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) {
return (&crypto.NullAEAD{}).Open(dst, src, packetNumber, associatedData)
}
func (h *cryptoSetupClient) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte {
return (&crypto.NullAEAD{}).Seal(dst, src, packetNumber, associatedData)
}
func (h *cryptoSetupClient) DiversificationNonce() []byte {
return nil
}
func (h *cryptoSetupClient) LockForSealing() {
}
func (h *cryptoSetupClient) UnlockForSealing() {
}
func (h *cryptoSetupClient) HandshakeComplete() bool {
return false
}
func (h *cryptoSetupClient) sendInchoateCHLO() error {
b := &bytes.Buffer{}
tags := make(map[Tag][]byte)
tags[TagSNI] = []byte("quic.clemente.io") // TODO: use real SNI here
tags[TagPDMD] = []byte("X509")
tags[TagPAD] = bytes.Repeat([]byte("0"), 1000)
WriteHandshakeMessage(b, TagCHLO, tags)
_, err := h.cryptoStream.Write(b.Bytes())
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1 @@
package handshake

View File

@@ -46,7 +46,7 @@ type cryptoSetupServer struct {
var _ crypto.AEAD = &cryptoSetupServer{}
// NewCryptoSetup creates a new CryptoSetup instance
// NewCryptoSetup creates a new CryptoSetup instance for a server
func NewCryptoSetup(
connID protocol.ConnectionID,
ip net.IP,

View File

@@ -43,6 +43,7 @@ type closeCallback func(id protocol.ConnectionID)
// A Session is a QUIC session
type Session struct {
connectionID protocol.ConnectionID
perspective protocol.Perspective
version protocol.VersionNumber
streamCallback StreamCallback
@@ -95,56 +96,89 @@ type Session struct {
// newSession makes a new session
func newSession(conn connection, v protocol.VersionNumber, connectionID protocol.ConnectionID, sCfg *handshake.ServerConfig, streamCallback StreamCallback, closeCallback closeCallback) (packetHandler, error) {
connectionParameters := handshake.NewConnectionParamatersManager(v)
var sentPacketHandler ackhandler.SentPacketHandler
rttStats := &congestion.RTTStats{}
sentPacketHandler = ackhandler.NewSentPacketHandler(rttStats)
flowControlManager := flowcontrol.NewFlowControlManager(connectionParameters, rttStats)
now := time.Now()
session := &Session{
conn: conn,
connectionID: connectionID,
perspective: protocol.PerspectiveServer,
version: v,
streamCallback: streamCallback,
closeCallback: closeCallback,
connectionParameters: connectionParameters,
sentPacketHandler: sentPacketHandler,
flowControlManager: flowControlManager,
receivedPackets: make(chan *receivedPacket, protocol.MaxSessionUnprocessedPackets),
closeChan: make(chan *qerr.QuicError, 1),
sendingScheduled: make(chan struct{}, 1),
undecryptablePackets: make([]*receivedPacket, 0, protocol.MaxUndecryptablePackets),
aeadChanged: make(chan struct{}, 1),
runClosed: make(chan struct{}, 1), // this channel will receive once the run loop has been stopped
timer: time.NewTimer(0),
lastNetworkActivityTime: now,
sessionCreationTime: now,
}
session.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(session.ackAlarmChanged)
session.streamsMap = newStreamsMap(session.newStream, session.connectionParameters)
session.setup()
cryptoStream, _ := session.GetOrOpenStream(1)
var err error
session.cryptoSetup, err = handshake.NewCryptoSetup(connectionID, conn.RemoteAddr().IP, v, sCfg, cryptoStream, session.connectionParameters, session.aeadChanged)
if err != nil {
return nil, err
}
session.streamFramer = newStreamFramer(session.streamsMap, flowControlManager)
session.packer = newPacketPacker(connectionID, session.cryptoSetup, session.connectionParameters, session.streamFramer, v)
session.unpacker = &packetUnpacker{aead: session.cryptoSetup, version: v}
session.packer = newPacketPacker(connectionID, session.cryptoSetup, session.connectionParameters, session.streamFramer, session.version)
session.unpacker = &packetUnpacker{aead: session.cryptoSetup, version: session.version}
return session, err
}
func newClientSession(conn *net.UDPConn, addr *net.UDPAddr, v protocol.VersionNumber, connectionID protocol.ConnectionID, streamCallback StreamCallback, closeCallback closeCallback) (*Session, error) {
session := &Session{
conn: &udpConn{conn: conn, currentAddr: addr},
connectionID: connectionID,
perspective: protocol.PerspectiveClient,
version: v,
streamCallback: streamCallback,
closeCallback: closeCallback,
}
session.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(session.ackAlarmChanged)
session.setup()
cryptoStream, _ := session.GetOrOpenStream(1)
var err error
session.cryptoSetup, err = handshake.NewCryptoSetupClient(connectionID, v, cryptoStream)
if err != nil {
return nil, err
}
session.packer = newPacketPacker(connectionID, session.cryptoSetup, session.connectionParameters, session.streamFramer, session.version)
session.unpacker = &packetUnpacker{aead: session.cryptoSetup, version: session.version}
return session, err
}
// setup is called from newSession and newClientSession and initializes values that are independent of the perspective
func (s *Session) setup() {
s.rttStats = &congestion.RTTStats{}
connectionParameters := handshake.NewConnectionParamatersManager(s.version)
flowControlManager := flowcontrol.NewFlowControlManager(connectionParameters, s.rttStats)
var sentPacketHandler ackhandler.SentPacketHandler
sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats)
now := time.Now()
s.connectionParameters = connectionParameters
s.sentPacketHandler = sentPacketHandler
s.flowControlManager = flowControlManager
s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.ackAlarmChanged)
s.receivedPackets = make(chan *receivedPacket, protocol.MaxSessionUnprocessedPackets)
s.closeChan = make(chan *qerr.QuicError, 1)
s.sendingScheduled = make(chan struct{}, 1)
s.undecryptablePackets = make([]*receivedPacket, 0, protocol.MaxUndecryptablePackets)
s.aeadChanged = make(chan struct{}, 1)
s.runClosed = make(chan struct{}, 1)
s.timer = time.NewTimer(0)
s.lastNetworkActivityTime = now
s.sessionCreationTime = now
s.streamsMap = newStreamsMap(s.newStream, s.connectionParameters)
s.streamFramer = newStreamFramer(s.streamsMap, s.flowControlManager)
}
// run the session main loop
func (s *Session) run() {
// Start the crypto stream handler