client_auth_test.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. "strings"
  11. "testing"
  12. )
  13. type keyboardInteractive map[string]string
  14. func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
  15. var answers []string
  16. for _, q := range questions {
  17. answers = append(answers, cr[q])
  18. }
  19. return answers, nil
  20. }
  21. // reused internally by tests
  22. var clientPassword = "tiger"
  23. // tryAuth runs a handshake with a given config against an SSH server
  24. // with config serverConfig
  25. func tryAuth(t *testing.T, config *ClientConfig) error {
  26. c1, c2, err := netPipe()
  27. if err != nil {
  28. t.Fatalf("netPipe: %v", err)
  29. }
  30. defer c1.Close()
  31. defer c2.Close()
  32. certChecker := CertChecker{
  33. IsAuthority: func(k PublicKey) bool {
  34. return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
  35. },
  36. UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
  37. if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
  38. return nil, nil
  39. }
  40. return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
  41. },
  42. IsRevoked: func(c *Certificate) bool {
  43. return c.Serial == 666
  44. },
  45. }
  46. serverConfig := &ServerConfig{
  47. PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
  48. if conn.User() == "testuser" && string(pass) == clientPassword {
  49. return nil, nil
  50. }
  51. return nil, errors.New("password auth failed")
  52. },
  53. PublicKeyCallback: certChecker.Authenticate,
  54. KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
  55. ans, err := challenge("user",
  56. "instruction",
  57. []string{"question1", "question2"},
  58. []bool{true, true})
  59. if err != nil {
  60. return nil, err
  61. }
  62. ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
  63. if ok {
  64. challenge("user", "motd", nil, nil)
  65. return nil, nil
  66. }
  67. return nil, errors.New("keyboard-interactive failed")
  68. },
  69. AuthLogCallback: func(conn ConnMetadata, method string, err error) {
  70. t.Logf("user %q, method %q: %v", conn.User(), method, err)
  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. }
  85. if err := tryAuth(t, config); err != nil {
  86. t.Fatalf("unable to dial remote side: %s", err)
  87. }
  88. }
  89. func TestAuthMethodPassword(t *testing.T) {
  90. config := &ClientConfig{
  91. User: "testuser",
  92. Auth: []AuthMethod{
  93. Password(clientPassword),
  94. },
  95. }
  96. if err := tryAuth(t, config); err != nil {
  97. t.Fatalf("unable to dial remote side: %s", err)
  98. }
  99. }
  100. func TestAuthMethodWrongPassword(t *testing.T) {
  101. config := &ClientConfig{
  102. User: "testuser",
  103. Auth: []AuthMethod{
  104. Password("wrong"),
  105. PublicKeys(testSigners["rsa"]),
  106. },
  107. }
  108. if err := tryAuth(t, config); err != nil {
  109. t.Fatalf("unable to dial remote side: %s", err)
  110. }
  111. }
  112. func TestAuthMethodKeyboardInteractive(t *testing.T) {
  113. answers := keyboardInteractive(map[string]string{
  114. "question1": "answer1",
  115. "question2": "answer2",
  116. })
  117. config := &ClientConfig{
  118. User: "testuser",
  119. Auth: []AuthMethod{
  120. KeyboardInteractive(answers.Challenge),
  121. },
  122. }
  123. if err := tryAuth(t, config); err != nil {
  124. t.Fatalf("unable to dial remote side: %s", err)
  125. }
  126. }
  127. func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
  128. answers := keyboardInteractive(map[string]string{
  129. "question1": "answer1",
  130. "question2": "WRONG",
  131. })
  132. config := &ClientConfig{
  133. User: "testuser",
  134. Auth: []AuthMethod{
  135. KeyboardInteractive(answers.Challenge),
  136. },
  137. }
  138. if err := tryAuth(t, config); err == nil {
  139. t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
  140. }
  141. }
  142. // the mock server will only authenticate ssh-rsa keys
  143. func TestAuthMethodInvalidPublicKey(t *testing.T) {
  144. config := &ClientConfig{
  145. User: "testuser",
  146. Auth: []AuthMethod{
  147. PublicKeys(testSigners["dsa"]),
  148. },
  149. }
  150. if err := tryAuth(t, config); err == nil {
  151. t.Fatalf("dsa private key should not have authenticated with rsa public key")
  152. }
  153. }
  154. // the client should authenticate with the second key
  155. func TestAuthMethodRSAandDSA(t *testing.T) {
  156. config := &ClientConfig{
  157. User: "testuser",
  158. Auth: []AuthMethod{
  159. PublicKeys(testSigners["dsa"], testSigners["rsa"]),
  160. },
  161. }
  162. if err := tryAuth(t, config); err != nil {
  163. t.Fatalf("client could not authenticate with rsa key: %v", err)
  164. }
  165. }
  166. func TestClientHMAC(t *testing.T) {
  167. for _, mac := range supportedMACs {
  168. config := &ClientConfig{
  169. User: "testuser",
  170. Auth: []AuthMethod{
  171. PublicKeys(testSigners["rsa"]),
  172. },
  173. Config: Config{
  174. MACs: []string{mac},
  175. },
  176. }
  177. if err := tryAuth(t, config); err != nil {
  178. t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
  179. }
  180. }
  181. }
  182. // issue 4285.
  183. func TestClientUnsupportedCipher(t *testing.T) {
  184. config := &ClientConfig{
  185. User: "testuser",
  186. Auth: []AuthMethod{
  187. PublicKeys(),
  188. },
  189. Config: Config{
  190. Ciphers: []string{"aes128-cbc"}, // not currently supported
  191. },
  192. }
  193. if err := tryAuth(t, config); err == nil {
  194. t.Errorf("expected no ciphers in common")
  195. }
  196. }
  197. func TestClientUnsupportedKex(t *testing.T) {
  198. config := &ClientConfig{
  199. User: "testuser",
  200. Auth: []AuthMethod{
  201. PublicKeys(),
  202. },
  203. Config: Config{
  204. KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
  205. },
  206. }
  207. if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "no common algorithms") {
  208. t.Errorf("got %v, expected 'no common algorithms'", err)
  209. }
  210. }
  211. func TestClientLoginCert(t *testing.T) {
  212. cert := &Certificate{
  213. Key: testPublicKeys["rsa"],
  214. ValidBefore: CertTimeInfinity,
  215. CertType: UserCert,
  216. }
  217. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  218. certSigner, err := NewCertSigner(cert, testSigners["rsa"])
  219. if err != nil {
  220. t.Fatalf("NewCertSigner: %v", err)
  221. }
  222. clientConfig := &ClientConfig{
  223. User: "user",
  224. }
  225. clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
  226. t.Log("should succeed")
  227. if err := tryAuth(t, clientConfig); err != nil {
  228. t.Errorf("cert login failed: %v", err)
  229. }
  230. t.Log("corrupted signature")
  231. cert.Signature.Blob[0]++
  232. if err := tryAuth(t, clientConfig); err == nil {
  233. t.Errorf("cert login passed with corrupted sig")
  234. }
  235. t.Log("revoked")
  236. cert.Serial = 666
  237. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  238. if err := tryAuth(t, clientConfig); err == nil {
  239. t.Errorf("revoked cert login succeeded")
  240. }
  241. cert.Serial = 1
  242. t.Log("sign with wrong key")
  243. cert.SignCert(rand.Reader, testSigners["dsa"])
  244. if err := tryAuth(t, clientConfig); err == nil {
  245. t.Errorf("cert login passed with non-authoritive key")
  246. }
  247. t.Log("host cert")
  248. cert.CertType = HostCert
  249. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  250. if err := tryAuth(t, clientConfig); err == nil {
  251. t.Errorf("cert login passed with wrong type")
  252. }
  253. cert.CertType = UserCert
  254. t.Log("principal specified")
  255. cert.ValidPrincipals = []string{"user"}
  256. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  257. if err := tryAuth(t, clientConfig); err != nil {
  258. t.Errorf("cert login failed: %v", err)
  259. }
  260. t.Log("wrong principal specified")
  261. cert.ValidPrincipals = []string{"fred"}
  262. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  263. if err := tryAuth(t, clientConfig); err == nil {
  264. t.Errorf("cert login passed with wrong principal")
  265. }
  266. cert.ValidPrincipals = nil
  267. t.Log("added critical option")
  268. cert.CriticalOptions = map[string]string{"root-access": "yes"}
  269. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  270. if err := tryAuth(t, clientConfig); err == nil {
  271. t.Errorf("cert login passed with unrecognized critical option")
  272. }
  273. t.Log("allowed source address")
  274. cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24"}
  275. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  276. if err := tryAuth(t, clientConfig); err != nil {
  277. t.Errorf("cert login with source-address failed: %v", err)
  278. }
  279. t.Log("disallowed source address")
  280. cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42"}
  281. cert.SignCert(rand.Reader, testSigners["ecdsa"])
  282. if err := tryAuth(t, clientConfig); err == nil {
  283. t.Errorf("cert login with source-address succeeded")
  284. }
  285. }