[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 提交者 Peter Wu
父節點 b0bcb44715
當前提交 7743362eba
共有 3 個檔案被更改,包括 64 行新增21 行删除

查看文件

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

82
conn.go
查看文件

@ -297,13 +297,17 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
nonce = hc.seq[:]
}
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
n := len(payload) - c.Overhead()
hc.additionalData[11] = byte(n >> 8)
hc.additionalData[12] = byte(n)
var additionalData []byte
if hc.version < VersionTLS13 {
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
n := len(payload) - c.Overhead()
hc.additionalData[11] = byte(n >> 8)
hc.additionalData[12] = byte(n)
additionalData = hc.additionalData[:]
}
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 {
return false, 0, alertBadRecordMAC
}
@ -404,20 +408,36 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
c.XORKeyStream(payload, payload)
case aead:
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]
if len(nonce) == 0 {
nonce = hc.seq[:]
}
payload := b.data[recordHeaderLen+explicitIVLen:]
payload = b.data[recordHeaderLen+explicitIVLen:]
payload = payload[:payloadLen]
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
hc.additionalData[11] = byte(payloadLen >> 8)
hc.additionalData[12] = byte(payloadLen)
var additionalData []byte
if hc.version < VersionTLS13 {
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
hc.additionalData[11] = byte(payloadLen >> 8)
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:
blockSize := c.BlockSize()
if explicitIVLen > 0 {
@ -612,11 +632,6 @@ Again:
vers := uint16(b.data[1])<<8 | uint16(b.data[2])
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 {
c.sendAlert(alertRecordOverflow)
msg := fmt.Sprintf("oversized record received with length %d", n)
@ -652,9 +667,28 @@ Again:
b.off = off
data := b.data[b.off:]
if len(data) > maxPlaintext {
err := c.sendAlert(alertRecordOverflow)
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 {
@ -795,6 +829,9 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
payloadBytes -= macSize
case cipher.AEAD:
payloadBytes -= ciph.Overhead()
if c.vers >= VersionTLS13 {
payloadBytes -= 1 // ContentType
}
case cbcMode:
blockSize := ciph.BlockSize()
// 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.
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[2] = byte(vers)
b.data[3] = byte(m >> 8)

查看文件

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