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.
 
 
 

380 lines
9.5 KiB

  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. "net"
  10. "os"
  11. "os/exec"
  12. "path/filepath"
  13. "strconv"
  14. "testing"
  15. "time"
  16. "golang.org/x/crypto/ssh"
  17. )
  18. // startOpenSSHAgent executes ssh-agent, and returns an Agent interface to it.
  19. func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func()) {
  20. if testing.Short() {
  21. // ssh-agent is not always available, and the key
  22. // types supported vary by platform.
  23. t.Skip("skipping test due to -short")
  24. }
  25. bin, err := exec.LookPath("ssh-agent")
  26. if err != nil {
  27. t.Skip("could not find ssh-agent")
  28. }
  29. cmd := exec.Command(bin, "-s")
  30. out, err := cmd.Output()
  31. if err != nil {
  32. t.Fatalf("cmd.Output: %v", err)
  33. }
  34. /* Output looks like:
  35. SSH_AUTH_SOCK=/tmp/ssh-P65gpcqArqvH/agent.15541; export SSH_AUTH_SOCK;
  36. SSH_AGENT_PID=15542; export SSH_AGENT_PID;
  37. echo Agent pid 15542;
  38. */
  39. fields := bytes.Split(out, []byte(";"))
  40. line := bytes.SplitN(fields[0], []byte("="), 2)
  41. line[0] = bytes.TrimLeft(line[0], "\n")
  42. if string(line[0]) != "SSH_AUTH_SOCK" {
  43. t.Fatalf("could not find key SSH_AUTH_SOCK in %q", fields[0])
  44. }
  45. socket = string(line[1])
  46. line = bytes.SplitN(fields[2], []byte("="), 2)
  47. line[0] = bytes.TrimLeft(line[0], "\n")
  48. if string(line[0]) != "SSH_AGENT_PID" {
  49. t.Fatalf("could not find key SSH_AGENT_PID in %q", fields[2])
  50. }
  51. pidStr := line[1]
  52. pid, err := strconv.Atoi(string(pidStr))
  53. if err != nil {
  54. t.Fatalf("Atoi(%q): %v", pidStr, err)
  55. }
  56. conn, err := net.Dial("unix", string(socket))
  57. if err != nil {
  58. t.Fatalf("net.Dial: %v", err)
  59. }
  60. ac := NewClient(conn)
  61. return ac, socket, func() {
  62. proc, _ := os.FindProcess(pid)
  63. if proc != nil {
  64. proc.Kill()
  65. }
  66. conn.Close()
  67. os.RemoveAll(filepath.Dir(socket))
  68. }
  69. }
  70. // startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client.
  71. func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) {
  72. c1, c2, err := netPipe()
  73. if err != nil {
  74. t.Fatalf("netPipe: %v", err)
  75. }
  76. go ServeAgent(NewKeyring(), c2)
  77. return NewClient(c1), func() {
  78. c1.Close()
  79. c2.Close()
  80. }
  81. }
  82. func testOpenSSHAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
  83. agent, _, cleanup := startOpenSSHAgent(t)
  84. defer cleanup()
  85. testAgentInterface(t, agent, key, cert, lifetimeSecs)
  86. }
  87. func testKeyringAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
  88. agent, cleanup := startKeyringAgent(t)
  89. defer cleanup()
  90. testAgentInterface(t, agent, key, cert, lifetimeSecs)
  91. }
  92. func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
  93. signer, err := ssh.NewSignerFromKey(key)
  94. if err != nil {
  95. t.Fatalf("NewSignerFromKey(%T): %v", key, err)
  96. }
  97. // The agent should start up empty.
  98. if keys, err := agent.List(); err != nil {
  99. t.Fatalf("RequestIdentities: %v", err)
  100. } else if len(keys) > 0 {
  101. t.Fatalf("got %d keys, want 0: %v", len(keys), keys)
  102. }
  103. // Attempt to insert the key, with certificate if specified.
  104. var pubKey ssh.PublicKey
  105. if cert != nil {
  106. err = agent.Add(AddedKey{
  107. PrivateKey: key,
  108. Certificate: cert,
  109. Comment: "comment",
  110. LifetimeSecs: lifetimeSecs,
  111. })
  112. pubKey = cert
  113. } else {
  114. err = agent.Add(AddedKey{PrivateKey: key, Comment: "comment", LifetimeSecs: lifetimeSecs})
  115. pubKey = signer.PublicKey()
  116. }
  117. if err != nil {
  118. t.Fatalf("insert(%T): %v", key, err)
  119. }
  120. // Did the key get inserted successfully?
  121. if keys, err := agent.List(); err != nil {
  122. t.Fatalf("List: %v", err)
  123. } else if len(keys) != 1 {
  124. t.Fatalf("got %v, want 1 key", keys)
  125. } else if keys[0].Comment != "comment" {
  126. t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment")
  127. } else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) {
  128. t.Fatalf("key mismatch")
  129. }
  130. // Can the agent make a valid signature?
  131. data := []byte("hello")
  132. sig, err := agent.Sign(pubKey, data)
  133. if err != nil {
  134. t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
  135. }
  136. if err := pubKey.Verify(data, sig); err != nil {
  137. t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
  138. }
  139. // If the key has a lifetime, is it removed when it should be?
  140. if lifetimeSecs > 0 {
  141. time.Sleep(time.Second*time.Duration(lifetimeSecs) + 100*time.Millisecond)
  142. keys, err := agent.List()
  143. if err != nil {
  144. t.Fatalf("List: %v", err)
  145. }
  146. if len(keys) > 0 {
  147. t.Fatalf("key not expired")
  148. }
  149. }
  150. }
  151. func TestAgent(t *testing.T) {
  152. for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} {
  153. testOpenSSHAgent(t, testPrivateKeys[keyType], nil, 0)
  154. testKeyringAgent(t, testPrivateKeys[keyType], nil, 0)
  155. }
  156. }
  157. func TestCert(t *testing.T) {
  158. cert := &ssh.Certificate{
  159. Key: testPublicKeys["rsa"],
  160. ValidBefore: ssh.CertTimeInfinity,
  161. CertType: ssh.UserCert,
  162. }
  163. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  164. testOpenSSHAgent(t, testPrivateKeys["rsa"], cert, 0)
  165. testKeyringAgent(t, testPrivateKeys["rsa"], cert, 0)
  166. }
  167. // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
  168. // therefore is buffered (net.Pipe deadlocks if both sides start with
  169. // a write.)
  170. func netPipe() (net.Conn, net.Conn, error) {
  171. listener, err := net.Listen("tcp", "127.0.0.1:0")
  172. if err != nil {
  173. listener, err = net.Listen("tcp", "[::1]:0")
  174. if err != nil {
  175. return nil, nil, err
  176. }
  177. }
  178. defer listener.Close()
  179. c1, err := net.Dial("tcp", listener.Addr().String())
  180. if err != nil {
  181. return nil, nil, err
  182. }
  183. c2, err := listener.Accept()
  184. if err != nil {
  185. c1.Close()
  186. return nil, nil, err
  187. }
  188. return c1, c2, nil
  189. }
  190. func TestAuth(t *testing.T) {
  191. agent, _, cleanup := startOpenSSHAgent(t)
  192. defer cleanup()
  193. a, b, err := netPipe()
  194. if err != nil {
  195. t.Fatalf("netPipe: %v", err)
  196. }
  197. defer a.Close()
  198. defer b.Close()
  199. if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil {
  200. t.Errorf("Add: %v", err)
  201. }
  202. serverConf := ssh.ServerConfig{}
  203. serverConf.AddHostKey(testSigners["rsa"])
  204. serverConf.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
  205. if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
  206. return nil, nil
  207. }
  208. return nil, errors.New("pubkey rejected")
  209. }
  210. go func() {
  211. conn, _, _, err := ssh.NewServerConn(a, &serverConf)
  212. if err != nil {
  213. t.Fatalf("Server: %v", err)
  214. }
  215. conn.Close()
  216. }()
  217. conf := ssh.ClientConfig{
  218. HostKeyCallback: ssh.InsecureIgnoreHostKey(),
  219. }
  220. conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
  221. conn, _, _, err := ssh.NewClientConn(b, "", &conf)
  222. if err != nil {
  223. t.Fatalf("NewClientConn: %v", err)
  224. }
  225. conn.Close()
  226. }
  227. func TestLockOpenSSHAgent(t *testing.T) {
  228. agent, _, cleanup := startOpenSSHAgent(t)
  229. defer cleanup()
  230. testLockAgent(agent, t)
  231. }
  232. func TestLockKeyringAgent(t *testing.T) {
  233. agent, cleanup := startKeyringAgent(t)
  234. defer cleanup()
  235. testLockAgent(agent, t)
  236. }
  237. func testLockAgent(agent Agent, t *testing.T) {
  238. if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment 1"}); err != nil {
  239. t.Errorf("Add: %v", err)
  240. }
  241. if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["dsa"], Comment: "comment dsa"}); err != nil {
  242. t.Errorf("Add: %v", err)
  243. }
  244. if keys, err := agent.List(); err != nil {
  245. t.Errorf("List: %v", err)
  246. } else if len(keys) != 2 {
  247. t.Errorf("Want 2 keys, got %v", keys)
  248. }
  249. passphrase := []byte("secret")
  250. if err := agent.Lock(passphrase); err != nil {
  251. t.Errorf("Lock: %v", err)
  252. }
  253. if keys, err := agent.List(); err != nil {
  254. t.Errorf("List: %v", err)
  255. } else if len(keys) != 0 {
  256. t.Errorf("Want 0 keys, got %v", keys)
  257. }
  258. signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"])
  259. if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil {
  260. t.Fatalf("Sign did not fail")
  261. }
  262. if err := agent.Remove(signer.PublicKey()); err == nil {
  263. t.Fatalf("Remove did not fail")
  264. }
  265. if err := agent.RemoveAll(); err == nil {
  266. t.Fatalf("RemoveAll did not fail")
  267. }
  268. if err := agent.Unlock(nil); err == nil {
  269. t.Errorf("Unlock with wrong passphrase succeeded")
  270. }
  271. if err := agent.Unlock(passphrase); err != nil {
  272. t.Errorf("Unlock: %v", err)
  273. }
  274. if err := agent.Remove(signer.PublicKey()); err != nil {
  275. t.Fatalf("Remove: %v", err)
  276. }
  277. if keys, err := agent.List(); err != nil {
  278. t.Errorf("List: %v", err)
  279. } else if len(keys) != 1 {
  280. t.Errorf("Want 1 keys, got %v", keys)
  281. }
  282. }
  283. func testOpenSSHAgentLifetime(t *testing.T) {
  284. agent, _, cleanup := startOpenSSHAgent(t)
  285. defer cleanup()
  286. testAgentLifetime(t, agent)
  287. }
  288. func testKeyringAgentLifetime(t *testing.T) {
  289. agent, cleanup := startKeyringAgent(t)
  290. defer cleanup()
  291. testAgentLifetime(t, agent)
  292. }
  293. func testAgentLifetime(t *testing.T, agent Agent) {
  294. for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
  295. // Add private keys to the agent.
  296. err := agent.Add(AddedKey{
  297. PrivateKey: testPrivateKeys[keyType],
  298. Comment: "comment",
  299. LifetimeSecs: 1,
  300. })
  301. if err != nil {
  302. t.Fatalf("add: %v", err)
  303. }
  304. // Add certs to the agent.
  305. cert := &ssh.Certificate{
  306. Key: testPublicKeys[keyType],
  307. ValidBefore: ssh.CertTimeInfinity,
  308. CertType: ssh.UserCert,
  309. }
  310. cert.SignCert(rand.Reader, testSigners[keyType])
  311. err = agent.Add(AddedKey{
  312. PrivateKey: testPrivateKeys[keyType],
  313. Certificate: cert,
  314. Comment: "comment",
  315. LifetimeSecs: 1,
  316. })
  317. if err != nil {
  318. t.Fatalf("add: %v", err)
  319. }
  320. }
  321. time.Sleep(1100 * time.Millisecond)
  322. if keys, err := agent.List(); err != nil {
  323. t.Errorf("List: %v", err)
  324. } else if len(keys) != 0 {
  325. t.Errorf("Want 0 keys, got %v", len(keys))
  326. }
  327. }