Rebase.
[official-gcc.git] / libgo / go / crypto / tls / handshake_test.go
blobf95f274ab415909f4ce3f838eb779f1856b136a9
1 // Copyright 2013 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.
5 package tls
7 import (
8 "bufio"
9 "encoding/hex"
10 "errors"
11 "flag"
12 "fmt"
13 "io"
14 "io/ioutil"
15 "net"
16 "strconv"
17 "strings"
18 "sync"
21 // TLS reference tests run a connection against a reference implementation
22 // (OpenSSL) of TLS and record the bytes of the resulting connection. The Go
23 // code, during a test, is configured with deterministic randomness and so the
24 // reference test can be reproduced exactly in the future.
26 // In order to save everyone who wishes to run the tests from needing the
27 // reference implementation installed, the reference connections are saved in
28 // files in the testdata directory. Thus running the tests involves nothing
29 // external, but creating and updating them requires the reference
30 // implementation.
32 // Tests can be updated by running them with the -update flag. This will cause
33 // the test files. Generally one should combine the -update flag with -test.run
34 // to updated a specific test. Since the reference implementation will always
35 // generate fresh random numbers, large parts of the reference connection will
36 // always change.
38 var update = flag.Bool("update", false, "update golden files on disk")
40 // recordingConn is a net.Conn that records the traffic that passes through it.
41 // WriteTo can be used to produce output that can be later be loaded with
42 // ParseTestData.
43 type recordingConn struct {
44 net.Conn
45 sync.Mutex
46 flows [][]byte
47 reading bool
50 func (r *recordingConn) Read(b []byte) (n int, err error) {
51 if n, err = r.Conn.Read(b); n == 0 {
52 return
54 b = b[:n]
56 r.Lock()
57 defer r.Unlock()
59 if l := len(r.flows); l == 0 || !r.reading {
60 buf := make([]byte, len(b))
61 copy(buf, b)
62 r.flows = append(r.flows, buf)
63 } else {
64 r.flows[l-1] = append(r.flows[l-1], b[:n]...)
66 r.reading = true
67 return
70 func (r *recordingConn) Write(b []byte) (n int, err error) {
71 if n, err = r.Conn.Write(b); n == 0 {
72 return
74 b = b[:n]
76 r.Lock()
77 defer r.Unlock()
79 if l := len(r.flows); l == 0 || r.reading {
80 buf := make([]byte, len(b))
81 copy(buf, b)
82 r.flows = append(r.flows, buf)
83 } else {
84 r.flows[l-1] = append(r.flows[l-1], b[:n]...)
86 r.reading = false
87 return
90 // WriteTo writes Go source code to w that contains the recorded traffic.
91 func (r *recordingConn) WriteTo(w io.Writer) {
92 // TLS always starts with a client to server flow.
93 clientToServer := true
95 for i, flow := range r.flows {
96 source, dest := "client", "server"
97 if !clientToServer {
98 source, dest = dest, source
100 fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
101 dumper := hex.Dumper(w)
102 dumper.Write(flow)
103 dumper.Close()
104 clientToServer = !clientToServer
108 func parseTestData(r io.Reader) (flows [][]byte, err error) {
109 var currentFlow []byte
111 scanner := bufio.NewScanner(r)
112 for scanner.Scan() {
113 line := scanner.Text()
114 // If the line starts with ">>> " then it marks the beginning
115 // of a new flow.
116 if strings.HasPrefix(line, ">>> ") {
117 if len(currentFlow) > 0 || len(flows) > 0 {
118 flows = append(flows, currentFlow)
119 currentFlow = nil
121 continue
124 // Otherwise the line is a line of hex dump that looks like:
125 // 00000170 fc f5 06 bf (...) |.....X{&?......!|
126 // (Some bytes have been omitted from the middle section.)
128 if i := strings.IndexByte(line, ' '); i >= 0 {
129 line = line[i:]
130 } else {
131 return nil, errors.New("invalid test data")
134 if i := strings.IndexByte(line, '|'); i >= 0 {
135 line = line[:i]
136 } else {
137 return nil, errors.New("invalid test data")
140 hexBytes := strings.Fields(line)
141 for _, hexByte := range hexBytes {
142 val, err := strconv.ParseUint(hexByte, 16, 8)
143 if err != nil {
144 return nil, errors.New("invalid hex byte in test data: " + err.Error())
146 currentFlow = append(currentFlow, byte(val))
150 if len(currentFlow) > 0 {
151 flows = append(flows, currentFlow)
154 return flows, nil
157 // tempFile creates a temp file containing contents and returns its path.
158 func tempFile(contents string) string {
159 file, err := ioutil.TempFile("", "go-tls-test")
160 if err != nil {
161 panic("failed to create temp file: " + err.Error())
163 path := file.Name()
164 file.WriteString(contents)
165 file.Close()
166 return path