ca_pool_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. package cert
  2. import (
  3. "net/netip"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. )
  8. func TestNewCAPoolFromBytes(t *testing.T) {
  9. noNewLines := `
  10. # Current provisional, Remove once everything moves over to the real root.
  11. -----BEGIN NEBULA CERTIFICATE-----
  12. Cj4KDm5lYnVsYSByb290IGNhKM0cMM24zPCvBzogV24YEw5YiqeI/oYo8XXFsoo+
  13. PBmiOafNJhLacf9rsspAARJAz9OAnh8TKAUKix1kKVMyQU4iM3LsFfZRf6ODWXIf
  14. 2qWMpB6fpd3PSoVYziPoOt2bIHIFLlgRLPJz3I3xBEdBCQ==
  15. -----END NEBULA CERTIFICATE-----
  16. # root-ca01
  17. -----BEGIN NEBULA CERTIFICATE-----
  18. CkEKEW5lYnVsYSByb290IGNhIDAxKM0cMM24zPCvBzogPzbWTxt8ZgXPQEwup7Br
  19. BrtIt1O0q5AuTRT3+t2x1VJAARJAZ+2ib23qBXjdy49oU1YysrwuKkWWKrtJ7Jye
  20. rFBQpDXikOukhQD/mfkloFwJ+Yjsfru7IpTN4ZfjXL+kN/2sCA==
  21. -----END NEBULA CERTIFICATE-----
  22. `
  23. withNewLines := `
  24. # Current provisional, Remove once everything moves over to the real root.
  25. -----BEGIN NEBULA CERTIFICATE-----
  26. Cj4KDm5lYnVsYSByb290IGNhKM0cMM24zPCvBzogV24YEw5YiqeI/oYo8XXFsoo+
  27. PBmiOafNJhLacf9rsspAARJAz9OAnh8TKAUKix1kKVMyQU4iM3LsFfZRf6ODWXIf
  28. 2qWMpB6fpd3PSoVYziPoOt2bIHIFLlgRLPJz3I3xBEdBCQ==
  29. -----END NEBULA CERTIFICATE-----
  30. # root-ca01
  31. -----BEGIN NEBULA CERTIFICATE-----
  32. CkEKEW5lYnVsYSByb290IGNhIDAxKM0cMM24zPCvBzogPzbWTxt8ZgXPQEwup7Br
  33. BrtIt1O0q5AuTRT3+t2x1VJAARJAZ+2ib23qBXjdy49oU1YysrwuKkWWKrtJ7Jye
  34. rFBQpDXikOukhQD/mfkloFwJ+Yjsfru7IpTN4ZfjXL+kN/2sCA==
  35. -----END NEBULA CERTIFICATE-----
  36. `
  37. expired := `
  38. # expired certificate
  39. -----BEGIN NEBULA CERTIFICATE-----
  40. CjMKB2V4cGlyZWQozRwwzRw6ICJSG94CqX8wn5I65Pwn25V6HftVfWeIySVtp2DA
  41. 7TY/QAESQMaAk5iJT5EnQwK524ZaaHGEJLUqqbh5yyOHhboIGiVTWkFeH3HccTW8
  42. Tq5a8AyWDQdfXbtEZ1FwabeHfH5Asw0=
  43. -----END NEBULA CERTIFICATE-----
  44. `
  45. p256 := `
  46. # p256 certificate
  47. -----BEGIN NEBULA CERTIFICATE-----
  48. CmQKEG5lYnVsYSBQMjU2IHRlc3QozRwwzbjM8K8HOkEEdrmmg40zQp44AkMq6DZp
  49. k+coOv04r+zh33ISyhbsafnYduN17p2eD7CmHvHuerguXD9f32gcxo/KsFCKEjMe
  50. +0ABoAYBEkcwRQIgVoTg38L7uWku9xQgsr06kxZ/viQLOO/w1Qj1vFUEnhcCIQCq
  51. 75SjTiV92kv/1GcbT3wWpAZQQDBiUHVMVmh1822szA==
  52. -----END NEBULA CERTIFICATE-----
  53. `
  54. rootCA := certificateV1{
  55. details: detailsV1{
  56. name: "nebula root ca",
  57. },
  58. }
  59. rootCA01 := certificateV1{
  60. details: detailsV1{
  61. name: "nebula root ca 01",
  62. },
  63. }
  64. rootCAP256 := certificateV1{
  65. details: detailsV1{
  66. name: "nebula P256 test",
  67. },
  68. }
  69. p, err := NewCAPoolFromPEM([]byte(noNewLines))
  70. assert.Nil(t, err)
  71. assert.Equal(t, p.CAs["ce4e6c7a596996eb0d82a8875f0f0137a4b53ce22d2421c9fd7150e7a26f6300"].Certificate.Name(), rootCA.details.name)
  72. assert.Equal(t, p.CAs["04c585fcd9a49b276df956a22b7ebea3bf23f1fca5a17c0b56ce2e626631969e"].Certificate.Name(), rootCA01.details.name)
  73. pp, err := NewCAPoolFromPEM([]byte(withNewLines))
  74. assert.Nil(t, err)
  75. assert.Equal(t, pp.CAs["ce4e6c7a596996eb0d82a8875f0f0137a4b53ce22d2421c9fd7150e7a26f6300"].Certificate.Name(), rootCA.details.name)
  76. assert.Equal(t, pp.CAs["04c585fcd9a49b276df956a22b7ebea3bf23f1fca5a17c0b56ce2e626631969e"].Certificate.Name(), rootCA01.details.name)
  77. // expired cert, no valid certs
  78. ppp, err := NewCAPoolFromPEM([]byte(expired))
  79. assert.Equal(t, ErrExpired, err)
  80. assert.Equal(t, ppp.CAs["c39b35a0e8f246203fe4f32b9aa8bfd155f1ae6a6be9d78370641e43397f48f5"].Certificate.Name(), "expired")
  81. // expired cert, with valid certs
  82. pppp, err := NewCAPoolFromPEM(append([]byte(expired), noNewLines...))
  83. assert.Equal(t, ErrExpired, err)
  84. assert.Equal(t, pppp.CAs["ce4e6c7a596996eb0d82a8875f0f0137a4b53ce22d2421c9fd7150e7a26f6300"].Certificate.Name(), rootCA.details.name)
  85. assert.Equal(t, pppp.CAs["04c585fcd9a49b276df956a22b7ebea3bf23f1fca5a17c0b56ce2e626631969e"].Certificate.Name(), rootCA01.details.name)
  86. assert.Equal(t, pppp.CAs["c39b35a0e8f246203fe4f32b9aa8bfd155f1ae6a6be9d78370641e43397f48f5"].Certificate.Name(), "expired")
  87. assert.Equal(t, len(pppp.CAs), 3)
  88. ppppp, err := NewCAPoolFromPEM([]byte(p256))
  89. assert.Nil(t, err)
  90. assert.Equal(t, ppppp.CAs["552bf7d99bec1fc775a0e4c324bf6d8f789b3078f1919c7960d2e5e0c351ee97"].Certificate.Name(), rootCAP256.details.name)
  91. assert.Equal(t, len(ppppp.CAs), 1)
  92. }
  93. func TestCertificateV1_Verify(t *testing.T) {
  94. ca, _, caKey, _ := NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
  95. c, _, _, _ := NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test cert", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
  96. caPool := NewCAPool()
  97. assert.NoError(t, caPool.AddCA(ca))
  98. f, err := c.Fingerprint()
  99. assert.Nil(t, err)
  100. caPool.BlocklistFingerprint(f)
  101. _, err = caPool.VerifyCertificate(time.Now(), c)
  102. assert.EqualError(t, err, "certificate is in the block list")
  103. caPool.ResetCertBlocklist()
  104. _, err = caPool.VerifyCertificate(time.Now(), c)
  105. assert.Nil(t, err)
  106. _, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
  107. assert.EqualError(t, err, "root certificate is expired")
  108. assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
  109. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test cert2", time.Time{}, time.Time{}, nil, nil, nil)
  110. })
  111. // Test group assertion
  112. ca, _, caKey, _ = NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
  113. caPem, err := ca.MarshalPEM()
  114. assert.Nil(t, err)
  115. caPool = NewCAPool()
  116. b, err := caPool.AddCAFromPEM(caPem)
  117. assert.NoError(t, err)
  118. assert.Empty(t, b)
  119. assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
  120. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
  121. })
  122. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test2", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
  123. assert.Nil(t, err)
  124. _, err = caPool.VerifyCertificate(time.Now(), c)
  125. assert.Nil(t, err)
  126. }
  127. func TestCertificateV1_VerifyP256(t *testing.T) {
  128. ca, _, caKey, _ := NewTestCaCert(Version1, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
  129. c, _, _, _ := NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
  130. caPool := NewCAPool()
  131. assert.NoError(t, caPool.AddCA(ca))
  132. f, err := c.Fingerprint()
  133. assert.Nil(t, err)
  134. caPool.BlocklistFingerprint(f)
  135. _, err = caPool.VerifyCertificate(time.Now(), c)
  136. assert.EqualError(t, err, "certificate is in the block list")
  137. caPool.ResetCertBlocklist()
  138. _, err = caPool.VerifyCertificate(time.Now(), c)
  139. assert.Nil(t, err)
  140. _, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
  141. assert.EqualError(t, err, "root certificate is expired")
  142. assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
  143. NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Time{}, time.Time{}, nil, nil, nil)
  144. })
  145. // Test group assertion
  146. ca, _, caKey, _ = NewTestCaCert(Version1, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
  147. caPem, err := ca.MarshalPEM()
  148. assert.Nil(t, err)
  149. caPool = NewCAPool()
  150. b, err := caPool.AddCAFromPEM(caPem)
  151. assert.NoError(t, err)
  152. assert.Empty(t, b)
  153. assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
  154. NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
  155. })
  156. c, _, _, _ = NewTestCert(Version1, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
  157. _, err = caPool.VerifyCertificate(time.Now(), c)
  158. assert.Nil(t, err)
  159. }
  160. func TestCertificateV1_Verify_IPs(t *testing.T) {
  161. caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
  162. caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
  163. ca, _, caKey, _ := NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
  164. caPem, err := ca.MarshalPEM()
  165. assert.Nil(t, err)
  166. caPool := NewCAPool()
  167. b, err := caPool.AddCAFromPEM(caPem)
  168. assert.NoError(t, err)
  169. assert.Empty(t, b)
  170. // ip is outside the network
  171. cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
  172. cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
  173. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  174. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  175. })
  176. // ip is outside the network reversed order of above
  177. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  178. cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
  179. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  180. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  181. })
  182. // ip is within the network but mask is outside
  183. cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
  184. cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
  185. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  186. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  187. })
  188. // ip is within the network but mask is outside reversed order of above
  189. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  190. cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
  191. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  192. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  193. })
  194. // ip and mask are within the network
  195. cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
  196. cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
  197. c, _, _, _ := NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  198. _, err = caPool.VerifyCertificate(time.Now(), c)
  199. assert.Nil(t, err)
  200. // Exact matches
  201. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
  202. assert.Nil(t, err)
  203. _, err = caPool.VerifyCertificate(time.Now(), c)
  204. assert.Nil(t, err)
  205. // Exact matches reversed
  206. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp2, caIp1}, nil, []string{"test"})
  207. assert.Nil(t, err)
  208. _, err = caPool.VerifyCertificate(time.Now(), c)
  209. assert.Nil(t, err)
  210. // Exact matches reversed with just 1
  211. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1}, nil, []string{"test"})
  212. assert.Nil(t, err)
  213. _, err = caPool.VerifyCertificate(time.Now(), c)
  214. assert.Nil(t, err)
  215. }
  216. func TestCertificateV1_Verify_Subnets(t *testing.T) {
  217. caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
  218. caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
  219. ca, _, caKey, _ := NewTestCaCert(Version1, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
  220. caPem, err := ca.MarshalPEM()
  221. assert.Nil(t, err)
  222. caPool := NewCAPool()
  223. b, err := caPool.AddCAFromPEM(caPem)
  224. assert.NoError(t, err)
  225. assert.Empty(t, b)
  226. // ip is outside the network
  227. cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
  228. cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
  229. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  230. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  231. })
  232. // ip is outside the network reversed order of above
  233. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  234. cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
  235. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  236. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  237. })
  238. // ip is within the network but mask is outside
  239. cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
  240. cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
  241. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  242. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  243. })
  244. // ip is within the network but mask is outside reversed order of above
  245. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  246. cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
  247. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  248. NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  249. })
  250. // ip and mask are within the network
  251. cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
  252. cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
  253. c, _, _, _ := NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  254. assert.Nil(t, err)
  255. _, err = caPool.VerifyCertificate(time.Now(), c)
  256. assert.Nil(t, err)
  257. // Exact matches
  258. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
  259. assert.Nil(t, err)
  260. _, err = caPool.VerifyCertificate(time.Now(), c)
  261. assert.Nil(t, err)
  262. // Exact matches reversed
  263. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp2, caIp1}, []string{"test"})
  264. assert.Nil(t, err)
  265. _, err = caPool.VerifyCertificate(time.Now(), c)
  266. assert.Nil(t, err)
  267. // Exact matches reversed with just 1
  268. c, _, _, _ = NewTestCert(Version1, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1}, []string{"test"})
  269. assert.Nil(t, err)
  270. _, err = caPool.VerifyCertificate(time.Now(), c)
  271. assert.Nil(t, err)
  272. }
  273. func TestCertificateV2_Verify(t *testing.T) {
  274. ca, _, caKey, _ := NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
  275. c, _, _, _ := NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test cert", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
  276. caPool := NewCAPool()
  277. assert.NoError(t, caPool.AddCA(ca))
  278. f, err := c.Fingerprint()
  279. assert.Nil(t, err)
  280. caPool.BlocklistFingerprint(f)
  281. _, err = caPool.VerifyCertificate(time.Now(), c)
  282. assert.EqualError(t, err, "certificate is in the block list")
  283. caPool.ResetCertBlocklist()
  284. _, err = caPool.VerifyCertificate(time.Now(), c)
  285. assert.Nil(t, err)
  286. _, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
  287. assert.EqualError(t, err, "root certificate is expired")
  288. assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
  289. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test cert2", time.Time{}, time.Time{}, nil, nil, nil)
  290. })
  291. // Test group assertion
  292. ca, _, caKey, _ = NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
  293. caPem, err := ca.MarshalPEM()
  294. assert.Nil(t, err)
  295. caPool = NewCAPool()
  296. b, err := caPool.AddCAFromPEM(caPem)
  297. assert.NoError(t, err)
  298. assert.Empty(t, b)
  299. assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
  300. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
  301. })
  302. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test2", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
  303. assert.Nil(t, err)
  304. _, err = caPool.VerifyCertificate(time.Now(), c)
  305. assert.Nil(t, err)
  306. }
  307. func TestCertificateV2_VerifyP256(t *testing.T) {
  308. ca, _, caKey, _ := NewTestCaCert(Version2, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, nil)
  309. c, _, _, _ := NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, nil)
  310. caPool := NewCAPool()
  311. assert.NoError(t, caPool.AddCA(ca))
  312. f, err := c.Fingerprint()
  313. assert.Nil(t, err)
  314. caPool.BlocklistFingerprint(f)
  315. _, err = caPool.VerifyCertificate(time.Now(), c)
  316. assert.EqualError(t, err, "certificate is in the block list")
  317. caPool.ResetCertBlocklist()
  318. _, err = caPool.VerifyCertificate(time.Now(), c)
  319. assert.Nil(t, err)
  320. _, err = caPool.VerifyCertificate(time.Now().Add(time.Hour*1000), c)
  321. assert.EqualError(t, err, "root certificate is expired")
  322. assert.PanicsWithError(t, "certificate is valid before the signing certificate", func() {
  323. NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Time{}, time.Time{}, nil, nil, nil)
  324. })
  325. // Test group assertion
  326. ca, _, caKey, _ = NewTestCaCert(Version2, Curve_P256, time.Now(), time.Now().Add(10*time.Minute), nil, nil, []string{"test1", "test2"})
  327. caPem, err := ca.MarshalPEM()
  328. assert.Nil(t, err)
  329. caPool = NewCAPool()
  330. b, err := caPool.AddCAFromPEM(caPem)
  331. assert.NoError(t, err)
  332. assert.Empty(t, b)
  333. assert.PanicsWithError(t, "certificate contained a group not present on the signing ca: bad", func() {
  334. NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1", "bad"})
  335. })
  336. c, _, _, _ = NewTestCert(Version2, Curve_P256, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, nil, []string{"test1"})
  337. _, err = caPool.VerifyCertificate(time.Now(), c)
  338. assert.Nil(t, err)
  339. }
  340. func TestCertificateV2_Verify_IPs(t *testing.T) {
  341. caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
  342. caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
  343. ca, _, caKey, _ := NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
  344. caPem, err := ca.MarshalPEM()
  345. assert.Nil(t, err)
  346. caPool := NewCAPool()
  347. b, err := caPool.AddCAFromPEM(caPem)
  348. assert.NoError(t, err)
  349. assert.Empty(t, b)
  350. // ip is outside the network
  351. cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
  352. cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
  353. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  354. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  355. })
  356. // ip is outside the network reversed order of above
  357. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  358. cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
  359. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  360. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  361. })
  362. // ip is within the network but mask is outside
  363. cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
  364. cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
  365. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  366. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  367. })
  368. // ip is within the network but mask is outside reversed order of above
  369. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  370. cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
  371. assert.PanicsWithError(t, "certificate contained a network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  372. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  373. })
  374. // ip and mask are within the network
  375. cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
  376. cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
  377. c, _, _, _ := NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{cIp1, cIp2}, nil, []string{"test"})
  378. _, err = caPool.VerifyCertificate(time.Now(), c)
  379. assert.Nil(t, err)
  380. // Exact matches
  381. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1, caIp2}, nil, []string{"test"})
  382. assert.Nil(t, err)
  383. _, err = caPool.VerifyCertificate(time.Now(), c)
  384. assert.Nil(t, err)
  385. // Exact matches reversed
  386. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp2, caIp1}, nil, []string{"test"})
  387. assert.Nil(t, err)
  388. _, err = caPool.VerifyCertificate(time.Now(), c)
  389. assert.Nil(t, err)
  390. // Exact matches reversed with just 1
  391. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), []netip.Prefix{caIp1}, nil, []string{"test"})
  392. assert.Nil(t, err)
  393. _, err = caPool.VerifyCertificate(time.Now(), c)
  394. assert.Nil(t, err)
  395. }
  396. func TestCertificateV2_Verify_Subnets(t *testing.T) {
  397. caIp1 := mustParsePrefixUnmapped("10.0.0.0/16")
  398. caIp2 := mustParsePrefixUnmapped("192.168.0.0/24")
  399. ca, _, caKey, _ := NewTestCaCert(Version2, Curve_CURVE25519, time.Now(), time.Now().Add(10*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
  400. caPem, err := ca.MarshalPEM()
  401. assert.Nil(t, err)
  402. caPool := NewCAPool()
  403. b, err := caPool.AddCAFromPEM(caPem)
  404. assert.NoError(t, err)
  405. assert.Empty(t, b)
  406. // ip is outside the network
  407. cIp1 := mustParsePrefixUnmapped("10.1.0.0/24")
  408. cIp2 := mustParsePrefixUnmapped("192.168.0.1/16")
  409. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  410. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  411. })
  412. // ip is outside the network reversed order of above
  413. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  414. cIp2 = mustParsePrefixUnmapped("10.1.0.0/24")
  415. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.1.0.0/24", func() {
  416. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  417. })
  418. // ip is within the network but mask is outside
  419. cIp1 = mustParsePrefixUnmapped("10.0.1.0/15")
  420. cIp2 = mustParsePrefixUnmapped("192.168.0.1/24")
  421. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  422. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  423. })
  424. // ip is within the network but mask is outside reversed order of above
  425. cIp1 = mustParsePrefixUnmapped("192.168.0.1/24")
  426. cIp2 = mustParsePrefixUnmapped("10.0.1.0/15")
  427. assert.PanicsWithError(t, "certificate contained an unsafe network assignment outside the limitations of the signing ca: 10.0.1.0/15", func() {
  428. NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  429. })
  430. // ip and mask are within the network
  431. cIp1 = mustParsePrefixUnmapped("10.0.1.0/16")
  432. cIp2 = mustParsePrefixUnmapped("192.168.0.1/25")
  433. c, _, _, _ := NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{cIp1, cIp2}, []string{"test"})
  434. assert.Nil(t, err)
  435. _, err = caPool.VerifyCertificate(time.Now(), c)
  436. assert.Nil(t, err)
  437. // Exact matches
  438. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1, caIp2}, []string{"test"})
  439. assert.Nil(t, err)
  440. _, err = caPool.VerifyCertificate(time.Now(), c)
  441. assert.Nil(t, err)
  442. // Exact matches reversed
  443. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp2, caIp1}, []string{"test"})
  444. assert.Nil(t, err)
  445. _, err = caPool.VerifyCertificate(time.Now(), c)
  446. assert.Nil(t, err)
  447. // Exact matches reversed with just 1
  448. c, _, _, _ = NewTestCert(Version2, Curve_CURVE25519, ca, caKey, "test", time.Now(), time.Now().Add(5*time.Minute), nil, []netip.Prefix{caIp1}, []string{"test"})
  449. assert.Nil(t, err)
  450. _, err = caPool.VerifyCertificate(time.Now(), c)
  451. assert.Nil(t, err)
  452. }