github.com/devops-filetransfer/sshego@v7.0.4+incompatible/_vendor/golang.org/x/crypto/ssh/server.go (about) 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 5 package ssh 6 7 import ( 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 18 // user. Permissions, except for "source-address", must be enforced in 19 // the server application layer, after successful authentication. The 20 // Permissions are passed on in ServerConn so a server implementation 21 // can honor them. 22 type Permissions struct { 23 // Critical options restrict default permissions. Common 24 // restrictions are "source-address" and "force-command". If 25 // the server cannot enforce the restriction, or does not 26 // recognize it, the user should not authenticate. 27 CriticalOptions map[string]string 28 29 // Extensions are extra functionality that the server may 30 // offer on authenticated connections. Common extensions are 31 // "permit-agent-forwarding", "permit-X11-forwarding". Lack of 32 // support for an extension does not preclude authenticating a 33 // user. 34 Extensions map[string]string 35 } 36 37 // ServerConfig holds server specific configuration data. 38 type ServerConfig struct { 39 // Config contains configuration shared between client and server. 40 Config 41 42 hostKeys []Signer 43 44 // NoClientAuth is true if clients are allowed to connect without 45 // authenticating. 46 NoClientAuth bool 47 48 // MaxAuthTries specifies the maximum number of authentication attempts 49 // permitted per connection. If set to a negative number, the number of 50 // attempts are unlimited. If set to zero, the number of attempts are limited 51 // to 6. 52 MaxAuthTries int 53 54 // PasswordCallback, if non-nil, is called when a user 55 // attempts to authenticate using a password. 56 PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) 57 58 // PublicKeyCallback, if non-nil, is called when a client attempts public 59 // key authentication. It must return true if the given public key is 60 // valid for the given user. For example, see CertChecker.Authenticate. 61 PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) 62 63 // KeyboardInteractiveCallback, if non-nil, is called when 64 // keyboard-interactive authentication is selected (RFC 65 // 4256). The client object's Challenge function should be 66 // used to query the user. The callback may offer multiple 67 // Challenge rounds. To avoid information leaks, the client 68 // should be presented a challenge even if the user is 69 // unknown. 70 KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) 71 72 // AuthLogCallback, if non-nil, is called to log all authentication 73 // attempts. 74 AuthLogCallback func(conn ConnMetadata, method string, err error) 75 76 // ServerVersion is the version identification string to announce in 77 // the public handshake. 78 // If empty, a reasonable default is used. 79 // Note that RFC 4253 section 4.2 requires that this string start with 80 // "SSH-2.0-". 81 ServerVersion string 82 } 83 84 // AddHostKey adds a private key as a host key. If an existing host 85 // key exists with the same algorithm, it is overwritten. Each server 86 // config must have at least one host key. 87 func (s *ServerConfig) AddHostKey(key Signer) { 88 for i, k := range s.hostKeys { 89 if k.PublicKey().Type() == key.PublicKey().Type() { 90 s.hostKeys[i] = key 91 return 92 } 93 } 94 95 s.hostKeys = append(s.hostKeys, key) 96 } 97 98 // cachedPubKey contains the results of querying whether a public key is 99 // acceptable for a user. 100 type cachedPubKey struct { 101 user string 102 pubKeyData []byte 103 result error 104 perms *Permissions 105 } 106 107 const maxCachedPubKeys = 16 108 109 // pubKeyCache caches tests for public keys. Since SSH clients 110 // will query whether a public key is acceptable before attempting to 111 // authenticate with it, we end up with duplicate queries for public 112 // key validity. The cache only applies to a single ServerConn. 113 type pubKeyCache struct { 114 keys []cachedPubKey 115 } 116 117 // get returns the result for a given user/algo/key tuple. 118 func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { 119 for _, k := range c.keys { 120 if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { 121 return k, true 122 } 123 } 124 return cachedPubKey{}, false 125 } 126 127 // add adds the given tuple to the cache. 128 func (c *pubKeyCache) add(candidate cachedPubKey) { 129 if len(c.keys) < maxCachedPubKeys { 130 c.keys = append(c.keys, candidate) 131 } 132 } 133 134 // ServerConn is an authenticated SSH connection, as seen from the 135 // server 136 type ServerConn struct { 137 Conn 138 139 // If the succeeding authentication callback returned a 140 // non-nil Permissions pointer, it is stored here. 141 Permissions *Permissions 142 } 143 144 // NewServerConn starts a new SSH server with c as the underlying 145 // transport. It starts with a handshake and, if the handshake is 146 // unsuccessful, it closes the connection and returns an error. The 147 // Request and NewChannel channels must be serviced, or the connection 148 // will hang. 149 func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { 150 if config.MaxAuthTries == 0 { 151 config.MaxAuthTries = 6 152 } 153 154 fullConf := *config 155 fullConf.SetDefaults() 156 s := &connection{ 157 sshConn: sshConn{conn: c}, 158 } 159 perms, err := s.serverHandshake(&fullConf) 160 if err != nil { 161 c.Close() 162 return nil, nil, nil, err 163 } 164 return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil 165 } 166 167 // signAndMarshal signs the data with the appropriate algorithm, 168 // and serializes the result in SSH wire format. 169 func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { 170 sig, err := k.Sign(rand, data) 171 if err != nil { 172 return nil, err 173 } 174 175 return Marshal(sig), nil 176 } 177 178 // handshake performs key exchange and user authentication. 179 func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { 180 if len(config.hostKeys) == 0 { 181 return nil, errors.New("ssh: server has no host keys") 182 } 183 184 if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { 185 return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") 186 } 187 188 if config.ServerVersion != "" { 189 s.serverVersion = []byte(config.ServerVersion) 190 } else { 191 s.serverVersion = []byte(packageVersion) 192 } 193 var err error 194 s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) 195 if err != nil { 196 return nil, err 197 } 198 199 tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) 200 s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) 201 202 if err := s.transport.waitSession(); err != nil { 203 return nil, err 204 } 205 206 // We just did the key change, so the session ID is established. 207 s.sessionID = s.transport.getSessionID() 208 209 var packet []byte 210 if packet, err = s.transport.readPacket(); err != nil { 211 return nil, err 212 } 213 214 var serviceRequest serviceRequestMsg 215 if err = Unmarshal(packet, &serviceRequest); err != nil { 216 return nil, err 217 } 218 if serviceRequest.Service != serviceUserAuth { 219 return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") 220 } 221 serviceAccept := serviceAcceptMsg{ 222 Service: serviceUserAuth, 223 } 224 if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { 225 return nil, err 226 } 227 228 perms, err := s.serverAuthenticate(config) 229 if err != nil { 230 return nil, err 231 } 232 s.mux = newMux(s.transport) 233 return perms, err 234 } 235 236 func isAcceptableAlgo(algo string) bool { 237 switch algo { 238 case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519, 239 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01: 240 return true 241 } 242 return false 243 } 244 245 func checkSourceAddress(addr net.Addr, sourceAddrs string) error { 246 if addr == nil { 247 return errors.New("ssh: no address known for client, but source-address match required") 248 } 249 250 tcpAddr, ok := addr.(*net.TCPAddr) 251 if !ok { 252 return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) 253 } 254 255 for _, sourceAddr := range strings.Split(sourceAddrs, ",") { 256 if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { 257 if allowedIP.Equal(tcpAddr.IP) { 258 return nil 259 } 260 } else { 261 _, ipNet, err := net.ParseCIDR(sourceAddr) 262 if err != nil { 263 return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) 264 } 265 266 if ipNet.Contains(tcpAddr.IP) { 267 return nil 268 } 269 } 270 } 271 272 return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) 273 } 274 275 func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { 276 sessionID := s.transport.getSessionID() 277 var cache pubKeyCache 278 var perms *Permissions 279 280 authFailures := 0 281 282 userAuthLoop: 283 for { 284 if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 { 285 discMsg := &disconnectMsg{ 286 Reason: 2, 287 Message: "too many authentication failures", 288 } 289 290 if err := s.transport.writePacket(Marshal(discMsg)); err != nil { 291 return nil, err 292 } 293 294 return nil, discMsg 295 } 296 297 var userAuthReq userAuthRequestMsg 298 if packet, err := s.transport.readPacket(); err != nil { 299 return nil, err 300 } else if err = Unmarshal(packet, &userAuthReq); err != nil { 301 return nil, err 302 } 303 304 if userAuthReq.Service != serviceSSH { 305 return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) 306 } 307 308 s.user = userAuthReq.User 309 perms = nil 310 authErr := errors.New("no auth passed yet") 311 312 switch userAuthReq.Method { 313 case "none": 314 if config.NoClientAuth { 315 authErr = nil 316 } 317 318 // allow initial attempt of 'none' without penalty 319 if authFailures == 0 { 320 authFailures-- 321 } 322 case "password": 323 if config.PasswordCallback == nil { 324 authErr = errors.New("ssh: password auth not configured") 325 break 326 } 327 payload := userAuthReq.Payload 328 if len(payload) < 1 || payload[0] != 0 { 329 return nil, parseError(msgUserAuthRequest) 330 } 331 payload = payload[1:] 332 password, payload, ok := parseString(payload) 333 if !ok || len(payload) > 0 { 334 return nil, parseError(msgUserAuthRequest) 335 } 336 337 perms, authErr = config.PasswordCallback(s, password) 338 case "keyboard-interactive": 339 if config.KeyboardInteractiveCallback == nil { 340 authErr = errors.New("ssh: keyboard-interactive auth not configubred") 341 break 342 } 343 344 prompter := &sshClientKeyboardInteractive{s} 345 perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) 346 case "publickey": 347 if config.PublicKeyCallback == nil { 348 authErr = errors.New("ssh: publickey auth not configured") 349 break 350 } 351 payload := userAuthReq.Payload 352 if len(payload) < 1 { 353 return nil, parseError(msgUserAuthRequest) 354 } 355 isQuery := payload[0] == 0 356 payload = payload[1:] 357 algoBytes, payload, ok := parseString(payload) 358 if !ok { 359 return nil, parseError(msgUserAuthRequest) 360 } 361 algo := string(algoBytes) 362 if !isAcceptableAlgo(algo) { 363 authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) 364 break 365 } 366 367 pubKeyData, payload, ok := parseString(payload) 368 if !ok { 369 return nil, parseError(msgUserAuthRequest) 370 } 371 372 pubKey, err := ParsePublicKey(pubKeyData) 373 if err != nil { 374 return nil, err 375 } 376 377 candidate, ok := cache.get(s.user, pubKeyData) 378 if !ok { 379 candidate.user = s.user 380 candidate.pubKeyData = pubKeyData 381 candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) 382 if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { 383 candidate.result = checkSourceAddress( 384 s.RemoteAddr(), 385 candidate.perms.CriticalOptions[sourceAddressCriticalOption]) 386 } 387 cache.add(candidate) 388 } 389 390 if isQuery { 391 // The client can query if the given public key 392 // would be okay. 393 394 if len(payload) > 0 { 395 return nil, parseError(msgUserAuthRequest) 396 } 397 398 if candidate.result == nil { 399 okMsg := userAuthPubKeyOkMsg{ 400 Algo: algo, 401 PubKey: pubKeyData, 402 } 403 if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { 404 return nil, err 405 } 406 continue userAuthLoop 407 } 408 authErr = candidate.result 409 } else { 410 sig, payload, ok := parseSignature(payload) 411 if !ok || len(payload) > 0 { 412 return nil, parseError(msgUserAuthRequest) 413 } 414 // Ensure the public key algo and signature algo 415 // are supported. Compare the private key 416 // algorithm name that corresponds to algo with 417 // sig.Format. This is usually the same, but 418 // for certs, the names differ. 419 if !isAcceptableAlgo(sig.Format) { 420 break 421 } 422 signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) 423 424 if err := pubKey.Verify(signedData, sig); err != nil { 425 return nil, err 426 } 427 428 authErr = candidate.result 429 perms = candidate.perms 430 } 431 default: 432 authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) 433 } 434 435 if config.AuthLogCallback != nil { 436 config.AuthLogCallback(s, userAuthReq.Method, authErr) 437 } 438 439 if authErr == nil { 440 break userAuthLoop 441 } 442 443 authFailures++ 444 445 var failureMsg userAuthFailureMsg 446 if config.PasswordCallback != nil { 447 failureMsg.Methods = append(failureMsg.Methods, "password") 448 } 449 if config.PublicKeyCallback != nil { 450 failureMsg.Methods = append(failureMsg.Methods, "publickey") 451 } 452 if config.KeyboardInteractiveCallback != nil { 453 failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") 454 } 455 456 if len(failureMsg.Methods) == 0 { 457 return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") 458 } 459 460 if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { 461 return nil, err 462 } 463 } 464 465 if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { 466 return nil, err 467 } 468 return perms, nil 469 } 470 471 // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by 472 // asking the client on the other side of a ServerConn. 473 type sshClientKeyboardInteractive struct { 474 *connection 475 } 476 477 func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { 478 if len(questions) != len(echos) { 479 return nil, errors.New("ssh: echos and questions must have equal length") 480 } 481 482 var prompts []byte 483 for i := range questions { 484 prompts = appendString(prompts, questions[i]) 485 prompts = appendBool(prompts, echos[i]) 486 } 487 488 if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ 489 Instruction: instruction, 490 NumPrompts: uint32(len(questions)), 491 Prompts: prompts, 492 })); err != nil { 493 return nil, err 494 } 495 496 packet, err := c.transport.readPacket() 497 if err != nil { 498 return nil, err 499 } 500 if packet[0] != msgUserAuthInfoResponse { 501 return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) 502 } 503 packet = packet[1:] 504 505 n, packet, ok := parseUint32(packet) 506 if !ok || int(n) != len(questions) { 507 return nil, parseError(msgUserAuthInfoResponse) 508 } 509 510 for i := uint32(0); i < n; i++ { 511 ans, rest, ok := parseString(packet) 512 if !ok { 513 return nil, parseError(msgUserAuthInfoResponse) 514 } 515 516 answers = append(answers, string(ans)) 517 packet = rest 518 } 519 if len(packet) != 0 { 520 return nil, errors.New("ssh: junk at end of message") 521 } 522 523 return answers, nil 524 }