client_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. // Copyright 2012 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 agent
  5. import (
  6. "bytes"
  7. "crypto/rand"
  8. "errors"
  9. "io"
  10. "net"
  11. "os"
  12. "os/exec"
  13. "path/filepath"
  14. "runtime"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "testing"
  19. "time"
  20. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
  21. )
  22. // startOpenSSHAgent executes ssh-agent, and returns an Agent interface to it.
  23. func startOpenSSHAgent(t *testing.T) (client ExtendedAgent, socket string, cleanup func()) {
  24. if testing.Short() {
  25. // ssh-agent is not always available, and the key
  26. // types supported vary by platform.
  27. t.Skip("skipping test due to -short")
  28. }
  29. bin, err := exec.LookPath("ssh-agent")
  30. if err != nil {
  31. t.Skip("could not find ssh-agent")
  32. }
  33. cmd := exec.Command(bin, "-s")
  34. cmd.Env = []string{} // Do not let the user's environment influence ssh-agent behavior.
  35. cmd.Stderr = new(bytes.Buffer)
  36. out, err := cmd.Output()
  37. if err != nil {
  38. t.Fatalf("%s failed: %v\n%s", strings.Join(cmd.Args, " "), err, cmd.Stderr)
  39. }
  40. // Output looks like:
  41. //
  42. // SSH_AUTH_SOCK=/tmp/ssh-P65gpcqArqvH/agent.15541; export SSH_AUTH_SOCK;
  43. // SSH_AGENT_PID=15542; export SSH_AGENT_PID;
  44. // echo Agent pid 15542;
  45. fields := bytes.Split(out, []byte(";"))
  46. line := bytes.SplitN(fields[0], []byte("="), 2)
  47. line[0] = bytes.TrimLeft(line[0], "\n")
  48. if string(line[0]) != "SSH_AUTH_SOCK" {
  49. t.Fatalf("could not find key SSH_AUTH_SOCK in %q", fields[0])
  50. }
  51. socket = string(line[1])
  52. line = bytes.SplitN(fields[2], []byte("="), 2)
  53. line[0] = bytes.TrimLeft(line[0], "\n")
  54. if string(line[0]) != "SSH_AGENT_PID" {
  55. t.Fatalf("could not find key SSH_AGENT_PID in %q", fields[2])
  56. }
  57. pidStr := line[1]
  58. pid, err := strconv.Atoi(string(pidStr))
  59. if err != nil {
  60. t.Fatalf("Atoi(%q): %v", pidStr, err)
  61. }
  62. conn, err := net.Dial("unix", string(socket))
  63. if err != nil {
  64. t.Fatalf("net.Dial: %v", err)
  65. }
  66. ac := NewClient(conn)
  67. return ac, socket, func() {
  68. proc, _ := os.FindProcess(pid)
  69. if proc != nil {
  70. proc.Kill()
  71. }
  72. conn.Close()
  73. os.RemoveAll(filepath.Dir(socket))
  74. }
  75. }
  76. func startAgent(t *testing.T, agent Agent) (client ExtendedAgent, cleanup func()) {
  77. c1, c2, err := netPipe()
  78. if err != nil {
  79. t.Fatalf("netPipe: %v", err)
  80. }
  81. go ServeAgent(agent, c2)
  82. return NewClient(c1), func() {
  83. c1.Close()
  84. c2.Close()
  85. }
  86. }
  87. // startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client.
  88. func startKeyringAgent(t *testing.T) (client ExtendedAgent, cleanup func()) {
  89. return startAgent(t, NewKeyring())
  90. }
  91. func testOpenSSHAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
  92. agent, _, cleanup := startOpenSSHAgent(t)
  93. defer cleanup()
  94. testAgentInterface(t, agent, key, cert, lifetimeSecs)
  95. }
  96. func testKeyringAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
  97. agent, cleanup := startKeyringAgent(t)
  98. defer cleanup()
  99. testAgentInterface(t, agent, key, cert, lifetimeSecs)
  100. }
  101. func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
  102. signer, err := ssh.NewSignerFromKey(key)
  103. if err != nil {
  104. t.Fatalf("NewSignerFromKey(%T): %v", key, err)
  105. }
  106. // The agent should start up empty.
  107. if keys, err := agent.List(); err != nil {
  108. t.Fatalf("RequestIdentities: %v", err)
  109. } else if len(keys) > 0 {
  110. t.Fatalf("got %d keys, want 0: %v", len(keys), keys)
  111. }
  112. // Attempt to insert the key, with certificate if specified.
  113. var pubKey ssh.PublicKey
  114. if cert != nil {
  115. err = agent.Add(AddedKey{
  116. PrivateKey: key,
  117. Certificate: cert,
  118. Comment: "comment",
  119. LifetimeSecs: lifetimeSecs,
  120. })
  121. pubKey = cert
  122. } else {
  123. err = agent.Add(AddedKey{PrivateKey: key, Comment: "comment", LifetimeSecs: lifetimeSecs})
  124. pubKey = signer.PublicKey()
  125. }
  126. if err != nil {
  127. t.Fatalf("insert(%T): %v", key, err)
  128. }
  129. // Did the key get inserted successfully?
  130. if keys, err := agent.List(); err != nil {
  131. t.Fatalf("List: %v", err)
  132. } else if len(keys) != 1 {
  133. t.Fatalf("got %v, want 1 key", keys)
  134. } else if keys[0].Comment != "comment" {
  135. t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment")
  136. } else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) {
  137. t.Fatalf("key mismatch")
  138. }
  139. // Can the agent make a valid signature?
  140. data := []byte("hello")
  141. sig, err := agent.Sign(pubKey, data)
  142. if err != nil {
  143. t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
  144. }
  145. if err := pubKey.Verify(data, sig); err != nil {
  146. t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
  147. }
  148. // For tests on RSA keys, try signing with SHA-256 and SHA-512 flags
  149. if pubKey.Type() == "ssh-rsa" {
  150. sshFlagTest := func(flag SignatureFlags, expectedSigFormat string) {
  151. sig, err = agent.SignWithFlags(pubKey, data, flag)
  152. if err != nil {
  153. t.Fatalf("SignWithFlags(%s): %v", pubKey.Type(), err)
  154. }
  155. if sig.Format != expectedSigFormat {
  156. t.Fatalf("Signature format didn't match expected value: %s != %s", sig.Format, expectedSigFormat)
  157. }
  158. if err := pubKey.Verify(data, sig); err != nil {
  159. t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
  160. }
  161. }
  162. sshFlagTest(0, ssh.SigAlgoRSA)
  163. sshFlagTest(SignatureFlagRsaSha256, ssh.SigAlgoRSASHA2256)
  164. sshFlagTest(SignatureFlagRsaSha512, ssh.SigAlgoRSASHA2512)
  165. }
  166. // If the key has a lifetime, is it removed when it should be?
  167. if lifetimeSecs > 0 {
  168. time.Sleep(time.Second*time.Duration(lifetimeSecs) + 100*time.Millisecond)
  169. keys, err := agent.List()
  170. if err != nil {
  171. t.Fatalf("List: %v", err)
  172. }
  173. if len(keys) > 0 {
  174. t.Fatalf("key not expired")
  175. }
  176. }
  177. }
  178. func TestMalformedRequests(t *testing.T) {
  179. keyringAgent := NewKeyring()
  180. listener, err := netListener()
  181. if err != nil {
  182. t.Fatalf("netListener: %v", err)
  183. }
  184. defer listener.Close()
  185. testCase := func(t *testing.T, requestBytes []byte, wantServerErr bool) {
  186. var wg sync.WaitGroup
  187. wg.Add(1)
  188. go func() {
  189. defer wg.Done()
  190. c, err := listener.Accept()
  191. if err != nil {
  192. t.Errorf("listener.Accept: %v", err)
  193. return
  194. }
  195. defer c.Close()
  196. err = ServeAgent(keyringAgent, c)
  197. if err == nil {
  198. t.Error("ServeAgent should have returned an error to malformed input")
  199. } else {
  200. if (err != io.EOF) != wantServerErr {
  201. t.Errorf("ServeAgent returned expected error: %v", err)
  202. }
  203. }
  204. }()
  205. c, err := net.Dial("tcp", listener.Addr().String())
  206. if err != nil {
  207. t.Fatalf("net.Dial: %v", err)
  208. }
  209. _, err = c.Write(requestBytes)
  210. if err != nil {
  211. t.Errorf("Unexpected error writing raw bytes on connection: %v", err)
  212. }
  213. c.Close()
  214. wg.Wait()
  215. }
  216. var testCases = []struct {
  217. name string
  218. requestBytes []byte
  219. wantServerErr bool
  220. }{
  221. {"Empty request", []byte{}, false},
  222. {"Short header", []byte{0x00}, true},
  223. {"Empty body", []byte{0x00, 0x00, 0x00, 0x00}, true},
  224. {"Short body", []byte{0x00, 0x00, 0x00, 0x01}, false},
  225. }
  226. for _, tc := range testCases {
  227. t.Run(tc.name, func(t *testing.T) { testCase(t, tc.requestBytes, tc.wantServerErr) })
  228. }
  229. }
  230. func TestAgent(t *testing.T) {
  231. for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
  232. testOpenSSHAgent(t, testPrivateKeys[keyType], nil, 0)
  233. testKeyringAgent(t, testPrivateKeys[keyType], nil, 0)
  234. }
  235. }
  236. func TestCert(t *testing.T) {
  237. cert := &ssh.Certificate{
  238. Key: testPublicKeys["rsa"],
  239. ValidBefore: ssh.CertTimeInfinity,
  240. CertType: ssh.UserCert,
  241. }
  242. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  243. testOpenSSHAgent(t, testPrivateKeys["rsa"], cert, 0)
  244. testKeyringAgent(t, testPrivateKeys["rsa"], cert, 0)
  245. }
  246. // netListener creates a localhost network listener.
  247. func netListener() (net.Listener, error) {
  248. listener, err := net.Listen("tcp", "127.0.0.1:0")
  249. if err != nil {
  250. listener, err = net.Listen("tcp", "[::1]:0")
  251. if err != nil {
  252. return nil, err
  253. }
  254. }
  255. return listener, nil
  256. }
  257. // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
  258. // therefore is buffered (net.Pipe deadlocks if both sides start with
  259. // a write.)
  260. func netPipe() (net.Conn, net.Conn, error) {
  261. listener, err := netListener()
  262. if err != nil {
  263. return nil, nil, err
  264. }
  265. defer listener.Close()
  266. c1, err := net.Dial("tcp", listener.Addr().String())
  267. if err != nil {
  268. return nil, nil, err
  269. }
  270. c2, err := listener.Accept()
  271. if err != nil {
  272. c1.Close()
  273. return nil, nil, err
  274. }
  275. return c1, c2, nil
  276. }
  277. func TestServerResponseTooLarge(t *testing.T) {
  278. a, b, err := netPipe()
  279. if err != nil {
  280. t.Fatalf("netPipe: %v", err)
  281. }
  282. done := make(chan struct{})
  283. defer func() { <-done }()
  284. defer a.Close()
  285. defer b.Close()
  286. var response identitiesAnswerAgentMsg
  287. response.NumKeys = 1
  288. response.Keys = make([]byte, maxAgentResponseBytes+1)
  289. agent := NewClient(a)
  290. go func() {
  291. defer close(done)
  292. n, err := b.Write(ssh.Marshal(response))
  293. if n < 4 {
  294. if runtime.GOOS == "plan9" {
  295. if e1, ok := err.(*net.OpError); ok {
  296. if e2, ok := e1.Err.(*os.PathError); ok {
  297. switch e2.Err.Error() {
  298. case "Hangup", "i/o on hungup channel":
  299. // syscall.Pwrite returns -1 in this case even when some data did get written.
  300. return
  301. }
  302. }
  303. }
  304. }
  305. t.Errorf("At least 4 bytes (the response size) should have been successfully written: %d < 4: %v", n, err)
  306. }
  307. }()
  308. _, err = agent.List()
  309. if err == nil {
  310. t.Fatal("Did not get error result")
  311. }
  312. if err.Error() != "agent: client error: response too large" {
  313. t.Fatal("Did not get expected error result")
  314. }
  315. }
  316. func TestAuth(t *testing.T) {
  317. agent, _, cleanup := startOpenSSHAgent(t)
  318. defer cleanup()
  319. a, b, err := netPipe()
  320. if err != nil {
  321. t.Fatalf("netPipe: %v", err)
  322. }
  323. defer a.Close()
  324. defer b.Close()
  325. if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil {
  326. t.Errorf("Add: %v", err)
  327. }
  328. serverConf := ssh.ServerConfig{}
  329. serverConf.AddHostKey(testSigners["rsa"])
  330. serverConf.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
  331. if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
  332. return nil, nil
  333. }
  334. return nil, errors.New("pubkey rejected")
  335. }
  336. go func() {
  337. conn, _, _, err := ssh.NewServerConn(a, &serverConf)
  338. if err != nil {
  339. t.Fatalf("Server: %v", err)
  340. }
  341. conn.Close()
  342. }()
  343. conf := ssh.ClientConfig{
  344. HostKeyCallback: ssh.InsecureIgnoreHostKey(),
  345. }
  346. conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
  347. conn, _, _, err := ssh.NewClientConn(b, "", &conf)
  348. if err != nil {
  349. t.Fatalf("NewClientConn: %v", err)
  350. }
  351. conn.Close()
  352. }
  353. func TestLockOpenSSHAgent(t *testing.T) {
  354. agent, _, cleanup := startOpenSSHAgent(t)
  355. defer cleanup()
  356. testLockAgent(agent, t)
  357. }
  358. func TestLockKeyringAgent(t *testing.T) {
  359. agent, cleanup := startKeyringAgent(t)
  360. defer cleanup()
  361. testLockAgent(agent, t)
  362. }
  363. func testLockAgent(agent Agent, t *testing.T) {
  364. if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment 1"}); err != nil {
  365. t.Errorf("Add: %v", err)
  366. }
  367. if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["dsa"], Comment: "comment dsa"}); err != nil {
  368. t.Errorf("Add: %v", err)
  369. }
  370. if keys, err := agent.List(); err != nil {
  371. t.Errorf("List: %v", err)
  372. } else if len(keys) != 2 {
  373. t.Errorf("Want 2 keys, got %v", keys)
  374. }
  375. passphrase := []byte("secret")
  376. if err := agent.Lock(passphrase); err != nil {
  377. t.Errorf("Lock: %v", err)
  378. }
  379. if keys, err := agent.List(); err != nil {
  380. t.Errorf("List: %v", err)
  381. } else if len(keys) != 0 {
  382. t.Errorf("Want 0 keys, got %v", keys)
  383. }
  384. signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"])
  385. if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil {
  386. t.Fatalf("Sign did not fail")
  387. }
  388. if err := agent.Remove(signer.PublicKey()); err == nil {
  389. t.Fatalf("Remove did not fail")
  390. }
  391. if err := agent.RemoveAll(); err == nil {
  392. t.Fatalf("RemoveAll did not fail")
  393. }
  394. if err := agent.Unlock(nil); err == nil {
  395. t.Errorf("Unlock with wrong passphrase succeeded")
  396. }
  397. if err := agent.Unlock(passphrase); err != nil {
  398. t.Errorf("Unlock: %v", err)
  399. }
  400. if err := agent.Remove(signer.PublicKey()); err != nil {
  401. t.Fatalf("Remove: %v", err)
  402. }
  403. if keys, err := agent.List(); err != nil {
  404. t.Errorf("List: %v", err)
  405. } else if len(keys) != 1 {
  406. t.Errorf("Want 1 keys, got %v", keys)
  407. }
  408. }
  409. func testOpenSSHAgentLifetime(t *testing.T) {
  410. agent, _, cleanup := startOpenSSHAgent(t)
  411. defer cleanup()
  412. testAgentLifetime(t, agent)
  413. }
  414. func testKeyringAgentLifetime(t *testing.T) {
  415. agent, cleanup := startKeyringAgent(t)
  416. defer cleanup()
  417. testAgentLifetime(t, agent)
  418. }
  419. func testAgentLifetime(t *testing.T, agent Agent) {
  420. for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
  421. // Add private keys to the agent.
  422. err := agent.Add(AddedKey{
  423. PrivateKey: testPrivateKeys[keyType],
  424. Comment: "comment",
  425. LifetimeSecs: 1,
  426. })
  427. if err != nil {
  428. t.Fatalf("add: %v", err)
  429. }
  430. // Add certs to the agent.
  431. cert := &ssh.Certificate{
  432. Key: testPublicKeys[keyType],
  433. ValidBefore: ssh.CertTimeInfinity,
  434. CertType: ssh.UserCert,
  435. }
  436. cert.SignCert(rand.Reader, testSigners[keyType])
  437. err = agent.Add(AddedKey{
  438. PrivateKey: testPrivateKeys[keyType],
  439. Certificate: cert,
  440. Comment: "comment",
  441. LifetimeSecs: 1,
  442. })
  443. if err != nil {
  444. t.Fatalf("add: %v", err)
  445. }
  446. }
  447. time.Sleep(1100 * time.Millisecond)
  448. if keys, err := agent.List(); err != nil {
  449. t.Errorf("List: %v", err)
  450. } else if len(keys) != 0 {
  451. t.Errorf("Want 0 keys, got %v", len(keys))
  452. }
  453. }
  454. type keyringExtended struct {
  455. *keyring
  456. }
  457. func (r *keyringExtended) Extension(extensionType string, contents []byte) ([]byte, error) {
  458. if extensionType != "my-extension@example.com" {
  459. return []byte{agentExtensionFailure}, nil
  460. }
  461. return append([]byte{agentSuccess}, contents...), nil
  462. }
  463. func TestAgentExtensions(t *testing.T) {
  464. agent, _, cleanup := startOpenSSHAgent(t)
  465. defer cleanup()
  466. _, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
  467. if err == nil {
  468. t.Fatal("should have gotten agent extension failure")
  469. }
  470. agent, cleanup = startAgent(t, &keyringExtended{})
  471. defer cleanup()
  472. result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02})
  473. if err != nil {
  474. t.Fatalf("agent extension failure: %v", err)
  475. }
  476. if len(result) != 4 || !bytes.Equal(result, []byte{agentSuccess, 0x00, 0x01, 0x02}) {
  477. t.Fatalf("agent extension result invalid: %v", result)
  478. }
  479. _, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02})
  480. if err == nil {
  481. t.Fatal("should have gotten agent extension failure")
  482. }
  483. }