OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / crypto / ssh / client_auth_test.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         "crypto/rand"
10         "errors"
11         "fmt"
12         "os"
13         "strings"
14         "testing"
15 )
16
17 type keyboardInteractive map[string]string
18
19 func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
20         var answers []string
21         for _, q := range questions {
22                 answers = append(answers, cr[q])
23         }
24         return answers, nil
25 }
26
27 // reused internally by tests
28 var clientPassword = "tiger"
29
30 // tryAuth runs a handshake with a given config against an SSH server
31 // with config serverConfig
32 func tryAuth(t *testing.T, config *ClientConfig) error {
33         c1, c2, err := netPipe()
34         if err != nil {
35                 t.Fatalf("netPipe: %v", err)
36         }
37         defer c1.Close()
38         defer c2.Close()
39
40         certChecker := CertChecker{
41                 IsUserAuthority: func(k PublicKey) bool {
42                         return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
43                 },
44                 UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
45                         if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
46                                 return nil, nil
47                         }
48
49                         return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
50                 },
51                 IsRevoked: func(c *Certificate) bool {
52                         return c.Serial == 666
53                 },
54         }
55
56         serverConfig := &ServerConfig{
57                 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
58                         if conn.User() == "testuser" && string(pass) == clientPassword {
59                                 return nil, nil
60                         }
61                         return nil, errors.New("password auth failed")
62                 },
63                 PublicKeyCallback: certChecker.Authenticate,
64                 KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
65                         ans, err := challenge("user",
66                                 "instruction",
67                                 []string{"question1", "question2"},
68                                 []bool{true, true})
69                         if err != nil {
70                                 return nil, err
71                         }
72                         ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
73                         if ok {
74                                 challenge("user", "motd", nil, nil)
75                                 return nil, nil
76                         }
77                         return nil, errors.New("keyboard-interactive failed")
78                 },
79         }
80         serverConfig.AddHostKey(testSigners["rsa"])
81
82         go newServer(c1, serverConfig)
83         _, _, _, err = NewClientConn(c2, "", config)
84         return err
85 }
86
87 func TestClientAuthPublicKey(t *testing.T) {
88         config := &ClientConfig{
89                 User: "testuser",
90                 Auth: []AuthMethod{
91                         PublicKeys(testSigners["rsa"]),
92                 },
93                 HostKeyCallback: InsecureIgnoreHostKey(),
94         }
95         if err := tryAuth(t, config); err != nil {
96                 t.Fatalf("unable to dial remote side: %s", err)
97         }
98 }
99
100 func TestAuthMethodPassword(t *testing.T) {
101         config := &ClientConfig{
102                 User: "testuser",
103                 Auth: []AuthMethod{
104                         Password(clientPassword),
105                 },
106                 HostKeyCallback: InsecureIgnoreHostKey(),
107         }
108
109         if err := tryAuth(t, config); err != nil {
110                 t.Fatalf("unable to dial remote side: %s", err)
111         }
112 }
113
114 func TestAuthMethodFallback(t *testing.T) {
115         var passwordCalled bool
116         config := &ClientConfig{
117                 User: "testuser",
118                 Auth: []AuthMethod{
119                         PublicKeys(testSigners["rsa"]),
120                         PasswordCallback(
121                                 func() (string, error) {
122                                         passwordCalled = true
123                                         return "WRONG", nil
124                                 }),
125                 },
126                 HostKeyCallback: InsecureIgnoreHostKey(),
127         }
128
129         if err := tryAuth(t, config); err != nil {
130                 t.Fatalf("unable to dial remote side: %s", err)
131         }
132
133         if passwordCalled {
134                 t.Errorf("password auth tried before public-key auth.")
135         }
136 }
137
138 func TestAuthMethodWrongPassword(t *testing.T) {
139         config := &ClientConfig{
140                 User: "testuser",
141                 Auth: []AuthMethod{
142                         Password("wrong"),
143                         PublicKeys(testSigners["rsa"]),
144                 },
145                 HostKeyCallback: InsecureIgnoreHostKey(),
146         }
147
148         if err := tryAuth(t, config); err != nil {
149                 t.Fatalf("unable to dial remote side: %s", err)
150         }
151 }
152
153 func TestAuthMethodKeyboardInteractive(t *testing.T) {
154         answers := keyboardInteractive(map[string]string{
155                 "question1": "answer1",
156                 "question2": "answer2",
157         })
158         config := &ClientConfig{
159                 User: "testuser",
160                 Auth: []AuthMethod{
161                         KeyboardInteractive(answers.Challenge),
162                 },
163                 HostKeyCallback: InsecureIgnoreHostKey(),
164         }
165
166         if err := tryAuth(t, config); err != nil {
167                 t.Fatalf("unable to dial remote side: %s", err)
168         }
169 }
170
171 func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
172         answers := keyboardInteractive(map[string]string{
173                 "question1": "answer1",
174                 "question2": "WRONG",
175         })
176         config := &ClientConfig{
177                 User: "testuser",
178                 Auth: []AuthMethod{
179                         KeyboardInteractive(answers.Challenge),
180                 },
181         }
182
183         if err := tryAuth(t, config); err == nil {
184                 t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
185         }
186 }
187
188 // the mock server will only authenticate ssh-rsa keys
189 func TestAuthMethodInvalidPublicKey(t *testing.T) {
190         config := &ClientConfig{
191                 User: "testuser",
192                 Auth: []AuthMethod{
193                         PublicKeys(testSigners["dsa"]),
194                 },
195         }
196
197         if err := tryAuth(t, config); err == nil {
198                 t.Fatalf("dsa private key should not have authenticated with rsa public key")
199         }
200 }
201
202 // the client should authenticate with the second key
203 func TestAuthMethodRSAandDSA(t *testing.T) {
204         config := &ClientConfig{
205                 User: "testuser",
206                 Auth: []AuthMethod{
207                         PublicKeys(testSigners["dsa"], testSigners["rsa"]),
208                 },
209                 HostKeyCallback: InsecureIgnoreHostKey(),
210         }
211         if err := tryAuth(t, config); err != nil {
212                 t.Fatalf("client could not authenticate with rsa key: %v", err)
213         }
214 }
215
216 func TestClientHMAC(t *testing.T) {
217         for _, mac := range supportedMACs {
218                 config := &ClientConfig{
219                         User: "testuser",
220                         Auth: []AuthMethod{
221                                 PublicKeys(testSigners["rsa"]),
222                         },
223                         Config: Config{
224                                 MACs: []string{mac},
225                         },
226                         HostKeyCallback: InsecureIgnoreHostKey(),
227                 }
228                 if err := tryAuth(t, config); err != nil {
229                         t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
230                 }
231         }
232 }
233
234 // issue 4285.
235 func TestClientUnsupportedCipher(t *testing.T) {
236         config := &ClientConfig{
237                 User: "testuser",
238                 Auth: []AuthMethod{
239                         PublicKeys(),
240                 },
241                 Config: Config{
242                         Ciphers: []string{"aes128-cbc"}, // not currently supported
243                 },
244         }
245         if err := tryAuth(t, config); err == nil {
246                 t.Errorf("expected no ciphers in common")
247         }
248 }
249
250 func TestClientUnsupportedKex(t *testing.T) {
251         if os.Getenv("GO_BUILDER_NAME") != "" {
252                 t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
253         }
254         config := &ClientConfig{
255                 User: "testuser",
256                 Auth: []AuthMethod{
257                         PublicKeys(),
258                 },
259                 Config: Config{
260                         KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
261                 },
262                 HostKeyCallback: InsecureIgnoreHostKey(),
263         }
264         if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
265                 t.Errorf("got %v, expected 'common algorithm'", err)
266         }
267 }
268
269 func TestClientLoginCert(t *testing.T) {
270         cert := &Certificate{
271                 Key:         testPublicKeys["rsa"],
272                 ValidBefore: CertTimeInfinity,
273                 CertType:    UserCert,
274         }
275         cert.SignCert(rand.Reader, testSigners["ecdsa"])
276         certSigner, err := NewCertSigner(cert, testSigners["rsa"])
277         if err != nil {
278                 t.Fatalf("NewCertSigner: %v", err)
279         }
280
281         clientConfig := &ClientConfig{
282                 User:            "user",
283                 HostKeyCallback: InsecureIgnoreHostKey(),
284         }
285         clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
286
287         // should succeed
288         if err := tryAuth(t, clientConfig); err != nil {
289                 t.Errorf("cert login failed: %v", err)
290         }
291
292         // corrupted signature
293         cert.Signature.Blob[0]++
294         if err := tryAuth(t, clientConfig); err == nil {
295                 t.Errorf("cert login passed with corrupted sig")
296         }
297
298         // revoked
299         cert.Serial = 666
300         cert.SignCert(rand.Reader, testSigners["ecdsa"])
301         if err := tryAuth(t, clientConfig); err == nil {
302                 t.Errorf("revoked cert login succeeded")
303         }
304         cert.Serial = 1
305
306         // sign with wrong key
307         cert.SignCert(rand.Reader, testSigners["dsa"])
308         if err := tryAuth(t, clientConfig); err == nil {
309                 t.Errorf("cert login passed with non-authoritative key")
310         }
311
312         // host cert
313         cert.CertType = HostCert
314         cert.SignCert(rand.Reader, testSigners["ecdsa"])
315         if err := tryAuth(t, clientConfig); err == nil {
316                 t.Errorf("cert login passed with wrong type")
317         }
318         cert.CertType = UserCert
319
320         // principal specified
321         cert.ValidPrincipals = []string{"user"}
322         cert.SignCert(rand.Reader, testSigners["ecdsa"])
323         if err := tryAuth(t, clientConfig); err != nil {
324                 t.Errorf("cert login failed: %v", err)
325         }
326
327         // wrong principal specified
328         cert.ValidPrincipals = []string{"fred"}
329         cert.SignCert(rand.Reader, testSigners["ecdsa"])
330         if err := tryAuth(t, clientConfig); err == nil {
331                 t.Errorf("cert login passed with wrong principal")
332         }
333         cert.ValidPrincipals = nil
334
335         // added critical option
336         cert.CriticalOptions = map[string]string{"root-access": "yes"}
337         cert.SignCert(rand.Reader, testSigners["ecdsa"])
338         if err := tryAuth(t, clientConfig); err == nil {
339                 t.Errorf("cert login passed with unrecognized critical option")
340         }
341
342         // allowed source address
343         cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
344         cert.SignCert(rand.Reader, testSigners["ecdsa"])
345         if err := tryAuth(t, clientConfig); err != nil {
346                 t.Errorf("cert login with source-address failed: %v", err)
347         }
348
349         // disallowed source address
350         cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
351         cert.SignCert(rand.Reader, testSigners["ecdsa"])
352         if err := tryAuth(t, clientConfig); err == nil {
353                 t.Errorf("cert login with source-address succeeded")
354         }
355 }
356
357 func testPermissionsPassing(withPermissions bool, t *testing.T) {
358         serverConfig := &ServerConfig{
359                 PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
360                         if conn.User() == "nopermissions" {
361                                 return nil, nil
362                         }
363                         return &Permissions{}, nil
364                 },
365         }
366         serverConfig.AddHostKey(testSigners["rsa"])
367
368         clientConfig := &ClientConfig{
369                 Auth: []AuthMethod{
370                         PublicKeys(testSigners["rsa"]),
371                 },
372                 HostKeyCallback: InsecureIgnoreHostKey(),
373         }
374         if withPermissions {
375                 clientConfig.User = "permissions"
376         } else {
377                 clientConfig.User = "nopermissions"
378         }
379
380         c1, c2, err := netPipe()
381         if err != nil {
382                 t.Fatalf("netPipe: %v", err)
383         }
384         defer c1.Close()
385         defer c2.Close()
386
387         go NewClientConn(c2, "", clientConfig)
388         serverConn, err := newServer(c1, serverConfig)
389         if err != nil {
390                 t.Fatal(err)
391         }
392         if p := serverConn.Permissions; (p != nil) != withPermissions {
393                 t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
394         }
395 }
396
397 func TestPermissionsPassing(t *testing.T) {
398         testPermissionsPassing(true, t)
399 }
400
401 func TestNoPermissionsPassing(t *testing.T) {
402         testPermissionsPassing(false, t)
403 }
404
405 func TestRetryableAuth(t *testing.T) {
406         n := 0
407         passwords := []string{"WRONG1", "WRONG2"}
408
409         config := &ClientConfig{
410                 User: "testuser",
411                 Auth: []AuthMethod{
412                         RetryableAuthMethod(PasswordCallback(func() (string, error) {
413                                 p := passwords[n]
414                                 n++
415                                 return p, nil
416                         }), 2),
417                         PublicKeys(testSigners["rsa"]),
418                 },
419                 HostKeyCallback: InsecureIgnoreHostKey(),
420         }
421
422         if err := tryAuth(t, config); err != nil {
423                 t.Fatalf("unable to dial remote side: %s", err)
424         }
425         if n != 2 {
426                 t.Fatalf("Did not try all passwords")
427         }
428 }
429
430 func ExampleRetryableAuthMethod(t *testing.T) {
431         user := "testuser"
432         NumberOfPrompts := 3
433
434         // Normally this would be a callback that prompts the user to answer the
435         // provided questions
436         Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
437                 return []string{"answer1", "answer2"}, nil
438         }
439
440         config := &ClientConfig{
441                 HostKeyCallback: InsecureIgnoreHostKey(),
442                 User:            user,
443                 Auth: []AuthMethod{
444                         RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
445                 },
446         }
447
448         if err := tryAuth(t, config); err != nil {
449                 t.Fatalf("unable to dial remote side: %s", err)
450         }
451 }
452
453 // Test if username is received on server side when NoClientAuth is used
454 func TestClientAuthNone(t *testing.T) {
455         user := "testuser"
456         serverConfig := &ServerConfig{
457                 NoClientAuth: true,
458         }
459         serverConfig.AddHostKey(testSigners["rsa"])
460
461         clientConfig := &ClientConfig{
462                 User:            user,
463                 HostKeyCallback: InsecureIgnoreHostKey(),
464         }
465
466         c1, c2, err := netPipe()
467         if err != nil {
468                 t.Fatalf("netPipe: %v", err)
469         }
470         defer c1.Close()
471         defer c2.Close()
472
473         go NewClientConn(c2, "", clientConfig)
474         serverConn, err := newServer(c1, serverConfig)
475         if err != nil {
476                 t.Fatalf("newServer: %v", err)
477         }
478         if serverConn.User() != user {
479                 t.Fatalf("server: got %q, want %q", serverConn.User(), user)
480         }
481 }
482
483 // Test if authentication attempts are limited on server when MaxAuthTries is set
484 func TestClientAuthMaxAuthTries(t *testing.T) {
485         user := "testuser"
486
487         serverConfig := &ServerConfig{
488                 MaxAuthTries: 2,
489                 PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
490                         if conn.User() == "testuser" && string(pass) == "right" {
491                                 return nil, nil
492                         }
493                         return nil, errors.New("password auth failed")
494                 },
495         }
496         serverConfig.AddHostKey(testSigners["rsa"])
497
498         expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
499                 Reason:  2,
500                 Message: "too many authentication failures",
501         })
502
503         for tries := 2; tries < 4; tries++ {
504                 n := tries
505                 clientConfig := &ClientConfig{
506                         User: user,
507                         Auth: []AuthMethod{
508                                 RetryableAuthMethod(PasswordCallback(func() (string, error) {
509                                         n--
510                                         if n == 0 {
511                                                 return "right", nil
512                                         }
513                                         return "wrong", nil
514                                 }), tries),
515                         },
516                         HostKeyCallback: InsecureIgnoreHostKey(),
517                 }
518
519                 c1, c2, err := netPipe()
520                 if err != nil {
521                         t.Fatalf("netPipe: %v", err)
522                 }
523                 defer c1.Close()
524                 defer c2.Close()
525
526                 go newServer(c1, serverConfig)
527                 _, _, _, err = NewClientConn(c2, "", clientConfig)
528                 if tries > 2 {
529                         if err == nil {
530                                 t.Fatalf("client: got no error, want %s", expectedErr)
531                         } else if err.Error() != expectedErr.Error() {
532                                 t.Fatalf("client: got %s, want %s", err, expectedErr)
533                         }
534                 } else {
535                         if err != nil {
536                                 t.Fatalf("client: got %s, want no error", err)
537                         }
538                 }
539         }
540 }
541
542 // Test if authentication attempts are correctly limited on server
543 // when more public keys are provided then MaxAuthTries
544 func TestClientAuthMaxAuthTriesPublicKey(t *testing.T) {
545         signers := []Signer{}
546         for i := 0; i < 6; i++ {
547                 signers = append(signers, testSigners["dsa"])
548         }
549
550         validConfig := &ClientConfig{
551                 User: "testuser",
552                 Auth: []AuthMethod{
553                         PublicKeys(append([]Signer{testSigners["rsa"]}, signers...)...),
554                 },
555                 HostKeyCallback: InsecureIgnoreHostKey(),
556         }
557         if err := tryAuth(t, validConfig); err != nil {
558                 t.Fatalf("unable to dial remote side: %s", err)
559         }
560
561         expectedErr := fmt.Errorf("ssh: handshake failed: %v", &disconnectMsg{
562                 Reason:  2,
563                 Message: "too many authentication failures",
564         })
565         invalidConfig := &ClientConfig{
566                 User: "testuser",
567                 Auth: []AuthMethod{
568                         PublicKeys(append(signers, testSigners["rsa"])...),
569                 },
570                 HostKeyCallback: InsecureIgnoreHostKey(),
571         }
572         if err := tryAuth(t, invalidConfig); err == nil {
573                 t.Fatalf("client: got no error, want %s", expectedErr)
574         } else if err.Error() != expectedErr.Error() {
575                 t.Fatalf("client: got %s, want %s", err, expectedErr)
576         }
577 }
578
579 // Test whether authentication errors are being properly logged if all
580 // authentication methods have been exhausted
581 func TestClientAuthErrorList(t *testing.T) {
582         publicKeyErr := errors.New("This is an error from PublicKeyCallback")
583
584         clientConfig := &ClientConfig{
585                 Auth: []AuthMethod{
586                         PublicKeys(testSigners["rsa"]),
587                 },
588                 HostKeyCallback: InsecureIgnoreHostKey(),
589         }
590         serverConfig := &ServerConfig{
591                 PublicKeyCallback: func(_ ConnMetadata, _ PublicKey) (*Permissions, error) {
592                         return nil, publicKeyErr
593                 },
594         }
595         serverConfig.AddHostKey(testSigners["rsa"])
596
597         c1, c2, err := netPipe()
598         if err != nil {
599                 t.Fatalf("netPipe: %v", err)
600         }
601         defer c1.Close()
602         defer c2.Close()
603
604         go NewClientConn(c2, "", clientConfig)
605         _, err = newServer(c1, serverConfig)
606         if err == nil {
607                 t.Fatal("newServer: got nil, expected errors")
608         }
609
610         authErrs, ok := err.(*ServerAuthError)
611         if !ok {
612                 t.Fatalf("errors: got %T, want *ssh.ServerAuthError", err)
613         }
614         for i, e := range authErrs.Errors {
615                 switch i {
616                 case 0:
617                         if e.Error() != "no auth passed yet" {
618                                 t.Fatalf("errors: got %v, want no auth passed yet", e.Error())
619                         }
620                 case 1:
621                         if e != publicKeyErr {
622                                 t.Fatalf("errors: got %v, want %v", e, publicKeyErr)
623                         }
624                 default:
625                         t.Fatalf("errors: got %v, expected 2 errors", authErrs.Errors)
626                 }
627         }
628 }