github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/crypto/ssh/server.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssh
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net"
    13  	"strings"
    14  )
    15  
    16  // The Permissions type holds fine-grained permissions that are
    17  // specific to a user or a specific authentication method for a user.
    18  // The Permissions value for a successful authentication attempt is
    19  // available in ServerConn, so it can be used to pass information from
    20  // the user-authentication phase to the application layer.
    21  type Permissions struct {
    22  	// CriticalOptions indicate restrictions to the default
    23  	// permissions, and are typically used in conjunction with
    24  	// user certificates. The standard for SSH certificates
    25  	// defines "force-command" (only allow the given command to
    26  	// execute) and "source-address" (only allow connections from
    27  	// the given address). The SSH package currently only enforces
    28  	// the "source-address" critical option. It is up to server
    29  	// implementations to enforce other critical options, such as
    30  	// "force-command", by checking them after the SSH handshake
    31  	// is successful. In general, SSH servers should reject
    32  	// connections that specify critical options that are unknown
    33  	// or not supported.
    34  	CriticalOptions map[string]string
    35  
    36  	// Extensions are extra functionality that the server may
    37  	// offer on authenticated connections. Lack of support for an
    38  	// extension does not preclude authenticating a user. Common
    39  	// extensions are "permit-agent-forwarding",
    40  	// "permit-X11-forwarding". The Go SSH library currently does
    41  	// not act on any extension, and it is up to server
    42  	// implementations to honor them. Extensions can be used to
    43  	// pass data from the authentication callbacks to the server
    44  	// application layer.
    45  	Extensions map[string]string
    46  }
    47  
    48  type GSSAPIWithMICConfig struct {
    49  	// AllowLogin, must be set, is called when gssapi-with-mic
    50  	// authentication is selected (RFC 4462 section 3). The srcName is from the
    51  	// results of the GSS-API authentication. The format is username@DOMAIN.
    52  	// GSSAPI just guarantees to the server who the user is, but not if they can log in, and with what permissions.
    53  	// This callback is called after the user identity is established with GSSAPI to decide if the user can login with
    54  	// which permissions. If the user is allowed to login, it should return a nil error.
    55  	AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
    56  
    57  	// Server must be set. It's the implementation
    58  	// of the GSSAPIServer interface. See GSSAPIServer interface for details.
    59  	Server GSSAPIServer
    60  }
    61  
    62  // ServerConfig holds server specific configuration data.
    63  type ServerConfig struct {
    64  	// Config contains configuration shared between client and server.
    65  	Config
    66  
    67  	hostKeys []Signer
    68  
    69  	// NoClientAuth is true if clients are allowed to connect without
    70  	// authenticating.
    71  	NoClientAuth bool
    72  
    73  	// MaxAuthTries specifies the maximum number of authentication attempts
    74  	// permitted per connection. If set to a negative number, the number of
    75  	// attempts are unlimited. If set to zero, the number of attempts are limited
    76  	// to 6.
    77  	MaxAuthTries int
    78  
    79  	// PasswordCallback, if non-nil, is called when a user
    80  	// attempts to authenticate using a password.
    81  	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
    82  
    83  	// PublicKeyCallback, if non-nil, is called when a client
    84  	// offers a public key for authentication. It must return a nil error
    85  	// if the given public key can be used to authenticate the
    86  	// given user. For example, see CertChecker.Authenticate. A
    87  	// call to this function does not guarantee that the key
    88  	// offered is in fact used to authenticate. To record any data
    89  	// depending on the public key, store it inside a
    90  	// Permissions.Extensions entry.
    91  	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
    92  
    93  	// KeyboardInteractiveCallback, if non-nil, is called when
    94  	// keyboard-interactive authentication is selected (RFC
    95  	// 4256). The client object's Challenge function should be
    96  	// used to query the user. The callback may offer multiple
    97  	// Challenge rounds. To avoid information leaks, the client
    98  	// should be presented a challenge even if the user is
    99  	// unknown.
   100  	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
   101  
   102  	// AuthLogCallback, if non-nil, is called to log all authentication
   103  	// attempts.
   104  	AuthLogCallback func(conn ConnMetadata, method string, err error)
   105  
   106  	// ServerVersion is the version identification string to announce in
   107  	// the public handshake.
   108  	// If empty, a reasonable default is used.
   109  	// Note that RFC 4253 section 4.2 requires that this string start with
   110  	// "SSH-2.0-".
   111  	ServerVersion string
   112  
   113  	// BannerCallback, if present, is called and the return string is sent to
   114  	// the client after key exchange completed but before authentication.
   115  	BannerCallback func(conn ConnMetadata) string
   116  
   117  	// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
   118  	// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
   119  	GSSAPIWithMICConfig *GSSAPIWithMICConfig
   120  }
   121  
   122  // AddHostKey adds a private key as a host key. If an existing host
   123  // key exists with the same algorithm, it is overwritten. Each server
   124  // config must have at least one host key.
   125  func (s *ServerConfig) AddHostKey(key Signer) {
   126  	for i, k := range s.hostKeys {
   127  		if k.PublicKey().Type() == key.PublicKey().Type() {
   128  			s.hostKeys[i] = key
   129  			return
   130  		}
   131  	}
   132  
   133  	s.hostKeys = append(s.hostKeys, key)
   134  }
   135  
   136  // cachedPubKey contains the results of querying whether a public key is
   137  // acceptable for a user.
   138  type cachedPubKey struct {
   139  	user       string
   140  	pubKeyData []byte
   141  	result     error
   142  	perms      *Permissions
   143  }
   144  
   145  const maxCachedPubKeys = 16
   146  
   147  // pubKeyCache caches tests for public keys.  Since SSH clients
   148  // will query whether a public key is acceptable before attempting to
   149  // authenticate with it, we end up with duplicate queries for public
   150  // key validity.  The cache only applies to a single ServerConn.
   151  type pubKeyCache struct {
   152  	keys []cachedPubKey
   153  }
   154  
   155  // get returns the result for a given user/algo/key tuple.
   156  func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
   157  	for _, k := range c.keys {
   158  		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
   159  			return k, true
   160  		}
   161  	}
   162  	return cachedPubKey{}, false
   163  }
   164  
   165  // add adds the given tuple to the cache.
   166  func (c *pubKeyCache) add(candidate cachedPubKey) {
   167  	if len(c.keys) < maxCachedPubKeys {
   168  		c.keys = append(c.keys, candidate)
   169  	}
   170  }
   171  
   172  // ServerConn is an authenticated SSH connection, as seen from the
   173  // server
   174  type ServerConn struct {
   175  	Conn
   176  
   177  	// If the succeeding authentication callback returned a
   178  	// non-nil Permissions pointer, it is stored here.
   179  	Permissions *Permissions
   180  }
   181  
   182  // NewServerConn starts a new SSH server with c as the underlying
   183  // transport.  It starts with a handshake and, if the handshake is
   184  // unsuccessful, it closes the connection and returns an error.  The
   185  // Request and NewChannel channels must be serviced, or the connection
   186  // will hang.
   187  //
   188  // The returned error may be of type *ServerAuthError for
   189  // authentication errors.
   190  func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
   191  	fullConf := *config
   192  	fullConf.SetDefaults()
   193  	if fullConf.MaxAuthTries == 0 {
   194  		fullConf.MaxAuthTries = 6
   195  	}
   196  	// Check if the config contains any unsupported key exchanges
   197  	for _, kex := range fullConf.KeyExchanges {
   198  		if _, ok := serverForbiddenKexAlgos[kex]; ok {
   199  			return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
   200  		}
   201  	}
   202  
   203  	s := &connection{
   204  		sshConn: sshConn{conn: c},
   205  	}
   206  	perms, err := s.serverHandshake(&fullConf)
   207  	if err != nil {
   208  		c.Close()
   209  		return nil, nil, nil, err
   210  	}
   211  	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
   212  }
   213  
   214  // signAndMarshal signs the data with the appropriate algorithm,
   215  // and serializes the result in SSH wire format.
   216  func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
   217  	sig, err := k.Sign(rand, data)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  
   222  	return Marshal(sig), nil
   223  }
   224  
   225  // handshake performs key exchange and user authentication.
   226  func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
   227  	if len(config.hostKeys) == 0 {
   228  		return nil, errors.New("ssh: server has no host keys")
   229  	}
   230  
   231  	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
   232  		config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
   233  		config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
   234  		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
   235  	}
   236  
   237  	if config.ServerVersion != "" {
   238  		s.serverVersion = []byte(config.ServerVersion)
   239  	} else {
   240  		s.serverVersion = []byte(packageVersion)
   241  	}
   242  	var err error
   243  	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  
   248  	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
   249  	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
   250  
   251  	if err := s.transport.waitSession(); err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	// We just did the key change, so the session ID is established.
   256  	s.sessionID = s.transport.getSessionID()
   257  
   258  	var packet []byte
   259  	if packet, err = s.transport.readPacket(); err != nil {
   260  		return nil, err
   261  	}
   262  
   263  	var serviceRequest serviceRequestMsg
   264  	if err = Unmarshal(packet, &serviceRequest); err != nil {
   265  		return nil, err
   266  	}
   267  	if serviceRequest.Service != serviceUserAuth {
   268  		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
   269  	}
   270  	serviceAccept := serviceAcceptMsg{
   271  		Service: serviceUserAuth,
   272  	}
   273  	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
   274  		return nil, err
   275  	}
   276  
   277  	perms, err := s.serverAuthenticate(config)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	s.mux = newMux(s.transport)
   282  	return perms, err
   283  }
   284  
   285  func isAcceptableAlgo(algo string) bool {
   286  	switch algo {
   287  	case SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519,
   288  		CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
   289  		return true
   290  	}
   291  	return false
   292  }
   293  
   294  func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
   295  	if addr == nil {
   296  		return errors.New("ssh: no address known for client, but source-address match required")
   297  	}
   298  
   299  	tcpAddr, ok := addr.(*net.TCPAddr)
   300  	if !ok {
   301  		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
   302  	}
   303  
   304  	for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
   305  		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
   306  			if allowedIP.Equal(tcpAddr.IP) {
   307  				return nil
   308  			}
   309  		} else {
   310  			_, ipNet, err := net.ParseCIDR(sourceAddr)
   311  			if err != nil {
   312  				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
   313  			}
   314  
   315  			if ipNet.Contains(tcpAddr.IP) {
   316  				return nil
   317  			}
   318  		}
   319  	}
   320  
   321  	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
   322  }
   323  
   324  func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, firstToken []byte, s *connection,
   325  	sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
   326  	gssAPIServer := gssapiConfig.Server
   327  	defer gssAPIServer.DeleteSecContext()
   328  	var srcName string
   329  	for {
   330  		var (
   331  			outToken     []byte
   332  			needContinue bool
   333  		)
   334  		outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(firstToken)
   335  		if err != nil {
   336  			return err, nil, nil
   337  		}
   338  		if len(outToken) != 0 {
   339  			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
   340  				Token: outToken,
   341  			})); err != nil {
   342  				return nil, nil, err
   343  			}
   344  		}
   345  		if !needContinue {
   346  			break
   347  		}
   348  		packet, err := s.transport.readPacket()
   349  		if err != nil {
   350  			return nil, nil, err
   351  		}
   352  		userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
   353  		if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
   354  			return nil, nil, err
   355  		}
   356  	}
   357  	packet, err := s.transport.readPacket()
   358  	if err != nil {
   359  		return nil, nil, err
   360  	}
   361  	userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
   362  	if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
   363  		return nil, nil, err
   364  	}
   365  	mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
   366  	if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
   367  		return err, nil, nil
   368  	}
   369  	perms, authErr = gssapiConfig.AllowLogin(s, srcName)
   370  	return authErr, perms, nil
   371  }
   372  
   373  // ServerAuthError represents server authentication errors and is
   374  // sometimes returned by NewServerConn. It appends any authentication
   375  // errors that may occur, and is returned if all of the authentication
   376  // methods provided by the user failed to authenticate.
   377  type ServerAuthError struct {
   378  	// Errors contains authentication errors returned by the authentication
   379  	// callback methods. The first entry is typically ErrNoAuth.
   380  	Errors []error
   381  }
   382  
   383  func (l ServerAuthError) Error() string {
   384  	var errs []string
   385  	for _, err := range l.Errors {
   386  		errs = append(errs, err.Error())
   387  	}
   388  	return "[" + strings.Join(errs, ", ") + "]"
   389  }
   390  
   391  // ErrNoAuth is the error value returned if no
   392  // authentication method has been passed yet. This happens as a normal
   393  // part of the authentication loop, since the client first tries
   394  // 'none' authentication to discover available methods.
   395  // It is returned in ServerAuthError.Errors from NewServerConn.
   396  var ErrNoAuth = errors.New("ssh: no auth passed yet")
   397  
   398  func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
   399  	sessionID := s.transport.getSessionID()
   400  	var cache pubKeyCache
   401  	var perms *Permissions
   402  
   403  	authFailures := 0
   404  	var authErrs []error
   405  	var displayedBanner bool
   406  
   407  userAuthLoop:
   408  	for {
   409  		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
   410  			discMsg := &disconnectMsg{
   411  				Reason:  2,
   412  				Message: "too many authentication failures",
   413  			}
   414  
   415  			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
   416  				return nil, err
   417  			}
   418  
   419  			return nil, discMsg
   420  		}
   421  
   422  		var userAuthReq userAuthRequestMsg
   423  		if packet, err := s.transport.readPacket(); err != nil {
   424  			if err == io.EOF {
   425  				return nil, &ServerAuthError{Errors: authErrs}
   426  			}
   427  			return nil, err
   428  		} else if err = Unmarshal(packet, &userAuthReq); err != nil {
   429  			return nil, err
   430  		}
   431  
   432  		if userAuthReq.Service != serviceSSH {
   433  			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
   434  		}
   435  
   436  		s.user = userAuthReq.User
   437  
   438  		if !displayedBanner && config.BannerCallback != nil {
   439  			displayedBanner = true
   440  			msg := config.BannerCallback(s)
   441  			if msg != "" {
   442  				bannerMsg := &userAuthBannerMsg{
   443  					Message: msg,
   444  				}
   445  				if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
   446  					return nil, err
   447  				}
   448  			}
   449  		}
   450  
   451  		perms = nil
   452  		authErr := ErrNoAuth
   453  
   454  		switch userAuthReq.Method {
   455  		case "none":
   456  			if config.NoClientAuth {
   457  				authErr = nil
   458  			}
   459  
   460  			// allow initial attempt of 'none' without penalty
   461  			if authFailures == 0 {
   462  				authFailures--
   463  			}
   464  		case "password":
   465  			if config.PasswordCallback == nil {
   466  				authErr = errors.New("ssh: password auth not configured")
   467  				break
   468  			}
   469  			payload := userAuthReq.Payload
   470  			if len(payload) < 1 || payload[0] != 0 {
   471  				return nil, parseError(msgUserAuthRequest)
   472  			}
   473  			payload = payload[1:]
   474  			password, payload, ok := parseString(payload)
   475  			if !ok || len(payload) > 0 {
   476  				return nil, parseError(msgUserAuthRequest)
   477  			}
   478  
   479  			perms, authErr = config.PasswordCallback(s, password)
   480  		case "keyboard-interactive":
   481  			if config.KeyboardInteractiveCallback == nil {
   482  				authErr = errors.New("ssh: keyboard-interactive auth not configured")
   483  				break
   484  			}
   485  
   486  			prompter := &sshClientKeyboardInteractive{s}
   487  			perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
   488  		case "publickey":
   489  			if config.PublicKeyCallback == nil {
   490  				authErr = errors.New("ssh: publickey auth not configured")
   491  				break
   492  			}
   493  			payload := userAuthReq.Payload
   494  			if len(payload) < 1 {
   495  				return nil, parseError(msgUserAuthRequest)
   496  			}
   497  			isQuery := payload[0] == 0
   498  			payload = payload[1:]
   499  			algoBytes, payload, ok := parseString(payload)
   500  			if !ok {
   501  				return nil, parseError(msgUserAuthRequest)
   502  			}
   503  			algo := string(algoBytes)
   504  			if !isAcceptableAlgo(algo) {
   505  				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
   506  				break
   507  			}
   508  
   509  			pubKeyData, payload, ok := parseString(payload)
   510  			if !ok {
   511  				return nil, parseError(msgUserAuthRequest)
   512  			}
   513  
   514  			pubKey, err := ParsePublicKey(pubKeyData)
   515  			if err != nil {
   516  				return nil, err
   517  			}
   518  
   519  			candidate, ok := cache.get(s.user, pubKeyData)
   520  			if !ok {
   521  				candidate.user = s.user
   522  				candidate.pubKeyData = pubKeyData
   523  				candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
   524  				if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
   525  					candidate.result = checkSourceAddress(
   526  						s.RemoteAddr(),
   527  						candidate.perms.CriticalOptions[sourceAddressCriticalOption])
   528  				}
   529  				cache.add(candidate)
   530  			}
   531  
   532  			if isQuery {
   533  				// The client can query if the given public key
   534  				// would be okay.
   535  
   536  				if len(payload) > 0 {
   537  					return nil, parseError(msgUserAuthRequest)
   538  				}
   539  
   540  				if candidate.result == nil {
   541  					okMsg := userAuthPubKeyOkMsg{
   542  						Algo:   algo,
   543  						PubKey: pubKeyData,
   544  					}
   545  					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
   546  						return nil, err
   547  					}
   548  					continue userAuthLoop
   549  				}
   550  				authErr = candidate.result
   551  			} else {
   552  				sig, payload, ok := parseSignature(payload)
   553  				if !ok || len(payload) > 0 {
   554  					return nil, parseError(msgUserAuthRequest)
   555  				}
   556  				// Ensure the public key algo and signature algo
   557  				// are supported.  Compare the private key
   558  				// algorithm name that corresponds to algo with
   559  				// sig.Format.  This is usually the same, but
   560  				// for certs, the names differ.
   561  				if !isAcceptableAlgo(sig.Format) {
   562  					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
   563  					break
   564  				}
   565  				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData)
   566  
   567  				if err := pubKey.Verify(signedData, sig); err != nil {
   568  					return nil, err
   569  				}
   570  
   571  				authErr = candidate.result
   572  				perms = candidate.perms
   573  			}
   574  		case "gssapi-with-mic":
   575  			if config.GSSAPIWithMICConfig == nil {
   576  				authErr = errors.New("ssh: gssapi-with-mic auth not configured")
   577  				break
   578  			}
   579  			gssapiConfig := config.GSSAPIWithMICConfig
   580  			userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
   581  			if err != nil {
   582  				return nil, parseError(msgUserAuthRequest)
   583  			}
   584  			// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
   585  			if userAuthRequestGSSAPI.N == 0 {
   586  				authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
   587  				break
   588  			}
   589  			var i uint32
   590  			present := false
   591  			for i = 0; i < userAuthRequestGSSAPI.N; i++ {
   592  				if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
   593  					present = true
   594  					break
   595  				}
   596  			}
   597  			if !present {
   598  				authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
   599  				break
   600  			}
   601  			// Initial server response, see RFC 4462 section 3.3.
   602  			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
   603  				SupportMech: krb5OID,
   604  			})); err != nil {
   605  				return nil, err
   606  			}
   607  			// Exchange token, see RFC 4462 section 3.4.
   608  			packet, err := s.transport.readPacket()
   609  			if err != nil {
   610  				return nil, err
   611  			}
   612  			userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
   613  			if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
   614  				return nil, err
   615  			}
   616  			authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
   617  				userAuthReq)
   618  			if err != nil {
   619  				return nil, err
   620  			}
   621  		default:
   622  			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
   623  		}
   624  
   625  		authErrs = append(authErrs, authErr)
   626  
   627  		if config.AuthLogCallback != nil {
   628  			config.AuthLogCallback(s, userAuthReq.Method, authErr)
   629  		}
   630  
   631  		if authErr == nil {
   632  			break userAuthLoop
   633  		}
   634  
   635  		authFailures++
   636  
   637  		var failureMsg userAuthFailureMsg
   638  		if config.PasswordCallback != nil {
   639  			failureMsg.Methods = append(failureMsg.Methods, "password")
   640  		}
   641  		if config.PublicKeyCallback != nil {
   642  			failureMsg.Methods = append(failureMsg.Methods, "publickey")
   643  		}
   644  		if config.KeyboardInteractiveCallback != nil {
   645  			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
   646  		}
   647  		if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
   648  			config.GSSAPIWithMICConfig.AllowLogin != nil {
   649  			failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
   650  		}
   651  
   652  		if len(failureMsg.Methods) == 0 {
   653  			return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
   654  		}
   655  
   656  		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
   657  			return nil, err
   658  		}
   659  	}
   660  
   661  	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
   662  		return nil, err
   663  	}
   664  	return perms, nil
   665  }
   666  
   667  // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
   668  // asking the client on the other side of a ServerConn.
   669  type sshClientKeyboardInteractive struct {
   670  	*connection
   671  }
   672  
   673  func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
   674  	if len(questions) != len(echos) {
   675  		return nil, errors.New("ssh: echos and questions must have equal length")
   676  	}
   677  
   678  	var prompts []byte
   679  	for i := range questions {
   680  		prompts = appendString(prompts, questions[i])
   681  		prompts = appendBool(prompts, echos[i])
   682  	}
   683  
   684  	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
   685  		Instruction: instruction,
   686  		NumPrompts:  uint32(len(questions)),
   687  		Prompts:     prompts,
   688  	})); err != nil {
   689  		return nil, err
   690  	}
   691  
   692  	packet, err := c.transport.readPacket()
   693  	if err != nil {
   694  		return nil, err
   695  	}
   696  	if packet[0] != msgUserAuthInfoResponse {
   697  		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
   698  	}
   699  	packet = packet[1:]
   700  
   701  	n, packet, ok := parseUint32(packet)
   702  	if !ok || int(n) != len(questions) {
   703  		return nil, parseError(msgUserAuthInfoResponse)
   704  	}
   705  
   706  	for i := uint32(0); i < n; i++ {
   707  		ans, rest, ok := parseString(packet)
   708  		if !ok {
   709  			return nil, parseError(msgUserAuthInfoResponse)
   710  		}
   711  
   712  		answers = append(answers, string(ans))
   713  		packet = rest
   714  	}
   715  	if len(packet) != 0 {
   716  		return nil, errors.New("ssh: junk at end of message")
   717  	}
   718  
   719  	return answers, nil
   720  }