mirror of
https://github.com/tailscale/tailscale.git
synced 2025-12-23 09:06:24 +00:00
control/controlclient: back out HW key attestation (#17664)
Temporarily back out the TPM-based hw attestation code while we debug
Windows exceptions.
Updates tailscale/corp#31269
Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
(cherry picked from commit a760cbe33f)
This commit is contained in:
@@ -7,8 +7,6 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"cmp"
|
"cmp"
|
||||||
"context"
|
"context"
|
||||||
"crypto"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -948,26 +946,6 @@ func (c *Direct) sendMapRequest(ctx context.Context, isStreaming bool, nu Netmap
|
|||||||
ConnectionHandleForTest: connectionHandleForTest,
|
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
|
var extraDebugFlags []string
|
||||||
if buildfeatures.HasAdvertiseRoutes && hi != nil && c.netMon != nil && !c.skipIPForwardingCheck &&
|
if buildfeatures.HasAdvertiseRoutes && hi != nil && c.netMon != nil && !c.skipIPForwardingCheck &&
|
||||||
ipForwardingBroken(hi.RoutableIPs, c.netMon.InterfaceState()) {
|
ipForwardingBroken(hi.RoutableIPs, c.netMon.InterfaceState()) {
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
// 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
|
|
||||||
}
|
|
||||||
@@ -1216,7 +1216,6 @@ func stripKeysFromPrefs(p ipn.PrefsView) ipn.PrefsView {
|
|||||||
p2.Persist.PrivateNodeKey = key.NodePrivate{}
|
p2.Persist.PrivateNodeKey = key.NodePrivate{}
|
||||||
p2.Persist.OldPrivateNodeKey = key.NodePrivate{}
|
p2.Persist.OldPrivateNodeKey = key.NodePrivate{}
|
||||||
p2.Persist.NetworkLockKey = key.NLPrivate{}
|
p2.Persist.NetworkLockKey = key.NLPrivate{}
|
||||||
p2.Persist.AttestationKey = nil
|
|
||||||
return p2.View()
|
return p2.View()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ import (
|
|||||||
"tailscale.com/ipn"
|
"tailscale.com/ipn"
|
||||||
"tailscale.com/ipn/ipnext"
|
"tailscale.com/ipn/ipnext"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
|
||||||
"tailscale.com/types/logger"
|
"tailscale.com/types/logger"
|
||||||
"tailscale.com/types/persist"
|
|
||||||
"tailscale.com/util/clientmetric"
|
"tailscale.com/util/clientmetric"
|
||||||
"tailscale.com/util/eventbus"
|
"tailscale.com/util/eventbus"
|
||||||
)
|
)
|
||||||
@@ -656,14 +654,6 @@ func (pm *profileManager) loadSavedPrefs(k ipn.StateKey) (ipn.PrefsView, error)
|
|||||||
return ipn.PrefsView{}, err
|
return ipn.PrefsView{}, err
|
||||||
}
|
}
|
||||||
savedPrefs := ipn.NewPrefs()
|
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 {
|
if err := ipn.PrefsFromBytes(bs, savedPrefs); err != nil {
|
||||||
return ipn.PrefsView{}, fmt.Errorf("parsing saved prefs: %v", err)
|
return ipn.PrefsView{}, fmt.Errorf("parsing saved prefs: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ func TestProfileDupe(t *testing.T) {
|
|||||||
ID: tailcfg.UserID(user),
|
ID: tailcfg.UserID(user),
|
||||||
LoginName: fmt.Sprintf("user%d@example.com", user),
|
LoginName: fmt.Sprintf("user%d@example.com", user),
|
||||||
},
|
},
|
||||||
AttestationKey: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user1Node1 := newPersist(1, 1)
|
user1Node1 := newPersist(1, 1)
|
||||||
|
|||||||
@@ -501,7 +501,7 @@ func TestPrefsPretty(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"linux",
|
"linux",
|
||||||
`Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist{o=, n=[B1VKl] u="" ak=-}}`,
|
`Prefs{ra=false dns=false want=false routes=[] nf=off update=off Persist{o=, n=[B1VKl] u=""}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Prefs{
|
Prefs{
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ type Persist struct {
|
|||||||
UserProfile tailcfg.UserProfile
|
UserProfile tailcfg.UserProfile
|
||||||
NetworkLockKey key.NLPrivate
|
NetworkLockKey key.NLPrivate
|
||||||
NodeID tailcfg.StableNodeID
|
NodeID tailcfg.StableNodeID
|
||||||
AttestationKey key.HardwareAttestationKey `json:",omitempty"`
|
|
||||||
|
|
||||||
// DisallowedTKAStateIDs stores the tka.State.StateID values which
|
// DisallowedTKAStateIDs stores the tka.State.StateID values which
|
||||||
// this node will not operate network lock on. This is used to
|
// this node will not operate network lock on. This is used to
|
||||||
@@ -85,20 +84,11 @@ func (p *Persist) Equals(p2 *Persist) bool {
|
|||||||
return false
|
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) &&
|
return p.PrivateNodeKey.Equal(p2.PrivateNodeKey) &&
|
||||||
p.OldPrivateNodeKey.Equal(p2.OldPrivateNodeKey) &&
|
p.OldPrivateNodeKey.Equal(p2.OldPrivateNodeKey) &&
|
||||||
p.UserProfile.Equal(&p2.UserProfile) &&
|
p.UserProfile.Equal(&p2.UserProfile) &&
|
||||||
p.NetworkLockKey.Equal(p2.NetworkLockKey) &&
|
p.NetworkLockKey.Equal(p2.NetworkLockKey) &&
|
||||||
p.NodeID == p2.NodeID &&
|
p.NodeID == p2.NodeID &&
|
||||||
pub.Equal(p2Pub) &&
|
|
||||||
reflect.DeepEqual(nilIfEmpty(p.DisallowedTKAStateIDs), nilIfEmpty(p2.DisallowedTKAStateIDs))
|
reflect.DeepEqual(nilIfEmpty(p.DisallowedTKAStateIDs), nilIfEmpty(p2.DisallowedTKAStateIDs))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,16 +96,12 @@ func (p *Persist) Pretty() string {
|
|||||||
var (
|
var (
|
||||||
ok, nk key.NodePublic
|
ok, nk key.NodePublic
|
||||||
)
|
)
|
||||||
akString := "-"
|
|
||||||
if !p.OldPrivateNodeKey.IsZero() {
|
if !p.OldPrivateNodeKey.IsZero() {
|
||||||
ok = p.OldPrivateNodeKey.Public()
|
ok = p.OldPrivateNodeKey.Public()
|
||||||
}
|
}
|
||||||
if !p.PrivateNodeKey.IsZero() {
|
if !p.PrivateNodeKey.IsZero() {
|
||||||
nk = p.PublicNodeKey()
|
nk = p.PublicNodeKey()
|
||||||
}
|
}
|
||||||
if p.AttestationKey != nil && !p.AttestationKey.IsZero() {
|
return fmt.Sprintf("Persist{o=%v, n=%v u=%#v}",
|
||||||
akString = fmt.Sprintf("%v", p.AttestationKey.Public())
|
ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName)
|
||||||
}
|
|
||||||
return fmt.Sprintf("Persist{o=%v, n=%v u=%#v ak=%s}",
|
|
||||||
ok.ShortString(), nk.ShortString(), p.UserProfile.LoginName, akString)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ func (src *Persist) Clone() *Persist {
|
|||||||
}
|
}
|
||||||
dst := new(Persist)
|
dst := new(Persist)
|
||||||
*dst = *src
|
*dst = *src
|
||||||
if src.AttestationKey != nil {
|
|
||||||
dst.AttestationKey = src.AttestationKey.Clone()
|
|
||||||
}
|
|
||||||
dst.DisallowedTKAStateIDs = append(src.DisallowedTKAStateIDs[:0:0], src.DisallowedTKAStateIDs...)
|
dst.DisallowedTKAStateIDs = append(src.DisallowedTKAStateIDs[:0:0], src.DisallowedTKAStateIDs...)
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
@@ -34,6 +31,5 @@ var _PersistCloneNeedsRegeneration = Persist(struct {
|
|||||||
UserProfile tailcfg.UserProfile
|
UserProfile tailcfg.UserProfile
|
||||||
NetworkLockKey key.NLPrivate
|
NetworkLockKey key.NLPrivate
|
||||||
NodeID tailcfg.StableNodeID
|
NodeID tailcfg.StableNodeID
|
||||||
AttestationKey key.HardwareAttestationKey
|
|
||||||
DisallowedTKAStateIDs []string
|
DisallowedTKAStateIDs []string
|
||||||
}{})
|
}{})
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func fieldsOf(t reflect.Type) (fields []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPersistEqual(t *testing.T) {
|
func TestPersistEqual(t *testing.T) {
|
||||||
persistHandles := []string{"PrivateNodeKey", "OldPrivateNodeKey", "UserProfile", "NetworkLockKey", "NodeID", "AttestationKey", "DisallowedTKAStateIDs"}
|
persistHandles := []string{"PrivateNodeKey", "OldPrivateNodeKey", "UserProfile", "NetworkLockKey", "NodeID", "DisallowedTKAStateIDs"}
|
||||||
if have := fieldsOf(reflect.TypeFor[Persist]()); !reflect.DeepEqual(have, persistHandles) {
|
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",
|
t.Errorf("Persist.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
||||||
have, persistHandles)
|
have, persistHandles)
|
||||||
|
|||||||
@@ -89,11 +89,10 @@ func (v *PersistView) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
|
|||||||
func (v PersistView) PrivateNodeKey() key.NodePrivate { return v.ж.PrivateNodeKey }
|
func (v PersistView) PrivateNodeKey() key.NodePrivate { return v.ж.PrivateNodeKey }
|
||||||
|
|
||||||
// needed to request key rotation
|
// needed to request key rotation
|
||||||
func (v PersistView) OldPrivateNodeKey() key.NodePrivate { return v.ж.OldPrivateNodeKey }
|
func (v PersistView) OldPrivateNodeKey() key.NodePrivate { return v.ж.OldPrivateNodeKey }
|
||||||
func (v PersistView) UserProfile() tailcfg.UserProfile { return v.ж.UserProfile }
|
func (v PersistView) UserProfile() tailcfg.UserProfile { return v.ж.UserProfile }
|
||||||
func (v PersistView) NetworkLockKey() key.NLPrivate { return v.ж.NetworkLockKey }
|
func (v PersistView) NetworkLockKey() key.NLPrivate { return v.ж.NetworkLockKey }
|
||||||
func (v PersistView) NodeID() tailcfg.StableNodeID { return v.ж.NodeID }
|
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
|
// DisallowedTKAStateIDs stores the tka.State.StateID values which
|
||||||
// this node will not operate network lock on. This is used to
|
// this node will not operate network lock on. This is used to
|
||||||
@@ -111,6 +110,5 @@ var _PersistViewNeedsRegeneration = Persist(struct {
|
|||||||
UserProfile tailcfg.UserProfile
|
UserProfile tailcfg.UserProfile
|
||||||
NetworkLockKey key.NLPrivate
|
NetworkLockKey key.NLPrivate
|
||||||
NodeID tailcfg.StableNodeID
|
NodeID tailcfg.StableNodeID
|
||||||
AttestationKey key.HardwareAttestationKey
|
|
||||||
DisallowedTKAStateIDs []string
|
DisallowedTKAStateIDs []string
|
||||||
}{})
|
}{})
|
||||||
|
|||||||
Reference in New Issue
Block a user