mirror of
https://github.com/tailscale/tailscale.git
synced 2025-11-30 23:11:33 +01:00
This reverts commit a760cbe33f4bed64b63c6118808d02b2771ff785. Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
parent
4c856078e4
commit
db7dcd516f
@ -7,6 +7,8 @@ import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -946,6 +948,26 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
||||
ConnectionHandleForTest: connectionHandleForTest,
|
||||
}
|
||||
|
||||
// If we have a hardware attestation key, sign the node key with it and send
|
||||
// the key & signature in the map request.
|
||||
if buildfeatures.HasTPM {
|
||||
if k := persist.AsStruct().AttestationKey; k != nil && !k.IsZero() {
|
||||
hwPub := key.HardwareAttestationPublicFromPlatformKey(k)
|
||||
request.HardwareAttestationKey = hwPub
|
||||
|
||||
t := c.clock.Now()
|
||||
msg := fmt.Sprintf("%d|%s", t.Unix(), nodeKey.String())
|
||||
digest := sha256.Sum256([]byte(msg))
|
||||
sig, err := k.Sign(nil, digest[:], crypto.SHA256)
|
||||
if err != nil {
|
||||
c.logf("failed to sign node key with hardware attestation key: %v", err)
|
||||
} else {
|
||||
request.HardwareAttestationKeySignature = sig
|
||||
request.HardwareAttestationKeySignatureTimestamp = t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var extraDebugFlags []string
|
||||
if buildfeatures.HasAdvertiseRoutes && hi != nil && c.netMon != nil && !c.skipIPForwardingCheck &&
|
||||
ipForwardingBroken(hi.RoutableIPs, c.netMon.InterfaceState()) {
|
||||
|
||||
48
ipn/ipnlocal/hwattest.go
Normal file
48
ipn/ipnlocal/hwattest.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ts_omit_tpm
|
||||
|
||||
package ipnlocal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"tailscale.com/feature"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/persist"
|
||||
)
|
||||
|
||||
func init() {
|
||||
feature.HookGenerateAttestationKeyIfEmpty.Set(generateAttestationKeyIfEmpty)
|
||||
}
|
||||
|
||||
// generateAttestationKeyIfEmpty generates a new hardware attestation key if
|
||||
// none exists. It returns true if a new key was generated and stored in
|
||||
// p.AttestationKey.
|
||||
func generateAttestationKeyIfEmpty(p *persist.Persist, logf logger.Logf) (bool, error) {
|
||||
// attempt to generate a new hardware attestation key if none exists
|
||||
var ak key.HardwareAttestationKey
|
||||
if p != nil {
|
||||
ak = p.AttestationKey
|
||||
}
|
||||
|
||||
if ak == nil || ak.IsZero() {
|
||||
var err error
|
||||
ak, err = key.NewHardwareAttestationKey()
|
||||
if err != nil {
|
||||
if !errors.Is(err, key.ErrUnsupported) {
|
||||
logf("failed to create hardware attestation key: %v", err)
|
||||
}
|
||||
} else if ak != nil {
|
||||
logf("using new hardware attestation key: %v", ak.Public())
|
||||
if p == nil {
|
||||
p = &persist.Persist{}
|
||||
}
|
||||
p.AttestationKey = ak
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
@ -1190,6 +1190,7 @@ func stripKeysFromPrefs(p ipn.PrefsView) ipn.PrefsView {
|
||||
p2.Persist.PrivateNodeKey = key.NodePrivate{}
|
||||
p2.Persist.OldPrivateNodeKey = key.NodePrivate{}
|
||||
p2.Persist.NetworkLockKey = key.NLPrivate{}
|
||||
p2.Persist.AttestationKey = nil
|
||||
return p2.View()
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,9 @@ import (
|
||||
"tailscale.com/ipn"
|
||||
"tailscale.com/ipn/ipnext"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/key"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/persist"
|
||||
"tailscale.com/util/clientmetric"
|
||||
"tailscale.com/util/eventbus"
|
||||
)
|
||||
@ -654,6 +656,14 @@ func (pm *profileManager) loadSavedPrefs(k ipn.StateKey) (ipn.PrefsView, error)
|
||||
return ipn.PrefsView{}, err
|
||||
}
|
||||
savedPrefs := ipn.NewPrefs()
|
||||
|
||||
// if supported by the platform, create an empty hardware attestation key to use when deserializing
|
||||
// to avoid type exceptions from json.Unmarshaling into an interface{}.
|
||||
hw, _ := key.NewEmptyHardwareAttestationKey()
|
||||
savedPrefs.Persist = &persist.Persist{
|
||||
AttestationKey: hw,
|
||||
}
|
||||
|
||||
if err := ipn.PrefsFromBytes(bs, savedPrefs); err != nil {
|
||||
return ipn.PrefsView{}, fmt.Errorf("parsing saved prefs: %v", err)
|
||||
}
|
||||
|
||||
@ -151,6 +151,7 @@ func TestProfileDupe(t *testing.T) {
|
||||
ID: tailcfg.UserID(user),
|
||||
LoginName: fmt.Sprintf("user%d@example.com", user),
|
||||
},
|
||||
AttestationKey: nil,
|
||||
}
|
||||
}
|
||||
user1Node1 := newPersist(1, 1)
|
||||
|
||||
@ -501,7 +501,7 @@ func TestPrefsPretty(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"linux",
|
||||
`Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist{o=, n=[B1VKl] u=""}}`,
|
||||
`Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist{o=, n=[B1VKl] u="" ak=-}}`,
|
||||
},
|
||||
{
|
||||
Prefs{
|
||||
|
||||
@ -26,6 +26,7 @@ type Persist struct {
|
||||
UserProfile tailcfg.UserProfile
|
||||
NetworkLockKey key.NLPrivate
|
||||
NodeID tailcfg.StableNodeID
|
||||
AttestationKey key.HardwareAttestationKey `json:",omitempty"`
|
||||
|
||||
// DisallowedTKAStateIDs stores the tka.State.StateID values which
|
||||
// this node will not operate network lock on. This is used to
|
||||
@ -84,11 +85,20 @@ func (p *Persist) Equals(p2 *Persist) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var pub, p2Pub key.HardwareAttestationPublic
|
||||
if p.AttestationKey != nil && !p.AttestationKey.IsZero() {
|
||||
pub = key.HardwareAttestationPublicFromPlatformKey(p.AttestationKey)
|
||||
}
|
||||
if p2.AttestationKey != nil && !p2.AttestationKey.IsZero() {
|
||||
p2Pub = key.HardwareAttestationPublicFromPlatformKey(p2.AttestationKey)
|
||||
}
|
||||
|
||||
return p.PrivateNodeKey.Equal(p2.PrivateNodeKey) &&
|
||||
p.OldPrivateNodeKey.Equal(p2.OldPrivateNodeKey) &&
|
||||
p.UserProfile.Equal(&p2.UserProfile) &&
|
||||
p.NetworkLockKey.Equal(p2.NetworkLockKey) &&
|
||||
p.NodeID == p2.NodeID &&
|
||||
pub.Equal(p2Pub) &&
|
||||
reflect.DeepEqual(nilIfEmpty(p.DisallowedTKAStateIDs), nilIfEmpty(p2.DisallowedTKAStateIDs))
|
||||
}
|
||||
|
||||
@ -96,12 +106,16 @@ func (p *Persist) Pretty() string {
|
||||
var (
|
||||
ok, nk key.NodePublic
|
||||
)
|
||||
akString := "-"
|
||||
if !p.OldPrivateNodeKey.IsZero() {
|
||||
ok = p.OldPrivateNodeKey.Public()
|
||||
}
|
||||
if !p.PrivateNodeKey.IsZero() {
|
||||
nk = p.PublicNodeKey()
|
||||
}
|
||||
return fmt.Sprintf("Persist{o=%v, n=%v u=%#v}",
|
||||
ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName)
|
||||
if p.AttestationKey != nil && !p.AttestationKey.IsZero() {
|
||||
akString = fmt.Sprintf("%v", p.AttestationKey.Public())
|
||||
}
|
||||
return fmt.Sprintf("Persist{o=%v, n=%v u=%#v ak=%s}",
|
||||
ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName, akString)
|
||||
}
|
||||
|
||||
@ -19,6 +19,9 @@ func (src *Persist) Clone() *Persist {
|
||||
}
|
||||
dst := new(Persist)
|
||||
*dst = *src
|
||||
if src.AttestationKey != nil {
|
||||
dst.AttestationKey = src.AttestationKey.Clone()
|
||||
}
|
||||
dst.DisallowedTKAStateIDs = append(src.DisallowedTKAStateIDs[:0:0], src.DisallowedTKAStateIDs...)
|
||||
return dst
|
||||
}
|
||||
@ -31,5 +34,6 @@ var _PersistCloneNeedsRegeneration = Persist(struct {
|
||||
UserProfile tailcfg.UserProfile
|
||||
NetworkLockKey key.NLPrivate
|
||||
NodeID tailcfg.StableNodeID
|
||||
AttestationKey key.HardwareAttestationKey
|
||||
DisallowedTKAStateIDs []string
|
||||
}{})
|
||||
|
||||
@ -21,7 +21,7 @@ func fieldsOf(t reflect.Type) (fields []string) {
|
||||
}
|
||||
|
||||
func TestPersistEqual(t *testing.T) {
|
||||
persistHandles := []string{"PrivateNodeKey", "OldPrivateNodeKey", "UserProfile", "NetworkLockKey", "NodeID", "DisallowedTKAStateIDs"}
|
||||
persistHandles := []string{"PrivateNodeKey", "OldPrivateNodeKey", "UserProfile", "NetworkLockKey", "NodeID", "AttestationKey", "DisallowedTKAStateIDs"}
|
||||
if have := fieldsOf(reflect.TypeFor[Persist]()); !reflect.DeepEqual(have, persistHandles) {
|
||||
t.Errorf("Persist.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
||||
have, persistHandles)
|
||||
|
||||
@ -89,10 +89,11 @@ func (v *PersistView) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
|
||||
func (v PersistView) PrivateNodeKey() key.NodePrivate { return v.ж.PrivateNodeKey }
|
||||
|
||||
// needed to request key rotation
|
||||
func (v PersistView) OldPrivateNodeKey() key.NodePrivate { return v.ж.OldPrivateNodeKey }
|
||||
func (v PersistView) UserProfile() tailcfg.UserProfile { return v.ж.UserProfile }
|
||||
func (v PersistView) NetworkLockKey() key.NLPrivate { return v.ж.NetworkLockKey }
|
||||
func (v PersistView) NodeID() tailcfg.StableNodeID { return v.ж.NodeID }
|
||||
func (v PersistView) OldPrivateNodeKey() key.NodePrivate { return v.ж.OldPrivateNodeKey }
|
||||
func (v PersistView) UserProfile() tailcfg.UserProfile { return v.ж.UserProfile }
|
||||
func (v PersistView) NetworkLockKey() key.NLPrivate { return v.ж.NetworkLockKey }
|
||||
func (v PersistView) NodeID() tailcfg.StableNodeID { return v.ж.NodeID }
|
||||
func (v PersistView) AttestationKey() tailcfg.StableNodeID { panic("unsupported") }
|
||||
|
||||
// DisallowedTKAStateIDs stores the tka.State.StateID values which
|
||||
// this node will not operate network lock on. This is used to
|
||||
@ -110,5 +111,6 @@ var _PersistViewNeedsRegeneration = Persist(struct {
|
||||
UserProfile tailcfg.UserProfile
|
||||
NetworkLockKey key.NLPrivate
|
||||
NodeID tailcfg.StableNodeID
|
||||
AttestationKey key.HardwareAttestationKey
|
||||
DisallowedTKAStateIDs []string
|
||||
}{})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user