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