runner: Refactor handshake fragmenting slightly.

No behavior change. This is in preparation for buffering a flight of handshake
messages to reorder vigorously on flush.

Change-Id: Ic348829b340bf58d28f332027646559cb11046ac
Reviewed-on: https://boringssl-review.googlesource.com/3215
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/dtls.go b/ssl/test/runner/dtls.go
index 2e1fb65..8e4b8a6 100644
--- a/ssl/test/runner/dtls.go
+++ b/ssl/test/runner/dtls.go
@@ -106,6 +106,69 @@
 }
 
 func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
+	if typ != recordTypeHandshake {
+		// Only handshake messages are fragmented.
+		return c.dtlsWriteRawRecord(typ, data)
+	}
+
+	maxLen := c.config.Bugs.MaxHandshakeRecordLength
+	if maxLen <= 0 {
+		maxLen = 1024
+	}
+
+	// Handshake messages have to be modified to include fragment
+	// offset and length and with the header replicated. Save the
+	// TLS header here.
+	//
+	// TODO(davidben): This assumes that data contains exactly one
+	// handshake message. This is incompatible with
+	// FragmentAcrossChangeCipherSpec. (Which is unfortunate
+	// because OpenSSL's DTLS implementation will probably accept
+	// such fragmentation and could do with a fix + tests.)
+	if len(data) < 4 {
+		// This should not happen.
+		panic(data)
+	}
+	header := data[:4]
+	data = data[4:]
+
+	firstRun := true
+	for firstRun || len(data) > 0 {
+		firstRun = false
+		m := len(data)
+		if m > maxLen {
+			m = maxLen
+		}
+
+		// Standard TLS handshake header.
+		fragment := make([]byte, 0, 12+m)
+		fragment = append(fragment, header...)
+		// message_seq
+		fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq))
+		// fragment_offset
+		fragment = append(fragment, byte(n>>16), byte(n>>8), byte(n))
+		// fragment_length
+		fragment = append(fragment, byte(m>>16), byte(m>>8), byte(m))
+		fragment = append(fragment, data[:m]...)
+
+		// TODO(davidben): A real DTLS implementation needs to
+		// retransmit handshake messages. For testing purposes, we don't
+		// actually care.
+		_, err = c.dtlsWriteRawRecord(recordTypeHandshake, fragment)
+		if err != nil {
+			break
+		}
+		n += m
+		data = data[m:]
+	}
+
+	// Increment the handshake sequence number for the next
+	// handshake message.
+	c.sendHandshakeSeq++
+	return
+}
+
+func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
 	recordHeaderLen := dtlsRecordHeaderLen
 	maxLen := c.config.Bugs.MaxHandshakeRecordLength
 	if maxLen <= 0 {
@@ -114,118 +177,58 @@
 
 	b := c.out.newBlock()
 
-	var header []byte
-	if typ == recordTypeHandshake {
-		// Handshake messages have to be modified to include
-		// fragment offset and length and with the header
-		// replicated. Save the header here.
-		//
-		// TODO(davidben): This assumes that data contains
-		// exactly one handshake message. This is incompatible
-		// with FragmentAcrossChangeCipherSpec. (Which is
-		// unfortunate because OpenSSL's DTLS implementation
-		// will probably accept such fragmentation and could
-		// do with a fix + tests.)
-		if len(data) < 4 {
-			// This should not happen.
-			panic(data)
-		}
-		header = data[:4]
-		data = data[4:]
+	explicitIVLen := 0
+	explicitIVIsSeq := false
+
+	if cbc, ok := c.out.cipher.(cbcMode); ok {
+		// Block cipher modes have an explicit IV.
+		explicitIVLen = cbc.BlockSize()
+	} else if _, ok := c.out.cipher.(cipher.AEAD); ok {
+		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 c.out.cipher != nil {
+		panic("Unknown cipher")
 	}
-
-	firstRun := true
-	for firstRun || len(data) > 0 {
-		firstRun = false
-		m := len(data)
-		var fragment []byte
-		// Handshake messages get fragmented. Other records we
-		// pass-through as is. DTLS should be a packet
-		// interface.
-		if typ == recordTypeHandshake {
-			if m > maxLen {
-				m = maxLen
-			}
-
-			// Standard handshake header.
-			fragment = make([]byte, 0, 12+m)
-			fragment = append(fragment, header...)
-			// message_seq
-			fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq))
-			// fragment_offset
-			fragment = append(fragment, byte(n>>16), byte(n>>8), byte(n))
-			// fragment_length
-			fragment = append(fragment, byte(m>>16), byte(m>>8), byte(m))
-			fragment = append(fragment, data[:m]...)
+	b.resize(recordHeaderLen + explicitIVLen + len(data))
+	b.data[0] = byte(typ)
+	vers := c.vers
+	if vers == 0 {
+		// Some TLS servers fail if the record version is greater than
+		// TLS 1.0 for the initial ClientHello.
+		vers = VersionTLS10
+	}
+	vers = versionToWire(vers, c.isDTLS)
+	b.data[1] = byte(vers >> 8)
+	b.data[2] = byte(vers)
+	// DTLS records include an explicit sequence number.
+	copy(b.data[3:11], c.out.seq[0:])
+	b.data[11] = byte(len(data) >> 8)
+	b.data[12] = byte(len(data))
+	if explicitIVLen > 0 {
+		explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+		if explicitIVIsSeq {
+			copy(explicitIV, c.out.seq[:])
 		} else {
-			fragment = data[:m]
-		}
-
-		// Send the fragment.
-		explicitIVLen := 0
-		explicitIVIsSeq := false
-
-		if cbc, ok := c.out.cipher.(cbcMode); ok {
-			// Block cipher modes have an explicit IV.
-			explicitIVLen = cbc.BlockSize()
-		} else if _, ok := c.out.cipher.(cipher.AEAD); ok {
-			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 c.out.cipher != nil {
-			panic("Unknown cipher")
-		}
-		b.resize(recordHeaderLen + explicitIVLen + len(fragment))
-		b.data[0] = byte(typ)
-		vers := c.vers
-		if vers == 0 {
-			// Some TLS servers fail if the record version is
-			// greater than TLS 1.0 for the initial ClientHello.
-			vers = VersionTLS10
-		}
-		vers = versionToWire(vers, c.isDTLS)
-		b.data[1] = byte(vers >> 8)
-		b.data[2] = byte(vers)
-		// DTLS records include an explicit sequence number.
-		copy(b.data[3:11], c.out.seq[0:])
-		b.data[11] = byte(len(fragment) >> 8)
-		b.data[12] = byte(len(fragment))
-		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
-				}
+			if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
+				return
 			}
 		}
-		copy(b.data[recordHeaderLen+explicitIVLen:], fragment)
-		c.out.encrypt(b, explicitIVLen)
-
-		// TODO(davidben): A real DTLS implementation needs to
-		// retransmit handshake messages. For testing
-		// purposes, we don't actually care.
-		_, err = c.conn.Write(b.data)
-		if err != nil {
-			break
-		}
-		n += m
-		data = data[m:]
 	}
+	copy(b.data[recordHeaderLen+explicitIVLen:], data)
+	c.out.encrypt(b, explicitIVLen)
+
+	_, err = c.conn.Write(b.data)
+	if err != nil {
+		return
+	}
+	n = len(data)
+
 	c.out.freeBlock(b)
 
-	// Increment the handshake sequence number for the next
-	// handshake message.
-	if typ == recordTypeHandshake {
-		c.sendHandshakeSeq++
-	}
-
 	if typ == recordTypeChangeCipherSpec {
 		err = c.out.changeCipherSpec(c.config)
 		if err != nil {