]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/measure.c
Merge pull request #7591 from poettering/retry-on-servfail
[thirdparty/systemd.git] / src / boot / efi / measure.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /*
3 * This program is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 */
14
15 #if ENABLE_TPM
16
17 #include <efi.h>
18 #include <efilib.h>
19 #include "measure.h"
20
21 #define EFI_TCG_PROTOCOL_GUID { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd} }
22
23 typedef struct _TCG_VERSION {
24 UINT8 Major;
25 UINT8 Minor;
26 UINT8 RevMajor;
27 UINT8 RevMinor;
28 } TCG_VERSION;
29
30 typedef struct tdEFI_TCG2_VERSION {
31 UINT8 Major;
32 UINT8 Minor;
33 } EFI_TCG2_VERSION;
34
35 typedef struct _TCG_BOOT_SERVICE_CAPABILITY {
36 UINT8 Size;
37 struct _TCG_VERSION StructureVersion;
38 struct _TCG_VERSION ProtocolSpecVersion;
39 UINT8 HashAlgorithmBitmap;
40 BOOLEAN TPMPresentFlag;
41 BOOLEAN TPMDeactivatedFlag;
42 } TCG_BOOT_SERVICE_CAPABILITY;
43
44 typedef struct tdTREE_BOOT_SERVICE_CAPABILITY {
45 UINT8 Size;
46 EFI_TCG2_VERSION StructureVersion;
47 EFI_TCG2_VERSION ProtocolVersion;
48 UINT32 HashAlgorithmBitmap;
49 UINT32 SupportedEventLogs;
50 BOOLEAN TrEEPresentFlag;
51 UINT16 MaxCommandSize;
52 UINT16 MaxResponseSize;
53 UINT32 ManufacturerID;
54 } TREE_BOOT_SERVICE_CAPABILITY;
55
56 typedef UINT32 TCG_ALGORITHM_ID;
57 #define TCG_ALG_SHA 0x00000004 // The SHA1 algorithm
58
59 #define SHA1_DIGEST_SIZE 20
60
61 typedef struct _TCG_DIGEST {
62 UINT8 Digest[SHA1_DIGEST_SIZE];
63 } TCG_DIGEST;
64
65 #define EV_IPL 13
66
67 typedef struct _TCG_PCR_EVENT {
68 UINT32 PCRIndex;
69 UINT32 EventType;
70 struct _TCG_DIGEST digest;
71 UINT32 EventSize;
72 UINT8 Event[1];
73 } TCG_PCR_EVENT;
74
75 INTERFACE_DECL(_EFI_TCG);
76
77 typedef EFI_STATUS(EFIAPI * EFI_TCG_STATUS_CHECK) (IN struct _EFI_TCG * This,
78 OUT struct _TCG_BOOT_SERVICE_CAPABILITY * ProtocolCapability,
79 OUT UINT32 * TCGFeatureFlags,
80 OUT EFI_PHYSICAL_ADDRESS * EventLogLocation,
81 OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry);
82
83 typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_ALL) (IN struct _EFI_TCG * This,
84 IN UINT8 * HashData,
85 IN UINT64 HashDataLen,
86 IN TCG_ALGORITHM_ID AlgorithmId,
87 IN OUT UINT64 * HashedDataLen, IN OUT UINT8 ** HashedDataResult);
88
89 typedef EFI_STATUS(EFIAPI * EFI_TCG_LOG_EVENT) (IN struct _EFI_TCG * This,
90 IN struct _TCG_PCR_EVENT * TCGLogData,
91 IN OUT UINT32 * EventNumber, IN UINT32 Flags);
92
93 typedef EFI_STATUS(EFIAPI * EFI_TCG_PASS_THROUGH_TO_TPM) (IN struct _EFI_TCG * This,
94 IN UINT32 TpmInputParameterBlockSize,
95 IN UINT8 * TpmInputParameterBlock,
96 IN UINT32 TpmOutputParameterBlockSize,
97 IN UINT8 * TpmOutputParameterBlock);
98
99 typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_LOG_EXTEND_EVENT) (IN struct _EFI_TCG * This,
100 IN EFI_PHYSICAL_ADDRESS HashData,
101 IN UINT64 HashDataLen,
102 IN TCG_ALGORITHM_ID AlgorithmId,
103 IN struct _TCG_PCR_EVENT * TCGLogData,
104 IN OUT UINT32 * EventNumber,
105 OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry);
106
107 typedef struct _EFI_TCG {
108 EFI_TCG_STATUS_CHECK StatusCheck;
109 EFI_TCG_HASH_ALL HashAll;
110 EFI_TCG_LOG_EVENT LogEvent;
111 EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTPM;
112 EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent;
113 } EFI_TCG;
114
115 #define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }}
116
117 typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL;
118
119 typedef UINT32 EFI_TCG2_EVENT_LOG_BITMAP;
120 typedef UINT32 EFI_TCG2_EVENT_LOG_FORMAT;
121 typedef UINT32 EFI_TCG2_EVENT_ALGORITHM_BITMAP;
122
123 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001
124 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002
125
126 typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY {
127 UINT8 Size;
128 EFI_TCG2_VERSION StructureVersion;
129 EFI_TCG2_VERSION ProtocolVersion;
130 EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
131 EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs;
132 BOOLEAN TPMPresentFlag;
133 UINT16 MaxCommandSize;
134 UINT16 MaxResponseSize;
135 UINT32 ManufacturerID;
136 UINT32 NumberOfPCRBanks;
137 EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks;
138 } EFI_TCG2_BOOT_SERVICE_CAPABILITY;
139
140 #define EFI_TCG2_EVENT_HEADER_VERSION 1
141
142 typedef struct {
143 UINT32 HeaderSize;
144 UINT16 HeaderVersion;
145 UINT32 PCRIndex;
146 UINT32 EventType;
147 } __attribute__ ((packed)) EFI_TCG2_EVENT_HEADER;
148
149 typedef struct tdEFI_TCG2_EVENT {
150 UINT32 Size;
151 EFI_TCG2_EVENT_HEADER Header;
152 UINT8 Event[1];
153 } __attribute__ ((packed)) EFI_TCG2_EVENT;
154
155 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This,
156 IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability);
157
158 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_EVENT_LOG) (IN EFI_TCG2_PROTOCOL * This,
159 IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
160 OUT EFI_PHYSICAL_ADDRESS * EventLogLocation,
161 OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry,
162 OUT BOOLEAN * EventLogTruncated);
163
164 typedef EFI_STATUS(EFIAPI * EFI_TCG2_HASH_LOG_EXTEND_EVENT) (IN EFI_TCG2_PROTOCOL * This,
165 IN UINT64 Flags,
166 IN EFI_PHYSICAL_ADDRESS DataToHash,
167 IN UINT64 DataToHashLen, IN EFI_TCG2_EVENT * EfiTcgEvent);
168
169 typedef EFI_STATUS(EFIAPI * EFI_TCG2_SUBMIT_COMMAND) (IN EFI_TCG2_PROTOCOL * This,
170 IN UINT32 InputParameterBlockSize,
171 IN UINT8 * InputParameterBlock,
172 IN UINT32 OutputParameterBlockSize, IN UINT8 * OutputParameterBlock);
173
174 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * ActivePcrBanks);
175
176 typedef EFI_STATUS(EFIAPI * EFI_TCG2_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 ActivePcrBanks);
177
178 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This,
179 OUT UINT32 * OperationPresent, OUT UINT32 * Response);
180
181 typedef struct tdEFI_TCG2_PROTOCOL {
182 EFI_TCG2_GET_CAPABILITY GetCapability;
183 EFI_TCG2_GET_EVENT_LOG GetEventLog;
184 EFI_TCG2_HASH_LOG_EXTEND_EVENT HashLogExtendEvent;
185 EFI_TCG2_SUBMIT_COMMAND SubmitCommand;
186 EFI_TCG2_GET_ACTIVE_PCR_BANKS GetActivePcrBanks;
187 EFI_TCG2_SET_ACTIVE_PCR_BANKS SetActivePcrBanks;
188 EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS GetResultOfSetActivePcrBanks;
189 } EFI_TCG2;
190
191
192 static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer,
193 UINTN buffer_size, const CHAR16 *description) {
194 EFI_STATUS status;
195 TCG_PCR_EVENT *tcg_event;
196 UINT32 event_number;
197 EFI_PHYSICAL_ADDRESS event_log_last;
198 UINTN desc_len;
199
200 desc_len = (StrLen(description) + 1) * sizeof(CHAR16);
201
202 tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT));
203
204 if (!tcg_event)
205 return EFI_OUT_OF_RESOURCES;
206
207 tcg_event->EventSize = desc_len;
208 CopyMem((VOID *) & tcg_event->Event[0], (VOID *) description, desc_len);
209
210 tcg_event->PCRIndex = pcrindex;
211 tcg_event->EventType = EV_IPL;
212
213 event_number = 1;
214 status = uefi_call_wrapper(tcg->HashLogExtendEvent, 7,
215 (EFI_TCG *) tcg, buffer, buffer_size, TCG_ALG_SHA, tcg_event, &event_number, &event_log_last);
216
217 if (EFI_ERROR(status))
218 return status;
219
220 uefi_call_wrapper(BS->FreePool, 1, tcg_event);
221
222 return EFI_SUCCESS;
223 }
224
225 /*
226 * According to TCG EFI Protocol Specification for TPM 2.0 family,
227 * all events generated after the invocation of EFI_TCG2_GET_EVENT_LOG
228 * shall be stored in an instance of an EFI_CONFIGURATION_TABLE aka
229 * EFI TCG 2.0 final events table. Hence, it is necessary to trigger the
230 * internal switch through calling get_event_log() in order to allow
231 * to retrieve the logs from OS runtime.
232 */
233 static EFI_STATUS trigger_tcg2_final_events_table(const EFI_TCG2 *tcg, EFI_TCG2_EVENT_LOG_FORMAT log_fmt)
234 {
235 return uefi_call_wrapper(tcg->GetEventLog, 5, (EFI_TCG2 *) tcg,
236 log_fmt, 0, 0, 0);
237 }
238
239 static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer,
240 UINT64 buffer_size, const CHAR16 *description, EFI_TCG2_EVENT_LOG_FORMAT log_fmt) {
241 EFI_STATUS status;
242 EFI_TCG2_EVENT *tcg_event;
243 UINTN desc_len;
244 static BOOLEAN triggered = FALSE;
245
246 if (triggered == FALSE) {
247 status = trigger_tcg2_final_events_table(tcg, log_fmt);
248 if (EFI_ERROR(status))
249 return status;
250
251 triggered = TRUE;
252 }
253
254 desc_len = StrLen(description) * sizeof(CHAR16);
255
256 tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1);
257
258 if (!tcg_event)
259 return EFI_OUT_OF_RESOURCES;
260
261 tcg_event->Size = sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1;
262 tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
263 tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
264 tcg_event->Header.PCRIndex = pcrindex;
265 tcg_event->Header.EventType = EV_IPL;
266
267 CopyMem((VOID *) tcg_event->Event, (VOID *) description, desc_len);
268
269 status = uefi_call_wrapper(tcg->HashLogExtendEvent, 5, (EFI_TCG2 *) tcg, 0, buffer, (UINT64) buffer_size, tcg_event);
270
271 uefi_call_wrapper(BS->FreePool, 1, tcg_event);
272
273 if (EFI_ERROR(status))
274 return status;
275
276 return EFI_SUCCESS;
277 }
278
279 static EFI_TCG * tcg1_interface_check(void) {
280 EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID;
281 EFI_STATUS status;
282 EFI_TCG *tcg;
283 TCG_BOOT_SERVICE_CAPABILITY capability;
284 UINT32 features;
285 EFI_PHYSICAL_ADDRESS event_log_location;
286 EFI_PHYSICAL_ADDRESS event_log_last_entry;
287
288 status = LibLocateProtocol(&tpm_guid, (void **) &tcg);
289
290 if (EFI_ERROR(status))
291 return NULL;
292
293 capability.Size = (UINT8) sizeof(capability);
294 status = uefi_call_wrapper(tcg->StatusCheck, 5, tcg, &capability, &features, &event_log_location, &event_log_last_entry);
295
296 if (EFI_ERROR(status))
297 return NULL;
298
299 if (capability.TPMDeactivatedFlag)
300 return NULL;
301
302 if (!capability.TPMPresentFlag)
303 return NULL;
304
305 return tcg;
306 }
307
308 static EFI_TCG2 * tcg2_interface_check(EFI_TCG2_BOOT_SERVICE_CAPABILITY *caps) {
309 EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
310 EFI_STATUS status;
311 EFI_TCG2 *tcg;
312
313 status = LibLocateProtocol(&tpm2_guid, (void **) &tcg);
314
315 if (EFI_ERROR(status))
316 return NULL;
317
318 caps->Size = (UINT8) sizeof(EFI_TCG2_BOOT_SERVICE_CAPABILITY);
319 status = uefi_call_wrapper(tcg->GetCapability, 2, tcg, caps);
320
321 if (EFI_ERROR(status))
322 return NULL;
323
324 if (caps->StructureVersion.Major == 1 &&
325 caps->StructureVersion.Minor == 0) {
326 TCG_BOOT_SERVICE_CAPABILITY *caps_1_0;
327 caps_1_0 = (TCG_BOOT_SERVICE_CAPABILITY *)caps;
328 if (caps_1_0->TPMPresentFlag)
329 return tcg;
330 }
331
332 if (!caps->TPMPresentFlag)
333 return NULL;
334
335 return tcg;
336 }
337
338 EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
339 EFI_TCG *tpm1;
340 EFI_TCG2 *tpm2;
341 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
342
343 tpm2 = tcg2_interface_check(&caps);
344 if (tpm2) {
345 EFI_TCG2_EVENT_LOG_BITMAP supported_logs;
346 EFI_TCG2_EVENT_LOG_FORMAT log_fmt;
347
348 if (caps.StructureVersion.Major == 1 &&
349 caps.StructureVersion.Minor == 0)
350 supported_logs = ((TREE_BOOT_SERVICE_CAPABILITY *)&caps)->SupportedEventLogs;
351 else
352 supported_logs = caps.SupportedEventLogs;
353
354 if (supported_logs & EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
355 log_fmt = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
356 else
357 log_fmt = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
358
359 uefi_call_wrapper(BS->Stall, 1, 2000 * 1000);
360 return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description, log_fmt);
361 }
362
363 tpm1 = tcg1_interface_check();
364 if (tpm1)
365 return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
366
367 /* No active TPM found, so don't return an error */
368 return EFI_SUCCESS;
369 }
370
371 #endif