main
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}