| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- package nebula
- import (
- "fmt"
- "net/netip"
- "strings"
- "testing"
- "time"
- "github.com/slackhq/nebula/cert"
- "github.com/slackhq/nebula/cert_test"
- "github.com/slackhq/nebula/config"
- "github.com/slackhq/nebula/test"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- func TestNewCipherSuite(t *testing.T) {
- tests := []struct {
- name string
- curve cert.Curve
- cipher string
- fips140Enforced bool
- wantErr string
- // wantName is the full expected CipherSuite name (<DH>_<Cipher>_<Hash>),
- // only checked when wantErr is empty. Asserting the whole name makes both
- // the curve and cipher selection load-bearing.
- wantName string
- }{
- {
- name: "curve25519 aesgcm, not enforced",
- curve: cert.Curve_CURVE25519,
- cipher: "aesgcm",
- wantName: "25519_AESGCM_SHA256",
- },
- {
- name: "curve25519 chachapoly, not enforced",
- curve: cert.Curve_CURVE25519,
- cipher: "chachapoly",
- wantName: "25519_ChaChaPoly_SHA256",
- },
- {
- name: "p256 aesgcm, not enforced",
- curve: cert.Curve_P256,
- cipher: "aesgcm",
- wantName: "P256_AESGCM_SHA256",
- },
- {
- name: "p256 aesgcm, enforced is allowed",
- curve: cert.Curve_P256,
- cipher: "aesgcm",
- fips140Enforced: true,
- wantName: "P256_AESGCM_SHA256",
- },
- {
- name: "curve25519 rejected when enforced",
- curve: cert.Curve_CURVE25519,
- cipher: "aesgcm",
- fips140Enforced: true,
- wantErr: "pki: use of Curve25519 is not allowed in FIPS 140-only mode",
- },
- {
- name: "chachapoly rejected when enforced",
- curve: cert.Curve_P256,
- cipher: "chachapoly",
- fips140Enforced: true,
- wantErr: "pki: use of ChaChaPoly is not allowed in FIPS 140-only mode",
- },
- {
- // Curve is checked before cipher, so a Curve25519+ChaChaPoly
- // request reports the Curve25519 rejection.
- name: "curve25519 chachapoly rejected on curve when enforced",
- curve: cert.Curve_CURVE25519,
- cipher: "chachapoly",
- fips140Enforced: true,
- wantErr: "pki: use of Curve25519 is not allowed in FIPS 140-only mode",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- cs, err := newCipherSuite(tt.curve, false, tt.cipher, tt.fips140Enforced)
- if tt.wantErr != "" {
- require.EqualError(t, err, tt.wantErr)
- assert.Nil(t, cs)
- return
- }
- require.NoError(t, err)
- require.NotNil(t, cs)
- assert.Equal(t, tt.wantName, string(cs.Name()))
- })
- }
- }
- func TestNewCipherSuiteUnsupportedCurve(t *testing.T) {
- cs, err := newCipherSuite(cert.Curve(99), false, "aesgcm", false)
- require.Error(t, err)
- assert.True(t, strings.HasPrefix(err.Error(), "unsupported curve:"), "got: %v", err)
- assert.Nil(t, cs)
- }
- func TestPKIReloadRestartRequired(t *testing.T) {
- ca, _, caKey, caPEM := cert_test.NewTestCaCert(cert.Version2, cert.Curve_CURVE25519, time.Time{}, time.Time{}, nil, nil, nil)
- pkiConfig := func(cipher, network string) string {
- _, _, keyPEM, certPEM := cert_test.NewTestCert(cert.Version2, cert.Curve_CURVE25519, ca, caKey, "host", time.Time{}, time.Time{}, []netip.Prefix{netip.MustParsePrefix(network)}, nil, nil)
- return fmt.Sprintf("cipher: %s\npki:\n ca: %q\n cert: %q\n key: %q\n", cipher, caPEM, certPEM, keyPEM)
- }
- c := config.NewC(test.NewLogger())
- require.NoError(t, c.LoadString(pkiConfig("aes", "10.1.0.2/24")))
- p, err := NewPKIFromConfig(test.NewLogger(), c)
- require.NoError(t, err)
- // A cert that changes our networks is refused and needs a restart, it is not a failure
- res := c.ReloadConfigString(pkiConfig("aes", "10.1.0.3/24"))
- require.NoError(t, res.Err)
- assert.True(t, res.RestartRequired)
- assert.False(t, res.Failed)
- assert.Equal(t, []netip.Prefix{netip.MustParsePrefix("10.1.0.2/24")}, p.getCertState().myVpnNetworks)
- // The cipher only applies at startup
- c2 := config.NewC(test.NewLogger())
- require.NoError(t, c2.LoadString(pkiConfig("aes", "10.1.0.2/24")))
- p, err = NewPKIFromConfig(test.NewLogger(), c2)
- require.NoError(t, err)
- res = c2.ReloadConfigString(pkiConfig("chachapoly", "10.1.0.2/24"))
- require.NoError(t, res.Err)
- assert.True(t, res.RestartRequired)
- assert.Equal(t, "aes", p.getCertState().cipher)
- // A cert that keeps our networks applies without a restart
- c3 := config.NewC(test.NewLogger())
- require.NoError(t, c3.LoadString(pkiConfig("aes", "10.1.0.2/24")))
- _, err = NewPKIFromConfig(test.NewLogger(), c3)
- require.NoError(t, err)
- res = c3.ReloadConfigString(pkiConfig("aes", "10.1.0.2/24"))
- require.NoError(t, res.Err)
- assert.False(t, res.RestartRequired)
- // A cert that can't be read is a failure, and a restart wouldn't help
- res = c3.ReloadConfigString(strings.Replace(pkiConfig("aes", "10.1.0.2/24"), "cert: \"", "cert: \"garbage", 1))
- require.NoError(t, res.Err)
- assert.True(t, res.Failed)
- assert.False(t, res.RestartRequired)
- }
- // A cert for a version we weren't running is accepted without comparing networks, so switching to one with different
- // networks needs a restart. One with the same networks doesn't
- func TestPKIReloadNewVersionWithOtherNetworks(t *testing.T) {
- ca1, _, ca1Key, ca1PEM := cert_test.NewTestCaCert(cert.Version1, cert.Curve_CURVE25519, time.Time{}, time.Time{}, nil, nil, nil)
- ca2, _, ca2Key, ca2PEM := cert_test.NewTestCaCert(cert.Version2, cert.Curve_CURVE25519, time.Time{}, time.Time{}, nil, nil, nil)
- caPEM := string(ca1PEM) + string(ca2PEM)
- pkiConfig := func(v cert.Version, network string) string {
- ca, caKey := ca1, ca1Key
- if v == cert.Version2 {
- ca, caKey = ca2, ca2Key
- }
- _, _, keyPEM, certPEM := cert_test.NewTestCert(v, cert.Curve_CURVE25519, ca, caKey, "host", time.Time{}, time.Time{}, []netip.Prefix{netip.MustParsePrefix(network)}, nil, nil)
- return fmt.Sprintf("pki:\n ca: %q\n cert: %q\n key: %q\n", caPEM, certPEM, keyPEM)
- }
- for _, tc := range []struct {
- network string
- restart bool
- }{
- {"10.9.0.7/24", true},
- {"10.1.0.2/24", false},
- } {
- c := config.NewC(test.NewLogger())
- require.NoError(t, c.LoadString(pkiConfig(cert.Version1, "10.1.0.2/24")))
- p, err := NewPKIFromConfig(test.NewLogger(), c)
- require.NoError(t, err)
- res := c.ReloadConfigString(pkiConfig(cert.Version2, tc.network))
- require.NoError(t, res.Err)
- assert.False(t, res.Failed, tc.network)
- assert.Equal(t, tc.restart, res.RestartRequired, tc.network)
- assert.Equal(t, []netip.Prefix{netip.MustParsePrefix(tc.network)}, p.getCertState().myVpnNetworks, "accepted either way, as before")
- }
- }
|