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
161
162
163
164
165
166 const maxCachedPubKeys = 1
167
168
169
170
171
172 type pubKeyCache struct {
173 keys []cachedPubKey
174 }
175
176
177 func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
178 for _, k := range c.keys {
179 if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
180 return k, true
181 }
182 }
183 return cachedPubKey{}, false
184 }
185
186
187 func (c *pubKeyCache) add(candidate cachedPubKey) {
188 if len(c.keys) >= maxCachedPubKeys {
189 c.keys = c.keys[1:]
190 }
191 c.keys = append(c.keys, candidate)
192 }
193
194
195
196 type ServerConn struct {
197 Conn
198
199
200
201 Permissions *Permissions
202 }
203
204
205
206
207
208
209
210
211
212 func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
213 fullConf := *config
214 fullConf.SetDefaults()
215 if fullConf.MaxAuthTries == 0 {
216 fullConf.MaxAuthTries = 6
217 }
218 if len(fullConf.PublicKeyAuthAlgorithms) == 0 {
219 fullConf.PublicKeyAuthAlgorithms = supportedPubKeyAuthAlgos
220 } else {
221 for _, algo := range fullConf.PublicKeyAuthAlgorithms {
222 if !contains(supportedPubKeyAuthAlgos, algo) {
223 c.Close()
224 return nil, nil, nil, fmt.Errorf("ssh: unsupported public key authentication algorithm %s", algo)
225 }
226 }
227 }
228
229 for _, kex := range fullConf.KeyExchanges {
230 if _, ok := serverForbiddenKexAlgos[kex]; ok {
231 c.Close()
232 return nil, nil, nil, fmt.Errorf("ssh: unsupported key exchange %s for server", kex)
233 }
234 }
235
236 s := &connection{
237 sshConn: sshConn{conn: c},
238 }
239 perms, err := s.serverHandshake(&fullConf)
240 if err != nil {
241 c.Close()
242 return nil, nil, nil, err
243 }
244 return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
245 }
246
247
248
249
250 func signAndMarshal(k AlgorithmSigner, rand io.Reader, data []byte, algo string) ([]byte, error) {
251 sig, err := k.SignWithAlgorithm(rand, data, underlyingAlgo(algo))
252 if err != nil {
253 return nil, err
254 }
255
256 return Marshal(sig), nil
257 }
258
259
260 func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
261 if len(config.hostKeys) == 0 {
262 return nil, errors.New("ssh: server has no host keys")
263 }
264
265 if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil &&
266 config.KeyboardInteractiveCallback == nil && (config.GSSAPIWithMICConfig == nil ||
267 config.GSSAPIWithMICConfig.AllowLogin == nil || config.GSSAPIWithMICConfig.Server == nil) {
268 return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
269 }
270
271 if config.ServerVersion != "" {
272 s.serverVersion = []byte(config.ServerVersion)
273 } else {
274 s.serverVersion = []byte(packageVersion)
275 }
276 var err error
277 s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
278 if err != nil {
279 return nil, err
280 }
281
282 tr := newTransport(s.sshConn.conn, config.Rand, false )
283 s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
284
285 if err := s.transport.waitSession(); err != nil {
286 return nil, err
287 }
288
289
290 s.sessionID = s.transport.getSessionID()
291
292 var packet []byte
293 if packet, err = s.transport.readPacket(); err != nil {
294 return nil, err
295 }
296
297 var serviceRequest serviceRequestMsg
298 if err = Unmarshal(packet, &serviceRequest); err != nil {
299 return nil, err
300 }
301 if serviceRequest.Service != serviceUserAuth {
302 return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
303 }
304 serviceAccept := serviceAcceptMsg{
305 Service: serviceUserAuth,
306 }
307 if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
308 return nil, err
309 }
310
311 perms, err := s.serverAuthenticate(config)
312 if err != nil {
313 return nil, err
314 }
315 s.mux = newMux(s.transport)
316 return perms, err
317 }
318
319 func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
320 if addr == nil {
321 return errors.New("ssh: no address known for client, but source-address match required")
322 }
323
324 tcpAddr, ok := addr.(*net.TCPAddr)
325 if !ok {
326 return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
327 }
328
329 for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
330 if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
331 if allowedIP.Equal(tcpAddr.IP) {
332 return nil
333 }
334 } else {
335 _, ipNet, err := net.ParseCIDR(sourceAddr)
336 if err != nil {
337 return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
338 }
339
340 if ipNet.Contains(tcpAddr.IP) {
341 return nil
342 }
343 }
344 }
345
346 return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
347 }
348
349 func gssExchangeToken(gssapiConfig *GSSAPIWithMICConfig, token []byte, s *connection,
350 sessionID []byte, userAuthReq userAuthRequestMsg) (authErr error, perms *Permissions, err error) {
351 gssAPIServer := gssapiConfig.Server
352 defer gssAPIServer.DeleteSecContext()
353 var srcName string
354 for {
355 var (
356 outToken []byte
357 needContinue bool
358 )
359 outToken, srcName, needContinue, err = gssAPIServer.AcceptSecContext(token)
360 if err != nil {
361 return err, nil, nil
362 }
363 if len(outToken) != 0 {
364 if err := s.transport.writePacket(Marshal(&userAuthGSSAPIToken{
365 Token: outToken,
366 })); err != nil {
367 return nil, nil, err
368 }
369 }
370 if !needContinue {
371 break
372 }
373 packet, err := s.transport.readPacket()
374 if err != nil {
375 return nil, nil, err
376 }
377 userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
378 if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
379 return nil, nil, err
380 }
381 token = userAuthGSSAPITokenReq.Token
382 }
383 packet, err := s.transport.readPacket()
384 if err != nil {
385 return nil, nil, err
386 }
387 userAuthGSSAPIMICReq := &userAuthGSSAPIMIC{}
388 if err := Unmarshal(packet, userAuthGSSAPIMICReq); err != nil {
389 return nil, nil, err
390 }
391 mic := buildMIC(string(sessionID), userAuthReq.User, userAuthReq.Service, userAuthReq.Method)
392 if err := gssAPIServer.VerifyMIC(mic, userAuthGSSAPIMICReq.MIC); err != nil {
393 return err, nil, nil
394 }
395 perms, authErr = gssapiConfig.AllowLogin(s, srcName)
396 return authErr, perms, nil
397 }
398
399
400
401
402 func isAlgoCompatible(algo, sigFormat string) bool {
403
404
405
406
407
408
409
410
411 if isRSA(algo) && isRSA(sigFormat) {
412 return true
413 }
414
415 return underlyingAlgo(algo) == sigFormat
416 }
417
418
419
420
421
422 type ServerAuthError struct {
423
424
425 Errors []error
426 }
427
428 func (l ServerAuthError) Error() string {
429 var errs []string
430 for _, err := range l.Errors {
431 errs = append(errs, err.Error())
432 }
433 return "[" + strings.Join(errs, ", ") + "]"
434 }
435
436
437 type ServerAuthCallbacks struct {
438
439 PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
440
441
442 PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
443
444
445 KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
446
447
448 GSSAPIWithMICConfig *GSSAPIWithMICConfig
449 }
450
451
452
453
454 type PartialSuccessError struct {
455
456
457
458 Next ServerAuthCallbacks
459 }
460
461 func (p *PartialSuccessError) Error() string {
462 return "ssh: authenticated with partial success"
463 }
464
465
466
467
468
469
470 var ErrNoAuth = errors.New("ssh: no auth passed yet")
471
472
473
474 type BannerError struct {
475 Err error
476 Message string
477 }
478
479 func (b *BannerError) Unwrap() error {
480 return b.Err
481 }
482
483 func (b *BannerError) Error() string {
484 if b.Err == nil {
485 return b.Message
486 }
487 return b.Err.Error()
488 }
489
490 func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
491 sessionID := s.transport.getSessionID()
492 var cache pubKeyCache
493 var perms *Permissions
494
495 authFailures := 0
496 noneAuthCount := 0
497 var authErrs []error
498 var displayedBanner bool
499 partialSuccessReturned := false
500
501
502 authConfig := ServerAuthCallbacks{
503 PasswordCallback: config.PasswordCallback,
504 PublicKeyCallback: config.PublicKeyCallback,
505 KeyboardInteractiveCallback: config.KeyboardInteractiveCallback,
506 GSSAPIWithMICConfig: config.GSSAPIWithMICConfig,
507 }
508
509 userAuthLoop:
510 for {
511 if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
512 discMsg := &disconnectMsg{
513 Reason: 2,
514 Message: "too many authentication failures",
515 }
516
517 if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
518 return nil, err
519 }
520 authErrs = append(authErrs, discMsg)
521 return nil, &ServerAuthError{Errors: authErrs}
522 }
523
524 var userAuthReq userAuthRequestMsg
525 if packet, err := s.transport.readPacket(); err != nil {
526 if err == io.EOF {
527 return nil, &ServerAuthError{Errors: authErrs}
528 }
529 return nil, err
530 } else if err = Unmarshal(packet, &userAuthReq); err != nil {
531 return nil, err
532 }
533
534 if userAuthReq.Service != serviceSSH {
535 return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
536 }
537
538 if s.user != userAuthReq.User && partialSuccessReturned {
539 return nil, fmt.Errorf("ssh: client changed the user after a partial success authentication, previous user %q, current user %q",
540 s.user, userAuthReq.User)
541 }
542
543 s.user = userAuthReq.User
544
545 if !displayedBanner && config.BannerCallback != nil {
546 displayedBanner = true
547 msg := config.BannerCallback(s)
548 if msg != "" {
549 bannerMsg := &userAuthBannerMsg{
550 Message: msg,
551 }
552 if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
553 return nil, err
554 }
555 }
556 }
557
558 perms = nil
559 authErr := ErrNoAuth
560
561 switch userAuthReq.Method {
562 case "none":
563 noneAuthCount++
564
565
566 if config.NoClientAuth && !partialSuccessReturned {
567 if config.NoClientAuthCallback != nil {
568 perms, authErr = config.NoClientAuthCallback(s)
569 } else {
570 authErr = nil
571 }
572 }
573 case "password":
574 if authConfig.PasswordCallback == nil {
575 authErr = errors.New("ssh: password auth not configured")
576 break
577 }
578 payload := userAuthReq.Payload
579 if len(payload) < 1 || payload[0] != 0 {
580 return nil, parseError(msgUserAuthRequest)
581 }
582 payload = payload[1:]
583 password, payload, ok := parseString(payload)
584 if !ok || len(payload) > 0 {
585 return nil, parseError(msgUserAuthRequest)
586 }
587
588 perms, authErr = authConfig.PasswordCallback(s, password)
589 case "keyboard-interactive":
590 if authConfig.KeyboardInteractiveCallback == nil {
591 authErr = errors.New("ssh: keyboard-interactive auth not configured")
592 break
593 }
594
595 prompter := &sshClientKeyboardInteractive{s}
596 perms, authErr = authConfig.KeyboardInteractiveCallback(s, prompter.Challenge)
597 case "publickey":
598 if authConfig.PublicKeyCallback == nil {
599 authErr = errors.New("ssh: publickey auth not configured")
600 break
601 }
602 payload := userAuthReq.Payload
603 if len(payload) < 1 {
604 return nil, parseError(msgUserAuthRequest)
605 }
606 isQuery := payload[0] == 0
607 payload = payload[1:]
608 algoBytes, payload, ok := parseString(payload)
609 if !ok {
610 return nil, parseError(msgUserAuthRequest)
611 }
612 algo := string(algoBytes)
613 if !contains(config.PublicKeyAuthAlgorithms, underlyingAlgo(algo)) {
614 authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
615 break
616 }
617
618 pubKeyData, payload, ok := parseString(payload)
619 if !ok {
620 return nil, parseError(msgUserAuthRequest)
621 }
622
623 pubKey, err := ParsePublicKey(pubKeyData)
624 if err != nil {
625 return nil, err
626 }
627
628 candidate, ok := cache.get(s.user, pubKeyData)
629 if !ok {
630 candidate.user = s.user
631 candidate.pubKeyData = pubKeyData
632 candidate.perms, candidate.result = authConfig.PublicKeyCallback(s, pubKey)
633 _, isPartialSuccessError := candidate.result.(*PartialSuccessError)
634
635 if (candidate.result == nil || isPartialSuccessError) &&
636 candidate.perms != nil &&
637 candidate.perms.CriticalOptions != nil &&
638 candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
639 if err := checkSourceAddress(
640 s.RemoteAddr(),
641 candidate.perms.CriticalOptions[sourceAddressCriticalOption]); err != nil {
642 candidate.result = err
643 }
644 }
645 cache.add(candidate)
646 }
647
648 if isQuery {
649
650
651
652 if len(payload) > 0 {
653 return nil, parseError(msgUserAuthRequest)
654 }
655 _, isPartialSuccessError := candidate.result.(*PartialSuccessError)
656 if candidate.result == nil || isPartialSuccessError {
657 okMsg := userAuthPubKeyOkMsg{
658 Algo: algo,
659 PubKey: pubKeyData,
660 }
661 if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
662 return nil, err
663 }
664 continue userAuthLoop
665 }
666 authErr = candidate.result
667 } else {
668 sig, payload, ok := parseSignature(payload)
669 if !ok || len(payload) > 0 {
670 return nil, parseError(msgUserAuthRequest)
671 }
672
673
674
675
676
677 if !contains(algorithmsForKeyFormat(pubKey.Type()), algo) {
678 authErr = fmt.Errorf("ssh: public key type %q not compatible with selected algorithm %q",
679 pubKey.Type(), algo)
680 break
681 }
682
683
684
685
686
687 if !contains(config.PublicKeyAuthAlgorithms, sig.Format) {
688 authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
689 break
690 }
691 if !isAlgoCompatible(algo, sig.Format) {
692 authErr = fmt.Errorf("ssh: signature %q not compatible with selected algorithm %q", sig.Format, algo)
693 break
694 }
695
696 signedData := buildDataSignedForAuth(sessionID, userAuthReq, algo, pubKeyData)
697
698 if err := pubKey.Verify(signedData, sig); err != nil {
699 return nil, err
700 }
701
702 authErr = candidate.result
703 perms = candidate.perms
704 }
705 case "gssapi-with-mic":
706 if authConfig.GSSAPIWithMICConfig == nil {
707 authErr = errors.New("ssh: gssapi-with-mic auth not configured")
708 break
709 }
710 gssapiConfig := authConfig.GSSAPIWithMICConfig
711 userAuthRequestGSSAPI, err := parseGSSAPIPayload(userAuthReq.Payload)
712 if err != nil {
713 return nil, parseError(msgUserAuthRequest)
714 }
715
716 if userAuthRequestGSSAPI.N == 0 {
717 authErr = fmt.Errorf("ssh: Mechanism negotiation is not supported")
718 break
719 }
720 var i uint32
721 present := false
722 for i = 0; i < userAuthRequestGSSAPI.N; i++ {
723 if userAuthRequestGSSAPI.OIDS[i].Equal(krb5Mesh) {
724 present = true
725 break
726 }
727 }
728 if !present {
729 authErr = fmt.Errorf("ssh: GSSAPI authentication must use the Kerberos V5 mechanism")
730 break
731 }
732
733 if err := s.transport.writePacket(Marshal(&userAuthGSSAPIResponse{
734 SupportMech: krb5OID,
735 })); err != nil {
736 return nil, err
737 }
738
739 packet, err := s.transport.readPacket()
740 if err != nil {
741 return nil, err
742 }
743 userAuthGSSAPITokenReq := &userAuthGSSAPIToken{}
744 if err := Unmarshal(packet, userAuthGSSAPITokenReq); err != nil {
745 return nil, err
746 }
747 authErr, perms, err = gssExchangeToken(gssapiConfig, userAuthGSSAPITokenReq.Token, s, sessionID,
748 userAuthReq)
749 if err != nil {
750 return nil, err
751 }
752 default:
753 authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
754 }
755
756 authErrs = append(authErrs, authErr)
757
758 if config.AuthLogCallback != nil {
759 config.AuthLogCallback(s, userAuthReq.Method, authErr)
760 }
761
762 var bannerErr *BannerError
763 if errors.As(authErr, &bannerErr) {
764 if bannerErr.Message != "" {
765 bannerMsg := &userAuthBannerMsg{
766 Message: bannerErr.Message,
767 }
768 if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
769 return nil, err
770 }
771 }
772 }
773
774 if authErr == nil {
775 break userAuthLoop
776 }
777
778 var failureMsg userAuthFailureMsg
779
780 if partialSuccess, ok := authErr.(*PartialSuccessError); ok {
781
782
783 partialSuccessReturned = true
784
785
786
787 authConfig = partialSuccess.Next
788
789
790
791 cache = pubKeyCache{}
792
793
794 failureMsg.PartialSuccess = true
795 } else {
796
797 if authFailures > 0 || userAuthReq.Method != "none" || noneAuthCount != 1 {
798 authFailures++
799 }
800 if config.MaxAuthTries > 0 && authFailures >= config.MaxAuthTries {
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822 continue
823 }
824 }
825
826 if authConfig.PasswordCallback != nil {
827 failureMsg.Methods = append(failureMsg.Methods, "password")
828 }
829 if authConfig.PublicKeyCallback != nil {
830 failureMsg.Methods = append(failureMsg.Methods, "publickey")
831 }
832 if authConfig.KeyboardInteractiveCallback != nil {
833 failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
834 }
835 if authConfig.GSSAPIWithMICConfig != nil && authConfig.GSSAPIWithMICConfig.Server != nil &&
836 authConfig.GSSAPIWithMICConfig.AllowLogin != nil {
837 failureMsg.Methods = append(failureMsg.Methods, "gssapi-with-mic")
838 }
839
840 if len(failureMsg.Methods) == 0 {
841 return nil, errors.New("ssh: no authentication methods available")
842 }
843
844 if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil {
845 return nil, err
846 }
847 }
848
849 if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
850 return nil, err
851 }
852 return perms, nil
853 }
854
855
856
857 type sshClientKeyboardInteractive struct {
858 *connection
859 }
860
861 func (c *sshClientKeyboardInteractive) Challenge(name, instruction string, questions []string, echos []bool) (answers []string, err error) {
862 if len(questions) != len(echos) {
863 return nil, errors.New("ssh: echos and questions must have equal length")
864 }
865
866 var prompts []byte
867 for i := range questions {
868 prompts = appendString(prompts, questions[i])
869 prompts = appendBool(prompts, echos[i])
870 }
871
872 if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
873 Name: name,
874 Instruction: instruction,
875 NumPrompts: uint32(len(questions)),
876 Prompts: prompts,
877 })); err != nil {
878 return nil, err
879 }
880
881 packet, err := c.transport.readPacket()
882 if err != nil {
883 return nil, err
884 }
885 if packet[0] != msgUserAuthInfoResponse {
886 return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
887 }
888 packet = packet[1:]
889
890 n, packet, ok := parseUint32(packet)
891 if !ok || int(n) != len(questions) {
892 return nil, parseError(msgUserAuthInfoResponse)
893 }
894
895 for i := uint32(0); i < n; i++ {
896 ans, rest, ok := parseString(packet)
897 if !ok {
898 return nil, parseError(msgUserAuthInfoResponse)
899 }
900
901 answers = append(answers, string(ans))
902 packet = rest
903 }
904 if len(packet) != 0 {
905 return nil, errors.New("ssh: junk at end of message")
906 }
907
908 return answers, nil
909 }
910
View as plain text