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