diff --git a/13.go b/13.go index 58e534f..98f037b 100644 --- a/13.go +++ b/13.go @@ -197,6 +197,11 @@ CurvePreferenceLoop: return err } + // middlebox compatibility mode: send CCS after first handshake message + if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { + return err + } + hs.keySchedule.setSecret(ecdheSecret) clientCipher, cTrafficSecret := hs.keySchedule.prepareCipher(secretHandshakeClient) hs.hsClientCipher = clientCipher @@ -792,6 +797,12 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { hash := hashForSuite(hs.suite) hashSize := hash.Size() serverHello := hs.serverHello + + // middlebox compatibility mode, send CCS before second flight. + if _, err := c.writeRecord(recordTypeChangeCipherSpec, []byte{1}); err != nil { + return err + } + // TODO check if keyshare is unacceptable, raise HRR. clientKS := hs.hello.keyShares[0] diff --git a/conn.go b/conn.go index a8d4ed2..b252cbf 100644 --- a/conn.go +++ b/conn.go @@ -713,6 +713,16 @@ Again: // Process message. b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n) + + // TLS 1.3 middlebox compatibility: skip over unencrypted CCS. + if c.vers >= VersionTLS13 && typ == recordTypeChangeCipherSpec && c.phase != handshakeConfirmed { + if len(b.data) != 6 || b.data[5] != 1 { + c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage)) + } + c.in.freeBlock(b) + return c.in.err + } + peekedAlert := peekAlert(b) // peek at a possible alert before decryption ok, off, alertValue := c.in.decrypt(b) switch { @@ -1044,7 +1054,8 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { if c.vers >= VersionTLS13 { // TLS 1.3 froze the record layer version at { 3, 1 }. // See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.1. - vers = VersionTLS10 + // But for draft 22, this was changed to { 3, 3 }. + vers = VersionTLS12 } b.data[1] = byte(vers >> 8) b.data[2] = byte(vers) @@ -1069,7 +1080,7 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { data = data[m:] } - if typ == recordTypeChangeCipherSpec { + if typ == recordTypeChangeCipherSpec && c.vers < VersionTLS13 { if err := c.out.changeCipherSpec(); err != nil { return n, c.sendAlertLocked(err.(alert)) } diff --git a/handshake_client.go b/handshake_client.go index c328fdd..d1264c4 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -197,6 +197,11 @@ func (c *Conn) clientHandshake() error { return err } hello.keyShares = []keyShare{clientKS} + // middlebox compatibility mode, provide a non-empty session ID + hello.sessionId = make([]byte, 16) + if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil { + return errors.New("tls: short read from Rand: " + err.Error()) + } } if err = hs.handshake(); err != nil { diff --git a/handshake_server.go b/handshake_server.go index fc129ec..48d4389 100644 --- a/handshake_server.go +++ b/handshake_server.go @@ -262,6 +262,7 @@ Curves: hs.hello13Enc = new(encryptedExtensionsMsg) hs.hello.vers = c.vers hs.hello.random = make([]byte, 32) + hs.hello.sessionId = hs.clientHello.sessionId _, err = io.ReadFull(c.config.rand(), hs.hello.random) if err != nil { c.sendAlert(alertInternalError)