You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

168 rivejä
4.2 KiB

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