github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/src/crypto/tls/handshake_test.go (about)

     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.
     4  
     5  package tls
     6  
     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"
    19  )
    20  
    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.
    25  //
    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.
    31  //
    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.
    37  
    38  var update = flag.Bool("update", false, "update golden files on disk")
    39  
    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
    48  }
    49  
    50  func (r *recordingConn) Read(b []byte) (n int, err error) {
    51  	if n, err = r.Conn.Read(b); n == 0 {
    52  		return
    53  	}
    54  	b = b[:n]
    55  
    56  	r.Lock()
    57  	defer r.Unlock()
    58  
    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]...)
    65  	}
    66  	r.reading = true
    67  	return
    68  }
    69  
    70  func (r *recordingConn) Write(b []byte) (n int, err error) {
    71  	if n, err = r.Conn.Write(b); n == 0 {
    72  		return
    73  	}
    74  	b = b[:n]
    75  
    76  	r.Lock()
    77  	defer r.Unlock()
    78  
    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]...)
    85  	}
    86  	r.reading = false
    87  	return
    88  }
    89  
    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
    94  
    95  	for i, flow := range r.flows {
    96  		source, dest := "client", "server"
    97  		if !clientToServer {
    98  			source, dest = dest, source
    99  		}
   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
   105  	}
   106  }
   107  
   108  func parseTestData(r io.Reader) (flows [][]byte, err error) {
   109  	var currentFlow []byte
   110  
   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
   120  			}
   121  			continue
   122  		}
   123  
   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.)
   127  
   128  		if i := strings.IndexByte(line, ' '); i >= 0 {
   129  			line = line[i:]
   130  		} else {
   131  			return nil, errors.New("invalid test data")
   132  		}
   133  
   134  		if i := strings.IndexByte(line, '|'); i >= 0 {
   135  			line = line[:i]
   136  		} else {
   137  			return nil, errors.New("invalid test data")
   138  		}
   139  
   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())
   145  			}
   146  			currentFlow = append(currentFlow, byte(val))
   147  		}
   148  	}
   149  
   150  	if len(currentFlow) > 0 {
   151  		flows = append(flows, currentFlow)
   152  	}
   153  
   154  	return flows, nil
   155  }
   156  
   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())
   162  	}
   163  	path := file.Name()
   164  	file.WriteString(contents)
   165  	file.Close()
   166  	return path
   167  }