This commit is contained in:
2026-02-19 10:07:43 +00:00
parent 007438e372
commit 6e637ecf77
1763 changed files with 60820 additions and 279516 deletions

49
vendor/tailscale.com/tka/tka.go generated vendored
View File

@@ -1,7 +1,9 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Package tka (WIP) implements the Tailnet Key Authority.
//go:build !ts_omit_tailnetlock
// Package tka implements the Tailnet Key Authority (TKA) for Tailnet Lock.
package tka
import (
@@ -92,7 +94,7 @@ func computeChainCandidates(storage Chonk, lastKnownOldest *AUMHash, maxIter int
// candidates.Oldest needs to be computed by working backwards from
// head as far as we can.
iterAgain := true // if theres still work to be done.
iterAgain := true // if there's still work to be done.
for i := 0; iterAgain; i++ {
if i >= maxIter {
return nil, fmt.Errorf("iteration limit exceeded (%d)", maxIter)
@@ -100,14 +102,14 @@ func computeChainCandidates(storage Chonk, lastKnownOldest *AUMHash, maxIter int
iterAgain = false
for j := range candidates {
parent, hasParent := candidates[j].Oldest.Parent()
parentHash, hasParent := candidates[j].Oldest.Parent()
if hasParent {
parent, err := storage.AUM(parent)
parent, err := storage.AUM(parentHash)
if err != nil {
if err == os.ErrNotExist {
continue
}
return nil, fmt.Errorf("reading parent: %v", err)
return nil, fmt.Errorf("reading parent %s: %v", parentHash, err)
}
candidates[j].Oldest = parent
if lastKnownOldest != nil && *lastKnownOldest == parent.Hash() {
@@ -208,7 +210,7 @@ func fastForwardWithAdvancer(
}
nextAUM, err := storage.AUM(*startState.LastAUMHash)
if err != nil {
return AUM{}, State{}, fmt.Errorf("reading next: %v", err)
return AUM{}, State{}, fmt.Errorf("reading next (%v): %v", *startState.LastAUMHash, err)
}
curs := nextAUM
@@ -293,9 +295,9 @@ func computeStateAt(storage Chonk, maxIter int, wantHash AUMHash) (State, error)
}
// If we got here, the current state is dependent on the previous.
// Keep iterating backwards till thats not the case.
// Keep iterating backwards till that's not the case.
if curs, err = storage.AUM(parent); err != nil {
return State{}, fmt.Errorf("reading parent: %v", err)
return State{}, fmt.Errorf("reading parent (%v): %v", parent, err)
}
}
@@ -322,7 +324,7 @@ func computeStateAt(storage Chonk, maxIter int, wantHash AUMHash) (State, error)
return curs.Hash() == wantHash
})
// fastForward only terminates before the done condition if it
// doesnt have any later AUMs to process. This cant be the case
// doesn't have any later AUMs to process. This can't be the case
// as we've already iterated through them above so they must exist,
// but we check anyway to be super duper sure.
if err == nil && *state.LastAUMHash != wantHash {
@@ -334,13 +336,13 @@ func computeStateAt(storage Chonk, maxIter int, wantHash AUMHash) (State, error)
// computeActiveAncestor determines which ancestor AUM to use as the
// ancestor of the valid chain.
//
// If all the chains end up having the same ancestor, then thats the
// If all the chains end up having the same ancestor, then that's the
// only possible ancestor, ezpz. However if there are multiple distinct
// ancestors, that means there are distinct chains, and we need some
// hint to choose what to use. For that, we rely on the chainsThroughActive
// bit, which signals to us that that ancestor was part of the
// chain in a previous run.
func computeActiveAncestor(storage Chonk, chains []chain) (AUMHash, error) {
func computeActiveAncestor(chains []chain) (AUMHash, error) {
// Dedupe possible ancestors, tracking if they were part of
// the active chain on a previous run.
ancestors := make(map[AUMHash]bool, len(chains))
@@ -355,7 +357,7 @@ func computeActiveAncestor(storage Chonk, chains []chain) (AUMHash, error) {
}
}
// Theres more than one, so we need to use the ancestor that was
// There's more than one, so we need to use the ancestor that was
// part of the active chain in a previous iteration.
// Note that there can only be one distinct ancestor that was
// formerly part of the active chain, because AUMs can only have
@@ -389,8 +391,12 @@ func computeActiveChain(storage Chonk, lastKnownOldest *AUMHash, maxIter int) (c
return chain{}, fmt.Errorf("computing candidates: %v", err)
}
if len(chains) == 0 {
return chain{}, errors.New("no chain candidates in AUM storage")
}
// Find the right ancestor.
oldestHash, err := computeActiveAncestor(storage, chains)
oldestHash, err := computeActiveAncestor(chains)
if err != nil {
return chain{}, fmt.Errorf("computing ancestor: %v", err)
}
@@ -440,6 +446,13 @@ func aumVerify(aum AUM, state State, isGenesisAUM bool) error {
return fmt.Errorf("signature %d: %v", i, err)
}
}
if aum.MessageKind == AUMRemoveKey && len(state.Keys) == 1 {
if kid, err := state.Keys[0].ID(); err == nil && bytes.Equal(aum.KeyID, kid) {
return errors.New("cannot remove the last key in the state")
}
}
return nil
}
@@ -466,7 +479,7 @@ func (a *Authority) Head() AUMHash {
// Open initializes an existing TKA from the given tailchonk.
//
// Only use this if the current node has initialized an Authority before.
// If a TKA exists on other nodes but theres nothing locally, use Bootstrap().
// If a TKA exists on other nodes but there's nothing locally, use Bootstrap().
// If no TKA exists anywhere and you are creating it for the first
// time, use New().
func Open(storage Chonk) (*Authority, error) {
@@ -579,14 +592,14 @@ func (a *Authority) InformIdempotent(storage Chonk, updates []AUM) (Authority, e
toCommit := make([]AUM, 0, len(updates))
prevHash := a.Head()
// The state at HEAD is the current state of the authority. Its likely
// The state at HEAD is the current state of the authority. It's likely
// to be needed, so we prefill it rather than computing it.
stateAt[prevHash] = a.state
// Optimization: If the set of updates is a chain building from
// the current head, EG:
// <a.Head()> ==> updates[0] ==> updates[1] ...
// Then theres no need to recompute the resulting state from the
// Then there's no need to recompute the resulting state from the
// stored ancestor, because the last state computed during iteration
// is the new state. This should be the common case.
// isHeadChain keeps track of this.
@@ -766,8 +779,8 @@ func (a *Authority) findParentForRewrite(storage Chonk, removeKeys []tkatype.Key
}
}
if !keyTrusted {
// Success: the revoked keys are not trusted!
// Lets check that our key was trusted to ensure
// Success: the revoked keys are not trusted.
// Check that our key was trusted to ensure
// we can sign a fork from here.
if _, err := state.GetKey(ourKey); err == nil {
break