mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-15 11:19:08 +02:00
76 lines
2.8 KiB
Go
76 lines
2.8 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
|
|
"github.com/netbirdio/netbird/shared/management/certposture"
|
|
"github.com/netbirdio/netbird/shared/management/certposture/certtest"
|
|
"github.com/netbirdio/netbird/shared/management/networkmap/nmdata"
|
|
"github.com/netbirdio/netbird/shared/management/proto"
|
|
)
|
|
|
|
func TestCertificateChallenge_StampAndVerifyRoundTrip(t *testing.T) {
|
|
serverKey := generateKey(t)
|
|
peerKey := generateKey(t).PublicKey()
|
|
ca := certtest.NewCA(t, "corp-root")
|
|
ctx := context.Background()
|
|
|
|
checks := toProtocolChecks(ctx, []*nmdata.PostureChecks{{
|
|
ID: "cert-check",
|
|
Checks: nmdata.ChecksDefinition{CertificateCheck: &nmdata.CertificateCheck{CACertificates: []string{ca.PEM}}},
|
|
}})
|
|
require.Len(t, checks, 1)
|
|
require.Equal(t, []string{ca.PEM}, checks[0].GetCertificateChallenge().GetCaCertificates())
|
|
require.Empty(t, checks[0].GetCertificateChallenge().GetNonce())
|
|
|
|
stampCertificateChallenges(checks, peerKey, serverKey)
|
|
nonce := checks[0].GetCertificateChallenge().GetNonce()
|
|
require.NotEmpty(t, nonce)
|
|
|
|
deviceKey := certtest.ECDSAKey(t)
|
|
leaf := ca.Issue(t, deviceKey, "device")
|
|
sigAlg, sig, err := certposture.Sign(deviceKey, nonce, peerKey[:])
|
|
require.NoError(t, err)
|
|
proofs := []*proto.CertificateProof{{Nonce: nonce, Chain: [][]byte{leaf.Raw}, SigAlg: sigAlg, Signature: sig}}
|
|
|
|
s := &Server{secretsManager: &TimeBasedAuthSecretsManager{wgKey: serverKey}}
|
|
|
|
chains := s.verifiedCertificates(ctx, peerKey, proofs)
|
|
require.Len(t, chains, 1)
|
|
assert.True(t, certposture.ChainMatchesCAs(chains[0], []string{ca.PEM}, time.Now()))
|
|
|
|
t.Run("proof replayed by another peer is rejected", func(t *testing.T) {
|
|
assert.Nil(t, s.verifiedCertificates(ctx, generateKey(t).PublicKey(), proofs))
|
|
})
|
|
t.Run("nonce from another management key is rejected", func(t *testing.T) {
|
|
other := &Server{secretsManager: &TimeBasedAuthSecretsManager{wgKey: generateKey(t)}}
|
|
assert.Nil(t, other.verifiedCertificates(ctx, peerKey, proofs))
|
|
})
|
|
t.Run("one invalid proof rejects the whole set", func(t *testing.T) {
|
|
bad := &proto.CertificateProof{Nonce: nonce, Chain: [][]byte{leaf.Raw}, SigAlg: sigAlg, Signature: []byte("junk")}
|
|
assert.Nil(t, s.verifiedCertificates(ctx, peerKey, append(proofs, bad)))
|
|
})
|
|
t.Run("no proofs yields no certificates", func(t *testing.T) {
|
|
assert.Nil(t, s.verifiedCertificates(ctx, peerKey, nil))
|
|
})
|
|
}
|
|
|
|
func TestStampCertificateChallenges_SkipsFileOnlyChecks(t *testing.T) {
|
|
checks := []*proto.Checks{{Files: []string{"/bin/agent"}}}
|
|
stampCertificateChallenges(checks, generateKey(t).PublicKey(), generateKey(t))
|
|
assert.Nil(t, checks[0].GetCertificateChallenge())
|
|
}
|
|
|
|
func generateKey(t *testing.T) wgtypes.Key {
|
|
t.Helper()
|
|
key, err := wgtypes.GeneratePrivateKey()
|
|
require.NoError(t, err)
|
|
return key
|
|
}
|