create handshake.CryptoSetup interface

This commit is contained in:
Marten Seemann 2016-11-07 13:04:54 +07:00
parent 7e4c695faf
commit 2b7c67d297
No known key found for this signature in database
GPG key ID: 3603F40B121FCDEA
7 changed files with 44 additions and 27 deletions

View file

@ -65,7 +65,7 @@ func (c *linkedConnection) write(p []byte) error {
func (*linkedConnection) setCurrentRemoteAddr(addr interface{}) {} func (*linkedConnection) setCurrentRemoteAddr(addr interface{}) {}
func (*linkedConnection) RemoteAddr() *net.UDPAddr { return &net.UDPAddr{} } func (*linkedConnection) RemoteAddr() *net.UDPAddr { return &net.UDPAddr{} }
func setAEAD(cs *handshake.CryptoSetup, aead crypto.AEAD) { func setAEAD(cs handshake.CryptoSetup, aead crypto.AEAD) {
*(*bool)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("receivedForwardSecurePacket").UnsafeAddr())) = true *(*bool)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("receivedForwardSecurePacket").UnsafeAddr())) = true
*(*crypto.AEAD)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("forwardSecureAEAD").UnsafeAddr())) = aead *(*crypto.AEAD)(unsafe.Pointer(reflect.ValueOf(cs).Elem().FieldByName("forwardSecureAEAD").UnsafeAddr())) = aead
} }

View file

@ -0,0 +1,14 @@
package handshake
import "github.com/lucas-clemente/quic-go/protocol"
// CryptoSetup is a crypto setup
type CryptoSetup interface {
HandleCryptoStream() error
Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error)
Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte
DiversificationNonce() []byte
LockForSealing()
UnlockForSealing()
HandshakeComplete() bool
}

View file

@ -20,8 +20,8 @@ type KeyDerivationFunction func(forwardSecure bool, sharedSecret, nonces []byte,
// KeyExchangeFunction is used to make a new KEX // KeyExchangeFunction is used to make a new KEX
type KeyExchangeFunction func() crypto.KeyExchange type KeyExchangeFunction func() crypto.KeyExchange
// The CryptoSetup handles all things crypto for the Session // The CryptoSetupServer handles all things crypto for the Session
type CryptoSetup struct { type cryptoSetupServer struct {
connID protocol.ConnectionID connID protocol.ConnectionID
ip net.IP ip net.IP
version protocol.VersionNumber version protocol.VersionNumber
@ -44,7 +44,7 @@ type CryptoSetup struct {
mutex sync.RWMutex mutex sync.RWMutex
} }
var _ crypto.AEAD = &CryptoSetup{} var _ crypto.AEAD = &cryptoSetupServer{}
// NewCryptoSetup creates a new CryptoSetup instance // NewCryptoSetup creates a new CryptoSetup instance
func NewCryptoSetup( func NewCryptoSetup(
@ -53,10 +53,10 @@ func NewCryptoSetup(
version protocol.VersionNumber, version protocol.VersionNumber,
scfg *ServerConfig, scfg *ServerConfig,
cryptoStream utils.Stream, cryptoStream utils.Stream,
connectionParameters ConnectionParametersManager, connectionParametersManager ConnectionParametersManager,
aeadChanged chan struct{}, aeadChanged chan struct{},
) (*CryptoSetup, error) { ) (CryptoSetup, error) {
return &CryptoSetup{ return &cryptoSetupServer{
connID: connID, connID: connID,
ip: ip, ip: ip,
version: version, version: version,
@ -64,13 +64,13 @@ func NewCryptoSetup(
keyDerivation: crypto.DeriveKeysAESGCM, keyDerivation: crypto.DeriveKeysAESGCM,
keyExchange: getEphermalKEX, keyExchange: getEphermalKEX,
cryptoStream: cryptoStream, cryptoStream: cryptoStream,
connectionParameters: connectionParameters, connectionParameters: connectionParametersManager,
aeadChanged: aeadChanged, aeadChanged: aeadChanged,
}, nil }, nil
} }
// HandleCryptoStream reads and writes messages on the crypto stream // HandleCryptoStream reads and writes messages on the crypto stream
func (h *CryptoSetup) HandleCryptoStream() error { func (h *cryptoSetupServer) HandleCryptoStream() error {
for { for {
var chloData bytes.Buffer var chloData bytes.Buffer
messageTag, cryptoData, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &chloData)) messageTag, cryptoData, err := ParseHandshakeMessage(io.TeeReader(h.cryptoStream, &chloData))
@ -93,7 +93,7 @@ func (h *CryptoSetup) HandleCryptoStream() error {
} }
} }
func (h *CryptoSetup) handleMessage(chloData []byte, cryptoData map[Tag][]byte) (bool, error) { func (h *cryptoSetupServer) handleMessage(chloData []byte, cryptoData map[Tag][]byte) (bool, error) {
sniSlice, ok := cryptoData[TagSNI] sniSlice, ok := cryptoData[TagSNI]
if !ok { if !ok {
return false, qerr.Error(qerr.CryptoMessageParameterNotFound, "SNI required") return false, qerr.Error(qerr.CryptoMessageParameterNotFound, "SNI required")
@ -153,7 +153,7 @@ func (h *CryptoSetup) handleMessage(chloData []byte, cryptoData map[Tag][]byte)
} }
// Open a message // Open a message
func (h *CryptoSetup) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) { func (h *cryptoSetupServer) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, error) {
h.mutex.RLock() h.mutex.RLock()
defer h.mutex.RUnlock() defer h.mutex.RUnlock()
@ -181,7 +181,7 @@ func (h *CryptoSetup) Open(dst, src []byte, packetNumber protocol.PacketNumber,
} }
// Seal a message, call LockForSealing() before! // Seal a message, call LockForSealing() before!
func (h *CryptoSetup) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte { func (h *cryptoSetupServer) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) []byte {
if h.receivedForwardSecurePacket { if h.receivedForwardSecurePacket {
return h.forwardSecureAEAD.Seal(dst, src, packetNumber, associatedData) return h.forwardSecureAEAD.Seal(dst, src, packetNumber, associatedData)
} else if h.secureAEAD != nil { } else if h.secureAEAD != nil {
@ -191,7 +191,7 @@ func (h *CryptoSetup) Seal(dst, src []byte, packetNumber protocol.PacketNumber,
} }
} }
func (h *CryptoSetup) isInchoateCHLO(cryptoData map[Tag][]byte, cert []byte) bool { func (h *cryptoSetupServer) isInchoateCHLO(cryptoData map[Tag][]byte, cert []byte) bool {
if _, ok := cryptoData[TagPUBS]; !ok { if _, ok := cryptoData[TagPUBS]; !ok {
return true return true
} }
@ -214,7 +214,7 @@ func (h *CryptoSetup) isInchoateCHLO(cryptoData map[Tag][]byte, cert []byte) boo
return false return false
} }
func (h *CryptoSetup) handleInchoateCHLO(sni string, chlo []byte, cryptoData map[Tag][]byte) ([]byte, error) { func (h *cryptoSetupServer) handleInchoateCHLO(sni string, chlo []byte, cryptoData map[Tag][]byte) ([]byte, error) {
if len(chlo) < protocol.ClientHelloMinimumSize { if len(chlo) < protocol.ClientHelloMinimumSize {
return nil, qerr.Error(qerr.CryptoInvalidValueLength, "CHLO too small") return nil, qerr.Error(qerr.CryptoInvalidValueLength, "CHLO too small")
} }
@ -254,7 +254,7 @@ func (h *CryptoSetup) handleInchoateCHLO(sni string, chlo []byte, cryptoData map
return serverReply.Bytes(), nil return serverReply.Bytes(), nil
} }
func (h *CryptoSetup) handleCHLO(sni string, data []byte, cryptoData map[Tag][]byte) ([]byte, error) { func (h *cryptoSetupServer) handleCHLO(sni string, data []byte, cryptoData map[Tag][]byte) ([]byte, error) {
// We have a CHLO matching our server config, we can continue with the 0-RTT handshake // We have a CHLO matching our server config, we can continue with the 0-RTT handshake
sharedSecret, err := h.scfg.kex.CalculateSharedKey(cryptoData[TagPUBS]) sharedSecret, err := h.scfg.kex.CalculateSharedKey(cryptoData[TagPUBS])
if err != nil { if err != nil {
@ -354,7 +354,7 @@ func (h *CryptoSetup) handleCHLO(sni string, data []byte, cryptoData map[Tag][]b
} }
// DiversificationNonce returns a diversification nonce if required in the next packet to be Seal'ed. See LockForSealing()! // DiversificationNonce returns a diversification nonce if required in the next packet to be Seal'ed. See LockForSealing()!
func (h *CryptoSetup) DiversificationNonce() []byte { func (h *cryptoSetupServer) DiversificationNonce() []byte {
if h.receivedForwardSecurePacket || h.secureAEAD == nil { if h.receivedForwardSecurePacket || h.secureAEAD == nil {
return nil return nil
} }
@ -362,21 +362,21 @@ func (h *CryptoSetup) DiversificationNonce() []byte {
} }
// LockForSealing should be called before Seal(). It is needed so that diversification nonces can be obtained before packets are sealed, and the AEADs are not changed in the meantime. // LockForSealing should be called before Seal(). It is needed so that diversification nonces can be obtained before packets are sealed, and the AEADs are not changed in the meantime.
func (h *CryptoSetup) LockForSealing() { func (h *cryptoSetupServer) LockForSealing() {
h.mutex.RLock() h.mutex.RLock()
} }
// UnlockForSealing should be called after Seal() is complete, see LockForSealing(). // UnlockForSealing should be called after Seal() is complete, see LockForSealing().
func (h *CryptoSetup) UnlockForSealing() { func (h *cryptoSetupServer) UnlockForSealing() {
h.mutex.RUnlock() h.mutex.RUnlock()
} }
// HandshakeComplete returns true after the first forward secure packet was received form the client. // HandshakeComplete returns true after the first forward secure packet was received form the client.
func (h *CryptoSetup) HandshakeComplete() bool { func (h *cryptoSetupServer) HandshakeComplete() bool {
return h.receivedForwardSecurePacket return h.receivedForwardSecurePacket
} }
func (h *CryptoSetup) validateClientNonce(nonce []byte) error { func (h *cryptoSetupServer) validateClientNonce(nonce []byte) error {
if len(nonce) != 32 { if len(nonce) != 32 {
return qerr.Error(qerr.InvalidCryptoMessageParameter, "invalid client nonce length") return qerr.Error(qerr.InvalidCryptoMessageParameter, "invalid client nonce length")
} }

View file

@ -138,7 +138,7 @@ var _ = Describe("Crypto setup", func() {
kex *mockKEX kex *mockKEX
signer *mockSigner signer *mockSigner
scfg *ServerConfig scfg *ServerConfig
cs *CryptoSetup cs *cryptoSetupServer
stream *mockStream stream *mockStream
cpm ConnectionParametersManager cpm ConnectionParametersManager
aeadChanged chan struct{} aeadChanged chan struct{}
@ -171,9 +171,10 @@ var _ = Describe("Crypto setup", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
scfg.stkSource = &mockStkSource{} scfg.stkSource = &mockStkSource{}
v := protocol.SupportedVersions[len(protocol.SupportedVersions)-1] v := protocol.SupportedVersions[len(protocol.SupportedVersions)-1]
cpm = NewConnectionParamatersManager(protocol.Version36) cpm = NewConnectionParamatersManager(protocol.VersionWhatever)
cs, err = NewCryptoSetup(protocol.ConnectionID(42), ip, v, scfg, stream, cpm, aeadChanged) csInt, err := NewCryptoSetup(protocol.ConnectionID(42), ip, v, scfg, stream, cpm, aeadChanged)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
cs = csInt.(*cryptoSetupServer)
cs.keyDerivation = mockKeyDerivation cs.keyDerivation = mockKeyDerivation
cs.keyExchange = func() crypto.KeyExchange { return &mockKEX{ephermal: true} } cs.keyExchange = func() crypto.KeyExchange { return &mockKEX{ephermal: true} }
}) })

View file

@ -19,7 +19,7 @@ type packedPacket struct {
type packetPacker struct { type packetPacker struct {
connectionID protocol.ConnectionID connectionID protocol.ConnectionID
version protocol.VersionNumber version protocol.VersionNumber
cryptoSetup *handshake.CryptoSetup cryptoSetup handshake.CryptoSetup
packetNumberGenerator *packetNumberGenerator packetNumberGenerator *packetNumberGenerator
@ -29,7 +29,7 @@ type packetPacker struct {
controlFrames []frames.Frame controlFrames []frames.Frame
} }
func newPacketPacker(connectionID protocol.ConnectionID, cryptoSetup *handshake.CryptoSetup, connectionParameters handshake.ConnectionParametersManager, streamFramer *streamFramer, version protocol.VersionNumber) *packetPacker { func newPacketPacker(connectionID protocol.ConnectionID, cryptoSetup handshake.CryptoSetup, connectionParameters handshake.ConnectionParametersManager, streamFramer *streamFramer, version protocol.VersionNumber) *packetPacker {
return &packetPacker{ return &packetPacker{
cryptoSetup: cryptoSetup, cryptoSetup: cryptoSetup,
connectionID: connectionID, connectionID: connectionID,

View file

@ -25,9 +25,11 @@ var _ = Describe("Packet packer", func() {
cpm := &mockConnectionParametersManager{} cpm := &mockConnectionParametersManager{}
streamFramer = newStreamFramer(newStreamsMap(nil, cpm), fcm) streamFramer = newStreamFramer(newStreamsMap(nil, cpm), fcm)
cs, err := handshake.NewCryptoSetup(0, nil, protocol.VersionWhatever, nil, nil, nil, nil)
Expect(err).ToNot(HaveOccurred())
packer = &packetPacker{ packer = &packetPacker{
cryptoSetup: &handshake.CryptoSetup{}, cryptoSetup: cs,
connectionParameters: cpm, connectionParameters: cpm,
packetNumberGenerator: newPacketNumberGenerator(protocol.SkipPacketAveragePeriodLength), packetNumberGenerator: newPacketNumberGenerator(protocol.SkipPacketAveragePeriodLength),
streamFramer: streamFramer, streamFramer: streamFramer,

View file

@ -63,7 +63,7 @@ type Session struct {
unpacker unpacker unpacker unpacker
packer *packetPacker packer *packetPacker
cryptoSetup *handshake.CryptoSetup cryptoSetup handshake.CryptoSetup
receivedPackets chan *receivedPacket receivedPackets chan *receivedPacket
sendingScheduled chan struct{} sendingScheduled chan struct{}