1
2
3
4
5 package ssh
6
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "io"
12 "net"
13 "strings"
14 )
15
16
17
18
19
20
21 type Permissions struct {
22
23
24
25
26
27
28
29
30
31
32
33
34 CriticalOptions map[string]string
35
36
37
38
39
40
41
42
43
44
45 Extensions map[string]string
46 }
47
48 type GSSAPIWithMICConfig struct {
49
50
51
52
53
54
55 AllowLogin func(conn ConnMetadata, srcName string) (*Permissions, error)
56
57
58
59 Server GSSAPIServer
60 }
61
62
63 type ServerConfig struct {
64
65 Config
66
67
68
69
70
71
72 PublicKeyAuthAlgorithms []string
73
74 hostKeys []Signer
75
76
77
78
79
80 NoClientAuth bool
81
82
83
84
85
86 NoClientAuthCallback func(ConnMetadata) (*Permissions, error)
87
88
89
90
91
92 MaxAuthTries int
93
94
95
96 PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
97
98
99
100
101
102
103
104
105
106 PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
107
108
109
110
111
112
113
114
115 KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
116
117
118
119 AuthLogCallback func(conn ConnMetadata, method string, err error)
120
121
122
123
124
125
126 ServerVersion string
127
128
129
130 BannerCallback func(conn ConnMetadata) string
131
132
133
134 GSSAPIWithMICConfig *GSSAPIWithMICConfig
135 }
136
137
138
139
140 func (s *ServerConfig) AddHostKey(key Signer) {
141 for i, k := range s.hostKeys {
142 if k.PublicKey().Type() == key.PublicKey().Type() {
143 s.hostKeys[i] = key
144 return
145 }
146 }
147
148 s.hostKeys = append(s.hostKeys, key)
149 }
150
151
152
153 type cachedPubKey struct {
154 user string
155 pubKeyData []byte
156 result error
157 perms *Permissions
158 }
159
160 const maxCachedPubKeys = 16
161
162
163
164
165
166 type pubKeyCache struct {
167 keys []cachedPubKey
168 }
169
170
171 func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
172 for _, k := range c.keys {
173 if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
174 return k, true
175 }
176 }
177 return cachedPubKey{}, false
178 }
179
180
181 func (c *pubKeyCache) add(candidate cachedPubKey) {
182 if len(c.keys) < maxCachedPubKeys {
183 c.keys = append(c.keys, candidate)
184 }
185 }
186
187
188
189 type ServerConn struct {
190 Conn
191
192
193
194 Permissions *Permissions
195 }
196
197
198
199
200
201
202
203
204
205 func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
206 fullConf := *config
207 fullConf.SetDefaults()
208 if fullConf.MaxAuthTries == 0 {
209 fullConf.MaxAuthTries = 6
210 }
211 if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
212 fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
213 } else {
214 for _, algo := range fullConf.PublicKeyAuthAlgorithms {
215 if !contains(supportedPubKeyAuthAlgos, algo) {
216 c.Close()
217 return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
218 }
219 }
220 }
221
222 for _, kex := range fullConf.KeyExchanges {
223 if _, ok := serverForbiddenKexAlgos[kex]; ok {
224 c.Close()
225 return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
226 }
227 }
228
229 s := &connection{
230 sshConn: sshConn{conn: c},
231 }
232 perms, err := s.serverHandshake(&fullConf)
233 if err != nil {
234 c.Close()
235 return nil, nil, nil, err
236 }
237 return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
238 }
239
240
241
242
243 func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
244 sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
245 if err != nil {
246 return nil, err
247 }
248
249 return Marshal(sig), nil
250 }
251
252
253 func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
254 if len(config.hostKeys) == 0 {
255 return nil, errors.New("ssh: server has no host keys")
256 }
257
258 if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
259 config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
260 config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
261 return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
262 }
263
264 if config.ServerVersion != "" {
265 s.serverVersion = []byte(config.ServerVersion)
266 } else {
267 s.serverVersion = []byte(packageVersion)
268 }
269 var err error
270 s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
271 if err != nil {
272 return nil, err
273 }
274
275 tr := newTransport(s.sshConn.conn, config.Rand, false )
276 s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
277
278 if err := s.transport.waitSession(); err != nil {
279 return nil, err
280 }
281
282
283 s.sessionID = s.transport.getSessionID()
284
285 var packet []byte
286 if packet, err = s.transport.readPacket(); err != nil {
287 return nil, err
288 }
289
290 var serviceRequest serviceRequestMsg
291 if err = Unmarshal(packet, &serviceRequest); err != nil {
292 return nil, err
293 }
294 if serviceRequest.Service != serviceUserAuth {
295 return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
296 }
297 serviceAccept := serviceAcceptMsg{
298 Service: serviceUserAuth,
299 }
300 if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
301 return nil, err
302 }
303
304 perms, err := s.serverAuthenticate(config)
305 if err != nil {
306 return nil, err
307 }
308 s.mux = newMux(s.transport)
309 return perms, err
310 }
311
312 func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
313 if addr == nil {
314 return errors.New("ssh: no address known for client, but source-address match required")
315 }
316
317 tcpAddr, ok := addr.(*net.TCPAddr)
318 if !ok {
319 return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
320 }
321
322 for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
323 if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
324 if allowedIP.Equal(tcpAddr.IP) {
325 return nil
326 }
327 } else {
328 _, ipNet, err := net.ParseCIDR(sourceAddr)
329 if err != nil {
330 return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
331 }
332
333 if ipNet.Contains(tcpAddr.IP) {
334 return nil
335 }
336 }
337 }
338
339 return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
340 }
341
342 func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
343 sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
344 gssAPIServer := gssapiConfig.Server
345 defer gssAPIServer.DeleteSecContext()
346 var srcName string
347 for {
348 var (
349 outToken []byte
350 needContinue bool
351 )
352 outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
353 if err != nil {
354 return err, nil, nil
355 }
356 if len(outToken) != 0 {
357 if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
358 Token: outToken,
359 })); err != nil {
360 return nil, nil, err
361 }
362 }
363 if !needContinue {
364 break
365 }
366 packet, err := s.transport.readPacket()
367 if err != nil {
368 return nil, nil, err
369 }
370 userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
371 if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
372 return nil, nil, err
373 }
374 token = userAuthGSSAPITokenReq.Token
375 }
376 packet, err := s.transport.readPacket()
377 if err != nil {
378 return nil, nil, err
379 }
380 userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
381 if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
382 return nil, nil, err
383 }
384 mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
385 if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
386 return err, nil, nil
387 }
388 perms, authErr = gssapiConfig.AllowLogin(s, srcName)
389 return authErr, perms, nil
390 }
391
392
393
394
395 func isAlgoCompatible(algo, sigFormat string) bool {
396
397
398
399
400
401
402
403
404 if isRSA(algo) && isRSA(sigFormat) {
405 return true
406 }
407
408 return underlyingAlgo(algo) == sigFormat
409 }
410
411
412
413
414
415 type ServerAuthError struct {
416
417
418 Errors []error
419 }
420
421 func (l ServerAuthError) Error() string {
422 var errs []string
423 for _, err := range l.Errors {
424 errs = append(errs, err.Error())
425 }
426 return "[" + strings.Join(errs, ", ") + "]"
427 }
428
429
430
431
432
433
434 var ErrNoAuth = errors.New("ssh: no auth passed yet")
435
436 func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
437 sessionID := s.transport.getSessionID()
438 var cache pubKeyCache
439 var perms *Permissions
440
441 authFailures := 0
442 var authErrs []error
443 var displayedBanner bool
444
445 userAuthLoop:
446 for {
447 if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
448 discMsg := &disconnectMsg{
449 Reason: 2,
450 Message: "too many authentication failures",
451 }
452
453 if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
454 return nil, err
455 }
456
457 return nil, discMsg
458 }
459
460 var userAuthReq userAuthRequestMsg
461 if packet, err := s.transport.readPacket(); err != nil {
462 if err == io.EOF {
463 return nil, &ServerAuthError{Errors: authErrs}
464 }
465 return nil, err
466 } else if err = Unmarshal(packet, &userAuthReq); err != nil {
467 return nil, err
468 }
469
470 if userAuthReq.Service != serviceSSH {
471 return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
472 }
473
474 s.user = userAuthReq.User
475
476 if !displayedBanner && config.BannerCallback != nil {
477 displayedBanner = true
478 msg := config.BannerCallback(s)
479 if msg != "" {
480 bannerMsg := &userAuthBannerMsg{
481 Message: msg,
482 }
483 if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
484 return nil, err
485 }
486 }
487 }
488
489 perms = nil
490 authErr := ErrNoAuth
491
492 switch userAuthReq.Method {
493 case "none":
494 if config.NoClientAuth {
495 if config.NoClientAuthCallback != nil {
496 perms, authErr = config.NoClientAuthCallback(s)
497 } else {
498 authErr = nil
499 }
500 }
501
502
503 if authFailures == 0 {
504 authFailures--
505 }
506 case "password":
507 if config.PasswordCallback == nil {
508 authErr = errors.New("ssh: password auth not configured")
509 break
510 }
511 payload := userAuthReq.Payload
512 if len(payload) < 1 || payload[0] != 0 {
513 return nil, parseError(msgUserAuthRequest)
514 }
515 payload = payload[1:]
516 password, payload, ok := parseString(payload)
517 if !ok || len(payload) > 0 {
518 return nil, parseError(msgUserAuthRequest)
519 }
520
521 perms, authErr = config.PasswordCallback(s, password)
522 case "keyboard-interactive":
523 if config.KeyboardInteractiveCallback == nil {
524 authErr = errors.New("ssh: keyboard-interactive auth not configured")
525 break
526 }
527
528 prompter := &sshClientKeyboardInteractive{s}
529 perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
530 case "publickey":
531 if config.PublicKeyCallback == nil {
532 authErr = errors.New("ssh: publickey auth not configured")
533 break
534 }
535 payload := userAuthReq.Payload
536 if len(payload) < 1 {
537 return nil, parseError(msgUserAuthRequest)
538 }
539 isQuery := payload[0] == 0
540 payload = payload[1:]
541 algoBytes, payload, ok := parseString(payload)
542 if !ok {
543 return nil, parseError(msgUserAuthRequest)
544 }
545 algo := string(algoBytes)
546 if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
547 authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
548 break
549 }
550
551 pubKeyData, payload, ok := parseString(payload)
552 if !ok {
553 return nil, parseError(msgUserAuthRequest)
554 }
555
556 pubKey, err := ParsePublicKey(pubKeyData)
557 if err != nil {
558 return nil, err
559 }
560
561 candidate, ok := cache.get(s.user, pubKeyData)
562 if !ok {
563 candidate.user = s.user
564 candidate.pubKeyData = pubKeyData
565 candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
566 if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
567 candidate.result = checkSourceAddress(
568 s.RemoteAddr(),
569 candidate.perms.CriticalOptions[sourceAddressCriticalOption])
570 }
571 cache.add(candidate)
572 }
573
574 if isQuery {
575
576
577
578 if len(payload) > 0 {
579 return nil, parseError(msgUserAuthRequest)
580 }
581
582 if candidate.result == nil {
583 okMsg := userAuthPubKeyOkMsg{
584 Algo: algo,
585 PubKey: pubKeyData,
586 }
587 if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
588 return nil, err
589 }
590 continue userAuthLoop
591 }
592 authErr = candidate.result
593 } else {
594 sig, payload, ok := parseSignature(payload)
595 if !ok || len(payload) > 0 {
596 return nil, parseError(msgUserAuthRequest)
597 }
598
599
600
601
602
603 if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
604 authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
605 pubKey.Type(), algo)
606 break
607 }
608
609
610
611
612
613 if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
614 authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
615 break
616 }
617 if !isAlgoCompatible(algo, sig.Format) {
618 authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
619 break
620 }
621
622 signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
623
624 if err := pubKey.Verify(signedData, sig); err != nil {
625 return nil, err
626 }
627
628 authErr = candidate.result
629 perms = candidate.perms
630 }
631 case "gssapi-with-mic":
632 if config.GSSAPIWithMICConfig == nil {
633 authErr = errors.New("ssh: gssapi-with-mic auth not configured")
634 break
635 }
636 gssapiConfig := config.GSSAPIWithMICConfig
637 userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
638 if err != nil {
639 return nil, parseError(msgUserAuthRequest)
640 }
641
642 if userAuthRequestGSSAPI.N == 0 {
643 authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
644 break
645 }
646 var i uint32
647 present := false
648 for i = 0; i < userAuthRequestGSSAPI.N; i++ {
649 if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
650 present = true
651 break
652 }
653 }
654 if !present {
655 authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
656 break
657 }
658
659 if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
660 SupportMech: krb5OID,
661 })); err != nil {
662 return nil, err
663 }
664
665 packet, err := s.transport.readPacket()
666 if err != nil {
667 return nil, err
668 }
669 userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
670 if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
671 return nil, err
672 }
673 authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
674 userAuthReq)
675 if err != nil {
676 return nil, err
677 }
678 default:
679 authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
680 }
681
682 authErrs = append(authErrs, authErr)
683
684 if config.AuthLogCallback != nil {
685 config.AuthLogCallback(s, userAuthReq.Method, authErr)
686 }
687
688 if authErr == nil {
689 break userAuthLoop
690 }
691
692 authFailures++
693 if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715 continue
716 }
717
718 var failureMsg userAuthFailureMsg
719 if config.PasswordCallback != nil {
720 failureMsg.Methods = append(failureMsg.Methods, "password")
721 }
722 if config.PublicKeyCallback != nil {
723 failureMsg.Methods = append(failureMsg.Methods, "publickey")
724 }
725 if config.KeyboardInteractiveCallback != nil {
726 failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
727 }
728 if config.GSSAPIWithMICConfig != nil && config.GSSAPIWithMICConfig.Server != nil &&
729 config.GSSAPIWithMICConfig.AllowLogin != nil {
730 failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
731 }
732
733 if len(failureMsg.Methods) == 0 {
734 return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
735 }
736
737 if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
738 return nil, err
739 }
740 }
741
742 if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
743 return nil, err
744 }
745 return perms, nil
746 }
747
748
749
750 type sshClientKeyboardInteractive struct {
751 *connection
752 }
753
754 func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
755 if len(questions) != len(echos) {
756 return nil, errors.New("ssh: echos and questions must have equal length")
757 }
758
759 var prompts []byte
760 for i := range questions {
761 prompts = appendString(prompts, questions[i])
762 prompts = appendBool(prompts, echos[i])
763 }
764
765 if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
766 Name: name,
767 Instruction: instruction,
768 NumPrompts: uint32(len(questions)),
769 Prompts: prompts,
770 })); err != nil {
771 return nil, err
772 }
773
774 packet, err := c.transport.readPacket()
775 if err != nil {
776 return nil, err
777 }
778 if packet[0] != msgUserAuthInfoResponse {
779 return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
780 }
781 packet = packet[1:]
782
783 n, packet, ok := parseUint32(packet)
784 if !ok || int(n) != len(questions) {
785 return nil, parseError(msgUserAuthInfoResponse)
786 }
787
788 for i := uint32(0); i < n; i++ {
789 ans, rest, ok := parseString(packet)
790 if !ok {
791 return nil, parseError(msgUserAuthInfoResponse)
792 }
793
794 answers = append(answers, string(ans))
795 packet = rest
796 }
797 if len(packet) != 0 {
798 return nil, errors.New("ssh: junk at end of message")
799 }
800
801 return answers, nil
802 }
803
View as plain text