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.
18 type keyboardInteractive map[string]string
20 func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
22 for _, q := range questions {
23 answers = append(answers, cr[q])
28 // reused internally by tests
29 var clientPassword = "tiger"
31 // tryAuth runs a handshake with a given config against an SSH server
32 // with config serverConfig. Returns both client and server side errors.
33 func tryAuth(t *testing.T, config *ClientConfig) error {
34 err, _ := tryAuthBothSides(t, config)
38 // tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection.
39 func tryAuthBothSides(t *testing.T, config *ClientConfig) (clientError error, serverAuthErrors []error) {
40 c1, c2, err := netPipe()
42 t.Fatalf("netPipe: %v", err)
47 certChecker := CertChecker{
48 IsUserAuthority: func(k PublicKey) bool {
49 return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
51 UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
52 if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
56 return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
58 IsRevoked: func(c *Certificate) bool {
59 return c.Serial == 666
63 serverConfig := &ServerConfig{
64 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
65 if conn.User() == "testuser" && string(pass) == clientPassword {
68 return nil, errors.New("password auth failed")
70 PublicKeyCallback: certChecker.Authenticate,
71 KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
72 ans, err := challenge("user",
74 []string{"question1", "question2"},
79 ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
81 challenge("user", "motd", nil, nil)
84 return nil, errors.New("keyboard-interactive failed")
87 serverConfig.AddHostKey(testSigners["rsa"])
89 serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
90 serverAuthErrors = append(serverAuthErrors, err)
93 go newServer(c1, serverConfig)
94 _, _, _, err = NewClientConn(c2, "", config)
95 return err, serverAuthErrors
98 func TestClientAuthPublicKey(t *testing.T) {
99 config := &ClientConfig{
102 PublicKeys(testSigners["rsa"]),
104 HostKeyCallback: InsecureIgnoreHostKey(),
106 if err := tryAuth(t, config); err != nil {
107 t.Fatalf("unable to dial remote side: %s", err)
111 func TestAuthMethodPassword(t *testing.T) {
112 config := &ClientConfig{
115 Password(clientPassword),
117 HostKeyCallback: InsecureIgnoreHostKey(),
120 if err := tryAuth(t, config); err != nil {
121 t.Fatalf("unable to dial remote side: %s", err)
125 func TestAuthMethodFallback(t *testing.T) {
126 var passwordCalled bool
127 config := &ClientConfig{
130 PublicKeys(testSigners["rsa"]),
132 func() (string, error) {
133 passwordCalled = true
137 HostKeyCallback: InsecureIgnoreHostKey(),
140 if err := tryAuth(t, config); err != nil {
141 t.Fatalf("unable to dial remote side: %s", err)
145 t.Errorf("password auth tried before public-key auth.")
149 func TestAuthMethodWrongPassword(t *testing.T) {
150 config := &ClientConfig{
154 PublicKeys(testSigners["rsa"]),
156 HostKeyCallback: InsecureIgnoreHostKey(),
159 if err := tryAuth(t, config); err != nil {
160 t.Fatalf("unable to dial remote side: %s", err)
164 func TestAuthMethodKeyboardInteractive(t *testing.T) {
165 answers := keyboardInteractive(map[string]string{
166 "question1": "answer1",
167 "question2": "answer2",
169 config := &ClientConfig{
172 KeyboardInteractive(answers.Challenge),
174 HostKeyCallback: InsecureIgnoreHostKey(),
177 if err := tryAuth(t, config); err != nil {
178 t.Fatalf("unable to dial remote side: %s", err)
182 func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
183 answers := keyboardInteractive(map[string]string{
184 "question1": "answer1",
185 "question2": "WRONG",
187 config := &ClientConfig{
190 KeyboardInteractive(answers.Challenge),
194 if err := tryAuth(t, config); err == nil {
195 t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
199 // the mock server will only authenticate ssh-rsa keys
200 func TestAuthMethodInvalidPublicKey(t *testing.T) {
201 config := &ClientConfig{
204 PublicKeys(testSigners["dsa"]),
208 if err := tryAuth(t, config); err == nil {
209 t.Fatalf("dsa private key should not have authenticated with rsa public key")
213 // the client should authenticate with the second key
214 func TestAuthMethodRSAandDSA(t *testing.T) {
215 config := &ClientConfig{
218 PublicKeys(testSigners["dsa"], testSigners["rsa"]),
220 HostKeyCallback: InsecureIgnoreHostKey(),
222 if err := tryAuth(t, config); err != nil {
223 t.Fatalf("client could not authenticate with rsa key: %v", err)
227 type invalidAlgSigner struct {
231 func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
232 sig, err := s.Signer.Sign(rand, data)
234 sig.Format = "invalid"
239 func TestMethodInvalidAlgorithm(t *testing.T) {
240 config := &ClientConfig{
243 PublicKeys(&invalidAlgSigner{testSigners["rsa"]}),
245 HostKeyCallback: InsecureIgnoreHostKey(),
248 err, serverErrors := tryAuthBothSides(t, config)
250 t.Fatalf("login succeeded")
254 want := "algorithm \"invalid\""
256 var errStrings []string
257 for _, err := range serverErrors {
258 found = found || (err != nil && strings.Contains(err.Error(), want))
259 errStrings = append(errStrings, err.Error())
262 t.Errorf("server got error %q, want substring %q", errStrings, want)
266 func TestClientHMAC(t *testing.T) {
267 for _, mac := range supportedMACs {
268 config := &ClientConfig{
271 PublicKeys(testSigners["rsa"]),
276 HostKeyCallback: InsecureIgnoreHostKey(),
278 if err := tryAuth(t, config); err != nil {
279 t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
285 func TestClientUnsupportedCipher(t *testing.T) {
286 config := &ClientConfig{
292 Ciphers: []string{"aes128-cbc"}, // not currently supported
295 if err := tryAuth(t, config); err == nil {
296 t.Errorf("expected no ciphers in common")
300 func TestClientUnsupportedKex(t *testing.T) {
301 if os.Getenv("GO_BUILDER_NAME") != "" {
302 t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
304 config := &ClientConfig{
310 KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
312 HostKeyCallback: InsecureIgnoreHostKey(),
314 if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
315 t.Errorf("got %v, expected 'common algorithm'", err)
319 func TestClientLoginCert(t *testing.T) {
320 cert := &Certificate{
321 Key: testPublicKeys["rsa"],
322 ValidBefore: CertTimeInfinity,
325 cert.SignCert(rand.Reader, testSigners["ecdsa"])
326 certSigner, err := NewCertSigner(cert, testSigners["rsa"])
328 t.Fatalf("NewCertSigner: %v", err)
331 clientConfig := &ClientConfig{
333 HostKeyCallback: InsecureIgnoreHostKey(),
335 clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
338 if err := tryAuth(t, clientConfig); err != nil {
339 t.Errorf("cert login failed: %v", err)
342 // corrupted signature
343 cert.Signature.Blob[0]++
344 if err := tryAuth(t, clientConfig); err == nil {
345 t.Errorf("cert login passed with corrupted sig")
350 cert.SignCert(rand.Reader, testSigners["ecdsa"])
351 if err := tryAuth(t, clientConfig); err == nil {
352 t.Errorf("revoked cert login succeeded")
356 // sign with wrong key
357 cert.SignCert(rand.Reader, testSigners["dsa"])
358 if err := tryAuth(t, clientConfig); err == nil {
359 t.Errorf("cert login passed with non-authoritative key")
363 cert.CertType = HostCert
364 cert.SignCert(rand.Reader, testSigners["ecdsa"])
365 if err := tryAuth(t, clientConfig); err == nil {
366 t.Errorf("cert login passed with wrong type")
368 cert.CertType = UserCert
370 // principal specified
371 cert.ValidPrincipals = []string{"user"}
372 cert.SignCert(rand.Reader, testSigners["ecdsa"])
373 if err := tryAuth(t, clientConfig); err != nil {
374 t.Errorf("cert login failed: %v", err)
377 // wrong principal specified
378 cert.ValidPrincipals = []string{"fred"}
379 cert.SignCert(rand.Reader, testSigners["ecdsa"])
380 if err := tryAuth(t, clientConfig); err == nil {
381 t.Errorf("cert login passed with wrong principal")
383 cert.ValidPrincipals = nil
385 // added critical option
386 cert.CriticalOptions = map[string]string{"root-access": "yes"}
387 cert.SignCert(rand.Reader, testSigners["ecdsa"])
388 if err := tryAuth(t, clientConfig); err == nil {
389 t.Errorf("cert login passed with unrecognized critical option")
392 // allowed source address
393 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
394 cert.SignCert(rand.Reader, testSigners["ecdsa"])
395 if err := tryAuth(t, clientConfig); err != nil {
396 t.Errorf("cert login with source-address failed: %v", err)
399 // disallowed source address
400 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
401 cert.SignCert(rand.Reader, testSigners["ecdsa"])
402 if err := tryAuth(t, clientConfig); err == nil {
403 t.Errorf("cert login with source-address succeeded")
407 func testPermissionsPassing(withPermissions bool, t *testing.T) {
408 serverConfig := &ServerConfig{
409 PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
410 if conn.User() == "nopermissions" {
413 return &Permissions{}, nil
416 serverConfig.AddHostKey(testSigners["rsa"])
418 clientConfig := &ClientConfig{
420 PublicKeys(testSigners["rsa"]),
422 HostKeyCallback: InsecureIgnoreHostKey(),
425 clientConfig.User = "permissions"
427 clientConfig.User = "nopermissions"
430 c1, c2, err := netPipe()
432 t.Fatalf("netPipe: %v", err)
437 go NewClientConn(c2, "", clientConfig)
438 serverConn, err := newServer(c1, serverConfig)
442 if p := serverConn.Permissions; (p != nil) != withPermissions {
443 t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
447 func TestPermissionsPassing(t *testing.T) {
448 testPermissionsPassing(true, t)
451 func TestNoPermissionsPassing(t *testing.T) {
452 testPermissionsPassing(false, t)
455 func TestRetryableAuth(t *testing.T) {
457 passwords := []string{"WRONG1", "WRONG2"}
459 config := &ClientConfig{
462 RetryableAuthMethod(PasswordCallback(func() (string, error) {
467 PublicKeys(testSigners["rsa"]),
469 HostKeyCallback: InsecureIgnoreHostKey(),
472 if err := tryAuth(t, config); err != nil {
473 t.Fatalf("unable to dial remote side: %s", err)
476 t.Fatalf("Did not try all passwords")
480 func ExampleRetryableAuthMethod(t *testing.T) {
484 // Normally this would be a callback that prompts the user to answer the
485 // provided questions
486 Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
487 return []string{"answer1", "answer2"}, nil
490 config := &ClientConfig{
491 HostKeyCallback: InsecureIgnoreHostKey(),
494 RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
498 if err := tryAuth(t, config); err != nil {
499 t.Fatalf("unable to dial remote side: %s", err)
503 // Test if username is received on server side when NoClientAuth is used
504 func TestClientAuthNone(t *testing.T) {
506 serverConfig := &ServerConfig{
509 serverConfig.AddHostKey(testSigners["rsa"])
511 clientConfig := &ClientConfig{
513 HostKeyCallback: InsecureIgnoreHostKey(),
516 c1, c2, err := netPipe()
518 t.Fatalf("netPipe: %v", err)
523 go NewClientConn(c2, "", clientConfig)
524 serverConn, err := newServer(c1, serverConfig)
526 t.Fatalf("newServer: %v", err)
528 if serverConn.User() != user {
529 t.Fatalf("server: got %q, want %q", serverConn.User(), user)
533 // Test if authentication attempts are limited on server when MaxAuthTries is set
534 func TestClientAuthMaxAuthTries(t *testing.T) {
537 serverConfig := &ServerConfig{
539 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
540 if conn.User() == "testuser" && string(pass) == "right" {
543 return nil, errors.New("password auth failed")
546 serverConfig.AddHostKey(testSigners["rsa"])
548 expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
550 Message: "too many authentication failures",
553 for tries := 2; tries < 4; tries++ {
555 clientConfig := &ClientConfig{
558 RetryableAuthMethod(PasswordCallback(func() (string, error) {
566 HostKeyCallback: InsecureIgnoreHostKey(),
569 c1, c2, err := netPipe()
571 t.Fatalf("netPipe: %v", err)
576 go newServer(c1, serverConfig)
577 _, _, _, err = NewClientConn(c2, "", clientConfig)
580 t.Fatalf("client: got no error, want %s", expectedErr)
581 } else if err.Error() != expectedErr.Error() {
582 t.Fatalf("client: got %s, want %s", err, expectedErr)
586 t.Fatalf("client: got %s, want no error", err)
592 // Test if authentication attempts are correctly limited on server
593 // when more public keys are provided then MaxAuthTries
594 func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) {
595 signers := []Signer{}
596 for i := 0; i < 6; i++ {
597 signers = append(signers, testSigners["dsa"])
600 validConfig := &ClientConfig{
603 PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...),
605 HostKeyCallback: InsecureIgnoreHostKey(),
607 if err := tryAuth(t, validConfig); err != nil {
608 t.Fatalf("unable to dial remote side: %s", err)
611 expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
613 Message: "too many authentication failures",
615 invalidConfig := &ClientConfig{
618 PublicKeys(append(signers, testSigners["rsa"])...),
620 HostKeyCallback: InsecureIgnoreHostKey(),
622 if err := tryAuth(t, invalidConfig); err == nil {
623 t.Fatalf("client: got no error, want %s", expectedErr)
624 } else if err.Error() != expectedErr.Error() {
625 t.Fatalf("client: got %s, want %s", err, expectedErr)
629 // Test whether authentication errors are being properly logged if all
630 // authentication methods have been exhausted
631 func TestClientAuthErrorList(t *testing.T) {
632 publicKeyErr := errors.New("This is an error from PublicKeyCallback")
634 clientConfig := &ClientConfig{
636 PublicKeys(testSigners["rsa"]),
638 HostKeyCallback: InsecureIgnoreHostKey(),
640 serverConfig := &ServerConfig{
641 PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) {
642 return nil, publicKeyErr
645 serverConfig.AddHostKey(testSigners["rsa"])
647 c1, c2, err := netPipe()
649 t.Fatalf("netPipe: %v", err)
654 go NewClientConn(c2, "", clientConfig)
655 _, err = newServer(c1, serverConfig)
657 t.Fatal("newServer: got nil, expected errors")
660 authErrs, ok := err.(*ServerAuthError)
662 t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err)
664 for i, e := range authErrs.Errors {
668 t.Fatalf("errors: got error %v, want ErrNoAuth", e)
671 if e != publicKeyErr {
672 t.Fatalf("errors: got %v, want %v", e, publicKeyErr)
675 t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors)