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