cert_test.go 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  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 is in the block list")
  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 TestDecryptAndUnmarshalEd25519PrivateKey(t *testing.T) {
  496. passphrase := []byte("DO NOT USE THIS KEY")
  497. privKey := []byte(`# A good key
  498. -----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
  499. CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDT
  500. oCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl
  501. +Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPB
  502. qrlJ69wer3ZUHFXA
  503. -----END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
  504. `)
  505. shortKey := []byte(`# A key which, once decrypted, is too short
  506. -----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
  507. CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCoga5h8owMEBWRSMMJKzuUvWce7
  508. k0qlBkQmCxiuLh80MuASW70YcKt8jeEIS2axo2V6zAKA9TSMcCsJW1kDDXEtL/xe
  509. GLF5T7sDl5COp4LU3pGxpV+KoeQ/S3gQCAAcnaOtnJQX+aSDnbO3jCHyP7U9CHbs
  510. rQr3bdH3Oy/WiYU=
  511. -----END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
  512. `)
  513. invalidBanner := []byte(`# Invalid banner (not encrypted)
  514. -----BEGIN NEBULA ED25519 PRIVATE KEY-----
  515. bWRp2CTVFhW9HD/qCd28ltDgK3w8VXSeaEYczDWos8sMUBqDb9jP3+NYwcS4lURG
  516. XgLvodMXZJuaFPssp+WwtA==
  517. -----END NEBULA ED25519 PRIVATE KEY-----
  518. `)
  519. invalidPem := []byte(`# Not a valid PEM format
  520. -BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
  521. CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDT
  522. oCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl
  523. +Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPB
  524. qrlJ69wer3ZUHFXA
  525. -END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
  526. `)
  527. keyBundle := appendByteSlices(privKey, shortKey, invalidBanner, invalidPem)
  528. // Success test case
  529. k, rest, err := DecryptAndUnmarshalEd25519PrivateKey(passphrase, keyBundle)
  530. assert.Nil(t, err)
  531. assert.Len(t, k, 64)
  532. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  533. // Fail due to short key
  534. k, rest, err = DecryptAndUnmarshalEd25519PrivateKey(passphrase, rest)
  535. assert.EqualError(t, err, "key was not 64 bytes, is invalid ed25519 private key")
  536. assert.Nil(t, k)
  537. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  538. // Fail due to invalid banner
  539. k, rest, err = DecryptAndUnmarshalEd25519PrivateKey(passphrase, rest)
  540. assert.EqualError(t, err, "bytes did not contain a proper nebula encrypted Ed25519 private key banner")
  541. assert.Nil(t, k)
  542. assert.Equal(t, rest, invalidPem)
  543. // Fail due to ivalid PEM format, because
  544. // it's missing the requisite pre-encapsulation boundary.
  545. k, rest, err = DecryptAndUnmarshalEd25519PrivateKey(passphrase, rest)
  546. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  547. assert.Nil(t, k)
  548. assert.Equal(t, rest, invalidPem)
  549. // Fail due to invalid passphrase
  550. k, rest, err = DecryptAndUnmarshalEd25519PrivateKey([]byte("invalid passphrase"), privKey)
  551. assert.EqualError(t, err, "invalid passphrase or corrupt private key")
  552. assert.Nil(t, k)
  553. assert.Equal(t, rest, []byte{})
  554. }
  555. func TestEncryptAndMarshalEd25519PrivateKey(t *testing.T) {
  556. // Having proved that decryption works correctly above, we can test the
  557. // encryption function produces a value which can be decrypted
  558. passphrase := []byte("passphrase")
  559. bytes := []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
  560. kdfParams := NewArgon2Parameters(64*1024, 4, 3)
  561. key, err := EncryptAndMarshalEd25519PrivateKey(bytes, passphrase, kdfParams)
  562. assert.Nil(t, err)
  563. // Verify the "key" can be decrypted successfully
  564. k, rest, err := DecryptAndUnmarshalEd25519PrivateKey(passphrase, key)
  565. assert.Len(t, k, 64)
  566. assert.Equal(t, rest, []byte{})
  567. assert.Nil(t, err)
  568. // EncryptAndMarshalEd25519PrivateKey does not create any errors itself
  569. }
  570. func TestUnmarshalX25519PrivateKey(t *testing.T) {
  571. privKey := []byte(`# A good key
  572. -----BEGIN NEBULA X25519 PRIVATE KEY-----
  573. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  574. -----END NEBULA X25519 PRIVATE KEY-----
  575. `)
  576. shortKey := []byte(`# A short key
  577. -----BEGIN NEBULA X25519 PRIVATE KEY-----
  578. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  579. -----END NEBULA X25519 PRIVATE KEY-----
  580. `)
  581. invalidBanner := []byte(`# Invalid banner
  582. -----BEGIN NOT A NEBULA PRIVATE KEY-----
  583. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  584. -----END NOT A NEBULA PRIVATE KEY-----
  585. `)
  586. invalidPem := []byte(`# Not a valid PEM format
  587. -BEGIN NEBULA X25519 PRIVATE KEY-----
  588. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  589. -END NEBULA X25519 PRIVATE KEY-----`)
  590. keyBundle := appendByteSlices(privKey, shortKey, invalidBanner, invalidPem)
  591. // Success test case
  592. k, rest, err := UnmarshalX25519PrivateKey(keyBundle)
  593. assert.Len(t, k, 32)
  594. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  595. assert.Nil(t, err)
  596. // Fail due to short key
  597. k, rest, err = UnmarshalX25519PrivateKey(rest)
  598. assert.Nil(t, k)
  599. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  600. assert.EqualError(t, err, "key was not 32 bytes, is invalid X25519 private key")
  601. // Fail due to invalid banner
  602. k, rest, err = UnmarshalX25519PrivateKey(rest)
  603. assert.Nil(t, k)
  604. assert.Equal(t, rest, invalidPem)
  605. assert.EqualError(t, err, "bytes did not contain a proper nebula X25519 private key banner")
  606. // Fail due to ivalid PEM format, because
  607. // it's missing the requisite pre-encapsulation boundary.
  608. k, rest, err = UnmarshalX25519PrivateKey(rest)
  609. assert.Nil(t, k)
  610. assert.Equal(t, rest, invalidPem)
  611. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  612. }
  613. func TestUnmarshalEd25519PublicKey(t *testing.T) {
  614. pubKey := []byte(`# A good key
  615. -----BEGIN NEBULA ED25519 PUBLIC KEY-----
  616. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  617. -----END NEBULA ED25519 PUBLIC KEY-----
  618. `)
  619. shortKey := []byte(`# A short key
  620. -----BEGIN NEBULA ED25519 PUBLIC KEY-----
  621. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  622. -----END NEBULA ED25519 PUBLIC KEY-----
  623. `)
  624. invalidBanner := []byte(`# Invalid banner
  625. -----BEGIN NOT A NEBULA PUBLIC KEY-----
  626. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  627. -----END NOT A NEBULA PUBLIC KEY-----
  628. `)
  629. invalidPem := []byte(`# Not a valid PEM format
  630. -BEGIN NEBULA ED25519 PUBLIC KEY-----
  631. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  632. -END NEBULA ED25519 PUBLIC KEY-----`)
  633. keyBundle := appendByteSlices(pubKey, shortKey, invalidBanner, invalidPem)
  634. // Success test case
  635. k, rest, err := UnmarshalEd25519PublicKey(keyBundle)
  636. assert.Equal(t, len(k), 32)
  637. assert.Nil(t, err)
  638. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  639. // Fail due to short key
  640. k, rest, err = UnmarshalEd25519PublicKey(rest)
  641. assert.Nil(t, k)
  642. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  643. assert.EqualError(t, err, "key was not 32 bytes, is invalid ed25519 public key")
  644. // Fail due to invalid banner
  645. k, rest, err = UnmarshalEd25519PublicKey(rest)
  646. assert.Nil(t, k)
  647. assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519 public key banner")
  648. assert.Equal(t, rest, invalidPem)
  649. // Fail due to ivalid PEM format, because
  650. // it's missing the requisite pre-encapsulation boundary.
  651. k, rest, err = UnmarshalEd25519PublicKey(rest)
  652. assert.Nil(t, k)
  653. assert.Equal(t, rest, invalidPem)
  654. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  655. }
  656. func TestUnmarshalX25519PublicKey(t *testing.T) {
  657. pubKey := []byte(`# A good key
  658. -----BEGIN NEBULA X25519 PUBLIC KEY-----
  659. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  660. -----END NEBULA X25519 PUBLIC KEY-----
  661. `)
  662. shortKey := []byte(`# A short key
  663. -----BEGIN NEBULA X25519 PUBLIC KEY-----
  664. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
  665. -----END NEBULA X25519 PUBLIC KEY-----
  666. `)
  667. invalidBanner := []byte(`# Invalid banner
  668. -----BEGIN NOT A NEBULA PUBLIC KEY-----
  669. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  670. -----END NOT A NEBULA PUBLIC KEY-----
  671. `)
  672. invalidPem := []byte(`# Not a valid PEM format
  673. -BEGIN NEBULA X25519 PUBLIC KEY-----
  674. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
  675. -END NEBULA X25519 PUBLIC KEY-----`)
  676. keyBundle := appendByteSlices(pubKey, shortKey, invalidBanner, invalidPem)
  677. // Success test case
  678. k, rest, err := UnmarshalX25519PublicKey(keyBundle)
  679. assert.Equal(t, len(k), 32)
  680. assert.Nil(t, err)
  681. assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))
  682. // Fail due to short key
  683. k, rest, err = UnmarshalX25519PublicKey(rest)
  684. assert.Nil(t, k)
  685. assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))
  686. assert.EqualError(t, err, "key was not 32 bytes, is invalid X25519 public key")
  687. // Fail due to invalid banner
  688. k, rest, err = UnmarshalX25519PublicKey(rest)
  689. assert.Nil(t, k)
  690. assert.EqualError(t, err, "bytes did not contain a proper nebula X25519 public key banner")
  691. assert.Equal(t, rest, invalidPem)
  692. // Fail due to ivalid PEM format, because
  693. // it's missing the requisite pre-encapsulation boundary.
  694. k, rest, err = UnmarshalX25519PublicKey(rest)
  695. assert.Nil(t, k)
  696. assert.Equal(t, rest, invalidPem)
  697. assert.EqualError(t, err, "input did not contain a valid PEM encoded block")
  698. }
  699. // Ensure that upgrading the protobuf library does not change how certificates
  700. // are marshalled, since this would break signature verification
  701. func TestMarshalingNebulaCertificateConsistency(t *testing.T) {
  702. before := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
  703. after := time.Date(2017, time.January, 18, 28, 40, 0, 0, time.UTC)
  704. pubKey := []byte("1234567890abcedfghij1234567890ab")
  705. nc := NebulaCertificate{
  706. Details: NebulaCertificateDetails{
  707. Name: "testing",
  708. Ips: []*net.IPNet{
  709. {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  710. {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  711. {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  712. },
  713. Subnets: []*net.IPNet{
  714. {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},
  715. {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},
  716. {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},
  717. },
  718. Groups: []string{"test-group1", "test-group2", "test-group3"},
  719. NotBefore: before,
  720. NotAfter: after,
  721. PublicKey: pubKey,
  722. IsCA: false,
  723. Issuer: "1234567890abcedfghij1234567890ab",
  724. },
  725. Signature: []byte("1234567890abcedfghij1234567890ab"),
  726. }
  727. b, err := nc.Marshal()
  728. assert.Nil(t, err)
  729. //t.Log("Cert size:", len(b))
  730. assert.Equal(t, "0aa2010a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf1220313233343536373839306162636564666768696a313233343536373839306162", fmt.Sprintf("%x", b))
  731. b, err = proto.Marshal(nc.getRawDetails())
  732. assert.Nil(t, err)
  733. //t.Log("Raw cert size:", len(b))
  734. assert.Equal(t, "0a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf", fmt.Sprintf("%x", b))
  735. }
  736. func TestNebulaCertificate_Copy(t *testing.T) {
  737. ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
  738. assert.Nil(t, err)
  739. c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})
  740. assert.Nil(t, err)
  741. cc := c.Copy()
  742. test.AssertDeepCopyEqual(t, c, cc)
  743. }
  744. func TestUnmarshalNebulaCertificate(t *testing.T) {
  745. // Test that we don't panic with an invalid certificate (#332)
  746. data := []byte("\x98\x00\x00")
  747. _, err := UnmarshalNebulaCertificate(data)
  748. assert.EqualError(t, err, "encoded Details was nil")
  749. }
  750. func newTestCaCert(before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {
  751. pub, priv, err := ed25519.GenerateKey(rand.Reader)
  752. if before.IsZero() {
  753. before = time.Now().Add(time.Second * -60).Round(time.Second)
  754. }
  755. if after.IsZero() {
  756. after = time.Now().Add(time.Second * 60).Round(time.Second)
  757. }
  758. nc := &NebulaCertificate{
  759. Details: NebulaCertificateDetails{
  760. Name: "test ca",
  761. NotBefore: time.Unix(before.Unix(), 0),
  762. NotAfter: time.Unix(after.Unix(), 0),
  763. PublicKey: pub,
  764. IsCA: true,
  765. InvertedGroups: make(map[string]struct{}),
  766. },
  767. }
  768. if len(ips) > 0 {
  769. nc.Details.Ips = ips
  770. }
  771. if len(subnets) > 0 {
  772. nc.Details.Subnets = subnets
  773. }
  774. if len(groups) > 0 {
  775. nc.Details.Groups = groups
  776. }
  777. err = nc.Sign(priv)
  778. if err != nil {
  779. return nil, nil, nil, err
  780. }
  781. return nc, pub, priv, nil
  782. }
  783. func newTestCert(ca *NebulaCertificate, key []byte, before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {
  784. issuer, err := ca.Sha256Sum()
  785. if err != nil {
  786. return nil, nil, nil, err
  787. }
  788. if before.IsZero() {
  789. before = time.Now().Add(time.Second * -60).Round(time.Second)
  790. }
  791. if after.IsZero() {
  792. after = time.Now().Add(time.Second * 60).Round(time.Second)
  793. }
  794. if len(groups) == 0 {
  795. groups = []string{"test-group1", "test-group2", "test-group3"}
  796. }
  797. if len(ips) == 0 {
  798. ips = []*net.IPNet{
  799. {IP: net.ParseIP("10.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())},
  800. {IP: net.ParseIP("10.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())},
  801. {IP: net.ParseIP("10.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())},
  802. }
  803. }
  804. if len(subnets) == 0 {
  805. subnets = []*net.IPNet{
  806. {IP: net.ParseIP("9.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())},
  807. {IP: net.ParseIP("9.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())},
  808. {IP: net.ParseIP("9.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())},
  809. }
  810. }
  811. pub, rawPriv := x25519Keypair()
  812. nc := &NebulaCertificate{
  813. Details: NebulaCertificateDetails{
  814. Name: "testing",
  815. Ips: ips,
  816. Subnets: subnets,
  817. Groups: groups,
  818. NotBefore: time.Unix(before.Unix(), 0),
  819. NotAfter: time.Unix(after.Unix(), 0),
  820. PublicKey: pub,
  821. IsCA: false,
  822. Issuer: issuer,
  823. InvertedGroups: make(map[string]struct{}),
  824. },
  825. }
  826. err = nc.Sign(key)
  827. if err != nil {
  828. return nil, nil, nil, err
  829. }
  830. return nc, pub, rawPriv, nil
  831. }
  832. func x25519Keypair() ([]byte, []byte) {
  833. privkey := make([]byte, 32)
  834. if _, err := io.ReadFull(rand.Reader, privkey); err != nil {
  835. panic(err)
  836. }
  837. pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)
  838. if err != nil {
  839. panic(err)
  840. }
  841. return pubkey, privkey
  842. }