client_auth_test.go 17 KB

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