2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2018 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 * EFI TPM support code.
22 #include <grub/i18n.h>
23 #include <grub/efi/api.h>
24 #include <grub/efi/efi.h>
25 #include <grub/efi/tpm.h>
28 #include <grub/term.h>
30 typedef TCG_PCR_EVENT grub_tpm_event_t
;
32 static grub_efi_guid_t tpm_guid
= EFI_TPM_GUID
;
33 static grub_efi_guid_t tpm2_guid
= EFI_TPM2_GUID
;
35 static grub_efi_handle_t
*grub_tpm_handle
;
36 static grub_uint8_t grub_tpm_version
;
38 static grub_int8_t tpm1_present
= -1;
39 static grub_int8_t tpm2_present
= -1;
41 static grub_efi_boolean_t
42 grub_tpm1_present (grub_efi_tpm_protocol_t
*tpm
)
44 grub_efi_status_t status
;
45 TCG_EFI_BOOT_SERVICE_CAPABILITY caps
;
47 grub_efi_physical_address_t eventlog
, lastevent
;
49 if (tpm1_present
!= -1)
50 return (grub_efi_boolean_t
) tpm1_present
;
52 caps
.Size
= (grub_uint8_t
) sizeof (caps
);
54 status
= efi_call_5 (tpm
->status_check
, tpm
, &caps
, &flags
, &eventlog
,
57 if (status
!= GRUB_EFI_SUCCESS
|| caps
.TPMDeactivatedFlag
58 || !caps
.TPMPresentFlag
)
59 return tpm1_present
= 0;
61 return tpm1_present
= 1;
64 static grub_efi_boolean_t
65 grub_tpm2_present (grub_efi_tpm2_protocol_t
*tpm
)
67 grub_efi_status_t status
;
68 EFI_TCG2_BOOT_SERVICE_CAPABILITY caps
;
70 caps
.Size
= (grub_uint8_t
) sizeof (caps
);
72 if (tpm2_present
!= -1)
73 return (grub_efi_boolean_t
) tpm2_present
;
75 status
= efi_call_2 (tpm
->get_capability
, tpm
, &caps
);
77 if (status
!= GRUB_EFI_SUCCESS
|| !caps
.TPMPresentFlag
)
78 return tpm2_present
= 0;
80 return tpm2_present
= 1;
83 static grub_efi_boolean_t
84 grub_tpm_handle_find (grub_efi_handle_t
*tpm_handle
,
85 grub_efi_uint8_t
*protocol_version
)
87 grub_efi_handle_t
*handles
;
88 grub_efi_uintn_t num_handles
;
90 if (grub_tpm_handle
!= NULL
)
92 *tpm_handle
= grub_tpm_handle
;
93 *protocol_version
= grub_tpm_version
;
97 handles
= grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL
, &tpm_guid
, NULL
,
99 if (handles
&& num_handles
> 0)
101 grub_tpm_handle
= handles
[0];
102 *tpm_handle
= handles
[0];
103 grub_tpm_version
= 1;
104 *protocol_version
= 1;
108 handles
= grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL
, &tpm2_guid
, NULL
,
110 if (handles
&& num_handles
> 0)
112 grub_tpm_handle
= handles
[0];
113 *tpm_handle
= handles
[0];
114 grub_tpm_version
= 2;
115 *protocol_version
= 2;
123 grub_tpm1_execute (grub_efi_handle_t tpm_handle
,
124 PassThroughToTPM_InputParamBlock
*inbuf
,
125 PassThroughToTPM_OutputParamBlock
*outbuf
)
127 grub_efi_status_t status
;
128 grub_efi_tpm_protocol_t
*tpm
;
129 grub_uint32_t inhdrsize
= sizeof (*inbuf
) - sizeof (inbuf
->TPMOperandIn
);
130 grub_uint32_t outhdrsize
=
131 sizeof (*outbuf
) - sizeof (outbuf
->TPMOperandOut
);
133 tpm
= grub_efi_open_protocol (tpm_handle
, &tpm_guid
,
134 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
136 if (!grub_tpm1_present (tpm
))
139 /* UEFI TPM protocol takes the raw operand block, no param block header. */
140 status
= efi_call_5 (tpm
->pass_through_to_tpm
, tpm
,
141 inbuf
->IPBLength
- inhdrsize
, inbuf
->TPMOperandIn
,
142 outbuf
->OPBLength
- outhdrsize
, outbuf
->TPMOperandOut
);
146 case GRUB_EFI_SUCCESS
:
148 case GRUB_EFI_DEVICE_ERROR
:
149 return grub_error (GRUB_ERR_IO
, N_("Command failed"));
150 case GRUB_EFI_INVALID_PARAMETER
:
151 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("Invalid parameter"));
152 case GRUB_EFI_BUFFER_TOO_SMALL
:
153 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
154 N_("Output buffer too small"));
155 case GRUB_EFI_NOT_FOUND
:
156 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("TPM unavailable"));
158 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("Unknown TPM error"));
163 grub_tpm2_execute (grub_efi_handle_t tpm_handle
,
164 PassThroughToTPM_InputParamBlock
*inbuf
,
165 PassThroughToTPM_OutputParamBlock
*outbuf
)
167 grub_efi_status_t status
;
168 grub_efi_tpm2_protocol_t
*tpm
;
169 grub_uint32_t inhdrsize
= sizeof (*inbuf
) - sizeof (inbuf
->TPMOperandIn
);
170 grub_uint32_t outhdrsize
=
171 sizeof (*outbuf
) - sizeof (outbuf
->TPMOperandOut
);
173 tpm
= grub_efi_open_protocol (tpm_handle
, &tpm2_guid
,
174 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
176 if (!grub_tpm2_present (tpm
))
179 /* UEFI TPM protocol takes the raw operand block, no param block header. */
180 status
= efi_call_5 (tpm
->submit_command
, tpm
,
181 inbuf
->IPBLength
- inhdrsize
, inbuf
->TPMOperandIn
,
182 outbuf
->OPBLength
- outhdrsize
, outbuf
->TPMOperandOut
);
186 case GRUB_EFI_SUCCESS
:
188 case GRUB_EFI_DEVICE_ERROR
:
189 return grub_error (GRUB_ERR_IO
, N_("Command failed"));
190 case GRUB_EFI_INVALID_PARAMETER
:
191 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("Invalid parameter"));
192 case GRUB_EFI_BUFFER_TOO_SMALL
:
193 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
194 N_("Output buffer too small"));
195 case GRUB_EFI_NOT_FOUND
:
196 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("TPM unavailable"));
198 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("Unknown TPM error"));
203 grub_tpm_execute (PassThroughToTPM_InputParamBlock
*inbuf
,
204 PassThroughToTPM_OutputParamBlock
*outbuf
)
206 grub_efi_handle_t tpm_handle
;
207 grub_uint8_t protocol_version
;
209 /* Absence of a TPM isn't a failure. */
210 if (!grub_tpm_handle_find (&tpm_handle
, &protocol_version
))
213 if (protocol_version
== 1)
214 return grub_tpm1_execute (tpm_handle
, inbuf
, outbuf
);
216 return grub_tpm2_execute (tpm_handle
, inbuf
, outbuf
);
220 grub_tpm1_log_event (grub_efi_handle_t tpm_handle
, unsigned char *buf
,
221 grub_size_t size
, grub_uint8_t pcr
,
222 const char *description
)
224 grub_tpm_event_t
*event
;
225 grub_efi_status_t status
;
226 grub_efi_tpm_protocol_t
*tpm
;
227 grub_efi_physical_address_t lastevent
;
228 grub_uint32_t algorithm
;
229 grub_uint32_t eventnum
= 0;
231 tpm
= grub_efi_open_protocol (tpm_handle
, &tpm_guid
,
232 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
234 if (!grub_tpm1_present (tpm
))
237 event
= grub_zalloc (sizeof (*event
) + grub_strlen (description
) + 1);
239 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
240 N_("cannot allocate TPM event buffer"));
242 event
->PCRIndex
= pcr
;
243 event
->EventType
= EV_IPL
;
244 event
->EventSize
= grub_strlen (description
) + 1;
245 grub_memcpy (event
->Event
, description
, event
->EventSize
);
247 algorithm
= TCG_ALG_SHA
;
248 status
= efi_call_7 (tpm
->log_extend_event
, tpm
, buf
, (grub_uint64_t
) size
,
249 algorithm
, event
, &eventnum
, &lastevent
);
253 case GRUB_EFI_SUCCESS
:
255 case GRUB_EFI_DEVICE_ERROR
:
256 return grub_error (GRUB_ERR_IO
, N_("Command failed"));
257 case GRUB_EFI_INVALID_PARAMETER
:
258 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("Invalid parameter"));
259 case GRUB_EFI_BUFFER_TOO_SMALL
:
260 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
261 N_("Output buffer too small"));
262 case GRUB_EFI_NOT_FOUND
:
263 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("TPM unavailable"));
265 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("Unknown TPM error"));
270 grub_tpm2_log_event (grub_efi_handle_t tpm_handle
, unsigned char *buf
,
271 grub_size_t size
, grub_uint8_t pcr
,
272 const char *description
)
274 EFI_TCG2_EVENT
*event
;
275 grub_efi_status_t status
;
276 grub_efi_tpm2_protocol_t
*tpm
;
278 tpm
= grub_efi_open_protocol (tpm_handle
, &tpm2_guid
,
279 GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
281 if (!grub_tpm2_present (tpm
))
285 grub_zalloc (sizeof (EFI_TCG2_EVENT
) + grub_strlen (description
) + 1);
287 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
288 N_("cannot allocate TPM event buffer"));
290 event
->Header
.HeaderSize
= sizeof (EFI_TCG2_EVENT_HEADER
);
291 event
->Header
.HeaderVersion
= 1;
292 event
->Header
.PCRIndex
= pcr
;
293 event
->Header
.EventType
= EV_IPL
;
295 sizeof (*event
) - sizeof (event
->Event
) + grub_strlen (description
) + 1;
296 grub_memcpy (event
->Event
, description
, grub_strlen (description
) + 1);
298 status
= efi_call_5 (tpm
->hash_log_extend_event
, tpm
, 0, buf
,
299 (grub_uint64_t
) size
, event
);
303 case GRUB_EFI_SUCCESS
:
305 case GRUB_EFI_DEVICE_ERROR
:
306 return grub_error (GRUB_ERR_IO
, N_("Command failed"));
307 case GRUB_EFI_INVALID_PARAMETER
:
308 return grub_error (GRUB_ERR_BAD_ARGUMENT
, N_("Invalid parameter"));
309 case GRUB_EFI_BUFFER_TOO_SMALL
:
310 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
311 N_("Output buffer too small"));
312 case GRUB_EFI_NOT_FOUND
:
313 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("TPM unavailable"));
315 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
, N_("Unknown TPM error"));
320 grub_tpm_log_event (unsigned char *buf
, grub_size_t size
, grub_uint8_t pcr
,
321 const char *description
)
323 grub_efi_handle_t tpm_handle
;
324 grub_efi_uint8_t protocol_version
;
326 if (!grub_tpm_handle_find (&tpm_handle
, &protocol_version
))
329 if (protocol_version
== 1)
330 return grub_tpm1_log_event (tpm_handle
, buf
, size
, pcr
, description
);
332 return grub_tpm2_log_event (tpm_handle
, buf
, size
, pcr
, description
);