keys_test.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. package test
  2. import (
  3. "crypto/rsa"
  4. "crypto/x509"
  5. "encoding/pem"
  6. "reflect"
  7. "strings"
  8. "testing"
  9. "code.google.com/p/go.crypto/ssh"
  10. )
  11. var (
  12. validKey = `AAAAB3NzaC1yc2EAAAADAQABAAABAQDEX/dPu4PmtvgK3La9zioCEDrJ` +
  13. `yUr6xEIK7Pr+rLgydcqWTU/kt7w7gKjOw4vvzgHfjKl09CWyvgb+y5dCiTk` +
  14. `9MxI+erGNhs3pwaoS+EavAbawB7iEqYyTep3YaJK+4RJ4OX7ZlXMAIMrTL+` +
  15. `UVrK89t56hCkFYaAgo3VY+z6rb/b3bDBYtE1Y2tS7C3au73aDgeb9psIrSV` +
  16. `86ucKBTl5X62FnYiyGd++xCnLB6uLximM5OKXfLzJQNS/QyZyk12g3D8y69` +
  17. `Xw1GzCSKX1u1+MQboyf0HJcG2ryUCLHdcDVppApyHx2OLq53hlkQ/yxdflD` +
  18. `qCqAE4j+doagSsIfC1T2T`
  19. authWithOptions = []string{
  20. `# comments to ignore before any keys...`,
  21. ``,
  22. `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + validKey + ` user@host`,
  23. `# comments to ignore, along with a blank line`,
  24. ``,
  25. `env="HOME=/home/root2" ssh-rsa ` + validKey + ` user2@host2`,
  26. ``,
  27. `# more comments, plus a invalid entry`,
  28. `ssh-rsa data-that-will-not-parse user@host3`,
  29. }
  30. authOptions = strings.Join(authWithOptions, "\n")
  31. authWithCRLF = strings.Join(authWithOptions, "\r\n")
  32. authInvalid = []byte(`ssh-rsa`)
  33. authWithQuotedCommaInEnv = []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + validKey + ` user@host`)
  34. authWithQuotedSpaceInEnv = []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + validKey + ` user@host`)
  35. authWithQuotedQuoteInEnv = []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + validKey + ` user@host`)
  36. authWithDoubleQuotedQuote = []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + validKey + "\t" + `user@host`)
  37. authWithInvalidSpace = []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + validKey + ` user@host
  38. #more to follow but still no valid keys`)
  39. authWithMissingQuote = []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + validKey + ` user@host
  40. env="HOME=/home/root",shared-control ssh-rsa ` + validKey + ` user@host`)
  41. )
  42. func TestMarshalParsePublicKey(t *testing.T) {
  43. pub := getTestPublicKey(t)
  44. authKeys := ssh.MarshalAuthorizedKey(pub)
  45. actualFields := strings.Fields(string(authKeys))
  46. if len(actualFields) == 0 {
  47. t.Fatalf("failed authKeys: %v", authKeys)
  48. }
  49. // drop the comment
  50. expectedFields := strings.Fields(keys["authorized_keys"])[0:2]
  51. if !reflect.DeepEqual(actualFields, expectedFields) {
  52. t.Errorf("got %v, expected %v", actualFields, expectedFields)
  53. }
  54. actPub, _, _, _, ok := ssh.ParseAuthorizedKey([]byte(keys["authorized_keys"]))
  55. if !ok {
  56. t.Fatalf("cannot parse %v", keys["authorized_keys"])
  57. }
  58. if !reflect.DeepEqual(actPub, pub) {
  59. t.Errorf("got %v, expected %v", actPub, pub)
  60. }
  61. }
  62. type authResult struct {
  63. pubKey interface{} //*rsa.PublicKey
  64. options []string
  65. comments string
  66. rest string
  67. ok bool
  68. }
  69. func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
  70. rest := authKeys
  71. var values []authResult
  72. for len(rest) > 0 {
  73. var r authResult
  74. r.pubKey, r.comments, r.options, rest, r.ok = ssh.ParseAuthorizedKey(rest)
  75. r.rest = string(rest)
  76. values = append(values, r)
  77. }
  78. if !reflect.DeepEqual(values, expected) {
  79. t.Errorf("got %q, expected %q", values, expected)
  80. }
  81. }
  82. func getTestPublicKey(t *testing.T) *rsa.PublicKey {
  83. block, _ := pem.Decode([]byte(testClientPrivateKey))
  84. if block == nil {
  85. t.Fatalf("pem.Decode: %v", testClientPrivateKey)
  86. }
  87. priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
  88. if err != nil {
  89. t.Fatalf("x509.ParsePKCS1PrivateKey: %v", err)
  90. }
  91. return &priv.PublicKey
  92. }
  93. func TestAuth(t *testing.T) {
  94. pub := getTestPublicKey(t)
  95. rest2 := strings.Join(authWithOptions[3:], "\n")
  96. rest3 := strings.Join(authWithOptions[6:], "\n")
  97. testAuthorizedKeys(t, []byte(authOptions), []authResult{
  98. {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
  99. {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
  100. {nil, nil, "", "", false},
  101. })
  102. }
  103. func TestAuthWithCRLF(t *testing.T) {
  104. pub := getTestPublicKey(t)
  105. rest2 := strings.Join(authWithOptions[3:], "\r\n")
  106. rest3 := strings.Join(authWithOptions[6:], "\r\n")
  107. testAuthorizedKeys(t, []byte(authWithCRLF), []authResult{
  108. {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
  109. {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
  110. {nil, nil, "", "", false},
  111. })
  112. }
  113. func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
  114. pub := getTestPublicKey(t)
  115. testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
  116. {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
  117. })
  118. }
  119. func TestAuthWithQuotedCommaInEnv(t *testing.T) {
  120. pub := getTestPublicKey(t)
  121. testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
  122. {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
  123. })
  124. }
  125. func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
  126. pub := getTestPublicKey(t)
  127. testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
  128. {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
  129. })
  130. testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
  131. {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
  132. })
  133. }
  134. func TestAuthWithInvalidSpace(t *testing.T) {
  135. testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
  136. {nil, nil, "", "", false},
  137. })
  138. }
  139. func TestAuthWithMissingQuote(t *testing.T) {
  140. pub := getTestPublicKey(t)
  141. testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
  142. {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
  143. })
  144. }
  145. func TestInvalidEntry(t *testing.T) {
  146. _, _, _, _, ok := ssh.ParseAuthorizedKey(authInvalid)
  147. if ok {
  148. t.Errorf("Expected invalid entry, returned valid entry")
  149. }
  150. }