Home | History | Annotate | Download | only in runner
      1 // Copyright 2014 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // DTLS implementation.
      6 //
      7 // NOTE: This is a not even a remotely production-quality DTLS
      8 // implementation. It is the bare minimum necessary to be able to
      9 // achieve coverage on BoringSSL's implementation. Of note is that
     10 // this implementation assumes the underlying net.PacketConn is not
     11 // only reliable but also ordered. BoringSSL will be expected to deal
     12 // with simulated loss, but there is no point in forcing the test
     13 // driver to.
     14 
     15 package main
     16 
     17 import (
     18 	"bytes"
     19 	"crypto/cipher"
     20 	"errors"
     21 	"fmt"
     22 	"io"
     23 	"net"
     24 )
     25 
     26 func versionToWire(vers uint16, isDTLS bool) uint16 {
     27 	if isDTLS {
     28 		return ^(vers - 0x0201)
     29 	}
     30 	return vers
     31 }
     32 
     33 func wireToVersion(vers uint16, isDTLS bool) uint16 {
     34 	if isDTLS {
     35 		return ^vers + 0x0201
     36 	}
     37 	return vers
     38 }
     39 
     40 func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
     41 	recordHeaderLen := dtlsRecordHeaderLen
     42 
     43 	if c.rawInput == nil {
     44 		c.rawInput = c.in.newBlock()
     45 	}
     46 	b := c.rawInput
     47 
     48 	// Read a new packet only if the current one is empty.
     49 	if len(b.data) == 0 {
     50 		// Pick some absurdly large buffer size.
     51 		b.resize(maxCiphertext + recordHeaderLen)
     52 		n, err := c.conn.Read(c.rawInput.data)
     53 		if err != nil {
     54 			return 0, nil, err
     55 		}
     56 		c.rawInput.resize(n)
     57 	}
     58 
     59 	// Read out one record.
     60 	//
     61 	// A real DTLS implementation should be tolerant of errors,
     62 	// but this is test code. We should not be tolerant of our
     63 	// peer sending garbage.
     64 	if len(b.data) < recordHeaderLen {
     65 		return 0, nil, errors.New("dtls: failed to read record header")
     66 	}
     67 	typ := recordType(b.data[0])
     68 	vers := wireToVersion(uint16(b.data[1])<<8|uint16(b.data[2]), c.isDTLS)
     69 	if c.haveVers && vers != c.vers {
     70 		c.sendAlert(alertProtocolVersion)
     71 		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, c.vers))
     72 	}
     73 	seq := b.data[3:11]
     74 	// For test purposes, we assume a reliable channel. Require
     75 	// that the explicit sequence number matches the incrementing
     76 	// one we maintain. A real implementation would maintain a
     77 	// replay window and such.
     78 	if !bytes.Equal(seq, c.in.seq[:]) {
     79 		c.sendAlert(alertIllegalParameter)
     80 		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad sequence number"))
     81 	}
     82 	n := int(b.data[11])<<8 | int(b.data[12])
     83 	if n > maxCiphertext || len(b.data) < recordHeaderLen+n {
     84 		c.sendAlert(alertRecordOverflow)
     85 		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: oversized record received with length %d", n))
     86 	}
     87 
     88 	// Process message.
     89 	b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
     90 	ok, off, err := c.in.decrypt(b)
     91 	if !ok {
     92 		c.in.setErrorLocked(c.sendAlert(err))
     93 	}
     94 	b.off = off
     95 	return typ, b, nil
     96 }
     97 
     98 func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
     99 	recordHeaderLen := dtlsRecordHeaderLen
    100 	maxLen := c.config.Bugs.MaxHandshakeRecordLength
    101 	if maxLen <= 0 {
    102 		maxLen = 1024
    103 	}
    104 
    105 	b := c.out.newBlock()
    106 
    107 	var header []byte
    108 	if typ == recordTypeHandshake {
    109 		// Handshake messages have to be modified to include
    110 		// fragment offset and length and with the header
    111 		// replicated. Save the header here.
    112 		//
    113 		// TODO(davidben): This assumes that data contains
    114 		// exactly one handshake message. This is incompatible
    115 		// with FragmentAcrossChangeCipherSpec. (Which is
    116 		// unfortunate because OpenSSL's DTLS implementation
    117 		// will probably accept such fragmentation and could
    118 		// do with a fix + tests.)
    119 		if len(data) < 4 {
    120 			// This should not happen.
    121 			panic(data)
    122 		}
    123 		header = data[:4]
    124 		data = data[4:]
    125 	}
    126 
    127 	firstRun := true
    128 	for firstRun || len(data) > 0 {
    129 		firstRun = false
    130 		m := len(data)
    131 		var fragment []byte
    132 		// Handshake messages get fragmented. Other records we
    133 		// pass-through as is. DTLS should be a packet
    134 		// interface.
    135 		if typ == recordTypeHandshake {
    136 			if m > maxLen {
    137 				m = maxLen
    138 			}
    139 
    140 			// Standard handshake header.
    141 			fragment = make([]byte, 0, 12+m)
    142 			fragment = append(fragment, header...)
    143 			// message_seq
    144 			fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq))
    145 			// fragment_offset
    146 			fragment = append(fragment, byte(n>>16), byte(n>>8), byte(n))
    147 			// fragment_length
    148 			fragment = append(fragment, byte(m>>16), byte(m>>8), byte(m))
    149 			fragment = append(fragment, data[:m]...)
    150 		} else {
    151 			fragment = data[:m]
    152 		}
    153 
    154 		// Send the fragment.
    155 		explicitIVLen := 0
    156 		explicitIVIsSeq := false
    157 
    158 		if cbc, ok := c.out.cipher.(cbcMode); ok {
    159 			// Block cipher modes have an explicit IV.
    160 			explicitIVLen = cbc.BlockSize()
    161 		} else if _, ok := c.out.cipher.(cipher.AEAD); ok {
    162 			explicitIVLen = 8
    163 			// The AES-GCM construction in TLS has an
    164 			// explicit nonce so that the nonce can be
    165 			// random. However, the nonce is only 8 bytes
    166 			// which is too small for a secure, random
    167 			// nonce. Therefore we use the sequence number
    168 			// as the nonce.
    169 			explicitIVIsSeq = true
    170 		} else if c.out.cipher != nil {
    171 			panic("Unknown cipher")
    172 		}
    173 		b.resize(recordHeaderLen + explicitIVLen + len(fragment))
    174 		b.data[0] = byte(typ)
    175 		vers := c.vers
    176 		if vers == 0 {
    177 			// Some TLS servers fail if the record version is
    178 			// greater than TLS 1.0 for the initial ClientHello.
    179 			vers = VersionTLS10
    180 		}
    181 		vers = versionToWire(vers, c.isDTLS)
    182 		b.data[1] = byte(vers >> 8)
    183 		b.data[2] = byte(vers)
    184 		// DTLS records include an explicit sequence number.
    185 		copy(b.data[3:11], c.out.seq[0:])
    186 		b.data[11] = byte(len(fragment) >> 8)
    187 		b.data[12] = byte(len(fragment))
    188 		if explicitIVLen > 0 {
    189 			explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
    190 			if explicitIVIsSeq {
    191 				copy(explicitIV, c.out.seq[:])
    192 			} else {
    193 				if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
    194 					break
    195 				}
    196 			}
    197 		}
    198 		copy(b.data[recordHeaderLen+explicitIVLen:], fragment)
    199 		c.out.encrypt(b, explicitIVLen)
    200 
    201 		// TODO(davidben): A real DTLS implementation needs to
    202 		// retransmit handshake messages. For testing
    203 		// purposes, we don't actually care.
    204 		_, err = c.conn.Write(b.data)
    205 		if err != nil {
    206 			break
    207 		}
    208 		n += m
    209 		data = data[m:]
    210 	}
    211 	c.out.freeBlock(b)
    212 
    213 	// Increment the handshake sequence number for the next
    214 	// handshake message.
    215 	if typ == recordTypeHandshake {
    216 		c.sendHandshakeSeq++
    217 	}
    218 
    219 	if typ == recordTypeChangeCipherSpec {
    220 		err = c.out.changeCipherSpec(c.config)
    221 		if err != nil {
    222 			// Cannot call sendAlert directly,
    223 			// because we already hold c.out.Mutex.
    224 			c.tmp[0] = alertLevelError
    225 			c.tmp[1] = byte(err.(alert))
    226 			c.writeRecord(recordTypeAlert, c.tmp[0:2])
    227 			return n, c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
    228 		}
    229 	}
    230 	return
    231 }
    232 
    233 func (c *Conn) dtlsDoReadHandshake() ([]byte, error) {
    234 	// Assemble a full handshake message.  For test purposes, this
    235 	// implementation assumes fragments arrive in order. It may
    236 	// need to be cleverer if we ever test BoringSSL's retransmit
    237 	// behavior.
    238 	for len(c.handMsg) < 4+c.handMsgLen {
    239 		// Get a new handshake record if the previous has been
    240 		// exhausted.
    241 		if c.hand.Len() == 0 {
    242 			if err := c.in.err; err != nil {
    243 				return nil, err
    244 			}
    245 			if err := c.readRecord(recordTypeHandshake); err != nil {
    246 				return nil, err
    247 			}
    248 		}
    249 
    250 		// Read the next fragment. It must fit entirely within
    251 		// the record.
    252 		if c.hand.Len() < 12 {
    253 			return nil, errors.New("dtls: bad handshake record")
    254 		}
    255 		header := c.hand.Next(12)
    256 		fragN := int(header[1])<<16 | int(header[2])<<8 | int(header[3])
    257 		fragSeq := uint16(header[4])<<8 | uint16(header[5])
    258 		fragOff := int(header[6])<<16 | int(header[7])<<8 | int(header[8])
    259 		fragLen := int(header[9])<<16 | int(header[10])<<8 | int(header[11])
    260 
    261 		if c.hand.Len() < fragLen {
    262 			return nil, errors.New("dtls: fragment length too long")
    263 		}
    264 		fragment := c.hand.Next(fragLen)
    265 
    266 		// Check it's a fragment for the right message.
    267 		if fragSeq != c.recvHandshakeSeq {
    268 			return nil, errors.New("dtls: bad handshake sequence number")
    269 		}
    270 
    271 		// Check that the length is consistent.
    272 		if c.handMsg == nil {
    273 			c.handMsgLen = fragN
    274 			if c.handMsgLen > maxHandshake {
    275 				return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
    276 			}
    277 			// Start with the TLS handshake header,
    278 			// without the DTLS bits.
    279 			c.handMsg = append([]byte{}, header[:4]...)
    280 		} else if fragN != c.handMsgLen {
    281 			return nil, errors.New("dtls: bad handshake length")
    282 		}
    283 
    284 		// Add the fragment to the pending message.
    285 		if 4+fragOff != len(c.handMsg) {
    286 			return nil, errors.New("dtls: bad fragment offset")
    287 		}
    288 		if fragOff+fragLen > c.handMsgLen {
    289 			return nil, errors.New("dtls: bad fragment length")
    290 		}
    291 		c.handMsg = append(c.handMsg, fragment...)
    292 	}
    293 	c.recvHandshakeSeq++
    294 	ret := c.handMsg
    295 	c.handMsg, c.handMsgLen = nil, 0
    296 	return ret, nil
    297 }
    298 
    299 // DTLSServer returns a new DTLS server side connection
    300 // using conn as the underlying transport.
    301 // The configuration config must be non-nil and must have
    302 // at least one certificate.
    303 func DTLSServer(conn net.Conn, config *Config) *Conn {
    304 	return &Conn{
    305 		config: config,
    306 		isDTLS: true,
    307 		conn:   conn,
    308 		in:     halfConn{isDTLS: true},
    309 		out:    halfConn{isDTLS: true},
    310 	}
    311 }
    312 
    313 // DTLSClient returns a new DTLS client side connection
    314 // using conn as the underlying transport.
    315 // The config cannot be nil: users must set either ServerHostname or
    316 // InsecureSkipVerify in the config.
    317 func DTLSClient(conn net.Conn, config *Config) *Conn {
    318 	return &Conn{
    319 		config:   config,
    320 		isClient: true,
    321 		isDTLS:   true,
    322 		conn:     conn,
    323 		in:       halfConn{isDTLS: true},
    324 		out:      halfConn{isDTLS: true},
    325 	}
    326 }
    327