keys_test.go 13 KB

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