interop_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // Copyright (c) 2021 Tailscale Inc & 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 controlbase
  5. import (
  6. "context"
  7. "encoding/binary"
  8. "errors"
  9. "io"
  10. "net"
  11. "testing"
  12. tsnettest "tailscale.com/net/nettest"
  13. "tailscale.com/types/key"
  14. )
  15. // Can a reference Noise IK client talk to our server?
  16. func TestInteropClient(t *testing.T) {
  17. var (
  18. s1, s2 = tsnettest.NewConn("noise", 128000)
  19. controlKey = key.NewMachine()
  20. machineKey = key.NewMachine()
  21. serverErr = make(chan error, 2)
  22. serverBytes = make(chan []byte, 1)
  23. c2s = "client>server"
  24. s2c = "server>client"
  25. )
  26. go func() {
  27. server, err := Server(context.Background(), s2, controlKey, nil)
  28. serverErr <- err
  29. if err != nil {
  30. return
  31. }
  32. var buf [1024]byte
  33. _, err = io.ReadFull(server, buf[:len(c2s)])
  34. serverBytes <- buf[:len(c2s)]
  35. if err != nil {
  36. serverErr <- err
  37. return
  38. }
  39. _, err = server.Write([]byte(s2c))
  40. serverErr <- err
  41. }()
  42. gotS2C, err := noiseExplorerClient(s1, controlKey.Public(), machineKey, []byte(c2s))
  43. if err != nil {
  44. t.Fatalf("failed client interop: %v", err)
  45. }
  46. if string(gotS2C) != s2c {
  47. t.Fatalf("server sent unexpected data %q, want %q", string(gotS2C), s2c)
  48. }
  49. if err := <-serverErr; err != nil {
  50. t.Fatalf("server handshake failed: %v", err)
  51. }
  52. if err := <-serverErr; err != nil {
  53. t.Fatalf("server read/write failed: %v", err)
  54. }
  55. if got := string(<-serverBytes); got != c2s {
  56. t.Fatalf("server received %q, want %q", got, c2s)
  57. }
  58. }
  59. // Can our client talk to a reference Noise IK server?
  60. func TestInteropServer(t *testing.T) {
  61. var (
  62. s1, s2 = tsnettest.NewConn("noise", 128000)
  63. controlKey = key.NewMachine()
  64. machineKey = key.NewMachine()
  65. clientErr = make(chan error, 2)
  66. clientBytes = make(chan []byte, 1)
  67. c2s = "client>server"
  68. s2c = "server>client"
  69. )
  70. go func() {
  71. client, err := Client(context.Background(), s1, machineKey, controlKey.Public())
  72. clientErr <- err
  73. if err != nil {
  74. return
  75. }
  76. _, err = client.Write([]byte(c2s))
  77. if err != nil {
  78. clientErr <- err
  79. return
  80. }
  81. var buf [1024]byte
  82. _, err = io.ReadFull(client, buf[:len(s2c)])
  83. clientBytes <- buf[:len(s2c)]
  84. clientErr <- err
  85. }()
  86. gotC2S, err := noiseExplorerServer(s2, controlKey, machineKey.Public(), []byte(s2c))
  87. if err != nil {
  88. t.Fatalf("failed server interop: %v", err)
  89. }
  90. if string(gotC2S) != c2s {
  91. t.Fatalf("server sent unexpected data %q, want %q", string(gotC2S), c2s)
  92. }
  93. if err := <-clientErr; err != nil {
  94. t.Fatalf("client handshake failed: %v", err)
  95. }
  96. if err := <-clientErr; err != nil {
  97. t.Fatalf("client read/write failed: %v", err)
  98. }
  99. if got := string(<-clientBytes); got != s2c {
  100. t.Fatalf("client received %q, want %q", got, s2c)
  101. }
  102. }
  103. // noiseExplorerClient uses the Noise Explorer implementation of Noise
  104. // IK to handshake as a Noise client on conn, transmit payload, and
  105. // read+return a payload from the peer.
  106. func noiseExplorerClient(conn net.Conn, controlKey key.MachinePublic, machineKey key.MachinePrivate, payload []byte) ([]byte, error) {
  107. var mk keypair
  108. copy(mk.private_key[:], machineKey.UntypedBytes())
  109. copy(mk.public_key[:], machineKey.Public().UntypedBytes())
  110. var peerKey [32]byte
  111. copy(peerKey[:], controlKey.UntypedBytes())
  112. session := InitSession(true, protocolVersionPrologue(protocolVersion), mk, peerKey)
  113. _, msg1 := SendMessage(&session, nil)
  114. var hdr [initiationHeaderLen]byte
  115. binary.BigEndian.PutUint16(hdr[:2], protocolVersion)
  116. hdr[2] = msgTypeInitiation
  117. binary.BigEndian.PutUint16(hdr[3:5], 96)
  118. if _, err := conn.Write(hdr[:]); err != nil {
  119. return nil, err
  120. }
  121. if _, err := conn.Write(msg1.ne[:]); err != nil {
  122. return nil, err
  123. }
  124. if _, err := conn.Write(msg1.ns); err != nil {
  125. return nil, err
  126. }
  127. if _, err := conn.Write(msg1.ciphertext); err != nil {
  128. return nil, err
  129. }
  130. var buf [1024]byte
  131. if _, err := io.ReadFull(conn, buf[:51]); err != nil {
  132. return nil, err
  133. }
  134. // ignore the header for this test, we're only checking the noise
  135. // implementation.
  136. msg2 := messagebuffer{
  137. ciphertext: buf[35:51],
  138. }
  139. copy(msg2.ne[:], buf[3:35])
  140. _, p, valid := RecvMessage(&session, &msg2)
  141. if !valid {
  142. return nil, errors.New("handshake failed")
  143. }
  144. if len(p) != 0 {
  145. return nil, errors.New("non-empty payload")
  146. }
  147. _, msg3 := SendMessage(&session, payload)
  148. hdr[0] = msgTypeRecord
  149. binary.BigEndian.PutUint16(hdr[1:3], uint16(len(msg3.ciphertext)))
  150. if _, err := conn.Write(hdr[:3]); err != nil {
  151. return nil, err
  152. }
  153. if _, err := conn.Write(msg3.ciphertext); err != nil {
  154. return nil, err
  155. }
  156. if _, err := io.ReadFull(conn, buf[:3]); err != nil {
  157. return nil, err
  158. }
  159. // Ignore all of the header except the payload length
  160. plen := int(binary.BigEndian.Uint16(buf[1:3]))
  161. if _, err := io.ReadFull(conn, buf[:plen]); err != nil {
  162. return nil, err
  163. }
  164. msg4 := messagebuffer{
  165. ciphertext: buf[:plen],
  166. }
  167. _, p, valid = RecvMessage(&session, &msg4)
  168. if !valid {
  169. return nil, errors.New("transport message decryption failed")
  170. }
  171. return p, nil
  172. }
  173. func noiseExplorerServer(conn net.Conn, controlKey key.MachinePrivate, wantMachineKey key.MachinePublic, payload []byte) ([]byte, error) {
  174. var mk keypair
  175. copy(mk.private_key[:], controlKey.UntypedBytes())
  176. copy(mk.public_key[:], controlKey.Public().UntypedBytes())
  177. session := InitSession(false, protocolVersionPrologue(protocolVersion), mk, [32]byte{})
  178. var buf [1024]byte
  179. if _, err := io.ReadFull(conn, buf[:101]); err != nil {
  180. return nil, err
  181. }
  182. // Ignore the header, we're just checking the noise implementation.
  183. msg1 := messagebuffer{
  184. ns: buf[37:85],
  185. ciphertext: buf[85:101],
  186. }
  187. copy(msg1.ne[:], buf[5:37])
  188. _, p, valid := RecvMessage(&session, &msg1)
  189. if !valid {
  190. return nil, errors.New("handshake failed")
  191. }
  192. if len(p) != 0 {
  193. return nil, errors.New("non-empty payload")
  194. }
  195. _, msg2 := SendMessage(&session, nil)
  196. var hdr [headerLen]byte
  197. hdr[0] = msgTypeResponse
  198. binary.BigEndian.PutUint16(hdr[1:3], 48)
  199. if _, err := conn.Write(hdr[:]); err != nil {
  200. return nil, err
  201. }
  202. if _, err := conn.Write(msg2.ne[:]); err != nil {
  203. return nil, err
  204. }
  205. if _, err := conn.Write(msg2.ciphertext[:]); err != nil {
  206. return nil, err
  207. }
  208. if _, err := io.ReadFull(conn, buf[:3]); err != nil {
  209. return nil, err
  210. }
  211. plen := int(binary.BigEndian.Uint16(buf[1:3]))
  212. if _, err := io.ReadFull(conn, buf[:plen]); err != nil {
  213. return nil, err
  214. }
  215. msg3 := messagebuffer{
  216. ciphertext: buf[:plen],
  217. }
  218. _, p, valid = RecvMessage(&session, &msg3)
  219. if !valid {
  220. return nil, errors.New("transport message decryption failed")
  221. }
  222. _, msg4 := SendMessage(&session, payload)
  223. hdr[0] = msgTypeRecord
  224. binary.BigEndian.PutUint16(hdr[1:3], uint16(len(msg4.ciphertext)))
  225. if _, err := conn.Write(hdr[:]); err != nil {
  226. return nil, err
  227. }
  228. if _, err := conn.Write(msg4.ciphertext); err != nil {
  229. return nil, err
  230. }
  231. return p, nil
  232. }