Add TLS 1.3 record layer to go implementation.
This implements the cipher suite constraints in "fake TLS 1.3". It also makes
bssl_shim and runner enable it by default so we can start adding MaxVersion:
VersionTLS12 markers to tests as 1.2 vs. 1.3 differences begin to take effect.
Change-Id: If1caf6e43938c8d15b0a0f39f40963b8199dcef5
Reviewed-on: https://boringssl-review.googlesource.com/8340
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 3913995..3f406bb 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -345,8 +345,9 @@
// decrypt checks and strips the mac and decrypts the data in b. Returns a
// success boolean, the number of bytes to skip from the start of the record in
-// order to get the application payload, and an optional alert value.
-func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert) {
+// order to get the application payload, the encrypted record type (or 0
+// if there is none), and an optional alert value.
+func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, contentType recordType, alertValue alert) {
recordHeaderLen := hc.recordHeaderLen()
// pull out payload
@@ -376,22 +377,37 @@
if c.explicitNonce {
explicitIVLen = 8
if len(payload) < explicitIVLen {
- return false, 0, alertBadRecordMAC
+ return false, 0, 0, alertBadRecordMAC
}
nonce = payload[:8]
payload = payload[8:]
}
- var additionalData [13]byte
- copy(additionalData[:], seq)
- copy(additionalData[8:], b.data[:3])
- n := len(payload) - c.Overhead()
- additionalData[11] = byte(n >> 8)
- additionalData[12] = byte(n)
+ var additionalData []byte
+ if hc.version < VersionTLS13 {
+ additionalData = make([]byte, 13)
+ copy(additionalData, seq)
+ copy(additionalData[8:], b.data[:3])
+ n := len(payload) - c.Overhead()
+ additionalData[11] = byte(n >> 8)
+ additionalData[12] = byte(n)
+ }
var err error
- payload, err = c.Open(payload[:0], nonce, payload, additionalData[:])
+ payload, err = c.Open(payload[:0], nonce, payload, additionalData)
if err != nil {
- return false, 0, alertBadRecordMAC
+ return false, 0, 0, alertBadRecordMAC
+ }
+ if hc.version >= VersionTLS13 {
+ i := len(payload)
+ for i > 0 && payload[i-1] == 0 {
+ i--
+ }
+ payload = payload[:i]
+ if len(payload) == 0 {
+ return false, 0, 0, alertUnexpectedMessage
+ }
+ contentType = recordType(payload[len(payload)-1])
+ payload = payload[:len(payload)-1]
}
b.resize(recordHeaderLen + explicitIVLen + len(payload))
case cbcMode:
@@ -401,7 +417,7 @@
}
if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) {
- return false, 0, alertBadRecordMAC
+ return false, 0, 0, alertBadRecordMAC
}
if explicitIVLen > 0 {
@@ -436,7 +452,7 @@
// check, strip mac
if hc.mac != nil {
if len(payload) < macSize {
- return false, 0, alertBadRecordMAC
+ return false, 0, 0, alertBadRecordMAC
}
// strip mac off payload, b.data
@@ -448,13 +464,13 @@
localMAC := hc.mac.MAC(hc.inDigestBuf, seq, b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], payload[:n])
if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
- return false, 0, alertBadRecordMAC
+ return false, 0, 0, alertBadRecordMAC
}
hc.inDigestBuf = localMAC
}
hc.incSeq(false)
- return true, recordHeaderLen + explicitIVLen, 0
+ return true, recordHeaderLen + explicitIVLen, contentType, 0
}
// padToBlockSize calculates the needed padding block, if any, for a payload.
@@ -486,7 +502,7 @@
}
// encrypt encrypts and macs the data in b.
-func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
+func (hc *halfConn) encrypt(b *block, explicitIVLen int, typ recordType) (bool, alert) {
recordHeaderLen := hc.recordHeaderLen()
// mac
@@ -507,8 +523,18 @@
case cipher.Stream:
c.XORKeyStream(payload, payload)
case *tlsAead:
+ contentTypeLen := 0
+ if hc.version >= VersionTLS13 {
+ contentTypeLen = 1
+ }
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
- b.resize(len(b.data) + c.Overhead())
+ b.resize(len(b.data) + contentTypeLen + c.Overhead())
+ if hc.version >= VersionTLS13 {
+ b.data[payloadLen+recordHeaderLen] = byte(typ)
+ payloadLen += 1
+ // TODO(nharper): Add ProtocolBugs to add
+ // padding.
+ }
nonce := hc.outSeq[:]
if c.explicitNonce {
nonce = b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
@@ -516,13 +542,16 @@
payload := b.data[recordHeaderLen+explicitIVLen:]
payload = payload[:payloadLen]
- var additionalData [13]byte
- copy(additionalData[:], hc.outSeq[:])
- copy(additionalData[8:], b.data[:3])
- additionalData[11] = byte(payloadLen >> 8)
- additionalData[12] = byte(payloadLen)
+ var additionalData []byte
+ if hc.version < VersionTLS13 {
+ additionalData = make([]byte, 13)
+ copy(additionalData, hc.outSeq[:])
+ copy(additionalData[8:], b.data[:3])
+ additionalData[11] = byte(payloadLen >> 8)
+ additionalData[12] = byte(payloadLen)
+ }
- c.Seal(payload[:0], nonce, payload, additionalData[:])
+ c.Seal(payload[:0], nonce, payload, additionalData)
case cbcMode:
blockSize := c.BlockSize()
if explicitIVLen > 0 {
@@ -686,7 +715,7 @@
vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4])
if c.haveVers {
- if vers != c.vers {
+ if vers != c.vers && c.vers < VersionTLS13 {
c.sendAlert(alertProtocolVersion)
return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
}
@@ -726,7 +755,12 @@
// Process message.
b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
- ok, off, err := c.in.decrypt(b)
+ ok, off, encTyp, err := c.in.decrypt(b)
+ if c.vers >= VersionTLS13 && c.in.cipher != nil {
+ // TODO(nharper): Check that outer type (typ) is
+ // application data.
+ typ = encTyp
+ }
if !ok {
c.in.setErrorLocked(c.sendAlert(err))
}
@@ -931,10 +965,17 @@
}
b.resize(recordHeaderLen + explicitIVLen + m)
b.data[0] = byte(typ)
+ if c.vers >= VersionTLS13 && c.out.cipher != nil {
+ // TODO(nharper): Add a ProtocolBugs to skip this.
+ b.data[0] = byte(recordTypeApplicationData)
+ }
vers := c.vers
- if vers == 0 {
+ if vers == 0 || vers >= VersionTLS13 {
// Some TLS servers fail if the record version is
// greater than TLS 1.0 for the initial ClientHello.
+ //
+ // TLS 1.3 fixes the version number in the record
+ // layer to {3, 1}.
vers = VersionTLS10
}
b.data[1] = byte(vers >> 8)
@@ -952,7 +993,7 @@
}
}
copy(b.data[recordHeaderLen+explicitIVLen:], data)
- c.out.encrypt(b, explicitIVLen)
+ c.out.encrypt(b, explicitIVLen, typ)
_, err = c.conn.Write(b.data)
if err != nil {
break