github.com/maenmax/kairep@v0.0.0-20210218001208-55bf3df36788/src/golang.org/x/crypto/ssh/client_auth_test.go (about) 1 // Copyright 2011 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 ssh 6 7 import ( 8 "bytes" 9 "crypto/rand" 10 "errors" 11 "fmt" 12 "os" 13 "strings" 14 "testing" 15 ) 16 17 type keyboardInteractive map[string]string 18 19 func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) { 20 var answers []string 21 for _, q := range questions { 22 answers = append(answers, cr[q]) 23 } 24 return answers, nil 25 } 26 27 // reused internally by tests 28 var clientPassword = "tiger" 29 30 // tryAuth runs a handshake with a given config against an SSH server 31 // with config serverConfig 32 func tryAuth(t *testing.T, config *ClientConfig) error { 33 c1, c2, err := netPipe() 34 if err != nil { 35 t.Fatalf("netPipe: %v", err) 36 } 37 defer c1.Close() 38 defer c2.Close() 39 40 certChecker := CertChecker{ 41 IsAuthority: func(k PublicKey) bool { 42 return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal()) 43 }, 44 UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { 45 if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) { 46 return nil, nil 47 } 48 49 return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User()) 50 }, 51 IsRevoked: func(c *Certificate) bool { 52 return c.Serial == 666 53 }, 54 } 55 56 serverConfig := &ServerConfig{ 57 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) { 58 if conn.User() == "testuser" && string(pass) == clientPassword { 59 return nil, nil 60 } 61 return nil, errors.New("password auth failed") 62 }, 63 PublicKeyCallback: certChecker.Authenticate, 64 KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) { 65 ans, err := challenge("user", 66 "instruction", 67 []string{"question1", "question2"}, 68 []bool{true, true}) 69 if err != nil { 70 return nil, err 71 } 72 ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2" 73 if ok { 74 challenge("user", "motd", nil, nil) 75 return nil, nil 76 } 77 return nil, errors.New("keyboard-interactive failed") 78 }, 79 AuthLogCallback: func(conn ConnMetadata, method string, err error) { 80 t.Logf("user %q, method %q: %v", conn.User(), method, err) 81 }, 82 } 83 serverConfig.AddHostKey(testSigners["rsa"]) 84 85 go newServer(c1, serverConfig) 86 _, _, _, err = NewClientConn(c2, "", config) 87 return err 88 } 89 90 func TestClientAuthPublicKey(t *testing.T) { 91 config := &ClientConfig{ 92 User: "testuser", 93 Auth: []AuthMethod{ 94 PublicKeys(testSigners["rsa"]), 95 }, 96 } 97 if err := tryAuth(t, config); err != nil { 98 t.Fatalf("unable to dial remote side: %s", err) 99 } 100 } 101 102 func TestAuthMethodPassword(t *testing.T) { 103 config := &ClientConfig{ 104 User: "testuser", 105 Auth: []AuthMethod{ 106 Password(clientPassword), 107 }, 108 } 109 110 if err := tryAuth(t, config); err != nil { 111 t.Fatalf("unable to dial remote side: %s", err) 112 } 113 } 114 115 func TestAuthMethodFallback(t *testing.T) { 116 var passwordCalled bool 117 config := &ClientConfig{ 118 User: "testuser", 119 Auth: []AuthMethod{ 120 PublicKeys(testSigners["rsa"]), 121 PasswordCallback( 122 func() (string, error) { 123 passwordCalled = true 124 return "WRONG", nil 125 }), 126 }, 127 } 128 129 if err := tryAuth(t, config); err != nil { 130 t.Fatalf("unable to dial remote side: %s", err) 131 } 132 133 if passwordCalled { 134 t.Errorf("password auth tried before public-key auth.") 135 } 136 } 137 138 func TestAuthMethodWrongPassword(t *testing.T) { 139 config := &ClientConfig{ 140 User: "testuser", 141 Auth: []AuthMethod{ 142 Password("wrong"), 143 PublicKeys(testSigners["rsa"]), 144 }, 145 } 146 147 if err := tryAuth(t, config); err != nil { 148 t.Fatalf("unable to dial remote side: %s", err) 149 } 150 } 151 152 func TestAuthMethodKeyboardInteractive(t *testing.T) { 153 answers := keyboardInteractive(map[string]string{ 154 "question1": "answer1", 155 "question2": "answer2", 156 }) 157 config := &ClientConfig{ 158 User: "testuser", 159 Auth: []AuthMethod{ 160 KeyboardInteractive(answers.Challenge), 161 }, 162 } 163 164 if err := tryAuth(t, config); err != nil { 165 t.Fatalf("unable to dial remote side: %s", err) 166 } 167 } 168 169 func TestAuthMethodWrongKeyboardInteractive(t *testing.T) { 170 answers := keyboardInteractive(map[string]string{ 171 "question1": "answer1", 172 "question2": "WRONG", 173 }) 174 config := &ClientConfig{ 175 User: "testuser", 176 Auth: []AuthMethod{ 177 KeyboardInteractive(answers.Challenge), 178 }, 179 } 180 181 if err := tryAuth(t, config); err == nil { 182 t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive") 183 } 184 } 185 186 // the mock server will only authenticate ssh-rsa keys 187 func TestAuthMethodInvalidPublicKey(t *testing.T) { 188 config := &ClientConfig{ 189 User: "testuser", 190 Auth: []AuthMethod{ 191 PublicKeys(testSigners["dsa"]), 192 }, 193 } 194 195 if err := tryAuth(t, config); err == nil { 196 t.Fatalf("dsa private key should not have authenticated with rsa public key") 197 } 198 } 199 200 // the client should authenticate with the second key 201 func TestAuthMethodRSAandDSA(t *testing.T) { 202 config := &ClientConfig{ 203 User: "testuser", 204 Auth: []AuthMethod{ 205 PublicKeys(testSigners["dsa"], testSigners["rsa"]), 206 }, 207 } 208 if err := tryAuth(t, config); err != nil { 209 t.Fatalf("client could not authenticate with rsa key: %v", err) 210 } 211 } 212 213 func TestClientHMAC(t *testing.T) { 214 for _, mac := range supportedMACs { 215 config := &ClientConfig{ 216 User: "testuser", 217 Auth: []AuthMethod{ 218 PublicKeys(testSigners["rsa"]), 219 }, 220 Config: Config{ 221 MACs: []string{mac}, 222 }, 223 } 224 if err := tryAuth(t, config); err != nil { 225 t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err) 226 } 227 } 228 } 229 230 // issue 4285. 231 func TestClientUnsupportedCipher(t *testing.T) { 232 config := &ClientConfig{ 233 User: "testuser", 234 Auth: []AuthMethod{ 235 PublicKeys(), 236 }, 237 Config: Config{ 238 Ciphers: []string{"aes128-cbc"}, // not currently supported 239 }, 240 } 241 if err := tryAuth(t, config); err == nil { 242 t.Errorf("expected no ciphers in common") 243 } 244 } 245 246 func TestClientUnsupportedKex(t *testing.T) { 247 if os.Getenv("GO_BUILDER_NAME") != "" { 248 t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198") 249 } 250 config := &ClientConfig{ 251 User: "testuser", 252 Auth: []AuthMethod{ 253 PublicKeys(), 254 }, 255 Config: Config{ 256 KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported 257 }, 258 } 259 if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") { 260 t.Errorf("got %v, expected 'common algorithm'", err) 261 } 262 } 263 264 func TestClientLoginCert(t *testing.T) { 265 cert := &Certificate{ 266 Key: testPublicKeys["rsa"], 267 ValidBefore: CertTimeInfinity, 268 CertType: UserCert, 269 } 270 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 271 certSigner, err := NewCertSigner(cert, testSigners["rsa"]) 272 if err != nil { 273 t.Fatalf("NewCertSigner: %v", err) 274 } 275 276 clientConfig := &ClientConfig{ 277 User: "user", 278 } 279 clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner)) 280 281 t.Log("should succeed") 282 if err := tryAuth(t, clientConfig); err != nil { 283 t.Errorf("cert login failed: %v", err) 284 } 285 286 t.Log("corrupted signature") 287 cert.Signature.Blob[0]++ 288 if err := tryAuth(t, clientConfig); err == nil { 289 t.Errorf("cert login passed with corrupted sig") 290 } 291 292 t.Log("revoked") 293 cert.Serial = 666 294 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 295 if err := tryAuth(t, clientConfig); err == nil { 296 t.Errorf("revoked cert login succeeded") 297 } 298 cert.Serial = 1 299 300 t.Log("sign with wrong key") 301 cert.SignCert(rand.Reader, testSigners["dsa"]) 302 if err := tryAuth(t, clientConfig); err == nil { 303 t.Errorf("cert login passed with non-authoritative key") 304 } 305 306 t.Log("host cert") 307 cert.CertType = HostCert 308 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 309 if err := tryAuth(t, clientConfig); err == nil { 310 t.Errorf("cert login passed with wrong type") 311 } 312 cert.CertType = UserCert 313 314 t.Log("principal specified") 315 cert.ValidPrincipals = []string{"user"} 316 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 317 if err := tryAuth(t, clientConfig); err != nil { 318 t.Errorf("cert login failed: %v", err) 319 } 320 321 t.Log("wrong principal specified") 322 cert.ValidPrincipals = []string{"fred"} 323 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 324 if err := tryAuth(t, clientConfig); err == nil { 325 t.Errorf("cert login passed with wrong principal") 326 } 327 cert.ValidPrincipals = nil 328 329 t.Log("added critical option") 330 cert.CriticalOptions = map[string]string{"root-access": "yes"} 331 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 332 if err := tryAuth(t, clientConfig); err == nil { 333 t.Errorf("cert login passed with unrecognized critical option") 334 } 335 336 t.Log("allowed source address") 337 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24"} 338 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 339 if err := tryAuth(t, clientConfig); err != nil { 340 t.Errorf("cert login with source-address failed: %v", err) 341 } 342 343 t.Log("disallowed source address") 344 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42"} 345 cert.SignCert(rand.Reader, testSigners["ecdsa"]) 346 if err := tryAuth(t, clientConfig); err == nil { 347 t.Errorf("cert login with source-address succeeded") 348 } 349 } 350 351 func testPermissionsPassing(withPermissions bool, t *testing.T) { 352 serverConfig := &ServerConfig{ 353 PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) { 354 if conn.User() == "nopermissions" { 355 return nil, nil 356 } else { 357 return &Permissions{}, nil 358 } 359 }, 360 } 361 serverConfig.AddHostKey(testSigners["rsa"]) 362 363 clientConfig := &ClientConfig{ 364 Auth: []AuthMethod{ 365 PublicKeys(testSigners["rsa"]), 366 }, 367 } 368 if withPermissions { 369 clientConfig.User = "permissions" 370 } else { 371 clientConfig.User = "nopermissions" 372 } 373 374 c1, c2, err := netPipe() 375 if err != nil { 376 t.Fatalf("netPipe: %v", err) 377 } 378 defer c1.Close() 379 defer c2.Close() 380 381 go NewClientConn(c2, "", clientConfig) 382 serverConn, err := newServer(c1, serverConfig) 383 if err != nil { 384 t.Fatal(err) 385 } 386 if p := serverConn.Permissions; (p != nil) != withPermissions { 387 t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p) 388 } 389 } 390 391 func TestPermissionsPassing(t *testing.T) { 392 testPermissionsPassing(true, t) 393 } 394 395 func TestNoPermissionsPassing(t *testing.T) { 396 testPermissionsPassing(false, t) 397 } 398 399 func TestRetryableAuth(t *testing.T) { 400 n := 0 401 passwords := []string{"WRONG1", "WRONG2"} 402 403 config := &ClientConfig{ 404 User: "testuser", 405 Auth: []AuthMethod{ 406 RetryableAuthMethod(PasswordCallback(func() (string, error) { 407 p := passwords[n] 408 n++ 409 return p, nil 410 }), 2), 411 PublicKeys(testSigners["rsa"]), 412 }, 413 } 414 415 if err := tryAuth(t, config); err != nil { 416 t.Fatalf("unable to dial remote side: %s", err) 417 } 418 if n != 2 { 419 t.Fatalf("Did not try all passwords") 420 } 421 } 422 423 func ExampleRetryableAuthMethod(t *testing.T) { 424 user := "testuser" 425 NumberOfPrompts := 3 426 427 // Normally this would be a callback that prompts the user to answer the 428 // provided questions 429 Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) { 430 return []string{"answer1", "answer2"}, nil 431 } 432 433 config := &ClientConfig{ 434 User: user, 435 Auth: []AuthMethod{ 436 RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts), 437 }, 438 } 439 440 if err := tryAuth(t, config); err != nil { 441 t.Fatalf("unable to dial remote side: %s", err) 442 } 443 }