...

Source file src/golang.org/x/crypto/ssh/client_auth_test.go

Documentation: golang.org/x/crypto/ssh

     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  	"io"
    13  	"log"
    14  	"net"
    15  	"os"
    16  	"runtime"
    17  	"strings"
    18  	"testing"
    19  )
    20  
    21  type keyboardInteractive map[string]string
    22  
    23  func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
    24  	var answers []string
    25  	for _, q := range questions {
    26  		answers = append(answers, cr[q])
    27  	}
    28  	return answers, nil
    29  }
    30  
    31  // reused internally by tests
    32  var clientPassword = "tiger"
    33  
    34  // tryAuth runs a handshake with a given config against an SSH server
    35  // with config serverConfig. Returns both client and server side errors.
    36  func tryAuth(t *testing.T, config *ClientConfig) error {
    37  	err, _ := tryAuthBothSides(t, config, nil)
    38  	return err
    39  }
    40  
    41  // tryAuthWithGSSAPIWithMICConfig runs a handshake with a given config against an SSH server
    42  // with a given GSSAPIWithMICConfig and config serverConfig. Returns both client and server side errors.
    43  func tryAuthWithGSSAPIWithMICConfig(t *testing.T, clientConfig *ClientConfig, gssAPIWithMICConfig *GSSAPIWithMICConfig) error {
    44  	err, _ := tryAuthBothSides(t, clientConfig, gssAPIWithMICConfig)
    45  	return err
    46  }
    47  
    48  // tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection.
    49  func tryAuthBothSides(t *testing.T, config *ClientConfig, gssAPIWithMICConfig *GSSAPIWithMICConfig) (clientError error, serverAuthErrors []error) {
    50  	c1, c2, err := netPipe()
    51  	if err != nil {
    52  		t.Fatalf("netPipe: %v", err)
    53  	}
    54  	defer c1.Close()
    55  	defer c2.Close()
    56  
    57  	certChecker := CertChecker{
    58  		IsUserAuthority: func(k PublicKey) bool {
    59  			return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
    60  		},
    61  		UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
    62  			if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
    63  				return nil, nil
    64  			}
    65  
    66  			return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
    67  		},
    68  		IsRevoked: func(c *Certificate) bool {
    69  			return c.Serial == 666
    70  		},
    71  	}
    72  	serverConfig := &ServerConfig{
    73  		PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
    74  			if conn.User() == "testuser" && string(pass) == clientPassword {
    75  				return nil, nil
    76  			}
    77  			return nil, errors.New("password auth failed")
    78  		},
    79  		PublicKeyCallback: certChecker.Authenticate,
    80  		KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
    81  			ans, err := challenge("user",
    82  				"instruction",
    83  				[]string{"question1", "question2"},
    84  				[]bool{true, true})
    85  			if err != nil {
    86  				return nil, err
    87  			}
    88  			ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
    89  			if ok {
    90  				challenge("user", "motd", nil, nil)
    91  				return nil, nil
    92  			}
    93  			return nil, errors.New("keyboard-interactive failed")
    94  		},
    95  		GSSAPIWithMICConfig: gssAPIWithMICConfig,
    96  	}
    97  	serverConfig.AddHostKey(testSigners["rsa"])
    98  
    99  	serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
   100  		serverAuthErrors = append(serverAuthErrors, err)
   101  	}
   102  
   103  	go newServer(c1, serverConfig)
   104  	_, _, _, err = NewClientConn(c2, "", config)
   105  	return err, serverAuthErrors
   106  }
   107  
   108  type loggingAlgorithmSigner struct {
   109  	used []string
   110  	AlgorithmSigner
   111  }
   112  
   113  func (l *loggingAlgorithmSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
   114  	l.used = append(l.used, "[Sign]")
   115  	return l.AlgorithmSigner.Sign(rand, data)
   116  }
   117  
   118  func (l *loggingAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
   119  	l.used = append(l.used, algorithm)
   120  	return l.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
   121  }
   122  
   123  func TestClientAuthPublicKey(t *testing.T) {
   124  	signer := &loggingAlgorithmSigner{AlgorithmSigner: testSigners["rsa"].(AlgorithmSigner)}
   125  	config := &ClientConfig{
   126  		User: "testuser",
   127  		Auth: []AuthMethod{
   128  			PublicKeys(signer),
   129  		},
   130  		HostKeyCallback: InsecureIgnoreHostKey(),
   131  	}
   132  	if err := tryAuth(t, config); err != nil {
   133  		t.Fatalf("unable to dial remote side: %s", err)
   134  	}
   135  	if len(signer.used) != 1 || signer.used[0] != KeyAlgoRSASHA256 {
   136  		t.Errorf("unexpected Sign/SignWithAlgorithm calls: %q", signer.used)
   137  	}
   138  }
   139  
   140  // TestClientAuthNoSHA2 tests a ssh-rsa Signer that doesn't implement AlgorithmSigner.
   141  func TestClientAuthNoSHA2(t *testing.T) {
   142  	config := &ClientConfig{
   143  		User: "testuser",
   144  		Auth: []AuthMethod{
   145  			PublicKeys(&legacyRSASigner{testSigners["rsa"]}),
   146  		},
   147  		HostKeyCallback: InsecureIgnoreHostKey(),
   148  	}
   149  	if err := tryAuth(t, config); err != nil {
   150  		t.Fatalf("unable to dial remote side: %s", err)
   151  	}
   152  }
   153  
   154  // TestClientAuthThirdKey checks that the third configured can succeed. If we
   155  // were to do three attempts for each key (rsa-sha2-256, rsa-sha2-512, ssh-rsa),
   156  // we'd hit the six maximum attempts before reaching it.
   157  func TestClientAuthThirdKey(t *testing.T) {
   158  	config := &ClientConfig{
   159  		User: "testuser",
   160  		Auth: []AuthMethod{
   161  			PublicKeys(testSigners["rsa-openssh-format"],
   162  				testSigners["rsa-openssh-format"], testSigners["rsa"]),
   163  		},
   164  		HostKeyCallback: InsecureIgnoreHostKey(),
   165  	}
   166  	if err := tryAuth(t, config); err != nil {
   167  		t.Fatalf("unable to dial remote side: %s", err)
   168  	}
   169  }
   170  
   171  func TestAuthMethodPassword(t *testing.T) {
   172  	config := &ClientConfig{
   173  		User: "testuser",
   174  		Auth: []AuthMethod{
   175  			Password(clientPassword),
   176  		},
   177  		HostKeyCallback: InsecureIgnoreHostKey(),
   178  	}
   179  
   180  	if err := tryAuth(t, config); err != nil {
   181  		t.Fatalf("unable to dial remote side: %s", err)
   182  	}
   183  }
   184  
   185  func TestAuthMethodFallback(t *testing.T) {
   186  	var passwordCalled bool
   187  	config := &ClientConfig{
   188  		User: "testuser",
   189  		Auth: []AuthMethod{
   190  			PublicKeys(testSigners["rsa"]),
   191  			PasswordCallback(
   192  				func() (string, error) {
   193  					passwordCalled = true
   194  					return "WRONG", nil
   195  				}),
   196  		},
   197  		HostKeyCallback: InsecureIgnoreHostKey(),
   198  	}
   199  
   200  	if err := tryAuth(t, config); err != nil {
   201  		t.Fatalf("unable to dial remote side: %s", err)
   202  	}
   203  
   204  	if passwordCalled {
   205  		t.Errorf("password auth tried before public-key auth.")
   206  	}
   207  }
   208  
   209  func TestAuthMethodWrongPassword(t *testing.T) {
   210  	config := &ClientConfig{
   211  		User: "testuser",
   212  		Auth: []AuthMethod{
   213  			Password("wrong"),
   214  			PublicKeys(testSigners["rsa"]),
   215  		},
   216  		HostKeyCallback: InsecureIgnoreHostKey(),
   217  	}
   218  
   219  	if err := tryAuth(t, config); err != nil {
   220  		t.Fatalf("unable to dial remote side: %s", err)
   221  	}
   222  }
   223  
   224  func TestAuthMethodKeyboardInteractive(t *testing.T) {
   225  	answers := keyboardInteractive(map[string]string{
   226  		"question1": "answer1",
   227  		"question2": "answer2",
   228  	})
   229  	config := &ClientConfig{
   230  		User: "testuser",
   231  		Auth: []AuthMethod{
   232  			KeyboardInteractive(answers.Challenge),
   233  		},
   234  		HostKeyCallback: InsecureIgnoreHostKey(),
   235  	}
   236  
   237  	if err := tryAuth(t, config); err != nil {
   238  		t.Fatalf("unable to dial remote side: %s", err)
   239  	}
   240  }
   241  
   242  func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
   243  	answers := keyboardInteractive(map[string]string{
   244  		"question1": "answer1",
   245  		"question2": "WRONG",
   246  	})
   247  	config := &ClientConfig{
   248  		User: "testuser",
   249  		Auth: []AuthMethod{
   250  			KeyboardInteractive(answers.Challenge),
   251  		},
   252  	}
   253  
   254  	if err := tryAuth(t, config); err == nil {
   255  		t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
   256  	}
   257  }
   258  
   259  // the mock server will only authenticate ssh-rsa keys
   260  func TestAuthMethodInvalidPublicKey(t *testing.T) {
   261  	config := &ClientConfig{
   262  		User: "testuser",
   263  		Auth: []AuthMethod{
   264  			PublicKeys(testSigners["dsa"]),
   265  		},
   266  	}
   267  
   268  	if err := tryAuth(t, config); err == nil {
   269  		t.Fatalf("dsa private key should not have authenticated with rsa public key")
   270  	}
   271  }
   272  
   273  // the client should authenticate with the second key
   274  func TestAuthMethodRSAandDSA(t *testing.T) {
   275  	config := &ClientConfig{
   276  		User: "testuser",
   277  		Auth: []AuthMethod{
   278  			PublicKeys(testSigners["dsa"], testSigners["rsa"]),
   279  		},
   280  		HostKeyCallback: InsecureIgnoreHostKey(),
   281  	}
   282  	if err := tryAuth(t, config); err != nil {
   283  		t.Fatalf("client could not authenticate with rsa key: %v", err)
   284  	}
   285  }
   286  
   287  type invalidAlgSigner struct {
   288  	Signer
   289  }
   290  
   291  func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
   292  	sig, err := s.Signer.Sign(rand, data)
   293  	if sig != nil {
   294  		sig.Format = "invalid"
   295  	}
   296  	return sig, err
   297  }
   298  
   299  func TestMethodInvalidAlgorithm(t *testing.T) {
   300  	config := &ClientConfig{
   301  		User: "testuser",
   302  		Auth: []AuthMethod{
   303  			PublicKeys(&invalidAlgSigner{testSigners["rsa"]}),
   304  		},
   305  		HostKeyCallback: InsecureIgnoreHostKey(),
   306  	}
   307  
   308  	err, serverErrors := tryAuthBothSides(t, config, nil)
   309  	if err == nil {
   310  		t.Fatalf("login succeeded")
   311  	}
   312  
   313  	found := false
   314  	want := "algorithm \"invalid\""
   315  
   316  	var errStrings []string
   317  	for _, err := range serverErrors {
   318  		found = found || (err != nil && strings.Contains(err.Error(), want))
   319  		errStrings = append(errStrings, err.Error())
   320  	}
   321  	if !found {
   322  		t.Errorf("server got error %q, want substring %q", errStrings, want)
   323  	}
   324  }
   325  
   326  func TestClientHMAC(t *testing.T) {
   327  	for _, mac := range supportedMACs {
   328  		config := &ClientConfig{
   329  			User: "testuser",
   330  			Auth: []AuthMethod{
   331  				PublicKeys(testSigners["rsa"]),
   332  			},
   333  			Config: Config{
   334  				MACs: []string{mac},
   335  			},
   336  			HostKeyCallback: InsecureIgnoreHostKey(),
   337  		}
   338  		if err := tryAuth(t, config); err != nil {
   339  			t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
   340  		}
   341  	}
   342  }
   343  
   344  // issue 4285.
   345  func TestClientUnsupportedCipher(t *testing.T) {
   346  	config := &ClientConfig{
   347  		User: "testuser",
   348  		Auth: []AuthMethod{
   349  			PublicKeys(),
   350  		},
   351  		Config: Config{
   352  			Ciphers: []string{"aes128-cbc"}, // not currently supported
   353  		},
   354  	}
   355  	if err := tryAuth(t, config); err == nil {
   356  		t.Errorf("expected no ciphers in common")
   357  	}
   358  }
   359  
   360  func TestClientUnsupportedKex(t *testing.T) {
   361  	if os.Getenv("GO_BUILDER_NAME") != "" {
   362  		t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
   363  	}
   364  	config := &ClientConfig{
   365  		User: "testuser",
   366  		Auth: []AuthMethod{
   367  			PublicKeys(),
   368  		},
   369  		Config: Config{
   370  			KeyExchanges: []string{"non-existent-kex"},
   371  		},
   372  		HostKeyCallback: InsecureIgnoreHostKey(),
   373  	}
   374  	if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
   375  		t.Errorf("got %v, expected 'common algorithm'", err)
   376  	}
   377  }
   378  
   379  func TestClientLoginCert(t *testing.T) {
   380  	cert := &Certificate{
   381  		Key:         testPublicKeys["rsa"],
   382  		ValidBefore: CertTimeInfinity,
   383  		CertType:    UserCert,
   384  	}
   385  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   386  	certSigner, err := NewCertSigner(cert, testSigners["rsa"])
   387  	if err != nil {
   388  		t.Fatalf("NewCertSigner: %v", err)
   389  	}
   390  
   391  	clientConfig := &ClientConfig{
   392  		User:            "user",
   393  		HostKeyCallback: InsecureIgnoreHostKey(),
   394  	}
   395  	clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
   396  
   397  	// should succeed
   398  	if err := tryAuth(t, clientConfig); err != nil {
   399  		t.Errorf("cert login failed: %v", err)
   400  	}
   401  
   402  	// corrupted signature
   403  	cert.Signature.Blob[0]++
   404  	if err := tryAuth(t, clientConfig); err == nil {
   405  		t.Errorf("cert login passed with corrupted sig")
   406  	}
   407  
   408  	// revoked
   409  	cert.Serial = 666
   410  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   411  	if err := tryAuth(t, clientConfig); err == nil {
   412  		t.Errorf("revoked cert login succeeded")
   413  	}
   414  	cert.Serial = 1
   415  
   416  	// sign with wrong key
   417  	cert.SignCert(rand.Reader, testSigners["dsa"])
   418  	if err := tryAuth(t, clientConfig); err == nil {
   419  		t.Errorf("cert login passed with non-authoritative key")
   420  	}
   421  
   422  	// host cert
   423  	cert.CertType = HostCert
   424  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   425  	if err := tryAuth(t, clientConfig); err == nil {
   426  		t.Errorf("cert login passed with wrong type")
   427  	}
   428  	cert.CertType = UserCert
   429  
   430  	// principal specified
   431  	cert.ValidPrincipals = []string{"user"}
   432  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   433  	if err := tryAuth(t, clientConfig); err != nil {
   434  		t.Errorf("cert login failed: %v", err)
   435  	}
   436  
   437  	// wrong principal specified
   438  	cert.ValidPrincipals = []string{"fred"}
   439  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   440  	if err := tryAuth(t, clientConfig); err == nil {
   441  		t.Errorf("cert login passed with wrong principal")
   442  	}
   443  	cert.ValidPrincipals = nil
   444  
   445  	// added critical option
   446  	cert.CriticalOptions = map[string]string{"root-access": "yes"}
   447  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   448  	if err := tryAuth(t, clientConfig); err == nil {
   449  		t.Errorf("cert login passed with unrecognized critical option")
   450  	}
   451  
   452  	// allowed source address
   453  	cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
   454  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   455  	if err := tryAuth(t, clientConfig); err != nil {
   456  		t.Errorf("cert login with source-address failed: %v", err)
   457  	}
   458  
   459  	// disallowed source address
   460  	cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
   461  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   462  	if err := tryAuth(t, clientConfig); err == nil {
   463  		t.Errorf("cert login with source-address succeeded")
   464  	}
   465  }
   466  
   467  func testPermissionsPassing(withPermissions bool, t *testing.T) {
   468  	serverConfig := &ServerConfig{
   469  		PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
   470  			if conn.User() == "nopermissions" {
   471  				return nil, nil
   472  			}
   473  			return &Permissions{}, nil
   474  		},
   475  	}
   476  	serverConfig.AddHostKey(testSigners["rsa"])
   477  
   478  	clientConfig := &ClientConfig{
   479  		Auth: []AuthMethod{
   480  			PublicKeys(testSigners["rsa"]),
   481  		},
   482  		HostKeyCallback: InsecureIgnoreHostKey(),
   483  	}
   484  	if withPermissions {
   485  		clientConfig.User = "permissions"
   486  	} else {
   487  		clientConfig.User = "nopermissions"
   488  	}
   489  
   490  	c1, c2, err := netPipe()
   491  	if err != nil {
   492  		t.Fatalf("netPipe: %v", err)
   493  	}
   494  	defer c1.Close()
   495  	defer c2.Close()
   496  
   497  	go NewClientConn(c2, "", clientConfig)
   498  	serverConn, err := newServer(c1, serverConfig)
   499  	if err != nil {
   500  		t.Fatal(err)
   501  	}
   502  	if p := serverConn.Permissions; (p != nil) != withPermissions {
   503  		t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
   504  	}
   505  }
   506  
   507  func TestPermissionsPassing(t *testing.T) {
   508  	testPermissionsPassing(true, t)
   509  }
   510  
   511  func TestNoPermissionsPassing(t *testing.T) {
   512  	testPermissionsPassing(false, t)
   513  }
   514  
   515  func TestRetryableAuth(t *testing.T) {
   516  	n := 0
   517  	passwords := []string{"WRONG1", "WRONG2"}
   518  
   519  	config := &ClientConfig{
   520  		User: "testuser",
   521  		Auth: []AuthMethod{
   522  			RetryableAuthMethod(PasswordCallback(func() (string, error) {
   523  				p := passwords[n]
   524  				n++
   525  				return p, nil
   526  			}), 2),
   527  			PublicKeys(testSigners["rsa"]),
   528  		},
   529  		HostKeyCallback: InsecureIgnoreHostKey(),
   530  	}
   531  
   532  	if err := tryAuth(t, config); err != nil {
   533  		t.Fatalf("unable to dial remote side: %s", err)
   534  	}
   535  	if n != 2 {
   536  		t.Fatalf("Did not try all passwords")
   537  	}
   538  }
   539  
   540  func ExampleRetryableAuthMethod() {
   541  	user := "testuser"
   542  	NumberOfPrompts := 3
   543  
   544  	// Normally this would be a callback that prompts the user to answer the
   545  	// provided questions
   546  	Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
   547  		return []string{"answer1", "answer2"}, nil
   548  	}
   549  
   550  	config := &ClientConfig{
   551  		HostKeyCallback: InsecureIgnoreHostKey(),
   552  		User:            user,
   553  		Auth: []AuthMethod{
   554  			RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
   555  		},
   556  	}
   557  
   558  	host := "mysshserver"
   559  	netConn, err := net.Dial("tcp", host)
   560  	if err != nil {
   561  		log.Fatal(err)
   562  	}
   563  
   564  	sshConn, _, _, err := NewClientConn(netConn, host, config)
   565  	if err != nil {
   566  		log.Fatal(err)
   567  	}
   568  	_ = sshConn
   569  }
   570  
   571  // Test if username is received on server side when NoClientAuth is used
   572  func TestClientAuthNone(t *testing.T) {
   573  	user := "testuser"
   574  	serverConfig := &ServerConfig{
   575  		NoClientAuth: true,
   576  	}
   577  	serverConfig.AddHostKey(testSigners["rsa"])
   578  
   579  	clientConfig := &ClientConfig{
   580  		User:            user,
   581  		HostKeyCallback: InsecureIgnoreHostKey(),
   582  	}
   583  
   584  	c1, c2, err := netPipe()
   585  	if err != nil {
   586  		t.Fatalf("netPipe: %v", err)
   587  	}
   588  	defer c1.Close()
   589  	defer c2.Close()
   590  
   591  	go NewClientConn(c2, "", clientConfig)
   592  	serverConn, err := newServer(c1, serverConfig)
   593  	if err != nil {
   594  		t.Fatalf("newServer: %v", err)
   595  	}
   596  	if serverConn.User() != user {
   597  		t.Fatalf("server: got %q, want %q", serverConn.User(), user)
   598  	}
   599  }
   600  
   601  // Test if authentication attempts are limited on server when MaxAuthTries is set
   602  func TestClientAuthMaxAuthTries(t *testing.T) {
   603  	user := "testuser"
   604  
   605  	serverConfig := &ServerConfig{
   606  		MaxAuthTries: 2,
   607  		PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
   608  			if conn.User() == "testuser" && string(pass) == "right" {
   609  				return nil, nil
   610  			}
   611  			return nil, errors.New("password auth failed")
   612  		},
   613  	}
   614  	serverConfig.AddHostKey(testSigners["rsa"])
   615  
   616  	expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
   617  		Reason:  2,
   618  		Message: "too many authentication failures",
   619  	})
   620  
   621  	for tries := 2; tries < 4; tries++ {
   622  		n := tries
   623  		clientConfig := &ClientConfig{
   624  			User: user,
   625  			Auth: []AuthMethod{
   626  				RetryableAuthMethod(PasswordCallback(func() (string, error) {
   627  					n--
   628  					if n == 0 {
   629  						return "right", nil
   630  					}
   631  					return "wrong", nil
   632  				}), tries),
   633  			},
   634  			HostKeyCallback: InsecureIgnoreHostKey(),
   635  		}
   636  
   637  		c1, c2, err := netPipe()
   638  		if err != nil {
   639  			t.Fatalf("netPipe: %v", err)
   640  		}
   641  		defer c1.Close()
   642  		defer c2.Close()
   643  
   644  		errCh := make(chan error, 1)
   645  
   646  		go func() {
   647  			_, err := newServer(c1, serverConfig)
   648  			errCh <- err
   649  		}()
   650  		_, _, _, cliErr := NewClientConn(c2, "", clientConfig)
   651  		srvErr := <-errCh
   652  
   653  		if tries > serverConfig.MaxAuthTries {
   654  			if cliErr == nil {
   655  				t.Fatalf("client: got no error, want %s", expectedErr)
   656  			} else if cliErr.Error() != expectedErr.Error() {
   657  				t.Fatalf("client: got %s, want %s", err, expectedErr)
   658  			}
   659  			var authErr *ServerAuthError
   660  			if !errors.As(srvErr, &authErr) {
   661  				t.Errorf("expected ServerAuthError, got: %v", srvErr)
   662  			}
   663  		} else {
   664  			if cliErr != nil {
   665  				t.Fatalf("client: got %s, want no error", cliErr)
   666  			}
   667  		}
   668  	}
   669  }
   670  
   671  // Test if authentication attempts are correctly limited on server
   672  // when more public keys are provided then MaxAuthTries
   673  func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) {
   674  	signers := []Signer{}
   675  	for i := 0; i < 6; i++ {
   676  		signers = append(signers, testSigners["dsa"])
   677  	}
   678  
   679  	validConfig := &ClientConfig{
   680  		User: "testuser",
   681  		Auth: []AuthMethod{
   682  			PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...),
   683  		},
   684  		HostKeyCallback: InsecureIgnoreHostKey(),
   685  	}
   686  	if err := tryAuth(t, validConfig); err != nil {
   687  		t.Fatalf("unable to dial remote side: %s", err)
   688  	}
   689  
   690  	expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
   691  		Reason:  2,
   692  		Message: "too many authentication failures",
   693  	})
   694  	invalidConfig := &ClientConfig{
   695  		User: "testuser",
   696  		Auth: []AuthMethod{
   697  			PublicKeys(append(signers, testSigners["rsa"])...),
   698  		},
   699  		HostKeyCallback: InsecureIgnoreHostKey(),
   700  	}
   701  	if err := tryAuth(t, invalidConfig); err == nil {
   702  		t.Fatalf("client: got no error, want %s", expectedErr)
   703  	} else if err.Error() != expectedErr.Error() {
   704  		// On Windows we can see a WSAECONNABORTED error
   705  		// if the client writes another authentication request
   706  		// before the client goroutine reads the disconnection
   707  		// message.  See issue 50805.
   708  		if runtime.GOOS == "windows" && strings.Contains(err.Error(), "wsarecv: An established connection was aborted") {
   709  			// OK.
   710  		} else {
   711  			t.Fatalf("client: got %s, want %s", err, expectedErr)
   712  		}
   713  	}
   714  }
   715  
   716  // Test whether authentication errors are being properly logged if all
   717  // authentication methods have been exhausted
   718  func TestClientAuthErrorList(t *testing.T) {
   719  	publicKeyErr := errors.New("This is an error from PublicKeyCallback")
   720  
   721  	clientConfig := &ClientConfig{
   722  		Auth: []AuthMethod{
   723  			PublicKeys(testSigners["rsa"]),
   724  		},
   725  		HostKeyCallback: InsecureIgnoreHostKey(),
   726  	}
   727  	serverConfig := &ServerConfig{
   728  		PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) {
   729  			return nil, publicKeyErr
   730  		},
   731  	}
   732  	serverConfig.AddHostKey(testSigners["rsa"])
   733  
   734  	c1, c2, err := netPipe()
   735  	if err != nil {
   736  		t.Fatalf("netPipe: %v", err)
   737  	}
   738  	defer c1.Close()
   739  	defer c2.Close()
   740  
   741  	go NewClientConn(c2, "", clientConfig)
   742  	_, err = newServer(c1, serverConfig)
   743  	if err == nil {
   744  		t.Fatal("newServer: got nil, expected errors")
   745  	}
   746  
   747  	authErrs, ok := err.(*ServerAuthError)
   748  	if !ok {
   749  		t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err)
   750  	}
   751  	for i, e := range authErrs.Errors {
   752  		switch i {
   753  		case 0:
   754  			if e != ErrNoAuth {
   755  				t.Fatalf("errors: got error %v, want ErrNoAuth", e)
   756  			}
   757  		case 1:
   758  			if e != publicKeyErr {
   759  				t.Fatalf("errors: got %v, want %v", e, publicKeyErr)
   760  			}
   761  		default:
   762  			t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors)
   763  		}
   764  	}
   765  }
   766  
   767  func TestAuthMethodGSSAPIWithMIC(t *testing.T) {
   768  	type testcase struct {
   769  		config        *ClientConfig
   770  		gssConfig     *GSSAPIWithMICConfig
   771  		clientWantErr string
   772  		serverWantErr string
   773  	}
   774  	testcases := []*testcase{
   775  		{
   776  			config: &ClientConfig{
   777  				User: "testuser",
   778  				Auth: []AuthMethod{
   779  					GSSAPIWithMICAuthMethod(
   780  						&FakeClient{
   781  							exchanges: []*exchange{
   782  								{
   783  									outToken: "client-valid-token-1",
   784  								},
   785  								{
   786  									expectedToken: "server-valid-token-1",
   787  								},
   788  							},
   789  							mic:      []byte("valid-mic"),
   790  							maxRound: 2,
   791  						}, "testtarget",
   792  					),
   793  				},
   794  				HostKeyCallback: InsecureIgnoreHostKey(),
   795  			},
   796  			gssConfig: &GSSAPIWithMICConfig{
   797  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   798  					if srcName != conn.User()+"@DOMAIN" {
   799  						return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
   800  					}
   801  					return nil, nil
   802  				},
   803  				Server: &FakeServer{
   804  					exchanges: []*exchange{
   805  						{
   806  							outToken:      "server-valid-token-1",
   807  							expectedToken: "client-valid-token-1",
   808  						},
   809  					},
   810  					maxRound:    1,
   811  					expectedMIC: []byte("valid-mic"),
   812  					srcName:     "testuser@DOMAIN",
   813  				},
   814  			},
   815  		},
   816  		{
   817  			config: &ClientConfig{
   818  				User: "testuser",
   819  				Auth: []AuthMethod{
   820  					GSSAPIWithMICAuthMethod(
   821  						&FakeClient{
   822  							exchanges: []*exchange{
   823  								{
   824  									outToken: "client-valid-token-1",
   825  								},
   826  								{
   827  									expectedToken: "server-valid-token-1",
   828  								},
   829  							},
   830  							mic:      []byte("valid-mic"),
   831  							maxRound: 2,
   832  						}, "testtarget",
   833  					),
   834  				},
   835  				HostKeyCallback: InsecureIgnoreHostKey(),
   836  			},
   837  			gssConfig: &GSSAPIWithMICConfig{
   838  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   839  					return nil, fmt.Errorf("user is not allowed to login")
   840  				},
   841  				Server: &FakeServer{
   842  					exchanges: []*exchange{
   843  						{
   844  							outToken:      "server-valid-token-1",
   845  							expectedToken: "client-valid-token-1",
   846  						},
   847  					},
   848  					maxRound:    1,
   849  					expectedMIC: []byte("valid-mic"),
   850  					srcName:     "testuser@DOMAIN",
   851  				},
   852  			},
   853  			serverWantErr: "user is not allowed to login",
   854  			clientWantErr: "ssh: handshake failed: ssh: unable to authenticate",
   855  		},
   856  		{
   857  			config: &ClientConfig{
   858  				User: "testuser",
   859  				Auth: []AuthMethod{
   860  					GSSAPIWithMICAuthMethod(
   861  						&FakeClient{
   862  							exchanges: []*exchange{
   863  								{
   864  									outToken: "client-valid-token-1",
   865  								},
   866  								{
   867  									expectedToken: "server-valid-token-1",
   868  								},
   869  							},
   870  							mic:      []byte("valid-mic"),
   871  							maxRound: 2,
   872  						}, "testtarget",
   873  					),
   874  				},
   875  				HostKeyCallback: InsecureIgnoreHostKey(),
   876  			},
   877  			gssConfig: &GSSAPIWithMICConfig{
   878  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   879  					if srcName != conn.User() {
   880  						return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
   881  					}
   882  					return nil, nil
   883  				},
   884  				Server: &FakeServer{
   885  					exchanges: []*exchange{
   886  						{
   887  							outToken:      "server-invalid-token-1",
   888  							expectedToken: "client-valid-token-1",
   889  						},
   890  					},
   891  					maxRound:    1,
   892  					expectedMIC: []byte("valid-mic"),
   893  					srcName:     "testuser@DOMAIN",
   894  				},
   895  			},
   896  			clientWantErr: "ssh: handshake failed: got \"server-invalid-token-1\", want token \"server-valid-token-1\"",
   897  		},
   898  		{
   899  			config: &ClientConfig{
   900  				User: "testuser",
   901  				Auth: []AuthMethod{
   902  					GSSAPIWithMICAuthMethod(
   903  						&FakeClient{
   904  							exchanges: []*exchange{
   905  								{
   906  									outToken: "client-valid-token-1",
   907  								},
   908  								{
   909  									expectedToken: "server-valid-token-1",
   910  								},
   911  							},
   912  							mic:      []byte("invalid-mic"),
   913  							maxRound: 2,
   914  						}, "testtarget",
   915  					),
   916  				},
   917  				HostKeyCallback: InsecureIgnoreHostKey(),
   918  			},
   919  			gssConfig: &GSSAPIWithMICConfig{
   920  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   921  					if srcName != conn.User() {
   922  						return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
   923  					}
   924  					return nil, nil
   925  				},
   926  				Server: &FakeServer{
   927  					exchanges: []*exchange{
   928  						{
   929  							outToken:      "server-valid-token-1",
   930  							expectedToken: "client-valid-token-1",
   931  						},
   932  					},
   933  					maxRound:    1,
   934  					expectedMIC: []byte("valid-mic"),
   935  					srcName:     "testuser@DOMAIN",
   936  				},
   937  			},
   938  			serverWantErr: "got MICToken \"invalid-mic\", want \"valid-mic\"",
   939  			clientWantErr: "ssh: handshake failed: ssh: unable to authenticate",
   940  		},
   941  	}
   942  
   943  	for i, c := range testcases {
   944  		clientErr, serverErrs := tryAuthBothSides(t, c.config, c.gssConfig)
   945  		if (c.clientWantErr == "") != (clientErr == nil) {
   946  			t.Fatalf("client got %v, want %s, case %d", clientErr, c.clientWantErr, i)
   947  		}
   948  		if (c.serverWantErr == "") != (len(serverErrs) == 2 && serverErrs[1] == nil || len(serverErrs) == 1) {
   949  			t.Fatalf("server got err %v, want %s", serverErrs, c.serverWantErr)
   950  		}
   951  		if c.clientWantErr != "" {
   952  			if clientErr != nil && !strings.Contains(clientErr.Error(), c.clientWantErr) {
   953  				t.Fatalf("client  got %v, want %s, case %d", clientErr, c.clientWantErr, i)
   954  			}
   955  		}
   956  		found := false
   957  		var errStrings []string
   958  		if c.serverWantErr != "" {
   959  			for _, err := range serverErrs {
   960  				found = found || (err != nil && strings.Contains(err.Error(), c.serverWantErr))
   961  				errStrings = append(errStrings, err.Error())
   962  			}
   963  			if !found {
   964  				t.Errorf("server got error %q, want substring %q, case %d", errStrings, c.serverWantErr, i)
   965  			}
   966  		}
   967  	}
   968  }
   969  
   970  func TestCompatibleAlgoAndSignatures(t *testing.T) {
   971  	type testcase struct {
   972  		algo       string
   973  		sigFormat  string
   974  		compatible bool
   975  	}
   976  	testcases := []*testcase{
   977  		{
   978  			KeyAlgoRSA,
   979  			KeyAlgoRSA,
   980  			true,
   981  		},
   982  		{
   983  			KeyAlgoRSA,
   984  			KeyAlgoRSASHA256,
   985  			true,
   986  		},
   987  		{
   988  			KeyAlgoRSA,
   989  			KeyAlgoRSASHA512,
   990  			true,
   991  		},
   992  		{
   993  			KeyAlgoRSASHA256,
   994  			KeyAlgoRSA,
   995  			true,
   996  		},
   997  		{
   998  			KeyAlgoRSASHA512,
   999  			KeyAlgoRSA,
  1000  			true,
  1001  		},
  1002  		{
  1003  			KeyAlgoRSASHA512,
  1004  			KeyAlgoRSASHA256,
  1005  			true,
  1006  		},
  1007  		{
  1008  			KeyAlgoRSASHA256,
  1009  			KeyAlgoRSASHA512,
  1010  			true,
  1011  		},
  1012  		{
  1013  			KeyAlgoRSASHA512,
  1014  			KeyAlgoRSASHA512,
  1015  			true,
  1016  		},
  1017  		{
  1018  			CertAlgoRSAv01,
  1019  			KeyAlgoRSA,
  1020  			true,
  1021  		},
  1022  		{
  1023  			CertAlgoRSAv01,
  1024  			KeyAlgoRSASHA256,
  1025  			true,
  1026  		},
  1027  		{
  1028  			CertAlgoRSAv01,
  1029  			KeyAlgoRSASHA512,
  1030  			true,
  1031  		},
  1032  		{
  1033  			CertAlgoRSASHA256v01,
  1034  			KeyAlgoRSASHA512,
  1035  			true,
  1036  		},
  1037  		{
  1038  			CertAlgoRSASHA512v01,
  1039  			KeyAlgoRSASHA512,
  1040  			true,
  1041  		},
  1042  		{
  1043  			CertAlgoRSASHA512v01,
  1044  			KeyAlgoRSASHA256,
  1045  			true,
  1046  		},
  1047  		{
  1048  			CertAlgoRSASHA256v01,
  1049  			CertAlgoRSAv01,
  1050  			true,
  1051  		},
  1052  		{
  1053  			CertAlgoRSAv01,
  1054  			CertAlgoRSASHA512v01,
  1055  			true,
  1056  		},
  1057  		{
  1058  			KeyAlgoECDSA256,
  1059  			KeyAlgoRSA,
  1060  			false,
  1061  		},
  1062  		{
  1063  			KeyAlgoECDSA256,
  1064  			KeyAlgoECDSA521,
  1065  			false,
  1066  		},
  1067  		{
  1068  			KeyAlgoECDSA256,
  1069  			KeyAlgoECDSA256,
  1070  			true,
  1071  		},
  1072  		{
  1073  			KeyAlgoECDSA256,
  1074  			KeyAlgoED25519,
  1075  			false,
  1076  		},
  1077  		{
  1078  			KeyAlgoED25519,
  1079  			KeyAlgoED25519,
  1080  			true,
  1081  		},
  1082  	}
  1083  
  1084  	for _, c := range testcases {
  1085  		if isAlgoCompatible(c.algo, c.sigFormat) != c.compatible {
  1086  			t.Errorf("algorithm %q, signature format %q, expected compatible to be %t", c.algo, c.sigFormat, c.compatible)
  1087  		}
  1088  	}
  1089  }
  1090  
  1091  func TestPickSignatureAlgorithm(t *testing.T) {
  1092  	type testcase struct {
  1093  		name       string
  1094  		extensions map[string][]byte
  1095  	}
  1096  	cases := []testcase{
  1097  		{
  1098  			name: "server with empty server-sig-algs",
  1099  			extensions: map[string][]byte{
  1100  				"server-sig-algs": []byte(``),
  1101  			},
  1102  		},
  1103  		{
  1104  			name:       "server with no server-sig-algs",
  1105  			extensions: nil,
  1106  		},
  1107  	}
  1108  	for _, c := range cases {
  1109  		t.Run(c.name, func(t *testing.T) {
  1110  			signer, ok := testSigners["rsa"].(MultiAlgorithmSigner)
  1111  			if !ok {
  1112  				t.Fatalf("rsa test signer does not implement the MultiAlgorithmSigner interface")
  1113  			}
  1114  			// The signer supports the public key algorithm which is then returned.
  1115  			_, algo, err := pickSignatureAlgorithm(signer, c.extensions)
  1116  			if err != nil {
  1117  				t.Fatalf("got %v, want no error", err)
  1118  			}
  1119  			if algo != signer.PublicKey().Type() {
  1120  				t.Fatalf("got algo %q, want %q", algo, signer.PublicKey().Type())
  1121  			}
  1122  			// Test a signer that uses a certificate algorithm as the public key
  1123  			// type.
  1124  			cert := &Certificate{
  1125  				CertType: UserCert,
  1126  				Key:      signer.PublicKey(),
  1127  			}
  1128  			cert.SignCert(rand.Reader, signer)
  1129  
  1130  			certSigner, err := NewCertSigner(cert, signer)
  1131  			if err != nil {
  1132  				t.Fatalf("error generating cert signer: %v", err)
  1133  			}
  1134  			// The signer supports the public key algorithm and the
  1135  			// public key format is a certificate type so the cerificate
  1136  			// algorithm matching the key format must be returned
  1137  			_, algo, err = pickSignatureAlgorithm(certSigner, c.extensions)
  1138  			if err != nil {
  1139  				t.Fatalf("got %v, want no error", err)
  1140  			}
  1141  			if algo != certSigner.PublicKey().Type() {
  1142  				t.Fatalf("got algo %q, want %q", algo, certSigner.PublicKey().Type())
  1143  			}
  1144  			signer, err = NewSignerWithAlgorithms(signer.(AlgorithmSigner), []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256})
  1145  			if err != nil {
  1146  				t.Fatalf("unable to create signer with algorithms: %v", err)
  1147  			}
  1148  			// The signer does not support the public key algorithm so an error
  1149  			// is returned.
  1150  			_, _, err = pickSignatureAlgorithm(signer, c.extensions)
  1151  			if err == nil {
  1152  				t.Fatal("got no error, no common public key signature algorithm error expected")
  1153  			}
  1154  		})
  1155  	}
  1156  }
  1157  
  1158  // configurablePublicKeyCallback is a public key callback that allows to
  1159  // configure the signature algorithm and format. This way we can emulate the
  1160  // behavior of buggy clients.
  1161  type configurablePublicKeyCallback struct {
  1162  	signer          AlgorithmSigner
  1163  	signatureAlgo   string
  1164  	signatureFormat string
  1165  }
  1166  
  1167  func (cb configurablePublicKeyCallback) method() string {
  1168  	return "publickey"
  1169  }
  1170  
  1171  func (cb configurablePublicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
  1172  	pub := cb.signer.PublicKey()
  1173  
  1174  	ok, err := validateKey(pub, cb.signatureAlgo, user, c)
  1175  	if err != nil {
  1176  		return authFailure, nil, err
  1177  	}
  1178  	if !ok {
  1179  		return authFailure, nil, fmt.Errorf("invalid public key")
  1180  	}
  1181  
  1182  	pubKey := pub.Marshal()
  1183  	data := buildDataSignedForAuth(session, userAuthRequestMsg{
  1184  		User:    user,
  1185  		Service: serviceSSH,
  1186  		Method:  cb.method(),
  1187  	}, cb.signatureAlgo, pubKey)
  1188  	sign, err := cb.signer.SignWithAlgorithm(rand, data, underlyingAlgo(cb.signatureFormat))
  1189  	if err != nil {
  1190  		return authFailure, nil, err
  1191  	}
  1192  
  1193  	s := Marshal(sign)
  1194  	sig := make([]byte, stringLength(len(s)))
  1195  	marshalString(sig, s)
  1196  	msg := publickeyAuthMsg{
  1197  		User:     user,
  1198  		Service:  serviceSSH,
  1199  		Method:   cb.method(),
  1200  		HasSig:   true,
  1201  		Algoname: cb.signatureAlgo,
  1202  		PubKey:   pubKey,
  1203  		Sig:      sig,
  1204  	}
  1205  	p := Marshal(&msg)
  1206  	if err := c.writePacket(p); err != nil {
  1207  		return authFailure, nil, err
  1208  	}
  1209  	var success authResult
  1210  	success, methods, err := handleAuthResponse(c)
  1211  	if err != nil {
  1212  		return authFailure, nil, err
  1213  	}
  1214  	if success == authSuccess || !contains(methods, cb.method()) {
  1215  		return success, methods, err
  1216  	}
  1217  
  1218  	return authFailure, methods, nil
  1219  }
  1220  
  1221  func TestPublicKeyAndAlgoCompatibility(t *testing.T) {
  1222  	cert := &Certificate{
  1223  		Key:         testPublicKeys["rsa"],
  1224  		ValidBefore: CertTimeInfinity,
  1225  		CertType:    UserCert,
  1226  	}
  1227  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
  1228  	certSigner, err := NewCertSigner(cert, testSigners["rsa"])
  1229  	if err != nil {
  1230  		t.Fatalf("NewCertSigner: %v", err)
  1231  	}
  1232  
  1233  	clientConfig := &ClientConfig{
  1234  		User:            "user",
  1235  		HostKeyCallback: InsecureIgnoreHostKey(),
  1236  		Auth: []AuthMethod{
  1237  			configurablePublicKeyCallback{
  1238  				signer:          certSigner.(AlgorithmSigner),
  1239  				signatureAlgo:   KeyAlgoRSASHA256,
  1240  				signatureFormat: KeyAlgoRSASHA256,
  1241  			},
  1242  		},
  1243  	}
  1244  	if err := tryAuth(t, clientConfig); err == nil {
  1245  		t.Error("cert login passed with incompatible public key type and algorithm")
  1246  	}
  1247  }
  1248  
  1249  func TestClientAuthGPGAgentCompat(t *testing.T) {
  1250  	clientConfig := &ClientConfig{
  1251  		User:            "testuser",
  1252  		HostKeyCallback: InsecureIgnoreHostKey(),
  1253  		Auth: []AuthMethod{
  1254  			// algorithm rsa-sha2-512 and signature format ssh-rsa.
  1255  			configurablePublicKeyCallback{
  1256  				signer:          testSigners["rsa"].(AlgorithmSigner),
  1257  				signatureAlgo:   KeyAlgoRSASHA512,
  1258  				signatureFormat: KeyAlgoRSA,
  1259  			},
  1260  		},
  1261  	}
  1262  	if err := tryAuth(t, clientConfig); err != nil {
  1263  		t.Fatalf("unable to dial remote side: %s", err)
  1264  	}
  1265  }
  1266  
  1267  func TestCertAuthOpenSSHCompat(t *testing.T) {
  1268  	cert := &Certificate{
  1269  		Key:         testPublicKeys["rsa"],
  1270  		ValidBefore: CertTimeInfinity,
  1271  		CertType:    UserCert,
  1272  	}
  1273  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
  1274  	certSigner, err := NewCertSigner(cert, testSigners["rsa"])
  1275  	if err != nil {
  1276  		t.Fatalf("NewCertSigner: %v", err)
  1277  	}
  1278  
  1279  	clientConfig := &ClientConfig{
  1280  		User:            "user",
  1281  		HostKeyCallback: InsecureIgnoreHostKey(),
  1282  		Auth: []AuthMethod{
  1283  			// algorithm ssh-rsa-cert-v01@openssh.com and signature format
  1284  			// rsa-sha2-256.
  1285  			configurablePublicKeyCallback{
  1286  				signer:          certSigner.(AlgorithmSigner),
  1287  				signatureAlgo:   CertAlgoRSAv01,
  1288  				signatureFormat: KeyAlgoRSASHA256,
  1289  			},
  1290  		},
  1291  	}
  1292  	if err := tryAuth(t, clientConfig); err != nil {
  1293  		t.Fatalf("unable to dial remote side: %s", err)
  1294  	}
  1295  }
  1296  
  1297  func TestKeyboardInteractiveAuthEarlyFail(t *testing.T) {
  1298  	const maxAuthTries = 2
  1299  
  1300  	c1, c2, err := netPipe()
  1301  	if err != nil {
  1302  		t.Fatalf("netPipe: %v", err)
  1303  	}
  1304  	defer c1.Close()
  1305  	defer c2.Close()
  1306  
  1307  	// Start testserver
  1308  	serverConfig := &ServerConfig{
  1309  		MaxAuthTries: maxAuthTries,
  1310  		KeyboardInteractiveCallback: func(c ConnMetadata,
  1311  			client KeyboardInteractiveChallenge) (*Permissions, error) {
  1312  			// Fail keyboard-interactive authentication early before
  1313  			// any prompt is sent to client.
  1314  			return nil, errors.New("keyboard-interactive auth failed")
  1315  		},
  1316  		PasswordCallback: func(c ConnMetadata,
  1317  			pass []byte) (*Permissions, error) {
  1318  			if string(pass) == clientPassword {
  1319  				return nil, nil
  1320  			}
  1321  			return nil, errors.New("password auth failed")
  1322  		},
  1323  	}
  1324  	serverConfig.AddHostKey(testSigners["rsa"])
  1325  
  1326  	serverDone := make(chan struct{})
  1327  	go func() {
  1328  		defer func() { serverDone <- struct{}{} }()
  1329  		conn, chans, reqs, err := NewServerConn(c2, serverConfig)
  1330  		if err != nil {
  1331  			return
  1332  		}
  1333  		_ = conn.Close()
  1334  
  1335  		discarderDone := make(chan struct{})
  1336  		go func() {
  1337  			defer func() { discarderDone <- struct{}{} }()
  1338  			DiscardRequests(reqs)
  1339  		}()
  1340  		for newChannel := range chans {
  1341  			newChannel.Reject(Prohibited,
  1342  				"testserver not accepting requests")
  1343  		}
  1344  
  1345  		<-discarderDone
  1346  	}()
  1347  
  1348  	// Connect to testserver, expect KeyboardInteractive() to be not called,
  1349  	// PasswordCallback() to be called and connection to succeed.
  1350  	passwordCallbackCalled := false
  1351  	clientConfig := &ClientConfig{
  1352  		User: "testuser",
  1353  		Auth: []AuthMethod{
  1354  			RetryableAuthMethod(KeyboardInteractive(func(name,
  1355  				instruction string, questions []string,
  1356  				echos []bool) ([]string, error) {
  1357  				t.Errorf("unexpected call to KeyboardInteractive()")
  1358  				return []string{clientPassword}, nil
  1359  			}), maxAuthTries),
  1360  			RetryableAuthMethod(PasswordCallback(func() (secret string,
  1361  				err error) {
  1362  				t.Logf("PasswordCallback()")
  1363  				passwordCallbackCalled = true
  1364  				return clientPassword, nil
  1365  			}), maxAuthTries),
  1366  		},
  1367  		HostKeyCallback: InsecureIgnoreHostKey(),
  1368  	}
  1369  
  1370  	conn, _, _, err := NewClientConn(c1, "", clientConfig)
  1371  	if err != nil {
  1372  		t.Errorf("unexpected NewClientConn() error: %v", err)
  1373  	}
  1374  	if conn != nil {
  1375  		conn.Close()
  1376  	}
  1377  
  1378  	// Wait for server to finish.
  1379  	<-serverDone
  1380  
  1381  	if !passwordCallbackCalled {
  1382  		t.Errorf("expected PasswordCallback() to be called")
  1383  	}
  1384  }
  1385  

View as plain text