keys_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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. func TestParseDSA(t *testing.T) {
  115. // We actually exercise the ParsePrivateKey codepath here, as opposed to
  116. // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
  117. // uses.
  118. s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
  119. if err != nil {
  120. t.Fatalf("ParsePrivateKey returned error: %s", err)
  121. }
  122. data := []byte("sign me")
  123. sig, err := s.Sign(rand.Reader, data)
  124. if err != nil {
  125. t.Fatalf("dsa.Sign: %v", err)
  126. }
  127. if err := s.PublicKey().Verify(data, sig); err != nil {
  128. t.Errorf("Verify failed: %v", err)
  129. }
  130. }
  131. // Tests for authorized_keys parsing.
  132. // getTestKey returns a public key, and its base64 encoding.
  133. func getTestKey() (PublicKey, string) {
  134. k := testPublicKeys["rsa"]
  135. b := &bytes.Buffer{}
  136. e := base64.NewEncoder(base64.StdEncoding, b)
  137. e.Write(k.Marshal())
  138. e.Close()
  139. return k, b.String()
  140. }
  141. func TestMarshalParsePublicKey(t *testing.T) {
  142. pub, pubSerialized := getTestKey()
  143. line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
  144. authKeys := MarshalAuthorizedKey(pub)
  145. actualFields := strings.Fields(string(authKeys))
  146. if len(actualFields) == 0 {
  147. t.Fatalf("failed authKeys: %v", authKeys)
  148. }
  149. // drop the comment
  150. expectedFields := strings.Fields(line)[0:2]
  151. if !reflect.DeepEqual(actualFields, expectedFields) {
  152. t.Errorf("got %v, expected %v", actualFields, expectedFields)
  153. }
  154. actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
  155. if err != nil {
  156. t.Fatalf("cannot parse %v: %v", line, err)
  157. }
  158. if !reflect.DeepEqual(actPub, pub) {
  159. t.Errorf("got %v, expected %v", actPub, pub)
  160. }
  161. }
  162. type authResult struct {
  163. pubKey PublicKey
  164. options []string
  165. comments string
  166. rest string
  167. ok bool
  168. }
  169. func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
  170. rest := authKeys
  171. var values []authResult
  172. for len(rest) > 0 {
  173. var r authResult
  174. var err error
  175. r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
  176. r.ok = (err == nil)
  177. t.Log(err)
  178. r.rest = string(rest)
  179. values = append(values, r)
  180. }
  181. if !reflect.DeepEqual(values, expected) {
  182. t.Errorf("got %#v, expected %#v", values, expected)
  183. }
  184. }
  185. func TestAuthorizedKeyBasic(t *testing.T) {
  186. pub, pubSerialized := getTestKey()
  187. line := "ssh-rsa " + pubSerialized + " user@host"
  188. testAuthorizedKeys(t, []byte(line),
  189. []authResult{
  190. {pub, nil, "user@host", "", true},
  191. })
  192. }
  193. func TestAuth(t *testing.T) {
  194. pub, pubSerialized := getTestKey()
  195. authWithOptions := []string{
  196. `# comments to ignore before any keys...`,
  197. ``,
  198. `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
  199. `# comments to ignore, along with a blank line`,
  200. ``,
  201. `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
  202. ``,
  203. `# more comments, plus a invalid entry`,
  204. `ssh-rsa data-that-will-not-parse user@host3`,
  205. }
  206. for _, eol := range []string{"\n", "\r\n"} {
  207. authOptions := strings.Join(authWithOptions, eol)
  208. rest2 := strings.Join(authWithOptions[3:], eol)
  209. rest3 := strings.Join(authWithOptions[6:], eol)
  210. testAuthorizedKeys(t, []byte(authOptions), []authResult{
  211. {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
  212. {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
  213. {nil, nil, "", "", false},
  214. })
  215. }
  216. }
  217. func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
  218. pub, pubSerialized := getTestKey()
  219. authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
  220. testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
  221. {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
  222. })
  223. }
  224. func TestAuthWithQuotedCommaInEnv(t *testing.T) {
  225. pub, pubSerialized := getTestKey()
  226. authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
  227. testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
  228. {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
  229. })
  230. }
  231. func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
  232. pub, pubSerialized := getTestKey()
  233. authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`)
  234. authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
  235. testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
  236. {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
  237. })
  238. testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
  239. {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
  240. })
  241. }
  242. func TestAuthWithInvalidSpace(t *testing.T) {
  243. _, pubSerialized := getTestKey()
  244. authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
  245. #more to follow but still no valid keys`)
  246. testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
  247. {nil, nil, "", "", false},
  248. })
  249. }
  250. func TestAuthWithMissingQuote(t *testing.T) {
  251. pub, pubSerialized := getTestKey()
  252. authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
  253. env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
  254. testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
  255. {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
  256. })
  257. }
  258. func TestInvalidEntry(t *testing.T) {
  259. authInvalid := []byte(`ssh-rsa`)
  260. _, _, _, _, err := ParseAuthorizedKey(authInvalid)
  261. if err == nil {
  262. t.Errorf("got valid entry for %q", authInvalid)
  263. }
  264. }
  265. var knownHostsParseTests = []struct {
  266. input string
  267. err string
  268. marker string
  269. comment string
  270. hosts []string
  271. rest string
  272. } {
  273. {
  274. "",
  275. "EOF",
  276. "", "", nil, "",
  277. },
  278. {
  279. "# Just a comment",
  280. "EOF",
  281. "", "", nil, "",
  282. },
  283. {
  284. " \t ",
  285. "EOF",
  286. "", "", nil, "",
  287. },
  288. {
  289. "localhost ssh-rsa {RSAPUB}",
  290. "",
  291. "", "", []string{"localhost"}, "",
  292. },
  293. {
  294. "localhost\tssh-rsa {RSAPUB}",
  295. "",
  296. "", "", []string{"localhost"}, "",
  297. },
  298. {
  299. "localhost\tssh-rsa {RSAPUB}\tcomment comment",
  300. "",
  301. "", "comment comment", []string{"localhost"}, "",
  302. },
  303. {
  304. "localhost\tssh-rsa {RSAPUB}\tcomment comment\n",
  305. "",
  306. "", "comment comment", []string{"localhost"}, "",
  307. },
  308. {
  309. "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n",
  310. "",
  311. "", "comment comment", []string{"localhost"}, "",
  312. },
  313. {
  314. "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line",
  315. "",
  316. "", "comment comment", []string{"localhost"}, "next line",
  317. },
  318. {
  319. "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
  320. "",
  321. "", "comment comment", []string{"localhost","[host2:123]"}, "",
  322. },
  323. {
  324. "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
  325. "",
  326. "marker", "", []string{"localhost","[host2:123]"}, "",
  327. },
  328. {
  329. "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
  330. "short read",
  331. "", "", nil, "",
  332. },
  333. }
  334. func TestKnownHostsParsing(t *testing.T) {
  335. rsaPub, rsaPubSerialized := getTestKey()
  336. for i, test := range knownHostsParseTests {
  337. var expectedKey PublicKey
  338. const rsaKeyToken = "{RSAPUB}"
  339. input := test.input
  340. if strings.Contains(input, rsaKeyToken) {
  341. expectedKey = rsaPub
  342. input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1)
  343. }
  344. marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input))
  345. if err != nil {
  346. if len(test.err) == 0 {
  347. t.Errorf("#%d: unexpectedly failed with %q", i, err)
  348. } else if !strings.Contains(err.Error(), test.err) {
  349. t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err)
  350. }
  351. continue
  352. } else if len(test.err) != 0 {
  353. t.Errorf("#%d: succeeded but expected error including %q", i, test.err)
  354. continue
  355. }
  356. if !reflect.DeepEqual(expectedKey, pubKey) {
  357. t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey)
  358. }
  359. if marker != test.marker {
  360. t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker)
  361. }
  362. if comment != test.comment {
  363. t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment)
  364. }
  365. if !reflect.DeepEqual(test.hosts, hosts) {
  366. t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts)
  367. }
  368. if rest := string(rest); rest != test.rest {
  369. t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest)
  370. }
  371. }
  372. }