mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 04:55:31 +00:00
ipn/ipnlocal,tka: generate a nonce for each TKA
Signed-off-by: Tom DNetto <tom@tailscale.com>
This commit is contained in:
parent
6708f9a93f
commit
aeb80bf8cb
@ -6,7 +6,9 @@
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -418,6 +420,11 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byt
|
||||
return errors.New("no node-key: is tailscale logged in?")
|
||||
}
|
||||
|
||||
var entropy [16]byte
|
||||
if _, err := rand.Read(entropy[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generates a genesis AUM representing trust in the provided keys.
|
||||
// We use an in-memory tailchonk because we don't want to commit to
|
||||
// the filesystem until we've finished the initialization sequence,
|
||||
@ -429,6 +436,9 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byt
|
||||
// - DisablementSecret: value needed to disable.
|
||||
// - DisablementValue: the KDF of the disablement secret, a public value.
|
||||
DisablementSecrets: disablementValues,
|
||||
|
||||
StateID1: binary.LittleEndian.Uint64(entropy[:8]),
|
||||
StateID2: binary.LittleEndian.Uint64(entropy[8:]),
|
||||
}, nlPriv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("tka.Create: %v", err)
|
||||
|
19
tka/state.go
19
tka/state.go
@ -36,6 +36,13 @@ type State struct {
|
||||
|
||||
// Keys are the public keys currently trusted by the TKA.
|
||||
Keys []Key `cbor:"3,keyasint"`
|
||||
|
||||
// StateID's are nonce's, generated on enablement and fixed for
|
||||
// the lifetime of the Tailnet Key Authority. We generate 16-bytes
|
||||
// worth of keyspace here just in case we come up with a cool future
|
||||
// use for this.
|
||||
StateID1 uint64 `cbor:"4,keyasint,omitempty"`
|
||||
StateID2 uint64 `cbor:"5,keyasint,omitempty"`
|
||||
}
|
||||
|
||||
// GetKey returns the trusted key with the specified KeyID.
|
||||
@ -55,7 +62,10 @@ func (s State) GetKey(key tkatype.KeyID) (Key, error) {
|
||||
// slice for encoding purposes, so an implementation of Clone()
|
||||
// must take care to preserve this.
|
||||
func (s State) Clone() State {
|
||||
out := State{}
|
||||
out := State{
|
||||
StateID1: s.StateID1,
|
||||
StateID2: s.StateID2,
|
||||
}
|
||||
|
||||
if s.LastAUMHash != nil {
|
||||
dupe := *s.LastAUMHash
|
||||
@ -149,6 +159,13 @@ func (s State) applyVerifiedAUM(update AUM) (State, error) {
|
||||
return out, nil
|
||||
|
||||
case AUMCheckpoint:
|
||||
if update.State == nil {
|
||||
return State{}, errors.New("missing checkpoint state")
|
||||
}
|
||||
id1Match, id2Match := update.State.StateID1 == s.StateID1, update.State.StateID2 == s.StateID2
|
||||
if !id1Match || !id2Match {
|
||||
return State{}, errors.New("checkpointed state has an incorrect stateID")
|
||||
}
|
||||
return update.State.cloneForUpdate(&update), nil
|
||||
|
||||
case AUMAddKey:
|
||||
|
@ -44,6 +44,13 @@ func TestCloneState(t *testing.T) {
|
||||
Keys: []Key{{Kind: Key25519, Votes: 2, Public: []byte{5, 6, 7, 8}, Meta: map[string]string{"a": "b"}}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"StateID",
|
||||
State{
|
||||
StateID1: 42,
|
||||
StateID2: 22,
|
||||
},
|
||||
},
|
||||
{
|
||||
"DisablementSecrets",
|
||||
State{
|
||||
@ -223,6 +230,12 @@ func TestApplyUpdateErrors(t *testing.T) {
|
||||
},
|
||||
errors.New("parent AUMHash mismatch"),
|
||||
},
|
||||
{
|
||||
"Bad StateID",
|
||||
[]AUM{{MessageKind: AUMCheckpoint, State: &State{StateID1: 1}}},
|
||||
State{Keys: []Key{{Kind: Key25519, Public: []byte{1}}}, StateID1: 42},
|
||||
errors.New("checkpointed state has an incorrect stateID"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
|
Loading…
Reference in New Issue
Block a user