]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/measure.c
Add SPDX license identifiers to source files under the LGPL
[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 _TCG_BOOT_SERVICE_CAPABILITY {
31 UINT8 Size;
32 struct _TCG_VERSION StructureVersion;
33 struct _TCG_VERSION ProtocolSpecVersion;
34 UINT8 HashAlgorithmBitmap;
35 BOOLEAN TPMPresentFlag;
36 BOOLEAN TPMDeactivatedFlag;
37 } TCG_BOOT_SERVICE_CAPABILITY;
38
39 typedef UINT32 TCG_ALGORITHM_ID;
40 #define TCG_ALG_SHA 0x00000004 // The SHA1 algorithm
41
42 #define SHA1_DIGEST_SIZE 20
43
44 typedef struct _TCG_DIGEST {
45 UINT8 Digest[SHA1_DIGEST_SIZE];
46 } TCG_DIGEST;
47
48 #define EV_IPL 13
49
50 typedef struct _TCG_PCR_EVENT {
51 UINT32 PCRIndex;
52 UINT32 EventType;
53 struct _TCG_DIGEST digest;
54 UINT32 EventSize;
55 UINT8 Event[1];
56 } TCG_PCR_EVENT;
57
58 INTERFACE_DECL(_EFI_TCG);
59
60 typedef EFI_STATUS(EFIAPI * EFI_TCG_STATUS_CHECK) (IN struct _EFI_TCG * This,
61 OUT struct _TCG_BOOT_SERVICE_CAPABILITY * ProtocolCapability,
62 OUT UINT32 * TCGFeatureFlags,
63 OUT EFI_PHYSICAL_ADDRESS * EventLogLocation,
64 OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry);
65
66 typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_ALL) (IN struct _EFI_TCG * This,
67 IN UINT8 * HashData,
68 IN UINT64 HashDataLen,
69 IN TCG_ALGORITHM_ID AlgorithmId,
70 IN OUT UINT64 * HashedDataLen, IN OUT UINT8 ** HashedDataResult);
71
72 typedef EFI_STATUS(EFIAPI * EFI_TCG_LOG_EVENT) (IN struct _EFI_TCG * This,
73 IN struct _TCG_PCR_EVENT * TCGLogData,
74 IN OUT UINT32 * EventNumber, IN UINT32 Flags);
75
76 typedef EFI_STATUS(EFIAPI * EFI_TCG_PASS_THROUGH_TO_TPM) (IN struct _EFI_TCG * This,
77 IN UINT32 TpmInputParameterBlockSize,
78 IN UINT8 * TpmInputParameterBlock,
79 IN UINT32 TpmOutputParameterBlockSize,
80 IN UINT8 * TpmOutputParameterBlock);
81
82 typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_LOG_EXTEND_EVENT) (IN struct _EFI_TCG * This,
83 IN EFI_PHYSICAL_ADDRESS HashData,
84 IN UINT64 HashDataLen,
85 IN TCG_ALGORITHM_ID AlgorithmId,
86 IN struct _TCG_PCR_EVENT * TCGLogData,
87 IN OUT UINT32 * EventNumber,
88 OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry);
89
90 typedef struct _EFI_TCG {
91 EFI_TCG_STATUS_CHECK StatusCheck;
92 EFI_TCG_HASH_ALL HashAll;
93 EFI_TCG_LOG_EVENT LogEvent;
94 EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTPM;
95 EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent;
96 } EFI_TCG;
97
98 #define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }}
99
100 typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL;
101
102 typedef struct tdEFI_TCG2_VERSION {
103 UINT8 Major;
104 UINT8 Minor;
105 } EFI_TCG2_VERSION;
106
107 typedef UINT32 EFI_TCG2_EVENT_LOG_BITMAP;
108 typedef UINT32 EFI_TCG2_EVENT_LOG_FORMAT;
109 typedef UINT32 EFI_TCG2_EVENT_ALGORITHM_BITMAP;
110
111 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001
112 #define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002
113
114 typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY {
115 UINT8 Size;
116 EFI_TCG2_VERSION StructureVersion;
117 EFI_TCG2_VERSION ProtocolVersion;
118 EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
119 EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs;
120 BOOLEAN TPMPresentFlag;
121 UINT16 MaxCommandSize;
122 UINT16 MaxResponseSize;
123 UINT32 ManufacturerID;
124 UINT32 NumberOfPCRBanks;
125 EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks;
126 } EFI_TCG2_BOOT_SERVICE_CAPABILITY;
127
128 #define EFI_TCG2_EVENT_HEADER_VERSION 1
129
130 typedef struct {
131 UINT32 HeaderSize;
132 UINT16 HeaderVersion;
133 UINT32 PCRIndex;
134 UINT32 EventType;
135 } EFI_TCG2_EVENT_HEADER;
136
137 typedef struct tdEFI_TCG2_EVENT {
138 UINT32 Size;
139 EFI_TCG2_EVENT_HEADER Header;
140 UINT8 Event[1];
141 } EFI_TCG2_EVENT;
142
143 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This,
144 IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability);
145
146 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_EVENT_LOG) (IN EFI_TCG2_PROTOCOL * This,
147 IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
148 OUT EFI_PHYSICAL_ADDRESS * EventLogLocation,
149 OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry,
150 OUT BOOLEAN * EventLogTruncated);
151
152 typedef EFI_STATUS(EFIAPI * EFI_TCG2_HASH_LOG_EXTEND_EVENT) (IN EFI_TCG2_PROTOCOL * This,
153 IN UINT64 Flags,
154 IN EFI_PHYSICAL_ADDRESS DataToHash,
155 IN UINT64 DataToHashLen, IN EFI_TCG2_EVENT * EfiTcgEvent);
156
157 typedef EFI_STATUS(EFIAPI * EFI_TCG2_SUBMIT_COMMAND) (IN EFI_TCG2_PROTOCOL * This,
158 IN UINT32 InputParameterBlockSize,
159 IN UINT8 * InputParameterBlock,
160 IN UINT32 OutputParameterBlockSize, IN UINT8 * OutputParameterBlock);
161
162 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * ActivePcrBanks);
163
164 typedef EFI_STATUS(EFIAPI * EFI_TCG2_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 ActivePcrBanks);
165
166 typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This,
167 OUT UINT32 * OperationPresent, OUT UINT32 * Response);
168
169 typedef struct tdEFI_TCG2_PROTOCOL {
170 EFI_TCG2_GET_CAPABILITY GetCapability;
171 EFI_TCG2_GET_EVENT_LOG GetEventLog;
172 EFI_TCG2_HASH_LOG_EXTEND_EVENT HashLogExtendEvent;
173 EFI_TCG2_SUBMIT_COMMAND SubmitCommand;
174 EFI_TCG2_GET_ACTIVE_PCR_BANKS GetActivePcrBanks;
175 EFI_TCG2_SET_ACTIVE_PCR_BANKS SetActivePcrBanks;
176 EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS GetResultOfSetActivePcrBanks;
177 } EFI_TCG2;
178
179
180 static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer,
181 UINTN buffer_size, const CHAR16 *description) {
182 EFI_STATUS status;
183 TCG_PCR_EVENT *tcg_event;
184 UINT32 event_number;
185 EFI_PHYSICAL_ADDRESS event_log_last;
186 UINTN desc_len;
187
188 desc_len = (StrLen(description) + 1) * sizeof(CHAR16);
189
190 tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT));
191
192 if (tcg_event == NULL)
193 return EFI_OUT_OF_RESOURCES;
194
195 tcg_event->EventSize = desc_len;
196 CopyMem((VOID *) & tcg_event->Event[0], (VOID *) description, desc_len);
197
198 tcg_event->PCRIndex = pcrindex;
199 tcg_event->EventType = EV_IPL;
200
201 event_number = 1;
202 status = uefi_call_wrapper(tcg->HashLogExtendEvent, 7,
203 (EFI_TCG *) tcg, buffer, buffer_size, TCG_ALG_SHA, tcg_event, &event_number, &event_log_last);
204
205 if (EFI_ERROR(status))
206 return status;
207
208 uefi_call_wrapper(BS->FreePool, 1, tcg_event);
209
210 return EFI_SUCCESS;
211 }
212
213 /*
214 * According to TCG EFI Protocol Specification for TPM 2.0 family,
215 * all events generated after the invocation of EFI_TCG2_GET_EVENT_LOG
216 * shall be stored in an instance of an EFI_CONFIGURATION_TABLE aka
217 * EFI TCG 2.0 final events table. Hence, it is necessary to trigger the
218 * internal switch through calling get_event_log() in order to allow
219 * to retrieve the logs from OS runtime.
220 */
221 static EFI_STATUS trigger_tcg2_final_events_table(const EFI_TCG2 *tcg)
222 {
223 return uefi_call_wrapper(tcg->GetEventLog, 5, (EFI_TCG2 *) tcg,
224 EFI_TCG2_EVENT_LOG_FORMAT_TCG_2, NULL,
225 NULL, NULL);
226 }
227
228 static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer,
229 UINT64 buffer_size, const CHAR16 *description) {
230 EFI_STATUS status;
231 EFI_TCG2_EVENT *tcg_event;
232 UINTN desc_len;
233 static BOOLEAN triggered = FALSE;
234
235 if (triggered == FALSE) {
236 status = trigger_tcg2_final_events_table(tcg);
237 if (EFI_ERROR(status))
238 return status;
239
240 triggered = TRUE;
241 }
242
243 desc_len = StrLen(description) * sizeof(CHAR16);
244
245 tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1);
246
247 if (tcg_event == NULL)
248 return EFI_OUT_OF_RESOURCES;
249
250 tcg_event->Size = sizeof(EFI_TCG2_EVENT) - sizeof(tcg_event->Event) + desc_len + 1;
251 tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
252 tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
253 tcg_event->Header.PCRIndex = pcrindex;
254 tcg_event->Header.EventType = EV_IPL;
255
256 CopyMem((VOID *) tcg_event->Event, (VOID *) description, desc_len);
257
258 status = uefi_call_wrapper(tcg->HashLogExtendEvent, 5, (EFI_TCG2 *) tcg, 0, buffer, buffer_size, tcg_event);
259
260 uefi_call_wrapper(BS->FreePool, 1, tcg_event);
261
262 if (EFI_ERROR(status))
263 return status;
264
265 return EFI_SUCCESS;
266 }
267
268 static EFI_TCG * tcg1_interface_check(void) {
269 EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID;
270 EFI_STATUS status;
271 EFI_TCG *tcg;
272 TCG_BOOT_SERVICE_CAPABILITY capability;
273 UINT32 features;
274 EFI_PHYSICAL_ADDRESS event_log_location;
275 EFI_PHYSICAL_ADDRESS event_log_last_entry;
276
277 status = LibLocateProtocol(&tpm_guid, (void **) &tcg);
278
279 if (EFI_ERROR(status))
280 return NULL;
281
282 capability.Size = (UINT8) sizeof(capability);
283 status = uefi_call_wrapper(tcg->StatusCheck, 5, tcg, &capability, &features, &event_log_location, &event_log_last_entry);
284
285 if (EFI_ERROR(status))
286 return NULL;
287
288 if (capability.TPMDeactivatedFlag)
289 return NULL;
290
291 if (!capability.TPMPresentFlag)
292 return NULL;
293
294 return tcg;
295 }
296
297 static EFI_TCG2 * tcg2_interface_check(void) {
298 EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
299 EFI_STATUS status;
300 EFI_TCG2 *tcg;
301 EFI_TCG2_BOOT_SERVICE_CAPABILITY capability;
302
303 status = LibLocateProtocol(&tpm2_guid, (void **) &tcg);
304
305 if (EFI_ERROR(status))
306 return NULL;
307
308 capability.Size = (UINT8) sizeof(capability);
309 status = uefi_call_wrapper(tcg->GetCapability, 2, tcg, &capability);
310
311 if (EFI_ERROR(status))
312 return NULL;
313
314 if (!capability.TPMPresentFlag)
315 return NULL;
316
317 return tcg;
318 }
319
320 EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
321 EFI_TCG *tpm1;
322 EFI_TCG2 *tpm2;
323
324 tpm2 = tcg2_interface_check();
325 if (tpm2)
326 return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
327
328 tpm1 = tcg1_interface_check();
329 if (tpm1)
330 return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
331
332 /* No active TPM found, so don't return an error */
333 return EFI_SUCCESS;
334 }
335
336 #endif