runner: Remove block pool
runner is a fork from a very old version of Go's crypto/tls. Back then,
crypto/tls implemented some pooled memory thing to reduce allocations.
The abstraction is pretty confusing.
Replace it with (I think) more idiomatic patterns using []byte and
bytes.Buffer. As part of this, I've moved things common to TLS and DTLS
into the encrypt method so encrypt is now responsible for generating the
explicit IV and adding TLS 1.3 padding.
Change-Id: I21527dd406d2691bc5d24378a832114c43b8b753
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/71367
Reviewed-by: Nick Harper <nharper@chromium.org>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 21c2991..9c775e9 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1997,8 +1997,9 @@
// session ID in the ServerHello.
DTLS13EchoSessionID bool
- // DTLSUsePlaintextRecord header, if true, has DTLS connections never
- // use the DTLS 1.3 record header.
+ // DTLSUsePlaintextRecord header, if true, has DTLS 1.3 connections to use
+ // the DTLS 1.2 record header once the handshake completes. The bug is not
+ // activated during the handshake so that the handshake can complete first.
DTLSUsePlaintextRecordHeader bool
// DTLS13RecordHeaderSetCIDBit, if true, sets the Connection ID bit in
@@ -2248,13 +2249,6 @@
return supportedSignatureAlgorithms
}
-// A TLS record.
-type record struct {
- contentType recordType
- major, minor uint8
- payload []byte
-}
-
type handshakeMessage interface {
marshal() []byte
unmarshal([]byte) bool
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 29ac87d..3287b01 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -18,6 +18,7 @@
"fmt"
"io"
"net"
+ "slices"
"sync"
"time"
@@ -96,8 +97,8 @@
// input/output
in, out halfConn // in.Mutex < out.Mutex
- rawInput *block // raw input, right off the wire
- input *block // application record waiting to be read
+ rawInput bytes.Buffer // raw input, right off the wire
+ input bytes.Buffer // application record waiting to be read
hand bytes.Buffer // handshake record waiting to be read
// pendingFlight, if PackHandshakeFlight is enabled, is the buffer of
@@ -188,14 +189,13 @@
mac macFunction
seq [8]byte // 64-bit sequence number
outSeq [8]byte // Mapped sequence number
- bfree *block // list of free blocks
nextCipher any // next encryption state
nextMac macFunction // next MAC algorithm
nextSeq [6]byte // next epoch's starting sequence number in DTLS
// used to save allocating a new buffer for each MAC.
- inDigestBuf, outDigestBuf []byte
+ macBuf []byte
trafficSecret []byte
@@ -376,33 +376,33 @@
copy(hc.outSeq[:], hc.seq[:])
}
-// writeRecordHeaderLen returns the length of the record header that will be
-// written. Do not use this for the length of a record header when reading, as
-// that can depend on the bytes read.
-func (hc *halfConn) writeRecordHeaderLen() int {
- if hc.isDTLS {
- usePlaintextHeader := hc.config.Bugs.DTLSUsePlaintextRecordHeader && hc.conn.handshakeComplete
- if hc.version >= VersionTLS13 && hc.cipher != nil && !usePlaintextHeader {
- // The DTLS 1.3 record header consists of a
- // demultiplexing/type byte, some number of connection
- // ID bytes, 1 or 2 sequence number bytes, and 0 or 2
- // length bytes. Configuration options or protocol bugs
- // will change these values to test all options of the
- // DTLS 1.3 record header.
- cidSize := 0
- seqSize := 2
- if hc.config.DTLSUseShortSeqNums {
- seqSize = 1
- }
- lenSize := 2
- if hc.config.DTLSRecordHeaderOmitLength {
- lenSize = 0
- }
- return 1 + cidSize + seqSize + lenSize
- }
- return dtlsMaxRecordHeaderLen
+func (hc *halfConn) explicitIVLen() int {
+ if hc.cipher == nil {
+ return 0
}
- return tlsRecordHeaderLen
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ return 0
+ case *tlsAead:
+ if c.explicitNonce {
+ return 8
+ }
+ return 0
+ case cbcMode:
+ if hc.version >= VersionTLS11 || hc.isDTLS {
+ return c.BlockSize()
+ }
+ return 0
+ case nullCipher:
+ return 0
+ default:
+ panic("unknown cipher type")
+ }
+}
+
+func (hc *halfConn) computeMAC(seq, header, data []byte) []byte {
+ hc.macBuf = hc.mac.MAC(hc.macBuf[:0], seq, header[:3], header[len(header)-2:], data)
+ return hc.macBuf
}
// removePadding returns an unpadded slice, in constant time, which is a prefix
@@ -453,13 +453,13 @@
SetIV([]byte)
}
-// 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, the encrypted record type (or 0
-// if there is none), and an optional alert value.
-func (hc *halfConn) decrypt(seq []byte, recordHeaderLen int, b *block) (ok bool, prefixLen int, contentType recordType, alertValue alert) {
+// decrypt checks and strips the mac and decrypts the data in record. Returns a
+// success boolean, the application payload, the encrypted record type (or 0
+// if there is none), and an optional alert value. Decryption occurs in-place,
+// so the contents of record will be overwritten as part of this process.
+func (hc *halfConn) decrypt(seq []byte, recordHeaderLen int, record []byte) (ok bool, contentType recordType, data []byte, alertValue alert) {
// pull out payload
- payload := b.data[recordHeaderLen:]
+ payload := record[recordHeaderLen:]
macSize := 0
if hc.mac != nil {
@@ -467,7 +467,7 @@
}
paddingGood := byte(255)
- explicitIVLen := 0
+ explicitIVLen := hc.explicitIVLen()
// decrypt
if hc.cipher != nil {
@@ -476,40 +476,34 @@
c.XORKeyStream(payload, payload)
case *tlsAead:
nonce := seq
- if c.explicitNonce {
- explicitIVLen = 8
+ if explicitIVLen != 0 {
if len(payload) < explicitIVLen {
- return false, 0, 0, alertBadRecordMAC
+ return false, 0, nil, alertBadRecordMAC
}
- nonce = payload[:8]
- payload = payload[8:]
+ nonce = payload[:explicitIVLen]
+ payload = payload[explicitIVLen:]
}
var additionalData []byte
if hc.version < VersionTLS13 {
additionalData = make([]byte, 13)
copy(additionalData, seq)
- copy(additionalData[8:], b.data[:3])
+ copy(additionalData[8:], record[:3])
n := len(payload) - c.Overhead()
additionalData[11] = byte(n >> 8)
additionalData[12] = byte(n)
} else {
- additionalData = b.data[:recordHeaderLen]
+ additionalData = record[:recordHeaderLen]
}
var err error
payload, err = c.Open(payload[:0], nonce, payload, additionalData)
if err != nil {
- return false, 0, 0, alertBadRecordMAC
+ return false, 0, nil, alertBadRecordMAC
}
- b.resize(recordHeaderLen + explicitIVLen + len(payload))
case cbcMode:
blockSize := c.BlockSize()
- if hc.version >= VersionTLS11 || hc.isDTLS {
- explicitIVLen = blockSize
- }
-
if len(payload)%blockSize != 0 || len(payload) < roundUp(explicitIVLen+macSize+1, blockSize) {
- return false, 0, 0, alertBadRecordMAC
+ return false, 0, nil, alertBadRecordMAC
}
if explicitIVLen > 0 {
@@ -518,7 +512,6 @@
}
c.CryptBlocks(payload, payload)
payload, paddingGood = removePadding(payload)
- b.resize(recordHeaderLen + explicitIVLen + len(payload))
// note that we still have a timing side-channel in the
// MAC check, below. An attacker can align the record
@@ -543,125 +536,193 @@
}
payload = payload[:i]
if len(payload) == 0 {
- return false, 0, 0, alertUnexpectedMessage
+ return false, 0, nil, alertUnexpectedMessage
}
contentType = recordType(payload[len(payload)-1])
payload = payload[:len(payload)-1]
- b.resize(recordHeaderLen + len(payload))
}
}
// check, strip mac
if hc.mac != nil {
if len(payload) < macSize {
- return false, 0, 0, alertBadRecordMAC
+ return false, 0, nil, alertBadRecordMAC
}
- // strip mac off payload, b.data
+ // strip mac off payload
n := len(payload) - macSize
- b.data[recordHeaderLen-2] = byte(n >> 8)
- b.data[recordHeaderLen-1] = byte(n)
- b.resize(recordHeaderLen + explicitIVLen + n)
remoteMAC := payload[n:]
- localMAC := hc.mac.MAC(hc.inDigestBuf, seq, b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], payload[:n])
-
+ payload = payload[:n]
+ record[recordHeaderLen-2] = byte(n >> 8)
+ record[recordHeaderLen-1] = byte(n)
+ localMAC := hc.computeMAC(seq, record[:recordHeaderLen], payload)
if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
- return false, 0, 0, alertBadRecordMAC
+ return false, 0, nil, alertBadRecordMAC
}
- hc.inDigestBuf = localMAC
}
hc.incSeq(false)
- return true, recordHeaderLen + explicitIVLen, contentType, 0
+ return true, contentType, payload, 0
}
-// padToBlockSize calculates the needed padding block, if any, for a payload.
-// On exit, prefix aliases payload and extends to the end of the last full
-// block of payload. finalBlock is a fresh slice which contains the contents of
-// any suffix of payload as well as the needed padding to make finalBlock a
-// full block.
-func padToBlockSize(payload []byte, blockSize int, config *Config) (prefix, finalBlock []byte) {
- overrun := len(payload) % blockSize
- prefix = payload[:len(payload)-overrun]
+// extendSlice updates *data to contain n more bytes and returns a slice
+// containing the bytes that were added.
+func extendSlice(data *[]byte, n int) []byte {
+ // Reallocate the slice if needed.
+ *data = slices.Grow(*data, n)
+ // Extend data into the capacity and return the newly added slice.
+ oldLen := len(*data)
+ newLen := oldLen + n
+ *data = (*data)[:newLen]
+ return (*data)[oldLen:newLen]
+}
- paddingLen := blockSize - overrun
- finalSize := blockSize
+// computingCBCPaddingLength returns the number of bytes of CBC padding to use
+// for a payload (plaintext + MAC) of length payloadLen.
+func computingCBCPaddingLength(payloadLen, blockSize int, config *Config) int {
+ paddingLen := blockSize - payloadLen%blockSize
if config.Bugs.MaxPadding {
for paddingLen+blockSize <= 256 {
paddingLen += blockSize
}
- finalSize = 256
}
- finalBlock = make([]byte, finalSize)
- for i := range finalBlock {
- finalBlock[i] = byte(paddingLen - 1)
- }
- if config.Bugs.PaddingFirstByteBad || config.Bugs.PaddingFirstByteBadIf255 && paddingLen == 256 {
- finalBlock[overrun] ^= 0xff
- }
- copy(finalBlock, payload[len(payload)-overrun:])
- return
+ return paddingLen
}
-// encrypt encrypts and macs the data in b.
-func (hc *halfConn) encrypt(b *block, explicitIVLen int, typ recordType) (bool, alert) {
- recordHeaderLen := hc.writeRecordHeaderLen()
+// appendCBCPadding computes paddingLen bytes of padding data, appends it to b,
+// and returns the result.
+func appendCBCPadding(b []byte, paddingLen int, config *Config) []byte {
+ padding := extendSlice(&b, paddingLen)
+ for i := range padding {
+ padding[i] = byte(paddingLen - 1)
+ }
+ if config.Bugs.PaddingFirstByteBad || config.Bugs.PaddingFirstByteBadIf255 && paddingLen == 256 {
+ padding[0] ^= 0xff
+ }
+ return b
+}
- // mac
+func (hc *halfConn) maxEncryptOverhead(payloadLen int) int {
+ var macSize int
if hc.mac != nil {
- mac := hc.mac.MAC(hc.outDigestBuf, hc.outSeq[0:], b.data[:3], b.data[recordHeaderLen-2:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
+ macSize = hc.mac.Size()
+ }
+ overhead := macSize + hc.explicitIVLen()
+ if hc.version >= VersionTLS13 {
+ overhead += 1 + hc.config.Bugs.RecordPadding // type + padding
+ }
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream, *nullCipher:
+ case *tlsAead:
+ overhead += c.Overhead()
+ case cbcMode:
+ overhead += computingCBCPaddingLength(payloadLen+macSize, c.BlockSize(), hc.config)
+ case nullCipher:
+ break
+ default:
+ panic("unknown cipher type")
+ }
+ }
+ return overhead
+}
- n := len(b.data)
- b.resize(n + len(mac))
- copy(b.data[n:], mac)
- hc.outDigestBuf = mac
+func (c *Conn) useDTLSPlaintextHeader() bool {
+ return c.config.Bugs.DTLSUsePlaintextRecordHeader && c.handshakeComplete
+}
+
+// encrypt encrypts and MACs the data in payload, appending it record. On
+// entry, the last headerLen bytes of record must be the header. The length
+// (which must be in the last two bytes of the header) should be computed for
+// the unencrypted, unpadded payload. It will be updated, potentially in-place,
+// with the final length.
+func (hc *halfConn) encrypt(record, payload []byte, typ recordType, headerLen int, headerHasLength bool) ([]byte, error) {
+ prefixLen := len(record)
+ header := record[prefixLen-headerLen:]
+ explicitIVLen := hc.explicitIVLen()
+
+ // Reserve some space for the explicit IV. The slice may get reallocated
+ // after this, so don't use the return value.
+ extendSlice(&record, explicitIVLen)
+
+ // Stage the plaintext, TLS 1.3 padding, and TLS 1.2 MAC in the record, to
+ // be encrypted in-place.
+ record = append(record, payload...)
+
+ if hc.version >= VersionTLS13 && hc.cipher != nil {
+ if hc.config.Bugs.OmitRecordContents {
+ record = record[:len(record)-len(payload)]
+ } else {
+ record = append(record, byte(typ))
+ }
+ padding := extendSlice(&record, hc.config.Bugs.RecordPadding)
+ for i := range padding {
+ padding[i] = 0
+ }
}
- payload := b.data[recordHeaderLen:]
+ if hc.mac != nil {
+ record = append(record, hc.computeMAC(hc.outSeq[:], header, payload)...)
+ }
- // encrypt
+ explicitIV := record[prefixLen : prefixLen+explicitIVLen]
if hc.cipher != nil {
switch c := hc.cipher.(type) {
case cipher.Stream:
- c.XORKeyStream(payload, payload)
- case *tlsAead:
- payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
- b.resize(len(b.data) + c.Overhead())
- nonce := hc.outSeq[:]
- if c.explicitNonce {
- nonce = b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+ if explicitIVLen != 0 {
+ panic("tls: unexpected explicit IV length")
}
- usePlaintextHeader := hc.config.Bugs.DTLSUsePlaintextRecordHeader && hc.conn.handshakeComplete
- if hc.isDTLS && hc.version >= VersionTLS13 && !usePlaintextHeader {
+ c.XORKeyStream(record[prefixLen:], record[prefixLen:])
+ case *tlsAead:
+ nonce := hc.outSeq[:]
+ if hc.isDTLS && hc.version >= VersionTLS13 && !hc.conn.useDTLSPlaintextHeader() {
+ // Unlike DTLS 1.2, DTLS 1.3's nonce construction does not use
+ // the epoch number. We store the epoch and nonce numbers
+ // together, so make a copy without the epoch.
nonce = make([]byte, 8)
copy(nonce[2:], hc.outSeq[2:])
}
- payload := b.data[recordHeaderLen+explicitIVLen:]
- payload = payload[:payloadLen]
+
+ // Save the explicit IV, if not empty.
+ if len(explicitIV) != 0 {
+ if explicitIVLen != len(nonce) {
+ panic("tls: unexpected explicit IV length")
+ }
+ copy(explicitIV, nonce)
+ }
var additionalData []byte
if hc.version < VersionTLS13 {
+ // (D)TLS 1.2's AD is seq_num || type || version || plaintext length
additionalData = make([]byte, 13)
copy(additionalData, hc.outSeq[:])
- copy(additionalData[8:], b.data[:3])
- additionalData[11] = byte(payloadLen >> 8)
- additionalData[12] = byte(payloadLen)
+ copy(additionalData[8:], header[:3])
+ additionalData[11] = byte(len(payload) >> 8)
+ additionalData[12] = byte(len(payload))
} else {
- additionalData = make([]byte, recordHeaderLen)
- copy(additionalData, b.data)
+ // (D)TLS 1.3's AD is the ciphertext record header, so update the
+ // length now.
+ if headerHasLength {
+ n := len(record) - prefixLen + c.Overhead()
+ record[prefixLen-2] = byte(n >> 8)
+ record[prefixLen-1] = byte(n)
+ }
+ additionalData = record[prefixLen-headerLen : prefixLen]
}
- c.Seal(payload[:0], nonce, payload, additionalData)
+ record = c.Seal(record[:prefixLen+explicitIVLen], nonce, record[prefixLen+explicitIVLen:], additionalData)
case cbcMode:
- blockSize := c.BlockSize()
if explicitIVLen > 0 {
- c.SetIV(payload[:explicitIVLen])
- payload = payload[explicitIVLen:]
+ if _, err := io.ReadFull(hc.config.rand(), explicitIV); err != nil {
+ return nil, err
+ }
+ c.SetIV(explicitIV)
}
- prefix, finalBlock := padToBlockSize(payload, blockSize, hc.config)
- b.resize(recordHeaderLen + explicitIVLen + len(prefix) + len(finalBlock))
- c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen:], prefix)
- c.CryptBlocks(b.data[recordHeaderLen+explicitIVLen+len(prefix):], finalBlock)
+
+ blockSize := c.BlockSize()
+ paddingLen := computingCBCPaddingLength(len(record)-prefixLen, blockSize, hc.config)
+ record = appendCBCPadding(record, paddingLen, hc.config)
+ c.CryptBlocks(record[prefixLen:], record[prefixLen:])
case nullCipher:
break
default:
@@ -669,113 +730,15 @@
}
}
- // update length to include MAC and any block padding needed.
- if !hc.config.DTLSRecordHeaderOmitLength {
- n := len(b.data) - recordHeaderLen
- b.data[recordHeaderLen-2] = byte(n >> 8)
- b.data[recordHeaderLen-1] = byte(n)
+ // Update the record header to include the encryption overhead.
+ if headerHasLength {
+ n := len(record) - prefixLen
+ record[prefixLen-2] = byte(n >> 8)
+ record[prefixLen-1] = byte(n)
}
hc.incSeq(true)
- return true, 0
-}
-
-// A block is a simple data buffer.
-type block struct {
- data []byte
- off int // index for Read
- link *block
-}
-
-// resize resizes block to be n bytes, growing if necessary.
-func (b *block) resize(n int) {
- if n > cap(b.data) {
- b.reserve(n)
- }
- b.data = b.data[0:n]
-}
-
-// reserve makes sure that block contains a capacity of at least n bytes.
-func (b *block) reserve(n int) {
- if cap(b.data) >= n {
- return
- }
- m := cap(b.data)
- if m == 0 {
- m = 1024
- }
- for m < n {
- m *= 2
- }
- data := make([]byte, len(b.data), m)
- copy(data, b.data)
- b.data = data
-}
-
-// readFromUntil reads from r into b until b contains at least n bytes
-// or else returns an error.
-func (b *block) readFromUntil(r io.Reader, n int) error {
- // quick case
- if len(b.data) >= n {
- return nil
- }
-
- // read until have enough.
- b.reserve(n)
- for {
- m, err := r.Read(b.data[len(b.data):cap(b.data)])
- b.data = b.data[0 : len(b.data)+m]
- if len(b.data) >= n {
- // TODO(bradfitz,agl): slightly suspicious
- // that we're throwing away r.Read's err here.
- break
- }
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func (b *block) Read(p []byte) (n int, err error) {
- n = copy(p, b.data[b.off:])
- b.off += n
- return
-}
-
-// newBlock allocates a new block, from hc's free list if possible.
-func (hc *halfConn) newBlock() *block {
- b := hc.bfree
- if b == nil {
- return new(block)
- }
- hc.bfree = b.link
- b.link = nil
- b.resize(0)
- return b
-}
-
-// freeBlock returns a block to hc's free list.
-// The protocol is such that each side only has a block or two on
-// its free list at a time, so there's no need to worry about
-// trimming the list, etc.
-func (hc *halfConn) freeBlock(b *block) {
- b.link = hc.bfree
- hc.bfree = b
-}
-
-// splitBlock splits a block after the first n bytes,
-// returning a block with those n bytes and a
-// block with the remainder. the latter may be nil.
-func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) {
- if len(b.data) <= n {
- return b, nil
- }
- bb := hc.newBlock()
- bb.resize(len(b.data) - n)
- copy(bb.data, b.data[n:])
- b.data = b.data[0:n]
- return b, bb
+ return record, nil
}
type recordNumberEncrypter interface {
@@ -879,7 +842,20 @@
return c.skipEarlyData
}
-func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) {
+func (c *Conn) readRawInputUntil(n int) error {
+ if c.rawInput.Len() >= n {
+ return nil
+ }
+
+ n -= c.rawInput.Len()
+ c.rawInput.Grow(n)
+ buf := c.rawInput.AvailableBuffer()
+ nread, err := io.ReadAtLeast(c.conn, buf[:cap(buf)], n)
+ c.rawInput.Write(buf[:nread])
+ return err
+}
+
+func (c *Conn) doReadRecord(want recordType) (recordType, []byte, error) {
RestartReadRecord:
if c.isDTLS {
return c.dtlsDoReadRecord(want)
@@ -887,13 +863,8 @@
recordHeaderLen := tlsRecordHeaderLen
- if c.rawInput == nil {
- c.rawInput = c.in.newBlock()
- }
- b := c.rawInput
-
// Read header, payload.
- if err := b.readFromUntil(c.conn, recordHeaderLen); err != nil {
+ if err := c.readRawInputUntil(recordHeaderLen); err != nil {
// RFC suggests that EOF without an alertCloseNotify is
// an error, but popular web sites seem to do this,
// so we can't make it an error, outside of tests.
@@ -906,7 +877,8 @@
return 0, nil, err
}
- typ := recordType(b.data[0])
+ header := c.rawInput.Bytes()[:recordHeaderLen]
+ typ := recordType(header[0])
// No valid TLS record has a type of 0x80, however SSLv2 handshakes
// start with a uint16 length where the MSB is set and the first record
@@ -917,8 +889,8 @@
return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
}
- vers := uint16(b.data[1])<<8 | uint16(b.data[2])
- n := int(b.data[3])<<8 | int(b.data[4])
+ vers := uint16(header[1])<<8 | uint16(header[2])
+ n := int(header[3])<<8 | int(header[4])
// Alerts sent near version negotiation do not have a well-defined
// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
@@ -956,7 +928,7 @@
return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
}
}
- if err := b.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+ if err := c.readRawInputUntil(recordHeaderLen + n); err != nil {
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
@@ -967,25 +939,24 @@
}
// Process message.
- b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
- ok, off, encTyp, alertValue := c.in.decrypt(c.in.seq[:], recordHeaderLen, b)
-
- // Handle skipping over early data.
- if !ok && c.skipEarlyData {
- goto RestartReadRecord
+ b := c.rawInput.Next(recordHeaderLen + n)
+ ok, encTyp, data, alertValue := c.in.decrypt(c.in.seq[:], recordHeaderLen, b)
+ if !ok {
+ // TLS 1.3 early data uses trial decryption.
+ if c.skipEarlyData {
+ goto RestartReadRecord
+ }
+ return 0, nil, c.in.setErrorLocked(c.sendAlert(alertValue))
}
// If the server is expecting a second ClientHello (in response to
// a HelloRetryRequest) and the client sends early data, there
- // won't be a decryption failure but it still needs to be skipped.
+ // won't be a decryption failure (we will interpret the ciphertext
+ // as plaintext application data) but it still needs to be skipped.
if c.in.cipher == nil && typ == recordTypeApplicationData && c.skipEarlyData {
goto RestartReadRecord
}
- if !ok {
- return 0, nil, c.in.setErrorLocked(c.sendAlert(alertValue))
- }
- b.off = off
c.skipEarlyData = false
if c.vers >= VersionTLS13 && c.in.cipher != nil {
@@ -995,13 +966,12 @@
typ = encTyp
}
- length := len(b.data[b.off:])
- if c.config.Bugs.ExpectRecordSplitting && typ == recordTypeApplicationData && length != 1 && !c.seenOneByteRecord {
+ if c.config.Bugs.ExpectRecordSplitting && typ == recordTypeApplicationData && len(data) != 1 && !c.seenOneByteRecord {
return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: application data records were not split"))
}
- c.seenOneByteRecord = typ == recordTypeApplicationData && length == 1
- return typ, b, nil
+ c.seenOneByteRecord = typ == recordTypeApplicationData && len(data) == 1
+ return typ, data, nil
}
func (c *Conn) readTLS13ChangeCipherSpec() error {
@@ -1017,36 +987,28 @@
}
// Read the ChangeCipherSpec.
- if c.rawInput == nil {
- c.rawInput = c.in.newBlock()
- }
- b := c.rawInput
- if err := b.readFromUntil(c.conn, 1); err != nil {
+ if err := c.readRawInputUntil(6); err != nil {
return c.in.setErrorLocked(fmt.Errorf("tls: error reading TLS 1.3 ChangeCipherSpec: %s", err))
}
- if recordType(b.data[0]) == recordTypeAlert {
+ if recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
// If the client is sending an alert, allow the ChangeCipherSpec
// to be skipped. It may be rejecting a sufficiently malformed
// ServerHello that it can't parse out the version.
c.expectTLS13ChangeCipherSpec = false
return nil
}
- if err := b.readFromUntil(c.conn, 6); err != nil {
- return c.in.setErrorLocked(fmt.Errorf("tls: error reading TLS 1.3 ChangeCipherSpec: %s", err))
- }
// Check they match that we expect.
expected := [6]byte{byte(recordTypeChangeCipherSpec), 3, 1, 0, 1, 1}
if c.vers >= VersionTLS13 {
expected[2] = 3
}
- if !bytes.Equal(b.data[:6], expected[:]) {
- return c.in.setErrorLocked(fmt.Errorf("tls: error invalid TLS 1.3 ChangeCipherSpec: %x", b.data[:6]))
+ if data := c.rawInput.Bytes()[:6]; !bytes.Equal(data, expected[:]) {
+ return c.in.setErrorLocked(fmt.Errorf("tls: error invalid TLS 1.3 ChangeCipherSpec: %x", data))
}
// Discard the data.
- b, c.rawInput = c.in.splitBlock(b, 6)
- c.in.freeBlock(b)
+ c.rawInput.Next(6)
c.expectTLS13ChangeCipherSpec = false
return nil
@@ -1083,25 +1045,22 @@
if c.config.Bugs.MockQUICTransport != nil {
doReadRecord = c.config.Bugs.MockQUICTransport.readRecord
}
- typ, b, err := doReadRecord(want)
+ typ, data, err := doReadRecord(want)
if err != nil {
return err
}
- data := b.data[b.off:]
max := maxPlaintext
if c.config.Bugs.MaxReceivePlaintext != 0 {
max = c.config.Bugs.MaxReceivePlaintext
}
if len(data) > max {
err := c.sendAlert(alertRecordOverflow)
- c.in.freeBlock(b)
return c.in.setErrorLocked(err)
}
if typ != recordTypeHandshake {
c.seenHandshakePackEnd = false
} else if c.seenHandshakePackEnd {
- c.in.freeBlock(b)
return c.in.setErrorLocked(errors.New("tls: peer violated ExpectPackedEncryptedHandshake"))
}
@@ -1121,7 +1080,6 @@
switch data[0] {
case alertLevelWarning:
// drop on the floor
- c.in.freeBlock(b)
goto Again
case alertLevelError:
c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
@@ -1147,8 +1105,7 @@
c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
break
}
- c.input = b
- b = nil
+ c.input.Write(data)
case recordTypeHandshake:
// Allow handshake data while reading application data to
@@ -1163,9 +1120,6 @@
}
}
- if b != nil {
- c.in.freeBlock(b)
- }
return c.in.err
}
@@ -1285,31 +1239,7 @@
return c.doWriteRecord(typ, data)
}
-func (c *Conn) addTLS13Padding(b *block, recordHeaderLen, recordLen int, typ recordType) int {
- if c.out.version < VersionTLS13 || c.out.cipher == nil {
- return recordLen
- }
- paddingLen := c.config.Bugs.RecordPadding
- if c.config.Bugs.OmitRecordContents {
- recordLen = paddingLen
- b.resize(recordHeaderLen + paddingLen)
- } else {
- recordLen += 1 + paddingLen
- b.resize(len(b.data) + 1 + paddingLen)
- b.data[len(b.data)-paddingLen-1] = byte(typ)
- }
- for i := 0; i < paddingLen; i++ {
- b.data[len(b.data)-paddingLen+i] = 0
- }
- if c, ok := c.out.cipher.(*tlsAead); ok {
- recordLen += c.Overhead()
- }
- return recordLen
-}
-
func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
- recordHeaderLen := c.out.writeRecordHeaderLen()
- b := c.out.newBlock()
first := true
isClientHello := typ == recordTypeHandshake && len(data) > 0 && data[0] == typeClientHello
for len(data) > 0 || first {
@@ -1326,38 +1256,9 @@
m = 6
}
}
- plaintextLen := m
- explicitIVLen := 0
- explicitIVIsSeq := false
first = false
- var cbc cbcMode
- if c.out.version >= VersionTLS11 {
- var ok bool
- if cbc, ok = c.out.cipher.(cbcMode); ok {
- explicitIVLen = cbc.BlockSize()
- }
- }
- if explicitIVLen == 0 {
- if aead, ok := c.out.cipher.(*tlsAead); ok && aead.explicitNonce {
- explicitIVLen = 8
- // The AES-GCM construction in TLS has an
- // explicit nonce so that the nonce can be
- // random. However, the nonce is only 8 bytes
- // which is too small for a secure, random
- // nonce. Therefore we use the sequence number
- // as the nonce.
- explicitIVIsSeq = true
- }
- }
- b.resize(recordHeaderLen + explicitIVLen + plaintextLen)
- b.data[0] = byte(typ)
- if c.vers >= VersionTLS13 && c.out.cipher != nil {
- b.data[0] = byte(recordTypeApplicationData)
- if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
- b.data[0] = byte(outerType)
- }
- }
+ // Determine record version.
vers := c.vers
if vers == 0 {
// Some TLS servers fail if the record version is
@@ -1370,39 +1271,38 @@
if c.vers >= VersionTLS13 || c.out.version >= VersionTLS13 {
vers = VersionTLS12
}
-
if c.config.Bugs.SendRecordVersion != 0 {
vers = c.config.Bugs.SendRecordVersion
}
if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
vers = c.config.Bugs.SendInitialRecordVersion
}
- copy(b.data[recordHeaderLen+explicitIVLen:], data)
- // Add TLS 1.3 padding.
- recordLen := c.addTLS13Padding(b, recordHeaderLen, plaintextLen, typ)
- b.data[1] = byte(vers >> 8)
- b.data[2] = byte(vers)
- b.data[3] = byte(recordLen >> 8)
- b.data[4] = byte(recordLen)
- if explicitIVLen > 0 {
- explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
- if explicitIVIsSeq {
- copy(explicitIV, c.out.seq[:])
- } else {
- if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
- break
- }
+
+ // Assemble the record header.
+ record := make([]byte, tlsRecordHeaderLen, tlsRecordHeaderLen+m+c.out.maxEncryptOverhead(m))
+ record[0] = byte(typ)
+ if c.vers >= VersionTLS13 && c.out.cipher != nil {
+ record[0] = byte(recordTypeApplicationData)
+ if outerType := c.config.Bugs.OuterRecordType; outerType != 0 {
+ record[0] = byte(outerType)
}
}
- c.out.encrypt(b, explicitIVLen, typ)
- _, err = c.conn.Write(b.data)
+ record[1] = byte(vers >> 8)
+ record[2] = byte(vers)
+ record[3] = byte(m >> 8) // encrypt will update this
+ record[4] = byte(m)
+
+ record, err = c.out.encrypt(record, data[:m], typ, tlsRecordHeaderLen, true /* header has length */)
+ if err != nil {
+ return
+ }
+ _, err = c.conn.Write(record)
if err != nil {
break
}
- n += plaintextLen
- data = data[plaintextLen:]
+ n += m
+ data = data[m:]
}
- c.out.freeBlock(b)
if typ == recordTypeChangeCipherSpec && c.vers < VersionTLS13 {
err = c.out.changeCipherSpec(c.config)
@@ -1836,7 +1736,7 @@
// CBC IV. So this loop ignores a limited number of empty records.
const maxConsecutiveEmptyRecords = 100
for emptyRecordCount := 0; emptyRecordCount <= maxConsecutiveEmptyRecords; emptyRecordCount++ {
- for c.input == nil && c.in.err == nil {
+ for c.input.Len() == 0 && c.in.err == nil {
if err := c.readRecord(recordTypeApplicationData); err != nil {
// Soft error, like EAGAIN
return 0, err
@@ -1854,9 +1754,8 @@
}
n, err = c.input.Read(b)
- if c.input.off >= len(c.input.data) || c.isDTLS {
- c.in.freeBlock(c.input)
- c.input = nil
+ if c.input.Len() == 0 || c.isDTLS {
+ c.input.Reset()
}
// If a close-notify alert is waiting, read it so that
@@ -1870,9 +1769,8 @@
// request.
// See https://codereview.appspot.com/76400046
// and http://golang.org/issue/3514
- if ri := c.rawInput; ri != nil &&
- n != 0 && err == nil &&
- c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
+ if ri := c.rawInput.Bytes(); !c.isDTLS && n != 0 && err == nil &&
+ c.input.Len() == 0 && len(ri) > 0 && recordType(ri[0]) == recordTypeAlert {
if recErr := c.readRecord(recordTypeApplicationData); recErr != nil {
err = recErr // will be io.EOF on closeNotify
}
diff --git a/ssl/test/runner/dtls.go b/ssl/test/runner/dtls.go
index 8c723f2..201b6b8 100644
--- a/ssl/test/runner/dtls.go
+++ b/ssl/test/runner/dtls.go
@@ -19,12 +19,11 @@
"encoding/binary"
"errors"
"fmt"
- "io"
"math/rand"
"net"
)
-func (c *Conn) readDTLS13RecordHeader(b *block) (headerLen int, recordLen int, recTyp recordType, seq []byte, err error) {
+func (c *Conn) readDTLS13RecordHeader(b []byte) (headerLen int, recordLen int, recTyp recordType, seq []byte, err error) {
// The DTLS 1.3 record header starts with the type byte containing
// 0b001CSLEE, where C, S, L, and EE are bits with the following
// meanings:
@@ -41,10 +40,10 @@
// anything else is set. This means we expect the type byte to look like
// 0b001011EE, or 0x2c-0x2f.
recordHeaderLen := 5
- if len(b.data) < recordHeaderLen {
+ if len(b) < recordHeaderLen {
return 0, 0, 0, nil, errors.New("dtls: failed to read record header")
}
- typ := b.data[0]
+ typ := b[0]
if typ&0xfc != 0x2c {
return 0, 0, 0, nil, errors.New("dtls: DTLS 1.3 record header has bad type byte")
}
@@ -55,9 +54,9 @@
c.sendAlert(alertIllegalParameter)
return 0, 0, 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad epoch"))
}
- wireSeq := b.data[1:3]
+ wireSeq := b[1:3]
if !c.config.Bugs.NullAllCiphers {
- sample := b.data[recordHeaderLen:]
+ sample := b[recordHeaderLen:]
mask := c.in.recordNumberEncrypter.generateMask(sample)
xorSlice(wireSeq, mask)
}
@@ -82,16 +81,16 @@
binary.BigEndian.PutUint64(seq, newSeq)
copy(c.in.seq[2:], seq[2:])
- recordLen = int(b.data[3])<<8 | int(b.data[4])
+ recordLen = int(b[3])<<8 | int(b[4])
return recordHeaderLen, recordLen, 0, seq, nil
}
-// readDTLSRecordHeader reads the record header from the block. Based on the
+// readDTLSRecordHeader reads the record header from the input. Based on the
// header it reads, it checks the header's validity and sets appropriate state
// as needed. This function returns the record header, the record type indicated
// in the header (if it contains the type), and the sequence number to use for
// record decryption.
-func (c *Conn) readDTLSRecordHeader(b *block) (headerLen int, recordLen int, typ recordType, seq []byte, err error) {
+func (c *Conn) readDTLSRecordHeader(b []byte) (headerLen int, recordLen int, typ recordType, seq []byte, err error) {
if c.in.cipher != nil && c.in.version >= VersionTLS13 {
return c.readDTLS13RecordHeader(b)
}
@@ -102,11 +101,11 @@
// A real DTLS implementation should be tolerant of errors,
// but this is test code. We should not be tolerant of our
// peer sending garbage.
- if len(b.data) < recordHeaderLen {
+ if len(b) < recordHeaderLen {
return 0, 0, 0, nil, errors.New("dtls: failed to read record header")
}
- typ = recordType(b.data[0])
- vers := uint16(b.data[1])<<8 | uint16(b.data[2])
+ typ = recordType(b[0])
+ vers := uint16(b[1])<<8 | uint16(b[2])
// Alerts sent near version negotiation do not have a well-defined
// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
// version is irrelevant.)
@@ -128,8 +127,8 @@
}
}
}
- epoch := b.data[3:5]
- seq = b.data[5:11]
+ epoch := b[3:5]
+ seq = b[5:11]
// For test purposes, require the sequence number be monotonically
// increasing, so c.in includes the minimum next sequence number. Gaps
// may occur if packets failed to be sent out. A real implementation
@@ -143,51 +142,47 @@
return 0, 0, 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad sequence number"))
}
copy(c.in.seq[2:], seq)
- recordLen = int(b.data[11])<<8 | int(b.data[12])
- return recordHeaderLen, recordLen, typ, b.data[3:11], nil
+ recordLen = int(b[11])<<8 | int(b[12])
+ return recordHeaderLen, recordLen, typ, b[3:11], nil
}
-func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
- if c.rawInput == nil {
- c.rawInput = c.in.newBlock()
- }
- b := c.rawInput
-
+func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, []byte, error) {
// Read a new packet only if the current one is empty.
var newPacket bool
- if len(b.data) == 0 {
+ if c.rawInput.Len() == 0 {
// Pick some absurdly large buffer size.
- b.resize(maxCiphertext + dtlsMaxRecordHeaderLen)
- n, err := c.conn.Read(c.rawInput.data)
+ c.rawInput.Grow(maxCiphertext + dtlsMaxRecordHeaderLen)
+ buf := c.rawInput.AvailableBuffer()
+ n, err := c.conn.Read(buf[:cap(buf)])
if err != nil {
return 0, nil, err
}
if c.config.Bugs.MaxPacketLength != 0 && n > c.config.Bugs.MaxPacketLength {
return 0, nil, fmt.Errorf("dtls: exceeded maximum packet length")
}
- c.rawInput.resize(n)
+ c.rawInput.Write(buf[:n])
newPacket = true
}
- recordHeaderLen, n, typ, seq, err := c.readDTLSRecordHeader(b)
+ // Consume the next record from the buffer.
+ recordHeaderLen, n, typ, seq, err := c.readDTLSRecordHeader(c.rawInput.Bytes())
if err != nil {
return 0, nil, err
}
- if n > maxCiphertext || len(b.data) < recordHeaderLen+n {
+ if n > maxCiphertext || c.rawInput.Len() < recordHeaderLen+n {
c.sendAlert(alertRecordOverflow)
return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: oversized record received with length %d", n))
}
- b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
+ b := c.rawInput.Next(recordHeaderLen + n)
// Process message.
- ok, off, encTyp, alertValue := c.in.decrypt(seq, recordHeaderLen, b)
+ ok, encTyp, data, alertValue := c.in.decrypt(seq, recordHeaderLen, b)
if !ok {
// A real DTLS implementation would silently ignore bad records,
// but we want to notice errors from the implementation under
// test.
return 0, nil, c.in.setErrorLocked(c.sendAlert(alertValue))
}
- b.off = off
if typ == 0 {
// readDTLSRecordHeader sets typ=0 when decoding the DTLS 1.3
@@ -198,11 +193,11 @@
// Require that ChangeCipherSpec always share a packet with either the
// previous or next handshake message.
- if newPacket && typ == recordTypeChangeCipherSpec && c.rawInput == nil {
+ if newPacket && typ == recordTypeChangeCipherSpec && c.rawInput.Len() == 0 {
return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: ChangeCipherSpec not packed together with Finished"))
}
- return typ, b, nil
+ return typ, data, nil
}
func (c *Conn) makeFragment(header, data []byte, fragOffset, fragLen int) []byte {
@@ -414,18 +409,16 @@
return nil
}
-// writeDTLS13RecordHeader writes to b the record header for a record of length
+// appendDTLS13RecordHeader appends to b the record header for a record of length
// recordLen.
-func (c *Conn) writeDTLS13RecordHeader(b *block, recordLen int) {
+func (c *Conn) appendDTLS13RecordHeader(b []byte, recordLen int) []byte {
// Set the top 3 bits on the type byte to indicate the DTLS 1.3 record
// header format.
typ := byte(0x20)
-
+ // Set the Connection ID bit
if c.config.Bugs.DTLS13RecordHeaderSetCIDBit && c.handshakeComplete {
- // Set the Connection ID bit
typ |= 0x10
}
-
// Set the sequence number length bit
if !c.config.DTLSUseShortSeqNums {
typ |= 0x08
@@ -436,51 +429,27 @@
}
// Set the epoch bits
typ |= c.out.outSeq[1] & 0x3
- b.data[0] = typ
- lenOffset := 3
+ b = append(b, typ)
if c.config.DTLSUseShortSeqNums {
- b.data[1] = c.out.outSeq[7]
- lenOffset = 2
+ b = append(b, c.out.outSeq[7])
} else {
- copy(b.data[1:3], c.out.outSeq[6:8])
+ b = append(b, c.out.outSeq[6], c.out.outSeq[7])
}
if !c.config.DTLSRecordHeaderOmitLength {
- b.data[lenOffset] = byte(recordLen >> 8)
- b.data[lenOffset+1] = byte(recordLen)
+ b = append(b, byte(recordLen>>8), byte(recordLen))
}
+ return b
}
// dtlsPackRecord packs a single record to the pending packet, flushing it
// if necessary. The caller should call dtlsFlushPacket to flush the current
// pending packet afterwards.
func (c *Conn) dtlsPackRecord(typ recordType, data []byte, mustPack bool) (n int, err error) {
- recordHeaderLen := c.out.writeRecordHeaderLen()
maxLen := c.config.Bugs.MaxHandshakeRecordLength
if maxLen <= 0 {
maxLen = 1024
}
- b := c.out.newBlock()
-
- explicitIVLen := 0
- explicitIVIsSeq := false
-
- if cbc, ok := c.out.cipher.(cbcMode); ok {
- // Block cipher modes have an explicit IV.
- explicitIVLen = cbc.BlockSize()
- } else if aead, ok := c.out.cipher.(*tlsAead); ok {
- if aead.explicitNonce {
- explicitIVLen = 8
- // The AES-GCM construction in TLS has an explicit nonce so that
- // the nonce can be random. However, the nonce is only 8 bytes
- // which is too small for a secure, random nonce. Therefore we
- // use the sequence number as the nonce.
- explicitIVIsSeq = true
- }
- } else if _, ok := c.out.cipher.(nullCipher); !ok && c.out.cipher != nil {
- panic("Unknown cipher")
- }
- b.resize(recordHeaderLen + explicitIVLen + len(data))
vers := c.wireVersion
if vers == 0 {
// Some TLS servers fail if the record version is greater than
@@ -494,62 +463,51 @@
if c.vers >= VersionTLS13 || c.out.version >= VersionTLS13 {
vers = VersionDTLS12
}
- if explicitIVLen > 0 {
- explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
- if explicitIVIsSeq {
- copy(explicitIV, c.out.outSeq[:])
- } else {
- if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
- return
- }
- }
- }
- copy(b.data[recordHeaderLen+explicitIVLen:], data)
- recordLen := c.addTLS13Padding(b, recordHeaderLen, len(data), typ)
- useDTLS13RecordHeader := c.out.version >= VersionTLS13 && c.out.cipher != nil && !(c.config.Bugs.DTLSUsePlaintextRecordHeader && c.handshakeComplete)
+
+ useDTLS13RecordHeader := c.out.version >= VersionTLS13 && c.out.cipher != nil && !c.useDTLSPlaintextHeader()
+ headerHasLength := true
+ record := make([]byte, 0, dtlsMaxRecordHeaderLen+len(data)+c.out.maxEncryptOverhead(len(data)))
if useDTLS13RecordHeader {
- c.writeDTLS13RecordHeader(b, recordLen)
+ record = c.appendDTLS13RecordHeader(record, len(data))
+ headerHasLength = !c.config.DTLSRecordHeaderOmitLength
} else {
- b.data[0] = byte(typ)
- b.data[1] = byte(vers >> 8)
- b.data[2] = byte(vers)
+ record = append(record, byte(typ))
+ record = append(record, byte(vers>>8))
+ record = append(record, byte(vers))
// DTLS records include an explicit sequence number.
- copy(b.data[3:11], c.out.outSeq[0:])
- b.data[11] = byte(recordLen >> 8)
- b.data[12] = byte(recordLen)
+ record = append(record, c.out.outSeq[:]...)
+ record = append(record, byte(len(data)>>8))
+ record = append(record, byte(len(data)))
}
- // encrypt will increment the sequence number. Copy it here to use when
- // performing sequence number encryption.
- seqBytes := make([]byte, 2)
- copy(seqBytes, c.out.outSeq[6:8])
- c.out.encrypt(b, explicitIVLen, typ)
+
+ recordHeaderLen := len(record)
+ record, err = c.out.encrypt(record, data, typ, recordHeaderLen, headerHasLength)
+ if err != nil {
+ return
+ }
+
+ // Encrypt the sequence number.
if useDTLS13RecordHeader && !c.config.Bugs.NullAllCiphers {
- recordHeaderLen := c.out.writeRecordHeaderLen()
- sample := b.data[recordHeaderLen:]
+ sample := record[recordHeaderLen:]
mask := c.out.recordNumberEncrypter.generateMask(sample)
+ seqLen := 2
if c.config.DTLSUseShortSeqNums {
- seqBytes = seqBytes[1:2]
+ seqLen = 1
}
- xorSlice(seqBytes, mask)
- for i := range seqBytes {
- // The sequence number starts at index 1 in the record
- // header.
- b.data[1+i] = seqBytes[i]
- }
+ // The sequence number starts at index 1 in the record header.
+ xorSlice(record[1:1+seqLen], mask)
}
// Flush the current pending packet if necessary.
- if !mustPack && len(b.data)+len(c.pendingPacket) > c.config.Bugs.PackHandshakeRecords {
+ if !mustPack && len(record)+len(c.pendingPacket) > c.config.Bugs.PackHandshakeRecords {
err = c.dtlsFlushPacket()
if err != nil {
- c.out.freeBlock(b)
return
}
}
// Add the record to the pending packet.
- c.pendingPacket = append(c.pendingPacket, b.data...)
- c.out.freeBlock(b)
+ c.pendingPacket = append(c.pendingPacket, record...)
if c.config.DTLSRecordHeaderOmitLength {
if c.config.Bugs.SplitAndPackAppData {
panic("incompatible config")
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index 96fd335..f968d09 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -1371,11 +1371,10 @@
if err := c.readRecord(recordTypeApplicationData); err != nil {
return err
}
- if !bytes.Equal(c.input.data[c.input.off:], expectedMsg) {
- return errors.New("ExpectHalfRTTData: did not get expected message")
+ if !bytes.Equal(c.input.Bytes(), expectedMsg) {
+ return fmt.Errorf("tls: got half-RTT data record %x, wanted %x", c.input.Bytes(), expectedMsg)
}
- c.in.freeBlock(c.input)
- c.input = nil
+ c.input.Reset()
}
}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 177d715..87cedb9 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -945,12 +945,10 @@
if err := c.readRecord(recordTypeApplicationData); err != nil {
return err
}
- msg := c.input.data[c.input.off:]
- if !bytes.Equal(msg, expectedMsg) {
- return fmt.Errorf("tls: got early data record %x, wanted %x", msg, expectedMsg)
+ if !bytes.Equal(c.input.Bytes(), expectedMsg) {
+ return fmt.Errorf("tls: got early data record %x, wanted %x", c.input.Bytes(), expectedMsg)
}
- c.in.freeBlock(c.input)
- c.input = nil
+ c.input.Reset()
}
} else {
c.setSkipEarlyData()
@@ -1218,11 +1216,10 @@
if err := c.readRecord(recordTypeApplicationData); err != nil {
return err
}
- if !bytes.Equal(c.input.data[c.input.off:], expectedMsg) {
- return errors.New("ExpectLateEarlyData: did not get expected message")
+ if !bytes.Equal(c.input.Bytes(), expectedMsg) {
+ return fmt.Errorf("tls: got late early data record %x, wanted %x", c.input.Bytes(), expectedMsg)
}
- c.in.freeBlock(c.input)
- c.input = nil
+ c.input.Reset()
}
}
diff --git a/ssl/test/runner/mock_quic_transport.go b/ssl/test/runner/mock_quic_transport.go
index 2939274..af1f988 100644
--- a/ssl/test/runner/mock_quic_transport.go
+++ b/ssl/test/runner/mock_quic_transport.go
@@ -119,12 +119,8 @@
}
}
-func (m *mockQUICTransport) readRecord(want recordType) (recordType, *block, error) {
- typ, contents, err := m.read()
- if err != nil {
- return 0, nil, err
- }
- return typ, &block{contents, 0, nil}, nil
+func (m *mockQUICTransport) readRecord(want recordType) (recordType, []byte, error) {
+ return m.read()
}
func (m *mockQUICTransport) writeRecord(typ recordType, data []byte) (int, error) {