...

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  // tryAuth 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  		go newServer(c1, serverConfig)
   645  		_, _, _, err = NewClientConn(c2, "", clientConfig)
   646  		if tries > 2 {
   647  			if err == nil {
   648  				t.Fatalf("client: got no error, want %s", expectedErr)
   649  			} else if err.Error() != expectedErr.Error() {
   650  				t.Fatalf("client: got %s, want %s", err, expectedErr)
   651  			}
   652  		} else {
   653  			if err != nil {
   654  				t.Fatalf("client: got %s, want no error", err)
   655  			}
   656  		}
   657  	}
   658  }
   659  
   660  // Test if authentication attempts are correctly limited on server
   661  // when more public keys are provided then MaxAuthTries
   662  func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) {
   663  	signers := []Signer{}
   664  	for i := 0; i < 6; i++ {
   665  		signers = append(signers, testSigners["dsa"])
   666  	}
   667  
   668  	validConfig := &ClientConfig{
   669  		User: "testuser",
   670  		Auth: []AuthMethod{
   671  			PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...),
   672  		},
   673  		HostKeyCallback: InsecureIgnoreHostKey(),
   674  	}
   675  	if err := tryAuth(t, validConfig); err != nil {
   676  		t.Fatalf("unable to dial remote side: %s", err)
   677  	}
   678  
   679  	expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
   680  		Reason:  2,
   681  		Message: "too many authentication failures",
   682  	})
   683  	invalidConfig := &ClientConfig{
   684  		User: "testuser",
   685  		Auth: []AuthMethod{
   686  			PublicKeys(append(signers, testSigners["rsa"])...),
   687  		},
   688  		HostKeyCallback: InsecureIgnoreHostKey(),
   689  	}
   690  	if err := tryAuth(t, invalidConfig); err == nil {
   691  		t.Fatalf("client: got no error, want %s", expectedErr)
   692  	} else if err.Error() != expectedErr.Error() {
   693  		// On Windows we can see a WSAECONNABORTED error
   694  		// if the client writes another authentication request
   695  		// before the client goroutine reads the disconnection
   696  		// message.  See issue 50805.
   697  		if runtime.GOOS == "windows" && strings.Contains(err.Error(), "wsarecv: An established connection was aborted") {
   698  			// OK.
   699  		} else {
   700  			t.Fatalf("client: got %s, want %s", err, expectedErr)
   701  		}
   702  	}
   703  }
   704  
   705  // Test whether authentication errors are being properly logged if all
   706  // authentication methods have been exhausted
   707  func TestClientAuthErrorList(t *testing.T) {
   708  	publicKeyErr := errors.New("This is an error from PublicKeyCallback")
   709  
   710  	clientConfig := &ClientConfig{
   711  		Auth: []AuthMethod{
   712  			PublicKeys(testSigners["rsa"]),
   713  		},
   714  		HostKeyCallback: InsecureIgnoreHostKey(),
   715  	}
   716  	serverConfig := &ServerConfig{
   717  		PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) {
   718  			return nil, publicKeyErr
   719  		},
   720  	}
   721  	serverConfig.AddHostKey(testSigners["rsa"])
   722  
   723  	c1, c2, err := netPipe()
   724  	if err != nil {
   725  		t.Fatalf("netPipe: %v", err)
   726  	}
   727  	defer c1.Close()
   728  	defer c2.Close()
   729  
   730  	go NewClientConn(c2, "", clientConfig)
   731  	_, err = newServer(c1, serverConfig)
   732  	if err == nil {
   733  		t.Fatal("newServer: got nil, expected errors")
   734  	}
   735  
   736  	authErrs, ok := err.(*ServerAuthError)
   737  	if !ok {
   738  		t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err)
   739  	}
   740  	for i, e := range authErrs.Errors {
   741  		switch i {
   742  		case 0:
   743  			if e != ErrNoAuth {
   744  				t.Fatalf("errors: got error %v, want ErrNoAuth", e)
   745  			}
   746  		case 1:
   747  			if e != publicKeyErr {
   748  				t.Fatalf("errors: got %v, want %v", e, publicKeyErr)
   749  			}
   750  		default:
   751  			t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors)
   752  		}
   753  	}
   754  }
   755  
   756  func TestAuthMethodGSSAPIWithMIC(t *testing.T) {
   757  	type testcase struct {
   758  		config        *ClientConfig
   759  		gssConfig     *GSSAPIWithMICConfig
   760  		clientWantErr string
   761  		serverWantErr string
   762  	}
   763  	testcases := []*testcase{
   764  		{
   765  			config: &ClientConfig{
   766  				User: "testuser",
   767  				Auth: []AuthMethod{
   768  					GSSAPIWithMICAuthMethod(
   769  						&FakeClient{
   770  							exchanges: []*exchange{
   771  								{
   772  									outToken: "client-valid-token-1",
   773  								},
   774  								{
   775  									expectedToken: "server-valid-token-1",
   776  								},
   777  							},
   778  							mic:      []byte("valid-mic"),
   779  							maxRound: 2,
   780  						}, "testtarget",
   781  					),
   782  				},
   783  				HostKeyCallback: InsecureIgnoreHostKey(),
   784  			},
   785  			gssConfig: &GSSAPIWithMICConfig{
   786  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   787  					if srcName != conn.User()+"@DOMAIN" {
   788  						return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
   789  					}
   790  					return nil, nil
   791  				},
   792  				Server: &FakeServer{
   793  					exchanges: []*exchange{
   794  						{
   795  							outToken:      "server-valid-token-1",
   796  							expectedToken: "client-valid-token-1",
   797  						},
   798  					},
   799  					maxRound:    1,
   800  					expectedMIC: []byte("valid-mic"),
   801  					srcName:     "testuser@DOMAIN",
   802  				},
   803  			},
   804  		},
   805  		{
   806  			config: &ClientConfig{
   807  				User: "testuser",
   808  				Auth: []AuthMethod{
   809  					GSSAPIWithMICAuthMethod(
   810  						&FakeClient{
   811  							exchanges: []*exchange{
   812  								{
   813  									outToken: "client-valid-token-1",
   814  								},
   815  								{
   816  									expectedToken: "server-valid-token-1",
   817  								},
   818  							},
   819  							mic:      []byte("valid-mic"),
   820  							maxRound: 2,
   821  						}, "testtarget",
   822  					),
   823  				},
   824  				HostKeyCallback: InsecureIgnoreHostKey(),
   825  			},
   826  			gssConfig: &GSSAPIWithMICConfig{
   827  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   828  					return nil, fmt.Errorf("user is not allowed to login")
   829  				},
   830  				Server: &FakeServer{
   831  					exchanges: []*exchange{
   832  						{
   833  							outToken:      "server-valid-token-1",
   834  							expectedToken: "client-valid-token-1",
   835  						},
   836  					},
   837  					maxRound:    1,
   838  					expectedMIC: []byte("valid-mic"),
   839  					srcName:     "testuser@DOMAIN",
   840  				},
   841  			},
   842  			serverWantErr: "user is not allowed to login",
   843  			clientWantErr: "ssh: handshake failed: ssh: unable to authenticate",
   844  		},
   845  		{
   846  			config: &ClientConfig{
   847  				User: "testuser",
   848  				Auth: []AuthMethod{
   849  					GSSAPIWithMICAuthMethod(
   850  						&FakeClient{
   851  							exchanges: []*exchange{
   852  								{
   853  									outToken: "client-valid-token-1",
   854  								},
   855  								{
   856  									expectedToken: "server-valid-token-1",
   857  								},
   858  							},
   859  							mic:      []byte("valid-mic"),
   860  							maxRound: 2,
   861  						}, "testtarget",
   862  					),
   863  				},
   864  				HostKeyCallback: InsecureIgnoreHostKey(),
   865  			},
   866  			gssConfig: &GSSAPIWithMICConfig{
   867  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   868  					if srcName != conn.User() {
   869  						return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
   870  					}
   871  					return nil, nil
   872  				},
   873  				Server: &FakeServer{
   874  					exchanges: []*exchange{
   875  						{
   876  							outToken:      "server-invalid-token-1",
   877  							expectedToken: "client-valid-token-1",
   878  						},
   879  					},
   880  					maxRound:    1,
   881  					expectedMIC: []byte("valid-mic"),
   882  					srcName:     "testuser@DOMAIN",
   883  				},
   884  			},
   885  			clientWantErr: "ssh: handshake failed: got \"server-invalid-token-1\", want token \"server-valid-token-1\"",
   886  		},
   887  		{
   888  			config: &ClientConfig{
   889  				User: "testuser",
   890  				Auth: []AuthMethod{
   891  					GSSAPIWithMICAuthMethod(
   892  						&FakeClient{
   893  							exchanges: []*exchange{
   894  								{
   895  									outToken: "client-valid-token-1",
   896  								},
   897  								{
   898  									expectedToken: "server-valid-token-1",
   899  								},
   900  							},
   901  							mic:      []byte("invalid-mic"),
   902  							maxRound: 2,
   903  						}, "testtarget",
   904  					),
   905  				},
   906  				HostKeyCallback: InsecureIgnoreHostKey(),
   907  			},
   908  			gssConfig: &GSSAPIWithMICConfig{
   909  				AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
   910  					if srcName != conn.User() {
   911  						return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
   912  					}
   913  					return nil, nil
   914  				},
   915  				Server: &FakeServer{
   916  					exchanges: []*exchange{
   917  						{
   918  							outToken:      "server-valid-token-1",
   919  							expectedToken: "client-valid-token-1",
   920  						},
   921  					},
   922  					maxRound:    1,
   923  					expectedMIC: []byte("valid-mic"),
   924  					srcName:     "testuser@DOMAIN",
   925  				},
   926  			},
   927  			serverWantErr: "got MICToken \"invalid-mic\", want \"valid-mic\"",
   928  			clientWantErr: "ssh: handshake failed: ssh: unable to authenticate",
   929  		},
   930  	}
   931  
   932  	for i, c := range testcases {
   933  		clientErr, serverErrs := tryAuthBothSides(t, c.config, c.gssConfig)
   934  		if (c.clientWantErr == "") != (clientErr == nil) {
   935  			t.Fatalf("client got %v, want %s, case %d", clientErr, c.clientWantErr, i)
   936  		}
   937  		if (c.serverWantErr == "") != (len(serverErrs) == 2 && serverErrs[1] == nil || len(serverErrs) == 1) {
   938  			t.Fatalf("server got err %v, want %s", serverErrs, c.serverWantErr)
   939  		}
   940  		if c.clientWantErr != "" {
   941  			if clientErr != nil && !strings.Contains(clientErr.Error(), c.clientWantErr) {
   942  				t.Fatalf("client  got %v, want %s, case %d", clientErr, c.clientWantErr, i)
   943  			}
   944  		}
   945  		found := false
   946  		var errStrings []string
   947  		if c.serverWantErr != "" {
   948  			for _, err := range serverErrs {
   949  				found = found || (err != nil && strings.Contains(err.Error(), c.serverWantErr))
   950  				errStrings = append(errStrings, err.Error())
   951  			}
   952  			if !found {
   953  				t.Errorf("server got error %q, want substring %q, case %d", errStrings, c.serverWantErr, i)
   954  			}
   955  		}
   956  	}
   957  }
   958  
   959  func TestCompatibleAlgoAndSignatures(t *testing.T) {
   960  	type testcase struct {
   961  		algo       string
   962  		sigFormat  string
   963  		compatible bool
   964  	}
   965  	testcases := []*testcase{
   966  		{
   967  			KeyAlgoRSA,
   968  			KeyAlgoRSA,
   969  			true,
   970  		},
   971  		{
   972  			KeyAlgoRSA,
   973  			KeyAlgoRSASHA256,
   974  			true,
   975  		},
   976  		{
   977  			KeyAlgoRSA,
   978  			KeyAlgoRSASHA512,
   979  			true,
   980  		},
   981  		{
   982  			KeyAlgoRSASHA256,
   983  			KeyAlgoRSA,
   984  			true,
   985  		},
   986  		{
   987  			KeyAlgoRSASHA512,
   988  			KeyAlgoRSA,
   989  			true,
   990  		},
   991  		{
   992  			KeyAlgoRSASHA512,
   993  			KeyAlgoRSASHA256,
   994  			true,
   995  		},
   996  		{
   997  			KeyAlgoRSASHA256,
   998  			KeyAlgoRSASHA512,
   999  			true,
  1000  		},
  1001  		{
  1002  			KeyAlgoRSASHA512,
  1003  			KeyAlgoRSASHA512,
  1004  			true,
  1005  		},
  1006  		{
  1007  			CertAlgoRSAv01,
  1008  			KeyAlgoRSA,
  1009  			true,
  1010  		},
  1011  		{
  1012  			CertAlgoRSAv01,
  1013  			KeyAlgoRSASHA256,
  1014  			true,
  1015  		},
  1016  		{
  1017  			CertAlgoRSAv01,
  1018  			KeyAlgoRSASHA512,
  1019  			true,
  1020  		},
  1021  		{
  1022  			CertAlgoRSASHA256v01,
  1023  			KeyAlgoRSASHA512,
  1024  			true,
  1025  		},
  1026  		{
  1027  			CertAlgoRSASHA512v01,
  1028  			KeyAlgoRSASHA512,
  1029  			true,
  1030  		},
  1031  		{
  1032  			CertAlgoRSASHA512v01,
  1033  			KeyAlgoRSASHA256,
  1034  			true,
  1035  		},
  1036  		{
  1037  			CertAlgoRSASHA256v01,
  1038  			CertAlgoRSAv01,
  1039  			true,
  1040  		},
  1041  		{
  1042  			CertAlgoRSAv01,
  1043  			CertAlgoRSASHA512v01,
  1044  			true,
  1045  		},
  1046  		{
  1047  			KeyAlgoECDSA256,
  1048  			KeyAlgoRSA,
  1049  			false,
  1050  		},
  1051  		{
  1052  			KeyAlgoECDSA256,
  1053  			KeyAlgoECDSA521,
  1054  			false,
  1055  		},
  1056  		{
  1057  			KeyAlgoECDSA256,
  1058  			KeyAlgoECDSA256,
  1059  			true,
  1060  		},
  1061  		{
  1062  			KeyAlgoECDSA256,
  1063  			KeyAlgoED25519,
  1064  			false,
  1065  		},
  1066  		{
  1067  			KeyAlgoED25519,
  1068  			KeyAlgoED25519,
  1069  			true,
  1070  		},
  1071  	}
  1072  
  1073  	for _, c := range testcases {
  1074  		if isAlgoCompatible(c.algo, c.sigFormat) != c.compatible {
  1075  			t.Errorf("algorithm %q, signature format %q, expected compatible to be %t", c.algo, c.sigFormat, c.compatible)
  1076  		}
  1077  	}
  1078  }
  1079  
  1080  func TestPickSignatureAlgorithm(t *testing.T) {
  1081  	type testcase struct {
  1082  		name       string
  1083  		extensions map[string][]byte
  1084  	}
  1085  	cases := []testcase{
  1086  		{
  1087  			name: "server with empty server-sig-algs",
  1088  			extensions: map[string][]byte{
  1089  				"server-sig-algs": []byte(``),
  1090  			},
  1091  		},
  1092  		{
  1093  			name:       "server with no server-sig-algs",
  1094  			extensions: nil,
  1095  		},
  1096  	}
  1097  	for _, c := range cases {
  1098  		t.Run(c.name, func(t *testing.T) {
  1099  			signer, ok := testSigners["rsa"].(MultiAlgorithmSigner)
  1100  			if !ok {
  1101  				t.Fatalf("rsa test signer does not implement the MultiAlgorithmSigner interface")
  1102  			}
  1103  			// The signer supports the public key algorithm which is then returned.
  1104  			_, algo, err := pickSignatureAlgorithm(signer, c.extensions)
  1105  			if err != nil {
  1106  				t.Fatalf("got %v, want no error", err)
  1107  			}
  1108  			if algo != signer.PublicKey().Type() {
  1109  				t.Fatalf("got algo %q, want %q", algo, signer.PublicKey().Type())
  1110  			}
  1111  			// Test a signer that uses a certificate algorithm as the public key
  1112  			// type.
  1113  			cert := &Certificate{
  1114  				CertType: UserCert,
  1115  				Key:      signer.PublicKey(),
  1116  			}
  1117  			cert.SignCert(rand.Reader, signer)
  1118  
  1119  			certSigner, err := NewCertSigner(cert, signer)
  1120  			if err != nil {
  1121  				t.Fatalf("error generating cert signer: %v", err)
  1122  			}
  1123  			// The signer supports the public key algorithm and the
  1124  			// public key format is a certificate type so the cerificate
  1125  			// algorithm matching the key format must be returned
  1126  			_, algo, err = pickSignatureAlgorithm(certSigner, c.extensions)
  1127  			if err != nil {
  1128  				t.Fatalf("got %v, want no error", err)
  1129  			}
  1130  			if algo != certSigner.PublicKey().Type() {
  1131  				t.Fatalf("got algo %q, want %q", algo, certSigner.PublicKey().Type())
  1132  			}
  1133  			signer, err = NewSignerWithAlgorithms(signer.(AlgorithmSigner), []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256})
  1134  			if err != nil {
  1135  				t.Fatalf("unable to create signer with algorithms: %v", err)
  1136  			}
  1137  			// The signer does not support the public key algorithm so an error
  1138  			// is returned.
  1139  			_, _, err = pickSignatureAlgorithm(signer, c.extensions)
  1140  			if err == nil {
  1141  				t.Fatal("got no error, no common public key signature algorithm error expected")
  1142  			}
  1143  		})
  1144  	}
  1145  }
  1146  
  1147  // configurablePublicKeyCallback is a public key callback that allows to
  1148  // configure the signature algorithm and format. This way we can emulate the
  1149  // behavior of buggy clients.
  1150  type configurablePublicKeyCallback struct {
  1151  	signer          AlgorithmSigner
  1152  	signatureAlgo   string
  1153  	signatureFormat string
  1154  }
  1155  
  1156  func (cb configurablePublicKeyCallback) method() string {
  1157  	return "publickey"
  1158  }
  1159  
  1160  func (cb configurablePublicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
  1161  	pub := cb.signer.PublicKey()
  1162  
  1163  	ok, err := validateKey(pub, cb.signatureAlgo, user, c)
  1164  	if err != nil {
  1165  		return authFailure, nil, err
  1166  	}
  1167  	if !ok {
  1168  		return authFailure, nil, fmt.Errorf("invalid public key")
  1169  	}
  1170  
  1171  	pubKey := pub.Marshal()
  1172  	data := buildDataSignedForAuth(session, userAuthRequestMsg{
  1173  		User:    user,
  1174  		Service: serviceSSH,
  1175  		Method:  cb.method(),
  1176  	}, cb.signatureAlgo, pubKey)
  1177  	sign, err := cb.signer.SignWithAlgorithm(rand, data, underlyingAlgo(cb.signatureFormat))
  1178  	if err != nil {
  1179  		return authFailure, nil, err
  1180  	}
  1181  
  1182  	s := Marshal(sign)
  1183  	sig := make([]byte, stringLength(len(s)))
  1184  	marshalString(sig, s)
  1185  	msg := publickeyAuthMsg{
  1186  		User:     user,
  1187  		Service:  serviceSSH,
  1188  		Method:   cb.method(),
  1189  		HasSig:   true,
  1190  		Algoname: cb.signatureAlgo,
  1191  		PubKey:   pubKey,
  1192  		Sig:      sig,
  1193  	}
  1194  	p := Marshal(&msg)
  1195  	if err := c.writePacket(p); err != nil {
  1196  		return authFailure, nil, err
  1197  	}
  1198  	var success authResult
  1199  	success, methods, err := handleAuthResponse(c)
  1200  	if err != nil {
  1201  		return authFailure, nil, err
  1202  	}
  1203  	if success == authSuccess || !contains(methods, cb.method()) {
  1204  		return success, methods, err
  1205  	}
  1206  
  1207  	return authFailure, methods, nil
  1208  }
  1209  
  1210  func TestPublicKeyAndAlgoCompatibility(t *testing.T) {
  1211  	cert := &Certificate{
  1212  		Key:         testPublicKeys["rsa"],
  1213  		ValidBefore: CertTimeInfinity,
  1214  		CertType:    UserCert,
  1215  	}
  1216  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
  1217  	certSigner, err := NewCertSigner(cert, testSigners["rsa"])
  1218  	if err != nil {
  1219  		t.Fatalf("NewCertSigner: %v", err)
  1220  	}
  1221  
  1222  	clientConfig := &ClientConfig{
  1223  		User:            "user",
  1224  		HostKeyCallback: InsecureIgnoreHostKey(),
  1225  		Auth: []AuthMethod{
  1226  			configurablePublicKeyCallback{
  1227  				signer:          certSigner.(AlgorithmSigner),
  1228  				signatureAlgo:   KeyAlgoRSASHA256,
  1229  				signatureFormat: KeyAlgoRSASHA256,
  1230  			},
  1231  		},
  1232  	}
  1233  	if err := tryAuth(t, clientConfig); err == nil {
  1234  		t.Error("cert login passed with incompatible public key type and algorithm")
  1235  	}
  1236  }
  1237  
  1238  func TestClientAuthGPGAgentCompat(t *testing.T) {
  1239  	clientConfig := &ClientConfig{
  1240  		User:            "testuser",
  1241  		HostKeyCallback: InsecureIgnoreHostKey(),
  1242  		Auth: []AuthMethod{
  1243  			// algorithm rsa-sha2-512 and signature format ssh-rsa.
  1244  			configurablePublicKeyCallback{
  1245  				signer:          testSigners["rsa"].(AlgorithmSigner),
  1246  				signatureAlgo:   KeyAlgoRSASHA512,
  1247  				signatureFormat: KeyAlgoRSA,
  1248  			},
  1249  		},
  1250  	}
  1251  	if err := tryAuth(t, clientConfig); err != nil {
  1252  		t.Fatalf("unable to dial remote side: %s", err)
  1253  	}
  1254  }
  1255  
  1256  func TestCertAuthOpenSSHCompat(t *testing.T) {
  1257  	cert := &Certificate{
  1258  		Key:         testPublicKeys["rsa"],
  1259  		ValidBefore: CertTimeInfinity,
  1260  		CertType:    UserCert,
  1261  	}
  1262  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
  1263  	certSigner, err := NewCertSigner(cert, testSigners["rsa"])
  1264  	if err != nil {
  1265  		t.Fatalf("NewCertSigner: %v", err)
  1266  	}
  1267  
  1268  	clientConfig := &ClientConfig{
  1269  		User:            "user",
  1270  		HostKeyCallback: InsecureIgnoreHostKey(),
  1271  		Auth: []AuthMethod{
  1272  			// algorithm ssh-rsa-cert-v01@openssh.com and signature format
  1273  			// rsa-sha2-256.
  1274  			configurablePublicKeyCallback{
  1275  				signer:          certSigner.(AlgorithmSigner),
  1276  				signatureAlgo:   CertAlgoRSAv01,
  1277  				signatureFormat: KeyAlgoRSASHA256,
  1278  			},
  1279  		},
  1280  	}
  1281  	if err := tryAuth(t, clientConfig); err != nil {
  1282  		t.Fatalf("unable to dial remote side: %s", err)
  1283  	}
  1284  }
  1285  

View as plain text