github.com/slackhq/nebula@v1.9.0/cert/cert_test.go (about) 1 package cert 2 3 import ( 4 "crypto/ecdh" 5 "crypto/ecdsa" 6 "crypto/elliptic" 7 "crypto/rand" 8 "fmt" 9 "io" 10 "net" 11 "testing" 12 "time" 13 14 "github.com/slackhq/nebula/test" 15 "github.com/stretchr/testify/assert" 16 "golang.org/x/crypto/curve25519" 17 "golang.org/x/crypto/ed25519" 18 "google.golang.org/protobuf/proto" 19 ) 20 21 func TestMarshalingNebulaCertificate(t *testing.T) { 22 before := time.Now().Add(time.Second * -60).Round(time.Second) 23 after := time.Now().Add(time.Second * 60).Round(time.Second) 24 pubKey := []byte("1234567890abcedfghij1234567890ab") 25 26 nc := NebulaCertificate{ 27 Details: NebulaCertificateDetails{ 28 Name: "testing", 29 Ips: []*net.IPNet{ 30 {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 31 {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 32 {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 33 }, 34 Subnets: []*net.IPNet{ 35 {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 36 {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 37 {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 38 }, 39 Groups: []string{"test-group1", "test-group2", "test-group3"}, 40 NotBefore: before, 41 NotAfter: after, 42 PublicKey: pubKey, 43 IsCA: false, 44 Issuer: "1234567890abcedfghij1234567890ab", 45 }, 46 Signature: []byte("1234567890abcedfghij1234567890ab"), 47 } 48 49 b, err := nc.Marshal() 50 assert.Nil(t, err) 51 //t.Log("Cert size:", len(b)) 52 53 nc2, err := UnmarshalNebulaCertificate(b) 54 assert.Nil(t, err) 55 56 assert.Equal(t, nc.Signature, nc2.Signature) 57 assert.Equal(t, nc.Details.Name, nc2.Details.Name) 58 assert.Equal(t, nc.Details.NotBefore, nc2.Details.NotBefore) 59 assert.Equal(t, nc.Details.NotAfter, nc2.Details.NotAfter) 60 assert.Equal(t, nc.Details.PublicKey, nc2.Details.PublicKey) 61 assert.Equal(t, nc.Details.IsCA, nc2.Details.IsCA) 62 63 // IP byte arrays can be 4 or 16 in length so we have to go this route 64 assert.Equal(t, len(nc.Details.Ips), len(nc2.Details.Ips)) 65 for i, wIp := range nc.Details.Ips { 66 assert.Equal(t, wIp.String(), nc2.Details.Ips[i].String()) 67 } 68 69 assert.Equal(t, len(nc.Details.Subnets), len(nc2.Details.Subnets)) 70 for i, wIp := range nc.Details.Subnets { 71 assert.Equal(t, wIp.String(), nc2.Details.Subnets[i].String()) 72 } 73 74 assert.EqualValues(t, nc.Details.Groups, nc2.Details.Groups) 75 } 76 77 func TestNebulaCertificate_Sign(t *testing.T) { 78 before := time.Now().Add(time.Second * -60).Round(time.Second) 79 after := time.Now().Add(time.Second * 60).Round(time.Second) 80 pubKey := []byte("1234567890abcedfghij1234567890ab") 81 82 nc := NebulaCertificate{ 83 Details: NebulaCertificateDetails{ 84 Name: "testing", 85 Ips: []*net.IPNet{ 86 {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 87 {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 88 {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 89 }, 90 Subnets: []*net.IPNet{ 91 {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 92 {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 93 {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 94 }, 95 Groups: []string{"test-group1", "test-group2", "test-group3"}, 96 NotBefore: before, 97 NotAfter: after, 98 PublicKey: pubKey, 99 IsCA: false, 100 Issuer: "1234567890abcedfghij1234567890ab", 101 }, 102 } 103 104 pub, priv, err := ed25519.GenerateKey(rand.Reader) 105 assert.Nil(t, err) 106 assert.False(t, nc.CheckSignature(pub)) 107 assert.Nil(t, nc.Sign(Curve_CURVE25519, priv)) 108 assert.True(t, nc.CheckSignature(pub)) 109 110 _, err = nc.Marshal() 111 assert.Nil(t, err) 112 //t.Log("Cert size:", len(b)) 113 } 114 115 func TestNebulaCertificate_SignP256(t *testing.T) { 116 before := time.Now().Add(time.Second * -60).Round(time.Second) 117 after := time.Now().Add(time.Second * 60).Round(time.Second) 118 pubKey := []byte("01234567890abcedfghij1234567890ab1234567890abcedfghij1234567890ab") 119 120 nc := NebulaCertificate{ 121 Details: NebulaCertificateDetails{ 122 Name: "testing", 123 Ips: []*net.IPNet{ 124 {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 125 {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 126 {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 127 }, 128 Subnets: []*net.IPNet{ 129 {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 130 {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 131 {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 132 }, 133 Groups: []string{"test-group1", "test-group2", "test-group3"}, 134 NotBefore: before, 135 NotAfter: after, 136 PublicKey: pubKey, 137 IsCA: false, 138 Curve: Curve_P256, 139 Issuer: "1234567890abcedfghij1234567890ab", 140 }, 141 } 142 143 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 144 pub := elliptic.Marshal(elliptic.P256(), priv.PublicKey.X, priv.PublicKey.Y) 145 rawPriv := priv.D.FillBytes(make([]byte, 32)) 146 147 assert.Nil(t, err) 148 assert.False(t, nc.CheckSignature(pub)) 149 assert.Nil(t, nc.Sign(Curve_P256, rawPriv)) 150 assert.True(t, nc.CheckSignature(pub)) 151 152 _, err = nc.Marshal() 153 assert.Nil(t, err) 154 //t.Log("Cert size:", len(b)) 155 } 156 157 func TestNebulaCertificate_Expired(t *testing.T) { 158 nc := NebulaCertificate{ 159 Details: NebulaCertificateDetails{ 160 NotBefore: time.Now().Add(time.Second * -60).Round(time.Second), 161 NotAfter: time.Now().Add(time.Second * 60).Round(time.Second), 162 }, 163 } 164 165 assert.True(t, nc.Expired(time.Now().Add(time.Hour))) 166 assert.True(t, nc.Expired(time.Now().Add(-time.Hour))) 167 assert.False(t, nc.Expired(time.Now())) 168 } 169 170 func TestNebulaCertificate_MarshalJSON(t *testing.T) { 171 time.Local = time.UTC 172 pubKey := []byte("1234567890abcedfghij1234567890ab") 173 174 nc := NebulaCertificate{ 175 Details: NebulaCertificateDetails{ 176 Name: "testing", 177 Ips: []*net.IPNet{ 178 {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 179 {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 180 {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 181 }, 182 Subnets: []*net.IPNet{ 183 {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 184 {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 185 {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 186 }, 187 Groups: []string{"test-group1", "test-group2", "test-group3"}, 188 NotBefore: time.Date(1, 0, 0, 1, 0, 0, 0, time.UTC), 189 NotAfter: time.Date(1, 0, 0, 2, 0, 0, 0, time.UTC), 190 PublicKey: pubKey, 191 IsCA: false, 192 Issuer: "1234567890abcedfghij1234567890ab", 193 }, 194 Signature: []byte("1234567890abcedfghij1234567890ab"), 195 } 196 197 b, err := nc.MarshalJSON() 198 assert.Nil(t, err) 199 assert.Equal( 200 t, 201 "{\"details\":{\"curve\":\"CURVE25519\",\"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\"}", 202 string(b), 203 ) 204 } 205 206 func TestNebulaCertificate_Verify(t *testing.T) { 207 ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) 208 assert.Nil(t, err) 209 210 c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) 211 assert.Nil(t, err) 212 213 h, err := ca.Sha256Sum() 214 assert.Nil(t, err) 215 216 caPool := NewCAPool() 217 caPool.CAs[h] = ca 218 219 f, err := c.Sha256Sum() 220 assert.Nil(t, err) 221 caPool.BlocklistFingerprint(f) 222 223 v, err := c.Verify(time.Now(), caPool) 224 assert.False(t, v) 225 assert.EqualError(t, err, "certificate is in the block list") 226 227 caPool.ResetCertBlocklist() 228 v, err = c.Verify(time.Now(), caPool) 229 assert.True(t, v) 230 assert.Nil(t, err) 231 232 v, err = c.Verify(time.Now().Add(time.Hour*1000), caPool) 233 assert.False(t, v) 234 assert.EqualError(t, err, "root certificate is expired") 235 236 c, _, _, err = newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 237 assert.Nil(t, err) 238 v, err = c.Verify(time.Now().Add(time.Minute*6), caPool) 239 assert.False(t, v) 240 assert.EqualError(t, err, "certificate is expired") 241 242 // Test group assertion 243 ca, _, caKey, err = newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "test2"}) 244 assert.Nil(t, err) 245 246 caPem, err := ca.MarshalToPEM() 247 assert.Nil(t, err) 248 249 caPool = NewCAPool() 250 caPool.AddCACertificate(caPem) 251 252 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "bad"}) 253 assert.Nil(t, err) 254 v, err = c.Verify(time.Now(), caPool) 255 assert.False(t, v) 256 assert.EqualError(t, err, "certificate contained a group not present on the signing ca: bad") 257 258 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1"}) 259 assert.Nil(t, err) 260 v, err = c.Verify(time.Now(), caPool) 261 assert.True(t, v) 262 assert.Nil(t, err) 263 } 264 265 func TestNebulaCertificate_VerifyP256(t *testing.T) { 266 ca, _, caKey, err := newTestCaCertP256(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) 267 assert.Nil(t, err) 268 269 c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) 270 assert.Nil(t, err) 271 272 h, err := ca.Sha256Sum() 273 assert.Nil(t, err) 274 275 caPool := NewCAPool() 276 caPool.CAs[h] = ca 277 278 f, err := c.Sha256Sum() 279 assert.Nil(t, err) 280 caPool.BlocklistFingerprint(f) 281 282 v, err := c.Verify(time.Now(), caPool) 283 assert.False(t, v) 284 assert.EqualError(t, err, "certificate is in the block list") 285 286 caPool.ResetCertBlocklist() 287 v, err = c.Verify(time.Now(), caPool) 288 assert.True(t, v) 289 assert.Nil(t, err) 290 291 v, err = c.Verify(time.Now().Add(time.Hour*1000), caPool) 292 assert.False(t, v) 293 assert.EqualError(t, err, "root certificate is expired") 294 295 c, _, _, err = newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 296 assert.Nil(t, err) 297 v, err = c.Verify(time.Now().Add(time.Minute*6), caPool) 298 assert.False(t, v) 299 assert.EqualError(t, err, "certificate is expired") 300 301 // Test group assertion 302 ca, _, caKey, err = newTestCaCertP256(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "test2"}) 303 assert.Nil(t, err) 304 305 caPem, err := ca.MarshalToPEM() 306 assert.Nil(t, err) 307 308 caPool = NewCAPool() 309 caPool.AddCACertificate(caPem) 310 311 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "bad"}) 312 assert.Nil(t, err) 313 v, err = c.Verify(time.Now(), caPool) 314 assert.False(t, v) 315 assert.EqualError(t, err, "certificate contained a group not present on the signing ca: bad") 316 317 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1"}) 318 assert.Nil(t, err) 319 v, err = c.Verify(time.Now(), caPool) 320 assert.True(t, v) 321 assert.Nil(t, err) 322 } 323 324 func TestNebulaCertificate_Verify_IPs(t *testing.T) { 325 _, caIp1, _ := net.ParseCIDR("10.0.0.0/16") 326 _, caIp2, _ := net.ParseCIDR("192.168.0.0/24") 327 ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{caIp1, caIp2}, []*net.IPNet{}, []string{"test"}) 328 assert.Nil(t, err) 329 330 caPem, err := ca.MarshalToPEM() 331 assert.Nil(t, err) 332 333 caPool := NewCAPool() 334 caPool.AddCACertificate(caPem) 335 336 // ip is outside the network 337 cIp1 := &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}} 338 cIp2 := &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 0, 0}} 339 c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"}) 340 assert.Nil(t, err) 341 v, err := c.Verify(time.Now(), caPool) 342 assert.False(t, v) 343 assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.1.0.0/24") 344 345 // ip is outside the network reversed order of above 346 cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}} 347 cIp2 = &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}} 348 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"}) 349 assert.Nil(t, err) 350 v, err = c.Verify(time.Now(), caPool) 351 assert.False(t, v) 352 assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.1.0.0/24") 353 354 // ip is within the network but mask is outside 355 cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}} 356 cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}} 357 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"}) 358 assert.Nil(t, err) 359 v, err = c.Verify(time.Now(), caPool) 360 assert.False(t, v) 361 assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.0.1.0/15") 362 363 // ip is within the network but mask is outside reversed order of above 364 cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}} 365 cIp2 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}} 366 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"}) 367 assert.Nil(t, err) 368 v, err = c.Verify(time.Now(), caPool) 369 assert.False(t, v) 370 assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.0.1.0/15") 371 372 // ip and mask are within the network 373 cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 255, 0, 0}} 374 cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 128}} 375 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"}) 376 assert.Nil(t, err) 377 v, err = c.Verify(time.Now(), caPool) 378 assert.True(t, v) 379 assert.Nil(t, err) 380 381 // Exact matches 382 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp1, caIp2}, []*net.IPNet{}, []string{"test"}) 383 assert.Nil(t, err) 384 v, err = c.Verify(time.Now(), caPool) 385 assert.True(t, v) 386 assert.Nil(t, err) 387 388 // Exact matches reversed 389 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp2, caIp1}, []*net.IPNet{}, []string{"test"}) 390 assert.Nil(t, err) 391 v, err = c.Verify(time.Now(), caPool) 392 assert.True(t, v) 393 assert.Nil(t, err) 394 395 // Exact matches reversed with just 1 396 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp1}, []*net.IPNet{}, []string{"test"}) 397 assert.Nil(t, err) 398 v, err = c.Verify(time.Now(), caPool) 399 assert.True(t, v) 400 assert.Nil(t, err) 401 } 402 403 func TestNebulaCertificate_Verify_Subnets(t *testing.T) { 404 _, caIp1, _ := net.ParseCIDR("10.0.0.0/16") 405 _, caIp2, _ := net.ParseCIDR("192.168.0.0/24") 406 ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1, caIp2}, []string{"test"}) 407 assert.Nil(t, err) 408 409 caPem, err := ca.MarshalToPEM() 410 assert.Nil(t, err) 411 412 caPool := NewCAPool() 413 caPool.AddCACertificate(caPem) 414 415 // ip is outside the network 416 cIp1 := &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}} 417 cIp2 := &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 0, 0}} 418 c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"}) 419 assert.Nil(t, err) 420 v, err := c.Verify(time.Now(), caPool) 421 assert.False(t, v) 422 assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.1.0.0/24") 423 424 // ip is outside the network reversed order of above 425 cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}} 426 cIp2 = &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}} 427 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"}) 428 assert.Nil(t, err) 429 v, err = c.Verify(time.Now(), caPool) 430 assert.False(t, v) 431 assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.1.0.0/24") 432 433 // ip is within the network but mask is outside 434 cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}} 435 cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}} 436 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"}) 437 assert.Nil(t, err) 438 v, err = c.Verify(time.Now(), caPool) 439 assert.False(t, v) 440 assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.0.1.0/15") 441 442 // ip is within the network but mask is outside reversed order of above 443 cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}} 444 cIp2 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}} 445 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"}) 446 assert.Nil(t, err) 447 v, err = c.Verify(time.Now(), caPool) 448 assert.False(t, v) 449 assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.0.1.0/15") 450 451 // ip and mask are within the network 452 cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 255, 0, 0}} 453 cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 128}} 454 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"}) 455 assert.Nil(t, err) 456 v, err = c.Verify(time.Now(), caPool) 457 assert.True(t, v) 458 assert.Nil(t, err) 459 460 // Exact matches 461 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1, caIp2}, []string{"test"}) 462 assert.Nil(t, err) 463 v, err = c.Verify(time.Now(), caPool) 464 assert.True(t, v) 465 assert.Nil(t, err) 466 467 // Exact matches reversed 468 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp2, caIp1}, []string{"test"}) 469 assert.Nil(t, err) 470 v, err = c.Verify(time.Now(), caPool) 471 assert.True(t, v) 472 assert.Nil(t, err) 473 474 // Exact matches reversed with just 1 475 c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1}, []string{"test"}) 476 assert.Nil(t, err) 477 v, err = c.Verify(time.Now(), caPool) 478 assert.True(t, v) 479 assert.Nil(t, err) 480 } 481 482 func TestNebulaCertificate_VerifyPrivateKey(t *testing.T) { 483 ca, _, caKey, err := newTestCaCert(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 484 assert.Nil(t, err) 485 err = ca.VerifyPrivateKey(Curve_CURVE25519, caKey) 486 assert.Nil(t, err) 487 488 _, _, caKey2, err := newTestCaCert(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 489 assert.Nil(t, err) 490 err = ca.VerifyPrivateKey(Curve_CURVE25519, caKey2) 491 assert.NotNil(t, err) 492 493 c, _, priv, err := newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 494 err = c.VerifyPrivateKey(Curve_CURVE25519, priv) 495 assert.Nil(t, err) 496 497 _, priv2 := x25519Keypair() 498 err = c.VerifyPrivateKey(Curve_CURVE25519, priv2) 499 assert.NotNil(t, err) 500 } 501 502 func TestNebulaCertificate_VerifyPrivateKeyP256(t *testing.T) { 503 ca, _, caKey, err := newTestCaCertP256(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 504 assert.Nil(t, err) 505 err = ca.VerifyPrivateKey(Curve_P256, caKey) 506 assert.Nil(t, err) 507 508 _, _, caKey2, err := newTestCaCertP256(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 509 assert.Nil(t, err) 510 err = ca.VerifyPrivateKey(Curve_P256, caKey2) 511 assert.NotNil(t, err) 512 513 c, _, priv, err := newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{}) 514 err = c.VerifyPrivateKey(Curve_P256, priv) 515 assert.Nil(t, err) 516 517 _, priv2 := p256Keypair() 518 err = c.VerifyPrivateKey(Curve_P256, priv2) 519 assert.NotNil(t, err) 520 } 521 522 func TestNewCAPoolFromBytes(t *testing.T) { 523 noNewLines := ` 524 # Current provisional, Remove once everything moves over to the real root. 525 -----BEGIN NEBULA CERTIFICATE----- 526 CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL 527 vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv 528 bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB 529 -----END NEBULA CERTIFICATE----- 530 # root-ca01 531 -----BEGIN NEBULA CERTIFICATE----- 532 CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTG 533 BVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf 534 8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF 535 -----END NEBULA CERTIFICATE----- 536 ` 537 538 withNewLines := ` 539 # Current provisional, Remove once everything moves over to the real root. 540 541 -----BEGIN NEBULA CERTIFICATE----- 542 CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL 543 vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv 544 bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB 545 -----END NEBULA CERTIFICATE----- 546 547 # root-ca01 548 549 550 -----BEGIN NEBULA CERTIFICATE----- 551 CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTG 552 BVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf 553 8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF 554 -----END NEBULA CERTIFICATE----- 555 556 ` 557 558 expired := ` 559 # expired certificate 560 -----BEGIN NEBULA CERTIFICATE----- 561 CjkKB2V4cGlyZWQouPmWjQYwufmWjQY6ILCRaoCkJlqHgv5jfDN4lzLHBvDzaQm4 562 vZxfu144hmgjQAESQG4qlnZi8DncvD/LDZnLgJHOaX1DWCHHEh59epVsC+BNgTie 563 WH1M9n4O7cFtGlM6sJJOS+rCVVEJ3ABS7+MPdQs= 564 -----END NEBULA CERTIFICATE----- 565 ` 566 567 p256 := ` 568 # p256 certificate 569 -----BEGIN NEBULA CERTIFICATE----- 570 CmYKEG5lYnVsYSBQMjU2IHRlc3Qo4s+7mgYw4tXrsAc6QQRkaW2jFmllYvN4+/k2 571 6tctO9sPT3jOx8ES6M1nIqOhpTmZeabF/4rELDqPV4aH5jfJut798DUXql0FlF8H 572 76gvQAGgBgESRzBFAiEAib0/te6eMiZOKD8gdDeloMTS0wGuX2t0C7TFdUhAQzgC 573 IBNWYMep3ysx9zCgknfG5dKtwGTaqF++BWKDYdyl34KX 574 -----END NEBULA CERTIFICATE----- 575 ` 576 577 rootCA := NebulaCertificate{ 578 Details: NebulaCertificateDetails{ 579 Name: "nebula root ca", 580 }, 581 } 582 583 rootCA01 := NebulaCertificate{ 584 Details: NebulaCertificateDetails{ 585 Name: "nebula root ca 01", 586 }, 587 } 588 589 rootCAP256 := NebulaCertificate{ 590 Details: NebulaCertificateDetails{ 591 Name: "nebula P256 test", 592 }, 593 } 594 595 p, err := NewCAPoolFromBytes([]byte(noNewLines)) 596 assert.Nil(t, err) 597 assert.Equal(t, p.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name) 598 assert.Equal(t, p.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name) 599 600 pp, err := NewCAPoolFromBytes([]byte(withNewLines)) 601 assert.Nil(t, err) 602 assert.Equal(t, pp.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name) 603 assert.Equal(t, pp.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name) 604 605 // expired cert, no valid certs 606 ppp, err := NewCAPoolFromBytes([]byte(expired)) 607 assert.Equal(t, ErrExpired, err) 608 assert.Equal(t, ppp.CAs[string("152070be6bb19bc9e3bde4c2f0e7d8f4ff5448b4c9856b8eccb314fade0229b0")].Details.Name, "expired") 609 610 // expired cert, with valid certs 611 pppp, err := NewCAPoolFromBytes(append([]byte(expired), noNewLines...)) 612 assert.Equal(t, ErrExpired, err) 613 assert.Equal(t, pppp.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name) 614 assert.Equal(t, pppp.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name) 615 assert.Equal(t, pppp.CAs[string("152070be6bb19bc9e3bde4c2f0e7d8f4ff5448b4c9856b8eccb314fade0229b0")].Details.Name, "expired") 616 assert.Equal(t, len(pppp.CAs), 3) 617 618 ppppp, err := NewCAPoolFromBytes([]byte(p256)) 619 assert.Nil(t, err) 620 assert.Equal(t, ppppp.CAs[string("a7938893ec8c4ef769b06d7f425e5e46f7a7f5ffa49c3bcf4a86b608caba9159")].Details.Name, rootCAP256.Details.Name) 621 assert.Equal(t, len(ppppp.CAs), 1) 622 } 623 624 func appendByteSlices(b ...[]byte) []byte { 625 retSlice := []byte{} 626 for _, v := range b { 627 retSlice = append(retSlice, v...) 628 } 629 return retSlice 630 } 631 632 func TestUnmrshalCertPEM(t *testing.T) { 633 goodCert := []byte(` 634 # A good cert 635 -----BEGIN NEBULA CERTIFICATE----- 636 CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL 637 vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv 638 bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB 639 -----END NEBULA CERTIFICATE----- 640 `) 641 badBanner := []byte(`# A bad banner 642 -----BEGIN NOT A NEBULA CERTIFICATE----- 643 CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL 644 vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv 645 bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB 646 -----END NOT A NEBULA CERTIFICATE----- 647 `) 648 invalidPem := []byte(`# Not a valid PEM format 649 -BEGIN NEBULA CERTIFICATE----- 650 CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL 651 vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv 652 bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB 653 -END NEBULA CERTIFICATE----`) 654 655 certBundle := appendByteSlices(goodCert, badBanner, invalidPem) 656 657 // Success test case 658 cert, rest, err := UnmarshalNebulaCertificateFromPEM(certBundle) 659 assert.NotNil(t, cert) 660 assert.Equal(t, rest, append(badBanner, invalidPem...)) 661 assert.Nil(t, err) 662 663 // Fail due to invalid banner. 664 cert, rest, err = UnmarshalNebulaCertificateFromPEM(rest) 665 assert.Nil(t, cert) 666 assert.Equal(t, rest, invalidPem) 667 assert.EqualError(t, err, "bytes did not contain a proper nebula certificate banner") 668 669 // Fail due to ivalid PEM format, because 670 // it's missing the requisite pre-encapsulation boundary. 671 cert, rest, err = UnmarshalNebulaCertificateFromPEM(rest) 672 assert.Nil(t, cert) 673 assert.Equal(t, rest, invalidPem) 674 assert.EqualError(t, err, "input did not contain a valid PEM encoded block") 675 } 676 677 func TestUnmarshalSigningPrivateKey(t *testing.T) { 678 privKey := []byte(`# A good key 679 -----BEGIN NEBULA ED25519 PRIVATE KEY----- 680 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 681 -----END NEBULA ED25519 PRIVATE KEY----- 682 `) 683 privP256Key := []byte(`# A good key 684 -----BEGIN NEBULA ECDSA P256 PRIVATE KEY----- 685 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 686 -----END NEBULA ECDSA P256 PRIVATE KEY----- 687 `) 688 shortKey := []byte(`# A short key 689 -----BEGIN NEBULA ED25519 PRIVATE KEY----- 690 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 691 -----END NEBULA ED25519 PRIVATE KEY----- 692 `) 693 invalidBanner := []byte(`# Invalid banner 694 -----BEGIN NOT A NEBULA PRIVATE KEY----- 695 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 696 -----END NOT A NEBULA PRIVATE KEY----- 697 `) 698 invalidPem := []byte(`# Not a valid PEM format 699 -BEGIN NEBULA ED25519 PRIVATE KEY----- 700 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 701 -END NEBULA ED25519 PRIVATE KEY-----`) 702 703 keyBundle := appendByteSlices(privKey, privP256Key, shortKey, invalidBanner, invalidPem) 704 705 // Success test case 706 k, rest, curve, err := UnmarshalSigningPrivateKey(keyBundle) 707 assert.Len(t, k, 64) 708 assert.Equal(t, rest, appendByteSlices(privP256Key, shortKey, invalidBanner, invalidPem)) 709 assert.Equal(t, Curve_CURVE25519, curve) 710 assert.Nil(t, err) 711 712 // Success test case 713 k, rest, curve, err = UnmarshalSigningPrivateKey(rest) 714 assert.Len(t, k, 32) 715 assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem)) 716 assert.Equal(t, Curve_P256, curve) 717 assert.Nil(t, err) 718 719 // Fail due to short key 720 k, rest, curve, err = UnmarshalSigningPrivateKey(rest) 721 assert.Nil(t, k) 722 assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem)) 723 assert.EqualError(t, err, "key was not 64 bytes, is invalid Ed25519 private key") 724 725 // Fail due to invalid banner 726 k, rest, curve, err = UnmarshalSigningPrivateKey(rest) 727 assert.Nil(t, k) 728 assert.Equal(t, rest, invalidPem) 729 assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519/ECDSA private key banner") 730 731 // Fail due to ivalid PEM format, because 732 // it's missing the requisite pre-encapsulation boundary. 733 k, rest, curve, err = UnmarshalSigningPrivateKey(rest) 734 assert.Nil(t, k) 735 assert.Equal(t, rest, invalidPem) 736 assert.EqualError(t, err, "input did not contain a valid PEM encoded block") 737 } 738 739 func TestDecryptAndUnmarshalSigningPrivateKey(t *testing.T) { 740 passphrase := []byte("DO NOT USE THIS KEY") 741 privKey := []byte(`# A good key 742 -----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY----- 743 CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDT 744 oCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl 745 +Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPB 746 qrlJ69wer3ZUHFXA 747 -----END NEBULA ED25519 ENCRYPTED PRIVATE KEY----- 748 `) 749 shortKey := []byte(`# A key which, once decrypted, is too short 750 -----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY----- 751 CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCoga5h8owMEBWRSMMJKzuUvWce7 752 k0qlBkQmCxiuLh80MuASW70YcKt8jeEIS2axo2V6zAKA9TSMcCsJW1kDDXEtL/xe 753 GLF5T7sDl5COp4LU3pGxpV+KoeQ/S3gQCAAcnaOtnJQX+aSDnbO3jCHyP7U9CHbs 754 rQr3bdH3Oy/WiYU= 755 -----END NEBULA ED25519 ENCRYPTED PRIVATE KEY----- 756 `) 757 invalidBanner := []byte(`# Invalid banner (not encrypted) 758 -----BEGIN NEBULA ED25519 PRIVATE KEY----- 759 bWRp2CTVFhW9HD/qCd28ltDgK3w8VXSeaEYczDWos8sMUBqDb9jP3+NYwcS4lURG 760 XgLvodMXZJuaFPssp+WwtA== 761 -----END NEBULA ED25519 PRIVATE KEY----- 762 `) 763 invalidPem := []byte(`# Not a valid PEM format 764 -BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY----- 765 CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDT 766 oCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl 767 +Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPB 768 qrlJ69wer3ZUHFXA 769 -END NEBULA ED25519 ENCRYPTED PRIVATE KEY----- 770 `) 771 772 keyBundle := appendByteSlices(privKey, shortKey, invalidBanner, invalidPem) 773 774 // Success test case 775 curve, k, rest, err := DecryptAndUnmarshalSigningPrivateKey(passphrase, keyBundle) 776 assert.Nil(t, err) 777 assert.Equal(t, Curve_CURVE25519, curve) 778 assert.Len(t, k, 64) 779 assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem)) 780 781 // Fail due to short key 782 curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest) 783 assert.EqualError(t, err, "key was not 64 bytes, is invalid ed25519 private key") 784 assert.Nil(t, k) 785 assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem)) 786 787 // Fail due to invalid banner 788 curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest) 789 assert.EqualError(t, err, "bytes did not contain a proper nebula encrypted Ed25519/ECDSA private key banner") 790 assert.Nil(t, k) 791 assert.Equal(t, rest, invalidPem) 792 793 // Fail due to ivalid PEM format, because 794 // it's missing the requisite pre-encapsulation boundary. 795 curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest) 796 assert.EqualError(t, err, "input did not contain a valid PEM encoded block") 797 assert.Nil(t, k) 798 assert.Equal(t, rest, invalidPem) 799 800 // Fail due to invalid passphrase 801 curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey([]byte("invalid passphrase"), privKey) 802 assert.EqualError(t, err, "invalid passphrase or corrupt private key") 803 assert.Nil(t, k) 804 assert.Equal(t, rest, []byte{}) 805 } 806 807 func TestEncryptAndMarshalSigningPrivateKey(t *testing.T) { 808 // Having proved that decryption works correctly above, we can test the 809 // encryption function produces a value which can be decrypted 810 passphrase := []byte("passphrase") 811 bytes := []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") 812 kdfParams := NewArgon2Parameters(64*1024, 4, 3) 813 key, err := EncryptAndMarshalSigningPrivateKey(Curve_CURVE25519, bytes, passphrase, kdfParams) 814 assert.Nil(t, err) 815 816 // Verify the "key" can be decrypted successfully 817 curve, k, rest, err := DecryptAndUnmarshalSigningPrivateKey(passphrase, key) 818 assert.Len(t, k, 64) 819 assert.Equal(t, Curve_CURVE25519, curve) 820 assert.Equal(t, rest, []byte{}) 821 assert.Nil(t, err) 822 823 // EncryptAndMarshalEd25519PrivateKey does not create any errors itself 824 } 825 826 func TestUnmarshalPrivateKey(t *testing.T) { 827 privKey := []byte(`# A good key 828 -----BEGIN NEBULA X25519 PRIVATE KEY----- 829 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 830 -----END NEBULA X25519 PRIVATE KEY----- 831 `) 832 privP256Key := []byte(`# A good key 833 -----BEGIN NEBULA P256 PRIVATE KEY----- 834 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 835 -----END NEBULA P256 PRIVATE KEY----- 836 `) 837 shortKey := []byte(`# A short key 838 -----BEGIN NEBULA X25519 PRIVATE KEY----- 839 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 840 -----END NEBULA X25519 PRIVATE KEY----- 841 `) 842 invalidBanner := []byte(`# Invalid banner 843 -----BEGIN NOT A NEBULA PRIVATE KEY----- 844 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 845 -----END NOT A NEBULA PRIVATE KEY----- 846 `) 847 invalidPem := []byte(`# Not a valid PEM format 848 -BEGIN NEBULA X25519 PRIVATE KEY----- 849 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 850 -END NEBULA X25519 PRIVATE KEY-----`) 851 852 keyBundle := appendByteSlices(privKey, privP256Key, shortKey, invalidBanner, invalidPem) 853 854 // Success test case 855 k, rest, curve, err := UnmarshalPrivateKey(keyBundle) 856 assert.Len(t, k, 32) 857 assert.Equal(t, rest, appendByteSlices(privP256Key, shortKey, invalidBanner, invalidPem)) 858 assert.Equal(t, Curve_CURVE25519, curve) 859 assert.Nil(t, err) 860 861 // Success test case 862 k, rest, curve, err = UnmarshalPrivateKey(rest) 863 assert.Len(t, k, 32) 864 assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem)) 865 assert.Equal(t, Curve_P256, curve) 866 assert.Nil(t, err) 867 868 // Fail due to short key 869 k, rest, curve, err = UnmarshalPrivateKey(rest) 870 assert.Nil(t, k) 871 assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem)) 872 assert.EqualError(t, err, "key was not 32 bytes, is invalid CURVE25519 private key") 873 874 // Fail due to invalid banner 875 k, rest, curve, err = UnmarshalPrivateKey(rest) 876 assert.Nil(t, k) 877 assert.Equal(t, rest, invalidPem) 878 assert.EqualError(t, err, "bytes did not contain a proper nebula private key banner") 879 880 // Fail due to ivalid PEM format, because 881 // it's missing the requisite pre-encapsulation boundary. 882 k, rest, curve, err = UnmarshalPrivateKey(rest) 883 assert.Nil(t, k) 884 assert.Equal(t, rest, invalidPem) 885 assert.EqualError(t, err, "input did not contain a valid PEM encoded block") 886 } 887 888 func TestUnmarshalEd25519PublicKey(t *testing.T) { 889 pubKey := []byte(`# A good key 890 -----BEGIN NEBULA ED25519 PUBLIC KEY----- 891 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 892 -----END NEBULA ED25519 PUBLIC KEY----- 893 `) 894 shortKey := []byte(`# A short key 895 -----BEGIN NEBULA ED25519 PUBLIC KEY----- 896 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 897 -----END NEBULA ED25519 PUBLIC KEY----- 898 `) 899 invalidBanner := []byte(`# Invalid banner 900 -----BEGIN NOT A NEBULA PUBLIC KEY----- 901 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 902 -----END NOT A NEBULA PUBLIC KEY----- 903 `) 904 invalidPem := []byte(`# Not a valid PEM format 905 -BEGIN NEBULA ED25519 PUBLIC KEY----- 906 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 907 -END NEBULA ED25519 PUBLIC KEY-----`) 908 909 keyBundle := appendByteSlices(pubKey, shortKey, invalidBanner, invalidPem) 910 911 // Success test case 912 k, rest, err := UnmarshalEd25519PublicKey(keyBundle) 913 assert.Equal(t, len(k), 32) 914 assert.Nil(t, err) 915 assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem)) 916 917 // Fail due to short key 918 k, rest, err = UnmarshalEd25519PublicKey(rest) 919 assert.Nil(t, k) 920 assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem)) 921 assert.EqualError(t, err, "key was not 32 bytes, is invalid ed25519 public key") 922 923 // Fail due to invalid banner 924 k, rest, err = UnmarshalEd25519PublicKey(rest) 925 assert.Nil(t, k) 926 assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519 public key banner") 927 assert.Equal(t, rest, invalidPem) 928 929 // Fail due to ivalid PEM format, because 930 // it's missing the requisite pre-encapsulation boundary. 931 k, rest, err = UnmarshalEd25519PublicKey(rest) 932 assert.Nil(t, k) 933 assert.Equal(t, rest, invalidPem) 934 assert.EqualError(t, err, "input did not contain a valid PEM encoded block") 935 } 936 937 func TestUnmarshalX25519PublicKey(t *testing.T) { 938 pubKey := []byte(`# A good key 939 -----BEGIN NEBULA X25519 PUBLIC KEY----- 940 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 941 -----END NEBULA X25519 PUBLIC KEY----- 942 `) 943 pubP256Key := []byte(`# A good key 944 -----BEGIN NEBULA P256 PUBLIC KEY----- 945 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 946 AAAAAAAAAAAAAAAAAAAAAAA= 947 -----END NEBULA P256 PUBLIC KEY----- 948 `) 949 shortKey := []byte(`# A short key 950 -----BEGIN NEBULA X25519 PUBLIC KEY----- 951 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== 952 -----END NEBULA X25519 PUBLIC KEY----- 953 `) 954 invalidBanner := []byte(`# Invalid banner 955 -----BEGIN NOT A NEBULA PUBLIC KEY----- 956 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 957 -----END NOT A NEBULA PUBLIC KEY----- 958 `) 959 invalidPem := []byte(`# Not a valid PEM format 960 -BEGIN NEBULA X25519 PUBLIC KEY----- 961 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 962 -END NEBULA X25519 PUBLIC KEY-----`) 963 964 keyBundle := appendByteSlices(pubKey, pubP256Key, shortKey, invalidBanner, invalidPem) 965 966 // Success test case 967 k, rest, curve, err := UnmarshalPublicKey(keyBundle) 968 assert.Equal(t, len(k), 32) 969 assert.Nil(t, err) 970 assert.Equal(t, rest, appendByteSlices(pubP256Key, shortKey, invalidBanner, invalidPem)) 971 assert.Equal(t, Curve_CURVE25519, curve) 972 973 // Success test case 974 k, rest, curve, err = UnmarshalPublicKey(rest) 975 assert.Equal(t, len(k), 65) 976 assert.Nil(t, err) 977 assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem)) 978 assert.Equal(t, Curve_P256, curve) 979 980 // Fail due to short key 981 k, rest, curve, err = UnmarshalPublicKey(rest) 982 assert.Nil(t, k) 983 assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem)) 984 assert.EqualError(t, err, "key was not 32 bytes, is invalid CURVE25519 public key") 985 986 // Fail due to invalid banner 987 k, rest, curve, err = UnmarshalPublicKey(rest) 988 assert.Nil(t, k) 989 assert.EqualError(t, err, "bytes did not contain a proper nebula public key banner") 990 assert.Equal(t, rest, invalidPem) 991 992 // Fail due to ivalid PEM format, because 993 // it's missing the requisite pre-encapsulation boundary. 994 k, rest, curve, err = UnmarshalPublicKey(rest) 995 assert.Nil(t, k) 996 assert.Equal(t, rest, invalidPem) 997 assert.EqualError(t, err, "input did not contain a valid PEM encoded block") 998 } 999 1000 // Ensure that upgrading the protobuf library does not change how certificates 1001 // are marshalled, since this would break signature verification 1002 func TestMarshalingNebulaCertificateConsistency(t *testing.T) { 1003 before := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 1004 after := time.Date(2017, time.January, 18, 28, 40, 0, 0, time.UTC) 1005 pubKey := []byte("1234567890abcedfghij1234567890ab") 1006 1007 nc := NebulaCertificate{ 1008 Details: NebulaCertificateDetails{ 1009 Name: "testing", 1010 Ips: []*net.IPNet{ 1011 {IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 1012 {IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 1013 {IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 1014 }, 1015 Subnets: []*net.IPNet{ 1016 {IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))}, 1017 {IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))}, 1018 {IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))}, 1019 }, 1020 Groups: []string{"test-group1", "test-group2", "test-group3"}, 1021 NotBefore: before, 1022 NotAfter: after, 1023 PublicKey: pubKey, 1024 IsCA: false, 1025 Issuer: "1234567890abcedfghij1234567890ab", 1026 }, 1027 Signature: []byte("1234567890abcedfghij1234567890ab"), 1028 } 1029 1030 b, err := nc.Marshal() 1031 assert.Nil(t, err) 1032 //t.Log("Cert size:", len(b)) 1033 assert.Equal(t, "0aa2010a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf1220313233343536373839306162636564666768696a313233343536373839306162", fmt.Sprintf("%x", b)) 1034 1035 b, err = proto.Marshal(nc.getRawDetails()) 1036 assert.Nil(t, err) 1037 //t.Log("Raw cert size:", len(b)) 1038 assert.Equal(t, "0a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf", fmt.Sprintf("%x", b)) 1039 } 1040 1041 func TestNebulaCertificate_Copy(t *testing.T) { 1042 ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) 1043 assert.Nil(t, err) 1044 1045 c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{}) 1046 assert.Nil(t, err) 1047 cc := c.Copy() 1048 1049 test.AssertDeepCopyEqual(t, c, cc) 1050 } 1051 1052 func TestUnmarshalNebulaCertificate(t *testing.T) { 1053 // Test that we don't panic with an invalid certificate (#332) 1054 data := []byte("\x98\x00\x00") 1055 _, err := UnmarshalNebulaCertificate(data) 1056 assert.EqualError(t, err, "encoded Details was nil") 1057 } 1058 1059 func newTestCaCert(before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) { 1060 pub, priv, err := ed25519.GenerateKey(rand.Reader) 1061 if before.IsZero() { 1062 before = time.Now().Add(time.Second * -60).Round(time.Second) 1063 } 1064 if after.IsZero() { 1065 after = time.Now().Add(time.Second * 60).Round(time.Second) 1066 } 1067 1068 nc := &NebulaCertificate{ 1069 Details: NebulaCertificateDetails{ 1070 Name: "test ca", 1071 NotBefore: time.Unix(before.Unix(), 0), 1072 NotAfter: time.Unix(after.Unix(), 0), 1073 PublicKey: pub, 1074 IsCA: true, 1075 InvertedGroups: make(map[string]struct{}), 1076 }, 1077 } 1078 1079 if len(ips) > 0 { 1080 nc.Details.Ips = ips 1081 } 1082 1083 if len(subnets) > 0 { 1084 nc.Details.Subnets = subnets 1085 } 1086 1087 if len(groups) > 0 { 1088 nc.Details.Groups = groups 1089 } 1090 1091 err = nc.Sign(Curve_CURVE25519, priv) 1092 if err != nil { 1093 return nil, nil, nil, err 1094 } 1095 return nc, pub, priv, nil 1096 } 1097 1098 func newTestCaCertP256(before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) { 1099 priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 1100 pub := elliptic.Marshal(elliptic.P256(), priv.PublicKey.X, priv.PublicKey.Y) 1101 rawPriv := priv.D.FillBytes(make([]byte, 32)) 1102 1103 if before.IsZero() { 1104 before = time.Now().Add(time.Second * -60).Round(time.Second) 1105 } 1106 if after.IsZero() { 1107 after = time.Now().Add(time.Second * 60).Round(time.Second) 1108 } 1109 1110 nc := &NebulaCertificate{ 1111 Details: NebulaCertificateDetails{ 1112 Name: "test ca", 1113 NotBefore: time.Unix(before.Unix(), 0), 1114 NotAfter: time.Unix(after.Unix(), 0), 1115 PublicKey: pub, 1116 IsCA: true, 1117 Curve: Curve_P256, 1118 InvertedGroups: make(map[string]struct{}), 1119 }, 1120 } 1121 1122 if len(ips) > 0 { 1123 nc.Details.Ips = ips 1124 } 1125 1126 if len(subnets) > 0 { 1127 nc.Details.Subnets = subnets 1128 } 1129 1130 if len(groups) > 0 { 1131 nc.Details.Groups = groups 1132 } 1133 1134 err = nc.Sign(Curve_P256, rawPriv) 1135 if err != nil { 1136 return nil, nil, nil, err 1137 } 1138 return nc, pub, rawPriv, nil 1139 } 1140 1141 func newTestCert(ca *NebulaCertificate, key []byte, before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) { 1142 issuer, err := ca.Sha256Sum() 1143 if err != nil { 1144 return nil, nil, nil, err 1145 } 1146 1147 if before.IsZero() { 1148 before = time.Now().Add(time.Second * -60).Round(time.Second) 1149 } 1150 if after.IsZero() { 1151 after = time.Now().Add(time.Second * 60).Round(time.Second) 1152 } 1153 1154 if len(groups) == 0 { 1155 groups = []string{"test-group1", "test-group2", "test-group3"} 1156 } 1157 1158 if len(ips) == 0 { 1159 ips = []*net.IPNet{ 1160 {IP: net.ParseIP("10.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())}, 1161 {IP: net.ParseIP("10.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())}, 1162 {IP: net.ParseIP("10.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())}, 1163 } 1164 } 1165 1166 if len(subnets) == 0 { 1167 subnets = []*net.IPNet{ 1168 {IP: net.ParseIP("9.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())}, 1169 {IP: net.ParseIP("9.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())}, 1170 {IP: net.ParseIP("9.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())}, 1171 } 1172 } 1173 1174 var pub, rawPriv []byte 1175 1176 switch ca.Details.Curve { 1177 case Curve_CURVE25519: 1178 pub, rawPriv = x25519Keypair() 1179 case Curve_P256: 1180 pub, rawPriv = p256Keypair() 1181 default: 1182 return nil, nil, nil, fmt.Errorf("unknown curve: %v", ca.Details.Curve) 1183 } 1184 1185 nc := &NebulaCertificate{ 1186 Details: NebulaCertificateDetails{ 1187 Name: "testing", 1188 Ips: ips, 1189 Subnets: subnets, 1190 Groups: groups, 1191 NotBefore: time.Unix(before.Unix(), 0), 1192 NotAfter: time.Unix(after.Unix(), 0), 1193 PublicKey: pub, 1194 IsCA: false, 1195 Curve: ca.Details.Curve, 1196 Issuer: issuer, 1197 InvertedGroups: make(map[string]struct{}), 1198 }, 1199 } 1200 1201 err = nc.Sign(ca.Details.Curve, key) 1202 if err != nil { 1203 return nil, nil, nil, err 1204 } 1205 1206 return nc, pub, rawPriv, nil 1207 } 1208 1209 func x25519Keypair() ([]byte, []byte) { 1210 privkey := make([]byte, 32) 1211 if _, err := io.ReadFull(rand.Reader, privkey); err != nil { 1212 panic(err) 1213 } 1214 1215 pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint) 1216 if err != nil { 1217 panic(err) 1218 } 1219 1220 return pubkey, privkey 1221 } 1222 1223 func p256Keypair() ([]byte, []byte) { 1224 privkey, err := ecdh.P256().GenerateKey(rand.Reader) 1225 if err != nil { 1226 panic(err) 1227 } 1228 pubkey := privkey.PublicKey() 1229 return pubkey.Bytes(), privkey.Bytes() 1230 }