File: info.go

package info (click to toggle)
golang-github-smallstep-crypto 0.57.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,284 kB
  • sloc: sh: 53; makefile: 36
file content (158 lines) | stat: -rw-r--r-- 4,124 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package tpm

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/smallstep/go-attestation/attest"

	"go.step.sm/crypto/tpm/manufacturer"
)

// Info models information about a TPM. It contains the
// TPM version, interface, manufacturer, vendor info and
// firmware version.
type Info struct {
	Version         Version         `json:"version"`
	Interface       Interface       `json:"interface"`
	Manufacturer    Manufacturer    `json:"manufacturer"`
	VendorInfo      string          `json:"vendorInfo,omitempty"`
	FirmwareVersion FirmwareVersion `json:"firmwareVersion,omitempty"`
}

// Version models the TPM specification version supported
// by the TPM.
type Version attest.TPMVersion

func (v Version) String() string {
	switch v {
	case Version(attest.TPMVersion12):
		return "TPM 1.2"
	case Version(attest.TPMVersion20):
		return "TPM 2.0"
	default:
		return fmt.Sprintf("unknown (%d)", v)
	}
}

// MarshalJSON marshals the version into JSON.
func (v Version) MarshalJSON() ([]byte, error) {
	var s string
	switch v {
	case Version(attest.TPMVersion12):
		s = "1.2"
	case Version(attest.TPMVersion20):
		s = "2.0"
	default:
		s = fmt.Sprintf("unknown (%d)", v)
	}
	return json.Marshal(s)
}

// Interface models a TPM interface.
type Interface attest.TPMInterface

// String returns a textual representation of the
// TPM interface.
func (i Interface) String() string {
	switch i {
	case Interface(attest.TPMInterfaceDirect):
		return "direct"
	case Interface(attest.TPMInterfaceKernelManaged):
		return "kernel-managed"
	case Interface(attest.TPMInterfaceDaemonManaged):
		return "daemon-managed"
	case Interface(attest.TPMInterfaceCommandChannel):
		return "command-channel"
	default:
		return fmt.Sprintf("unknown (%d)", i)
	}
}

// MarshalJSON marshals the TPM interface into JSON.
func (i Interface) MarshalJSON() ([]byte, error) {
	return json.Marshal(i.String())
}

// FirmwareVersion models the TPM firmware version.
type FirmwareVersion struct {
	Major int
	Minor int
}

// String returns a textual representation of the
// TPM firmware version.
func (fv FirmwareVersion) String() string {
	return fmt.Sprintf("%d.%d", fv.Major, fv.Minor)
}

// MarshalJSON marshals the TPM firmware version to JSON.
func (fv FirmwareVersion) MarshalJSON() ([]byte, error) {
	// TODO(hs): make empty if major.minor is 0.0?
	return json.Marshal(fv.String())
}

// Manufacturer models a TPM Manufacturer.
type Manufacturer struct {
	ID    manufacturer.ID `json:"id"`
	Name  string          `json:"name"`
	ASCII string          `json:"ascii"`
	Hex   string          `json:"hex"`
}

// String returns a textual representation of the TPM
// manufacturer. An example looks like this:
//
//	ST Microelectronics (<STM >, 53544D20, 1398033696)
func (m Manufacturer) String() string {
	return fmt.Sprintf("%s (<%s>, %s, %d)", m.Name, m.ASCII, m.Hex, m.ID)
}

// GetManufacturerByID returns a Manufacturer based on its Manufacturer ID
// code.
func GetManufacturerByID(id manufacturer.ID) (m Manufacturer) {
	m.ID = id
	m.ASCII, m.Hex = manufacturer.GetEncodings(id)
	// the FIDO Alliance fake TPM vendor ID doesn't conform to the standard ASCII lookup
	if id == 4294963664 {
		m.ASCII = "FIDO"
	}
	m.Name = manufacturer.GetNameByASCII(m.ASCII)

	return
}

// Info returns info about the TPM. The info doesn't change, so
// it's cached after the first lookup.
func (t *TPM) Info(ctx context.Context) (info *Info, err error) {
	if t.info != nil {
		return t.info, nil
	}

	if err = t.open(ctx); err != nil {
		return nil, fmt.Errorf("failed opening TPM: %w", err)
	}
	defer closeTPM(ctx, t, &err)

	ainfo, err := t.attestTPM.Info()
	if err != nil {
		return nil, fmt.Errorf("failed getting TPM info: %w", err)
	}

	// the TPM info won't change, so it's cached for future lookups
	info = &Info{
		FirmwareVersion: FirmwareVersion{
			Major: ainfo.FirmwareVersionMajor,
			Minor: ainfo.FirmwareVersionMinor,
		},
		Interface:    Interface(ainfo.Interface),
		Manufacturer: GetManufacturerByID(manufacturer.ID(ainfo.Manufacturer)),
		VendorInfo:   ainfo.VendorInfo,
		Version:      Version(ainfo.Version),
	}

	t.info = info

	return
}