• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
15package runner
16
17import (
18	"bytes"
19	"errors"
20	"fmt"
21	"io"
22	"math/rand"
23	"net"
24)
25
26func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
27	if isDTLS {
28		switch vers {
29		case VersionDTLS12:
30			return VersionTLS12, true
31		case VersionDTLS10:
32			return VersionTLS10, true
33		}
34	} else {
35		switch vers {
36		case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
37			return vers, true
38		case tls13DraftVersion, tls13ExperimentVersion, tls13RecordTypeExperimentVersion:
39			return VersionTLS13, true
40		}
41	}
42
43	return 0, false
44}
45
46func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) {
47	recordHeaderLen := dtlsRecordHeaderLen
48
49	if c.rawInput == nil {
50		c.rawInput = c.in.newBlock()
51	}
52	b := c.rawInput
53
54	// Read a new packet only if the current one is empty.
55	var newPacket bool
56	if len(b.data) == 0 {
57		// Pick some absurdly large buffer size.
58		b.resize(maxCiphertext + recordHeaderLen)
59		n, err := c.conn.Read(c.rawInput.data)
60		if err != nil {
61			return 0, nil, err
62		}
63		if c.config.Bugs.MaxPacketLength != 0 && n > c.config.Bugs.MaxPacketLength {
64			return 0, nil, fmt.Errorf("dtls: exceeded maximum packet length")
65		}
66		c.rawInput.resize(n)
67		newPacket = true
68	}
69
70	// Read out one record.
71	//
72	// A real DTLS implementation should be tolerant of errors,
73	// but this is test code. We should not be tolerant of our
74	// peer sending garbage.
75	if len(b.data) < recordHeaderLen {
76		return 0, nil, errors.New("dtls: failed to read record header")
77	}
78	typ := recordType(b.data[0])
79	vers := uint16(b.data[1])<<8 | uint16(b.data[2])
80	// Alerts sent near version negotiation do not have a well-defined
81	// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
82	// version is irrelevant.)
83	if typ != recordTypeAlert {
84		if c.haveVers {
85			if vers != c.wireVersion {
86				c.sendAlert(alertProtocolVersion)
87				return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, c.wireVersion))
88			}
89		} else {
90			// Pre-version-negotiation alerts may be sent with any version.
91			if expect := c.config.Bugs.ExpectInitialRecordVersion; expect != 0 && vers != expect {
92				c.sendAlert(alertProtocolVersion)
93				return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, expect))
94			}
95		}
96	}
97	epoch := b.data[3:5]
98	seq := b.data[5:11]
99	// For test purposes, require the sequence number be monotonically
100	// increasing, so c.in includes the minimum next sequence number. Gaps
101	// may occur if packets failed to be sent out. A real implementation
102	// would maintain a replay window and such.
103	if !bytes.Equal(epoch, c.in.seq[:2]) {
104		c.sendAlert(alertIllegalParameter)
105		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad epoch"))
106	}
107	if bytes.Compare(seq, c.in.seq[2:]) < 0 {
108		c.sendAlert(alertIllegalParameter)
109		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: bad sequence number"))
110	}
111	copy(c.in.seq[2:], seq)
112	n := int(b.data[11])<<8 | int(b.data[12])
113	if n > maxCiphertext || len(b.data) < recordHeaderLen+n {
114		c.sendAlert(alertRecordOverflow)
115		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: oversized record received with length %d", n))
116	}
117
118	// Process message.
119	b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
120	ok, off, _, alertValue := c.in.decrypt(b)
121	if !ok {
122		// A real DTLS implementation would silently ignore bad records,
123		// but we want to notice errors from the implementation under
124		// test.
125		return 0, nil, c.in.setErrorLocked(c.sendAlert(alertValue))
126	}
127	b.off = off
128
129	// TODO(nharper): Once DTLS 1.3 is defined, handle the extra
130	// parameter from decrypt.
131
132	// Require that ChangeCipherSpec always share a packet with either the
133	// previous or next handshake message.
134	if newPacket && typ == recordTypeChangeCipherSpec && c.rawInput == nil {
135		return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: ChangeCipherSpec not packed together with Finished"))
136	}
137
138	return typ, b, nil
139}
140
141func (c *Conn) makeFragment(header, data []byte, fragOffset, fragLen int) []byte {
142	fragment := make([]byte, 0, 12+fragLen)
143	fragment = append(fragment, header...)
144	fragment = append(fragment, byte(c.sendHandshakeSeq>>8), byte(c.sendHandshakeSeq))
145	fragment = append(fragment, byte(fragOffset>>16), byte(fragOffset>>8), byte(fragOffset))
146	fragment = append(fragment, byte(fragLen>>16), byte(fragLen>>8), byte(fragLen))
147	fragment = append(fragment, data[fragOffset:fragOffset+fragLen]...)
148	return fragment
149}
150
151func (c *Conn) dtlsWriteRecord(typ recordType, data []byte) (n int, err error) {
152	if typ != recordTypeHandshake {
153		// Only handshake messages are fragmented.
154		n, err = c.dtlsWriteRawRecord(typ, data)
155		if err != nil {
156			return
157		}
158
159		if typ == recordTypeChangeCipherSpec {
160			err = c.out.changeCipherSpec(c.config)
161			if err != nil {
162				return n, c.sendAlertLocked(alertLevelError, err.(alert))
163			}
164		}
165		return
166	}
167
168	if c.out.cipher == nil && c.config.Bugs.StrayChangeCipherSpec {
169		_, err = c.dtlsWriteRawRecord(recordTypeChangeCipherSpec, []byte{1})
170		if err != nil {
171			return
172		}
173	}
174
175	maxLen := c.config.Bugs.MaxHandshakeRecordLength
176	if maxLen <= 0 {
177		maxLen = 1024
178	}
179
180	// Handshake messages have to be modified to include fragment
181	// offset and length and with the header replicated. Save the
182	// TLS header here.
183	//
184	// TODO(davidben): This assumes that data contains exactly one
185	// handshake message. This is incompatible with
186	// FragmentAcrossChangeCipherSpec. (Which is unfortunate
187	// because OpenSSL's DTLS implementation will probably accept
188	// such fragmentation and could do with a fix + tests.)
189	header := data[:4]
190	data = data[4:]
191
192	isFinished := header[0] == typeFinished
193
194	if c.config.Bugs.SendEmptyFragments {
195		fragment := c.makeFragment(header, data, 0, 0)
196		c.pendingFragments = append(c.pendingFragments, fragment)
197	}
198
199	firstRun := true
200	fragOffset := 0
201	for firstRun || fragOffset < len(data) {
202		firstRun = false
203		fragLen := len(data) - fragOffset
204		if fragLen > maxLen {
205			fragLen = maxLen
206		}
207
208		fragment := c.makeFragment(header, data, fragOffset, fragLen)
209		if c.config.Bugs.FragmentMessageTypeMismatch && fragOffset > 0 {
210			fragment[0]++
211		}
212		if c.config.Bugs.FragmentMessageLengthMismatch && fragOffset > 0 {
213			fragment[3]++
214		}
215
216		// Buffer the fragment for later. They will be sent (and
217		// reordered) on flush.
218		c.pendingFragments = append(c.pendingFragments, fragment)
219		if c.config.Bugs.ReorderHandshakeFragments {
220			// Don't duplicate Finished to avoid the peer
221			// interpreting it as a retransmit request.
222			if !isFinished {
223				c.pendingFragments = append(c.pendingFragments, fragment)
224			}
225
226			if fragLen > (maxLen+1)/2 {
227				// Overlap each fragment by half.
228				fragLen = (maxLen + 1) / 2
229			}
230		}
231		fragOffset += fragLen
232		n += fragLen
233	}
234	if !isFinished && c.config.Bugs.MixCompleteMessageWithFragments {
235		fragment := c.makeFragment(header, data, 0, len(data))
236		c.pendingFragments = append(c.pendingFragments, fragment)
237	}
238
239	// Increment the handshake sequence number for the next
240	// handshake message.
241	c.sendHandshakeSeq++
242	return
243}
244
245func (c *Conn) dtlsFlushHandshake() error {
246	// This is a test-only DTLS implementation, so there is no need to
247	// retain |c.pendingFragments| for a future retransmit.
248	var fragments [][]byte
249	fragments, c.pendingFragments = c.pendingFragments, fragments
250
251	if c.config.Bugs.ReorderHandshakeFragments {
252		perm := rand.New(rand.NewSource(0)).Perm(len(fragments))
253		tmp := make([][]byte, len(fragments))
254		for i := range tmp {
255			tmp[i] = fragments[perm[i]]
256		}
257		fragments = tmp
258	} else if c.config.Bugs.ReverseHandshakeFragments {
259		tmp := make([][]byte, len(fragments))
260		for i := range tmp {
261			tmp[i] = fragments[len(fragments)-i-1]
262		}
263		fragments = tmp
264	}
265
266	maxRecordLen := c.config.Bugs.PackHandshakeFragments
267	maxPacketLen := c.config.Bugs.PackHandshakeRecords
268
269	// Pack handshake fragments into records.
270	var records [][]byte
271	for _, fragment := range fragments {
272		if n := c.config.Bugs.SplitFragments; n > 0 {
273			if len(fragment) > n {
274				records = append(records, fragment[:n])
275				records = append(records, fragment[n:])
276			} else {
277				records = append(records, fragment)
278			}
279		} else if i := len(records) - 1; len(records) > 0 && len(records[i])+len(fragment) <= maxRecordLen {
280			records[i] = append(records[i], fragment...)
281		} else {
282			// The fragment will be appended to, so copy it.
283			records = append(records, append([]byte{}, fragment...))
284		}
285	}
286
287	// Format them into packets.
288	var packets [][]byte
289	for _, record := range records {
290		b, err := c.dtlsSealRecord(recordTypeHandshake, record)
291		if err != nil {
292			return err
293		}
294
295		if i := len(packets) - 1; len(packets) > 0 && len(packets[i])+len(b.data) <= maxPacketLen {
296			packets[i] = append(packets[i], b.data...)
297		} else {
298			// The sealed record will be appended to and reused by
299			// |c.out|, so copy it.
300			packets = append(packets, append([]byte{}, b.data...))
301		}
302		c.out.freeBlock(b)
303	}
304
305	// Send all the packets.
306	for _, packet := range packets {
307		if _, err := c.conn.Write(packet); err != nil {
308			return err
309		}
310	}
311	return nil
312}
313
314// dtlsSealRecord seals a record into a block from |c.out|'s pool.
315func (c *Conn) dtlsSealRecord(typ recordType, data []byte) (b *block, err error) {
316	recordHeaderLen := dtlsRecordHeaderLen
317	maxLen := c.config.Bugs.MaxHandshakeRecordLength
318	if maxLen <= 0 {
319		maxLen = 1024
320	}
321
322	b = c.out.newBlock()
323
324	explicitIVLen := 0
325	explicitIVIsSeq := false
326
327	if cbc, ok := c.out.cipher.(cbcMode); ok {
328		// Block cipher modes have an explicit IV.
329		explicitIVLen = cbc.BlockSize()
330	} else if aead, ok := c.out.cipher.(*tlsAead); ok {
331		if aead.explicitNonce {
332			explicitIVLen = 8
333			// The AES-GCM construction in TLS has an explicit nonce so that
334			// the nonce can be random. However, the nonce is only 8 bytes
335			// which is too small for a secure, random nonce. Therefore we
336			// use the sequence number as the nonce.
337			explicitIVIsSeq = true
338		}
339	} else if _, ok := c.out.cipher.(nullCipher); !ok && c.out.cipher != nil {
340		panic("Unknown cipher")
341	}
342	b.resize(recordHeaderLen + explicitIVLen + len(data))
343	// TODO(nharper): DTLS 1.3 will likely need to set this to
344	// recordTypeApplicationData if c.out.cipher != nil.
345	b.data[0] = byte(typ)
346	vers := c.wireVersion
347	if vers == 0 {
348		// Some TLS servers fail if the record version is greater than
349		// TLS 1.0 for the initial ClientHello.
350		if c.isDTLS {
351			vers = VersionDTLS10
352		} else {
353			vers = VersionTLS10
354		}
355	}
356	b.data[1] = byte(vers >> 8)
357	b.data[2] = byte(vers)
358	// DTLS records include an explicit sequence number.
359	copy(b.data[3:11], c.out.outSeq[0:])
360	b.data[11] = byte(len(data) >> 8)
361	b.data[12] = byte(len(data))
362	if explicitIVLen > 0 {
363		explicitIV := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
364		if explicitIVIsSeq {
365			copy(explicitIV, c.out.outSeq[:])
366		} else {
367			if _, err = io.ReadFull(c.config.rand(), explicitIV); err != nil {
368				return
369			}
370		}
371	}
372	copy(b.data[recordHeaderLen+explicitIVLen:], data)
373	c.out.encrypt(b, explicitIVLen, typ)
374	return
375}
376
377func (c *Conn) dtlsWriteRawRecord(typ recordType, data []byte) (n int, err error) {
378	b, err := c.dtlsSealRecord(typ, data)
379	if err != nil {
380		return
381	}
382
383	_, err = c.conn.Write(b.data)
384	if err != nil {
385		return
386	}
387	n = len(data)
388
389	c.out.freeBlock(b)
390	return
391}
392
393func (c *Conn) dtlsDoReadHandshake() ([]byte, error) {
394	// Assemble a full handshake message.  For test purposes, this
395	// implementation assumes fragments arrive in order. It may
396	// need to be cleverer if we ever test BoringSSL's retransmit
397	// behavior.
398	for len(c.handMsg) < 4+c.handMsgLen {
399		// Get a new handshake record if the previous has been
400		// exhausted.
401		if c.hand.Len() == 0 {
402			if err := c.in.err; err != nil {
403				return nil, err
404			}
405			if err := c.readRecord(recordTypeHandshake); err != nil {
406				return nil, err
407			}
408		}
409
410		// Read the next fragment. It must fit entirely within
411		// the record.
412		if c.hand.Len() < 12 {
413			return nil, errors.New("dtls: bad handshake record")
414		}
415		header := c.hand.Next(12)
416		fragN := int(header[1])<<16 | int(header[2])<<8 | int(header[3])
417		fragSeq := uint16(header[4])<<8 | uint16(header[5])
418		fragOff := int(header[6])<<16 | int(header[7])<<8 | int(header[8])
419		fragLen := int(header[9])<<16 | int(header[10])<<8 | int(header[11])
420
421		if c.hand.Len() < fragLen {
422			return nil, errors.New("dtls: fragment length too long")
423		}
424		fragment := c.hand.Next(fragLen)
425
426		// Check it's a fragment for the right message.
427		if fragSeq != c.recvHandshakeSeq {
428			return nil, errors.New("dtls: bad handshake sequence number")
429		}
430
431		// Check that the length is consistent.
432		if c.handMsg == nil {
433			c.handMsgLen = fragN
434			if c.handMsgLen > maxHandshake {
435				return nil, c.in.setErrorLocked(c.sendAlert(alertInternalError))
436			}
437			// Start with the TLS handshake header,
438			// without the DTLS bits.
439			c.handMsg = append([]byte{}, header[:4]...)
440		} else if fragN != c.handMsgLen {
441			return nil, errors.New("dtls: bad handshake length")
442		}
443
444		// Add the fragment to the pending message.
445		if 4+fragOff != len(c.handMsg) {
446			return nil, errors.New("dtls: bad fragment offset")
447		}
448		if fragOff+fragLen > c.handMsgLen {
449			return nil, errors.New("dtls: bad fragment length")
450		}
451		c.handMsg = append(c.handMsg, fragment...)
452	}
453	c.recvHandshakeSeq++
454	ret := c.handMsg
455	c.handMsg, c.handMsgLen = nil, 0
456	return ret, nil
457}
458
459// DTLSServer returns a new DTLS server side connection
460// using conn as the underlying transport.
461// The configuration config must be non-nil and must have
462// at least one certificate.
463func DTLSServer(conn net.Conn, config *Config) *Conn {
464	c := &Conn{config: config, isDTLS: true, conn: conn}
465	c.init()
466	return c
467}
468
469// DTLSClient returns a new DTLS client side connection
470// using conn as the underlying transport.
471// The config cannot be nil: users must set either ServerHostname or
472// InsecureSkipVerify in the config.
473func DTLSClient(conn net.Conn, config *Config) *Conn {
474	c := &Conn{config: config, isClient: true, isDTLS: true, conn: conn}
475	c.init()
476	return c
477}
478