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>
This commit is contained in:
David Benjamin
2024-09-19 17:32:59 +00:00
committed by Boringssl LUCI CQ
parent 59c222fcf1
commit 2c0cc6c95e
6 changed files with 329 additions and 487 deletions
+3 -9
View File
@@ -1997,8 +1997,9 @@ type ProtocolBugs struct {
// 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 @@ func (c *Credential) signatureAlgorithms() []signatureAlgorithm {
return supportedSignatureAlgorithms
}
// A TLS record.
type record struct {
contentType recordType
major, minor uint8
payload []byte
}
type handshakeMessage interface {
marshal() []byte
unmarshal([]byte) bool
+252 -354
View File
@@ -18,6 +18,7 @@ import (
"fmt"
"io"
"net"
"slices"
"sync"
"time"
@@ -96,8 +97,8 @@ type Conn struct {
// 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 @@ type halfConn struct {
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 @@ func (hc *halfConn) updateOutSeq() {
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 @@ type cbcMode interface {
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 @@ func (hc *halfConn) decrypt(seq []byte, recordHeaderLen int, b *block) (ok bool,
}
paddingGood := byte(255)
explicitIVLen := 0
explicitIVLen := hc.explicitIVLen()
// decrypt
if hc.cipher != nil {
@@ -476,40 +476,34 @@ func (hc *halfConn) decrypt(seq []byte, recordHeaderLen int, b *block) (ok bool,
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 @@ func (hc *halfConn) decrypt(seq []byte, recordHeaderLen int, b *block) (ok bool,
}
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 @@ func (hc *halfConn) decrypt(seq []byte, recordHeaderLen int, b *block) (ok bool,
}
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 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int, typ recordType) (bool,
}
}
// 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 @@ func (c *Conn) shouldSkipEarlyData() bool {
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 @@ RestartReadRecord:
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 @@ RestartReadRecord:
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 @@ RestartReadRecord:
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 @@ RestartReadRecord:
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 @@ RestartReadRecord:
}
// 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 @@ RestartReadRecord:
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 @@ func (c *Conn) readTLS13ChangeCipherSpec() error {
}
// 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 @@ Again:
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 @@ Again:
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 @@ Again:
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 @@ Again:
}
}
if b != nil {
c.in.freeBlock(b)
}
return c.in.err
}
@@ -1285,31 +1239,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {
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 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
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 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
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 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// 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 @@ func (c *Conn) Read(b []byte) (n int, err error) {
}
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 @@ func (c *Conn) Read(b []byte) (n int, err error) {
// 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
}
+63 -105
View File
@@ -19,12 +19,11 @@ import (
"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 @@ func (c *Conn) readDTLS13RecordHeader(b *block) (headerLen int, recordLen int, r
// 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 @@ func (c *Conn) readDTLS13RecordHeader(b *block) (headerLen int, recordLen int, r
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 @@ func (c *Conn) readDTLS13RecordHeader(b *block) (headerLen int, recordLen int, r
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 @@ func (c *Conn) readDTLSRecordHeader(b *block) (headerLen int, recordLen int, typ
// 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 @@ func (c *Conn) readDTLSRecordHeader(b *block) (headerLen int, recordLen int, typ
}
}
}
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 @@ func (c *Conn) readDTLSRecordHeader(b *block) (headerLen int, recordLen int, typ
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 @@ func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
// 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 @@ func (c *Conn) dtlsFlushHandshake() error {
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 @@ func (c *Conn) writeDTLS13RecordHeader(b *block, recordLen int) {
}
// 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 @@ func (c *Conn) dtlsPackRecord(typ recordType, data []byte, mustPack bool) (n int
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]
}
xorSlice(seqBytes, mask)
for i := range seqBytes {
// The sequence number starts at index 1 in the record
// header.
b.data[1+i] = seqBytes[i]
seqLen = 1
}
// 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")
+3 -4
View File
@@ -1371,11 +1371,10 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg any) error {
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()
}
}
+6 -9
View File
@@ -945,12 +945,10 @@ ResendHelloRetryRequest:
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 @@ ResendHelloRetryRequest:
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()
}
}
+2 -6
View File
@@ -119,12 +119,8 @@ func (m *mockQUICTransport) read() (recordType, []byte, error) {
}
}
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) {