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