1
2
3
4
5 package ssh
6
7 import (
8 "bytes"
9 "crypto/rand"
10 "errors"
11 "fmt"
12 "io"
13 "log"
14 "net"
15 "os"
16 "runtime"
17 "strings"
18 "testing"
19 )
20
21 type keyboardInteractive map[string]string
22
23 func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
24 var answers []string
25 for _, q := range questions {
26 answers = append(answers, cr[q])
27 }
28 return answers, nil
29 }
30
31
32 var clientPassword = "tiger"
33
34
35
36 func tryAuth(t *testing.T, config *ClientConfig) error {
37 err, _ := tryAuthBothSides(t, config, nil)
38 return err
39 }
40
41
42
43 func tryAuthWithGSSAPIWithMICConfig(t *testing.T, clientConfig *ClientConfig, gssAPIWithMICConfig *GSSAPIWithMICConfig) error {
44 err, _ := tryAuthBothSides(t, clientConfig, gssAPIWithMICConfig)
45 return err
46 }
47
48
49 func tryAuthBothSides(t *testing.T, config *ClientConfig, gssAPIWithMICConfig *GSSAPIWithMICConfig) (clientError error, serverAuthErrors []error) {
50 c1, c2, err := netPipe()
51 if err != nil {
52 t.Fatalf("netPipe: %v", err)
53 }
54 defer c1.Close()
55 defer c2.Close()
56
57 certChecker := CertChecker{
58 IsUserAuthority: func(k PublicKey) bool {
59 return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
60 },
61 UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
62 if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
63 return nil, nil
64 }
65
66 return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
67 },
68 IsRevoked: func(c *Certificate) bool {
69 return c.Serial == 666
70 },
71 }
72 serverConfig := &ServerConfig{
73 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
74 if conn.User() == "testuser" && string(pass) == clientPassword {
75 return nil, nil
76 }
77 return nil, errors.New("password auth failed")
78 },
79 PublicKeyCallback: certChecker.Authenticate,
80 KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
81 ans, err := challenge("user",
82 "instruction",
83 []string{"question1", "question2"},
84 []bool{true, true})
85 if err != nil {
86 return nil, err
87 }
88 ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
89 if ok {
90 challenge("user", "motd", nil, nil)
91 return nil, nil
92 }
93 return nil, errors.New("keyboard-interactive failed")
94 },
95 GSSAPIWithMICConfig: gssAPIWithMICConfig,
96 }
97 serverConfig.AddHostKey(testSigners["rsa"])
98
99 serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) {
100 serverAuthErrors = append(serverAuthErrors, err)
101 }
102
103 go newServer(c1, serverConfig)
104 _, _, _, err = NewClientConn(c2, "", config)
105 return err, serverAuthErrors
106 }
107
108 type loggingAlgorithmSigner struct {
109 used []string
110 AlgorithmSigner
111 }
112
113 func (l *loggingAlgorithmSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
114 l.used = append(l.used, "[Sign]")
115 return l.AlgorithmSigner.Sign(rand, data)
116 }
117
118 func (l *loggingAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
119 l.used = append(l.used, algorithm)
120 return l.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
121 }
122
123 func TestClientAuthPublicKey(t *testing.T) {
124 signer := &loggingAlgorithmSigner{AlgorithmSigner: testSigners["rsa"].(AlgorithmSigner)}
125 config := &ClientConfig{
126 User: "testuser",
127 Auth: []AuthMethod{
128 PublicKeys(signer),
129 },
130 HostKeyCallback: InsecureIgnoreHostKey(),
131 }
132 if err := tryAuth(t, config); err != nil {
133 t.Fatalf("unable to dial remote side: %s", err)
134 }
135 if len(signer.used) != 1 || signer.used[0] != KeyAlgoRSASHA256 {
136 t.Errorf("unexpected Sign/SignWithAlgorithm calls: %q", signer.used)
137 }
138 }
139
140
141 func TestClientAuthNoSHA2(t *testing.T) {
142 config := &ClientConfig{
143 User: "testuser",
144 Auth: []AuthMethod{
145 PublicKeys(&legacyRSASigner{testSigners["rsa"]}),
146 },
147 HostKeyCallback: InsecureIgnoreHostKey(),
148 }
149 if err := tryAuth(t, config); err != nil {
150 t.Fatalf("unable to dial remote side: %s", err)
151 }
152 }
153
154
155
156
157 func TestClientAuthThirdKey(t *testing.T) {
158 config := &ClientConfig{
159 User: "testuser",
160 Auth: []AuthMethod{
161 PublicKeys(testSigners["rsa-openssh-format"],
162 testSigners["rsa-openssh-format"], testSigners["rsa"]),
163 },
164 HostKeyCallback: InsecureIgnoreHostKey(),
165 }
166 if err := tryAuth(t, config); err != nil {
167 t.Fatalf("unable to dial remote side: %s", err)
168 }
169 }
170
171 func TestAuthMethodPassword(t *testing.T) {
172 config := &ClientConfig{
173 User: "testuser",
174 Auth: []AuthMethod{
175 Password(clientPassword),
176 },
177 HostKeyCallback: InsecureIgnoreHostKey(),
178 }
179
180 if err := tryAuth(t, config); err != nil {
181 t.Fatalf("unable to dial remote side: %s", err)
182 }
183 }
184
185 func TestAuthMethodFallback(t *testing.T) {
186 var passwordCalled bool
187 config := &ClientConfig{
188 User: "testuser",
189 Auth: []AuthMethod{
190 PublicKeys(testSigners["rsa"]),
191 PasswordCallback(
192 func() (string, error) {
193 passwordCalled = true
194 return "WRONG", nil
195 }),
196 },
197 HostKeyCallback: InsecureIgnoreHostKey(),
198 }
199
200 if err := tryAuth(t, config); err != nil {
201 t.Fatalf("unable to dial remote side: %s", err)
202 }
203
204 if passwordCalled {
205 t.Errorf("password auth tried before public-key auth.")
206 }
207 }
208
209 func TestAuthMethodWrongPassword(t *testing.T) {
210 config := &ClientConfig{
211 User: "testuser",
212 Auth: []AuthMethod{
213 Password("wrong"),
214 PublicKeys(testSigners["rsa"]),
215 },
216 HostKeyCallback: InsecureIgnoreHostKey(),
217 }
218
219 if err := tryAuth(t, config); err != nil {
220 t.Fatalf("unable to dial remote side: %s", err)
221 }
222 }
223
224 func TestAuthMethodKeyboardInteractive(t *testing.T) {
225 answers := keyboardInteractive(map[string]string{
226 "question1": "answer1",
227 "question2": "answer2",
228 })
229 config := &ClientConfig{
230 User: "testuser",
231 Auth: []AuthMethod{
232 KeyboardInteractive(answers.Challenge),
233 },
234 HostKeyCallback: InsecureIgnoreHostKey(),
235 }
236
237 if err := tryAuth(t, config); err != nil {
238 t.Fatalf("unable to dial remote side: %s", err)
239 }
240 }
241
242 func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
243 answers := keyboardInteractive(map[string]string{
244 "question1": "answer1",
245 "question2": "WRONG",
246 })
247 config := &ClientConfig{
248 User: "testuser",
249 Auth: []AuthMethod{
250 KeyboardInteractive(answers.Challenge),
251 },
252 }
253
254 if err := tryAuth(t, config); err == nil {
255 t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
256 }
257 }
258
259
260 func TestAuthMethodInvalidPublicKey(t *testing.T) {
261 config := &ClientConfig{
262 User: "testuser",
263 Auth: []AuthMethod{
264 PublicKeys(testSigners["dsa"]),
265 },
266 }
267
268 if err := tryAuth(t, config); err == nil {
269 t.Fatalf("dsa private key should not have authenticated with rsa public key")
270 }
271 }
272
273
274 func TestAuthMethodRSAandDSA(t *testing.T) {
275 config := &ClientConfig{
276 User: "testuser",
277 Auth: []AuthMethod{
278 PublicKeys(testSigners["dsa"], testSigners["rsa"]),
279 },
280 HostKeyCallback: InsecureIgnoreHostKey(),
281 }
282 if err := tryAuth(t, config); err != nil {
283 t.Fatalf("client could not authenticate with rsa key: %v", err)
284 }
285 }
286
287 type invalidAlgSigner struct {
288 Signer
289 }
290
291 func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
292 sig, err := s.Signer.Sign(rand, data)
293 if sig != nil {
294 sig.Format = "invalid"
295 }
296 return sig, err
297 }
298
299 func TestMethodInvalidAlgorithm(t *testing.T) {
300 config := &ClientConfig{
301 User: "testuser",
302 Auth: []AuthMethod{
303 PublicKeys(&invalidAlgSigner{testSigners["rsa"]}),
304 },
305 HostKeyCallback: InsecureIgnoreHostKey(),
306 }
307
308 err, serverErrors := tryAuthBothSides(t, config, nil)
309 if err == nil {
310 t.Fatalf("login succeeded")
311 }
312
313 found := false
314 want := "algorithm \"invalid\""
315
316 var errStrings []string
317 for _, err := range serverErrors {
318 found = found || (err != nil && strings.Contains(err.Error(), want))
319 errStrings = append(errStrings, err.Error())
320 }
321 if !found {
322 t.Errorf("server got error %q, want substring %q", errStrings, want)
323 }
324 }
325
326 func TestClientHMAC(t *testing.T) {
327 for _, mac := range supportedMACs {
328 config := &ClientConfig{
329 User: "testuser",
330 Auth: []AuthMethod{
331 PublicKeys(testSigners["rsa"]),
332 },
333 Config: Config{
334 MACs: []string{mac},
335 },
336 HostKeyCallback: InsecureIgnoreHostKey(),
337 }
338 if err := tryAuth(t, config); err != nil {
339 t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
340 }
341 }
342 }
343
344
345 func TestClientUnsupportedCipher(t *testing.T) {
346 config := &ClientConfig{
347 User: "testuser",
348 Auth: []AuthMethod{
349 PublicKeys(),
350 },
351 Config: Config{
352 Ciphers: []string{"aes128-cbc"},
353 },
354 }
355 if err := tryAuth(t, config); err == nil {
356 t.Errorf("expected no ciphers in common")
357 }
358 }
359
360 func TestClientUnsupportedKex(t *testing.T) {
361 if os.Getenv("GO_BUILDER_NAME") != "" {
362 t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
363 }
364 config := &ClientConfig{
365 User: "testuser",
366 Auth: []AuthMethod{
367 PublicKeys(),
368 },
369 Config: Config{
370 KeyExchanges: []string{"non-existent-kex"},
371 },
372 HostKeyCallback: InsecureIgnoreHostKey(),
373 }
374 if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
375 t.Errorf("got %v, expected 'common algorithm'", err)
376 }
377 }
378
379 func TestClientLoginCert(t *testing.T) {
380 cert := &Certificate{
381 Key: testPublicKeys["rsa"],
382 ValidBefore: CertTimeInfinity,
383 CertType: UserCert,
384 }
385 cert.SignCert(rand.Reader, testSigners["ecdsa"])
386 certSigner, err := NewCertSigner(cert, testSigners["rsa"])
387 if err != nil {
388 t.Fatalf("NewCertSigner: %v", err)
389 }
390
391 clientConfig := &ClientConfig{
392 User: "user",
393 HostKeyCallback: InsecureIgnoreHostKey(),
394 }
395 clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
396
397
398 if err := tryAuth(t, clientConfig); err != nil {
399 t.Errorf("cert login failed: %v", err)
400 }
401
402
403 cert.Signature.Blob[0]++
404 if err := tryAuth(t, clientConfig); err == nil {
405 t.Errorf("cert login passed with corrupted sig")
406 }
407
408
409 cert.Serial = 666
410 cert.SignCert(rand.Reader, testSigners["ecdsa"])
411 if err := tryAuth(t, clientConfig); err == nil {
412 t.Errorf("revoked cert login succeeded")
413 }
414 cert.Serial = 1
415
416
417 cert.SignCert(rand.Reader, testSigners["dsa"])
418 if err := tryAuth(t, clientConfig); err == nil {
419 t.Errorf("cert login passed with non-authoritative key")
420 }
421
422
423 cert.CertType = HostCert
424 cert.SignCert(rand.Reader, testSigners["ecdsa"])
425 if err := tryAuth(t, clientConfig); err == nil {
426 t.Errorf("cert login passed with wrong type")
427 }
428 cert.CertType = UserCert
429
430
431 cert.ValidPrincipals = []string{"user"}
432 cert.SignCert(rand.Reader, testSigners["ecdsa"])
433 if err := tryAuth(t, clientConfig); err != nil {
434 t.Errorf("cert login failed: %v", err)
435 }
436
437
438 cert.ValidPrincipals = []string{"fred"}
439 cert.SignCert(rand.Reader, testSigners["ecdsa"])
440 if err := tryAuth(t, clientConfig); err == nil {
441 t.Errorf("cert login passed with wrong principal")
442 }
443 cert.ValidPrincipals = nil
444
445
446 cert.CriticalOptions = map[string]string{"root-access": "yes"}
447 cert.SignCert(rand.Reader, testSigners["ecdsa"])
448 if err := tryAuth(t, clientConfig); err == nil {
449 t.Errorf("cert login passed with unrecognized critical option")
450 }
451
452
453 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
454 cert.SignCert(rand.Reader, testSigners["ecdsa"])
455 if err := tryAuth(t, clientConfig); err != nil {
456 t.Errorf("cert login with source-address failed: %v", err)
457 }
458
459
460 cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
461 cert.SignCert(rand.Reader, testSigners["ecdsa"])
462 if err := tryAuth(t, clientConfig); err == nil {
463 t.Errorf("cert login with source-address succeeded")
464 }
465 }
466
467 func testPermissionsPassing(withPermissions bool, t *testing.T) {
468 serverConfig := &ServerConfig{
469 PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
470 if conn.User() == "nopermissions" {
471 return nil, nil
472 }
473 return &Permissions{}, nil
474 },
475 }
476 serverConfig.AddHostKey(testSigners["rsa"])
477
478 clientConfig := &ClientConfig{
479 Auth: []AuthMethod{
480 PublicKeys(testSigners["rsa"]),
481 },
482 HostKeyCallback: InsecureIgnoreHostKey(),
483 }
484 if withPermissions {
485 clientConfig.User = "permissions"
486 } else {
487 clientConfig.User = "nopermissions"
488 }
489
490 c1, c2, err := netPipe()
491 if err != nil {
492 t.Fatalf("netPipe: %v", err)
493 }
494 defer c1.Close()
495 defer c2.Close()
496
497 go NewClientConn(c2, "", clientConfig)
498 serverConn, err := newServer(c1, serverConfig)
499 if err != nil {
500 t.Fatal(err)
501 }
502 if p := serverConn.Permissions; (p != nil) != withPermissions {
503 t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
504 }
505 }
506
507 func TestPermissionsPassing(t *testing.T) {
508 testPermissionsPassing(true, t)
509 }
510
511 func TestNoPermissionsPassing(t *testing.T) {
512 testPermissionsPassing(false, t)
513 }
514
515 func TestRetryableAuth(t *testing.T) {
516 n := 0
517 passwords := []string{"WRONG1", "WRONG2"}
518
519 config := &ClientConfig{
520 User: "testuser",
521 Auth: []AuthMethod{
522 RetryableAuthMethod(PasswordCallback(func() (string, error) {
523 p := passwords[n]
524 n++
525 return p, nil
526 }), 2),
527 PublicKeys(testSigners["rsa"]),
528 },
529 HostKeyCallback: InsecureIgnoreHostKey(),
530 }
531
532 if err := tryAuth(t, config); err != nil {
533 t.Fatalf("unable to dial remote side: %s", err)
534 }
535 if n != 2 {
536 t.Fatalf("Did not try all passwords")
537 }
538 }
539
540 func ExampleRetryableAuthMethod() {
541 user := "testuser"
542 NumberOfPrompts := 3
543
544
545
546 Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
547 return []string{"answer1", "answer2"}, nil
548 }
549
550 config := &ClientConfig{
551 HostKeyCallback: InsecureIgnoreHostKey(),
552 User: user,
553 Auth: []AuthMethod{
554 RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
555 },
556 }
557
558 host := "mysshserver"
559 netConn, err := net.Dial("tcp", host)
560 if err != nil {
561 log.Fatal(err)
562 }
563
564 sshConn, _, _, err := NewClientConn(netConn, host, config)
565 if err != nil {
566 log.Fatal(err)
567 }
568 _ = sshConn
569 }
570
571
572 func TestClientAuthNone(t *testing.T) {
573 user := "testuser"
574 serverConfig := &ServerConfig{
575 NoClientAuth: true,
576 }
577 serverConfig.AddHostKey(testSigners["rsa"])
578
579 clientConfig := &ClientConfig{
580 User: user,
581 HostKeyCallback: InsecureIgnoreHostKey(),
582 }
583
584 c1, c2, err := netPipe()
585 if err != nil {
586 t.Fatalf("netPipe: %v", err)
587 }
588 defer c1.Close()
589 defer c2.Close()
590
591 go NewClientConn(c2, "", clientConfig)
592 serverConn, err := newServer(c1, serverConfig)
593 if err != nil {
594 t.Fatalf("newServer: %v", err)
595 }
596 if serverConn.User() != user {
597 t.Fatalf("server: got %q, want %q", serverConn.User(), user)
598 }
599 }
600
601
602 func TestClientAuthMaxAuthTries(t *testing.T) {
603 user := "testuser"
604
605 serverConfig := &ServerConfig{
606 MaxAuthTries: 2,
607 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
608 if conn.User() == "testuser" && string(pass) == "right" {
609 return nil, nil
610 }
611 return nil, errors.New("password auth failed")
612 },
613 }
614 serverConfig.AddHostKey(testSigners["rsa"])
615
616 expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
617 Reason: 2,
618 Message: "too many authentication failures",
619 })
620
621 for tries := 2; tries < 4; tries++ {
622 n := tries
623 clientConfig := &ClientConfig{
624 User: user,
625 Auth: []AuthMethod{
626 RetryableAuthMethod(PasswordCallback(func() (string, error) {
627 n--
628 if n == 0 {
629 return "right", nil
630 }
631 return "wrong", nil
632 }), tries),
633 },
634 HostKeyCallback: InsecureIgnoreHostKey(),
635 }
636
637 c1, c2, err := netPipe()
638 if err != nil {
639 t.Fatalf("netPipe: %v", err)
640 }
641 defer c1.Close()
642 defer c2.Close()
643
644 go newServer(c1, serverConfig)
645 _, _, _, err = NewClientConn(c2, "", clientConfig)
646 if tries > 2 {
647 if err == nil {
648 t.Fatalf("client: got no error, want %s", expectedErr)
649 } else if err.Error() != expectedErr.Error() {
650 t.Fatalf("client: got %s, want %s", err, expectedErr)
651 }
652 } else {
653 if err != nil {
654 t.Fatalf("client: got %s, want no error", err)
655 }
656 }
657 }
658 }
659
660
661
662 func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) {
663 signers := []Signer{}
664 for i := 0; i < 6; i++ {
665 signers = append(signers, testSigners["dsa"])
666 }
667
668 validConfig := &ClientConfig{
669 User: "testuser",
670 Auth: []AuthMethod{
671 PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...),
672 },
673 HostKeyCallback: InsecureIgnoreHostKey(),
674 }
675 if err := tryAuth(t, validConfig); err != nil {
676 t.Fatalf("unable to dial remote side: %s", err)
677 }
678
679 expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
680 Reason: 2,
681 Message: "too many authentication failures",
682 })
683 invalidConfig := &ClientConfig{
684 User: "testuser",
685 Auth: []AuthMethod{
686 PublicKeys(append(signers, testSigners["rsa"])...),
687 },
688 HostKeyCallback: InsecureIgnoreHostKey(),
689 }
690 if err := tryAuth(t, invalidConfig); err == nil {
691 t.Fatalf("client: got no error, want %s", expectedErr)
692 } else if err.Error() != expectedErr.Error() {
693
694
695
696
697 if runtime.GOOS == "windows" && strings.Contains(err.Error(), "wsarecv: An established connection was aborted") {
698
699 } else {
700 t.Fatalf("client: got %s, want %s", err, expectedErr)
701 }
702 }
703 }
704
705
706
707 func TestClientAuthErrorList(t *testing.T) {
708 publicKeyErr := errors.New("This is an error from PublicKeyCallback")
709
710 clientConfig := &ClientConfig{
711 Auth: []AuthMethod{
712 PublicKeys(testSigners["rsa"]),
713 },
714 HostKeyCallback: InsecureIgnoreHostKey(),
715 }
716 serverConfig := &ServerConfig{
717 PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) {
718 return nil, publicKeyErr
719 },
720 }
721 serverConfig.AddHostKey(testSigners["rsa"])
722
723 c1, c2, err := netPipe()
724 if err != nil {
725 t.Fatalf("netPipe: %v", err)
726 }
727 defer c1.Close()
728 defer c2.Close()
729
730 go NewClientConn(c2, "", clientConfig)
731 _, err = newServer(c1, serverConfig)
732 if err == nil {
733 t.Fatal("newServer: got nil, expected errors")
734 }
735
736 authErrs, ok := err.(*ServerAuthError)
737 if !ok {
738 t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err)
739 }
740 for i, e := range authErrs.Errors {
741 switch i {
742 case 0:
743 if e != ErrNoAuth {
744 t.Fatalf("errors: got error %v, want ErrNoAuth", e)
745 }
746 case 1:
747 if e != publicKeyErr {
748 t.Fatalf("errors: got %v, want %v", e, publicKeyErr)
749 }
750 default:
751 t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors)
752 }
753 }
754 }
755
756 func TestAuthMethodGSSAPIWithMIC(t *testing.T) {
757 type testcase struct {
758 config *ClientConfig
759 gssConfig *GSSAPIWithMICConfig
760 clientWantErr string
761 serverWantErr string
762 }
763 testcases := []*testcase{
764 {
765 config: &ClientConfig{
766 User: "testuser",
767 Auth: []AuthMethod{
768 GSSAPIWithMICAuthMethod(
769 &FakeClient{
770 exchanges: []*exchange{
771 {
772 outToken: "client-valid-token-1",
773 },
774 {
775 expectedToken: "server-valid-token-1",
776 },
777 },
778 mic: []byte("valid-mic"),
779 maxRound: 2,
780 }, "testtarget",
781 ),
782 },
783 HostKeyCallback: InsecureIgnoreHostKey(),
784 },
785 gssConfig: &GSSAPIWithMICConfig{
786 AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
787 if srcName != conn.User()+"@DOMAIN" {
788 return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
789 }
790 return nil, nil
791 },
792 Server: &FakeServer{
793 exchanges: []*exchange{
794 {
795 outToken: "server-valid-token-1",
796 expectedToken: "client-valid-token-1",
797 },
798 },
799 maxRound: 1,
800 expectedMIC: []byte("valid-mic"),
801 srcName: "testuser@DOMAIN",
802 },
803 },
804 },
805 {
806 config: &ClientConfig{
807 User: "testuser",
808 Auth: []AuthMethod{
809 GSSAPIWithMICAuthMethod(
810 &FakeClient{
811 exchanges: []*exchange{
812 {
813 outToken: "client-valid-token-1",
814 },
815 {
816 expectedToken: "server-valid-token-1",
817 },
818 },
819 mic: []byte("valid-mic"),
820 maxRound: 2,
821 }, "testtarget",
822 ),
823 },
824 HostKeyCallback: InsecureIgnoreHostKey(),
825 },
826 gssConfig: &GSSAPIWithMICConfig{
827 AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
828 return nil, fmt.Errorf("user is not allowed to login")
829 },
830 Server: &FakeServer{
831 exchanges: []*exchange{
832 {
833 outToken: "server-valid-token-1",
834 expectedToken: "client-valid-token-1",
835 },
836 },
837 maxRound: 1,
838 expectedMIC: []byte("valid-mic"),
839 srcName: "testuser@DOMAIN",
840 },
841 },
842 serverWantErr: "user is not allowed to login",
843 clientWantErr: "ssh: handshake failed: ssh: unable to authenticate",
844 },
845 {
846 config: &ClientConfig{
847 User: "testuser",
848 Auth: []AuthMethod{
849 GSSAPIWithMICAuthMethod(
850 &FakeClient{
851 exchanges: []*exchange{
852 {
853 outToken: "client-valid-token-1",
854 },
855 {
856 expectedToken: "server-valid-token-1",
857 },
858 },
859 mic: []byte("valid-mic"),
860 maxRound: 2,
861 }, "testtarget",
862 ),
863 },
864 HostKeyCallback: InsecureIgnoreHostKey(),
865 },
866 gssConfig: &GSSAPIWithMICConfig{
867 AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
868 if srcName != conn.User() {
869 return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
870 }
871 return nil, nil
872 },
873 Server: &FakeServer{
874 exchanges: []*exchange{
875 {
876 outToken: "server-invalid-token-1",
877 expectedToken: "client-valid-token-1",
878 },
879 },
880 maxRound: 1,
881 expectedMIC: []byte("valid-mic"),
882 srcName: "testuser@DOMAIN",
883 },
884 },
885 clientWantErr: "ssh: handshake failed: got \"server-invalid-token-1\", want token \"server-valid-token-1\"",
886 },
887 {
888 config: &ClientConfig{
889 User: "testuser",
890 Auth: []AuthMethod{
891 GSSAPIWithMICAuthMethod(
892 &FakeClient{
893 exchanges: []*exchange{
894 {
895 outToken: "client-valid-token-1",
896 },
897 {
898 expectedToken: "server-valid-token-1",
899 },
900 },
901 mic: []byte("invalid-mic"),
902 maxRound: 2,
903 }, "testtarget",
904 ),
905 },
906 HostKeyCallback: InsecureIgnoreHostKey(),
907 },
908 gssConfig: &GSSAPIWithMICConfig{
909 AllowLogin: func(conn ConnMetadata, srcName string) (*Permissions, error) {
910 if srcName != conn.User() {
911 return nil, fmt.Errorf("srcName is %s, conn user is %s", srcName, conn.User())
912 }
913 return nil, nil
914 },
915 Server: &FakeServer{
916 exchanges: []*exchange{
917 {
918 outToken: "server-valid-token-1",
919 expectedToken: "client-valid-token-1",
920 },
921 },
922 maxRound: 1,
923 expectedMIC: []byte("valid-mic"),
924 srcName: "testuser@DOMAIN",
925 },
926 },
927 serverWantErr: "got MICToken \"invalid-mic\", want \"valid-mic\"",
928 clientWantErr: "ssh: handshake failed: ssh: unable to authenticate",
929 },
930 }
931
932 for i, c := range testcases {
933 clientErr, serverErrs := tryAuthBothSides(t, c.config, c.gssConfig)
934 if (c.clientWantErr == "") != (clientErr == nil) {
935 t.Fatalf("client got %v, want %s, case %d", clientErr, c.clientWantErr, i)
936 }
937 if (c.serverWantErr == "") != (len(serverErrs) == 2 && serverErrs[1] == nil || len(serverErrs) == 1) {
938 t.Fatalf("server got err %v, want %s", serverErrs, c.serverWantErr)
939 }
940 if c.clientWantErr != "" {
941 if clientErr != nil && !strings.Contains(clientErr.Error(), c.clientWantErr) {
942 t.Fatalf("client got %v, want %s, case %d", clientErr, c.clientWantErr, i)
943 }
944 }
945 found := false
946 var errStrings []string
947 if c.serverWantErr != "" {
948 for _, err := range serverErrs {
949 found = found || (err != nil && strings.Contains(err.Error(), c.serverWantErr))
950 errStrings = append(errStrings, err.Error())
951 }
952 if !found {
953 t.Errorf("server got error %q, want substring %q, case %d", errStrings, c.serverWantErr, i)
954 }
955 }
956 }
957 }
958
959 func TestCompatibleAlgoAndSignatures(t *testing.T) {
960 type testcase struct {
961 algo string
962 sigFormat string
963 compatible bool
964 }
965 testcases := []*testcase{
966 {
967 KeyAlgoRSA,
968 KeyAlgoRSA,
969 true,
970 },
971 {
972 KeyAlgoRSA,
973 KeyAlgoRSASHA256,
974 true,
975 },
976 {
977 KeyAlgoRSA,
978 KeyAlgoRSASHA512,
979 true,
980 },
981 {
982 KeyAlgoRSASHA256,
983 KeyAlgoRSA,
984 true,
985 },
986 {
987 KeyAlgoRSASHA512,
988 KeyAlgoRSA,
989 true,
990 },
991 {
992 KeyAlgoRSASHA512,
993 KeyAlgoRSASHA256,
994 true,
995 },
996 {
997 KeyAlgoRSASHA256,
998 KeyAlgoRSASHA512,
999 true,
1000 },
1001 {
1002 KeyAlgoRSASHA512,
1003 KeyAlgoRSASHA512,
1004 true,
1005 },
1006 {
1007 CertAlgoRSAv01,
1008 KeyAlgoRSA,
1009 true,
1010 },
1011 {
1012 CertAlgoRSAv01,
1013 KeyAlgoRSASHA256,
1014 true,
1015 },
1016 {
1017 CertAlgoRSAv01,
1018 KeyAlgoRSASHA512,
1019 true,
1020 },
1021 {
1022 CertAlgoRSASHA256v01,
1023 KeyAlgoRSASHA512,
1024 true,
1025 },
1026 {
1027 CertAlgoRSASHA512v01,
1028 KeyAlgoRSASHA512,
1029 true,
1030 },
1031 {
1032 CertAlgoRSASHA512v01,
1033 KeyAlgoRSASHA256,
1034 true,
1035 },
1036 {
1037 CertAlgoRSASHA256v01,
1038 CertAlgoRSAv01,
1039 true,
1040 },
1041 {
1042 CertAlgoRSAv01,
1043 CertAlgoRSASHA512v01,
1044 true,
1045 },
1046 {
1047 KeyAlgoECDSA256,
1048 KeyAlgoRSA,
1049 false,
1050 },
1051 {
1052 KeyAlgoECDSA256,
1053 KeyAlgoECDSA521,
1054 false,
1055 },
1056 {
1057 KeyAlgoECDSA256,
1058 KeyAlgoECDSA256,
1059 true,
1060 },
1061 {
1062 KeyAlgoECDSA256,
1063 KeyAlgoED25519,
1064 false,
1065 },
1066 {
1067 KeyAlgoED25519,
1068 KeyAlgoED25519,
1069 true,
1070 },
1071 }
1072
1073 for _, c := range testcases {
1074 if isAlgoCompatible(c.algo, c.sigFormat) != c.compatible {
1075 t.Errorf("algorithm %q, signature format %q, expected compatible to be %t", c.algo, c.sigFormat, c.compatible)
1076 }
1077 }
1078 }
1079
1080 func TestPickSignatureAlgorithm(t *testing.T) {
1081 type testcase struct {
1082 name string
1083 extensions map[string][]byte
1084 }
1085 cases := []testcase{
1086 {
1087 name: "server with empty server-sig-algs",
1088 extensions: map[string][]byte{
1089 "server-sig-algs": []byte(``),
1090 },
1091 },
1092 {
1093 name: "server with no server-sig-algs",
1094 extensions: nil,
1095 },
1096 }
1097 for _, c := range cases {
1098 t.Run(c.name, func(t *testing.T) {
1099 signer, ok := testSigners["rsa"].(MultiAlgorithmSigner)
1100 if !ok {
1101 t.Fatalf("rsa test signer does not implement the MultiAlgorithmSigner interface")
1102 }
1103
1104 _, algo, err := pickSignatureAlgorithm(signer, c.extensions)
1105 if err != nil {
1106 t.Fatalf("got %v, want no error", err)
1107 }
1108 if algo != signer.PublicKey().Type() {
1109 t.Fatalf("got algo %q, want %q", algo, signer.PublicKey().Type())
1110 }
1111
1112
1113 cert := &Certificate{
1114 CertType: UserCert,
1115 Key: signer.PublicKey(),
1116 }
1117 cert.SignCert(rand.Reader, signer)
1118
1119 certSigner, err := NewCertSigner(cert, signer)
1120 if err != nil {
1121 t.Fatalf("error generating cert signer: %v", err)
1122 }
1123
1124
1125
1126 _, algo, err = pickSignatureAlgorithm(certSigner, c.extensions)
1127 if err != nil {
1128 t.Fatalf("got %v, want no error", err)
1129 }
1130 if algo != certSigner.PublicKey().Type() {
1131 t.Fatalf("got algo %q, want %q", algo, certSigner.PublicKey().Type())
1132 }
1133 signer, err = NewSignerWithAlgorithms(signer.(AlgorithmSigner), []string{KeyAlgoRSASHA512, KeyAlgoRSASHA256})
1134 if err != nil {
1135 t.Fatalf("unable to create signer with algorithms: %v", err)
1136 }
1137
1138
1139 _, _, err = pickSignatureAlgorithm(signer, c.extensions)
1140 if err == nil {
1141 t.Fatal("got no error, no common public key signature algorithm error expected")
1142 }
1143 })
1144 }
1145 }
1146
1147
1148
1149
1150 type configurablePublicKeyCallback struct {
1151 signer AlgorithmSigner
1152 signatureAlgo string
1153 signatureFormat string
1154 }
1155
1156 func (cb configurablePublicKeyCallback) method() string {
1157 return "publickey"
1158 }
1159
1160 func (cb configurablePublicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader, extensions map[string][]byte) (authResult, []string, error) {
1161 pub := cb.signer.PublicKey()
1162
1163 ok, err := validateKey(pub, cb.signatureAlgo, user, c)
1164 if err != nil {
1165 return authFailure, nil, err
1166 }
1167 if !ok {
1168 return authFailure, nil, fmt.Errorf("invalid public key")
1169 }
1170
1171 pubKey := pub.Marshal()
1172 data := buildDataSignedForAuth(session, userAuthRequestMsg{
1173 User: user,
1174 Service: serviceSSH,
1175 Method: cb.method(),
1176 }, cb.signatureAlgo, pubKey)
1177 sign, err := cb.signer.SignWithAlgorithm(rand, data, underlyingAlgo(cb.signatureFormat))
1178 if err != nil {
1179 return authFailure, nil, err
1180 }
1181
1182 s := Marshal(sign)
1183 sig := make([]byte, stringLength(len(s)))
1184 marshalString(sig, s)
1185 msg := publickeyAuthMsg{
1186 User: user,
1187 Service: serviceSSH,
1188 Method: cb.method(),
1189 HasSig: true,
1190 Algoname: cb.signatureAlgo,
1191 PubKey: pubKey,
1192 Sig: sig,
1193 }
1194 p := Marshal(&msg)
1195 if err := c.writePacket(p); err != nil {
1196 return authFailure, nil, err
1197 }
1198 var success authResult
1199 success, methods, err := handleAuthResponse(c)
1200 if err != nil {
1201 return authFailure, nil, err
1202 }
1203 if success == authSuccess || !contains(methods, cb.method()) {
1204 return success, methods, err
1205 }
1206
1207 return authFailure, methods, nil
1208 }
1209
1210 func TestPublicKeyAndAlgoCompatibility(t *testing.T) {
1211 cert := &Certificate{
1212 Key: testPublicKeys["rsa"],
1213 ValidBefore: CertTimeInfinity,
1214 CertType: UserCert,
1215 }
1216 cert.SignCert(rand.Reader, testSigners["ecdsa"])
1217 certSigner, err := NewCertSigner(cert, testSigners["rsa"])
1218 if err != nil {
1219 t.Fatalf("NewCertSigner: %v", err)
1220 }
1221
1222 clientConfig := &ClientConfig{
1223 User: "user",
1224 HostKeyCallback: InsecureIgnoreHostKey(),
1225 Auth: []AuthMethod{
1226 configurablePublicKeyCallback{
1227 signer: certSigner.(AlgorithmSigner),
1228 signatureAlgo: KeyAlgoRSASHA256,
1229 signatureFormat: KeyAlgoRSASHA256,
1230 },
1231 },
1232 }
1233 if err := tryAuth(t, clientConfig); err == nil {
1234 t.Error("cert login passed with incompatible public key type and algorithm")
1235 }
1236 }
1237
1238 func TestClientAuthGPGAgentCompat(t *testing.T) {
1239 clientConfig := &ClientConfig{
1240 User: "testuser",
1241 HostKeyCallback: InsecureIgnoreHostKey(),
1242 Auth: []AuthMethod{
1243
1244 configurablePublicKeyCallback{
1245 signer: testSigners["rsa"].(AlgorithmSigner),
1246 signatureAlgo: KeyAlgoRSASHA512,
1247 signatureFormat: KeyAlgoRSA,
1248 },
1249 },
1250 }
1251 if err := tryAuth(t, clientConfig); err != nil {
1252 t.Fatalf("unable to dial remote side: %s", err)
1253 }
1254 }
1255
1256 func TestCertAuthOpenSSHCompat(t *testing.T) {
1257 cert := &Certificate{
1258 Key: testPublicKeys["rsa"],
1259 ValidBefore: CertTimeInfinity,
1260 CertType: UserCert,
1261 }
1262 cert.SignCert(rand.Reader, testSigners["ecdsa"])
1263 certSigner, err := NewCertSigner(cert, testSigners["rsa"])
1264 if err != nil {
1265 t.Fatalf("NewCertSigner: %v", err)
1266 }
1267
1268 clientConfig := &ClientConfig{
1269 User: "user",
1270 HostKeyCallback: InsecureIgnoreHostKey(),
1271 Auth: []AuthMethod{
1272
1273
1274 configurablePublicKeyCallback{
1275 signer: certSigner.(AlgorithmSigner),
1276 signatureAlgo: CertAlgoRSAv01,
1277 signatureFormat: KeyAlgoRSASHA256,
1278 },
1279 },
1280 }
1281 if err := tryAuth(t, clientConfig); err != nil {
1282 t.Fatalf("unable to dial remote side: %s", err)
1283 }
1284 }
1285
View as plain text