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}