]> git.proxmox.com Git - efi-boot-shim.git/blame - tpm.c
Add Debian SBAT data to the shim build
[efi-boot-shim.git] / tpm.c
CommitLineData
aedb8470
PJ
1// SPDX-License-Identifier: BSD-2-Clause-Patent
2
22b58f24
MG
3#include <efi.h>
4#include <efilib.h>
5#include <string.h>
2d82a389 6#include <stdint.h>
22b58f24 7
dc62a3c4 8#include "shim.h"
22b58f24 9
8af7c4ca
MG
10typedef struct {
11 CHAR16 *VariableName;
12 EFI_GUID *VendorGuid;
13 VOID *Data;
14 UINTN Size;
15} VARIABLE_RECORD;
16
17UINTN measuredcount = 0;
18VARIABLE_RECORD *measureddata = NULL;
19
22b58f24
MG
20static BOOLEAN tpm_present(efi_tpm_protocol_t *tpm)
21{
1c237633 22 EFI_STATUS efi_status;
22b58f24
MG
23 TCG_EFI_BOOT_SERVICE_CAPABILITY caps;
24 UINT32 flags;
25 EFI_PHYSICAL_ADDRESS eventlog, lastevent;
26
27 caps.Size = (UINT8)sizeof(caps);
9fdca5bb 28 efi_status = tpm->status_check(tpm, &caps, &flags,
1c237633
PJ
29 &eventlog, &lastevent);
30 if (EFI_ERROR(efi_status) ||
31 caps.TPMDeactivatedFlag || !caps.TPMPresentFlag)
22b58f24
MG
32 return FALSE;
33
34 return TRUE;
35}
36
0baa9150
JMC
37static EFI_STATUS tpm2_get_caps(efi_tpm2_protocol_t *tpm,
38 EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps,
39 BOOLEAN *old_caps)
22b58f24 40{
1c237633 41 EFI_STATUS efi_status;
22b58f24 42
0baa9150 43 caps->Size = (UINT8)sizeof(*caps);
22b58f24 44
9fdca5bb 45 efi_status = tpm->get_capability(tpm, caps);
1c237633
PJ
46 if (EFI_ERROR(efi_status))
47 return efi_status;
0baa9150
JMC
48
49 if (caps->StructureVersion.Major == 1 &&
50 caps->StructureVersion.Minor == 0)
51 *old_caps = TRUE;
00197895
PJ
52 else
53 *old_caps = FALSE;
22b58f24 54
0baa9150
JMC
55 return EFI_SUCCESS;
56}
57
919c17a4 58static BOOLEAN tpm2_present(EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps,
0baa9150
JMC
59 BOOLEAN old_caps)
60{
61 TREE_BOOT_SERVICE_CAPABILITY *caps_1_0;
62
63 if (old_caps) {
64 caps_1_0 = (TREE_BOOT_SERVICE_CAPABILITY *)caps;
94c955bb 65 if (caps_1_0->TrEEPresentFlag)
22b58f24 66 return TRUE;
22b58f24
MG
67 }
68
0baa9150
JMC
69 if (caps->TPMPresentFlag)
70 return TRUE;
71
22b58f24
MG
72 return FALSE;
73}
74
431b8a2e
PJ
75static EFI_STATUS tpm_locate_protocol(efi_tpm_protocol_t **tpm,
76 efi_tpm2_protocol_t **tpm2,
77 BOOLEAN *old_caps_p,
78 EFI_TCG2_BOOT_SERVICE_CAPABILITY *capsp)
22b58f24 79{
1c237633 80 EFI_STATUS efi_status;
22b58f24 81
431b8a2e
PJ
82 *tpm = NULL;
83 *tpm2 = NULL;
1c237633 84 efi_status = LibLocateProtocol(&EFI_TPM2_GUID, (VOID **)tpm2);
22b58f24 85 /* TPM 2.0 */
1c237633 86 if (!EFI_ERROR(efi_status)) {
0baa9150 87 BOOLEAN old_caps;
0baa9150
JMC
88 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
89
1c237633
PJ
90 efi_status = tpm2_get_caps(*tpm2, &caps, &old_caps);
91 if (EFI_ERROR(efi_status))
92 return efi_status;
431b8a2e
PJ
93
94 if (tpm2_present(&caps, old_caps)) {
95 if (old_caps_p)
96 *old_caps_p = old_caps;
97 if (capsp)
98 memcpy(capsp, &caps, sizeof(caps));
0baa9150 99 return EFI_SUCCESS;
431b8a2e
PJ
100 }
101 } else {
1c237633
PJ
102 efi_status = LibLocateProtocol(&EFI_TPM_GUID, (VOID **)tpm);
103 if (EFI_ERROR(efi_status))
104 return efi_status;
22b58f24 105
431b8a2e 106 if (tpm_present(*tpm))
22b58f24 107 return EFI_SUCCESS;
431b8a2e
PJ
108 }
109
110 return EFI_NOT_FOUND;
111}
112
113static EFI_STATUS tpm_log_event_raw(EFI_PHYSICAL_ADDRESS buf, UINTN size,
114 UINT8 pcr, const CHAR8 *log, UINTN logsize,
115 UINT32 type, CHAR8 *hash)
116{
1c237633 117 EFI_STATUS efi_status;
431b8a2e
PJ
118 efi_tpm_protocol_t *tpm;
119 efi_tpm2_protocol_t *tpm2;
120 BOOLEAN old_caps;
121 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
122
1c237633
PJ
123 efi_status = tpm_locate_protocol(&tpm, &tpm2, &old_caps, &caps);
124 if (EFI_ERROR(efi_status)) {
15a34804
PJ
125#ifdef REQUIRE_TPM
126 perror(L"TPM logging failed: %r\n", efi_status);
1c237633 127 return efi_status;
15a34804
PJ
128#else
129 if (efi_status != EFI_NOT_FOUND) {
130 perror(L"TPM logging failed: %r\n", efi_status);
131 return efi_status;
132 }
133#endif
431b8a2e
PJ
134 } else if (tpm2) {
135 EFI_TCG2_EVENT *event;
6fd8db6b
CC
136 UINTN event_size = sizeof(*event) - sizeof(event->Event) +
137 logsize;
d3884fe8 138
6fd8db6b 139 event = AllocatePool(event_size);
22b58f24
MG
140 if (!event) {
141 perror(L"Unable to allocate event structure\n");
142 return EFI_OUT_OF_RESOURCES;
143 }
144
145 event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
146 event->Header.HeaderVersion = 1;
147 event->Header.PCRIndex = pcr;
8af7c4ca 148 event->Header.EventType = type;
6fd8db6b 149 event->Size = event_size;
8af7c4ca 150 CopyMem(event->Event, (VOID *)log, logsize);
22f27375
MG
151 if (hash) {
152 /* TPM 2 systems will generate the appropriate hash
571bfc95
TL
153 themselves if we pass PE_COFF_IMAGE. In case that
154 fails we fall back to measuring without it.
22f27375 155 */
9fdca5bb
PJ
156 efi_status = tpm2->hash_log_extend_event(tpm2,
157 PE_COFF_IMAGE, buf, (UINT64) size, event);
571bfc95
TL
158 }
159
1c237633 160 if (!hash || EFI_ERROR(efi_status)) {
9fdca5bb
PJ
161 efi_status = tpm2->hash_log_extend_event(tpm2,
162 0, buf, (UINT64) size, event);
22f27375 163 }
22b58f24 164 FreePool(event);
1c237633 165 return efi_status;
431b8a2e 166 } else if (tpm) {
22b58f24 167 TCG_PCR_EVENT *event;
9c40fb7c 168 UINT32 eventnum = 0;
22b58f24
MG
169 EFI_PHYSICAL_ADDRESS lastevent;
170
1c237633
PJ
171 efi_status = LibLocateProtocol(&EFI_TPM_GUID, (VOID **)&tpm);
172 if (EFI_ERROR(efi_status))
22b58f24
MG
173 return EFI_SUCCESS;
174
175 if (!tpm_present(tpm))
176 return EFI_SUCCESS;
177
8af7c4ca 178 event = AllocatePool(sizeof(*event) + logsize);
22b58f24
MG
179
180 if (!event) {
181 perror(L"Unable to allocate event structure\n");
182 return EFI_OUT_OF_RESOURCES;
183 }
184
185 event->PCRIndex = pcr;
8af7c4ca
MG
186 event->EventType = type;
187 event->EventSize = logsize;
188 CopyMem(event->Event, (VOID *)log, logsize);
22f27375
MG
189 if (hash) {
190 /* TPM 1.2 devices require us to pass the Authenticode
191 hash rather than allowing the firmware to attempt
192 to calculate it */
193 CopyMem(event->digest, hash, sizeof(event->digest));
9fdca5bb
PJ
194 efi_status = tpm->log_extend_event(tpm, 0, 0,
195 TPM_ALG_SHA, event, &eventnum, &lastevent);
22f27375 196 } else {
9fdca5bb
PJ
197 efi_status = tpm->log_extend_event(tpm, buf,
198 (UINT64)size, TPM_ALG_SHA, event, &eventnum,
199 &lastevent);
22f27375 200 }
22b58f24 201 FreePool(event);
1c237633 202 return efi_status;
22b58f24
MG
203 }
204
205 return EFI_SUCCESS;
206}
431b8a2e 207
8af7c4ca
MG
208EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
209 const CHAR8 *description)
210{
211 return tpm_log_event_raw(buf, size, pcr, description,
22f27375
MG
212 strlen(description) + 1, 0xd, NULL);
213}
214
0a8f7ade
JMC
215EFI_STATUS tpm_log_pe(EFI_PHYSICAL_ADDRESS buf, UINTN size,
216 EFI_PHYSICAL_ADDRESS addr, EFI_DEVICE_PATH *path,
217 UINT8 *sha1hash, UINT8 pcr)
22f27375 218{
0a8f7ade
JMC
219 EFI_IMAGE_LOAD_EVENT *ImageLoad = NULL;
220 EFI_STATUS efi_status;
221 UINTN path_size = 0;
222
223 if (path)
224 path_size = DevicePathSize(path);
225
226 ImageLoad = AllocateZeroPool(sizeof(*ImageLoad) + path_size);
227 if (!ImageLoad) {
228 perror(L"Unable to allocate image load event structure\n");
229 return EFI_OUT_OF_RESOURCES;
230 }
231
232 ImageLoad->ImageLocationInMemory = buf;
233 ImageLoad->ImageLengthInMemory = size;
234 ImageLoad->ImageLinkTimeAddress = addr;
235
236 if (path_size > 0) {
237 CopyMem(ImageLoad->DevicePath, path, path_size);
238 ImageLoad->LengthOfDevicePath = path_size;
239 }
240
241 efi_status = tpm_log_event_raw(buf, size, pcr, (CHAR8 *)ImageLoad,
242 sizeof(*ImageLoad) + path_size,
243 EV_EFI_BOOT_SERVICES_APPLICATION,
a7f9911b 244 (CHAR8 *)sha1hash);
0a8f7ade
JMC
245 FreePool(ImageLoad);
246
247 return efi_status;
8af7c4ca
MG
248}
249
250typedef struct {
251 EFI_GUID VariableName;
252 UINT64 UnicodeNameLength;
253 UINT64 VariableDataLength;
254 CHAR16 UnicodeName[1];
255 INT8 VariableData[1];
9f80be9f 256} __attribute__ ((packed)) EFI_VARIABLE_DATA_TREE;
8af7c4ca
MG
257
258static BOOLEAN tpm_data_measured(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
259{
260 UINTN i;
261
262 for (i=0; i<measuredcount; i++) {
263 if ((StrCmp (VarName, measureddata[i].VariableName) == 0) &&
58df8d74 264 (CompareGuid (&VendorGuid, measureddata[i].VendorGuid) == 0) &&
8af7c4ca
MG
265 (VarSize == measureddata[i].Size) &&
266 (CompareMem (VarData, measureddata[i].Data, VarSize) == 0)) {
267 return TRUE;
268 }
269 }
270
271 return FALSE;
272}
273
274static EFI_STATUS tpm_record_data_measurement(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
275{
276 if (measureddata == NULL) {
277 measureddata = AllocatePool(sizeof(*measureddata));
278 } else {
279 measureddata = ReallocatePool(measureddata, measuredcount * sizeof(*measureddata),
280 (measuredcount + 1) * sizeof(*measureddata));
281 }
282
283 if (measureddata == NULL)
284 return EFI_OUT_OF_RESOURCES;
285
286 measureddata[measuredcount].VariableName = AllocatePool(StrSize(VarName));
287 measureddata[measuredcount].VendorGuid = AllocatePool(sizeof(EFI_GUID));
288 measureddata[measuredcount].Data = AllocatePool(VarSize);
289
290 if (measureddata[measuredcount].VariableName == NULL ||
291 measureddata[measuredcount].VendorGuid == NULL ||
292 measureddata[measuredcount].Data == NULL) {
293 return EFI_OUT_OF_RESOURCES;
294 }
295
296 StrCpy(measureddata[measuredcount].VariableName, VarName);
297 CopyMem(measureddata[measuredcount].VendorGuid, &VendorGuid, sizeof(EFI_GUID));
298 CopyMem(measureddata[measuredcount].Data, VarData, VarSize);
299 measureddata[measuredcount].Size = VarSize;
300 measuredcount++;
301
302 return EFI_SUCCESS;
303}
304
305EFI_STATUS tpm_measure_variable(CHAR16 *VarName, EFI_GUID VendorGuid, UINTN VarSize, VOID *VarData)
306{
1c237633 307 EFI_STATUS efi_status;
8af7c4ca
MG
308 UINTN VarNameLength;
309 EFI_VARIABLE_DATA_TREE *VarLog;
310 UINT32 VarLogSize;
311
312 /* Don't measure something that we've already measured */
313 if (tpm_data_measured(VarName, VendorGuid, VarSize, VarData))
314 return EFI_SUCCESS;
315
316 VarNameLength = StrLen (VarName);
317 VarLogSize = (UINT32)(sizeof (*VarLog) +
318 VarNameLength * sizeof (*VarName) +
319 VarSize -
320 sizeof (VarLog->UnicodeName) -
321 sizeof (VarLog->VariableData));
322
323 VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
324 if (VarLog == NULL) {
325 return EFI_OUT_OF_RESOURCES;
326 }
327
328 CopyMem (&VarLog->VariableName, &VendorGuid,
329 sizeof(VarLog->VariableName));
330 VarLog->UnicodeNameLength = VarNameLength;
331 VarLog->VariableDataLength = VarSize;
332 CopyMem (VarLog->UnicodeName, VarName,
333 VarNameLength * sizeof (*VarName));
334 CopyMem ((CHAR16 *)VarLog->UnicodeName + VarNameLength, VarData,
335 VarSize);
336
1c237633
PJ
337 efi_status = tpm_log_event_raw((EFI_PHYSICAL_ADDRESS)(intptr_t)VarLog,
338 VarLogSize, 7, (CHAR8 *)VarLog, VarLogSize,
339 EV_EFI_VARIABLE_AUTHORITY, NULL);
8af7c4ca
MG
340
341 FreePool(VarLog);
342
1c237633
PJ
343 if (EFI_ERROR(efi_status))
344 return efi_status;
8af7c4ca
MG
345
346 return tpm_record_data_measurement(VarName, VendorGuid, VarSize,
347 VarData);
348}
431b8a2e
PJ
349
350EFI_STATUS
351fallback_should_prefer_reset(void)
352{
1c237633 353 EFI_STATUS efi_status;
431b8a2e
PJ
354 efi_tpm_protocol_t *tpm;
355 efi_tpm2_protocol_t *tpm2;
356
1c237633
PJ
357 efi_status = tpm_locate_protocol(&tpm, &tpm2, NULL, NULL);
358 if (EFI_ERROR(efi_status))
431b8a2e
PJ
359 return EFI_NOT_FOUND;
360 return EFI_SUCCESS;
361}