cert_test.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. package cert
  2. import (
  3. "crypto/rand"
  4. "fmt"
  5. "io"
  6. "net"
  7. "testing"
  8. "time"
  9. "github.com/slackhq/nebula/test"
  10. "github.com/stretchr/testify/assert"
  11. "golang.org/x/crypto/curve25519"
  12. "golang.org/x/crypto/ed25519"
  13. "google.golang.org/protobuf/proto"
  14. )
  15. func TestMarshalingNebulaCertificate(t *testing.T) {
  16. before := time.Now().Add(time.Second * -60).Round(time.Second)
  17. after := time.Now().Add(time.Second * 60).Round(time.Second)
  18. pubKey := []byte("1234567890abcedfghij1234567890ab")
  19. nc := NebulaCertificate{
  20. Details: NebulaCertificateDetails{
  21. Name: "testing",
  22. Ips: []*net.IPNet{
  23. {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  24. {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  25. {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  26. },
  27. Subnets: []*net.IPNet{
  28. {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  29. {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  30. {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  31. },
  32. Groups: []string{"test-group1", "test-group2", "test-group3"},
  33. NotBefore: before,
  34. NotAfter: after,
  35. PublicKey: pubKey,
  36. IsCA: false,
  37. Issuer: "1234567890abcedfghij1234567890ab",
  38. },
  39. Signature: []byte("1234567890abcedfghij1234567890ab"),
  40. }
  41. b, err := nc.Marshal()
  42. assert.Nil(t, err)
  43. //t.Log("Cert size:", len(b))
  44. nc2, err := UnmarshalNebulaCertificate(b)
  45. assert.Nil(t, err)
  46. assert.Equal(t, nc.Signature, nc2.Signature)
  47. assert.Equal(t, nc.Details.Name, nc2.Details.Name)
  48. assert.Equal(t, nc.Details.NotBefore, nc2.Details.NotBefore)
  49. assert.Equal(t, nc.Details.NotAfter, nc2.Details.NotAfter)
  50. assert.Equal(t, nc.Details.PublicKey, nc2.Details.PublicKey)
  51. assert.Equal(t, nc.Details.IsCA, nc2.Details.IsCA)
  52. // IP byte arrays can be 4 or 16 in length so we have to go this route
  53. assert.Equal(t, len(nc.Details.Ips), len(nc2.Details.Ips))
  54. for i, wIp := range nc.Details.Ips {
  55. assert.Equal(t, wIp.String(), nc2.Details.Ips[i].String())
  56. }
  57. assert.Equal(t, len(nc.Details.Subnets), len(nc2.Details.Subnets))
  58. for i, wIp := range nc.Details.Subnets {
  59. assert.Equal(t, wIp.String(), nc2.Details.Subnets[i].String())
  60. }
  61. assert.EqualValues(t, nc.Details.Groups, nc2.Details.Groups)
  62. }
  63. func TestNebulaCertificate_Sign(t *testing.T) {
  64. before := time.Now().Add(time.Second * -60).Round(time.Second)
  65. after := time.Now().Add(time.Second * 60).Round(time.Second)
  66. pubKey := []byte("1234567890abcedfghij1234567890ab")
  67. nc := NebulaCertificate{
  68. Details: NebulaCertificateDetails{
  69. Name: "testing",
  70. Ips: []*net.IPNet{
  71. {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  72. {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  73. {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  74. },
  75. Subnets: []*net.IPNet{
  76. {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  77. {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  78. {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  79. },
  80. Groups: []string{"test-group1", "test-group2", "test-group3"},
  81. NotBefore: before,
  82. NotAfter: after,
  83. PublicKey: pubKey,
  84. IsCA: false,
  85. Issuer: "1234567890abcedfghij1234567890ab",
  86. },
  87. }
  88. pub, priv, err := ed25519.GenerateKey(rand.Reader)
  89. assert.Nil(t, err)
  90. assert.False(t, nc.CheckSignature(pub))
  91. assert.Nil(t, nc.Sign(priv))
  92. assert.True(t, nc.CheckSignature(pub))
  93. _, err = nc.Marshal()
  94. assert.Nil(t, err)
  95. //t.Log("Cert size:", len(b))
  96. }
  97. func TestNebulaCertificate_Expired(t *testing.T) {
  98. nc := NebulaCertificate{
  99. Details: NebulaCertificateDetails{
  100. NotBefore: time.Now().Add(time.Second * -60).Round(time.Second),
  101. NotAfter: time.Now().Add(time.Second * 60).Round(time.Second),
  102. },
  103. }
  104. assert.True(t, nc.Expired(time.Now().Add(time.Hour)))
  105. assert.True(t, nc.Expired(time.Now().Add(-time.Hour)))
  106. assert.False(t, nc.Expired(time.Now()))
  107. }
  108. func TestNebulaCertificate_MarshalJSON(t *testing.T) {
  109. time.Local = time.UTC
  110. pubKey := []byte("1234567890abcedfghij1234567890ab")
  111. nc := NebulaCertificate{
  112. Details: NebulaCertificateDetails{
  113. Name: "testing",
  114. Ips: []*net.IPNet{
  115. {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  116. {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  117. {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  118. },
  119. Subnets: []*net.IPNet{
  120. {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  121. {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  122. {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  123. },
  124. Groups: []string{"test-group1", "test-group2", "test-group3"},
  125. NotBefore: time.Date(1, 0, 0, 1, 0, 0, 0, time.UTC),
  126. NotAfter: time.Date(1, 0, 0, 2, 0, 0, 0, time.UTC),
  127. PublicKey: pubKey,
  128. IsCA: false,
  129. Issuer: "1234567890abcedfghij1234567890ab",
  130. },
  131. Signature: []byte("1234567890abcedfghij1234567890ab"),
  132. }
  133. b, err := nc.MarshalJSON()
  134. assert.Nil(t, err)
  135. assert.Equal(
  136. t,
  137. "{\"details\":{\"groups\":[\"test-group1\",\"test-group2\",\"test-group3\"],\"ips\":[\"10.1.1.1/24\",\"10.1.1.2/16\",\"10.1.1.3/ff00ff00\"],\"isCa\":false,\"issuer\":\"1234567890abcedfghij1234567890ab\",\"name\":\"testing\",\"notAfter\":\"0000-11-30T02:00:00Z\",\"notBefore\":\"0000-11-30T01:00:00Z\",\"publicKey\":\"313233343536373839306162636564666768696a313233343536373839306162\",\"subnets\":[\"9.1.1.1/ff00ff00\",\"9.1.1.2/24\",\"9.1.1.3/16\"]},\"fingerprint\":\"26cb1c30ad7872c804c166b5150fa372f437aa3856b04edb4334b4470ec728e4\",\"signature\":\"313233343536373839306162636564666768696a313233343536373839306162\"}",
  138. string(b),
  139. )
  140. }
  141. func TestNebulaCertificate_Verify(t *testing.T) {
  142. ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
  143. assert.Nil(t, err)
  144. c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
  145. assert.Nil(t, err)
  146. h, err := ca.Sha256Sum()
  147. assert.Nil(t, err)
  148. caPool := NewCAPool()
  149. caPool.CAs[h] = ca
  150. f, err := c.Sha256Sum()
  151. assert.Nil(t, err)
  152. caPool.BlocklistFingerprint(f)
  153. v, err := c.Verify(time.Now(), caPool)
  154. assert.False(t, v)
  155. assert.EqualError(t, err, "certificate has been blocked")
  156. caPool.ResetCertBlocklist()
  157. v, err = c.Verify(time.Now(), caPool)
  158. assert.True(t, v)
  159. assert.Nil(t, err)
  160. v, err = c.Verify(time.Now().Add(time.Hour*1000), caPool)
  161. assert.False(t, v)
  162. assert.EqualError(t, err, "root certificate is expired")
  163. c, _, _, err = newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})
  164. assert.Nil(t, err)
  165. v, err = c.Verify(time.Now().Add(time.Minute*6), caPool)
  166. assert.False(t, v)
  167. assert.EqualError(t, err, "certificate is expired")
  168. // Test group assertion
  169. ca, _, caKey, err = newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "test2"})
  170. assert.Nil(t, err)
  171. caPem, err := ca.MarshalToPEM()
  172. assert.Nil(t, err)
  173. caPool = NewCAPool()
  174. caPool.AddCACertificate(caPem)
  175. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "bad"})
  176. assert.Nil(t, err)
  177. v, err = c.Verify(time.Now(), caPool)
  178. assert.False(t, v)
  179. assert.EqualError(t, err, "certificate contained a group not present on the signing ca: bad")
  180. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1"})
  181. assert.Nil(t, err)
  182. v, err = c.Verify(time.Now(), caPool)
  183. assert.True(t, v)
  184. assert.Nil(t, err)
  185. }
  186. func TestNebulaCertificate_Verify_IPs(t *testing.T) {
  187. _, caIp1, _ := net.ParseCIDR("10.0.0.0/16")
  188. _, caIp2, _ := net.ParseCIDR("192.168.0.0/24")
  189. ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{caIp1, caIp2}, []*net.IPNet{}, []string{"test"})
  190. assert.Nil(t, err)
  191. caPem, err := ca.MarshalToPEM()
  192. assert.Nil(t, err)
  193. caPool := NewCAPool()
  194. caPool.AddCACertificate(caPem)
  195. // ip is outside the network
  196. cIp1 := &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}
  197. cIp2 := &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 0, 0}}
  198. c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})
  199. assert.Nil(t, err)
  200. v, err := c.Verify(time.Now(), caPool)
  201. assert.False(t, v)
  202. assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.1.0.0/24")
  203. // ip is outside the network reversed order of above
  204. cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}
  205. cIp2 = &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}
  206. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})
  207. assert.Nil(t, err)
  208. v, err = c.Verify(time.Now(), caPool)
  209. assert.False(t, v)
  210. assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.1.0.0/24")
  211. // ip is within the network but mask is outside
  212. cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}
  213. cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}
  214. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})
  215. assert.Nil(t, err)
  216. v, err = c.Verify(time.Now(), caPool)
  217. assert.False(t, v)
  218. assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.0.1.0/15")
  219. // ip is within the network but mask is outside reversed order of above
  220. cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}
  221. cIp2 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}
  222. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})
  223. assert.Nil(t, err)
  224. v, err = c.Verify(time.Now(), caPool)
  225. assert.False(t, v)
  226. assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.0.1.0/15")
  227. // ip and mask are within the network
  228. cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 255, 0, 0}}
  229. cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 128}}
  230. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})
  231. assert.Nil(t, err)
  232. v, err = c.Verify(time.Now(), caPool)
  233. assert.True(t, v)
  234. assert.Nil(t, err)
  235. // Exact matches
  236. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp1, caIp2}, []*net.IPNet{}, []string{"test"})
  237. assert.Nil(t, err)
  238. v, err = c.Verify(time.Now(), caPool)
  239. assert.True(t, v)
  240. assert.Nil(t, err)
  241. // Exact matches reversed
  242. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp2, caIp1}, []*net.IPNet{}, []string{"test"})
  243. assert.Nil(t, err)
  244. v, err = c.Verify(time.Now(), caPool)
  245. assert.True(t, v)
  246. assert.Nil(t, err)
  247. // Exact matches reversed with just 1
  248. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp1}, []*net.IPNet{}, []string{"test"})
  249. assert.Nil(t, err)
  250. v, err = c.Verify(time.Now(), caPool)
  251. assert.True(t, v)
  252. assert.Nil(t, err)
  253. }
  254. func TestNebulaCertificate_Verify_Subnets(t *testing.T) {
  255. _, caIp1, _ := net.ParseCIDR("10.0.0.0/16")
  256. _, caIp2, _ := net.ParseCIDR("192.168.0.0/24")
  257. ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1, caIp2}, []string{"test"})
  258. assert.Nil(t, err)
  259. caPem, err := ca.MarshalToPEM()
  260. assert.Nil(t, err)
  261. caPool := NewCAPool()
  262. caPool.AddCACertificate(caPem)
  263. // ip is outside the network
  264. cIp1 := &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}
  265. cIp2 := &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 0, 0}}
  266. c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})
  267. assert.Nil(t, err)
  268. v, err := c.Verify(time.Now(), caPool)
  269. assert.False(t, v)
  270. assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.1.0.0/24")
  271. // ip is outside the network reversed order of above
  272. cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}
  273. cIp2 = &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}
  274. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})
  275. assert.Nil(t, err)
  276. v, err = c.Verify(time.Now(), caPool)
  277. assert.False(t, v)
  278. assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.1.0.0/24")
  279. // ip is within the network but mask is outside
  280. cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}
  281. cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}
  282. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})
  283. assert.Nil(t, err)
  284. v, err = c.Verify(time.Now(), caPool)
  285. assert.False(t, v)
  286. assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.0.1.0/15")
  287. // ip is within the network but mask is outside reversed order of above
  288. cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}
  289. cIp2 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}
  290. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})
  291. assert.Nil(t, err)
  292. v, err = c.Verify(time.Now(), caPool)
  293. assert.False(t, v)
  294. assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.0.1.0/15")
  295. // ip and mask are within the network
  296. cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 255, 0, 0}}
  297. cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 128}}
  298. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})
  299. assert.Nil(t, err)
  300. v, err = c.Verify(time.Now(), caPool)
  301. assert.True(t, v)
  302. assert.Nil(t, err)
  303. // Exact matches
  304. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1, caIp2}, []string{"test"})
  305. assert.Nil(t, err)
  306. v, err = c.Verify(time.Now(), caPool)
  307. assert.True(t, v)
  308. assert.Nil(t, err)
  309. // Exact matches reversed
  310. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp2, caIp1}, []string{"test"})
  311. assert.Nil(t, err)
  312. v, err = c.Verify(time.Now(), caPool)
  313. assert.True(t, v)
  314. assert.Nil(t, err)
  315. // Exact matches reversed with just 1
  316. c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1}, []string{"test"})
  317. assert.Nil(t, err)
  318. v, err = c.Verify(time.Now(), caPool)
  319. assert.True(t, v)
  320. assert.Nil(t, err)
  321. }
  322. func TestNebulaCertificate_VerifyPrivateKey(t *testing.T) {
  323. ca, _, caKey, err := newTestCaCert(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})
  324. assert.Nil(t, err)
  325. err = ca.VerifyPrivateKey(caKey)
  326. assert.Nil(t, err)
  327. _, _, caKey2, err := newTestCaCert(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})
  328. assert.Nil(t, err)
  329. err = ca.VerifyPrivateKey(caKey2)
  330. assert.NotNil(t, err)
  331. c, _, priv, err := newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})
  332. err = c.VerifyPrivateKey(priv)
  333. assert.Nil(t, err)
  334. _, priv2 := x25519Keypair()
  335. err = c.VerifyPrivateKey(priv2)
  336. assert.NotNil(t, err)
  337. }
  338. func TestNewCAPoolFromBytes(t *testing.T) {
  339. noNewLines := `
  340. # Current provisional, Remove once everything moves over to the real root.
  341. -----BEGIN NEBULA CERTIFICATE-----
  342. CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
  343. vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
  344. bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
  345. -----END NEBULA CERTIFICATE-----
  346. # root-ca01
  347. -----BEGIN NEBULA CERTIFICATE-----
  348. CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTG
  349. BVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf
  350. 8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF
  351. -----END NEBULA CERTIFICATE-----
  352. `
  353. withNewLines := `
  354. # Current provisional, Remove once everything moves over to the real root.
  355. -----BEGIN NEBULA CERTIFICATE-----
  356. CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
  357. vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
  358. bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
  359. -----END NEBULA CERTIFICATE-----
  360. # root-ca01
  361. -----BEGIN NEBULA CERTIFICATE-----
  362. CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTG
  363. BVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf
  364. 8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF
  365. -----END NEBULA CERTIFICATE-----
  366. `
  367. expired := `
  368. # expired certificate
  369. -----BEGIN NEBULA CERTIFICATE-----
  370. CjkKB2V4cGlyZWQouPmWjQYwufmWjQY6ILCRaoCkJlqHgv5jfDN4lzLHBvDzaQm4
  371. vZxfu144hmgjQAESQG4qlnZi8DncvD/LDZnLgJHOaX1DWCHHEh59epVsC+BNgTie
  372. WH1M9n4O7cFtGlM6sJJOS+rCVVEJ3ABS7+MPdQs=
  373. -----END NEBULA CERTIFICATE-----
  374. `
  375. rootCA := NebulaCertificate{
  376. Details: NebulaCertificateDetails{
  377. Name: "nebula root ca",
  378. },
  379. }
  380. rootCA01 := NebulaCertificate{
  381. Details: NebulaCertificateDetails{
  382. Name: "nebula root ca 01",
  383. },
  384. }
  385. p, err := NewCAPoolFromBytes([]byte(noNewLines))
  386. assert.Nil(t, err)
  387. assert.Equal(t, p.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name)
  388. assert.Equal(t, p.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name)
  389. pp, err := NewCAPoolFromBytes([]byte(withNewLines))
  390. assert.Nil(t, err)
  391. assert.Equal(t, pp.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name)
  392. assert.Equal(t, pp.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name)
  393. // expired cert, no valid certs
  394. ppp, err := NewCAPoolFromBytes([]byte(expired))
  395. assert.Equal(t, ErrExpired, err)
  396. assert.Equal(t, ppp.CAs[string("152070be6bb19bc9e3bde4c2f0e7d8f4ff5448b4c9856b8eccb314fade0229b0")].Details.Name, "expired")
  397. // expired cert, with valid certs
  398. pppp, err := NewCAPoolFromBytes(append([]byte(expired), noNewLines...))
  399. assert.Equal(t, ErrExpired, err)
  400. assert.Equal(t, pppp.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name)
  401. assert.Equal(t, pppp.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name)
  402. assert.Equal(t, pppp.CAs[string("152070be6bb19bc9e3bde4c2f0e7d8f4ff5448b4c9856b8eccb314fade0229b0")].Details.Name, "expired")
  403. assert.Equal(t, len(pppp.CAs), 3)
  404. }
  405. func appendByteSlices(b ...[]byte) []byte {
  406. retSlice := []byte{}
  407. for _, v := range b {
  408. retSlice = append(retSlice, v...)
  409. }
  410. return retSlice
  411. }
  412. func TestUnmrshalCertPEM(t *testing.T) {
  413. goodCert := []byte(`
  414. # A good cert
  415. -----BEGIN NEBULA CERTIFICATE-----
  416. CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
  417. vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
  418. bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
  419. -----END NEBULA CERTIFICATE-----
  420. `)
  421. badBanner := []byte(`# A bad banner
  422. -----BEGIN NOT A NEBULA CERTIFICATE-----
  423. CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
  424. vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
  425. bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
  426. -----END NOT A NEBULA CERTIFICATE-----
  427. `)
  428. invalidPem := []byte(`# Not a valid PEM format
  429. -BEGIN NEBULA CERTIFICATE-----
  430. CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
  431. vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
  432. bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
  433. -END NEBULA CERTIFICATE----`)
  434. certBundle := appendByteSlices(goodCert, badBanner, invalidPem)
  435. // Success test case
  436. cert, rest, err := UnmarshalNebulaCertificateFromPEM(certBundle)
  437. assert.NotNil(t, cert)
  438. assert.Equal(t, rest, append(badBanner, invalidPem...))
  439. assert.Nil(t, err)
  440. // Fail due to invalid banner.
  441. cert, rest, err = UnmarshalNebulaCertificateFromPEM(rest)
  442. assert.Nil(t, cert)
  443. assert.Equal(t, rest, invalidPem)
  444. assert.EqualError(t, err, "bytes did not contain a proper nebula certificate banner")
  445. // Fail due to ivalid PEM format, because
  446. // it's missing the requisite pre-encapsulation boundary.
  447. cert, rest, err = UnmarshalNebulaCertificateFromPEM(rest)
  448. assert.Nil(t, cert)
  449. assert.Equal(t, rest, invalidPem)
  450. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  451. }
  452. func TestUnmarshalEd25519PrivateKey(t *testing.T) {
  453. privKey := []byte(`# A good key
  454. -----BEGIN NEBULA ED25519 PRIVATE KEY-----
  455. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  456. -----END NEBULA ED25519 PRIVATE KEY-----
  457. `)
  458. shortKey := []byte(`# A short key
  459. -----BEGIN NEBULA ED25519 PRIVATE KEY-----
  460. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  461. -----END NEBULA ED25519 PRIVATE KEY-----
  462. `)
  463. invalidBanner := []byte(`# Invalid banner
  464. -----BEGIN NOT A NEBULA PRIVATE KEY-----
  465. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  466. -----END NOT A NEBULA PRIVATE KEY-----
  467. `)
  468. invalidPem := []byte(`# Not a valid PEM format
  469. -BEGIN NEBULA ED25519 PRIVATE KEY-----
  470. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  471. -END NEBULA ED25519 PRIVATE KEY-----`)
  472. keyBundle := appendByteSlices(privKey, shortKey, invalidBanner, invalidPem)
  473. // Success test case
  474. k, rest, err := UnmarshalEd25519PrivateKey(keyBundle)
  475. assert.Len(t, k, 64)
  476. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  477. assert.Nil(t, err)
  478. // Fail due to short key
  479. k, rest, err = UnmarshalEd25519PrivateKey(rest)
  480. assert.Nil(t, k)
  481. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  482. assert.EqualError(t, err, "key was not 64 bytes, is invalid ed25519 private key")
  483. // Fail due to invalid banner
  484. k, rest, err = UnmarshalEd25519PrivateKey(rest)
  485. assert.Nil(t, k)
  486. assert.Equal(t, rest, invalidPem)
  487. assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519 private key banner")
  488. // Fail due to ivalid PEM format, because
  489. // it's missing the requisite pre-encapsulation boundary.
  490. k, rest, err = UnmarshalEd25519PrivateKey(rest)
  491. assert.Nil(t, k)
  492. assert.Equal(t, rest, invalidPem)
  493. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  494. }
  495. func TestUnmarshalX25519PrivateKey(t *testing.T) {
  496. privKey := []byte(`# A good key
  497. -----BEGIN NEBULA X25519 PRIVATE KEY-----
  498. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  499. -----END NEBULA X25519 PRIVATE KEY-----
  500. `)
  501. shortKey := []byte(`# A short key
  502. -----BEGIN NEBULA X25519 PRIVATE KEY-----
  503. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  504. -----END NEBULA X25519 PRIVATE KEY-----
  505. `)
  506. invalidBanner := []byte(`# Invalid banner
  507. -----BEGIN NOT A NEBULA PRIVATE KEY-----
  508. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  509. -----END NOT A NEBULA PRIVATE KEY-----
  510. `)
  511. invalidPem := []byte(`# Not a valid PEM format
  512. -BEGIN NEBULA X25519 PRIVATE KEY-----
  513. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  514. -END NEBULA X25519 PRIVATE KEY-----`)
  515. keyBundle := appendByteSlices(privKey, shortKey, invalidBanner, invalidPem)
  516. // Success test case
  517. k, rest, err := UnmarshalX25519PrivateKey(keyBundle)
  518. assert.Len(t, k, 32)
  519. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  520. assert.Nil(t, err)
  521. // Fail due to short key
  522. k, rest, err = UnmarshalX25519PrivateKey(rest)
  523. assert.Nil(t, k)
  524. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  525. assert.EqualError(t, err, "key was not 32 bytes, is invalid X25519 private key")
  526. // Fail due to invalid banner
  527. k, rest, err = UnmarshalX25519PrivateKey(rest)
  528. assert.Nil(t, k)
  529. assert.Equal(t, rest, invalidPem)
  530. assert.EqualError(t, err, "bytes did not contain a proper nebula X25519 private key banner")
  531. // Fail due to ivalid PEM format, because
  532. // it's missing the requisite pre-encapsulation boundary.
  533. k, rest, err = UnmarshalX25519PrivateKey(rest)
  534. assert.Nil(t, k)
  535. assert.Equal(t, rest, invalidPem)
  536. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  537. }
  538. func TestUnmarshalEd25519PublicKey(t *testing.T) {
  539. pubKey := []byte(`# A good key
  540. -----BEGIN NEBULA ED25519 PUBLIC KEY-----
  541. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  542. -----END NEBULA ED25519 PUBLIC KEY-----
  543. `)
  544. shortKey := []byte(`# A short key
  545. -----BEGIN NEBULA ED25519 PUBLIC KEY-----
  546. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  547. -----END NEBULA ED25519 PUBLIC KEY-----
  548. `)
  549. invalidBanner := []byte(`# Invalid banner
  550. -----BEGIN NOT A NEBULA PUBLIC KEY-----
  551. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  552. -----END NOT A NEBULA PUBLIC KEY-----
  553. `)
  554. invalidPem := []byte(`# Not a valid PEM format
  555. -BEGIN NEBULA ED25519 PUBLIC KEY-----
  556. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  557. -END NEBULA ED25519 PUBLIC KEY-----`)
  558. keyBundle := appendByteSlices(pubKey, shortKey, invalidBanner, invalidPem)
  559. // Success test case
  560. k, rest, err := UnmarshalEd25519PublicKey(keyBundle)
  561. assert.Equal(t, len(k), 32)
  562. assert.Nil(t, err)
  563. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  564. // Fail due to short key
  565. k, rest, err = UnmarshalEd25519PublicKey(rest)
  566. assert.Nil(t, k)
  567. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  568. assert.EqualError(t, err, "key was not 32 bytes, is invalid ed25519 public key")
  569. // Fail due to invalid banner
  570. k, rest, err = UnmarshalEd25519PublicKey(rest)
  571. assert.Nil(t, k)
  572. assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519 public key banner")
  573. assert.Equal(t, rest, invalidPem)
  574. // Fail due to ivalid PEM format, because
  575. // it's missing the requisite pre-encapsulation boundary.
  576. k, rest, err = UnmarshalEd25519PublicKey(rest)
  577. assert.Nil(t, k)
  578. assert.Equal(t, rest, invalidPem)
  579. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  580. }
  581. func TestUnmarshalX25519PublicKey(t *testing.T) {
  582. pubKey := []byte(`# A good key
  583. -----BEGIN NEBULA X25519 PUBLIC KEY-----
  584. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  585. -----END NEBULA X25519 PUBLIC KEY-----
  586. `)
  587. shortKey := []byte(`# A short key
  588. -----BEGIN NEBULA X25519 PUBLIC KEY-----
  589. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  590. -----END NEBULA X25519 PUBLIC KEY-----
  591. `)
  592. invalidBanner := []byte(`# Invalid banner
  593. -----BEGIN NOT A NEBULA PUBLIC KEY-----
  594. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  595. -----END NOT A NEBULA PUBLIC KEY-----
  596. `)
  597. invalidPem := []byte(`# Not a valid PEM format
  598. -BEGIN NEBULA X25519 PUBLIC KEY-----
  599. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  600. -END NEBULA X25519 PUBLIC KEY-----`)
  601. keyBundle := appendByteSlices(pubKey, shortKey, invalidBanner, invalidPem)
  602. // Success test case
  603. k, rest, err := UnmarshalX25519PublicKey(keyBundle)
  604. assert.Equal(t, len(k), 32)
  605. assert.Nil(t, err)
  606. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  607. // Fail due to short key
  608. k, rest, err = UnmarshalX25519PublicKey(rest)
  609. assert.Nil(t, k)
  610. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  611. assert.EqualError(t, err, "key was not 32 bytes, is invalid X25519 public key")
  612. // Fail due to invalid banner
  613. k, rest, err = UnmarshalX25519PublicKey(rest)
  614. assert.Nil(t, k)
  615. assert.EqualError(t, err, "bytes did not contain a proper nebula X25519 public key banner")
  616. assert.Equal(t, rest, invalidPem)
  617. // Fail due to ivalid PEM format, because
  618. // it's missing the requisite pre-encapsulation boundary.
  619. k, rest, err = UnmarshalX25519PublicKey(rest)
  620. assert.Nil(t, k)
  621. assert.Equal(t, rest, invalidPem)
  622. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  623. }
  624. // Ensure that upgrading the protobuf library does not change how certificates
  625. // are marshalled, since this would break signature verification
  626. func TestMarshalingNebulaCertificateConsistency(t *testing.T) {
  627. before := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
  628. after := time.Date(2017, time.January, 18, 28, 40, 0, 0, time.UTC)
  629. pubKey := []byte("1234567890abcedfghij1234567890ab")
  630. nc := NebulaCertificate{
  631. Details: NebulaCertificateDetails{
  632. Name: "testing",
  633. Ips: []*net.IPNet{
  634. {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  635. {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  636. {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  637. },
  638. Subnets: []*net.IPNet{
  639. {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  640. {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  641. {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  642. },
  643. Groups: []string{"test-group1", "test-group2", "test-group3"},
  644. NotBefore: before,
  645. NotAfter: after,
  646. PublicKey: pubKey,
  647. IsCA: false,
  648. Issuer: "1234567890abcedfghij1234567890ab",
  649. },
  650. Signature: []byte("1234567890abcedfghij1234567890ab"),
  651. }
  652. b, err := nc.Marshal()
  653. assert.Nil(t, err)
  654. //t.Log("Cert size:", len(b))
  655. assert.Equal(t, "0aa2010a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf1220313233343536373839306162636564666768696a313233343536373839306162", fmt.Sprintf("%x", b))
  656. b, err = proto.Marshal(nc.getRawDetails())
  657. assert.Nil(t, err)
  658. //t.Log("Raw cert size:", len(b))
  659. assert.Equal(t, "0a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf", fmt.Sprintf("%x", b))
  660. }
  661. func TestNebulaCertificate_Copy(t *testing.T) {
  662. ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
  663. assert.Nil(t, err)
  664. c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
  665. assert.Nil(t, err)
  666. cc := c.Copy()
  667. test.AssertDeepCopyEqual(t, c, cc)
  668. }
  669. func TestUnmarshalNebulaCertificate(t *testing.T) {
  670. // Test that we don't panic with an invalid certificate (#332)
  671. data := []byte("\x98\x00\x00")
  672. _, err := UnmarshalNebulaCertificate(data)
  673. assert.EqualError(t, err, "encoded Details was nil")
  674. }
  675. func newTestCaCert(before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {
  676. pub, priv, err := ed25519.GenerateKey(rand.Reader)
  677. if before.IsZero() {
  678. before = time.Now().Add(time.Second * -60).Round(time.Second)
  679. }
  680. if after.IsZero() {
  681. after = time.Now().Add(time.Second * 60).Round(time.Second)
  682. }
  683. nc := &NebulaCertificate{
  684. Details: NebulaCertificateDetails{
  685. Name: "test ca",
  686. NotBefore: time.Unix(before.Unix(), 0),
  687. NotAfter: time.Unix(after.Unix(), 0),
  688. PublicKey: pub,
  689. IsCA: true,
  690. InvertedGroups: make(map[string]struct{}),
  691. },
  692. }
  693. if len(ips) > 0 {
  694. nc.Details.Ips = ips
  695. }
  696. if len(subnets) > 0 {
  697. nc.Details.Subnets = subnets
  698. }
  699. if len(groups) > 0 {
  700. nc.Details.Groups = groups
  701. }
  702. err = nc.Sign(priv)
  703. if err != nil {
  704. return nil, nil, nil, err
  705. }
  706. return nc, pub, priv, nil
  707. }
  708. func newTestCert(ca *NebulaCertificate, key []byte, before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {
  709. issuer, err := ca.Sha256Sum()
  710. if err != nil {
  711. return nil, nil, nil, err
  712. }
  713. if before.IsZero() {
  714. before = time.Now().Add(time.Second * -60).Round(time.Second)
  715. }
  716. if after.IsZero() {
  717. after = time.Now().Add(time.Second * 60).Round(time.Second)
  718. }
  719. if len(groups) == 0 {
  720. groups = []string{"test-group1", "test-group2", "test-group3"}
  721. }
  722. if len(ips) == 0 {
  723. ips = []*net.IPNet{
  724. {IP: net.ParseIP("10.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())},
  725. {IP: net.ParseIP("10.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())},
  726. {IP: net.ParseIP("10.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())},
  727. }
  728. }
  729. if len(subnets) == 0 {
  730. subnets = []*net.IPNet{
  731. {IP: net.ParseIP("9.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())},
  732. {IP: net.ParseIP("9.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())},
  733. {IP: net.ParseIP("9.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())},
  734. }
  735. }
  736. pub, rawPriv := x25519Keypair()
  737. nc := &NebulaCertificate{
  738. Details: NebulaCertificateDetails{
  739. Name: "testing",
  740. Ips: ips,
  741. Subnets: subnets,
  742. Groups: groups,
  743. NotBefore: time.Unix(before.Unix(), 0),
  744. NotAfter: time.Unix(after.Unix(), 0),
  745. PublicKey: pub,
  746. IsCA: false,
  747. Issuer: issuer,
  748. InvertedGroups: make(map[string]struct{}),
  749. },
  750. }
  751. err = nc.Sign(key)
  752. if err != nil {
  753. return nil, nil, nil, err
  754. }
  755. return nc, pub, rawPriv, nil
  756. }
  757. func x25519Keypair() ([]byte, []byte) {
  758. privkey := make([]byte, 32)
  759. if _, err := io.ReadFull(rand.Reader, privkey); err != nil {
  760. panic(err)
  761. }
  762. pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)
  763. if err != nil {
  764. panic(err)
  765. }
  766. return pubkey, privkey
  767. }