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