Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / boringssl / src / ssl / test / runner / dtls.go
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 }