mirror of
https://github.com/slackhq/nebula.git
synced 2025-11-09 00:33:58 +01:00
* Support NIST curve P256 This change adds support for NIST curve P256. When you use `nebula-cert ca` or `nebula-cert keygen`, you can specify `-curve P256` to enable it. The curve to use is based on the curve defined in your CA certificate. Internally, we use ECDSA P256 to sign certificates, and ECDH P256 to do Noise handshakes. P256 is not supported natively in Noise Protocol, so we define `DHP256` in the `noiseutil` package to implement support for it. You cannot have a mixed network of Curve25519 and P256 certificates, since the Noise protocol will only attempt to parse using the Curve defined in the host's certificate. * verify the curves match in VerifyPrivateKey This would have failed anyways once we tried to actually use the bytes in the private key, but its better to detect the issue up front with a better error message. * add cert.Curve argument to Sign method * fix mismerge * use crypto/ecdh This is the preferred method for doing ECDH functions now, and also has a boringcrypto specific codepath. * remove other ecdh uses of crypto/elliptic use crypto/ecdh instead
1231 lines
45 KiB
Go
1231 lines
45 KiB
Go
package cert
|
|
|
|
import (
|
|
"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 has been blocked")
|
|
|
|
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+YGOiCUQGByMuNRhIlQBOyzXWbL
|
|
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
|
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
|
-----END NEBULA CERTIFICATE-----
|
|
# root-ca01
|
|
-----BEGIN NEBULA CERTIFICATE-----
|
|
CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTG
|
|
BVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf
|
|
8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF
|
|
-----END NEBULA CERTIFICATE-----
|
|
`
|
|
|
|
withNewLines := `
|
|
# Current provisional, Remove once everything moves over to the real root.
|
|
|
|
-----BEGIN NEBULA CERTIFICATE-----
|
|
CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
|
|
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
|
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
|
-----END NEBULA CERTIFICATE-----
|
|
|
|
# root-ca01
|
|
|
|
|
|
-----BEGIN NEBULA CERTIFICATE-----
|
|
CkMKEW5lYnVsYSByb290IGNhIDAxKJL2u9EFMJL86+cGOiDPXMH4oU6HZTk/CqTG
|
|
BVG+oJpAoqokUBbI4U0N8CSfpUABEkB/Pm5A2xyH/nc8mg/wvGUWG3pZ7nHzaDMf
|
|
8/phAUt+FLzqTECzQKisYswKvE3pl9mbEYKbOdIHrxdIp95mo4sF
|
|
-----END NEBULA CERTIFICATE-----
|
|
|
|
`
|
|
|
|
expired := `
|
|
# expired certificate
|
|
-----BEGIN NEBULA CERTIFICATE-----
|
|
CjkKB2V4cGlyZWQouPmWjQYwufmWjQY6ILCRaoCkJlqHgv5jfDN4lzLHBvDzaQm4
|
|
vZxfu144hmgjQAESQG4qlnZi8DncvD/LDZnLgJHOaX1DWCHHEh59epVsC+BNgTie
|
|
WH1M9n4O7cFtGlM6sJJOS+rCVVEJ3ABS7+MPdQs=
|
|
-----END NEBULA CERTIFICATE-----
|
|
`
|
|
|
|
p256 := `
|
|
# p256 certificate
|
|
-----BEGIN NEBULA CERTIFICATE-----
|
|
CmYKEG5lYnVsYSBQMjU2IHRlc3Qo4s+7mgYw4tXrsAc6QQRkaW2jFmllYvN4+/k2
|
|
6tctO9sPT3jOx8ES6M1nIqOhpTmZeabF/4rELDqPV4aH5jfJut798DUXql0FlF8H
|
|
76gvQAGgBgESRzBFAiEAib0/te6eMiZOKD8gdDeloMTS0wGuX2t0C7TFdUhAQzgC
|
|
IBNWYMep3ysx9zCgknfG5dKtwGTaqF++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+YGOiCUQGByMuNRhIlQBOyzXWbL
|
|
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
|
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
|
-----END NEBULA CERTIFICATE-----
|
|
`)
|
|
badBanner := []byte(`# A bad banner
|
|
-----BEGIN NOT A NEBULA CERTIFICATE-----
|
|
CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
|
|
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
|
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
|
-----END NOT A NEBULA CERTIFICATE-----
|
|
`)
|
|
invalidPem := []byte(`# Not a valid PEM format
|
|
-BEGIN NEBULA CERTIFICATE-----
|
|
CkAKDm5lYnVsYSByb290IGNhKJfap9AFMJfg1+YGOiCUQGByMuNRhIlQBOyzXWbL
|
|
vcKBwDhov900phEfJ5DN3kABEkDCq5R8qBiu8sl54yVfgRcQXEDt3cHr8UTSLszv
|
|
bzBEr00kERQxxTzTsH8cpYEgRoipvmExvg8WP8NdAJEYJosB
|
|
-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-----
|
|
CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDT
|
|
oCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl
|
|
+Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPB
|
|
qrlJ69wer3ZUHFXA
|
|
-----END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
|
|
`)
|
|
shortKey := []byte(`# A key which, once decrypted, is too short
|
|
-----BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
|
|
CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCoga5h8owMEBWRSMMJKzuUvWce7
|
|
k0qlBkQmCxiuLh80MuASW70YcKt8jeEIS2axo2V6zAKA9TSMcCsJW1kDDXEtL/xe
|
|
GLF5T7sDl5COp4LU3pGxpV+KoeQ/S3gQCAAcnaOtnJQX+aSDnbO3jCHyP7U9CHbs
|
|
rQr3bdH3Oy/WiYU=
|
|
-----END NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
|
|
`)
|
|
invalidBanner := []byte(`# Invalid banner (not encrypted)
|
|
-----BEGIN NEBULA ED25519 PRIVATE KEY-----
|
|
bWRp2CTVFhW9HD/qCd28ltDgK3w8VXSeaEYczDWos8sMUBqDb9jP3+NYwcS4lURG
|
|
XgLvodMXZJuaFPssp+WwtA==
|
|
-----END NEBULA ED25519 PRIVATE KEY-----
|
|
`)
|
|
invalidPem := []byte(`# Not a valid PEM format
|
|
-BEGIN NEBULA ED25519 ENCRYPTED PRIVATE KEY-----
|
|
CjwKC0FFUy0yNTYtR0NNEi0IExCAgIABGAEgBCognnjujd67Vsv99p22wfAjQaDT
|
|
oCMW1mdjkU3gACKNW4MSXOWR9Sts4C81yk1RUku2gvGKs3TB9LYoklLsIizSYOLl
|
|
+Vs//O1T0I1Xbml2XBAROsb/VSoDln/6LMqR4B6fn6B3GOsLBBqRI8daDl9lRMPB
|
|
qrlJ69wer3ZUHFXA
|
|
-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-----
|
|
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
|
AAAAAAAAAAAAAAAAAAAAAAA=
|
|
-----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 verification
|
|
func 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()
|
|
}
|