You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

501 line
13 KiB

  1. // Copyright 2014 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/dsa"
  8. "crypto/ecdsa"
  9. "crypto/elliptic"
  10. "crypto/rand"
  11. "crypto/rsa"
  12. "crypto/x509"
  13. "encoding/base64"
  14. "fmt"
  15. "reflect"
  16. "strings"
  17. "testing"
  18. "golang.org/x/crypto/ed25519"
  19. "golang.org/x/crypto/ssh/testdata"
  20. )
  21. func rawKey(pub PublicKey) interface{} {
  22. switch k := pub.(type) {
  23. case *rsaPublicKey:
  24. return (*rsa.PublicKey)(k)
  25. case *dsaPublicKey:
  26. return (*dsa.PublicKey)(k)
  27. case *ecdsaPublicKey:
  28. return (*ecdsa.PublicKey)(k)
  29. case ed25519PublicKey:
  30. return (ed25519.PublicKey)(k)
  31. case *Certificate:
  32. return k
  33. }
  34. panic("unknown key type")
  35. }
  36. func TestKeyMarshalParse(t *testing.T) {
  37. for _, priv := range testSigners {
  38. pub := priv.PublicKey()
  39. roundtrip, err := ParsePublicKey(pub.Marshal())
  40. if err != nil {
  41. t.Errorf("ParsePublicKey(%T): %v", pub, err)
  42. }
  43. k1 := rawKey(pub)
  44. k2 := rawKey(roundtrip)
  45. if !reflect.DeepEqual(k1, k2) {
  46. t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
  47. }
  48. }
  49. }
  50. func TestUnsupportedCurves(t *testing.T) {
  51. raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
  52. if err != nil {
  53. t.Fatalf("GenerateKey: %v", err)
  54. }
  55. if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P-256") {
  56. t.Fatalf("NewPrivateKey should not succeed with P-224, got: %v", err)
  57. }
  58. if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P-256") {
  59. t.Fatalf("NewPublicKey should not succeed with P-224, got: %v", err)
  60. }
  61. }
  62. func TestNewPublicKey(t *testing.T) {
  63. for _, k := range testSigners {
  64. raw := rawKey(k.PublicKey())
  65. // Skip certificates, as NewPublicKey does not support them.
  66. if _, ok := raw.(*Certificate); ok {
  67. continue
  68. }
  69. pub, err := NewPublicKey(raw)
  70. if err != nil {
  71. t.Errorf("NewPublicKey(%#v): %v", raw, err)
  72. }
  73. if !reflect.DeepEqual(k.PublicKey(), pub) {
  74. t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
  75. }
  76. }
  77. }
  78. func TestKeySignVerify(t *testing.T) {
  79. for _, priv := range testSigners {
  80. pub := priv.PublicKey()
  81. data := []byte("sign me")
  82. sig, err := priv.Sign(rand.Reader, data)
  83. if err != nil {
  84. t.Fatalf("Sign(%T): %v", priv, err)
  85. }
  86. if err := pub.Verify(data, sig); err != nil {
  87. t.Errorf("publicKey.Verify(%T): %v", priv, err)
  88. }
  89. sig.Blob[5]++
  90. if err := pub.Verify(data, sig); err == nil {
  91. t.Errorf("publicKey.Verify on broken sig did not fail")
  92. }
  93. }
  94. }
  95. func TestParseRSAPrivateKey(t *testing.T) {
  96. key := testPrivateKeys["rsa"]
  97. rsa, ok := key.(*rsa.PrivateKey)
  98. if !ok {
  99. t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
  100. }
  101. if err := rsa.Validate(); err != nil {
  102. t.Errorf("Validate: %v", err)
  103. }
  104. }
  105. func TestParseECPrivateKey(t *testing.T) {
  106. key := testPrivateKeys["ecdsa"]
  107. ecKey, ok := key.(*ecdsa.PrivateKey)
  108. if !ok {
  109. t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey)
  110. }
  111. if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
  112. t.Fatalf("public key does not validate.")
  113. }
  114. }
  115. // See Issue https://github.com/golang/go/issues/6650.
  116. func TestParseEncryptedPrivateKeysFails(t *testing.T) {
  117. const wantSubstring = "encrypted"
  118. for i, tt := range testdata.PEMEncryptedKeys {
  119. _, err := ParsePrivateKey(tt.PEMBytes)
  120. if err == nil {
  121. t.Errorf("#%d key %s: ParsePrivateKey successfully parsed, expected an error", i, tt.Name)
  122. continue
  123. }
  124. if !strings.Contains(err.Error(), wantSubstring) {
  125. t.Errorf("#%d key %s: got error %q, want substring %q", i, tt.Name, err, wantSubstring)
  126. }
  127. }
  128. }
  129. // Parse encrypted private keys with passphrase
  130. func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) {
  131. data := []byte("sign me")
  132. for _, tt := range testdata.PEMEncryptedKeys {
  133. s, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey))
  134. if err != nil {
  135. t.Fatalf("ParsePrivateKeyWithPassphrase returned error: %s", err)
  136. continue
  137. }
  138. sig, err := s.Sign(rand.Reader, data)
  139. if err != nil {
  140. t.Fatalf("dsa.Sign: %v", err)
  141. }
  142. if err := s.PublicKey().Verify(data, sig); err != nil {
  143. t.Errorf("Verify failed: %v", err)
  144. }
  145. }
  146. tt := testdata.PEMEncryptedKeys[0]
  147. _, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte("incorrect"))
  148. if err != x509.IncorrectPasswordError {
  149. t.Fatalf("got %v want IncorrectPasswordError", err)
  150. }
  151. }
  152. func TestParseDSA(t *testing.T) {
  153. // We actually exercise the ParsePrivateKey codepath here, as opposed to
  154. // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
  155. // uses.
  156. s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
  157. if err != nil {
  158. t.Fatalf("ParsePrivateKey returned error: %s", err)
  159. }
  160. data := []byte("sign me")
  161. sig, err := s.Sign(rand.Reader, data)
  162. if err != nil {
  163. t.Fatalf("dsa.Sign: %v", err)
  164. }
  165. if err := s.PublicKey().Verify(data, sig); err != nil {
  166. t.Errorf("Verify failed: %v", err)
  167. }
  168. }
  169. // Tests for authorized_keys parsing.
  170. // getTestKey returns a public key, and its base64 encoding.
  171. func getTestKey() (PublicKey, string) {
  172. k := testPublicKeys["rsa"]
  173. b := &bytes.Buffer{}
  174. e := base64.NewEncoder(base64.StdEncoding, b)
  175. e.Write(k.Marshal())
  176. e.Close()
  177. return k, b.String()
  178. }
  179. func TestMarshalParsePublicKey(t *testing.T) {
  180. pub, pubSerialized := getTestKey()
  181. line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
  182. authKeys := MarshalAuthorizedKey(pub)
  183. actualFields := strings.Fields(string(authKeys))
  184. if len(actualFields) == 0 {
  185. t.Fatalf("failed authKeys: %v", authKeys)
  186. }
  187. // drop the comment
  188. expectedFields := strings.Fields(line)[0:2]
  189. if !reflect.DeepEqual(actualFields, expectedFields) {
  190. t.Errorf("got %v, expected %v", actualFields, expectedFields)
  191. }
  192. actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
  193. if err != nil {
  194. t.Fatalf("cannot parse %v: %v", line, err)
  195. }
  196. if !reflect.DeepEqual(actPub, pub) {
  197. t.Errorf("got %v, expected %v", actPub, pub)
  198. }
  199. }
  200. type testAuthResult struct {
  201. pubKey PublicKey
  202. options []string
  203. comments string
  204. rest string
  205. ok bool
  206. }
  207. func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []testAuthResult) {
  208. rest := authKeys
  209. var values []testAuthResult
  210. for len(rest) > 0 {
  211. var r testAuthResult
  212. var err error
  213. r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
  214. r.ok = (err == nil)
  215. t.Log(err)
  216. r.rest = string(rest)
  217. values = append(values, r)
  218. }
  219. if !reflect.DeepEqual(values, expected) {
  220. t.Errorf("got %#v, expected %#v", values, expected)
  221. }
  222. }
  223. func TestAuthorizedKeyBasic(t *testing.T) {
  224. pub, pubSerialized := getTestKey()
  225. line := "ssh-rsa " + pubSerialized + " user@host"
  226. testAuthorizedKeys(t, []byte(line),
  227. []testAuthResult{
  228. {pub, nil, "user@host", "", true},
  229. })
  230. }
  231. func TestAuth(t *testing.T) {
  232. pub, pubSerialized := getTestKey()
  233. authWithOptions := []string{
  234. `# comments to ignore before any keys...`,
  235. ``,
  236. `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
  237. `# comments to ignore, along with a blank line`,
  238. ``,
  239. `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
  240. ``,
  241. `# more comments, plus a invalid entry`,
  242. `ssh-rsa data-that-will-not-parse user@host3`,
  243. }
  244. for _, eol := range []string{"\n", "\r\n"} {
  245. authOptions := strings.Join(authWithOptions, eol)
  246. rest2 := strings.Join(authWithOptions[3:], eol)
  247. rest3 := strings.Join(authWithOptions[6:], eol)
  248. testAuthorizedKeys(t, []byte(authOptions), []testAuthResult{
  249. {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
  250. {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
  251. {nil, nil, "", "", false},
  252. })
  253. }
  254. }
  255. func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
  256. pub, pubSerialized := getTestKey()
  257. authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
  258. testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []testAuthResult{
  259. {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
  260. })
  261. }
  262. func TestAuthWithQuotedCommaInEnv(t *testing.T) {
  263. pub, pubSerialized := getTestKey()
  264. authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
  265. testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []testAuthResult{
  266. {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
  267. })
  268. }
  269. func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
  270. pub, pubSerialized := getTestKey()
  271. authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`)
  272. authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
  273. testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []testAuthResult{
  274. {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
  275. })
  276. testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []testAuthResult{
  277. {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
  278. })
  279. }
  280. func TestAuthWithInvalidSpace(t *testing.T) {
  281. _, pubSerialized := getTestKey()
  282. authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
  283. #more to follow but still no valid keys`)
  284. testAuthorizedKeys(t, []byte(authWithInvalidSpace), []testAuthResult{
  285. {nil, nil, "", "", false},
  286. })
  287. }
  288. func TestAuthWithMissingQuote(t *testing.T) {
  289. pub, pubSerialized := getTestKey()
  290. authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
  291. env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
  292. testAuthorizedKeys(t, []byte(authWithMissingQuote), []testAuthResult{
  293. {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
  294. })
  295. }
  296. func TestInvalidEntry(t *testing.T) {
  297. authInvalid := []byte(`ssh-rsa`)
  298. _, _, _, _, err := ParseAuthorizedKey(authInvalid)
  299. if err == nil {
  300. t.Errorf("got valid entry for %q", authInvalid)
  301. }
  302. }
  303. var knownHostsParseTests = []struct {
  304. input string
  305. err string
  306. marker string
  307. comment string
  308. hosts []string
  309. rest string
  310. }{
  311. {
  312. "",
  313. "EOF",
  314. "", "", nil, "",
  315. },
  316. {
  317. "# Just a comment",
  318. "EOF",
  319. "", "", nil, "",
  320. },
  321. {
  322. " \t ",
  323. "EOF",
  324. "", "", nil, "",
  325. },
  326. {
  327. "localhost ssh-rsa {RSAPUB}",
  328. "",
  329. "", "", []string{"localhost"}, "",
  330. },
  331. {
  332. "localhost\tssh-rsa {RSAPUB}",
  333. "",
  334. "", "", []string{"localhost"}, "",
  335. },
  336. {
  337. "localhost\tssh-rsa {RSAPUB}\tcomment comment",
  338. "",
  339. "", "comment comment", []string{"localhost"}, "",
  340. },
  341. {
  342. "localhost\tssh-rsa {RSAPUB}\tcomment comment\n",
  343. "",
  344. "", "comment comment", []string{"localhost"}, "",
  345. },
  346. {
  347. "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n",
  348. "",
  349. "", "comment comment", []string{"localhost"}, "",
  350. },
  351. {
  352. "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line",
  353. "",
  354. "", "comment comment", []string{"localhost"}, "next line",
  355. },
  356. {
  357. "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
  358. "",
  359. "", "comment comment", []string{"localhost", "[host2:123]"}, "",
  360. },
  361. {
  362. "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
  363. "",
  364. "marker", "", []string{"localhost", "[host2:123]"}, "",
  365. },
  366. {
  367. "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
  368. "short read",
  369. "", "", nil, "",
  370. },
  371. }
  372. func TestKnownHostsParsing(t *testing.T) {
  373. rsaPub, rsaPubSerialized := getTestKey()
  374. for i, test := range knownHostsParseTests {
  375. var expectedKey PublicKey
  376. const rsaKeyToken = "{RSAPUB}"
  377. input := test.input
  378. if strings.Contains(input, rsaKeyToken) {
  379. expectedKey = rsaPub
  380. input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1)
  381. }
  382. marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input))
  383. if err != nil {
  384. if len(test.err) == 0 {
  385. t.Errorf("#%d: unexpectedly failed with %q", i, err)
  386. } else if !strings.Contains(err.Error(), test.err) {
  387. t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err)
  388. }
  389. continue
  390. } else if len(test.err) != 0 {
  391. t.Errorf("#%d: succeeded but expected error including %q", i, test.err)
  392. continue
  393. }
  394. if !reflect.DeepEqual(expectedKey, pubKey) {
  395. t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey)
  396. }
  397. if marker != test.marker {
  398. t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker)
  399. }
  400. if comment != test.comment {
  401. t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment)
  402. }
  403. if !reflect.DeepEqual(test.hosts, hosts) {
  404. t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts)
  405. }
  406. if rest := string(rest); rest != test.rest {
  407. t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest)
  408. }
  409. }
  410. }
  411. func TestFingerprintLegacyMD5(t *testing.T) {
  412. pub, _ := getTestKey()
  413. fingerprint := FingerprintLegacyMD5(pub)
  414. want := "fb:61:6d:1a:e3:f0:95:45:3c:a0:79:be:4a:93:63:66" // ssh-keygen -lf -E md5 rsa
  415. if fingerprint != want {
  416. t.Errorf("got fingerprint %q want %q", fingerprint, want)
  417. }
  418. }
  419. func TestFingerprintSHA256(t *testing.T) {
  420. pub, _ := getTestKey()
  421. fingerprint := FingerprintSHA256(pub)
  422. want := "SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8" // ssh-keygen -lf rsa
  423. if fingerprint != want {
  424. t.Errorf("got fingerprint %q want %q", fingerprint, want)
  425. }
  426. }