You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

357 lines
9.9 KiB

  1. // Copyright 2017 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 knownhosts
  5. import (
  6. "bytes"
  7. "fmt"
  8. "net"
  9. "reflect"
  10. "testing"
  11. "golang.org/x/crypto/ssh"
  12. )
  13. const edKeyStr = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGBAarftlLeoyf+v+nVchEZII/vna2PCV8FaX4vsF5BX"
  14. const alternateEdKeyStr = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIXffBYeYL+WVzVru8npl5JHt2cjlr4ornFTWzoij9sx"
  15. const ecKeyStr = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNLCu01+wpXe3xB5olXCN4SqU2rQu0qjSRKJO4Bg+JRCPU+ENcgdA5srTU8xYDz/GEa4dzK5ldPw4J/gZgSXCMs="
  16. var ecKey, alternateEdKey, edKey ssh.PublicKey
  17. var testAddr = &net.TCPAddr{
  18. IP: net.IP{198, 41, 30, 196},
  19. Port: 22,
  20. }
  21. var testAddr6 = &net.TCPAddr{
  22. IP: net.IP{198, 41, 30, 196,
  23. 1, 2, 3, 4,
  24. 1, 2, 3, 4,
  25. 1, 2, 3, 4,
  26. },
  27. Port: 22,
  28. }
  29. func init() {
  30. var err error
  31. ecKey, _, _, _, err = ssh.ParseAuthorizedKey([]byte(ecKeyStr))
  32. if err != nil {
  33. panic(err)
  34. }
  35. edKey, _, _, _, err = ssh.ParseAuthorizedKey([]byte(edKeyStr))
  36. if err != nil {
  37. panic(err)
  38. }
  39. alternateEdKey, _, _, _, err = ssh.ParseAuthorizedKey([]byte(alternateEdKeyStr))
  40. if err != nil {
  41. panic(err)
  42. }
  43. }
  44. func testDB(t *testing.T, s string) *hostKeyDB {
  45. db := newHostKeyDB()
  46. if err := db.Read(bytes.NewBufferString(s), "testdb"); err != nil {
  47. t.Fatalf("Read: %v", err)
  48. }
  49. return db
  50. }
  51. func TestRevoked(t *testing.T) {
  52. db := testDB(t, "\n\n@revoked * "+edKeyStr+"\n")
  53. want := &RevokedError{
  54. Revoked: KnownKey{
  55. Key: edKey,
  56. Filename: "testdb",
  57. Line: 3,
  58. },
  59. }
  60. if err := db.check("", &net.TCPAddr{
  61. Port: 42,
  62. }, edKey); err == nil {
  63. t.Fatal("no error for revoked key")
  64. } else if !reflect.DeepEqual(want, err) {
  65. t.Fatalf("got %#v, want %#v", want, err)
  66. }
  67. }
  68. func TestHostAuthority(t *testing.T) {
  69. for _, m := range []struct {
  70. authorityFor string
  71. address string
  72. good bool
  73. }{
  74. {authorityFor: "localhost", address: "localhost:22", good: true},
  75. {authorityFor: "localhost", address: "localhost", good: false},
  76. {authorityFor: "localhost", address: "localhost:1234", good: false},
  77. {authorityFor: "[localhost]:1234", address: "localhost:1234", good: true},
  78. {authorityFor: "[localhost]:1234", address: "localhost:22", good: false},
  79. {authorityFor: "[localhost]:1234", address: "localhost", good: false},
  80. } {
  81. db := testDB(t, `@cert-authority `+m.authorityFor+` `+edKeyStr)
  82. if ok := db.IsHostAuthority(db.lines[0].knownKey.Key, m.address); ok != m.good {
  83. t.Errorf("IsHostAuthority: authority %s, address %s, wanted good = %v, got good = %v",
  84. m.authorityFor, m.address, m.good, ok)
  85. }
  86. }
  87. }
  88. func TestBracket(t *testing.T) {
  89. db := testDB(t, `[git.eclipse.org]:29418,[198.41.30.196]:29418 `+edKeyStr)
  90. if err := db.check("git.eclipse.org:29418", &net.TCPAddr{
  91. IP: net.IP{198, 41, 30, 196},
  92. Port: 29418,
  93. }, edKey); err != nil {
  94. t.Errorf("got error %v, want none", err)
  95. }
  96. if err := db.check("git.eclipse.org:29419", &net.TCPAddr{
  97. Port: 42,
  98. }, edKey); err == nil {
  99. t.Fatalf("no error for unknown address")
  100. } else if ke, ok := err.(*KeyError); !ok {
  101. t.Fatalf("got type %T, want *KeyError", err)
  102. } else if len(ke.Want) > 0 {
  103. t.Fatalf("got Want %v, want []", ke.Want)
  104. }
  105. }
  106. func TestNewKeyType(t *testing.T) {
  107. str := fmt.Sprintf("%s %s", testAddr, edKeyStr)
  108. db := testDB(t, str)
  109. if err := db.check("", testAddr, ecKey); err == nil {
  110. t.Fatalf("no error for unknown address")
  111. } else if ke, ok := err.(*KeyError); !ok {
  112. t.Fatalf("got type %T, want *KeyError", err)
  113. } else if len(ke.Want) == 0 {
  114. t.Fatalf("got empty KeyError.Want")
  115. }
  116. }
  117. func TestSameKeyType(t *testing.T) {
  118. str := fmt.Sprintf("%s %s", testAddr, edKeyStr)
  119. db := testDB(t, str)
  120. if err := db.check("", testAddr, alternateEdKey); err == nil {
  121. t.Fatalf("no error for unknown address")
  122. } else if ke, ok := err.(*KeyError); !ok {
  123. t.Fatalf("got type %T, want *KeyError", err)
  124. } else if len(ke.Want) == 0 {
  125. t.Fatalf("got empty KeyError.Want")
  126. } else if got, want := ke.Want[0].Key.Marshal(), edKey.Marshal(); !bytes.Equal(got, want) {
  127. t.Fatalf("got key %q, want %q", got, want)
  128. }
  129. }
  130. func TestIPAddress(t *testing.T) {
  131. str := fmt.Sprintf("%s %s", testAddr, edKeyStr)
  132. db := testDB(t, str)
  133. if err := db.check("", testAddr, edKey); err != nil {
  134. t.Errorf("got error %q, want none", err)
  135. }
  136. }
  137. func TestIPv6Address(t *testing.T) {
  138. str := fmt.Sprintf("%s %s", testAddr6, edKeyStr)
  139. db := testDB(t, str)
  140. if err := db.check("", testAddr6, edKey); err != nil {
  141. t.Errorf("got error %q, want none", err)
  142. }
  143. }
  144. func TestBasic(t *testing.T) {
  145. str := fmt.Sprintf("#comment\n\nserver.org,%s %s\notherhost %s", testAddr, edKeyStr, ecKeyStr)
  146. db := testDB(t, str)
  147. if err := db.check("server.org:22", testAddr, edKey); err != nil {
  148. t.Errorf("got error %v, want none", err)
  149. }
  150. want := KnownKey{
  151. Key: edKey,
  152. Filename: "testdb",
  153. Line: 3,
  154. }
  155. if err := db.check("server.org:22", testAddr, ecKey); err == nil {
  156. t.Errorf("succeeded, want KeyError")
  157. } else if ke, ok := err.(*KeyError); !ok {
  158. t.Errorf("got %T, want *KeyError", err)
  159. } else if len(ke.Want) != 1 {
  160. t.Errorf("got %v, want 1 entry", ke)
  161. } else if !reflect.DeepEqual(ke.Want[0], want) {
  162. t.Errorf("got %v, want %v", ke.Want[0], want)
  163. }
  164. }
  165. func TestHostNamePrecedence(t *testing.T) {
  166. var evilAddr = &net.TCPAddr{
  167. IP: net.IP{66, 66, 66, 66},
  168. Port: 22,
  169. }
  170. str := fmt.Sprintf("server.org,%s %s\nevil.org,%s %s", testAddr, edKeyStr, evilAddr, ecKeyStr)
  171. db := testDB(t, str)
  172. if err := db.check("server.org:22", evilAddr, ecKey); err == nil {
  173. t.Errorf("check succeeded")
  174. } else if _, ok := err.(*KeyError); !ok {
  175. t.Errorf("got %T, want *KeyError", err)
  176. }
  177. }
  178. func TestDBOrderingPrecedenceKeyType(t *testing.T) {
  179. str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr)
  180. db := testDB(t, str)
  181. if err := db.check("server.org:22", testAddr, alternateEdKey); err == nil {
  182. t.Errorf("check succeeded")
  183. } else if _, ok := err.(*KeyError); !ok {
  184. t.Errorf("got %T, want *KeyError", err)
  185. }
  186. }
  187. func TestNegate(t *testing.T) {
  188. str := fmt.Sprintf("%s,!server.org %s", testAddr, edKeyStr)
  189. db := testDB(t, str)
  190. if err := db.check("server.org:22", testAddr, ecKey); err == nil {
  191. t.Errorf("succeeded")
  192. } else if ke, ok := err.(*KeyError); !ok {
  193. t.Errorf("got error type %T, want *KeyError", err)
  194. } else if len(ke.Want) != 0 {
  195. t.Errorf("got expected keys %d (first of type %s), want []", len(ke.Want), ke.Want[0].Key.Type())
  196. }
  197. }
  198. func TestWildcard(t *testing.T) {
  199. str := fmt.Sprintf("server*.domain %s", edKeyStr)
  200. db := testDB(t, str)
  201. want := &KeyError{
  202. Want: []KnownKey{{
  203. Filename: "testdb",
  204. Line: 1,
  205. Key: edKey,
  206. }},
  207. }
  208. got := db.check("server.domain:22", &net.TCPAddr{}, ecKey)
  209. if !reflect.DeepEqual(got, want) {
  210. t.Errorf("got %s, want %s", got, want)
  211. }
  212. }
  213. func TestLine(t *testing.T) {
  214. for in, want := range map[string]string{
  215. "server.org": "server.org " + edKeyStr,
  216. "server.org:22": "server.org " + edKeyStr,
  217. "server.org:23": "[server.org]:23 " + edKeyStr,
  218. "[c629:1ec4:102:304:102:304:102:304]:22": "[c629:1ec4:102:304:102:304:102:304] " + edKeyStr,
  219. "[c629:1ec4:102:304:102:304:102:304]:23": "[c629:1ec4:102:304:102:304:102:304]:23 " + edKeyStr,
  220. } {
  221. if got := Line([]string{in}, edKey); got != want {
  222. t.Errorf("Line(%q) = %q, want %q", in, got, want)
  223. }
  224. }
  225. }
  226. func TestWildcardMatch(t *testing.T) {
  227. for _, c := range []struct {
  228. pat, str string
  229. want bool
  230. }{
  231. {"a?b", "abb", true},
  232. {"ab", "abc", false},
  233. {"abc", "ab", false},
  234. {"a*b", "axxxb", true},
  235. {"a*b", "axbxb", true},
  236. {"a*b", "axbxbc", false},
  237. {"a*?", "axbxc", true},
  238. {"a*b*", "axxbxxxxxx", true},
  239. {"a*b*c", "axxbxxxxxxc", true},
  240. {"a*b*?", "axxbxxxxxxc", true},
  241. {"a*b*z", "axxbxxbxxxz", true},
  242. {"a*b*z", "axxbxxzxxxz", true},
  243. {"a*b*z", "axxbxxzxxx", false},
  244. } {
  245. got := wildcardMatch([]byte(c.pat), []byte(c.str))
  246. if got != c.want {
  247. t.Errorf("wildcardMatch(%q, %q) = %v, want %v", c.pat, c.str, got, c.want)
  248. }
  249. }
  250. }
  251. // TODO(hanwen): test coverage for certificates.
  252. const testHostname = "hostname"
  253. // generated with keygen -H -f
  254. const encodedTestHostnameHash = "|1|IHXZvQMvTcZTUU29+2vXFgx8Frs=|UGccIWfRVDwilMBnA3WJoRAC75Y="
  255. func TestHostHash(t *testing.T) {
  256. testHostHash(t, testHostname, encodedTestHostnameHash)
  257. }
  258. func TestHashList(t *testing.T) {
  259. encoded := HashHostname(testHostname)
  260. testHostHash(t, testHostname, encoded)
  261. }
  262. func testHostHash(t *testing.T, hostname, encoded string) {
  263. typ, salt, hash, err := decodeHash(encoded)
  264. if err != nil {
  265. t.Fatalf("decodeHash: %v", err)
  266. }
  267. if got := encodeHash(typ, salt, hash); got != encoded {
  268. t.Errorf("got encoding %s want %s", got, encoded)
  269. }
  270. if typ != sha1HashType {
  271. t.Fatalf("got hash type %q, want %q", typ, sha1HashType)
  272. }
  273. got := hashHost(hostname, salt)
  274. if !bytes.Equal(got, hash) {
  275. t.Errorf("got hash %x want %x", got, hash)
  276. }
  277. }
  278. func TestNormalize(t *testing.T) {
  279. for in, want := range map[string]string{
  280. "127.0.0.1:22": "127.0.0.1",
  281. "[127.0.0.1]:22": "127.0.0.1",
  282. "[127.0.0.1]:23": "[127.0.0.1]:23",
  283. "127.0.0.1:23": "[127.0.0.1]:23",
  284. "[a.b.c]:22": "a.b.c",
  285. "[abcd:abcd:abcd:abcd]": "[abcd:abcd:abcd:abcd]",
  286. "[abcd:abcd:abcd:abcd]:22": "[abcd:abcd:abcd:abcd]",
  287. "[abcd:abcd:abcd:abcd]:23": "[abcd:abcd:abcd:abcd]:23",
  288. } {
  289. got := Normalize(in)
  290. if got != want {
  291. t.Errorf("Normalize(%q) = %q, want %q", in, got, want)
  292. }
  293. }
  294. }
  295. func TestHashedHostkeyCheck(t *testing.T) {
  296. str := fmt.Sprintf("%s %s", HashHostname(testHostname), edKeyStr)
  297. db := testDB(t, str)
  298. if err := db.check(testHostname+":22", testAddr, edKey); err != nil {
  299. t.Errorf("check(%s): %v", testHostname, err)
  300. }
  301. want := &KeyError{
  302. Want: []KnownKey{{
  303. Filename: "testdb",
  304. Line: 1,
  305. Key: edKey,
  306. }},
  307. }
  308. if got := db.check(testHostname+":22", testAddr, alternateEdKey); !reflect.DeepEqual(got, want) {
  309. t.Errorf("got error %v, want %v", got, want)
  310. }
  311. }