[dev.tls] crypto/tls: implement TLS 1.3 record layer

Opening the 1.3 dances with the record layer because it has been the
most stable through the drafts, has the least dependencies, and has been
tricky in my experience.

Note that the record layer version check is entirely removed according
to https://tools.ietf.org/html/draft-ietf-tls-tls13-18#appendix-C.2.

A test that happened to hit that check (but was not made to test for it)
has changed to the next error in the stack.

There are no 1.3 tests at the moment, and I suspect they will all have to
wait for the patch cycle to reach interoperability.

Using > / <= VersionTLS13 for all conditionals to transparently support
draft versions and hypotetical future versions.

See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.

Updates #9671

Change-Id: I97f0a59439728f194a1c50b48cff041469a0f00b
This commit is contained in:
Filippo Valsorda 2016-11-12 12:35:50 -08:00 committed by Peter Wu
parent b0bcb44715
commit 7743362eba
3 changed files with 64 additions and 21 deletions

View File

@ -26,6 +26,7 @@ const (
VersionTLS10 = 0x0301 VersionTLS10 = 0x0301
VersionTLS11 = 0x0302 VersionTLS11 = 0x0302
VersionTLS12 = 0x0303 VersionTLS12 = 0x0303
VersionTLS13 = 0x0304
) )
const ( const (

64
conn.go
View File

@ -297,13 +297,17 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
nonce = hc.seq[:] nonce = hc.seq[:]
} }
var additionalData []byte
if hc.version < VersionTLS13 {
copy(hc.additionalData[:], hc.seq[:]) copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3]) copy(hc.additionalData[8:], b.data[:3])
n := len(payload) - c.Overhead() n := len(payload) - c.Overhead()
hc.additionalData[11] = byte(n >> 8) hc.additionalData[11] = byte(n >> 8)
hc.additionalData[12] = byte(n) hc.additionalData[12] = byte(n)
additionalData = hc.additionalData[:]
}
var err error var err error
payload, err = c.Open(payload[:0], nonce, payload, hc.additionalData[:]) payload, err = c.Open(payload[:0], nonce, payload, additionalData)
if err != nil { if err != nil {
return false, 0, alertBadRecordMAC return false, 0, alertBadRecordMAC
} }
@ -404,20 +408,36 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
c.XORKeyStream(payload, payload) c.XORKeyStream(payload, payload)
case aead: case aead:
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
b.resize(len(b.data) + c.Overhead()) overhead := c.Overhead()
if hc.version >= VersionTLS13 {
overhead++
}
b.resize(len(b.data) + overhead)
nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen] nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
if len(nonce) == 0 { if len(nonce) == 0 {
nonce = hc.seq[:] nonce = hc.seq[:]
} }
payload := b.data[recordHeaderLen+explicitIVLen:] payload = b.data[recordHeaderLen+explicitIVLen:]
payload = payload[:payloadLen] payload = payload[:payloadLen]
var additionalData []byte
if hc.version < VersionTLS13 {
copy(hc.additionalData[:], hc.seq[:]) copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3]) copy(hc.additionalData[8:], b.data[:3])
hc.additionalData[11] = byte(payloadLen >> 8) hc.additionalData[11] = byte(payloadLen >> 8)
hc.additionalData[12] = byte(payloadLen) hc.additionalData[12] = byte(payloadLen)
additionalData = hc.additionalData[:]
}
c.Seal(payload[:0], nonce, payload, hc.additionalData[:]) if hc.version >= VersionTLS13 {
// opaque type
payload = payload[:len(payload)+1]
payload[len(payload)-1] = b.data[0]
b.data[0] = byte(recordTypeApplicationData)
}
c.Seal(payload[:0], nonce, payload, additionalData)
case cbcMode: case cbcMode:
blockSize := c.BlockSize() blockSize := c.BlockSize()
if explicitIVLen > 0 { if explicitIVLen > 0 {
@ -612,11 +632,6 @@ Again:
vers := uint16(b.data[1])<<8 | uint16(b.data[2]) vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4]) n := int(b.data[3])<<8 | int(b.data[4])
if c.haveVers && vers != c.vers {
c.sendAlert(alertProtocolVersion)
msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers)
return c.in.setErrorLocked(c.newRecordHeaderError(msg))
}
if n > maxCiphertext { if n > maxCiphertext {
c.sendAlert(alertRecordOverflow) c.sendAlert(alertRecordOverflow)
msg := fmt.Sprintf("oversized record received with length %d", n) msg := fmt.Sprintf("oversized record received with length %d", n)
@ -652,9 +667,28 @@ Again:
b.off = off b.off = off
data := b.data[b.off:] data := b.data[b.off:]
if len(data) > maxPlaintext { if len(data) > maxPlaintext {
err := c.sendAlert(alertRecordOverflow)
c.in.freeBlock(b) c.in.freeBlock(b)
return c.in.setErrorLocked(err) return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow))
}
// After checking the plaintext length, remove 1.3 padding and
// extract the real content type.
// See https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-5.4.
if c.vers >= VersionTLS13 {
i := len(data) - 1
for i >= 0 {
if data[i] != 0 {
break
}
i--
}
if i < 0 {
c.in.freeBlock(b)
return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
typ = recordType(data[i])
data = data[:i]
b.resize(b.off + i) // shrinks, guaranteed not to reallocate
} }
switch typ { switch typ {
@ -795,6 +829,9 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
payloadBytes -= macSize payloadBytes -= macSize
case cipher.AEAD: case cipher.AEAD:
payloadBytes -= ciph.Overhead() payloadBytes -= ciph.Overhead()
if c.vers >= VersionTLS13 {
payloadBytes -= 1 // ContentType
}
case cbcMode: case cbcMode:
blockSize := ciph.BlockSize() blockSize := ciph.BlockSize()
// The payload must fit in a multiple of blockSize, with // The payload must fit in a multiple of blockSize, with
@ -890,6 +927,11 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
// greater than TLS 1.0 for the initial ClientHello. // greater than TLS 1.0 for the initial ClientHello.
vers = VersionTLS10 vers = VersionTLS10
} }
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
}
b.data[1] = byte(vers >> 8) b.data[1] = byte(vers >> 8)
b.data[2] = byte(vers) b.data[2] = byte(vers)
b.data[3] = byte(m >> 8) b.data[3] = byte(m >> 8)

View File

@ -1173,7 +1173,7 @@ var getConfigForClientTests = []struct {
config.MaxVersion = VersionTLS11 config.MaxVersion = VersionTLS11
return config, nil return config, nil
}, },
"version 301 when expecting version 302", "protocol version not supported",
nil, nil,
}, },
{ {