client_auth_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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. "os"
  11. "strings"
  12. "testing"
  13. )
  14. type keyboardInteractive map[string]string
  15. func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
  16. var answers []string
  17. for _, q := range questions {
  18. answers = append(answers, cr[q])
  19. }
  20. return answers, nil
  21. }
  22. // reused internally by tests
  23. var clientPassword = "tiger"
  24. // tryAuth runs a handshake with a given config against an SSH server
  25. // with config serverConfig
  26. func tryAuth(t *testing.T, config *ClientConfig) error {
  27. c1, c2, err := netPipe()
  28. if err != nil {
  29. t.Fatalf("netPipe: %v", err)
  30. }
  31. defer c1.Close()
  32. defer c2.Close()
  33. certChecker := CertChecker{
  34. IsAuthority: func(k PublicKey) bool {
  35. return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
  36. },
  37. UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
  38. if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
  39. return nil, nil
  40. }
  41. return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
  42. },
  43. IsRevoked: func(c *Certificate) bool {
  44. return c.Serial == 666
  45. },
  46. }
  47. serverConfig := &ServerConfig{
  48. PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
  49. if conn.User() == "testuser" && string(pass) == clientPassword {
  50. return nil, nil
  51. }
  52. return nil, errors.New("password auth failed")
  53. },
  54. PublicKeyCallback: certChecker.Authenticate,
  55. KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
  56. ans, err := challenge("user",
  57. "instruction",
  58. []string{"question1", "question2"},
  59. []bool{true, true})
  60. if err != nil {
  61. return nil, err
  62. }
  63. ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
  64. if ok {
  65. challenge("user", "motd", nil, nil)
  66. return nil, nil
  67. }
  68. return nil, errors.New("keyboard-interactive failed")
  69. },
  70. AuthLogCallback: func(conn ConnMetadata, method string, err error) {
  71. },
  72. }
  73. serverConfig.AddHostKey(testSigners["rsa"])
  74. go newServer(c1, serverConfig)
  75. _, _, _, err = NewClientConn(c2, "", config)
  76. return err
  77. }
  78. func TestClientAuthPublicKey(t *testing.T) {
  79. config := &ClientConfig{
  80. User: "testuser",
  81. Auth: []AuthMethod{
  82. PublicKeys(testSigners["rsa"]),
  83. },
  84. HostKeyCallback: InsecureIgnoreHostKey(),
  85. }
  86. if err := tryAuth(t, config); err != nil {
  87. t.Fatalf("unable to dial remote side: %s", err)
  88. }
  89. }
  90. func TestAuthMethodPassword(t *testing.T) {
  91. config := &ClientConfig{
  92. User: "testuser",
  93. Auth: []AuthMethod{
  94. Password(clientPassword),
  95. },
  96. HostKeyCallback: InsecureIgnoreHostKey(),
  97. }
  98. if err := tryAuth(t, config); err != nil {
  99. t.Fatalf("unable to dial remote side: %s", err)
  100. }
  101. }
  102. func TestAuthMethodFallback(t *testing.T) {
  103. var passwordCalled bool
  104. config := &ClientConfig{
  105. User: "testuser",
  106. Auth: []AuthMethod{
  107. PublicKeys(testSigners["rsa"]),
  108. PasswordCallback(
  109. func() (string, error) {
  110. passwordCalled = true
  111. return "WRONG", nil
  112. }),
  113. },
  114. HostKeyCallback: InsecureIgnoreHostKey(),
  115. }
  116. if err := tryAuth(t, config); err != nil {
  117. t.Fatalf("unable to dial remote side: %s", err)
  118. }
  119. if passwordCalled {
  120. t.Errorf("password auth tried before public-key auth.")
  121. }
  122. }
  123. func TestAuthMethodWrongPassword(t *testing.T) {
  124. config := &ClientConfig{
  125. User: "testuser",
  126. Auth: []AuthMethod{
  127. Password("wrong"),
  128. PublicKeys(testSigners["rsa"]),
  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. }
  136. func TestAuthMethodKeyboardInteractive(t *testing.T) {
  137. answers := keyboardInteractive(map[string]string{
  138. "question1": "answer1",
  139. "question2": "answer2",
  140. })
  141. config := &ClientConfig{
  142. User: "testuser",
  143. Auth: []AuthMethod{
  144. KeyboardInteractive(answers.Challenge),
  145. },
  146. HostKeyCallback: InsecureIgnoreHostKey(),
  147. }
  148. if err := tryAuth(t, config); err != nil {
  149. t.Fatalf("unable to dial remote side: %s", err)
  150. }
  151. }
  152. func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
  153. answers := keyboardInteractive(map[string]string{
  154. "question1": "answer1",
  155. "question2": "WRONG",
  156. })
  157. config := &ClientConfig{
  158. User: "testuser",
  159. Auth: []AuthMethod{
  160. KeyboardInteractive(answers.Challenge),
  161. },
  162. }
  163. if err := tryAuth(t, config); err == nil {
  164. t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
  165. }
  166. }
  167. // the mock server will only authenticate ssh-rsa keys
  168. func TestAuthMethodInvalidPublicKey(t *testing.T) {
  169. config := &ClientConfig{
  170. User: "testuser",
  171. Auth: []AuthMethod{
  172. PublicKeys(testSigners["dsa"]),
  173. },
  174. }
  175. if err := tryAuth(t, config); err == nil {
  176. t.Fatalf("dsa private key should not have authenticated with rsa public key")
  177. }
  178. }
  179. // the client should authenticate with the second key
  180. func TestAuthMethodRSAandDSA(t *testing.T) {
  181. config := &ClientConfig{
  182. User: "testuser",
  183. Auth: []AuthMethod{
  184. PublicKeys(testSigners["dsa"], testSigners["rsa"]),
  185. },
  186. HostKeyCallback: InsecureIgnoreHostKey(),
  187. }
  188. if err := tryAuth(t, config); err != nil {
  189. t.Fatalf("client could not authenticate with rsa key: %v", err)
  190. }
  191. }
  192. func TestClientHMAC(t *testing.T) {
  193. for _, mac := range supportedMACs {
  194. config := &ClientConfig{
  195. User: "testuser",
  196. Auth: []AuthMethod{
  197. PublicKeys(testSigners["rsa"]),
  198. },
  199. Config: Config{
  200. MACs: []string{mac},
  201. },
  202. HostKeyCallback: InsecureIgnoreHostKey(),
  203. }
  204. if err := tryAuth(t, config); err != nil {
  205. t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
  206. }
  207. }
  208. }
  209. // issue 4285.
  210. func TestClientUnsupportedCipher(t *testing.T) {
  211. config := &ClientConfig{
  212. User: "testuser",
  213. Auth: []AuthMethod{
  214. PublicKeys(),
  215. },
  216. Config: Config{
  217. Ciphers: []string{"aes128-cbc"}, // not currently supported
  218. },
  219. }
  220. if err := tryAuth(t, config); err == nil {
  221. t.Errorf("expected no ciphers in common")
  222. }
  223. }
  224. func TestClientUnsupportedKex(t *testing.T) {
  225. if os.Getenv("GO_BUILDER_NAME") != "" {
  226. t.Skip("skipping known-flaky test on the Go build dashboard; see golang.org/issue/15198")
  227. }
  228. config := &ClientConfig{
  229. User: "testuser",
  230. Auth: []AuthMethod{
  231. PublicKeys(),
  232. },
  233. Config: Config{
  234. KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
  235. },
  236. HostKeyCallback: InsecureIgnoreHostKey(),
  237. }
  238. if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
  239. t.Errorf("got %v, expected 'common algorithm'", err)
  240. }
  241. }
  242. func TestClientLoginCert(t *testing.T) {
  243. cert := &Certificate{
  244. Key: testPublicKeys["rsa"],
  245. ValidBefore: CertTimeInfinity,
  246. CertType: UserCert,
  247. }
  248. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  249. certSigner, err := NewCertSigner(cert, testSigners["rsa"])
  250. if err != nil {
  251. t.Fatalf("NewCertSigner: %v", err)
  252. }
  253. clientConfig := &ClientConfig{
  254. User: "user",
  255. HostKeyCallback: InsecureIgnoreHostKey(),
  256. }
  257. clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
  258. // should succeed
  259. if err := tryAuth(t, clientConfig); err != nil {
  260. t.Errorf("cert login failed: %v", err)
  261. }
  262. // corrupted signature
  263. cert.Signature.Blob[0]++
  264. if err := tryAuth(t, clientConfig); err == nil {
  265. t.Errorf("cert login passed with corrupted sig")
  266. }
  267. // revoked
  268. cert.Serial = 666
  269. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  270. if err := tryAuth(t, clientConfig); err == nil {
  271. t.Errorf("revoked cert login succeeded")
  272. }
  273. cert.Serial = 1
  274. // sign with wrong key
  275. cert.SignCert(rand.Reader, testSigners["dsa"])
  276. if err := tryAuth(t, clientConfig); err == nil {
  277. t.Errorf("cert login passed with non-authoritative key")
  278. }
  279. // host cert
  280. cert.CertType = HostCert
  281. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  282. if err := tryAuth(t, clientConfig); err == nil {
  283. t.Errorf("cert login passed with wrong type")
  284. }
  285. cert.CertType = UserCert
  286. // principal specified
  287. cert.ValidPrincipals = []string{"user"}
  288. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  289. if err := tryAuth(t, clientConfig); err != nil {
  290. t.Errorf("cert login failed: %v", err)
  291. }
  292. // wrong principal specified
  293. cert.ValidPrincipals = []string{"fred"}
  294. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  295. if err := tryAuth(t, clientConfig); err == nil {
  296. t.Errorf("cert login passed with wrong principal")
  297. }
  298. cert.ValidPrincipals = nil
  299. // added critical option
  300. cert.CriticalOptions = map[string]string{"root-access": "yes"}
  301. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  302. if err := tryAuth(t, clientConfig); err == nil {
  303. t.Errorf("cert login passed with unrecognized critical option")
  304. }
  305. // allowed source address
  306. cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
  307. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  308. if err := tryAuth(t, clientConfig); err != nil {
  309. t.Errorf("cert login with source-address failed: %v", err)
  310. }
  311. // disallowed source address
  312. cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
  313. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  314. if err := tryAuth(t, clientConfig); err == nil {
  315. t.Errorf("cert login with source-address succeeded")
  316. }
  317. }
  318. func testPermissionsPassing(withPermissions bool, t *testing.T) {
  319. serverConfig := &ServerConfig{
  320. PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
  321. if conn.User() == "nopermissions" {
  322. return nil, nil
  323. } else {
  324. return &Permissions{}, nil
  325. }
  326. },
  327. }
  328. serverConfig.AddHostKey(testSigners["rsa"])
  329. clientConfig := &ClientConfig{
  330. Auth: []AuthMethod{
  331. PublicKeys(testSigners["rsa"]),
  332. },
  333. HostKeyCallback: InsecureIgnoreHostKey(),
  334. }
  335. if withPermissions {
  336. clientConfig.User = "permissions"
  337. } else {
  338. clientConfig.User = "nopermissions"
  339. }
  340. c1, c2, err := netPipe()
  341. if err != nil {
  342. t.Fatalf("netPipe: %v", err)
  343. }
  344. defer c1.Close()
  345. defer c2.Close()
  346. go NewClientConn(c2, "", clientConfig)
  347. serverConn, err := newServer(c1, serverConfig)
  348. if err != nil {
  349. t.Fatal(err)
  350. }
  351. if p := serverConn.Permissions; (p != nil) != withPermissions {
  352. t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
  353. }
  354. }
  355. func TestPermissionsPassing(t *testing.T) {
  356. testPermissionsPassing(true, t)
  357. }
  358. func TestNoPermissionsPassing(t *testing.T) {
  359. testPermissionsPassing(false, t)
  360. }
  361. func TestRetryableAuth(t *testing.T) {
  362. n := 0
  363. passwords := []string{"WRONG1", "WRONG2"}
  364. config := &ClientConfig{
  365. User: "testuser",
  366. Auth: []AuthMethod{
  367. RetryableAuthMethod(PasswordCallback(func() (string, error) {
  368. p := passwords[n]
  369. n++
  370. return p, nil
  371. }), 2),
  372. PublicKeys(testSigners["rsa"]),
  373. },
  374. HostKeyCallback: InsecureIgnoreHostKey(),
  375. }
  376. if err := tryAuth(t, config); err != nil {
  377. t.Fatalf("unable to dial remote side: %s", err)
  378. }
  379. if n != 2 {
  380. t.Fatalf("Did not try all passwords")
  381. }
  382. }
  383. func ExampleRetryableAuthMethod(t *testing.T) {
  384. user := "testuser"
  385. NumberOfPrompts := 3
  386. // Normally this would be a callback that prompts the user to answer the
  387. // provided questions
  388. Cb := func(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
  389. return []string{"answer1", "answer2"}, nil
  390. }
  391. config := &ClientConfig{
  392. HostKeyCallback: InsecureIgnoreHostKey(),
  393. User: user,
  394. Auth: []AuthMethod{
  395. RetryableAuthMethod(KeyboardInteractiveChallenge(Cb), NumberOfPrompts),
  396. },
  397. }
  398. if err := tryAuth(t, config); err != nil {
  399. t.Fatalf("unable to dial remote side: %s", err)
  400. }
  401. }
  402. // Test if username is received on server side when NoClientAuth is used
  403. func TestClientAuthNone(t *testing.T) {
  404. user := "testuser"
  405. serverConfig := &ServerConfig{
  406. NoClientAuth: true,
  407. }
  408. serverConfig.AddHostKey(testSigners["rsa"])
  409. clientConfig := &ClientConfig{
  410. User: user,
  411. HostKeyCallback: InsecureIgnoreHostKey(),
  412. }
  413. c1, c2, err := netPipe()
  414. if err != nil {
  415. t.Fatalf("netPipe: %v", err)
  416. }
  417. defer c1.Close()
  418. defer c2.Close()
  419. go NewClientConn(c2, "", clientConfig)
  420. serverConn, err := newServer(c1, serverConfig)
  421. if err != nil {
  422. t.Fatalf("newServer: %v", err)
  423. }
  424. if serverConn.User() != user {
  425. t.Fatalf("server: got %q, want %q", serverConn.User(), user)
  426. }
  427. }