mirror of
https://github.com/tailscale/tailscale.git
synced 2025-05-11 16:16:53 +00:00

Start collecting fleet data on TPM availability via hostinfo. Updates #15830 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
84 lines
2.5 KiB
Go
84 lines
2.5 KiB
Go
// 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 > '~' }))
|
|
}
|