main
Raw Download raw file
  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
  5package ssh
  6
  7import (
  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.
 21type 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
 48type 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// SendAuthBanner implements [ServerPreAuthConn].
 63func (s *connection) SendAuthBanner(msg string) error {
 64	return s.transport.writePacket(Marshal(&userAuthBannerMsg{
 65		Message: msg,
 66	}))
 67}
 68
 69func (*connection) unexportedMethodForFutureProofing() {}
 70
 71// ServerPreAuthConn is the interface available on an incoming server
 72// connection before authentication has completed.
 73type ServerPreAuthConn interface {
 74	unexportedMethodForFutureProofing() // permits growing ServerPreAuthConn safely later, ala testing.TB
 75
 76	ConnMetadata
 77
 78	// SendAuthBanner sends a banner message to the client.
 79	// It returns an error once the authentication phase has ended.
 80	SendAuthBanner(string) error
 81}
 82
 83// ServerConfig holds server specific configuration data.
 84type ServerConfig struct {
 85	// Config contains configuration shared between client and server.
 86	Config
 87
 88	// PublicKeyAuthAlgorithms specifies the supported client public key
 89	// authentication algorithms. Note that this should not include certificate
 90	// types since those use the underlying algorithm. This list is sent to the
 91	// client if it supports the server-sig-algs extension. Order is irrelevant.
 92	// If unspecified then a default set of algorithms is used.
 93	PublicKeyAuthAlgorithms []string
 94
 95	hostKeys []Signer
 96
 97	// NoClientAuth is true if clients are allowed to connect without
 98	// authenticating.
 99	// To determine NoClientAuth at runtime, set NoClientAuth to true
100	// and the optional NoClientAuthCallback to a non-nil value.
101	NoClientAuth bool
102
103	// NoClientAuthCallback, if non-nil, is called when a user
104	// attempts to authenticate with auth method "none".
105	// NoClientAuth must also be set to true for this be used, or
106	// this func is unused.
107	NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
108
109	// MaxAuthTries specifies the maximum number of authentication attempts
110	// permitted per connection. If set to a negative number, the number of
111	// attempts are unlimited. If set to zero, the number of attempts are limited
112	// to 6.
113	MaxAuthTries int
114
115	// PasswordCallback, if non-nil, is called when a user
116	// attempts to authenticate using a password.
117	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
118
119	// PublicKeyCallback, if non-nil, is called when a client
120	// offers a public key for authentication. It must return a nil error
121	// if the given public key can be used to authenticate the
122	// given user. For example, see CertChecker.Authenticate. A
123	// call to this function does not guarantee that the key
124	// offered is in fact used to authenticate. To record any data
125	// depending on the public key, store it inside a
126	// Permissions.Extensions entry.
127	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
128
129	// KeyboardInteractiveCallback, if non-nil, is called when
130	// keyboard-interactive authentication is selected (RFC
131	// 4256). The client object's Challenge function should be
132	// used to query the user. The callback may offer multiple
133	// Challenge rounds. To avoid information leaks, the client
134	// should be presented a challenge even if the user is
135	// unknown.
136	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
137
138	// AuthLogCallback, if non-nil, is called to log all authentication
139	// attempts.
140	AuthLogCallback func(conn ConnMetadata, method string, err error)
141
142	// PreAuthConnCallback, if non-nil, is called upon receiving a new connection
143	// before any authentication has started. The provided ServerPreAuthConn
144	// can be used at any time before authentication is complete, including
145	// after this callback has returned.
146	PreAuthConnCallback func(ServerPreAuthConn)
147
148	// ServerVersion is the version identification string to announce in
149	// the public handshake.
150	// If empty, a reasonable default is used.
151	// Note that RFC 4253 section 4.2 requires that this string start with
152	// "SSH-2.0-".
153	ServerVersion string
154
155	// BannerCallback, if present, is called and the return string is sent to
156	// the client after key exchange completed but before authentication.
157	BannerCallback func(conn ConnMetadata) string
158
159	// GSSAPIWithMICConfig includes gssapi server and callback, which if both non-nil, is used
160	// when gssapi-with-mic authentication is selected (RFC 4462 section 3).
161	GSSAPIWithMICConfig *GSSAPIWithMICConfig
162}
163
164// AddHostKey adds a private key as a host key. If an existing host
165// key exists with the same public key format, it is replaced. Each server
166// config must have at least one host key.
167func (s *ServerConfig) AddHostKey(key Signer) {
168	for i, k := range s.hostKeys {
169		if k.PublicKey().Type() == key.PublicKey().Type() {
170			s.hostKeys[i] = key
171			return
172		}
173	}
174
175	s.hostKeys = append(s.hostKeys, key)
176}
177
178// cachedPubKey contains the results of querying whether a public key is
179// acceptable for a user. This is a FIFO cache.
180type cachedPubKey struct {
181	user       string
182	pubKeyData []byte
183	result     error
184	perms      *Permissions
185}
186
187// maxCachedPubKeys is the number of cache entries we store.
188//
189// Due to consistent misuse of the PublicKeyCallback API, we have reduced this
190// to 1, such that the only key in the cache is the most recently seen one. This
191// forces the behavior that the last call to PublicKeyCallback will always be
192// with the key that is used for authentication.
193const maxCachedPubKeys = 1
194
195// pubKeyCache caches tests for public keys.  Since SSH clients
196// will query whether a public key is acceptable before attempting to
197// authenticate with it, we end up with duplicate queries for public
198// key validity.  The cache only applies to a single ServerConn.
199type pubKeyCache struct {
200	keys []cachedPubKey
201}
202
203// get returns the result for a given user/algo/key tuple.
204func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
205	for _, k := range c.keys {
206		if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
207			return k, true
208		}
209	}
210	return cachedPubKey{}, false
211}
212
213// add adds the given tuple to the cache.
214func (c *pubKeyCache) add(candidate cachedPubKey) {
215	if len(c.keys) >= maxCachedPubKeys {
216		c.keys = c.keys[1:]
217	}
218	c.keys = append(c.keys, candidate)
219}
220
221// ServerConn is an authenticated SSH connection, as seen from the
222// server
223type ServerConn struct {
224	Conn
225
226	// If the succeeding authentication callback returned a
227	// non-nil Permissions pointer, it is stored here.
228	Permissions *Permissions
229}
230
231// NewServerConn starts a new SSH server with c as the underlying
232// transport.  It starts with a handshake and, if the handshake is
233// unsuccessful, it closes the connection and returns an error.  The
234// Request and NewChannel channels must be serviced, or the connection
235// will hang.
236//
237// The returned error may be of type *ServerAuthError for
238// authentication errors.
239func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
240	fullConf := *config
241	fullConf.SetDefaults()
242	if fullConf.MaxAuthTries == 0 {
243		fullConf.MaxAuthTries = 6
244	}
245	if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
246		fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
247	} else {
248		for _, algo := range fullConf.PublicKeyAuthAlgorithms {
249			if !contains(supportedPubKeyAuthAlgos, algo) {
250				c.Close()
251				return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
252			}
253		}
254	}
255	// Check if the config contains any unsupported key exchanges
256	for _, kex := range fullConf.KeyExchanges {
257		if _, ok := serverForbiddenKexAlgos[kex]; ok {
258			c.Close()
259			return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
260		}
261	}
262
263	s := &connection{
264		sshConn: sshConn{conn: c},
265	}
266	perms, err := s.serverHandshake(&fullConf)
267	if err != nil {
268		c.Close()
269		return nil, nil, nil, err
270	}
271	return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
272}
273
274// signAndMarshal signs the data with the appropriate algorithm,
275// and serializes the result in SSH wire format. algo is the negotiate
276// algorithm and may be a certificate type.
277func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
278	sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
279	if err != nil {
280		return nil, err
281	}
282
283	return Marshal(sig), nil
284}
285
286// handshake performs key exchange and user authentication.
287func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
288	if len(config.hostKeys) == 0 {
289		return nil, errors.New("ssh: server has no host keys")
290	}
291
292	if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
293		config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
294		config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
295		return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
296	}
297
298	if config.ServerVersion != "" {
299		s.serverVersion = []byte(config.ServerVersion)
300	} else {
301		s.serverVersion = []byte(packageVersion)
302	}
303	var err error
304	s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
305	if err != nil {
306		return nil, err
307	}
308
309	tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
310	s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
311
312	if err := s.transport.waitSession(); err != nil {
313		return nil, err
314	}
315
316	// We just did the key change, so the session ID is established.
317	s.sessionID = s.transport.getSessionID()
318
319	var packet []byte
320	if packet, err = s.transport.readPacket(); err != nil {
321		return nil, err
322	}
323
324	var serviceRequest serviceRequestMsg
325	if err = Unmarshal(packet, &serviceRequest); err != nil {
326		return nil, err
327	}
328	if serviceRequest.Service != serviceUserAuth {
329		return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
330	}
331	serviceAccept := serviceAcceptMsg{
332		Service: serviceUserAuth,
333	}
334	if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
335		return nil, err
336	}
337
338	perms, err := s.serverAuthenticate(config)
339	if err != nil {
340		return nil, err
341	}
342	s.mux = newMux(s.transport)
343	return perms, err
344}
345
346func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
347	if addr == nil {
348		return errors.New("ssh: no address known for client, but source-address match required")
349	}
350
351	tcpAddr, ok := addr.(*net.TCPAddr)
352	if !ok {
353		return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
354	}
355
356	for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
357		if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
358			if allowedIP.Equal(tcpAddr.IP) {
359				return nil
360			}
361		} else {
362			_, ipNet, err := net.ParseCIDR(sourceAddr)
363			if err != nil {
364				return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
365			}
366
367			if ipNet.Contains(tcpAddr.IP) {
368				return nil
369			}
370		}
371	}
372
373	return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
374}
375
376func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
377	sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
378	gssAPIServer := gssapiConfig.Server
379	defer gssAPIServer.DeleteSecContext()
380	var srcName string
381	for {
382		var (
383			outToken     []byte
384			needContinue bool
385		)
386		outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
387		if err != nil {
388			return err, nil, nil
389		}
390		if len(outToken) != 0 {
391			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
392				Token: outToken,
393			})); err != nil {
394				return nil, nil, err
395			}
396		}
397		if !needContinue {
398			break
399		}
400		packet, err := s.transport.readPacket()
401		if err != nil {
402			return nil, nil, err
403		}
404		userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
405		if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
406			return nil, nil, err
407		}
408		token = userAuthGSSAPITokenReq.Token
409	}
410	packet, err := s.transport.readPacket()
411	if err != nil {
412		return nil, nil, err
413	}
414	userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
415	if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
416		return nil, nil, err
417	}
418	mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
419	if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
420		return err, nil, nil
421	}
422	perms, authErr = gssapiConfig.AllowLogin(s, srcName)
423	return authErr, perms, nil
424}
425
426// isAlgoCompatible checks if the signature format is compatible with the
427// selected algorithm taking into account edge cases that occur with old
428// clients.
429func isAlgoCompatible(algo, sigFormat string) bool {
430	// Compatibility for old clients.
431	//
432	// For certificate authentication with OpenSSH 7.2-7.7 signature format can
433	// be rsa-sha2-256 or rsa-sha2-512 for the algorithm
434	// ssh-rsa-cert-v01@openssh.com.
435	//
436	// With gpg-agent < 2.2.6 the algorithm can be rsa-sha2-256 or rsa-sha2-512
437	// for signature format ssh-rsa.
438	if isRSA(algo) && isRSA(sigFormat) {
439		return true
440	}
441	// Standard case: the underlying algorithm must match the signature format.
442	return underlyingAlgo(algo) == sigFormat
443}
444
445// ServerAuthError represents server authentication errors and is
446// sometimes returned by NewServerConn. It appends any authentication
447// errors that may occur, and is returned if all of the authentication
448// methods provided by the user failed to authenticate.
449type ServerAuthError struct {
450	// Errors contains authentication errors returned by the authentication
451	// callback methods. The first entry is typically ErrNoAuth.
452	Errors []error
453}
454
455func (l ServerAuthError) Error() string {
456	var errs []string
457	for _, err := range l.Errors {
458		errs = append(errs, err.Error())
459	}
460	return "[" + strings.Join(errs, ", ") + "]"
461}
462
463// ServerAuthCallbacks defines server-side authentication callbacks.
464type ServerAuthCallbacks struct {
465	// PasswordCallback behaves like [ServerConfig.PasswordCallback].
466	PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
467
468	// PublicKeyCallback behaves like [ServerConfig.PublicKeyCallback].
469	PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
470
471	// KeyboardInteractiveCallback behaves like [ServerConfig.KeyboardInteractiveCallback].
472	KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
473
474	// GSSAPIWithMICConfig behaves like [ServerConfig.GSSAPIWithMICConfig].
475	GSSAPIWithMICConfig *GSSAPIWithMICConfig
476}
477
478// PartialSuccessError can be returned by any of the [ServerConfig]
479// authentication callbacks to indicate to the client that authentication has
480// partially succeeded, but further steps are required.
481type PartialSuccessError struct {
482	// Next defines the authentication callbacks to apply to further steps. The
483	// available methods communicated to the client are based on the non-nil
484	// ServerAuthCallbacks fields.
485	Next ServerAuthCallbacks
486}
487
488func (p *PartialSuccessError) Error() string {
489	return "ssh: authenticated with partial success"
490}
491
492// ErrNoAuth is the error value returned if no
493// authentication method has been passed yet. This happens as a normal
494// part of the authentication loop, since the client first tries
495// 'none' authentication to discover available methods.
496// It is returned in ServerAuthError.Errors from NewServerConn.
497var ErrNoAuth = errors.New("ssh: no auth passed yet")
498
499// BannerError is an error that can be returned by authentication handlers in
500// ServerConfig to send a banner message to the client.
501type BannerError struct {
502	Err     error
503	Message string
504}
505
506func (b *BannerError) Unwrap() error {
507	return b.Err
508}
509
510func (b *BannerError) Error() string {
511	if b.Err == nil {
512		return b.Message
513	}
514	return b.Err.Error()
515}
516
517func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
518	if config.PreAuthConnCallback != nil {
519		config.PreAuthConnCallback(s)
520	}
521
522	sessionID := s.transport.getSessionID()
523	var cache pubKeyCache
524	var perms *Permissions
525
526	authFailures := 0
527	noneAuthCount := 0
528	var authErrs []error
529	var calledBannerCallback bool
530	partialSuccessReturned := false
531	// Set the initial authentication callbacks from the config. They can be
532	// changed if a PartialSuccessError is returned.
533	authConfig := ServerAuthCallbacks{
534		PasswordCallback:            config.PasswordCallback,
535		PublicKeyCallback:           config.PublicKeyCallback,
536		KeyboardInteractiveCallback: config.KeyboardInteractiveCallback,
537		GSSAPIWithMICConfig:         config.GSSAPIWithMICConfig,
538	}
539
540userAuthLoop:
541	for {
542		if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
543			discMsg := &disconnectMsg{
544				Reason:  2,
545				Message: "too many authentication failures",
546			}
547
548			if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
549				return nil, err
550			}
551			authErrs = append(authErrs, discMsg)
552			return nil, &ServerAuthError{Errors: authErrs}
553		}
554
555		var userAuthReq userAuthRequestMsg
556		if packet, err := s.transport.readPacket(); err != nil {
557			if err == io.EOF {
558				return nil, &ServerAuthError{Errors: authErrs}
559			}
560			return nil, err
561		} else if err = Unmarshal(packet, &userAuthReq); err != nil {
562			return nil, err
563		}
564
565		if userAuthReq.Service != serviceSSH {
566			return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
567		}
568
569		if s.user != userAuthReq.User && partialSuccessReturned {
570			return nil, fmt.Errorf("ssh: client changed the user after a partial success authentication, previous user %q, current user %q",
571				s.user, userAuthReq.User)
572		}
573
574		s.user = userAuthReq.User
575
576		if !calledBannerCallback && config.BannerCallback != nil {
577			calledBannerCallback = true
578			if msg := config.BannerCallback(s); msg != "" {
579				if err := s.SendAuthBanner(msg); err != nil {
580					return nil, err
581				}
582			}
583		}
584
585		perms = nil
586		authErr := ErrNoAuth
587
588		switch userAuthReq.Method {
589		case "none":
590			noneAuthCount++
591			// We don't allow none authentication after a partial success
592			// response.
593			if config.NoClientAuth && !partialSuccessReturned {
594				if config.NoClientAuthCallback != nil {
595					perms, authErr = config.NoClientAuthCallback(s)
596				} else {
597					authErr = nil
598				}
599			}
600		case "password":
601			if authConfig.PasswordCallback == nil {
602				authErr = errors.New("ssh: password auth not configured")
603				break
604			}
605			payload := userAuthReq.Payload
606			if len(payload) < 1 || payload[0] != 0 {
607				return nil, parseError(msgUserAuthRequest)
608			}
609			payload = payload[1:]
610			password, payload, ok := parseString(payload)
611			if !ok || len(payload) > 0 {
612				return nil, parseError(msgUserAuthRequest)
613			}
614
615			perms, authErr = authConfig.PasswordCallback(s, password)
616		case "keyboard-interactive":
617			if authConfig.KeyboardInteractiveCallback == nil {
618				authErr = errors.New("ssh: keyboard-interactive auth not configured")
619				break
620			}
621
622			prompter := &sshClientKeyboardInteractive{s}
623			perms, authErr = authConfig.KeyboardInteractiveCallback(s, prompter.Challenge)
624		case "publickey":
625			if authConfig.PublicKeyCallback == nil {
626				authErr = errors.New("ssh: publickey auth not configured")
627				break
628			}
629			payload := userAuthReq.Payload
630			if len(payload) < 1 {
631				return nil, parseError(msgUserAuthRequest)
632			}
633			isQuery := payload[0] == 0
634			payload = payload[1:]
635			algoBytes, payload, ok := parseString(payload)
636			if !ok {
637				return nil, parseError(msgUserAuthRequest)
638			}
639			algo := string(algoBytes)
640			if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
641				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
642				break
643			}
644
645			pubKeyData, payload, ok := parseString(payload)
646			if !ok {
647				return nil, parseError(msgUserAuthRequest)
648			}
649
650			pubKey, err := ParsePublicKey(pubKeyData)
651			if err != nil {
652				return nil, err
653			}
654
655			candidate, ok := cache.get(s.user, pubKeyData)
656			if !ok {
657				candidate.user = s.user
658				candidate.pubKeyData = pubKeyData
659				candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey)
660				_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
661
662				if (candidate.result == nil || isPartialSuccessError) &&
663					candidate.perms != nil &&
664					candidate.perms.CriticalOptions != nil &&
665					candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
666					if err := checkSourceAddress(
667						s.RemoteAddr(),
668						candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil {
669						candidate.result = err
670					}
671				}
672				cache.add(candidate)
673			}
674
675			if isQuery {
676				// The client can query if the given public key
677				// would be okay.
678
679				if len(payload) > 0 {
680					return nil, parseError(msgUserAuthRequest)
681				}
682				_, isPartialSuccessError := candidate.result.(*PartialSuccessError)
683				if candidate.result == nil || isPartialSuccessError {
684					okMsg := userAuthPubKeyOkMsg{
685						Algo:   algo,
686						PubKey: pubKeyData,
687					}
688					if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
689						return nil, err
690					}
691					continue userAuthLoop
692				}
693				authErr = candidate.result
694			} else {
695				sig, payload, ok := parseSignature(payload)
696				if !ok || len(payload) > 0 {
697					return nil, parseError(msgUserAuthRequest)
698				}
699				// Ensure the declared public key algo is compatible with the
700				// decoded one. This check will ensure we don't accept e.g.
701				// ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public
702				// key type. The algorithm and public key type must be
703				// consistent: both must be certificate algorithms, or neither.
704				if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
705					authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
706						pubKey.Type(), algo)
707					break
708				}
709				// Ensure the public key algo and signature algo
710				// are supported.  Compare the private key
711				// algorithm name that corresponds to algo with
712				// sig.Format.  This is usually the same, but
713				// for certs, the names differ.
714				if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
715					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
716					break
717				}
718				if !isAlgoCompatible(algo, sig.Format) {
719					authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
720					break
721				}
722
723				signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
724
725				if err := pubKey.Verify(signedData, sig); err != nil {
726					return nil, err
727				}
728
729				authErr = candidate.result
730				perms = candidate.perms
731			}
732		case "gssapi-with-mic":
733			if authConfig.GSSAPIWithMICConfig == nil {
734				authErr = errors.New("ssh: gssapi-with-mic auth not configured")
735				break
736			}
737			gssapiConfig := authConfig.GSSAPIWithMICConfig
738			userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
739			if err != nil {
740				return nil, parseError(msgUserAuthRequest)
741			}
742			// OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication.
743			if userAuthRequestGSSAPI.N == 0 {
744				authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
745				break
746			}
747			var i uint32
748			present := false
749			for i = 0; i < userAuthRequestGSSAPI.N; i++ {
750				if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
751					present = true
752					break
753				}
754			}
755			if !present {
756				authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
757				break
758			}
759			// Initial server response, see RFC 4462 section 3.3.
760			if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
761				SupportMech: krb5OID,
762			})); err != nil {
763				return nil, err
764			}
765			// Exchange token, see RFC 4462 section 3.4.
766			packet, err := s.transport.readPacket()
767			if err != nil {
768				return nil, err
769			}
770			userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
771			if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
772				return nil, err
773			}
774			authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
775				userAuthReq)
776			if err != nil {
777				return nil, err
778			}
779		default:
780			authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
781		}
782
783		authErrs = append(authErrs, authErr)
784
785		if config.AuthLogCallback != nil {
786			config.AuthLogCallback(s, userAuthReq.Method, authErr)
787		}
788
789		var bannerErr *BannerError
790		if errors.As(authErr, &bannerErr) {
791			if bannerErr.Message != "" {
792				if err := s.SendAuthBanner(bannerErr.Message); err != nil {
793					return nil, err
794				}
795			}
796		}
797
798		if authErr == nil {
799			break userAuthLoop
800		}
801
802		var failureMsg userAuthFailureMsg
803
804		if partialSuccess, ok := authErr.(*PartialSuccessError); ok {
805			// After a partial success error we don't allow changing the user
806			// name and execute the NoClientAuthCallback.
807			partialSuccessReturned = true
808
809			// In case a partial success is returned, the server may send
810			// a new set of authentication methods.
811			authConfig = partialSuccess.Next
812
813			// Reset pubkey cache, as the new PublicKeyCallback might
814			// accept a different set of public keys.
815			cache = pubKeyCache{}
816
817			// Send back a partial success message to the user.
818			failureMsg.PartialSuccess = true
819		} else {
820			// Allow initial attempt of 'none' without penalty.
821			if authFailures > 0 || userAuthReq.Method != "none" || noneAuthCount != 1 {
822				authFailures++
823			}
824			if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
825				// If we have hit the max attempts, don't bother sending the
826				// final SSH_MSG_USERAUTH_FAILURE message, since there are
827				// no more authentication methods which can be attempted,
828				// and this message may cause the client to re-attempt
829				// authentication while we send the disconnect message.
830				// Continue, and trigger the disconnect at the start of
831				// the loop.
832				//
833				// The SSH specification is somewhat confusing about this,
834				// RFC 4252 Section 5.1 requires each authentication failure
835				// be responded to with a respective SSH_MSG_USERAUTH_FAILURE
836				// message, but Section 4 says the server should disconnect
837				// after some number of attempts, but it isn't explicit which
838				// message should take precedence (i.e. should there be a failure
839				// message than a disconnect message, or if we are going to
840				// disconnect, should we only send that message.)
841				//
842				// Either way, OpenSSH disconnects immediately after the last
843				// failed authentication attempt, and given they are typically
844				// considered the golden implementation it seems reasonable
845				// to match that behavior.
846				continue
847			}
848		}
849
850		if authConfig.PasswordCallback != nil {
851			failureMsg.Methods = append(failureMsg.Methods, "password")
852		}
853		if authConfig.PublicKeyCallback != nil {
854			failureMsg.Methods = append(failureMsg.Methods, "publickey")
855		}
856		if authConfig.KeyboardInteractiveCallback != nil {
857			failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
858		}
859		if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil &&
860			authConfig.GSSAPIWithMICConfig.AllowLogin != nil {
861			failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
862		}
863
864		if len(failureMsg.Methods) == 0 {
865			return nil, errors.New("ssh: no authentication methods available")
866		}
867
868		if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
869			return nil, err
870		}
871	}
872
873	if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
874		return nil, err
875	}
876	return perms, nil
877}
878
879// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
880// asking the client on the other side of a ServerConn.
881type sshClientKeyboardInteractive struct {
882	*connection
883}
884
885func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
886	if len(questions) != len(echos) {
887		return nil, errors.New("ssh: echos and questions must have equal length")
888	}
889
890	var prompts []byte
891	for i := range questions {
892		prompts = appendString(prompts, questions[i])
893		prompts = appendBool(prompts, echos[i])
894	}
895
896	if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
897		Name:        name,
898		Instruction: instruction,
899		NumPrompts:  uint32(len(questions)),
900		Prompts:     prompts,
901	})); err != nil {
902		return nil, err
903	}
904
905	packet, err := c.transport.readPacket()
906	if err != nil {
907		return nil, err
908	}
909	if packet[0] != msgUserAuthInfoResponse {
910		return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
911	}
912	packet = packet[1:]
913
914	n, packet, ok := parseUint32(packet)
915	if !ok || int(n) != len(questions) {
916		return nil, parseError(msgUserAuthInfoResponse)
917	}
918
919	for i := uint32(0); i < n; i++ {
920		ans, rest, ok := parseString(packet)
921		if !ok {
922			return nil, parseError(msgUserAuthInfoResponse)
923		}
924
925		answers = append(answers, string(ans))
926		packet = rest
927	}
928	if len(packet) != 0 {
929		return nil, errors.New("ssh: junk at end of message")
930	}
931
932	return answers, nil
933}