mirror of
https://github.com/tailscale/tailscale.git
synced 2025-02-27 10:47:35 +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 @@ package ipnlocal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -418,6 +420,11 @@ func (b *LocalBackend) NetworkLockInit(keys []tka.Key, disablementValues [][]byt
|
|||||||
return errors.New("no node-key: is tailscale logged in?")
|
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.
|
// Generates a genesis AUM representing trust in the provided keys.
|
||||||
// We use an in-memory tailchonk because we don't want to commit to
|
// We use an in-memory tailchonk because we don't want to commit to
|
||||||
// the filesystem until we've finished the initialization sequence,
|
// 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.
|
// - DisablementSecret: value needed to disable.
|
||||||
// - DisablementValue: the KDF of the disablement secret, a public value.
|
// - DisablementValue: the KDF of the disablement secret, a public value.
|
||||||
DisablementSecrets: disablementValues,
|
DisablementSecrets: disablementValues,
|
||||||
|
|
||||||
|
StateID1: binary.LittleEndian.Uint64(entropy[:8]),
|
||||||
|
StateID2: binary.LittleEndian.Uint64(entropy[8:]),
|
||||||
}, nlPriv)
|
}, nlPriv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("tka.Create: %v", err)
|
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 are the public keys currently trusted by the TKA.
|
||||||
Keys []Key `cbor:"3,keyasint"`
|
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.
|
// 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()
|
// slice for encoding purposes, so an implementation of Clone()
|
||||||
// must take care to preserve this.
|
// must take care to preserve this.
|
||||||
func (s State) Clone() State {
|
func (s State) Clone() State {
|
||||||
out := State{}
|
out := State{
|
||||||
|
StateID1: s.StateID1,
|
||||||
|
StateID2: s.StateID2,
|
||||||
|
}
|
||||||
|
|
||||||
if s.LastAUMHash != nil {
|
if s.LastAUMHash != nil {
|
||||||
dupe := *s.LastAUMHash
|
dupe := *s.LastAUMHash
|
||||||
@ -149,6 +159,13 @@ func (s State) applyVerifiedAUM(update AUM) (State, error) {
|
|||||||
return out, nil
|
return out, nil
|
||||||
|
|
||||||
case AUMCheckpoint:
|
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
|
return update.State.cloneForUpdate(&update), nil
|
||||||
|
|
||||||
case AUMAddKey:
|
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"}}},
|
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",
|
"DisablementSecrets",
|
||||||
State{
|
State{
|
||||||
@ -223,6 +230,12 @@ func TestApplyUpdateErrors(t *testing.T) {
|
|||||||
},
|
},
|
||||||
errors.New("parent AUMHash mismatch"),
|
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 {
|
for _, tc := range tcs {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user