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.
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
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
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
43 type recordingConn
struct {
50 func (r
*recordingConn
) Read(b
[]byte) (n
int, err error
) {
51 if n
, err
= r
.Conn
.Read(b
); n
== 0 {
59 if l
:= len(r
.flows
); l
== 0 ||
!r
.reading
{
60 buf
:= make([]byte, len(b
))
62 r
.flows
= append(r
.flows
, buf
)
64 r
.flows
[l
-1] = append(r
.flows
[l
-1], b
[:n
]...)
70 func (r
*recordingConn
) Write(b
[]byte) (n
int, err error
) {
71 if n
, err
= r
.Conn
.Write(b
); n
== 0 {
79 if l
:= len(r
.flows
); l
== 0 || r
.reading
{
80 buf
:= make([]byte, len(b
))
82 r
.flows
= append(r
.flows
, buf
)
84 r
.flows
[l
-1] = append(r
.flows
[l
-1], b
[:n
]...)
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"
98 source
, dest
= dest
, source
100 fmt
.Fprintf(w
, ">>> Flow %d (%s to %s)\n", i
+1, source
, dest
)
101 dumper
:= hex
.Dumper(w
)
104 clientToServer
= !clientToServer
108 func parseTestData(r io
.Reader
) (flows
[][]byte, err error
) {
109 var currentFlow
[]byte
111 scanner
:= bufio
.NewScanner(r
)
113 line
:= scanner
.Text()
114 // If the line starts with ">>> " then it marks the beginning
116 if strings
.HasPrefix(line
, ">>> ") {
117 if len(currentFlow
) > 0 ||
len(flows
) > 0 {
118 flows
= append(flows
, currentFlow
)
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 {
131 return nil, errors
.New("invalid test data")
134 if i
:= strings
.IndexByte(line
, '|'); i
>= 0 {
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)
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
)
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")
161 panic("failed to create temp file: " + err
.Error())
164 file
.WriteString(contents
)