client_auth_test.go 17 KB

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