keys_test.go 15 KB

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