types/persist: add AttestationKey (#17281)
Extend Persist with AttestationKey to record a hardware-backed attestation key for the node's identity. Add a flag to tailscaled to allow users to control the use of hardware-backed keys to bind node identity to individual machines. Updates tailscale/corp#31269 Change-Id: Idcf40d730a448d85f07f1bebf387f086d4c58be3 Signed-off-by: Patrick O'Doherty <patrick@tailscale.com>
This commit is contained in:
committed by
GitHub
parent
a2dc517d7d
commit
e45557afc0
@@ -6,6 +6,9 @@ package feature
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/types/persist"
|
||||
)
|
||||
|
||||
// HookCanAutoUpdate is a hook for the clientupdate package
|
||||
@@ -45,6 +48,8 @@ var HookProxySetTransportGetProxyConnectHeader Hook[func(*http.Transport)]
|
||||
// and available.
|
||||
var HookTPMAvailable Hook[func() bool]
|
||||
|
||||
var HookGenerateAttestationKeyIfEmpty Hook[func(p *persist.Persist, logf logger.Logf) (bool, error)]
|
||||
|
||||
// TPMAvailable reports whether a TPM device is supported and available.
|
||||
func TPMAvailable() bool {
|
||||
if f, ok := HookTPMAvailable.GetOk(); ok {
|
||||
@@ -52,3 +57,17 @@ func TPMAvailable() bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HookHardwareAttestationAvailable is a hook that reports whether hardware
|
||||
// attestation is supported and available.
|
||||
var HookHardwareAttestationAvailable Hook[func() bool]
|
||||
|
||||
// HardwareAttestationAvailable reports whether hardware attestation is
|
||||
// supported and available (TPM on Windows/Linux, Secure Enclave on macOS|iOS,
|
||||
// KeyStore on Android)
|
||||
func HardwareAttestationAvailable() bool {
|
||||
if f, ok := HookHardwareAttestationAvailable.GetOk(); ok {
|
||||
return f()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -142,13 +142,18 @@ type attestationKeySerialized struct {
|
||||
TPMPublic []byte `json:"tpmPublic"`
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (ak *attestationKey) MarshalJSON() ([]byte, error) {
|
||||
if ak == nil || ak.IsZero() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(attestationKeySerialized{
|
||||
TPMPublic: ak.tpmPublic.Bytes(),
|
||||
TPMPrivate: ak.tpmPrivate.Buffer,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (ak *attestationKey) UnmarshalJSON(data []byte) (retErr error) {
|
||||
var aks attestationKeySerialized
|
||||
if err := json.Unmarshal(data, &aks); err != nil {
|
||||
@@ -254,6 +259,9 @@ func (ak *attestationKey) Close() error {
|
||||
}
|
||||
|
||||
func (ak *attestationKey) Clone() key.HardwareAttestationKey {
|
||||
if ak == nil {
|
||||
return nil
|
||||
}
|
||||
return &attestationKey{
|
||||
tpm: ak.tpm,
|
||||
tpmPrivate: ak.tpmPrivate,
|
||||
@@ -263,4 +271,9 @@ func (ak *attestationKey) Clone() key.HardwareAttestationKey {
|
||||
}
|
||||
}
|
||||
|
||||
func (ak *attestationKey) IsZero() bool { return !ak.loaded() }
|
||||
func (ak *attestationKey) IsZero() bool {
|
||||
if ak == nil {
|
||||
return true
|
||||
}
|
||||
return !ak.loaded()
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ var infoOnce = sync.OnceValue(info)
|
||||
func init() {
|
||||
feature.Register("tpm")
|
||||
feature.HookTPMAvailable.Set(tpmSupported)
|
||||
feature.HookHardwareAttestationAvailable.Set(tpmSupported)
|
||||
|
||||
hostinfo.RegisterHostinfoNewHook(func(hi *tailcfg.Hostinfo) {
|
||||
hi.TPM = infoOnce()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user