| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230 | package certimport (	"crypto/ecdh"	"crypto/ecdsa"	"crypto/elliptic"	"crypto/rand"	"fmt"	"io"	"net"	"testing"	"time"	"github.com/slackhq/nebula/test"	"github.com/stretchr/testify/assert"	"golang.org/x/crypto/curve25519"	"golang.org/x/crypto/ed25519"	"google.golang.org/protobuf/proto")func TestMarshalingNebulaCertificate(t *testing.T) {	before := time.Now().Add(time.Second * -60).Round(time.Second)	after := time.Now().Add(time.Second * 60).Round(time.Second)	pubKey := []byte("1234567890abcedfghij1234567890ab")	nc := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "testing",			Ips: []*net.IPNet{				{IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},				{IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},			},			Subnets: []*net.IPNet{				{IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},				{IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},			},			Groups:    []string{"test-group1", "test-group2", "test-group3"},			NotBefore: before,			NotAfter:  after,			PublicKey: pubKey,			IsCA:      false,			Issuer:    "1234567890abcedfghij1234567890ab",		},		Signature: []byte("1234567890abcedfghij1234567890ab"),	}	b, err := nc.Marshal()	assert.Nil(t, err)	//t.Log("Cert size:", len(b))	nc2, err := UnmarshalNebulaCertificate(b)	assert.Nil(t, err)	assert.Equal(t, nc.Signature, nc2.Signature)	assert.Equal(t, nc.Details.Name, nc2.Details.Name)	assert.Equal(t, nc.Details.NotBefore, nc2.Details.NotBefore)	assert.Equal(t, nc.Details.NotAfter, nc2.Details.NotAfter)	assert.Equal(t, nc.Details.PublicKey, nc2.Details.PublicKey)	assert.Equal(t, nc.Details.IsCA, nc2.Details.IsCA)	// IP byte arrays can be 4 or 16 in length so we have to go this route	assert.Equal(t, len(nc.Details.Ips), len(nc2.Details.Ips))	for i, wIp := range nc.Details.Ips {		assert.Equal(t, wIp.String(), nc2.Details.Ips[i].String())	}	assert.Equal(t, len(nc.Details.Subnets), len(nc2.Details.Subnets))	for i, wIp := range nc.Details.Subnets {		assert.Equal(t, wIp.String(), nc2.Details.Subnets[i].String())	}	assert.EqualValues(t, nc.Details.Groups, nc2.Details.Groups)}func TestNebulaCertificate_Sign(t *testing.T) {	before := time.Now().Add(time.Second * -60).Round(time.Second)	after := time.Now().Add(time.Second * 60).Round(time.Second)	pubKey := []byte("1234567890abcedfghij1234567890ab")	nc := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "testing",			Ips: []*net.IPNet{				{IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},				{IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},			},			Subnets: []*net.IPNet{				{IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},				{IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},			},			Groups:    []string{"test-group1", "test-group2", "test-group3"},			NotBefore: before,			NotAfter:  after,			PublicKey: pubKey,			IsCA:      false,			Issuer:    "1234567890abcedfghij1234567890ab",		},	}	pub, priv, err := ed25519.GenerateKey(rand.Reader)	assert.Nil(t, err)	assert.False(t, nc.CheckSignature(pub))	assert.Nil(t, nc.Sign(Curve_CURVE25519, priv))	assert.True(t, nc.CheckSignature(pub))	_, err = nc.Marshal()	assert.Nil(t, err)	//t.Log("Cert size:", len(b))}func TestNebulaCertificate_SignP256(t *testing.T) {	before := time.Now().Add(time.Second * -60).Round(time.Second)	after := time.Now().Add(time.Second * 60).Round(time.Second)	pubKey := []byte("01234567890abcedfghij1234567890ab1234567890abcedfghij1234567890ab")	nc := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "testing",			Ips: []*net.IPNet{				{IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},				{IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},			},			Subnets: []*net.IPNet{				{IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},				{IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},			},			Groups:    []string{"test-group1", "test-group2", "test-group3"},			NotBefore: before,			NotAfter:  after,			PublicKey: pubKey,			IsCA:      false,			Curve:     Curve_P256,			Issuer:    "1234567890abcedfghij1234567890ab",		},	}	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)	pub := elliptic.Marshal(elliptic.P256(), priv.PublicKey.X, priv.PublicKey.Y)	rawPriv := priv.D.FillBytes(make([]byte, 32))	assert.Nil(t, err)	assert.False(t, nc.CheckSignature(pub))	assert.Nil(t, nc.Sign(Curve_P256, rawPriv))	assert.True(t, nc.CheckSignature(pub))	_, err = nc.Marshal()	assert.Nil(t, err)	//t.Log("Cert size:", len(b))}func TestNebulaCertificate_Expired(t *testing.T) {	nc := NebulaCertificate{		Details: NebulaCertificateDetails{			NotBefore: time.Now().Add(time.Second * -60).Round(time.Second),			NotAfter:  time.Now().Add(time.Second * 60).Round(time.Second),		},	}	assert.True(t, nc.Expired(time.Now().Add(time.Hour)))	assert.True(t, nc.Expired(time.Now().Add(-time.Hour)))	assert.False(t, nc.Expired(time.Now()))}func TestNebulaCertificate_MarshalJSON(t *testing.T) {	time.Local = time.UTC	pubKey := []byte("1234567890abcedfghij1234567890ab")	nc := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "testing",			Ips: []*net.IPNet{				{IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},				{IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},			},			Subnets: []*net.IPNet{				{IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},				{IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},			},			Groups:    []string{"test-group1", "test-group2", "test-group3"},			NotBefore: time.Date(1, 0, 0, 1, 0, 0, 0, time.UTC),			NotAfter:  time.Date(1, 0, 0, 2, 0, 0, 0, time.UTC),			PublicKey: pubKey,			IsCA:      false,			Issuer:    "1234567890abcedfghij1234567890ab",		},		Signature: []byte("1234567890abcedfghij1234567890ab"),	}	b, err := nc.MarshalJSON()	assert.Nil(t, err)	assert.Equal(		t,		"{\"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\"}",		string(b),	)}func TestNebulaCertificate_Verify(t *testing.T) {	ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	h, err := ca.Sha256Sum()	assert.Nil(t, err)	caPool := NewCAPool()	caPool.CAs[h] = ca	f, err := c.Sha256Sum()	assert.Nil(t, err)	caPool.BlocklistFingerprint(f)	v, err := c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate is in the block list")	caPool.ResetCertBlocklist()	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	v, err = c.Verify(time.Now().Add(time.Hour*1000), caPool)	assert.False(t, v)	assert.EqualError(t, err, "root certificate is expired")	c, _, _, err = newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	v, err = c.Verify(time.Now().Add(time.Minute*6), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate is expired")	// Test group assertion	ca, _, caKey, err = newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "test2"})	assert.Nil(t, err)	caPem, err := ca.MarshalToPEM()	assert.Nil(t, err)	caPool = NewCAPool()	caPool.AddCACertificate(caPem)	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "bad"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained a group not present on the signing ca: bad")	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)}func TestNebulaCertificate_VerifyP256(t *testing.T) {	ca, _, caKey, err := newTestCaCertP256(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	h, err := ca.Sha256Sum()	assert.Nil(t, err)	caPool := NewCAPool()	caPool.CAs[h] = ca	f, err := c.Sha256Sum()	assert.Nil(t, err)	caPool.BlocklistFingerprint(f)	v, err := c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate is in the block list")	caPool.ResetCertBlocklist()	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	v, err = c.Verify(time.Now().Add(time.Hour*1000), caPool)	assert.False(t, v)	assert.EqualError(t, err, "root certificate is expired")	c, _, _, err = newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	v, err = c.Verify(time.Now().Add(time.Minute*6), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate is expired")	// Test group assertion	ca, _, caKey, err = newTestCaCertP256(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "test2"})	assert.Nil(t, err)	caPem, err := ca.MarshalToPEM()	assert.Nil(t, err)	caPool = NewCAPool()	caPool.AddCACertificate(caPem)	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1", "bad"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained a group not present on the signing ca: bad")	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{"test1"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)}func TestNebulaCertificate_Verify_IPs(t *testing.T) {	_, caIp1, _ := net.ParseCIDR("10.0.0.0/16")	_, caIp2, _ := net.ParseCIDR("192.168.0.0/24")	ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{caIp1, caIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	caPem, err := ca.MarshalToPEM()	assert.Nil(t, err)	caPool := NewCAPool()	caPool.AddCACertificate(caPem)	// ip is outside the network	cIp1 := &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}	cIp2 := &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 0, 0}}	c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err := c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.1.0.0/24")	// ip is outside the network reversed order of above	cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.1.0.0/24")	// ip is within the network but mask is outside	cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.0.1.0/15")	// ip is within the network but mask is outside reversed order of above	cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained an ip assignment outside the limitations of the signing ca: 10.0.1.0/15")	// ip and mask are within the network	cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 255, 0, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 128}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{cIp1, cIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	// Exact matches	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp1, caIp2}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	// Exact matches reversed	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp2, caIp1}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	// Exact matches reversed with just 1	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{caIp1}, []*net.IPNet{}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)}func TestNebulaCertificate_Verify_Subnets(t *testing.T) {	_, caIp1, _ := net.ParseCIDR("10.0.0.0/16")	_, caIp2, _ := net.ParseCIDR("192.168.0.0/24")	ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1, caIp2}, []string{"test"})	assert.Nil(t, err)	caPem, err := ca.MarshalToPEM()	assert.Nil(t, err)	caPool := NewCAPool()	caPool.AddCACertificate(caPem)	// ip is outside the network	cIp1 := &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}	cIp2 := &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 0, 0}}	c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})	assert.Nil(t, err)	v, err := c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.1.0.0/24")	// ip is outside the network reversed order of above	cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("10.1.0.0"), Mask: []byte{255, 255, 255, 0}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.1.0.0/24")	// ip is within the network but mask is outside	cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.0.1.0/15")	// ip is within the network but mask is outside reversed order of above	cIp1 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 254, 0, 0}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.False(t, v)	assert.EqualError(t, err, "certificate contained a subnet assignment outside the limitations of the signing ca: 10.0.1.0/15")	// ip and mask are within the network	cIp1 = &net.IPNet{IP: net.ParseIP("10.0.1.0"), Mask: []byte{255, 255, 0, 0}}	cIp2 = &net.IPNet{IP: net.ParseIP("192.168.0.1"), Mask: []byte{255, 255, 255, 128}}	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{cIp1, cIp2}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	// Exact matches	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1, caIp2}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	// Exact matches reversed	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp2, caIp1}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)	// Exact matches reversed with just 1	c, _, _, err = newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{caIp1}, []string{"test"})	assert.Nil(t, err)	v, err = c.Verify(time.Now(), caPool)	assert.True(t, v)	assert.Nil(t, err)}func TestNebulaCertificate_VerifyPrivateKey(t *testing.T) {	ca, _, caKey, err := newTestCaCert(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	err = ca.VerifyPrivateKey(Curve_CURVE25519, caKey)	assert.Nil(t, err)	_, _, caKey2, err := newTestCaCert(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	err = ca.VerifyPrivateKey(Curve_CURVE25519, caKey2)	assert.NotNil(t, err)	c, _, priv, err := newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	err = c.VerifyPrivateKey(Curve_CURVE25519, priv)	assert.Nil(t, err)	_, priv2 := x25519Keypair()	err = c.VerifyPrivateKey(Curve_CURVE25519, priv2)	assert.NotNil(t, err)}func TestNebulaCertificate_VerifyPrivateKeyP256(t *testing.T) {	ca, _, caKey, err := newTestCaCertP256(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	err = ca.VerifyPrivateKey(Curve_P256, caKey)	assert.Nil(t, err)	_, _, caKey2, err := newTestCaCertP256(time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	err = ca.VerifyPrivateKey(Curve_P256, caKey2)	assert.NotNil(t, err)	c, _, priv, err := newTestCert(ca, caKey, time.Time{}, time.Time{}, []*net.IPNet{}, []*net.IPNet{}, []string{})	err = c.VerifyPrivateKey(Curve_P256, priv)	assert.Nil(t, err)	_, priv2 := p256Keypair()	err = c.VerifyPrivateKey(Curve_P256, priv2)	assert.NotNil(t, err)}func TestNewCAPoolFromBytes(t *testing.T) {	noNewLines := `# Current provisional, Remove once everything moves over to the real root.-----BEGIN NEBULA CERTIFICATE-----CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbLvcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszvbzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB-----END NEBULA CERTIFICATE-----# root-ca01-----BEGIN NEBULA CERTIFICATE-----CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTGBVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF-----END NEBULA CERTIFICATE-----`	withNewLines := `# Current provisional, Remove once everything moves over to the real root.-----BEGIN NEBULA CERTIFICATE-----CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbLvcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszvbzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB-----END NEBULA CERTIFICATE-----# root-ca01-----BEGIN NEBULA CERTIFICATE-----CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTGBVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF-----END NEBULA CERTIFICATE-----`	expired := `# expired certificate-----BEGIN NEBULA CERTIFICATE-----CjkKB2V4cGlyZWQouPmWjQYwufmWjQY6ILCRaoCkJlqHgv5jfDN4lzLHBvDzaQm4vZxfu144hmgjQAESQG4qlnZi8DncvD/LDZnLgJHOaX1DWCHHEh59epVsC+BNgTieWH1M9n4O7cFtGlM6sJJOS+rCVVEJ3ABS7+MPdQs=-----END NEBULA CERTIFICATE-----`	p256 := `# p256 certificate-----BEGIN NEBULA CERTIFICATE-----CmYKEG5lYnVsYSBQMjU2IHRlc3Qo4s+7mgYw4tXrsAc6QQRkaW2jFmllYvN4+/k26tctO9sPT3jOx8ES6M1nIqOhpTmZeabF/4rELDqPV4aH5jfJut798DUXql0FlF8H76gvQAGgBgESRzBFAiEAib0/te6eMiZOKD8gdDeloMTS0wGuX2t0C7TFdUhAQzgCIBNWYMep3ysx9zCgknfG5dKtwGTaqF++BWKDYdyl34KX-----END NEBULA CERTIFICATE-----`	rootCA := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "nebula root ca",		},	}	rootCA01 := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "nebula root ca 01",		},	}	rootCAP256 := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "nebula P256 test",		},	}	p, err := NewCAPoolFromBytes([]byte(noNewLines))	assert.Nil(t, err)	assert.Equal(t, p.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name)	assert.Equal(t, p.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name)	pp, err := NewCAPoolFromBytes([]byte(withNewLines))	assert.Nil(t, err)	assert.Equal(t, pp.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name)	assert.Equal(t, pp.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name)	// expired cert, no valid certs	ppp, err := NewCAPoolFromBytes([]byte(expired))	assert.Equal(t, ErrExpired, err)	assert.Equal(t, ppp.CAs[string("152070be6bb19bc9e3bde4c2f0e7d8f4ff5448b4c9856b8eccb314fade0229b0")].Details.Name, "expired")	// expired cert, with valid certs	pppp, err := NewCAPoolFromBytes(append([]byte(expired), noNewLines...))	assert.Equal(t, ErrExpired, err)	assert.Equal(t, pppp.CAs[string("c9bfaf7ce8e84b2eeda2e27b469f4b9617bde192efd214b68891ecda6ed49522")].Details.Name, rootCA.Details.Name)	assert.Equal(t, pppp.CAs[string("5c9c3f23e7ee7fe97637cbd3a0a5b854154d1d9aaaf7b566a51f4a88f76b64cd")].Details.Name, rootCA01.Details.Name)	assert.Equal(t, pppp.CAs[string("152070be6bb19bc9e3bde4c2f0e7d8f4ff5448b4c9856b8eccb314fade0229b0")].Details.Name, "expired")	assert.Equal(t, len(pppp.CAs), 3)	ppppp, err := NewCAPoolFromBytes([]byte(p256))	assert.Nil(t, err)	assert.Equal(t, ppppp.CAs[string("a7938893ec8c4ef769b06d7f425e5e46f7a7f5ffa49c3bcf4a86b608caba9159")].Details.Name, rootCAP256.Details.Name)	assert.Equal(t, len(ppppp.CAs), 1)}func appendByteSlices(b ...[]byte) []byte {	retSlice := []byte{}	for _, v := range b {		retSlice = append(retSlice, v...)	}	return retSlice}func TestUnmrshalCertPEM(t *testing.T) {	goodCert := []byte(`# A good cert-----BEGIN NEBULA CERTIFICATE-----CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbLvcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszvbzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB-----END NEBULA CERTIFICATE-----`)	badBanner := []byte(`# A bad banner-----BEGIN NOT A NEBULA CERTIFICATE-----CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbLvcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszvbzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB-----END NOT A NEBULA CERTIFICATE-----`)	invalidPem := []byte(`# Not a valid PEM format-BEGIN NEBULA CERTIFICATE-----CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbLvcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszvbzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB-END NEBULA CERTIFICATE----`)	certBundle := appendByteSlices(goodCert, badBanner, invalidPem)	// Success test case	cert, rest, err := UnmarshalNebulaCertificateFromPEM(certBundle)	assert.NotNil(t, cert)	assert.Equal(t, rest, append(badBanner, invalidPem...))	assert.Nil(t, err)	// Fail due to invalid banner.	cert, rest, err = UnmarshalNebulaCertificateFromPEM(rest)	assert.Nil(t, cert)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "bytes did not contain a proper nebula certificate banner")	// Fail due to ivalid PEM format, because	// it's missing the requisite pre-encapsulation boundary.	cert, rest, err = UnmarshalNebulaCertificateFromPEM(rest)	assert.Nil(t, cert)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "input did not contain a valid PEM encoded block")}func TestUnmarshalSigningPrivateKey(t *testing.T) {	privKey := []byte(`# A good key-----BEGIN NEBULA ED25519 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==-----END NEBULA ED25519 PRIVATE KEY-----`)	privP256Key := []byte(`# A good key-----BEGIN NEBULA ECDSA P256 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NEBULA ECDSA P256 PRIVATE KEY-----`)	shortKey := []byte(`# A short key-----BEGIN NEBULA ED25519 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-----END NEBULA ED25519 PRIVATE KEY-----`)	invalidBanner := []byte(`# Invalid banner-----BEGIN NOT A NEBULA PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==-----END NOT A NEBULA PRIVATE KEY-----`)	invalidPem := []byte(`# Not a valid PEM format-BEGIN NEBULA ED25519 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==-END NEBULA ED25519 PRIVATE KEY-----`)	keyBundle := appendByteSlices(privKey, privP256Key, shortKey, invalidBanner, invalidPem)	// Success test case	k, rest, curve, err := UnmarshalSigningPrivateKey(keyBundle)	assert.Len(t, k, 64)	assert.Equal(t, rest, appendByteSlices(privP256Key, shortKey, invalidBanner, invalidPem))	assert.Equal(t, Curve_CURVE25519, curve)	assert.Nil(t, err)	// Success test case	k, rest, curve, err = UnmarshalSigningPrivateKey(rest)	assert.Len(t, k, 32)	assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))	assert.Equal(t, Curve_P256, curve)	assert.Nil(t, err)	// Fail due to short key	k, rest, curve, err = UnmarshalSigningPrivateKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))	assert.EqualError(t, err, "key was not 64 bytes, is invalid Ed25519 private key")	// Fail due to invalid banner	k, rest, curve, err = UnmarshalSigningPrivateKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519/ECDSA private key banner")	// Fail due to ivalid PEM format, because	// it's missing the requisite pre-encapsulation boundary.	k, rest, curve, err = UnmarshalSigningPrivateKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "input did not contain a valid PEM encoded block")}func TestDecryptAndUnmarshalSigningPrivateKey(t *testing.T) {	passphrase := []byte("DO NOT USE THIS KEY")	privKey := []byte(`# A good key-----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDToCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl+Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPBqrlJ69wer3ZUHFXA-----END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----`)	shortKey := []byte(`# A key which, once decrypted, is too short-----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCoga5h8owMEBWRSMMJKzuUvWce7k0qlBkQmCxiuLh80MuASW70YcKt8jeEIS2axo2V6zAKA9TSMcCsJW1kDDXEtL/xeGLF5T7sDl5COp4LU3pGxpV+KoeQ/S3gQCAAcnaOtnJQX+aSDnbO3jCHyP7U9CHbsrQr3bdH3Oy/WiYU=-----END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----`)	invalidBanner := []byte(`# Invalid banner (not encrypted)-----BEGIN NEBULA ED25519 PRIVATE KEY-----bWRp2CTVFhW9HD/qCd28ltDgK3w8VXSeaEYczDWos8sMUBqDb9jP3+NYwcS4lURGXgLvodMXZJuaFPssp+WwtA==-----END NEBULA ED25519 PRIVATE KEY-----`)	invalidPem := []byte(`# Not a valid PEM format-BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDToCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl+Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPBqrlJ69wer3ZUHFXA-END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----`)	keyBundle := appendByteSlices(privKey, shortKey, invalidBanner, invalidPem)	// Success test case	curve, k, rest, err := DecryptAndUnmarshalSigningPrivateKey(passphrase, keyBundle)	assert.Nil(t, err)	assert.Equal(t, Curve_CURVE25519, curve)	assert.Len(t, k, 64)	assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))	// Fail due to short key	curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest)	assert.EqualError(t, err, "key was not 64 bytes, is invalid ed25519 private key")	assert.Nil(t, k)	assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))	// Fail due to invalid banner	curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest)	assert.EqualError(t, err, "bytes did not contain a proper nebula encrypted Ed25519/ECDSA private key banner")	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	// Fail due to ivalid PEM format, because	// it's missing the requisite pre-encapsulation boundary.	curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey(passphrase, rest)	assert.EqualError(t, err, "input did not contain a valid PEM encoded block")	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	// Fail due to invalid passphrase	curve, k, rest, err = DecryptAndUnmarshalSigningPrivateKey([]byte("invalid passphrase"), privKey)	assert.EqualError(t, err, "invalid passphrase or corrupt private key")	assert.Nil(t, k)	assert.Equal(t, rest, []byte{})}func TestEncryptAndMarshalSigningPrivateKey(t *testing.T) {	// Having proved that decryption works correctly above, we can test the	// encryption function produces a value which can be decrypted	passphrase := []byte("passphrase")	bytes := []byte("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")	kdfParams := NewArgon2Parameters(64*1024, 4, 3)	key, err := EncryptAndMarshalSigningPrivateKey(Curve_CURVE25519, bytes, passphrase, kdfParams)	assert.Nil(t, err)	// Verify the "key" can be decrypted successfully	curve, k, rest, err := DecryptAndUnmarshalSigningPrivateKey(passphrase, key)	assert.Len(t, k, 64)	assert.Equal(t, Curve_CURVE25519, curve)	assert.Equal(t, rest, []byte{})	assert.Nil(t, err)	// EncryptAndMarshalEd25519PrivateKey does not create any errors itself}func TestUnmarshalPrivateKey(t *testing.T) {	privKey := []byte(`# A good key-----BEGIN NEBULA X25519 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NEBULA X25519 PRIVATE KEY-----`)	privP256Key := []byte(`# A good key-----BEGIN NEBULA P256 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NEBULA P256 PRIVATE KEY-----`)	shortKey := []byte(`# A short key-----BEGIN NEBULA X25519 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==-----END NEBULA X25519 PRIVATE KEY-----`)	invalidBanner := []byte(`# Invalid banner-----BEGIN NOT A NEBULA PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NOT A NEBULA PRIVATE KEY-----`)	invalidPem := []byte(`# Not a valid PEM format-BEGIN NEBULA X25519 PRIVATE KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-END NEBULA X25519 PRIVATE KEY-----`)	keyBundle := appendByteSlices(privKey, privP256Key, shortKey, invalidBanner, invalidPem)	// Success test case	k, rest, curve, err := UnmarshalPrivateKey(keyBundle)	assert.Len(t, k, 32)	assert.Equal(t, rest, appendByteSlices(privP256Key, shortKey, invalidBanner, invalidPem))	assert.Equal(t, Curve_CURVE25519, curve)	assert.Nil(t, err)	// Success test case	k, rest, curve, err = UnmarshalPrivateKey(rest)	assert.Len(t, k, 32)	assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))	assert.Equal(t, Curve_P256, curve)	assert.Nil(t, err)	// Fail due to short key	k, rest, curve, err = UnmarshalPrivateKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))	assert.EqualError(t, err, "key was not 32 bytes, is invalid CURVE25519 private key")	// Fail due to invalid banner	k, rest, curve, err = UnmarshalPrivateKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "bytes did not contain a proper nebula private key banner")	// Fail due to ivalid PEM format, because	// it's missing the requisite pre-encapsulation boundary.	k, rest, curve, err = UnmarshalPrivateKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "input did not contain a valid PEM encoded block")}func TestUnmarshalEd25519PublicKey(t *testing.T) {	pubKey := []byte(`# A good key-----BEGIN NEBULA ED25519 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NEBULA ED25519 PUBLIC KEY-----`)	shortKey := []byte(`# A short key-----BEGIN NEBULA ED25519 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==-----END NEBULA ED25519 PUBLIC KEY-----`)	invalidBanner := []byte(`# Invalid banner-----BEGIN NOT A NEBULA PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NOT A NEBULA PUBLIC KEY-----`)	invalidPem := []byte(`# Not a valid PEM format-BEGIN NEBULA ED25519 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-END NEBULA ED25519 PUBLIC KEY-----`)	keyBundle := appendByteSlices(pubKey, shortKey, invalidBanner, invalidPem)	// Success test case	k, rest, err := UnmarshalEd25519PublicKey(keyBundle)	assert.Equal(t, len(k), 32)	assert.Nil(t, err)	assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))	// Fail due to short key	k, rest, err = UnmarshalEd25519PublicKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))	assert.EqualError(t, err, "key was not 32 bytes, is invalid ed25519 public key")	// Fail due to invalid banner	k, rest, err = UnmarshalEd25519PublicKey(rest)	assert.Nil(t, k)	assert.EqualError(t, err, "bytes did not contain a proper nebula Ed25519 public key banner")	assert.Equal(t, rest, invalidPem)	// Fail due to ivalid PEM format, because	// it's missing the requisite pre-encapsulation boundary.	k, rest, err = UnmarshalEd25519PublicKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "input did not contain a valid PEM encoded block")}func TestUnmarshalX25519PublicKey(t *testing.T) {	pubKey := []byte(`# A good key-----BEGIN NEBULA X25519 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NEBULA X25519 PUBLIC KEY-----`)	pubP256Key := []byte(`# A good key-----BEGIN NEBULA P256 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NEBULA P256 PUBLIC KEY-----`)	shortKey := []byte(`# A short key-----BEGIN NEBULA X25519 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==-----END NEBULA X25519 PUBLIC KEY-----`)	invalidBanner := []byte(`# Invalid banner-----BEGIN NOT A NEBULA PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-----END NOT A NEBULA PUBLIC KEY-----`)	invalidPem := []byte(`# Not a valid PEM format-BEGIN NEBULA X25519 PUBLIC KEY-----AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=-END NEBULA X25519 PUBLIC KEY-----`)	keyBundle := appendByteSlices(pubKey, pubP256Key, shortKey, invalidBanner, invalidPem)	// Success test case	k, rest, curve, err := UnmarshalPublicKey(keyBundle)	assert.Equal(t, len(k), 32)	assert.Nil(t, err)	assert.Equal(t, rest, appendByteSlices(pubP256Key, shortKey, invalidBanner, invalidPem))	assert.Equal(t, Curve_CURVE25519, curve)	// Success test case	k, rest, curve, err = UnmarshalPublicKey(rest)	assert.Equal(t, len(k), 65)	assert.Nil(t, err)	assert.Equal(t, rest, appendByteSlices(shortKey, invalidBanner, invalidPem))	assert.Equal(t, Curve_P256, curve)	// Fail due to short key	k, rest, curve, err = UnmarshalPublicKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, appendByteSlices(invalidBanner, invalidPem))	assert.EqualError(t, err, "key was not 32 bytes, is invalid CURVE25519 public key")	// Fail due to invalid banner	k, rest, curve, err = UnmarshalPublicKey(rest)	assert.Nil(t, k)	assert.EqualError(t, err, "bytes did not contain a proper nebula public key banner")	assert.Equal(t, rest, invalidPem)	// Fail due to ivalid PEM format, because	// it's missing the requisite pre-encapsulation boundary.	k, rest, curve, err = UnmarshalPublicKey(rest)	assert.Nil(t, k)	assert.Equal(t, rest, invalidPem)	assert.EqualError(t, err, "input did not contain a valid PEM encoded block")}// Ensure that upgrading the protobuf library does not change how certificates// are marshalled, since this would break signature verificationfunc TestMarshalingNebulaCertificateConsistency(t *testing.T) {	before := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)	after := time.Date(2017, time.January, 18, 28, 40, 0, 0, time.UTC)	pubKey := []byte("1234567890abcedfghij1234567890ab")	nc := NebulaCertificate{		Details: NebulaCertificateDetails{			Name: "testing",			Ips: []*net.IPNet{				{IP: net.ParseIP("10.1.1.1"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("10.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},				{IP: net.ParseIP("10.1.1.3"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},			},			Subnets: []*net.IPNet{				{IP: net.ParseIP("9.1.1.1"), Mask: net.IPMask(net.ParseIP("255.0.255.0"))},				{IP: net.ParseIP("9.1.1.2"), Mask: net.IPMask(net.ParseIP("255.255.255.0"))},				{IP: net.ParseIP("9.1.1.3"), Mask: net.IPMask(net.ParseIP("255.255.0.0"))},			},			Groups:    []string{"test-group1", "test-group2", "test-group3"},			NotBefore: before,			NotAfter:  after,			PublicKey: pubKey,			IsCA:      false,			Issuer:    "1234567890abcedfghij1234567890ab",		},		Signature: []byte("1234567890abcedfghij1234567890ab"),	}	b, err := nc.Marshal()	assert.Nil(t, err)	//t.Log("Cert size:", len(b))	assert.Equal(t, "0aa2010a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf1220313233343536373839306162636564666768696a313233343536373839306162", fmt.Sprintf("%x", b))	b, err = proto.Marshal(nc.getRawDetails())	assert.Nil(t, err)	//t.Log("Raw cert size:", len(b))	assert.Equal(t, "0a0774657374696e67121b8182845080feffff0f828284508080fcff0f8382845080fe83f80f1a1b8182844880fe83f80f8282844880feffff0f838284488080fcff0f220b746573742d67726f757031220b746573742d67726f757032220b746573742d67726f75703328f0e0e7d70430a08681c4053a20313233343536373839306162636564666768696a3132333435363738393061624a081234567890abcedf", fmt.Sprintf("%x", b))}func TestNebulaCertificate_Copy(t *testing.T) {	ca, _, caKey, err := newTestCaCert(time.Now(), time.Now().Add(10*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	c, _, _, err := newTestCert(ca, caKey, time.Now(), time.Now().Add(5*time.Minute), []*net.IPNet{}, []*net.IPNet{}, []string{})	assert.Nil(t, err)	cc := c.Copy()	test.AssertDeepCopyEqual(t, c, cc)}func TestUnmarshalNebulaCertificate(t *testing.T) {	// Test that we don't panic with an invalid certificate (#332)	data := []byte("\x98\x00\x00")	_, err := UnmarshalNebulaCertificate(data)	assert.EqualError(t, err, "encoded Details was nil")}func newTestCaCert(before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {	pub, priv, err := ed25519.GenerateKey(rand.Reader)	if before.IsZero() {		before = time.Now().Add(time.Second * -60).Round(time.Second)	}	if after.IsZero() {		after = time.Now().Add(time.Second * 60).Round(time.Second)	}	nc := &NebulaCertificate{		Details: NebulaCertificateDetails{			Name:           "test ca",			NotBefore:      time.Unix(before.Unix(), 0),			NotAfter:       time.Unix(after.Unix(), 0),			PublicKey:      pub,			IsCA:           true,			InvertedGroups: make(map[string]struct{}),		},	}	if len(ips) > 0 {		nc.Details.Ips = ips	}	if len(subnets) > 0 {		nc.Details.Subnets = subnets	}	if len(groups) > 0 {		nc.Details.Groups = groups	}	err = nc.Sign(Curve_CURVE25519, priv)	if err != nil {		return nil, nil, nil, err	}	return nc, pub, priv, nil}func newTestCaCertP256(before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)	pub := elliptic.Marshal(elliptic.P256(), priv.PublicKey.X, priv.PublicKey.Y)	rawPriv := priv.D.FillBytes(make([]byte, 32))	if before.IsZero() {		before = time.Now().Add(time.Second * -60).Round(time.Second)	}	if after.IsZero() {		after = time.Now().Add(time.Second * 60).Round(time.Second)	}	nc := &NebulaCertificate{		Details: NebulaCertificateDetails{			Name:           "test ca",			NotBefore:      time.Unix(before.Unix(), 0),			NotAfter:       time.Unix(after.Unix(), 0),			PublicKey:      pub,			IsCA:           true,			Curve:          Curve_P256,			InvertedGroups: make(map[string]struct{}),		},	}	if len(ips) > 0 {		nc.Details.Ips = ips	}	if len(subnets) > 0 {		nc.Details.Subnets = subnets	}	if len(groups) > 0 {		nc.Details.Groups = groups	}	err = nc.Sign(Curve_P256, rawPriv)	if err != nil {		return nil, nil, nil, err	}	return nc, pub, rawPriv, nil}func newTestCert(ca *NebulaCertificate, key []byte, before, after time.Time, ips, subnets []*net.IPNet, groups []string) (*NebulaCertificate, []byte, []byte, error) {	issuer, err := ca.Sha256Sum()	if err != nil {		return nil, nil, nil, err	}	if before.IsZero() {		before = time.Now().Add(time.Second * -60).Round(time.Second)	}	if after.IsZero() {		after = time.Now().Add(time.Second * 60).Round(time.Second)	}	if len(groups) == 0 {		groups = []string{"test-group1", "test-group2", "test-group3"}	}	if len(ips) == 0 {		ips = []*net.IPNet{			{IP: net.ParseIP("10.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())},			{IP: net.ParseIP("10.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())},			{IP: net.ParseIP("10.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())},		}	}	if len(subnets) == 0 {		subnets = []*net.IPNet{			{IP: net.ParseIP("9.1.1.1").To4(), Mask: net.IPMask(net.ParseIP("255.0.255.0").To4())},			{IP: net.ParseIP("9.1.1.2").To4(), Mask: net.IPMask(net.ParseIP("255.255.255.0").To4())},			{IP: net.ParseIP("9.1.1.3").To4(), Mask: net.IPMask(net.ParseIP("255.255.0.0").To4())},		}	}	var pub, rawPriv []byte	switch ca.Details.Curve {	case Curve_CURVE25519:		pub, rawPriv = x25519Keypair()	case Curve_P256:		pub, rawPriv = p256Keypair()	default:		return nil, nil, nil, fmt.Errorf("unknown curve: %v", ca.Details.Curve)	}	nc := &NebulaCertificate{		Details: NebulaCertificateDetails{			Name:           "testing",			Ips:            ips,			Subnets:        subnets,			Groups:         groups,			NotBefore:      time.Unix(before.Unix(), 0),			NotAfter:       time.Unix(after.Unix(), 0),			PublicKey:      pub,			IsCA:           false,			Curve:          ca.Details.Curve,			Issuer:         issuer,			InvertedGroups: make(map[string]struct{}),		},	}	err = nc.Sign(ca.Details.Curve, key)	if err != nil {		return nil, nil, nil, err	}	return nc, pub, rawPriv, nil}func x25519Keypair() ([]byte, []byte) {	privkey := make([]byte, 32)	if _, err := io.ReadFull(rand.Reader, privkey); err != nil {		panic(err)	}	pubkey, err := curve25519.X25519(privkey, curve25519.Basepoint)	if err != nil {		panic(err)	}	return pubkey, privkey}func p256Keypair() ([]byte, []byte) {	privkey, err := ecdh.P256().GenerateKey(rand.Reader)	if err != nil {		panic(err)	}	pubkey := privkey.PublicKey()	return pubkey.Bytes(), privkey.Bytes()}
 |