a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
at main 31 kB view raw
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 = defaultPubKeyAuthAlgos 247 } else { 248 for _, algo := range fullConf.PublicKeyAuthAlgorithms { 249 if !contains(SupportedAlgorithms().PublicKeyAuths, algo) && !contains(InsecureAlgorithms().PublicKeyAuths, algo) { 250 c.Close() 251 return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo) 252 } 253 } 254 } 255 256 s := &connection{ 257 sshConn: sshConn{conn: c}, 258 } 259 perms, err := s.serverHandshake(&fullConf) 260 if err != nil { 261 c.Close() 262 return nil, nil, nil, err 263 } 264 return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil 265} 266 267// signAndMarshal signs the data with the appropriate algorithm, 268// and serializes the result in SSH wire format. algo is the negotiate 269// algorithm and may be a certificate type. 270func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) { 271 sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo)) 272 if err != nil { 273 return nil, err 274 } 275 276 return Marshal(sig), nil 277} 278 279// handshake performs key exchange and user authentication. 280func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { 281 if len(config.hostKeys) == 0 { 282 return nil, errors.New("ssh: server has no host keys") 283 } 284 285 if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && 286 config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil || 287 config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) { 288 return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") 289 } 290 291 if config.ServerVersion != "" { 292 s.serverVersion = []byte(config.ServerVersion) 293 } else { 294 s.serverVersion = []byte(packageVersion) 295 } 296 var err error 297 s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) 298 if err != nil { 299 return nil, err 300 } 301 302 tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) 303 s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) 304 305 if err := s.transport.waitSession(); err != nil { 306 return nil, err 307 } 308 309 // We just did the key change, so the session ID is established. 310 s.sessionID = s.transport.getSessionID() 311 s.algorithms = s.transport.getAlgorithms() 312 313 var packet []byte 314 if packet, err = s.transport.readPacket(); err != nil { 315 return nil, err 316 } 317 318 var serviceRequest serviceRequestMsg 319 if err = Unmarshal(packet, &serviceRequest); err != nil { 320 return nil, err 321 } 322 if serviceRequest.Service != serviceUserAuth { 323 return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") 324 } 325 serviceAccept := serviceAcceptMsg{ 326 Service: serviceUserAuth, 327 } 328 if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { 329 return nil, err 330 } 331 332 perms, err := s.serverAuthenticate(config) 333 if err != nil { 334 return nil, err 335 } 336 s.mux = newMux(s.transport) 337 return perms, err 338} 339 340func checkSourceAddress(addr net.Addr, sourceAddrs string) error { 341 if addr == nil { 342 return errors.New("ssh: no address known for client, but source-address match required") 343 } 344 345 tcpAddr, ok := addr.(*net.TCPAddr) 346 if !ok { 347 return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) 348 } 349 350 for _, sourceAddr := range strings.Split(sourceAddrs, ",") { 351 if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { 352 if allowedIP.Equal(tcpAddr.IP) { 353 return nil 354 } 355 } else { 356 _, ipNet, err := net.ParseCIDR(sourceAddr) 357 if err != nil { 358 return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) 359 } 360 361 if ipNet.Contains(tcpAddr.IP) { 362 return nil 363 } 364 } 365 } 366 367 return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) 368} 369 370func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection, 371 sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) { 372 gssAPIServer := gssapiConfig.Server 373 defer gssAPIServer.DeleteSecContext() 374 var srcName string 375 for { 376 var ( 377 outToken []byte 378 needContinue bool 379 ) 380 outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token) 381 if err != nil { 382 return err, nil, nil 383 } 384 if len(outToken) != 0 { 385 if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{ 386 Token: outToken, 387 })); err != nil { 388 return nil, nil, err 389 } 390 } 391 if !needContinue { 392 break 393 } 394 packet, err := s.transport.readPacket() 395 if err != nil { 396 return nil, nil, err 397 } 398 userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} 399 if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { 400 return nil, nil, err 401 } 402 token = userAuthGSSAPITokenReq.Token 403 } 404 packet, err := s.transport.readPacket() 405 if err != nil { 406 return nil, nil, err 407 } 408 userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{} 409 if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil { 410 return nil, nil, err 411 } 412 mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method) 413 if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil { 414 return err, nil, nil 415 } 416 perms, authErr = gssapiConfig.AllowLogin(s, srcName) 417 return authErr, perms, nil 418} 419 420// isAlgoCompatible checks if the signature format is compatible with the 421// selected algorithm taking into account edge cases that occur with old 422// clients. 423func isAlgoCompatible(algo, sigFormat string) bool { 424 // Compatibility for old clients. 425 // 426 // For certificate authentication with OpenSSH 7.2-7.7 signature format can 427 // be rsa-sha2-256 or rsa-sha2-512 for the algorithm 428 // ssh-rsa-cert-v01@openssh.com. 429 // 430 // With gpg-agent < 2.2.6 the algorithm can be rsa-sha2-256 or rsa-sha2-512 431 // for signature format ssh-rsa. 432 if isRSA(algo) && isRSA(sigFormat) { 433 return true 434 } 435 // Standard case: the underlying algorithm must match the signature format. 436 return underlyingAlgo(algo) == sigFormat 437} 438 439// ServerAuthError represents server authentication errors and is 440// sometimes returned by NewServerConn. It appends any authentication 441// errors that may occur, and is returned if all of the authentication 442// methods provided by the user failed to authenticate. 443type ServerAuthError struct { 444 // Errors contains authentication errors returned by the authentication 445 // callback methods. The first entry is typically ErrNoAuth. 446 Errors []error 447} 448 449func (l ServerAuthError) Error() string { 450 var errs []string 451 for _, err := range l.Errors { 452 errs = append(errs, err.Error()) 453 } 454 return "[" + strings.Join(errs, ", ") + "]" 455} 456 457// ServerAuthCallbacks defines server-side authentication callbacks. 458type ServerAuthCallbacks struct { 459 // PasswordCallback behaves like [ServerConfig.PasswordCallback]. 460 PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) 461 462 // PublicKeyCallback behaves like [ServerConfig.PublicKeyCallback]. 463 PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) 464 465 // KeyboardInteractiveCallback behaves like [ServerConfig.KeyboardInteractiveCallback]. 466 KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) 467 468 // GSSAPIWithMICConfig behaves like [ServerConfig.GSSAPIWithMICConfig]. 469 GSSAPIWithMICConfig *GSSAPIWithMICConfig 470} 471 472// PartialSuccessError can be returned by any of the [ServerConfig] 473// authentication callbacks to indicate to the client that authentication has 474// partially succeeded, but further steps are required. 475type PartialSuccessError struct { 476 // Next defines the authentication callbacks to apply to further steps. The 477 // available methods communicated to the client are based on the non-nil 478 // ServerAuthCallbacks fields. 479 Next ServerAuthCallbacks 480} 481 482func (p *PartialSuccessError) Error() string { 483 return "ssh: authenticated with partial success" 484} 485 486// ErrNoAuth is the error value returned if no 487// authentication method has been passed yet. This happens as a normal 488// part of the authentication loop, since the client first tries 489// 'none' authentication to discover available methods. 490// It is returned in ServerAuthError.Errors from NewServerConn. 491var ErrNoAuth = errors.New("ssh: no auth passed yet") 492 493// BannerError is an error that can be returned by authentication handlers in 494// ServerConfig to send a banner message to the client. 495type BannerError struct { 496 Err error 497 Message string 498} 499 500func (b *BannerError) Unwrap() error { 501 return b.Err 502} 503 504func (b *BannerError) Error() string { 505 if b.Err == nil { 506 return b.Message 507 } 508 return b.Err.Error() 509} 510 511func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { 512 if config.PreAuthConnCallback != nil { 513 config.PreAuthConnCallback(s) 514 } 515 516 sessionID := s.transport.getSessionID() 517 var cache pubKeyCache 518 var perms *Permissions 519 520 authFailures := 0 521 noneAuthCount := 0 522 var authErrs []error 523 var calledBannerCallback bool 524 partialSuccessReturned := false 525 // Set the initial authentication callbacks from the config. They can be 526 // changed if a PartialSuccessError is returned. 527 authConfig := ServerAuthCallbacks{ 528 PasswordCallback: config.PasswordCallback, 529 PublicKeyCallback: config.PublicKeyCallback, 530 KeyboardInteractiveCallback: config.KeyboardInteractiveCallback, 531 GSSAPIWithMICConfig: config.GSSAPIWithMICConfig, 532 } 533 534userAuthLoop: 535 for { 536 if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { 537 discMsg := &disconnectMsg{ 538 Reason: 2, 539 Message: "too many authentication failures", 540 } 541 542 if err := s.transport.writePacket(Marshal(discMsg)); err != nil { 543 return nil, err 544 } 545 authErrs = append(authErrs, discMsg) 546 return nil, &ServerAuthError{Errors: authErrs} 547 } 548 549 var userAuthReq userAuthRequestMsg 550 if packet, err := s.transport.readPacket(); err != nil { 551 if err == io.EOF { 552 return nil, &ServerAuthError{Errors: authErrs} 553 } 554 return nil, err 555 } else if err = Unmarshal(packet, &userAuthReq); err != nil { 556 return nil, err 557 } 558 559 if userAuthReq.Service != serviceSSH { 560 return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) 561 } 562 563 if s.user != userAuthReq.User && partialSuccessReturned { 564 return nil, fmt.Errorf("ssh: client changed the user after a partial success authentication, previous user %q, current user %q", 565 s.user, userAuthReq.User) 566 } 567 568 s.user = userAuthReq.User 569 570 if !calledBannerCallback && config.BannerCallback != nil { 571 calledBannerCallback = true 572 if msg := config.BannerCallback(s); msg != "" { 573 if err := s.SendAuthBanner(msg); err != nil { 574 return nil, err 575 } 576 } 577 } 578 579 perms = nil 580 authErr := ErrNoAuth 581 582 switch userAuthReq.Method { 583 case "none": 584 noneAuthCount++ 585 // We don't allow none authentication after a partial success 586 // response. 587 if config.NoClientAuth && !partialSuccessReturned { 588 if config.NoClientAuthCallback != nil { 589 perms, authErr = config.NoClientAuthCallback(s) 590 } else { 591 authErr = nil 592 } 593 } 594 case "password": 595 if authConfig.PasswordCallback == nil { 596 authErr = errors.New("ssh: password auth not configured") 597 break 598 } 599 payload := userAuthReq.Payload 600 if len(payload) < 1 || payload[0] != 0 { 601 return nil, parseError(msgUserAuthRequest) 602 } 603 payload = payload[1:] 604 password, payload, ok := parseString(payload) 605 if !ok || len(payload) > 0 { 606 return nil, parseError(msgUserAuthRequest) 607 } 608 609 perms, authErr = authConfig.PasswordCallback(s, password) 610 case "keyboard-interactive": 611 if authConfig.KeyboardInteractiveCallback == nil { 612 authErr = errors.New("ssh: keyboard-interactive auth not configured") 613 break 614 } 615 616 prompter := &sshClientKeyboardInteractive{s} 617 perms, authErr = authConfig.KeyboardInteractiveCallback(s, prompter.Challenge) 618 case "publickey": 619 if authConfig.PublicKeyCallback == nil { 620 authErr = errors.New("ssh: publickey auth not configured") 621 break 622 } 623 payload := userAuthReq.Payload 624 if len(payload) < 1 { 625 return nil, parseError(msgUserAuthRequest) 626 } 627 isQuery := payload[0] == 0 628 payload = payload[1:] 629 algoBytes, payload, ok := parseString(payload) 630 if !ok { 631 return nil, parseError(msgUserAuthRequest) 632 } 633 algo := string(algoBytes) 634 if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) { 635 authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) 636 break 637 } 638 639 pubKeyData, payload, ok := parseString(payload) 640 if !ok { 641 return nil, parseError(msgUserAuthRequest) 642 } 643 644 pubKey, err := ParsePublicKey(pubKeyData) 645 if err != nil { 646 return nil, err 647 } 648 649 candidate, ok := cache.get(s.user, pubKeyData) 650 if !ok { 651 candidate.user = s.user 652 candidate.pubKeyData = pubKeyData 653 candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey) 654 _, isPartialSuccessError := candidate.result.(*PartialSuccessError) 655 656 if (candidate.result == nil || isPartialSuccessError) && 657 candidate.perms != nil && 658 candidate.perms.CriticalOptions != nil && 659 candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { 660 if err := checkSourceAddress( 661 s.RemoteAddr(), 662 candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil { 663 candidate.result = err 664 } 665 } 666 cache.add(candidate) 667 } 668 669 if isQuery { 670 // The client can query if the given public key 671 // would be okay. 672 673 if len(payload) > 0 { 674 return nil, parseError(msgUserAuthRequest) 675 } 676 _, isPartialSuccessError := candidate.result.(*PartialSuccessError) 677 if candidate.result == nil || isPartialSuccessError { 678 okMsg := userAuthPubKeyOkMsg{ 679 Algo: algo, 680 PubKey: pubKeyData, 681 } 682 if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { 683 return nil, err 684 } 685 continue userAuthLoop 686 } 687 authErr = candidate.result 688 } else { 689 sig, payload, ok := parseSignature(payload) 690 if !ok || len(payload) > 0 { 691 return nil, parseError(msgUserAuthRequest) 692 } 693 // Ensure the declared public key algo is compatible with the 694 // decoded one. This check will ensure we don't accept e.g. 695 // ssh-rsa-cert-v01@openssh.com algorithm with ssh-rsa public 696 // key type. The algorithm and public key type must be 697 // consistent: both must be certificate algorithms, or neither. 698 if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) { 699 authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q", 700 pubKey.Type(), algo) 701 break 702 } 703 // Ensure the public key algo and signature algo 704 // are supported. Compare the private key 705 // algorithm name that corresponds to algo with 706 // sig.Format. This is usually the same, but 707 // for certs, the names differ. 708 if !contains(config.PublicKeyAuthAlgorithms, sig.Format) { 709 authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) 710 break 711 } 712 if !isAlgoCompatible(algo, sig.Format) { 713 authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo) 714 break 715 } 716 717 signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData) 718 719 if err := pubKey.Verify(signedData, sig); err != nil { 720 return nil, err 721 } 722 723 authErr = candidate.result 724 perms = candidate.perms 725 } 726 case "gssapi-with-mic": 727 if authConfig.GSSAPIWithMICConfig == nil { 728 authErr = errors.New("ssh: gssapi-with-mic auth not configured") 729 break 730 } 731 gssapiConfig := authConfig.GSSAPIWithMICConfig 732 userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload) 733 if err != nil { 734 return nil, parseError(msgUserAuthRequest) 735 } 736 // OpenSSH supports Kerberos V5 mechanism only for GSS-API authentication. 737 if userAuthRequestGSSAPI.N == 0 { 738 authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported") 739 break 740 } 741 var i uint32 742 present := false 743 for i = 0; i < userAuthRequestGSSAPI.N; i++ { 744 if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) { 745 present = true 746 break 747 } 748 } 749 if !present { 750 authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism") 751 break 752 } 753 // Initial server response, see RFC 4462 section 3.3. 754 if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{ 755 SupportMech: krb5OID, 756 })); err != nil { 757 return nil, err 758 } 759 // Exchange token, see RFC 4462 section 3.4. 760 packet, err := s.transport.readPacket() 761 if err != nil { 762 return nil, err 763 } 764 userAuthGSSAPITokenReq := &userAuthGSSAPIToken{} 765 if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil { 766 return nil, err 767 } 768 authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID, 769 userAuthReq) 770 if err != nil { 771 return nil, err 772 } 773 default: 774 authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) 775 } 776 777 authErrs = append(authErrs, authErr) 778 779 if config.AuthLogCallback != nil { 780 config.AuthLogCallback(s, userAuthReq.Method, authErr) 781 } 782 783 var bannerErr *BannerError 784 if errors.As(authErr, &bannerErr) { 785 if bannerErr.Message != "" { 786 if err := s.SendAuthBanner(bannerErr.Message); err != nil { 787 return nil, err 788 } 789 } 790 } 791 792 if authErr == nil { 793 break userAuthLoop 794 } 795 796 var failureMsg userAuthFailureMsg 797 798 if partialSuccess, ok := authErr.(*PartialSuccessError); ok { 799 // After a partial success error we don't allow changing the user 800 // name and execute the NoClientAuthCallback. 801 partialSuccessReturned = true 802 803 // In case a partial success is returned, the server may send 804 // a new set of authentication methods. 805 authConfig = partialSuccess.Next 806 807 // Reset pubkey cache, as the new PublicKeyCallback might 808 // accept a different set of public keys. 809 cache = pubKeyCache{} 810 811 // Send back a partial success message to the user. 812 failureMsg.PartialSuccess = true 813 } else { 814 // Allow initial attempt of 'none' without penalty. 815 if authFailures > 0 || userAuthReq.Method != "none" || noneAuthCount != 1 { 816 authFailures++ 817 } 818 if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries { 819 // If we have hit the max attempts, don't bother sending the 820 // final SSH_MSG_USERAUTH_FAILURE message, since there are 821 // no more authentication methods which can be attempted, 822 // and this message may cause the client to re-attempt 823 // authentication while we send the disconnect message. 824 // Continue, and trigger the disconnect at the start of 825 // the loop. 826 // 827 // The SSH specification is somewhat confusing about this, 828 // RFC 4252 Section 5.1 requires each authentication failure 829 // be responded to with a respective SSH_MSG_USERAUTH_FAILURE 830 // message, but Section 4 says the server should disconnect 831 // after some number of attempts, but it isn't explicit which 832 // message should take precedence (i.e. should there be a failure 833 // message than a disconnect message, or if we are going to 834 // disconnect, should we only send that message.) 835 // 836 // Either way, OpenSSH disconnects immediately after the last 837 // failed authentication attempt, and given they are typically 838 // considered the golden implementation it seems reasonable 839 // to match that behavior. 840 continue 841 } 842 } 843 844 if authConfig.PasswordCallback != nil { 845 failureMsg.Methods = append(failureMsg.Methods, "password") 846 } 847 if authConfig.PublicKeyCallback != nil { 848 failureMsg.Methods = append(failureMsg.Methods, "publickey") 849 } 850 if authConfig.KeyboardInteractiveCallback != nil { 851 failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") 852 } 853 if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil && 854 authConfig.GSSAPIWithMICConfig.AllowLogin != nil { 855 failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic") 856 } 857 858 if len(failureMsg.Methods) == 0 { 859 return nil, errors.New("ssh: no authentication methods available") 860 } 861 862 if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { 863 return nil, err 864 } 865 } 866 867 if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { 868 return nil, err 869 } 870 return perms, nil 871} 872 873// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by 874// asking the client on the other side of a ServerConn. 875type sshClientKeyboardInteractive struct { 876 *connection 877} 878 879func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) { 880 if len(questions) != len(echos) { 881 return nil, errors.New("ssh: echos and questions must have equal length") 882 } 883 884 var prompts []byte 885 for i := range questions { 886 prompts = appendString(prompts, questions[i]) 887 prompts = appendBool(prompts, echos[i]) 888 } 889 890 if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ 891 Name: name, 892 Instruction: instruction, 893 NumPrompts: uint32(len(questions)), 894 Prompts: prompts, 895 })); err != nil { 896 return nil, err 897 } 898 899 packet, err := c.transport.readPacket() 900 if err != nil { 901 return nil, err 902 } 903 if packet[0] != msgUserAuthInfoResponse { 904 return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) 905 } 906 packet = packet[1:] 907 908 n, packet, ok := parseUint32(packet) 909 if !ok || int(n) != len(questions) { 910 return nil, parseError(msgUserAuthInfoResponse) 911 } 912 913 for i := uint32(0); i < n; i++ { 914 ans, rest, ok := parseString(packet) 915 if !ok { 916 return nil, parseError(msgUserAuthInfoResponse) 917 } 918 919 answers = append(answers, string(ans)) 920 packet = rest 921 } 922 if len(packet) != 0 { 923 return nil, errors.New("ssh: junk at end of message") 924 } 925 926 return answers, nil 927}