hostinfo,tailcfg: report TPM availability on windows/linux (#15831)
Start collecting fleet data on TPM availability via hostinfo. Updates #15830 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>main
parent
f05347a5bf
commit
3105ecd958
@ -0,0 +1,8 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !ios && !ts_omit_tpm
|
||||
|
||||
package condregister |
||||
|
||||
import _ "tailscale.com/feature/tpm" |
||||
@ -0,0 +1,83 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package tpm implements support for TPM 2.0 devices.
|
||||
package tpm |
||||
|
||||
import ( |
||||
"slices" |
||||
"sync" |
||||
|
||||
"github.com/google/go-tpm/tpm2" |
||||
"github.com/google/go-tpm/tpm2/transport" |
||||
"tailscale.com/feature" |
||||
"tailscale.com/hostinfo" |
||||
"tailscale.com/tailcfg" |
||||
) |
||||
|
||||
var infoOnce = sync.OnceValue(info) |
||||
|
||||
func init() { |
||||
feature.Register("tpm") |
||||
hostinfo.RegisterHostinfoNewHook(func(hi *tailcfg.Hostinfo) { |
||||
hi.TPM = infoOnce() |
||||
}) |
||||
} |
||||
|
||||
//lint:ignore U1000 used in Linux and Windows builds only
|
||||
func infoFromCapabilities(tpm transport.TPM) *tailcfg.TPMInfo { |
||||
info := new(tailcfg.TPMInfo) |
||||
toStr := func(s *string) func(*tailcfg.TPMInfo, uint32) { |
||||
return func(info *tailcfg.TPMInfo, value uint32) { |
||||
*s += propToString(value) |
||||
} |
||||
} |
||||
for _, cap := range []struct { |
||||
prop tpm2.TPMPT |
||||
apply func(info *tailcfg.TPMInfo, value uint32) |
||||
}{ |
||||
{tpm2.TPMPTManufacturer, toStr(&info.Manufacturer)}, |
||||
{tpm2.TPMPTVendorString1, toStr(&info.Vendor)}, |
||||
{tpm2.TPMPTVendorString2, toStr(&info.Vendor)}, |
||||
{tpm2.TPMPTVendorString3, toStr(&info.Vendor)}, |
||||
{tpm2.TPMPTVendorString4, toStr(&info.Vendor)}, |
||||
{tpm2.TPMPTRevision, func(info *tailcfg.TPMInfo, value uint32) { info.SpecRevision = int(value) }}, |
||||
{tpm2.TPMPTVendorTPMType, func(info *tailcfg.TPMInfo, value uint32) { info.Model = int(value) }}, |
||||
{tpm2.TPMPTFirmwareVersion1, func(info *tailcfg.TPMInfo, value uint32) { info.FirmwareVersion += uint64(value) << 32 }}, |
||||
{tpm2.TPMPTFirmwareVersion2, func(info *tailcfg.TPMInfo, value uint32) { info.FirmwareVersion += uint64(value) }}, |
||||
} { |
||||
resp, err := tpm2.GetCapability{ |
||||
Capability: tpm2.TPMCapTPMProperties, |
||||
Property: uint32(cap.prop), |
||||
PropertyCount: 1, |
||||
}.Execute(tpm) |
||||
if err != nil { |
||||
continue |
||||
} |
||||
props, err := resp.CapabilityData.Data.TPMProperties() |
||||
if err != nil { |
||||
continue |
||||
} |
||||
if len(props.TPMProperty) == 0 { |
||||
continue |
||||
} |
||||
cap.apply(info, props.TPMProperty[0].Value) |
||||
} |
||||
return info |
||||
} |
||||
|
||||
// propToString converts TPM_PT property value, which is a uint32, into a
|
||||
// string of up to 4 ASCII characters. This encoding applies only to some
|
||||
// properties, see
|
||||
// https://trustedcomputinggroup.org/resource/tpm-library-specification/ Part
|
||||
// 2, section 6.13.
|
||||
func propToString(v uint32) string { |
||||
chars := []byte{ |
||||
byte(v >> 24), |
||||
byte(v >> 16), |
||||
byte(v >> 8), |
||||
byte(v), |
||||
} |
||||
// Delete any non-printable ASCII characters.
|
||||
return string(slices.DeleteFunc(chars, func(b byte) bool { return b < ' ' || b > '~' })) |
||||
} |
||||
@ -0,0 +1,18 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tpm |
||||
|
||||
import ( |
||||
"github.com/google/go-tpm/tpm2/transport/linuxtpm" |
||||
"tailscale.com/tailcfg" |
||||
) |
||||
|
||||
func info() *tailcfg.TPMInfo { |
||||
t, err := linuxtpm.Open("/dev/tpm0") |
||||
if err != nil { |
||||
return nil |
||||
} |
||||
defer t.Close() |
||||
return infoFromCapabilities(t) |
||||
} |
||||
@ -0,0 +1,12 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build !linux && !windows
|
||||
|
||||
package tpm |
||||
|
||||
import "tailscale.com/tailcfg" |
||||
|
||||
func info() *tailcfg.TPMInfo { |
||||
return nil |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tpm |
||||
|
||||
import "testing" |
||||
|
||||
func TestPropToString(t *testing.T) { |
||||
for prop, want := range map[uint32]string{ |
||||
0: "", |
||||
0x4D534654: "MSFT", |
||||
0x414D4400: "AMD", |
||||
0x414D440D: "AMD", |
||||
} { |
||||
if got := propToString(prop); got != want { |
||||
t.Errorf("propToString(0x%x): got %q, want %q", prop, got, want) |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,18 @@ |
||||
// Copyright (c) Tailscale Inc & AUTHORS
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package tpm |
||||
|
||||
import ( |
||||
"github.com/google/go-tpm/tpm2/transport/windowstpm" |
||||
"tailscale.com/tailcfg" |
||||
) |
||||
|
||||
func info() *tailcfg.TPMInfo { |
||||
t, err := windowstpm.Open() |
||||
if err != nil { |
||||
return nil |
||||
} |
||||
defer t.Close() |
||||
return infoFromCapabilities(t) |
||||
} |
||||
Loading…
Reference in new issue