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