/
flow.go
289 lines (267 loc) · 9.73 KB
/
flow.go
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
package pcr
import (
"fmt"
"strings"
"github.com/9elements/go-linux-lowlevel-hw/pkg/platformsecurity"
"github.com/klauspost/cpuid/v2"
)
// Flow defines which measurements are used to get the final PCR values.
type Flow int
// String implements fmt.Stringer
func (f Flow) String() string {
switch f {
case FlowAuto:
return "Auto"
case FlowIntelLegacyTXTDisabled:
return "LegacyTXTDisabled"
case FlowIntelLegacyTXTEnabled:
return "LegacyTXTEnabled"
case FlowIntelLegacyTXTEnabledTPM12:
return "LegacyTXTEnabledTPM12"
case FlowIntelCBnT0T:
return "CBnT0T"
case FlowLegacyAMDLocality0:
return "LegacyAMDLocality0"
case FlowLegacyAMDLocality3:
return "LegacyAMDLocality3"
case FlowAMDLocality0:
return "AMDLocality0"
case FlowAMDLocality3:
return "AMDLocality3"
}
panic(fmt.Sprintf("Flow's %d string representation is not supported", f))
}
// FlowFromString parses Flow from a string.
func FlowFromString(s string) (Flow, error) {
switch strings.ToLower(s) {
case "auto":
return FlowAuto, nil
case "legacytxtdisabled":
return FlowIntelLegacyTXTDisabled, nil
case "legacytxtenabled":
return FlowIntelLegacyTXTEnabled, nil
case "legacytxtenabledtpm12":
return FlowIntelLegacyTXTEnabledTPM12, nil
case "cbnt0t":
return FlowIntelCBnT0T, nil
case "legacyamdlocality0":
return FlowLegacyAMDLocality0, nil
case "legacyamdlocality3":
return FlowLegacyAMDLocality3, nil
case "amdlocality0":
return FlowAMDLocality0, nil
case "amdlocality3":
return FlowAMDLocality3, nil
}
return FlowAuto, fmt.Errorf("'%s' attestation flow is not supported", s)
}
const (
// FlowAuto means to guess the flow.
FlowAuto = Flow(iota)
// FlowIntelLegacyTXTDisabled means a pre-CBnT flow with disabled TXT.
FlowIntelLegacyTXTDisabled
// FlowIntelLegacyTXTEnabled means a pre-CBnT flow with enabled TXT.
FlowIntelLegacyTXTEnabled
// FlowIntelCBnT0T means CBnT flow with profile "0T".
FlowIntelCBnT0T
// FlowIntelLegacyTXTEnabledTPM12 means a pre-CBnT flow with enabled TXT for TPM 1.2
FlowIntelLegacyTXTEnabledTPM12
// FlowLegacyAMDLocality0 means an AMD flow with TPM locality 0 initialisation of TPM and with legacy set of measurements
FlowLegacyAMDLocality0
// FlowLegacyAMDLocality3 means an AMD flow with TPM locality 3 initialisation of TPM and with legacy set of measurements
FlowLegacyAMDLocality3
// FlowAMDLocality0 means an AMD flow with TPM locality 0 initialisation of TPM
FlowAMDLocality0
// FlowAMDLocality3 means an AMD flow with TPM locality 0 initialisation of TPM
FlowAMDLocality3
)
// Flows contains all supported PCR measurements flows
var Flows = []Flow{
FlowAuto,
FlowIntelLegacyTXTDisabled,
FlowIntelLegacyTXTEnabled,
FlowIntelLegacyTXTEnabledTPM12,
FlowIntelCBnT0T,
FlowLegacyAMDLocality0,
FlowLegacyAMDLocality3,
FlowAMDLocality0,
FlowAMDLocality3,
}
// TPMLocality returns TPM initialization locality in this flow.
func (f Flow) TPMLocality() uint8 {
switch f {
case FlowIntelCBnT0T, FlowIntelLegacyTXTEnabled, FlowLegacyAMDLocality3, FlowAMDLocality3:
return 3
}
return 0
}
// MeasurementIDs returns which measurements should be performed for in flow.
func (f Flow) MeasurementIDs() MeasurementIDs {
switch f {
case FlowIntelCBnT0T:
/*
A sample of the EventLog:
fwtool display_eventlog -pcr-index 0 -hash-algo 4
# idx typ hash digest data
0 0 3 4 0000000000000000000000000000000000000000 537461727475704C6F63616C6974790003 <- Init
1 0 7 4 3FD5F9C9D04E8C604052A3EE838A8D6EB9D598AA 426F6F74204775617264204D6561737572656420532D4352544D00 <- PCR0_DATA
3 0 8 4 C42FEDAD268200CB1D15F97841C344E79DAE3320 1EFB6B540C1D5540A4AD4EF4BF17B83A <- FirmwareVendorVersionData
4 0 1 4 0944F48783C30C8B69A8D1CF07C1BC1823DB6516 000011FF0000000000F0AA0000000000 <- DXE
13 0 4 4 9069CA78E7450A285173431B3E52C5C25299E473 00000000 <- Separator
*/
return MeasurementIDs{
MeasurementIDInit, // is a fake measurement
MeasurementIDACM, // is a fake measurement
MeasurementIDPCR0DATA,
MeasurementIDKeyManifest, // is a fake measurement
MeasurementIDBootPolicyManifest, // is a fake measurement
MeasurementIDIBBFake, // is a fake measurement
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
MeasurementIDDXE,
MeasurementIDSeparator,
MeasurementIDFITPointer, // is a fake measurement
MeasurementIDFITHeaders, // is a fake measurement
}
case FlowIntelLegacyTXTEnabled:
// See also:
// * https://www.trustedcomputinggroup.org/wp-content/uploads/TCG_EFI_Platform_1_22_Final_-v15.pdf
// * https://github.com/openpts/openpts/blob/master/models/uefi_pcr0.uml
// * https://github.com/openpts/openpts/blob/master/models/bios_pcr0.uml
// * https://www.trustedcomputinggroup.org/wp-content/uploads/PC-ClientSpecific_Platform_Profile_for_TPM_2p0_Systems_v21.pdf (Section 9.3.1)
// * doc/log/ymm03.txt
return MeasurementIDs{
MeasurementIDInit, // is a fake measurement
MeasurementIDACM, // is a fake measurement
MeasurementIDACMDate,
MeasurementIDBIOSStartupModule,
MeasurementIDSCRTMSeparator,
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
MeasurementIDDXE,
MeasurementIDSeparator,
MeasurementIDFITPointer, // is a fake measurement
MeasurementIDFITHeaders, // is a fake measurement
}
case FlowIntelLegacyTXTEnabledTPM12:
return MeasurementIDs{
MeasurementIDInit, // is a fake measurement
MeasurementIDACM, // is a fake measurement
MeasurementIDACMDateInPlace,
MeasurementIDBIOSStartupModule,
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
MeasurementIDDXE,
MeasurementIDSeparator,
MeasurementIDFITPointer, // is a fake measurement
MeasurementIDFITHeaders, // is a fake measurement
}
case FlowIntelLegacyTXTDisabled:
return MeasurementIDs{
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDPCDFirmwareVendorVersionCode, // is a fake measurement
MeasurementIDDXE,
MeasurementIDSeparator,
// Also we include as fake measurements the byte ranges which a known
// to be necessary to correctly parse the firmware.
MeasurementIDFITPointer, // is a fake measurement
MeasurementIDFITHeaders, // is a fake measurement
}
case FlowLegacyAMDLocality0:
return MeasurementIDs{
MeasurementIDPSPVersion,
MeasurementIDBIOSRTMVolume,
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDDXE,
MeasurementIDSeparator,
}
case FlowLegacyAMDLocality3:
return MeasurementIDs{
MeasurementIDPSPVersion,
MeasurementIDBIOSRTMVolume,
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDDXE,
MeasurementIDSeparator,
}
case FlowAMDLocality0:
return MeasurementIDs{
MeasurementIDPSPVersion,
MeasurementIDBIOSRTMVolume,
MeasurementIDMP0C2PMsgRegisters,
MeasurementIDEmbeddedFirmwareStructure,
MeasurementIDBIOSDirectoryLevel1Header,
MeasurementIDBIOSDirectoryLevel1,
MeasurementIDBIOSDirectoryLevel2Header,
MeasurementIDBIOSDirectoryLevel2,
MeasurementIDPMUFirmwareInstructions,
MeasurementIDPMUFirmwareData,
MeasurementIDMicrocodePatch,
MeasurementIDVideoImageInterpreter,
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDDXE,
MeasurementIDSeparator,
}
case FlowAMDLocality3:
return MeasurementIDs{
MeasurementIDInit,
MeasurementIDPSPVersion,
MeasurementIDBIOSRTMVolume,
MeasurementIDMP0C2PMsgRegisters,
MeasurementIDEmbeddedFirmwareStructure,
MeasurementIDBIOSDirectoryLevel1Header,
MeasurementIDBIOSDirectoryLevel1,
MeasurementIDBIOSDirectoryLevel2Header,
MeasurementIDBIOSDirectoryLevel2,
MeasurementIDBIOSDirectoryLevel1Entries, // fake measurement
MeasurementIDBIOSDirectoryLevel2Entries, // fake measurement
MeasurementIDPSPDirectoryLevel1, // fake measurement
MeasurementIDPSPDirectoryLevel1Entries, // fake measurement
MeasurementIDPSPDirectoryLevel1Header, // fake measurement
MeasurementIDPSPDirectoryLevel2, // fake measurement
MeasurementIDPSPDirectoryLevel2Entries, // fake measurement
MeasurementIDPSPDirectoryLevel2Header, // fake measurement
MeasurementIDPMUFirmwareInstructions,
MeasurementIDPMUFirmwareData,
MeasurementIDMicrocodePatch,
MeasurementIDVideoImageInterpreter,
MeasurementIDPCDFirmwareVendorVersionData,
MeasurementIDDXE,
MeasurementIDSeparator,
}
}
panic(fmt.Sprintf("should not happen: %v", f))
}
// ValidateFlow returns a validator could be used if the flow will indeed
// be active on a real machine. For example CBnT flow works only on firmwares
// with valid manifests, otherwise it falls back to TXT-disabled flow.
func (f Flow) ValidateFlow() ValidateFlow {
switch f {
case FlowIntelCBnT0T:
return ValidateFlow{
ValidateManifests{},
}
}
return nil
}
// PlatformSecurityID returns the ID of the platform security family (which combines CPU and
// RTM).
func (f Flow) PlatformSecurityID() platformsecurity.ID {
switch f {
case FlowIntelCBnT0T:
return platformsecurity.IDIntelCBnT
case FlowIntelLegacyTXTEnabled,
FlowIntelLegacyTXTEnabledTPM12,
FlowIntelLegacyTXTDisabled:
return platformsecurity.IDIntelTXT
case FlowAMDLocality3,
FlowAMDLocality0,
FlowLegacyAMDLocality3,
FlowLegacyAMDLocality0:
return platformsecurity.IDAMDMilan
}
return platformsecurity.IDUndefined
}
// CPUVendorID returns vendor ID of the CPU.
func (f Flow) CPUVendorID() cpuid.Vendor {
return f.PlatformSecurityID().CPUVendorID()
}