From 589dc6eb16010cc1bdde54e2f6d9748ae2265c2b Mon Sep 17 00:00:00 2001 From: Ryan Gordon Date: Wed, 11 Sep 2019 12:01:06 -0700 Subject: [PATCH] Compact handshake records into less packets Currently each record during the handshake process is sent as a separate packet. The dTLS spec allows for combining records into a signal packet so long as the packet fits within the MTU. Here we implement this improvement, compacting records during the handshake process into less packets. The number of packets sent for a complete handshake before this change was 12. With this change the number is reduced to 7. While improvements are likely hard to measure, this should reduce tail handshake latency in lossy networks. --- client_handlers.go | 153 ++++++++++++++++-------------- conn.go | 177 ++++++++++++++++++++++++----------- go.sum | 1 + packet.go | 7 ++ server_handlers.go | 225 +++++++++++++++++++++++++-------------------- 5 files changed, 342 insertions(+), 221 deletions(-) create mode 100644 packet.go diff --git a/client_handlers.go b/client_handlers.go index 0d9abd43b..54cb0aa75 100644 --- a/client_handlers.go +++ b/client_handlers.go @@ -289,23 +289,26 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) { }) } - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(c.handshakeMessageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, }, - handshakeMessage: &handshakeMessageClientHello{ - version: protocolVersion1_2, - cookie: c.cookie, - random: c.state.localRandom, - cipherSuites: c.localCipherSuites, - compressionMethods: defaultCompressionMethods, - extensions: extensions, - }}, - }, false) + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(c.handshakeMessageSequence), + }, + handshakeMessage: &handshakeMessageClientHello{ + version: protocolVersion1_2, + cookie: c.cookie, + random: c.state.localRandom, + cipherSuites: c.localCipherSuites, + compressionMethods: defaultCompressionMethods, + extensions: extensions, + }}, + }, + }) + c.flushPacketBuffer() case flight5: // TODO: Better way to end handshake if c.getRemoteEpoch() != 0 && c.getLocalEpoch() == 1 { @@ -315,18 +318,20 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) { messageSequence := c.handshakeMessageSequence if c.remoteRequestedCertificate { - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, }, - handshakeMessage: &handshakeMessageCertificate{ - certificate: c.localCertificate, - }}, - }, false) + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: &handshakeMessageCertificate{ + certificate: c.localCertificate, + }}, + }, + }) messageSequence++ } @@ -337,17 +342,19 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) { clientKeyExchange.identityHint = c.localPSKIdentityHint } - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, + }, + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: clientKeyExchange, }, - handshakeMessage: clientKeyExchange, }, - }, false) + }) messageSequence++ @@ -405,29 +412,36 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) { c.localCertificateVerify = certVerify } - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, }, - handshakeMessage: &handshakeMessageCertificateVerify{ - hashAlgorithm: HashAlgorithmSHA256, - signatureAlgorithm: signatureAlgorithmECDSA, - signature: c.localCertificateVerify, - }}, - }, false) + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: &handshakeMessageCertificateVerify{ + hashAlgorithm: HashAlgorithmSHA256, + signatureAlgorithm: signatureAlgorithmECDSA, + signature: c.localCertificateVerify, + }}, + }, + }) + messageSequence++ } - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, + c.flushPacketBuffer() + + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, + }, + content: &changeCipherSpec{}, }, - content: &changeCipherSpec{}, - }, false) + }) if len(c.localVerifyData) == 0 { plainText := c.handshakeCache.pullAndMerge( @@ -450,20 +464,25 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) { } // TODO: Fix hard-coded epoch, taking retransmitting into account. - atomic.StoreUint64(&c.state.localSequenceNumber, 0) - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - epoch: 1, - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + epoch: 1, + protocolVersion: protocolVersion1_2, }, - handshakeMessage: &handshakeMessageFinished{ - verifyData: c.localVerifyData, - }}, - }, true) + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: &handshakeMessageFinished{ + verifyData: c.localVerifyData, + }}, + }, + shouldEncrypt: true, + resetLocalSequenceNumber: true, + }) + + c.flushPacketBuffer() default: return false, &alert{alertLevelFatal, alertUnexpectedMessage}, fmt.Errorf("unhandled flight %s", c.currFlight.get()) } diff --git a/conn.go b/conn.go index 4f7ae51a9..c75e339a4 100644 --- a/conn.go +++ b/conn.go @@ -82,6 +82,8 @@ type Conn struct { handshakeDoneSignal *Closer handshakeCompletedSuccessfully atomic.Value + bufferedPackets []*packet + connErr atomic.Value log logging.LeveledLogger } @@ -277,15 +279,19 @@ func (c *Conn) Write(p []byte) (int, error) { return 0, c.getConnErr() } - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - epoch: c.getLocalEpoch(), - protocolVersion: protocolVersion1_2, - }, - content: &applicationData{ - data: p, + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + epoch: c.getLocalEpoch(), + protocolVersion: protocolVersion1_2, + }, + content: &applicationData{ + data: p, + }, }, - }, true) + shouldEncrypt: true, + }) + c.flushPacketBuffer() return len(p), nil } @@ -352,11 +358,9 @@ func (c *Conn) ExportKeyingMaterial(label string, context []byte, length int) ([ return prfPHash(c.state.masterSecret, seed, length, c.state.cipherSuite.hashFunc()) } -func (c *Conn) internalSend(record *recordLayer, shouldEncrypt bool) { - var packets [][]byte - - if h, ok := record.content.(*handshake); ok { - handshakeRaw, err := record.Marshal() +func (c *Conn) bufferPacket(p *packet) { + if h, ok := p.record.content.(*handshake); ok { + handshakeRaw, err := p.record.Marshal() if err != nil { c.stopWithError(err) return @@ -364,61 +368,123 @@ func (c *Conn) internalSend(record *recordLayer, shouldEncrypt bool) { c.log.Tracef("[handshake] -> %s", h.handshakeHeader.handshakeType.String()) c.handshakeCache.push(handshakeRaw[recordLayerHeaderSize:], h.handshakeHeader.messageSequence, h.handshakeHeader.handshakeType, c.state.isClient) + } - handshakeFragments, err := c.fragmentHandshake(h) - if err != nil { - c.stopWithError(err) - return + c.bufferedPackets = append(c.bufferedPackets, p) +} + +func (c *Conn) flushPacketBuffer() { + var rawPackets [][]byte + + for _, p := range c.bufferedPackets { + if p.resetLocalSequenceNumber { + atomic.StoreUint64(&c.state.localSequenceNumber, 0) } - for _, handshakeFragment := range handshakeFragments { - recordLayerHeader := &recordLayerHeader{ - contentType: record.recordLayerHeader.contentType, - contentLen: uint16(len(handshakeFragment)), - protocolVersion: record.recordLayerHeader.protocolVersion, - epoch: record.recordLayerHeader.epoch, - sequenceNumber: atomic.LoadUint64(&c.state.localSequenceNumber), + if h, ok := p.record.content.(*handshake); ok { + rawHandshakePackets, err := c.processHandshakePacket(p, h) + if err != nil { + c.stopWithError(err) + return } - atomic.AddUint64(&c.state.localSequenceNumber, 1) - - recordLayerHeaderBytes, err := recordLayerHeader.Marshal() + rawPackets = append(rawPackets, rawHandshakePackets...) + } else { + rawPacket, err := c.processPacket(p) if err != nil { c.stopWithError(err) return } - packet := append(recordLayerHeaderBytes, handshakeFragment...) - packets = append(packets, packet) + rawPackets = [][]byte{rawPacket} } - } else { - record.recordLayerHeader.sequenceNumber = atomic.LoadUint64(&c.state.localSequenceNumber) - atomic.AddUint64(&c.state.localSequenceNumber, 1) + } - packet, err := record.Marshal() - if err != nil { + c.bufferedPackets = []*packet{} + compactedRawPackets := c.compactRawPackets(rawPackets) + + for _, compactedRawPackets := range compactedRawPackets { + if _, err := c.nextConn.Write(compactedRawPackets); err != nil { c.stopWithError(err) return } + } +} + +func (c *Conn) compactRawPackets(rawPackets [][]byte) [][]byte { + combinedRawPackets := make([][]byte, 0) + currentCombinedRawPacket := make([]byte, 0) + + for _, rawPacket := range rawPackets { + if len(currentCombinedRawPacket) > 0 && len(currentCombinedRawPacket)+len(rawPacket) >= c.maximumTransmissionUnit { + combinedRawPackets = append(combinedRawPackets, currentCombinedRawPacket) + currentCombinedRawPacket = []byte{} + } + currentCombinedRawPacket = append(currentCombinedRawPacket, rawPacket...) + } + + combinedRawPackets = append(combinedRawPackets, currentCombinedRawPacket) + + return combinedRawPackets +} + +func (c *Conn) processPacket(p *packet) ([]byte, error) { + p.record.recordLayerHeader.sequenceNumber = atomic.LoadUint64(&c.state.localSequenceNumber) + atomic.AddUint64(&c.state.localSequenceNumber, 1) + + rawPacket, err := p.record.Marshal() + if err != nil { + return nil, err + } + + if p.shouldEncrypt { + var err error + rawPacket, err = c.state.cipherSuite.encrypt(p.record, rawPacket) + if err != nil { + return nil, err + } + } + + return rawPacket, nil +} + +func (c *Conn) processHandshakePacket(p *packet, h *handshake) ([][]byte, error) { + rawPackets := make([][]byte, 0) - packets = [][]byte{packet} + handshakeFragments, err := c.fragmentHandshake(h) + if err != nil { + return nil, err } - for _, packet := range packets { - if shouldEncrypt { + for _, handshakeFragment := range handshakeFragments { + recordLayerHeader := &recordLayerHeader{ + contentType: p.record.recordLayerHeader.contentType, + contentLen: uint16(len(handshakeFragment)), + protocolVersion: p.record.recordLayerHeader.protocolVersion, + epoch: p.record.recordLayerHeader.epoch, + sequenceNumber: atomic.LoadUint64(&c.state.localSequenceNumber), + } + + atomic.AddUint64(&c.state.localSequenceNumber, 1) + + recordLayerHeaderBytes, err := recordLayerHeader.Marshal() + if err != nil { + return nil, err + } + + rawPacket := append(recordLayerHeaderBytes, handshakeFragment...) + if p.shouldEncrypt { var err error - packet, err = c.state.cipherSuite.encrypt(record, packet) + rawPacket, err = c.state.cipherSuite.encrypt(p.record, rawPacket) if err != nil { - c.stopWithError(err) - return + return nil, err } } - if _, err := c.nextConn.Write(packet); err != nil { - c.stopWithError(err) - return - } + rawPackets = append(rawPackets, rawPacket) } + + return rawPackets, nil } func (c *Conn) fragmentHandshake(h *handshake) ([][]byte, error) { @@ -582,16 +648,21 @@ func (c *Conn) notify(level alertLevel, desc alertDescription) { c.lock.Lock() defer c.lock.Unlock() - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - epoch: c.getLocalEpoch(), - protocolVersion: protocolVersion1_2, - }, - content: &alert{ - alertLevel: level, - alertDescription: desc, + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + epoch: c.getLocalEpoch(), + protocolVersion: protocolVersion1_2, + }, + content: &alert{ + alertLevel: level, + alertDescription: desc, + }, }, - }, c.isHandshakeCompletedSuccessfully()) + shouldEncrypt: c.isHandshakeCompletedSuccessfully(), + }) + c.flushPacketBuffer() + } func (c *Conn) setHandshakeCompletedSuccessfully() { diff --git a/go.sum b/go.sum index 31f51098c..1d092e06d 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf h1:fnPsqIDRbCSgumaMCRpoIoF2s4qxv0xSSS0BVZUE/ss= golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/packet.go b/packet.go new file mode 100644 index 000000000..685f2e095 --- /dev/null +++ b/packet.go @@ -0,0 +1,7 @@ +package dtls + +type packet struct { + record *recordLayer + shouldEncrypt bool + resetLocalSequenceNumber bool +} diff --git a/server_handlers.go b/server_handlers.go index 67a089f02..e63803454 100644 --- a/server_handlers.go +++ b/server_handlers.go @@ -3,7 +3,6 @@ package dtls import ( "bytes" "fmt" - "sync/atomic" ) func serverHandshakeHandler(c *Conn) (*alert, error) { @@ -276,20 +275,23 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { case flight0: // Waiting for ClientHello case flight2: - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(c.handshakeMessageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, }, - handshakeMessage: &handshakeMessageHelloVerifyRequest{ - version: protocolVersion1_2, - cookie: c.cookie, + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(c.handshakeMessageSequence), + }, + handshakeMessage: &handshakeMessageHelloVerifyRequest{ + version: protocolVersion1_2, + cookie: c.cookie, + }, }, }, - }, false) + }) + c.flushPacketBuffer() case flight4: extensions := []extension{} @@ -316,26 +318,8 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { } messageSequence := c.handshakeMessageSequence - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), - }, - handshakeMessage: &handshakeMessageServerHello{ - version: protocolVersion1_2, - random: c.state.localRandom, - cipherSuite: c.state.cipherSuite, - compressionMethod: defaultCompressionMethods[0], - extensions: extensions, - }}, - }, false) - messageSequence++ - - if c.localPSKCallback == nil { - c.internalSend(&recordLayer{ + c.bufferPacket(&packet{ + record: &recordLayer{ recordLayerHeader: recordLayerHeader{ protocolVersion: protocolVersion1_2, }, @@ -343,10 +327,32 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { handshakeHeader: handshakeHeader{ messageSequence: uint16(messageSequence), }, - handshakeMessage: &handshakeMessageCertificate{ - certificate: c.localCertificate, + handshakeMessage: &handshakeMessageServerHello{ + version: protocolVersion1_2, + random: c.state.localRandom, + cipherSuite: c.state.cipherSuite, + compressionMethod: defaultCompressionMethods[0], + extensions: extensions, }}, - }, false) + }, + }) + messageSequence++ + + if c.localPSKCallback == nil { + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, + }, + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: &handshakeMessageCertificate{ + certificate: c.localCertificate, + }}, + }, + }) messageSequence++ if len(c.localKeySignature) == 0 { @@ -366,27 +372,8 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { c.localKeySignature = signature } - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), - }, - handshakeMessage: &handshakeMessageServerKeyExchange{ - ellipticCurveType: ellipticCurveTypeNamedCurve, - namedCurve: c.namedCurve, - publicKey: c.localKeypair.publicKey, - hashAlgorithm: HashAlgorithmSHA256, - signatureAlgorithm: signatureAlgorithmECDSA, - signature: c.localKeySignature, - }}, - }, false) - messageSequence++ - - if c.clientAuth > NoClientCert { - c.internalSend(&recordLayer{ + c.bufferPacket(&packet{ + record: &recordLayer{ recordLayerHeader: recordLayerHeader{ protocolVersion: protocolVersion1_2, }, @@ -394,19 +381,42 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { handshakeHeader: handshakeHeader{ messageSequence: uint16(messageSequence), }, - handshakeMessage: &handshakeMessageCertificateRequest{ - certificateTypes: []clientCertificateType{clientCertificateTypeRSASign, clientCertificateTypeECDSASign}, - signatureHashAlgorithms: []signatureHashAlgorithm{ - {HashAlgorithmSHA256, signatureAlgorithmRSA}, - {HashAlgorithmSHA384, signatureAlgorithmRSA}, - {HashAlgorithmSHA512, signatureAlgorithmRSA}, - {HashAlgorithmSHA256, signatureAlgorithmECDSA}, - {HashAlgorithmSHA384, signatureAlgorithmECDSA}, - {HashAlgorithmSHA512, signatureAlgorithmECDSA}, + handshakeMessage: &handshakeMessageServerKeyExchange{ + ellipticCurveType: ellipticCurveTypeNamedCurve, + namedCurve: c.namedCurve, + publicKey: c.localKeypair.publicKey, + hashAlgorithm: HashAlgorithmSHA256, + signatureAlgorithm: signatureAlgorithmECDSA, + signature: c.localKeySignature, + }}, + }, + }) + messageSequence++ + + if c.clientAuth > NoClientCert { + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, + }, + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: &handshakeMessageCertificateRequest{ + certificateTypes: []clientCertificateType{clientCertificateTypeRSASign, clientCertificateTypeECDSASign}, + signatureHashAlgorithms: []signatureHashAlgorithm{ + {HashAlgorithmSHA256, signatureAlgorithmRSA}, + {HashAlgorithmSHA384, signatureAlgorithmRSA}, + {HashAlgorithmSHA512, signatureAlgorithmRSA}, + {HashAlgorithmSHA256, signatureAlgorithmECDSA}, + {HashAlgorithmSHA384, signatureAlgorithmECDSA}, + {HashAlgorithmSHA512, signatureAlgorithmECDSA}, + }, }, }, }, - }, false) + }) messageSequence++ } } else if c.localPSKIdentityHint != nil { @@ -416,7 +426,25 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { * * https://tools.ietf.org/html/rfc4279#section-2 */ - c.internalSend(&recordLayer{ + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, + }, + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(messageSequence), + }, + handshakeMessage: &handshakeMessageServerKeyExchange{ + identityHint: c.localPSKIdentityHint, + }}, + }, + }) + messageSequence++ + } + + c.bufferPacket(&packet{ + record: &recordLayer{ recordLayerHeader: recordLayerHeader{ protocolVersion: protocolVersion1_2, }, @@ -424,31 +452,21 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { handshakeHeader: handshakeHeader{ messageSequence: uint16(messageSequence), }, - handshakeMessage: &handshakeMessageServerKeyExchange{ - identityHint: c.localPSKIdentityHint, - }}, - }, false) - messageSequence++ - } - - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(messageSequence), + handshakeMessage: &handshakeMessageServerHelloDone{}, }, - handshakeMessage: &handshakeMessageServerHelloDone{}, }, - }, false) + }) + + c.flushPacketBuffer() case flight6: - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - protocolVersion: protocolVersion1_2, + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + protocolVersion: protocolVersion1_2, + }, + content: &changeCipherSpec{}, }, - content: &changeCipherSpec{}, - }, false) + }) if len(c.localVerifyData) == 0 { plainText := c.handshakeCache.pullAndMerge( @@ -471,21 +489,26 @@ func serverFlightHandler(c *Conn) (bool, *alert, error) { } } - atomic.StoreUint64(&c.state.localSequenceNumber, 0) - c.internalSend(&recordLayer{ - recordLayerHeader: recordLayerHeader{ - epoch: 1, - protocolVersion: protocolVersion1_2, - }, - content: &handshake{ - handshakeHeader: handshakeHeader{ - messageSequence: uint16(c.handshakeMessageSequence), + c.bufferPacket(&packet{ + record: &recordLayer{ + recordLayerHeader: recordLayerHeader{ + epoch: 1, + protocolVersion: protocolVersion1_2, }, + content: &handshake{ + handshakeHeader: handshakeHeader{ + messageSequence: uint16(c.handshakeMessageSequence), + }, + + handshakeMessage: &handshakeMessageFinished{ + verifyData: c.localVerifyData, + }}, + }, + shouldEncrypt: true, + resetLocalSequenceNumber: true, + }) - handshakeMessage: &handshakeMessageFinished{ - verifyData: c.localVerifyData, - }}, - }, true) + c.flushPacketBuffer() c.handshakeDoneSignal.Close() return true, nil, nil