mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-14 10:49:07 +02:00
109 lines
3.7 KiB
Go
109 lines
3.7 KiB
Go
package certproof
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/netbirdio/netbird/shared/management/certposture"
|
|
"github.com/netbirdio/netbird/shared/management/certposture/certtest"
|
|
"github.com/netbirdio/netbird/shared/management/proto"
|
|
)
|
|
|
|
var peerKey = []byte("peer-public-key-aaaaaaaaaaaaaaaa")
|
|
|
|
func TestCollect_ProvesOneMatchingCertificatePerChallenge(t *testing.T) {
|
|
corpCA := certtest.NewCA(t, "corp-root")
|
|
otherCA := certtest.NewCA(t, "other-root")
|
|
unrelatedCA := certtest.NewCA(t, "unrelated-root")
|
|
|
|
dir := t.TempDir()
|
|
deviceKey := certtest.ECDSAKey(t)
|
|
device := corpCA.Issue(t, deviceKey, "device")
|
|
writeFile(t, dir, "device.pem", certtest.CertPEM(device)+certtest.KeyPEM(t, deviceKey))
|
|
|
|
otherKey := certtest.RSAKey(t)
|
|
writeFile(t, dir, "other.crt", certtest.CertPEM(otherCA.Issue(t, otherKey, "other")))
|
|
writeFile(t, dir, "other.key", certtest.KeyPEM(t, otherKey))
|
|
|
|
writeFile(t, dir, "keyless.crt", certtest.CertPEM(corpCA.Issue(t, certtest.ECDSAKey(t), "keyless")))
|
|
writeFile(t, dir, "notes.txt", "ignored")
|
|
|
|
challenger := certposture.NewChallenger([]byte("secret"))
|
|
nonce := challenger.Nonce(peerKey, time.Now())
|
|
challenge := func(cas ...string) *proto.Checks {
|
|
return &proto.Checks{CertificateChallenge: &proto.CertificateChallenge{Nonce: nonce, CaCertificates: cas}}
|
|
}
|
|
checks := []*proto.Checks{
|
|
{Files: []string{"/usr/bin/agent"}},
|
|
challenge(corpCA.PEM),
|
|
challenge(corpCA.PEM),
|
|
challenge(otherCA.PEM),
|
|
challenge(unrelatedCA.PEM),
|
|
challenge("not a pem"),
|
|
}
|
|
|
|
proofs := Collect(context.Background(), NewFileStore(dir), checks, peerKey)
|
|
|
|
require.Len(t, proofs, 2)
|
|
var subjects []string
|
|
for _, p := range proofs {
|
|
chain, err := challenger.Verify(p, peerKey, time.Now())
|
|
require.NoError(t, err)
|
|
subjects = append(subjects, chain[0].Subject.CommonName)
|
|
}
|
|
assert.ElementsMatch(t, []string{"device", "other"}, subjects)
|
|
}
|
|
|
|
func TestCollect_NothingToProve(t *testing.T) {
|
|
dir := t.TempDir()
|
|
key := certtest.ECDSAKey(t)
|
|
ca := certtest.NewCA(t, "root")
|
|
writeFile(t, dir, "device.pem", certtest.CertPEM(ca.Issue(t, key, "device"))+certtest.KeyPEM(t, key))
|
|
|
|
tests := []struct {
|
|
name string
|
|
store Store
|
|
checks []*proto.Checks
|
|
}{
|
|
{"no checks", NewFileStore(dir), nil},
|
|
{"files only", NewFileStore(dir), []*proto.Checks{{Files: []string{"/bin/x"}}}},
|
|
{"challenge without nonce", NewFileStore(dir), []*proto.Checks{{CertificateChallenge: &proto.CertificateChallenge{CaCertificates: []string{ca.PEM}}}}},
|
|
{"missing store dir", NewFileStore(filepath.Join(dir, "missing")), []*proto.Checks{{CertificateChallenge: &proto.CertificateChallenge{Nonce: []byte{1}, CaCertificates: []string{ca.PEM}}}}},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Nil(t, Collect(context.Background(), tt.store, tt.checks, peerKey))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFileStore_ChainWithIntermediate(t *testing.T) {
|
|
root := certtest.NewCA(t, "root")
|
|
intermediate := certtest.NewIntermediate(t, root, "intermediate")
|
|
key := certtest.ECDSAKey(t)
|
|
leaf := intermediate.Issue(t, key, "device")
|
|
|
|
dir := t.TempDir()
|
|
writeFile(t, dir, "device.pem", certtest.CertPEM(leaf)+certtest.CertPEM(intermediate.Cert)+certtest.KeyPEM(t, key))
|
|
|
|
candidates, err := NewFileStore(dir).Candidates(context.Background())
|
|
require.NoError(t, err)
|
|
require.Len(t, candidates, 1)
|
|
require.Len(t, candidates[0].Chain, 2)
|
|
|
|
roots, err := certposture.ParseCAs([]string{root.PEM})
|
|
require.NoError(t, err)
|
|
assert.NoError(t, certposture.VerifyChain(candidates[0].Chain, roots, time.Now()))
|
|
}
|
|
|
|
func writeFile(t *testing.T, dir, name, content string) {
|
|
t.Helper()
|
|
require.NoError(t, os.WriteFile(filepath.Join(dir, name), []byte(content), 0o600))
|
|
}
|