keys_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  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 TestParseRSAPrivateKey(t *testing.T) {
  98. key := testPrivateKeys["rsa"]
  99. rsa, ok := key.(*rsa.PrivateKey)
  100. if !ok {
  101. t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
  102. }
  103. if err := rsa.Validate(); err != nil {
  104. t.Errorf("Validate: %v", err)
  105. }
  106. }
  107. func TestParseECPrivateKey(t *testing.T) {
  108. key := testPrivateKeys["ecdsa"]
  109. ecKey, ok := key.(*ecdsa.PrivateKey)
  110. if !ok {
  111. t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey)
  112. }
  113. if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
  114. t.Fatalf("public key does not validate.")
  115. }
  116. }
  117. // See Issue https://github.com/golang/go/issues/6650.
  118. func TestParseEncryptedPrivateKeysFails(t *testing.T) {
  119. const wantSubstring = "encrypted"
  120. for i, tt := range testdata.PEMEncryptedKeys {
  121. _, err := ParsePrivateKey(tt.PEMBytes)
  122. if err == nil {
  123. t.Errorf("#%d key %s: ParsePrivateKey successfully parsed, expected an error", i, tt.Name)
  124. continue
  125. }
  126. if !strings.Contains(err.Error(), wantSubstring) {
  127. t.Errorf("#%d key %s: got error %q, want substring %q", i, tt.Name, err, wantSubstring)
  128. }
  129. }
  130. }
  131. // Parse encrypted private keys with passphrase
  132. func TestParseEncryptedPrivateKeysWithPassphrase(t *testing.T) {
  133. data := []byte("sign me")
  134. for _, tt := range testdata.PEMEncryptedKeys {
  135. s, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte(tt.EncryptionKey))
  136. if err != nil {
  137. t.Fatalf("ParsePrivateKeyWithPassphrase returned error: %s", err)
  138. continue
  139. }
  140. sig, err := s.Sign(rand.Reader, data)
  141. if err != nil {
  142. t.Fatalf("dsa.Sign: %v", err)
  143. }
  144. if err := s.PublicKey().Verify(data, sig); err != nil {
  145. t.Errorf("Verify failed: %v", err)
  146. }
  147. }
  148. tt := testdata.PEMEncryptedKeys[0]
  149. _, err := ParsePrivateKeyWithPassphrase(tt.PEMBytes, []byte("incorrect"))
  150. if err != x509.IncorrectPasswordError {
  151. t.Fatalf("got %v want IncorrectPasswordError", err)
  152. }
  153. }
  154. func TestParseDSA(t *testing.T) {
  155. // We actually exercise the ParsePrivateKey codepath here, as opposed to
  156. // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
  157. // uses.
  158. s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
  159. if err != nil {
  160. t.Fatalf("ParsePrivateKey returned error: %s", err)
  161. }
  162. data := []byte("sign me")
  163. sig, err := s.Sign(rand.Reader, data)
  164. if err != nil {
  165. t.Fatalf("dsa.Sign: %v", err)
  166. }
  167. if err := s.PublicKey().Verify(data, sig); err != nil {
  168. t.Errorf("Verify failed: %v", err)
  169. }
  170. }
  171. // Tests for authorized_keys parsing.
  172. // getTestKey returns a public key, and its base64 encoding.
  173. func getTestKey() (PublicKey, string) {
  174. k := testPublicKeys["rsa"]
  175. b := &bytes.Buffer{}
  176. e := base64.NewEncoder(base64.StdEncoding, b)
  177. e.Write(k.Marshal())
  178. e.Close()
  179. return k, b.String()
  180. }
  181. func TestMarshalParsePublicKey(t *testing.T) {
  182. pub, pubSerialized := getTestKey()
  183. line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
  184. authKeys := MarshalAuthorizedKey(pub)
  185. actualFields := strings.Fields(string(authKeys))
  186. if len(actualFields) == 0 {
  187. t.Fatalf("failed authKeys: %v", authKeys)
  188. }
  189. // drop the comment
  190. expectedFields := strings.Fields(line)[0:2]
  191. if !reflect.DeepEqual(actualFields, expectedFields) {
  192. t.Errorf("got %v, expected %v", actualFields, expectedFields)
  193. }
  194. actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
  195. if err != nil {
  196. t.Fatalf("cannot parse %v: %v", line, err)
  197. }
  198. if !reflect.DeepEqual(actPub, pub) {
  199. t.Errorf("got %v, expected %v", actPub, pub)
  200. }
  201. }
  202. type testAuthResult struct {
  203. pubKey PublicKey
  204. options []string
  205. comments string
  206. rest string
  207. ok bool
  208. }
  209. func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []testAuthResult) {
  210. rest := authKeys
  211. var values []testAuthResult
  212. for len(rest) > 0 {
  213. var r testAuthResult
  214. var err error
  215. r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
  216. r.ok = (err == nil)
  217. t.Log(err)
  218. r.rest = string(rest)
  219. values = append(values, r)
  220. }
  221. if !reflect.DeepEqual(values, expected) {
  222. t.Errorf("got %#v, expected %#v", values, expected)
  223. }
  224. }
  225. func TestAuthorizedKeyBasic(t *testing.T) {
  226. pub, pubSerialized := getTestKey()
  227. line := "ssh-rsa " + pubSerialized + " user@host"
  228. testAuthorizedKeys(t, []byte(line),
  229. []testAuthResult{
  230. {pub, nil, "user@host", "", true},
  231. })
  232. }
  233. func TestAuth(t *testing.T) {
  234. pub, pubSerialized := getTestKey()
  235. authWithOptions := []string{
  236. `# comments to ignore before any keys...`,
  237. ``,
  238. `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
  239. `# comments to ignore, along with a blank line`,
  240. ``,
  241. `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
  242. ``,
  243. `# more comments, plus a invalid entry`,
  244. `ssh-rsa data-that-will-not-parse user@host3`,
  245. }
  246. for _, eol := range []string{"\n", "\r\n"} {
  247. authOptions := strings.Join(authWithOptions, eol)
  248. rest2 := strings.Join(authWithOptions[3:], eol)
  249. rest3 := strings.Join(authWithOptions[6:], eol)
  250. testAuthorizedKeys(t, []byte(authOptions), []testAuthResult{
  251. {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
  252. {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
  253. {nil, nil, "", "", false},
  254. })
  255. }
  256. }
  257. func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
  258. pub, pubSerialized := getTestKey()
  259. authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
  260. testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []testAuthResult{
  261. {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
  262. })
  263. }
  264. func TestAuthWithQuotedCommaInEnv(t *testing.T) {
  265. pub, pubSerialized := getTestKey()
  266. authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
  267. testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []testAuthResult{
  268. {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
  269. })
  270. }
  271. func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
  272. pub, pubSerialized := getTestKey()
  273. authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`)
  274. authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
  275. testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []testAuthResult{
  276. {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
  277. })
  278. testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []testAuthResult{
  279. {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
  280. })
  281. }
  282. func TestAuthWithInvalidSpace(t *testing.T) {
  283. _, pubSerialized := getTestKey()
  284. authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
  285. #more to follow but still no valid keys`)
  286. testAuthorizedKeys(t, []byte(authWithInvalidSpace), []testAuthResult{
  287. {nil, nil, "", "", false},
  288. })
  289. }
  290. func TestAuthWithMissingQuote(t *testing.T) {
  291. pub, pubSerialized := getTestKey()
  292. authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
  293. env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
  294. testAuthorizedKeys(t, []byte(authWithMissingQuote), []testAuthResult{
  295. {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
  296. })
  297. }
  298. func TestInvalidEntry(t *testing.T) {
  299. authInvalid := []byte(`ssh-rsa`)
  300. _, _, _, _, err := ParseAuthorizedKey(authInvalid)
  301. if err == nil {
  302. t.Errorf("got valid entry for %q", authInvalid)
  303. }
  304. }
  305. var knownHostsParseTests = []struct {
  306. input string
  307. err string
  308. marker string
  309. comment string
  310. hosts []string
  311. rest string
  312. }{
  313. {
  314. "",
  315. "EOF",
  316. "", "", nil, "",
  317. },
  318. {
  319. "# Just a comment",
  320. "EOF",
  321. "", "", nil, "",
  322. },
  323. {
  324. " \t ",
  325. "EOF",
  326. "", "", nil, "",
  327. },
  328. {
  329. "localhost ssh-rsa {RSAPUB}",
  330. "",
  331. "", "", []string{"localhost"}, "",
  332. },
  333. {
  334. "localhost\tssh-rsa {RSAPUB}",
  335. "",
  336. "", "", []string{"localhost"}, "",
  337. },
  338. {
  339. "localhost\tssh-rsa {RSAPUB}\tcomment comment",
  340. "",
  341. "", "comment comment", []string{"localhost"}, "",
  342. },
  343. {
  344. "localhost\tssh-rsa {RSAPUB}\tcomment comment\n",
  345. "",
  346. "", "comment comment", []string{"localhost"}, "",
  347. },
  348. {
  349. "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n",
  350. "",
  351. "", "comment comment", []string{"localhost"}, "",
  352. },
  353. {
  354. "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line",
  355. "",
  356. "", "comment comment", []string{"localhost"}, "next line",
  357. },
  358. {
  359. "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
  360. "",
  361. "", "comment comment", []string{"localhost", "[host2:123]"}, "",
  362. },
  363. {
  364. "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
  365. "",
  366. "marker", "", []string{"localhost", "[host2:123]"}, "",
  367. },
  368. {
  369. "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
  370. "short read",
  371. "", "", nil, "",
  372. },
  373. }
  374. func TestKnownHostsParsing(t *testing.T) {
  375. rsaPub, rsaPubSerialized := getTestKey()
  376. for i, test := range knownHostsParseTests {
  377. var expectedKey PublicKey
  378. const rsaKeyToken = "{RSAPUB}"
  379. input := test.input
  380. if strings.Contains(input, rsaKeyToken) {
  381. expectedKey = rsaPub
  382. input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1)
  383. }
  384. marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input))
  385. if err != nil {
  386. if len(test.err) == 0 {
  387. t.Errorf("#%d: unexpectedly failed with %q", i, err)
  388. } else if !strings.Contains(err.Error(), test.err) {
  389. t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err)
  390. }
  391. continue
  392. } else if len(test.err) != 0 {
  393. t.Errorf("#%d: succeeded but expected error including %q", i, test.err)
  394. continue
  395. }
  396. if !reflect.DeepEqual(expectedKey, pubKey) {
  397. t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey)
  398. }
  399. if marker != test.marker {
  400. t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker)
  401. }
  402. if comment != test.comment {
  403. t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment)
  404. }
  405. if !reflect.DeepEqual(test.hosts, hosts) {
  406. t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts)
  407. }
  408. if rest := string(rest); rest != test.rest {
  409. t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest)
  410. }
  411. }
  412. }
  413. func TestFingerprintLegacyMD5(t *testing.T) {
  414. pub, _ := getTestKey()
  415. fingerprint := FingerprintLegacyMD5(pub)
  416. want := "fb:61:6d:1a:e3:f0:95:45:3c:a0:79:be:4a:93:63:66" // ssh-keygen -lf -E md5 rsa
  417. if fingerprint != want {
  418. t.Errorf("got fingerprint %q want %q", fingerprint, want)
  419. }
  420. }
  421. func TestFingerprintSHA256(t *testing.T) {
  422. pub, _ := getTestKey()
  423. fingerprint := FingerprintSHA256(pub)
  424. want := "SHA256:Anr3LjZK8YVpjrxu79myrW9Hrb/wpcMNpVvTq/RcBm8" // ssh-keygen -lf rsa
  425. if fingerprint != want {
  426. t.Errorf("got fingerprint %q want %q", fingerprint, want)
  427. }
  428. }
  429. func TestInvalidKeys(t *testing.T) {
  430. keyTypes := []string{
  431. "RSA PRIVATE KEY",
  432. "PRIVATE KEY",
  433. "EC PRIVATE KEY",
  434. "DSA PRIVATE KEY",
  435. "OPENSSH PRIVATE KEY",
  436. }
  437. for _, keyType := range keyTypes {
  438. for _, dataLen := range []int{0, 1, 2, 5, 10, 20} {
  439. data := make([]byte, dataLen)
  440. if _, err := io.ReadFull(rand.Reader, data); err != nil {
  441. t.Fatal(err)
  442. }
  443. var buf bytes.Buffer
  444. pem.Encode(&buf, &pem.Block{
  445. Type: keyType,
  446. Bytes: data,
  447. })
  448. // This test is just to ensure that the function
  449. // doesn't panic so the return value is ignored.
  450. ParseRawPrivateKey(buf.Bytes())
  451. }
  452. }
  453. }