github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/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 "time" 18 19 "golang.org/x/crypto/ssh" 20 ) 21 22 // startAgent executes ssh-agent, and returns a Agent interface to it. 23 func startAgent(t *testing.T) (client Agent, 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 30 bin, err := exec.LookPath("ssh-agent") 31 if err != nil { 32 t.Skip("could not find ssh-agent") 33 } 34 35 cmd := exec.Command(bin, "-s") 36 out, err := cmd.Output() 37 if err != nil { 38 t.Fatalf("cmd.Output: %v", err) 39 } 40 41 /* Output looks like: 42 43 SSH_AUTH_SOCK=/tmp/ssh-P65gpcqArqvH/agent.15541; export SSH_AUTH_SOCK; 44 SSH_AGENT_PID=15542; export SSH_AGENT_PID; 45 echo Agent pid 15542; 46 */ 47 fields := bytes.Split(out, []byte(";")) 48 line := bytes.SplitN(fields[0], []byte("="), 2) 49 line[0] = bytes.TrimLeft(line[0], "\n") 50 if string(line[0]) != "SSH_AUTH_SOCK" { 51 t.Fatalf("could not find key SSH_AUTH_SOCK in %q", fields[0]) 52 } 53 socket = string(line[1]) 54 55 line = bytes.SplitN(fields[2], []byte("="), 2) 56 line[0] = bytes.TrimLeft(line[0], "\n") 57 if string(line[0]) != "SSH_AGENT_PID" { 58 t.Fatalf("could not find key SSH_AGENT_PID in %q", fields[2]) 59 } 60 pidStr := line[1] 61 pid, err := strconv.Atoi(string(pidStr)) 62 if err != nil { 63 t.Fatalf("Atoi(%q): %v", pidStr, err) 64 } 65 66 conn, err := net.Dial("unix", string(socket)) 67 if err != nil { 68 t.Fatalf("net.Dial: %v", err) 69 } 70 71 ac := NewClient(conn) 72 return ac, socket, func() { 73 proc, _ := os.FindProcess(pid) 74 if proc != nil { 75 proc.Kill() 76 } 77 conn.Close() 78 os.RemoveAll(filepath.Dir(socket)) 79 } 80 } 81 82 func testAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { 83 agent, _, cleanup := startAgent(t) 84 defer cleanup() 85 86 testAgentInterface(t, agent, key, cert, lifetimeSecs) 87 } 88 89 func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { 90 signer, err := ssh.NewSignerFromKey(key) 91 if err != nil { 92 t.Fatalf("NewSignerFromKey(%T): %v", key, err) 93 } 94 // The agent should start up empty. 95 if keys, err := agent.List(); err != nil { 96 t.Fatalf("RequestIdentities: %v", err) 97 } else if len(keys) > 0 { 98 t.Fatalf("got %d keys, want 0: %v", len(keys), keys) 99 } 100 101 // Attempt to insert the key, with certificate if specified. 102 var pubKey ssh.PublicKey 103 if cert != nil { 104 err = agent.Add(AddedKey{ 105 PrivateKey: key, 106 Certificate: cert, 107 Comment: "comment", 108 LifetimeSecs: lifetimeSecs, 109 }) 110 pubKey = cert 111 } else { 112 err = agent.Add(AddedKey{PrivateKey: key, Comment: "comment", LifetimeSecs: lifetimeSecs}) 113 pubKey = signer.PublicKey() 114 } 115 if err != nil { 116 t.Fatalf("insert(%T): %v", key, err) 117 } 118 119 // Did the key get inserted successfully? 120 if keys, err := agent.List(); err != nil { 121 t.Fatalf("List: %v", err) 122 } else if len(keys) != 1 { 123 t.Fatalf("got %v, want 1 key", keys) 124 } else if keys[0].Comment != "comment" { 125 t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment") 126 } else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) { 127 t.Fatalf("key mismatch") 128 } 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 137 if err := pubKey.Verify(data, sig); err != nil { 138 t.Fatalf("Verify(%s): %v", pubKey.Type(), err) 139 } 140 } 141 142 func TestAgent(t *testing.T) { 143 for _, keyType := range []string{"rsa", "dsa", "ecdsa", "ed25519"} { 144 testAgent(t, testPrivateKeys[keyType], nil, 0) 145 } 146 } 147 148 func TestCert(t *testing.T) { 149 cert := &ssh.Certificate{ 150 Key: testPublicKeys["rsa"], 151 ValidBefore: ssh.CertTimeInfinity, 152 CertType: ssh.UserCert, 153 } 154 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 155 156 testAgent(t, testPrivateKeys["rsa"], cert, 0) 157 } 158 159 func TestConstraints(t *testing.T) { 160 testAgent(t, testPrivateKeys["rsa"], nil, 3600 /* lifetime in seconds */) 161 } 162 163 // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and 164 // therefore is buffered (net.Pipe deadlocks if both sides start with 165 // a write.) 166 func netPipe() (net.Conn, net.Conn, error) { 167 listener, err := net.Listen("tcp", "127.0.0.1:0") 168 if err != nil { 169 return nil, nil, err 170 } 171 defer listener.Close() 172 c1, err := net.Dial("tcp", listener.Addr().String()) 173 if err != nil { 174 return nil, nil, err 175 } 176 177 c2, err := listener.Accept() 178 if err != nil { 179 c1.Close() 180 return nil, nil, err 181 } 182 183 return c1, c2, nil 184 } 185 186 func TestAuth(t *testing.T) { 187 a, b, err := netPipe() 188 if err != nil { 189 t.Fatalf("netPipe: %v", err) 190 } 191 192 defer a.Close() 193 defer b.Close() 194 195 agent, _, cleanup := startAgent(t) 196 defer cleanup() 197 198 if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil { 199 t.Errorf("Add: %v", err) 200 } 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 209 return nil, errors.New("pubkey rejected") 210 } 211 212 go func() { 213 conn, _, _, err := ssh.NewServerConn(a, &serverConf) 214 if err != nil { 215 t.Fatalf("Server: %v", err) 216 } 217 conn.Close() 218 }() 219 220 conf := ssh.ClientConfig{} 221 conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers)) 222 conn, _, _, err := ssh.NewClientConn(b, "", &conf) 223 if err != nil { 224 t.Fatalf("NewClientConn: %v", err) 225 } 226 conn.Close() 227 } 228 229 func TestLockClient(t *testing.T) { 230 agent, _, cleanup := startAgent(t) 231 defer cleanup() 232 testLockAgent(agent, t) 233 } 234 235 func testLockAgent(agent Agent, t *testing.T) { 236 if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment 1"}); err != nil { 237 t.Errorf("Add: %v", err) 238 } 239 if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["dsa"], Comment: "comment dsa"}); err != nil { 240 t.Errorf("Add: %v", err) 241 } 242 if keys, err := agent.List(); err != nil { 243 t.Errorf("List: %v", err) 244 } else if len(keys) != 2 { 245 t.Errorf("Want 2 keys, got %v", keys) 246 } 247 248 passphrase := []byte("secret") 249 if err := agent.Lock(passphrase); err != nil { 250 t.Errorf("Lock: %v", err) 251 } 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 259 signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"]) 260 if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil { 261 t.Fatalf("Sign did not fail") 262 } 263 264 if err := agent.Remove(signer.PublicKey()); err == nil { 265 t.Fatalf("Remove did not fail") 266 } 267 268 if err := agent.RemoveAll(); err == nil { 269 t.Fatalf("RemoveAll did not fail") 270 } 271 272 if err := agent.Unlock(nil); err == nil { 273 t.Errorf("Unlock with wrong passphrase succeeded") 274 } 275 if err := agent.Unlock(passphrase); err != nil { 276 t.Errorf("Unlock: %v", err) 277 } 278 279 if err := agent.Remove(signer.PublicKey()); err != nil { 280 t.Fatalf("Remove: %v", err) 281 } 282 283 if keys, err := agent.List(); err != nil { 284 t.Errorf("List: %v", err) 285 } else if len(keys) != 1 { 286 t.Errorf("Want 1 keys, got %v", keys) 287 } 288 } 289 290 func TestAgentLifetime(t *testing.T) { 291 agent, _, cleanup := startAgent(t) 292 defer cleanup() 293 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 }