WIP: rebase for 2026-05-18 #7
@@ -22,15 +22,12 @@ func TestHandleC2NDebugTKA(t *testing.T) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
signerKey := key.NewNLPrivate()
|
||||
key1 := tka.Key{Kind: tka.Key25519, Public: signerKey.Public().Verifier(), Votes: 2}
|
||||
state := tka.CreateStateForTest(key1)
|
||||
|
||||
chonk := tka.ChonkMem()
|
||||
authority, _, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key1},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, signerKey)
|
||||
authority, _, err := tka.Create(chonk, state, signerKey)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -84,7 +84,29 @@ func fakeNoiseServer(t *testing.T, handler http.HandlerFunc) (*httptest.Server,
|
||||
return ts, client
|
||||
}
|
||||
|
||||
// newLocalBackendForTKA creates a new instance of [LocalBackend] for testing
|
||||
// Tailnet Lock, in particular setting the tka field.
|
||||
func newLocalBackendForTKA(t *testing.T, varRoot string, client *http.Client, pm *profileManager, authority *tka.Authority, chonk tka.CompactableChonk) LocalBackend {
|
||||
t.Helper()
|
||||
cc := fakeControlClient(t, client)
|
||||
return LocalBackend{
|
||||
varRoot: varRoot,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
profile: pm.CurrentProfile().ID(),
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
}
|
||||
|
||||
func setupProfileManager(t *testing.T, nodePriv key.NodePrivate, nlPriv key.NLPrivate) *profileManager {
|
||||
t.Helper()
|
||||
pm := must.Get(newProfileManager(new(mem.Store), t.Logf, health.NewTracker(eventbustest.NewBus(t))))
|
||||
must.Do(pm.SetPrefs((&ipn.Prefs{
|
||||
Persist: &persist.Persist{
|
||||
@@ -95,6 +117,18 @@ func setupProfileManager(t *testing.T, nodePriv key.NodePrivate, nlPriv key.NLPr
|
||||
return pm
|
||||
}
|
||||
|
||||
// setupChonkStorage creates a new [tka.FS] in a temporary folder.
|
||||
func setupChonkStorage(t *testing.T, pm *profileManager) (varRoot string, chonk *tka.FS) {
|
||||
varRoot = t.TempDir()
|
||||
tkaPath := filepath.Join(varRoot, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return varRoot, chonk
|
||||
}
|
||||
|
||||
func TestTKAEnablementFlow(t *testing.T) {
|
||||
nodePriv := key.NewNode()
|
||||
|
||||
@@ -102,11 +136,9 @@ func TestTKAEnablementFlow(t *testing.T) {
|
||||
// our mock server can communicate.
|
||||
nlPriv := key.NewNLPrivate()
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
state := tka.CreateStateForTest(key)
|
||||
chonk := tka.ChonkMem()
|
||||
a1, genesisAUM, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key},
|
||||
DisablementValues: [][]byte{bytes.Repeat([]byte{0xa5}, 32)},
|
||||
}, nlPriv)
|
||||
a1, genesisAUM, err := tka.Create(chonk, state, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -188,13 +220,7 @@ func TestTKADisablementFlow(t *testing.T) {
|
||||
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
varRoot, chonk := setupChonkStorage(t, pm)
|
||||
authority, _, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
@@ -239,20 +265,7 @@ func TestTKADisablementFlow(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, authority, chonk)
|
||||
|
||||
// Test that the wrong disablement secret does not shut down the authority.
|
||||
returnWrongSecret = true
|
||||
@@ -289,8 +302,6 @@ func TestTKASync(t *testing.T) {
|
||||
someKeyPriv := key.NewNLPrivate()
|
||||
someKey := tka.Key{Kind: tka.Key25519, Public: someKeyPriv.Public().Verifier(), Votes: 1}
|
||||
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
|
||||
type tkaSyncScenario struct {
|
||||
name string
|
||||
// controlAUMs is called (if non-nil) to get any AUMs which the tka state
|
||||
@@ -369,10 +380,8 @@ func TestTKASync(t *testing.T) {
|
||||
// Setup the tka authority on the control plane.
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
controlStorage := tka.ChonkMem()
|
||||
controlAuthority, bootstrap, err := tka.Create(controlStorage, tka.State{
|
||||
Keys: []tka.Key{key, someKey},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, nlPriv)
|
||||
controlState := tka.CreateStateForTest(key, someKey)
|
||||
controlAuthority, bootstrap, err := tka.Create(controlStorage, controlState, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -382,14 +391,8 @@ func TestTKASync(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
// Setup the TKA authority on the node.
|
||||
nodeStorage, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
varRoot, nodeStorage := setupChonkStorage(t, pm)
|
||||
nodeAuthority, err := tka.Bootstrap(nodeStorage, bootstrap)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Bootstrap() failed: %v", err)
|
||||
@@ -424,20 +427,7 @@ func TestTKASync(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
// Setup the client.
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
tka: &tkaState{
|
||||
authority: nodeAuthority,
|
||||
storage: nodeStorage,
|
||||
},
|
||||
}
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, nodeAuthority, nodeStorage)
|
||||
|
||||
// Finally, let's trigger a sync.
|
||||
err = b.tkaSyncIfNeeded(&netmap.NetworkMap{
|
||||
@@ -463,8 +453,6 @@ func TestTKASyncTriggersCompact(t *testing.T) {
|
||||
someKeyPriv := key.NewNLPrivate()
|
||||
someKey := tka.Key{Kind: tka.Key25519, Public: someKeyPriv.Public().Verifier(), Votes: 1}
|
||||
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
|
||||
nodePriv := key.NewNode()
|
||||
nlPriv := key.NewNLPrivate()
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
@@ -480,10 +468,8 @@ func TestTKASyncTriggersCompact(t *testing.T) {
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
controlStorage := tka.ChonkMem()
|
||||
controlStorage.SetClock(clock)
|
||||
controlAuthority, bootstrap, err := tka.Create(controlStorage, tka.State{
|
||||
Keys: []tka.Key{key, someKey},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, nlPriv)
|
||||
controlState := tka.CreateStateForTest(key, someKey)
|
||||
controlAuthority, bootstrap, err := tka.Create(controlStorage, controlState, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -542,19 +528,8 @@ func TestTKASyncTriggersCompact(t *testing.T) {
|
||||
defer ts.Close()
|
||||
|
||||
// Setup the client.
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
tka: &tkaState{
|
||||
authority: nodeAuthority,
|
||||
storage: nodeStorage,
|
||||
},
|
||||
}
|
||||
varRoot := ""
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, nodeAuthority, nodeStorage)
|
||||
|
||||
// Trigger a sync.
|
||||
err = b.tkaSyncIfNeeded(&netmap.NetworkMap{
|
||||
@@ -610,11 +585,9 @@ func TestTKASyncTriggersCompact(t *testing.T) {
|
||||
func TestTKAFilterNetmap(t *testing.T) {
|
||||
nlPriv := key.NewNLPrivate()
|
||||
nlKey := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
state := tka.CreateStateForTest(nlKey)
|
||||
storage := tka.ChonkMem()
|
||||
authority, _, err := tka.Create(storage, tka.State{
|
||||
Keys: []tka.Key{nlKey},
|
||||
DisablementValues: [][]byte{bytes.Repeat([]byte{0xa5}, 32)},
|
||||
}, nlPriv)
|
||||
authority, _, err := tka.Create(storage, state, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -764,17 +737,11 @@ func TestTKADisable(t *testing.T) {
|
||||
// Make a fake TKA authority, to seed local state.
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
nlPriv := key.NewNLPrivate()
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
temp, chonk := setupChonkStorage(t, pm)
|
||||
authority, _, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
@@ -821,21 +788,7 @@ func TestTKADisable(t *testing.T) {
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
profile: pm.CurrentProfile().ID(),
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
b := newLocalBackendForTKA(t, temp, client, pm, authority, chonk)
|
||||
|
||||
// Test that we get an error for an incorrect disablement secret.
|
||||
if err := b.NetworkLockDisable([]byte{1, 2, 3, 4}); err == nil || err.Error() != "incorrect disablement secret" {
|
||||
@@ -854,20 +807,11 @@ func TestTKASign(t *testing.T) {
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
|
||||
// Make a fake TKA authority, to seed local state.
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
state := tka.CreateStateForTest(key)
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authority, _, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, nlPriv)
|
||||
varRoot, chonk := setupChonkStorage(t, pm)
|
||||
authority, _, err := tka.Create(chonk, state, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -887,20 +831,8 @@ func TestTKASign(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, authority, chonk)
|
||||
|
||||
if err := b.NetworkLockSign(toSign.Public(), nil); err != nil {
|
||||
t.Errorf("NetworkLockSign() failed: %v", err)
|
||||
@@ -911,23 +843,14 @@ func TestTKAForceDisable(t *testing.T) {
|
||||
nodePriv := key.NewNode()
|
||||
|
||||
// Make a fake TKA authority, to seed local state.
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
nlPriv := key.NewNLPrivate()
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
state := tka.CreateStateForTest(key)
|
||||
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authority, genesis, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, nlPriv)
|
||||
temp, chonk := setupChonkStorage(t, pm)
|
||||
authority, genesis, err := tka.Create(chonk, state, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -1002,20 +925,11 @@ func TestTKAAffectedSigs(t *testing.T) {
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
|
||||
// Make a fake TKA authority, to seed local state.
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
tkaKey := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
state := tka.CreateStateForTest(tkaKey)
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authority, _, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{tkaKey},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, nlPriv)
|
||||
varRoot, chonk := setupChonkStorage(t, pm)
|
||||
authority, _, err := tka.Create(chonk, state, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -1084,20 +998,7 @@ func TestTKAAffectedSigs(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, authority, chonk)
|
||||
|
||||
sigs, err := b.NetworkLockAffectedSigs(nlPriv.KeyID())
|
||||
switch {
|
||||
@@ -1130,22 +1031,13 @@ func TestTKARecoverCompromisedKeyFlow(t *testing.T) {
|
||||
pm := setupProfileManager(t, nodePriv, nlPriv)
|
||||
|
||||
// Make a fake TKA authority, to seed local state.
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
key := tka.Key{Kind: tka.Key25519, Public: nlPriv.Public().Verifier(), Votes: 2}
|
||||
cosignKey := tka.Key{Kind: tka.Key25519, Public: cosignPriv.Public().Verifier(), Votes: 2}
|
||||
compromisedKey := tka.Key{Kind: tka.Key25519, Public: compromisedPriv.Public().Verifier(), Votes: 1}
|
||||
state := tka.CreateStateForTest(key, compromisedKey, cosignKey)
|
||||
|
||||
temp := t.TempDir()
|
||||
tkaPath := filepath.Join(temp, "tka-profile", string(pm.CurrentProfile().ID()))
|
||||
os.Mkdir(tkaPath, 0755)
|
||||
chonk, err := tka.ChonkDir(tkaPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
authority, _, err := tka.Create(chonk, tka.State{
|
||||
Keys: []tka.Key{key, compromisedKey, cosignKey},
|
||||
DisablementValues: [][]byte{tka.DisablementKDF(disablementSecret)},
|
||||
}, nlPriv)
|
||||
varRoot, chonk := setupChonkStorage(t, pm)
|
||||
authority, _, err := tka.Create(chonk, state, nlPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
@@ -1170,20 +1062,7 @@ func TestTKARecoverCompromisedKeyFlow(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
cc := fakeControlClient(t, client)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
cc: cc,
|
||||
ccAuto: cc,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, authority, chonk)
|
||||
|
||||
aum, err := b.NetworkLockGenerateRecoveryAUM([]tkatype.KeyID{compromisedPriv.KeyID()}, tka.AUMHash{})
|
||||
if err != nil {
|
||||
@@ -1193,17 +1072,7 @@ func TestTKARecoverCompromisedKeyFlow(t *testing.T) {
|
||||
// Cosign using the cosigning key.
|
||||
{
|
||||
pm := setupProfileManager(t, nodePriv, cosignPriv)
|
||||
b := LocalBackend{
|
||||
varRoot: temp,
|
||||
logf: t.Logf,
|
||||
health: health.NewTracker(eventbustest.NewBus(t)),
|
||||
tka: &tkaState{
|
||||
authority: authority,
|
||||
storage: chonk,
|
||||
},
|
||||
pm: pm,
|
||||
store: pm.Store(),
|
||||
}
|
||||
b := newLocalBackendForTKA(t, varRoot, client, pm, authority, chonk)
|
||||
if aum, err = b.NetworkLockCosignRecoveryAUM(aum); err != nil {
|
||||
t.Fatalf("NetworkLockCosignRecoveryAUM() failed: %v", err)
|
||||
}
|
||||
|
||||
+14
-28
@@ -27,12 +27,10 @@ func (s signer25519) SignAUM(sigHash tkatype.AUMSigHash) ([]tkatype.Signature, e
|
||||
func TestAuthorityBuilderAddKey(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -61,12 +59,10 @@ func TestAuthorityBuilderAddKey(t *testing.T) {
|
||||
func TestAuthorityBuilderMaxKey(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -108,12 +104,10 @@ func TestAuthorityBuilderRemoveKey(t *testing.T) {
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
pub2, _ := testingKey25519(t, 2)
|
||||
key2 := Key{Kind: Key25519, Public: pub2, Votes: 1}
|
||||
state := CreateStateForTest(key, key2)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key, key2},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -154,12 +148,10 @@ func TestAuthorityBuilderRemoveKey(t *testing.T) {
|
||||
func TestAuthorityBuilderSetKeyVote(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -190,12 +182,10 @@ func TestAuthorityBuilderSetKeyVote(t *testing.T) {
|
||||
func TestAuthorityBuilderSetKeyMeta(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2, Meta: map[string]string{"a": "b"}}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -226,12 +216,10 @@ func TestAuthorityBuilderSetKeyMeta(t *testing.T) {
|
||||
func TestAuthorityBuilderMultiple(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -274,12 +262,10 @@ func TestAuthorityBuilderMultiple(t *testing.T) {
|
||||
func TestAuthorityBuilderCheckpointsAfterXUpdates(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
storage := ChonkMem()
|
||||
a, _, err := Create(storage, State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a, _, err := Create(storage, state, signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -321,10 +321,8 @@ func optTemplate(name string, template AUM) testchainOpt {
|
||||
}
|
||||
|
||||
func genesisTemplate(key Key) testchainOpt {
|
||||
return optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}})
|
||||
state := CreateStateForTest(key)
|
||||
return optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &state})
|
||||
}
|
||||
|
||||
func checkpointTemplate() testchainOpt {
|
||||
|
||||
+2
-4
@@ -72,10 +72,8 @@ func TestNLPrivate(t *testing.T) {
|
||||
// Test that key.NLPrivate implements Signer by making a new
|
||||
// authority.
|
||||
k := Key{Kind: Key25519, Public: pub.Verifier(), Votes: 1}
|
||||
_, aum, err := Create(ChonkMem(), State{
|
||||
Keys: []Key{k},
|
||||
DisablementValues: [][]byte{bytes.Repeat([]byte{1}, 32)},
|
||||
}, p)
|
||||
state := CreateStateForTest(k)
|
||||
_, aum, err := Create(ChonkMem(), state, p)
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
"tailscale.com/types/tkatype"
|
||||
"tailscale.com/util/testenv"
|
||||
)
|
||||
|
||||
// ErrNoSuchKey is returned if the key referenced by a KeyID does not exist.
|
||||
@@ -313,3 +314,18 @@ func (s *State) staticValidateCheckpoint() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateStateForTest creates a [State] that marks the given keys as trusted
|
||||
// with an arbitrary disablement value.
|
||||
//
|
||||
// This is only for use in tests, and will panic if called outside a test.
|
||||
func CreateStateForTest(keys ...Key) State {
|
||||
testenv.AssertInTest()
|
||||
|
||||
disablementSecret := bytes.Repeat([]byte{0xa5}, 32)
|
||||
|
||||
return State{
|
||||
Keys: keys,
|
||||
DisablementValues: [][]byte{DisablementKDF(disablementSecret)},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,12 +597,10 @@ func TestCompactLongButYoung(t *testing.T) {
|
||||
ourPriv := key.NewNLPrivate()
|
||||
ourKey := Key{Kind: Key25519, Public: ourPriv.Public().Verifier(), Votes: 1}
|
||||
someOtherKey := Key{Kind: Key25519, Public: key.NewNLPrivate().Public().Verifier(), Votes: 1}
|
||||
state := CreateStateForTest(ourKey, someOtherKey)
|
||||
|
||||
storage := ChonkMem()
|
||||
auth, _, err := Create(storage, State{
|
||||
Keys: []Key{ourKey, someOtherKey},
|
||||
DisablementValues: [][]byte{DisablementKDF(bytes.Repeat([]byte{0xa5}, 32))},
|
||||
}, ourPriv)
|
||||
auth, _, err := Create(storage, state, ourPriv)
|
||||
if err != nil {
|
||||
t.Fatalf("tka.Create() failed: %v", err)
|
||||
}
|
||||
|
||||
+20
-29
@@ -197,6 +197,7 @@ func TestComputeStateAt(t *testing.T) {
|
||||
// for tests you want one AUM to be 'lower' than another, so that
|
||||
// that chain is taken based on fork resolution rules).
|
||||
func fakeAUM(t *testing.T, template any, parent *AUMHash) (AUM, AUMHash) {
|
||||
t.Helper()
|
||||
if seed, ok := template.(int); ok {
|
||||
a := AUM{MessageKind: AUMNoOp, KeyID: []byte{byte(seed)}}
|
||||
if parent != nil {
|
||||
@@ -299,12 +300,17 @@ func TestAuthorityHead(t *testing.T) {
|
||||
func TestAuthorityValidDisablement(t *testing.T) {
|
||||
pub, _ := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
disablementSecret := []byte{1, 2, 3}
|
||||
state := State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF(disablementSecret)},
|
||||
}
|
||||
c := newTestchain(t, `
|
||||
G1 -> L1
|
||||
|
||||
G1.template = genesis
|
||||
`,
|
||||
genesisTemplate(key),
|
||||
optTemplate("genesis", AUM{MessageKind: AUMCheckpoint, State: &state}),
|
||||
)
|
||||
|
||||
a, _ := Open(c.Chonk())
|
||||
@@ -317,10 +323,7 @@ func TestCreateBootstrapAuthority(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
|
||||
a1, genesisAUM, err := Create(ChonkMem(), State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, signer25519(priv))
|
||||
a1, genesisAUM, err := Create(ChonkMem(), CreateStateForTest(key), signer25519(priv))
|
||||
if err != nil {
|
||||
t.Fatalf("Create() failed: %v", err)
|
||||
}
|
||||
@@ -349,10 +352,7 @@ func TestBootstrapChonkMustBeEmpty(t *testing.T) {
|
||||
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
// Bootstrap our chonk for the first time, which should succeed.
|
||||
_, _, err := Create(chonk, state, signer25519(priv))
|
||||
@@ -412,7 +412,7 @@ func TestAuthorityInformNonLinear(t *testing.T) {
|
||||
| -> L4 -> L5
|
||||
|
||||
G1.template = genesis
|
||||
L1.hashSeed = 3
|
||||
L1.hashSeed = 2
|
||||
L2.hashSeed = 2
|
||||
L4.hashSeed = 2
|
||||
`,
|
||||
@@ -445,6 +445,8 @@ func TestAuthorityInformNonLinear(t *testing.T) {
|
||||
}
|
||||
|
||||
if a.Head() != c.AUMHashes["L3"] {
|
||||
t.Logf("a.Head() = %s", a.Head())
|
||||
t.Logf("auMHashes = %v", c.AUMHashes)
|
||||
t.Fatal("authority did not converge to correct AUM")
|
||||
}
|
||||
}
|
||||
@@ -495,21 +497,12 @@ func TestInteropWithNLKey(t *testing.T) {
|
||||
pub2 := key.NewNLPrivate().Public()
|
||||
pub3 := key.NewNLPrivate().Public()
|
||||
|
||||
a, _, err := Create(ChonkMem(), State{
|
||||
Keys: []Key{
|
||||
{
|
||||
Kind: Key25519,
|
||||
Votes: 1,
|
||||
Public: pub1.KeyID(),
|
||||
},
|
||||
{
|
||||
Kind: Key25519,
|
||||
Votes: 1,
|
||||
Public: pub2.KeyID(),
|
||||
},
|
||||
},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}, priv1)
|
||||
state := CreateStateForTest(
|
||||
Key{Kind: Key25519, Votes: 1, Public: pub1.KeyID()},
|
||||
Key{Kind: Key25519, Votes: 1, Public: pub2.KeyID()},
|
||||
)
|
||||
|
||||
a, _, err := Create(ChonkMem(), state, priv1)
|
||||
if err != nil {
|
||||
t.Errorf("tka.Create: %v", err)
|
||||
return
|
||||
@@ -529,6 +522,7 @@ func TestInteropWithNLKey(t *testing.T) {
|
||||
func TestAuthorityCompact(t *testing.T) {
|
||||
pub, priv := testingKey25519(t, 1)
|
||||
key := Key{Kind: Key25519, Public: pub, Votes: 2}
|
||||
state := CreateStateForTest(key)
|
||||
|
||||
c := newTestchain(t, `
|
||||
G -> A -> B -> C -> D -> E
|
||||
@@ -537,10 +531,7 @@ func TestAuthorityCompact(t *testing.T) {
|
||||
C.template = checkpoint2
|
||||
`,
|
||||
genesisTemplate(key),
|
||||
optTemplate("checkpoint2", AUM{MessageKind: AUMCheckpoint, State: &State{
|
||||
Keys: []Key{key},
|
||||
DisablementValues: [][]byte{DisablementKDF([]byte{1, 2, 3})},
|
||||
}}),
|
||||
optTemplate("checkpoint2", AUM{MessageKind: AUMCheckpoint, State: &state}),
|
||||
optKey("key", key, priv),
|
||||
optSignAllUsing("key"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user