tris: implement draft-22 middlebox compatibility mode
Send/Skip CCS, set legacy record version to 3,3 and echo session ID. CCS must be ignored while the handshake is running, but not thereafter: https://tools.ietf.org/html/draft-ietf-tls-tls13-22#section-5 Unconditionally send CCS as server because bogo requires it, even if no session ID is included in the Client Hello. TLS 1.3 clients MUST ignore it anyway, so it should not hurt. Fixes interop with boringssl and openssl and passes bogo.
This commit is contained in:
parent
a0bab1759d
commit
824987c5ad
11
13.go
11
13.go
@ -197,6 +197,11 @@ CurvePreferenceLoop:
|
|||||||
return err
|
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)
|
hs.keySchedule.setSecret(ecdheSecret)
|
||||||
clientCipher, cTrafficSecret := hs.keySchedule.prepareCipher(secretHandshakeClient)
|
clientCipher, cTrafficSecret := hs.keySchedule.prepareCipher(secretHandshakeClient)
|
||||||
hs.hsClientCipher = clientCipher
|
hs.hsClientCipher = clientCipher
|
||||||
@ -792,6 +797,12 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
|
|||||||
hash := hashForSuite(hs.suite)
|
hash := hashForSuite(hs.suite)
|
||||||
hashSize := hash.Size()
|
hashSize := hash.Size()
|
||||||
serverHello := hs.serverHello
|
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.
|
// TODO check if keyshare is unacceptable, raise HRR.
|
||||||
|
|
||||||
clientKS := hs.hello.keyShares[0]
|
clientKS := hs.hello.keyShares[0]
|
||||||
|
15
conn.go
15
conn.go
@ -713,6 +713,16 @@ Again:
|
|||||||
|
|
||||||
// Process message.
|
// Process message.
|
||||||
b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
|
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
|
peekedAlert := peekAlert(b) // peek at a possible alert before decryption
|
||||||
ok, off, alertValue := c.in.decrypt(b)
|
ok, off, alertValue := c.in.decrypt(b)
|
||||||
switch {
|
switch {
|
||||||
@ -1044,7 +1054,8 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
|
|||||||
if c.vers >= VersionTLS13 {
|
if c.vers >= VersionTLS13 {
|
||||||
// TLS 1.3 froze the record layer version at { 3, 1 }.
|
// 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.
|
// 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[1] = byte(vers >> 8)
|
||||||
b.data[2] = byte(vers)
|
b.data[2] = byte(vers)
|
||||||
@ -1069,7 +1080,7 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
|
|||||||
data = data[m:]
|
data = data[m:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if typ == recordTypeChangeCipherSpec {
|
if typ == recordTypeChangeCipherSpec && c.vers < VersionTLS13 {
|
||||||
if err := c.out.changeCipherSpec(); err != nil {
|
if err := c.out.changeCipherSpec(); err != nil {
|
||||||
return n, c.sendAlertLocked(err.(alert))
|
return n, c.sendAlertLocked(err.(alert))
|
||||||
}
|
}
|
||||||
|
@ -197,6 +197,11 @@ func (c *Conn) clientHandshake() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hello.keyShares = []keyShare{clientKS}
|
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 {
|
if err = hs.handshake(); err != nil {
|
||||||
|
@ -262,6 +262,7 @@ Curves:
|
|||||||
hs.hello13Enc = new(encryptedExtensionsMsg)
|
hs.hello13Enc = new(encryptedExtensionsMsg)
|
||||||
hs.hello.vers = c.vers
|
hs.hello.vers = c.vers
|
||||||
hs.hello.random = make([]byte, 32)
|
hs.hello.random = make([]byte, 32)
|
||||||
|
hs.hello.sessionId = hs.clientHello.sessionId
|
||||||
_, err = io.ReadFull(c.config.rand(), hs.hello.random)
|
_, err = io.ReadFull(c.config.rand(), hs.hello.random)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendAlert(alertInternalError)
|
c.sendAlert(alertInternalError)
|
||||||
|
Loading…
Reference in New Issue
Block a user