blob: 02921d8cae80184ca624a267af2f95e6ef413a04 [file] [log] [blame]
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001// Implementation of the TCG BIOS extension according to the specification
Stefan Berger2aff1c12015-05-26 15:48:33 -04002// described in specs found at
3// http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
Stefan Bergerb310dfa2015-03-23 14:22:16 -04004//
Stefan Berger2aff1c12015-05-26 15:48:33 -04005// Copyright (C) 2006-2011, 2014, 2015 IBM Corporation
Stefan Bergerb310dfa2015-03-23 14:22:16 -04006//
7// Authors:
8// Stefan Berger <stefanb@linux.vnet.ibm.com>
9//
10// This file may be distributed under the terms of the GNU LGPLv3 license.
11
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050012#include "bregs.h" // struct bregs
Stefan Bergerb310dfa2015-03-23 14:22:16 -040013#include "byteorder.h" // cpu_to_*
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050014#include "config.h" // CONFIG_TCGBIOS
Stefan Bergerb310dfa2015-03-23 14:22:16 -040015#include "farptr.h" // MAKE_FLATPTR
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050016#include "fw/paravirt.h" // runningOnXen
17#include "hw/tpm_drivers.h" // tpm_drivers[]
18#include "output.h" // dprintf
Stefan Berger4e57a542021-06-14 13:35:48 -040019#include "sha.h" // sha1, sha256, ...
Kevin O'Connordf50aaa2015-11-19 09:24:18 -050020#include "std/acpi.h" // RSDP_SIGNATURE, rsdt_descriptor
21#include "std/smbios.h" // struct smbios_entry_point
22#include "std/tcg.h" // TCG_PC_LOGOVERFLOW
Stefan Bergerb310dfa2015-03-23 14:22:16 -040023#include "string.h" // checksum
24#include "tcgbios.h"// tpm_*, prototypes
25#include "util.h" // printf, get_keystroke
Stefan Berger320df852015-11-30 11:14:19 -050026#include "stacks.h" // wait_threads, reset
Stefan Berger74544fa2016-08-05 11:07:08 -040027#include "malloc.h" // malloc_high
Stefan Bergerb310dfa2015-03-23 14:22:16 -040028
Stefan Bergerf53b93b2016-02-02 13:09:12 -050029
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050030/****************************************************************
Kevin O'Connor27065322015-11-28 14:25:41 -050031 * ACPI TCPA table interface
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050032 ****************************************************************/
Stefan Bergerb310dfa2015-03-23 14:22:16 -040033
Kevin O'Connor27065322015-11-28 14:25:41 -050034struct {
Stefan Berger60bb9e92015-11-21 14:54:42 -050035 /* length of the TCPA log buffer */
36 u32 log_area_minimum_length;
37
38 /* start address of TCPA log buffer */
39 u8 * log_area_start_address;
40
41 /* number of log entries written */
42 u32 entry_count;
43
44 /* address to write next log entry to */
45 u8 * log_area_next_entry;
46
47 /* address of last entry written (need for TCG_StatusCheck) */
48 u8 * log_area_last_entry;
Kevin O'Connor27065322015-11-28 14:25:41 -050049} tpm_state VARLOW;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050050
Stefan Bergerdf46d102017-11-14 15:03:47 -050051static int tpm_set_log_area(u8 *log_area_start_address,
52 u32 log_area_minimum_length)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050053{
Kevin O'Connor27065322015-11-28 14:25:41 -050054 if (!log_area_start_address || !log_area_minimum_length)
55 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050056
Kevin O'Connor27065322015-11-28 14:25:41 -050057 memset(log_area_start_address, 0, log_area_minimum_length);
58 tpm_state.log_area_start_address = log_area_start_address;
59 tpm_state.log_area_minimum_length = log_area_minimum_length;
60 tpm_state.log_area_next_entry = log_area_start_address;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050061 tpm_state.log_area_last_entry = NULL;
62 tpm_state.entry_count = 0;
Kevin O'Connor27065322015-11-28 14:25:41 -050063 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050064}
65
Stefan Bergerdf46d102017-11-14 15:03:47 -050066static int
67tpm_tcpa_probe(void)
68{
69 struct tcpa_descriptor_rev2 *tcpa = find_acpi_table(TCPA_SIGNATURE);
70 if (!tcpa)
71 return -1;
72
73 dprintf(DEBUG_tcg, "TCGBIOS: TCPA: LASA = %p, LAML = %u\n",
74 (u8 *)(long)tcpa->log_area_start_address,
75 tcpa->log_area_minimum_length);
76
77 return tpm_set_log_area((u8*)(long)tcpa->log_area_start_address,
78 tcpa->log_area_minimum_length);
79}
80
81static int
82tpm_tpm2_probe(void)
83{
84 struct tpm2_descriptor_rev2 *tpm2 = find_acpi_table(TPM2_SIGNATURE);
85 if (!tpm2)
86 return -1;
87
88 if (tpm2->length < 76)
89 return -1;
90
91 dprintf(DEBUG_tcg, "TCGBIOS: TPM2: LASA = %p, LAML = %u\n",
92 (u8 *)(long)tpm2->log_area_start_address,
93 tpm2->log_area_minimum_length);
94
95 return tpm_set_log_area((u8*)(long)tpm2->log_area_start_address,
96 tpm2->log_area_minimum_length);
97}
98
Kevin O'Connorf51c50a2015-11-22 10:57:52 -050099/*
100 * Extend the ACPI log with the given entry by copying the
101 * entry data into the log.
102 * Input
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400103 * entry : The header data to use (including the variable length digest)
104 * digest_len : Length of the digest in 'entry'
105 * event : Pointer to the event body to be copied into the log
106 * event_len : Length of 'event'
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500107 *
108 * Output:
109 * Returns an error code in case of faiure, 0 in case of success
110 */
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500111static int
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400112tpm_log_event(struct tpm_log_header *entry, int digest_len
113 , const void *event, int event_len)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500114{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500115 dprintf(DEBUG_tcg, "TCGBIOS: LASA = %p, next entry = %p\n",
116 tpm_state.log_area_start_address, tpm_state.log_area_next_entry);
117
Kevin O'Connorf4820ac2015-11-22 11:00:06 -0500118 if (tpm_state.log_area_next_entry == NULL)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500119 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500120
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400121 u32 size = (sizeof(*entry) + digest_len
122 + sizeof(struct tpm_log_trailer) + event_len);
Kevin O'Connor93784032016-02-05 22:28:17 -0500123 u32 logsize = (tpm_state.log_area_next_entry + size
124 - tpm_state.log_area_start_address);
125 if (logsize > tpm_state.log_area_minimum_length) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500126 dprintf(DEBUG_tcg, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500127 return -1;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500128 }
129
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400130 void *dest = tpm_state.log_area_next_entry;
131 memcpy(dest, entry, sizeof(*entry) + digest_len);
132 struct tpm_log_trailer *t = dest + sizeof(*entry) + digest_len;
133 t->eventdatasize = event_len;
134 memcpy(t->event, event, event_len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500135
136 tpm_state.log_area_last_entry = tpm_state.log_area_next_entry;
137 tpm_state.log_area_next_entry += size;
138 tpm_state.entry_count++;
139
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500140 return 0;
141}
142
143
144/****************************************************************
Kevin O'Connor01669932016-08-10 16:15:43 -0400145 * Digest formatting
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500146 ****************************************************************/
147
Kevin O'Connor01669932016-08-10 16:15:43 -0400148static TPMVersion TPM_version;
149static u32 tpm20_pcr_selection_size;
150static struct tpml_pcr_selection *tpm20_pcr_selection;
Stefan Berger115d0082016-01-07 12:02:49 -0500151
Stefan Bergera99de5c2016-08-05 11:07:11 -0400152// A 'struct tpm_log_entry' is a local data structure containing a
153// 'tpm_log_header' followed by space for the maximum supported
154// digest. (The digest is a sha1 hash on tpm1.2 or a series of
155// tpm2_digest_value structs on tpm2.0)
156struct tpm_log_entry {
157 struct tpm_log_header hdr;
158 u8 pad[sizeof(struct tpm2_digest_values)
Stefan Bergereaaf7262020-03-30 07:55:57 -0400159 + 8 * sizeof(struct tpm2_digest_value)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400160 + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE
Stefan Bergereaaf7262020-03-30 07:55:57 -0400161 + SHA512_BUFSIZE + SM3_256_BUFSIZE + SHA3_256_BUFSIZE
162 + SHA3_384_BUFSIZE + SHA3_512_BUFSIZE];
Stefan Bergera99de5c2016-08-05 11:07:11 -0400163} PACKED;
164
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500165static const struct hash_parameters {
166 u16 hashalg;
Stefan Berger171fc892019-01-30 14:06:07 -0500167 u8 hashalg_flag;
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500168 u8 hash_buffersize;
Stefan Berger171fc892019-01-30 14:06:07 -0500169 const char *name;
Stefan Berger1be65c52021-06-14 13:35:49 -0400170 void (*hashfunc)(const u8 *data, u32 length, u8 *hash);
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500171} hash_parameters[] = {
172 {
173 .hashalg = TPM2_ALG_SHA1,
Stefan Berger171fc892019-01-30 14:06:07 -0500174 .hashalg_flag = TPM2_ALG_SHA1_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500175 .hash_buffersize = SHA1_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500176 .name = "SHA1",
Stefan Berger1be65c52021-06-14 13:35:49 -0400177 .hashfunc = sha1,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500178 }, {
179 .hashalg = TPM2_ALG_SHA256,
Stefan Berger171fc892019-01-30 14:06:07 -0500180 .hashalg_flag = TPM2_ALG_SHA256_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500181 .hash_buffersize = SHA256_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500182 .name = "SHA256",
Stefan Berger1be65c52021-06-14 13:35:49 -0400183 .hashfunc = sha256,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500184 }, {
185 .hashalg = TPM2_ALG_SHA384,
Stefan Berger171fc892019-01-30 14:06:07 -0500186 .hashalg_flag = TPM2_ALG_SHA384_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500187 .hash_buffersize = SHA384_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500188 .name = "SHA384",
Stefan Berger1be65c52021-06-14 13:35:49 -0400189 .hashfunc = sha384,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500190 }, {
191 .hashalg = TPM2_ALG_SHA512,
Stefan Berger171fc892019-01-30 14:06:07 -0500192 .hashalg_flag = TPM2_ALG_SHA512_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500193 .hash_buffersize = SHA512_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500194 .name = "SHA512",
Stefan Berger1be65c52021-06-14 13:35:49 -0400195 .hashfunc = sha512,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500196 }, {
197 .hashalg = TPM2_ALG_SM3_256,
Stefan Berger171fc892019-01-30 14:06:07 -0500198 .hashalg_flag = TPM2_ALG_SM3_256_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500199 .hash_buffersize = SM3_256_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500200 .name = "SM3-256",
Stefan Bergereaaf7262020-03-30 07:55:57 -0400201 }, {
202 .hashalg = TPM2_ALG_SHA3_256,
203 .hashalg_flag = TPM2_ALG_SHA3_256_FLAG,
204 .hash_buffersize = SHA3_256_BUFSIZE,
205 .name = "SHA3-256",
206 }, {
207 .hashalg = TPM2_ALG_SHA3_384,
208 .hashalg_flag = TPM2_ALG_SHA3_384_FLAG,
209 .hash_buffersize = SHA3_384_BUFSIZE,
210 .name = "SHA3-384",
211 }, {
212 .hashalg = TPM2_ALG_SHA3_512,
213 .hashalg_flag = TPM2_ALG_SHA3_512_FLAG,
214 .hash_buffersize = SHA3_512_BUFSIZE,
215 .name = "SHA3-512",
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500216 }
217};
218
Stefan Bergera99de5c2016-08-05 11:07:11 -0400219static int
220tpm20_get_hash_buffersize(u16 hashAlg)
221{
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500222 unsigned i;
223
224 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
225 if (hash_parameters[i].hashalg == hashAlg)
226 return hash_parameters[i].hash_buffersize;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400227 }
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500228 return -1;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400229}
230
Stefan Berger171fc892019-01-30 14:06:07 -0500231static u8
232tpm20_hashalg_to_flag(u16 hashAlg)
233{
234 unsigned i;
235
236 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
237 if (hash_parameters[i].hashalg == hashAlg)
238 return hash_parameters[i].hashalg_flag;
239 }
240 return 0;
241}
242
243static u16
244tpm20_hashalg_flag_to_hashalg(u8 hashalg_flag)
245{
246 unsigned i;
247
248 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
249 if (hash_parameters[i].hashalg_flag == hashalg_flag)
250 return hash_parameters[i].hashalg;
251 }
252 return 0;
253}
254
255static const char *
256tpm20_hashalg_flag_to_name(u8 hashalg_flag)
257{
258 unsigned i;
259
260 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
261 if (hash_parameters[i].hashalg_flag == hashalg_flag)
262 return hash_parameters[i].name;
263 }
264 return NULL;
265}
266
Stefan Berger1be65c52021-06-14 13:35:49 -0400267static void tpm2_hash_data(u16 hashAlg, const u8 *data, u32 data_len, u8 *hash)
268{
269 unsigned i;
270
271 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
272 if (hash_parameters[i].hashalg == hashAlg) {
273 if (hash_parameters[i].hashfunc) {
274 hash_parameters[i].hashfunc(data, data_len, hash);
275 } else {
276 memset(hash, 0xff, hash_parameters[i].hash_buffersize);
277 }
278 }
279 }
280}
281
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400282// Add an entry at the start of the log describing digest formats
283static int
284tpm20_write_EfiSpecIdEventStruct(void)
285{
286 if (!tpm20_pcr_selection)
287 return -1;
288
289 struct {
290 struct TCG_EfiSpecIdEventStruct hdr;
Stefan Bergereaaf7262020-03-30 07:55:57 -0400291 u8 pad[sizeof(struct tpm_log_entry) + sizeof(u8)];
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400292 } event = {
293 .hdr.signature = "Spec ID Event03",
294 .hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
295 .hdr.specVersionMinor = 0,
296 .hdr.specVersionMajor = 2,
Stefan Bergerba949f52021-06-09 13:31:59 -0400297 .hdr.specErrata = 2,
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400298 .hdr.uintnSize = 2,
299 };
300
301 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
302 void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
303
Stefan Berger80fce2c2020-03-30 07:55:55 -0400304 u32 count, numAlgs = 0;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400305 for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
306 u8 sizeOfSelect = sel->sizeOfSelect;
307
308 nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
309 if (nsel > end)
310 break;
311
Stefan Berger80fce2c2020-03-30 07:55:55 -0400312 if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
313 sel = nsel;
314 continue;
315 }
316
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400317 int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
318 if (hsize < 0) {
319 dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
320 be16_to_cpu(sel->hashAlg));
321 return -1;
322 }
323
324 int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
325 , digestSizes[count+1]);
Stefan Bergeradaf9882020-03-30 07:55:56 -0400326 if (event_size > sizeof(event) - sizeof(u8)) {
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400327 dprintf(DEBUG_tcg, "EfiSpecIdEventStruct pad too small\n");
328 return -1;
329 }
330
Stefan Berger80fce2c2020-03-30 07:55:55 -0400331 event.hdr.digestSizes[numAlgs].algorithmId = be16_to_cpu(sel->hashAlg);
332 event.hdr.digestSizes[numAlgs].digestSize = hsize;
333 numAlgs++;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400334
335 sel = nsel;
336 }
337
338 if (sel != end) {
339 dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
340 return -1;
341 }
342
Stefan Berger80fce2c2020-03-30 07:55:55 -0400343 event.hdr.numberOfAlgorithms = numAlgs;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400344 int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
Stefan Berger80fce2c2020-03-30 07:55:55 -0400345 , digestSizes[numAlgs]);
Stefan Bergeradaf9882020-03-30 07:55:56 -0400346 u8 *vendorInfoSize = (void*)&event + event_size;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400347 *vendorInfoSize = 0;
348 event_size += sizeof(*vendorInfoSize);
349
350 struct tpm_log_entry le = {
351 .hdr.eventtype = EV_NO_ACTION,
352 };
353 return tpm_log_event(&le.hdr, SHA1_BUFSIZE, &event, event_size);
354}
355
Stefan Bergera99de5c2016-08-05 11:07:11 -0400356/*
357 * Build the TPM2 tpm2_digest_values data structure from the given hash.
358 * Follow the PCR bank configuration of the TPM and write the same hash
359 * in either truncated or zero-padded form in the areas of all the other
360 * hashes. For example, write the sha1 hash in the area of the sha256
361 * hash and fill the remaining bytes with zeros. Or truncate the sha256
362 * hash when writing it in the area of the sha1 hash.
363 *
364 * le: the log entry to build the digest in
Stefan Berger1be65c52021-06-14 13:35:49 -0400365 * hashdata: the data to hash
366 * hashdata_len: the length of the hashdata
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500367 * bigEndian: whether to build in big endian format for the TPM or
368 * little endian for the log
Stefan Bergera99de5c2016-08-05 11:07:11 -0400369 *
370 * Returns the digest size; -1 on fatal error
371 */
372static int
Stefan Berger1be65c52021-06-14 13:35:49 -0400373tpm20_build_digest(struct tpm_log_entry *le,
374 const u8 *hashdata, u32 hashdata_len, int bigEndian)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400375{
376 if (!tpm20_pcr_selection)
377 return -1;
378
379 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
380 void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
381 void *dest = le->hdr.digest + sizeof(struct tpm2_digest_values);
382
Stefan Berger80fce2c2020-03-30 07:55:55 -0400383 u32 count, numAlgs = 0;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400384 for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
385 u8 sizeOfSelect = sel->sizeOfSelect;
386
387 nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
388 if (nsel > end)
389 break;
390
Stefan Berger80fce2c2020-03-30 07:55:55 -0400391 /* PCR 0-7 unused? -- skip */
392 if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
393 sel = nsel;
394 continue;
395 }
396
Stefan Bergera99de5c2016-08-05 11:07:11 -0400397 int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
398 if (hsize < 0) {
399 dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
400 be16_to_cpu(sel->hashAlg));
401 return -1;
402 }
403
404 /* buffer size sanity check before writing */
405 struct tpm2_digest_value *v = dest;
406 if (dest + sizeof(*v) + hsize > (void*)le + sizeof(*le)) {
407 dprintf(DEBUG_tcg, "tpm_log_entry is too small\n");
408 return -1;
409 }
410
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500411 if (bigEndian)
412 v->hashAlg = sel->hashAlg;
413 else
414 v->hashAlg = be16_to_cpu(sel->hashAlg);
415
Stefan Berger1be65c52021-06-14 13:35:49 -0400416 tpm2_hash_data(be16_to_cpu(sel->hashAlg), hashdata, hashdata_len,
417 v->hash);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400418
419 dest += sizeof(*v) + hsize;
420 sel = nsel;
Stefan Berger80fce2c2020-03-30 07:55:55 -0400421
422 numAlgs++;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400423 }
424
425 if (sel != end) {
426 dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
427 return -1;
428 }
429
430 struct tpm2_digest_values *v = (void*)le->hdr.digest;
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500431 if (bigEndian)
Stefan Berger80fce2c2020-03-30 07:55:55 -0400432 v->count = cpu_to_be32(numAlgs);
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500433 else
Stefan Berger80fce2c2020-03-30 07:55:55 -0400434 v->count = numAlgs;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400435
436 return dest - (void*)le->hdr.digest;
437}
438
439static int
Stefan Berger1be65c52021-06-14 13:35:49 -0400440tpm12_build_digest(struct tpm_log_entry *le,
441 const u8 *hashdata, u32 hashdata_len)
442{
443 sha1(hashdata, hashdata_len, le->hdr.digest);
444 return SHA1_BUFSIZE;
445}
446
447static int
448tpm12_build_digest_direct(struct tpm_log_entry *le, const u8 *sha1)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400449{
450 // On TPM 1.2 the digest contains just the SHA1 hash
451 memcpy(le->hdr.digest, sha1, SHA1_BUFSIZE);
452 return SHA1_BUFSIZE;
453}
454
455static int
Stefan Berger1be65c52021-06-14 13:35:49 -0400456tpm_build_digest(struct tpm_log_entry *le, const u8 *hashdata, u32 hashdata_len
457 , int bigEndian)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400458{
459 switch (TPM_version) {
460 case TPM_VERSION_1_2:
Stefan Berger1be65c52021-06-14 13:35:49 -0400461 return tpm12_build_digest(le, hashdata, hashdata_len);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400462 case TPM_VERSION_2:
Stefan Berger1be65c52021-06-14 13:35:49 -0400463 return tpm20_build_digest(le, hashdata, hashdata_len, bigEndian);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400464 }
465 return -1;
466}
467
Kevin O'Connor01669932016-08-10 16:15:43 -0400468
469/****************************************************************
470 * TPM hardware command wrappers
471 ****************************************************************/
472
Kevin O'Connor846fd312016-08-10 18:15:13 -0400473// Helper function for sending tpm commands that take a single
474// optional parameter (0, 1, or 2 bytes) and have no special response.
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500475static int
Kevin O'Connor846fd312016-08-10 18:15:13 -0400476tpm_simple_cmd(u8 locty, u32 ordinal
477 , int param_size, u16 param, enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400478{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500479 struct {
480 struct tpm_req_header trqh;
Kevin O'Connor846fd312016-08-10 18:15:13 -0400481 u16 param;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500482 } PACKED req = {
Kevin O'Connor846fd312016-08-10 18:15:13 -0400483 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500484 .trqh.ordinal = cpu_to_be32(ordinal),
Kevin O'Connor846fd312016-08-10 18:15:13 -0400485 .param = param_size == 2 ? cpu_to_be16(param) : param,
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500486 };
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500487 switch (TPM_version) {
488 case TPM_VERSION_1_2:
489 req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
490 break;
491 case TPM_VERSION_2:
492 req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
493 break;
494 }
495
Stefan Bergerece25612015-11-12 10:14:46 -0500496 u8 obuffer[64];
Kevin O'Connor846fd312016-08-10 18:15:13 -0400497 struct tpm_rsp_header *trsh = (void*)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400498 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400499 memset(obuffer, 0x0, sizeof(obuffer));
500
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500501 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
502 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connor846fd312016-08-10 18:15:13 -0400503 dprintf(DEBUG_tcg, "Return from tpm_simple_cmd(%x, %x) = %x\n",
504 ordinal, param, ret);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500505 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400506}
507
Stefan Bergere444dce2016-02-02 13:09:17 -0500508static int
Stefan Berger74544fa2016-08-05 11:07:08 -0400509tpm20_getcapability(u32 capability, u32 property, u32 count,
510 struct tpm_rsp_header *rsp, u32 rsize)
511{
512 struct tpm2_req_getcapability trg = {
513 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
514 .hdr.totlen = cpu_to_be32(sizeof(trg)),
515 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
516 .capability = cpu_to_be32(capability),
517 .property = cpu_to_be32(property),
518 .propertycount = cpu_to_be32(count),
519 };
520
521 u32 resp_size = rsize;
522 int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size,
523 TPM_DURATION_TYPE_SHORT);
524 ret = (ret ||
525 rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode);
526
527 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
528 ret);
529
530 return ret;
531}
532
533static int
534tpm20_get_pcrbanks(void)
535{
536 u8 buffer[128];
537 struct tpm2_res_getcapability *trg =
538 (struct tpm2_res_getcapability *)&buffer;
539
540 int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
541 sizeof(buffer));
542 if (ret)
543 return ret;
544
Stefan Berger05944862019-11-06 16:36:00 -0500545 /* defend against (broken) TPM sending packets that are too short */
546 u32 resplen = be32_to_cpu(trg->hdr.totlen);
547 if (resplen <= offsetof(struct tpm2_res_getcapability, data))
548 return -1;
549
550 u32 size = resplen - offsetof(struct tpm2_res_getcapability, data);
551 /* we need a valid tpml_pcr_selection up to and including sizeOfSelect */
552 if (size < offsetof(struct tpml_pcr_selection, selections) +
553 offsetof(struct tpms_pcr_selection, pcrSelect))
554 return -1;
555
Stefan Berger74544fa2016-08-05 11:07:08 -0400556 tpm20_pcr_selection = malloc_high(size);
557 if (tpm20_pcr_selection) {
558 memcpy(tpm20_pcr_selection, &trg->data, size);
559 tpm20_pcr_selection_size = size;
560 } else {
561 warn_noalloc();
562 ret = -1;
563 }
564
565 return ret;
566}
567
568static int
Stefan Berger171fc892019-01-30 14:06:07 -0500569tpm20_get_suppt_pcrbanks(u8 *suppt_pcrbanks, u8 *active_pcrbanks)
570{
571 *suppt_pcrbanks = 0;
572 *active_pcrbanks = 0;
573
574 if (!tpm20_pcr_selection)
575 return -1;
576
577 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
578 void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
579
580 while (1) {
581 u8 sizeOfSelect = sel->sizeOfSelect;
582 void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
583 if (nsel > end)
584 return 0;
585
586 u16 hashalg = be16_to_cpu(sel->hashAlg);
587 u8 hashalg_flag = tpm20_hashalg_to_flag(hashalg);
588
589 *suppt_pcrbanks |= hashalg_flag;
590
591 unsigned i;
592 for (i = 0; i < sizeOfSelect; i++) {
593 if (sel->pcrSelect[i]) {
594 *active_pcrbanks |= hashalg_flag;
595 break;
596 }
597 }
598
599 sel = nsel;
600 }
601}
602
603static int
604tpm20_set_pcrbanks(u32 active_banks)
605{
606 struct tpm2_req_pcr_allocate trpa = {
607 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
608 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate),
609 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
610 .authblocksize = cpu_to_be32(sizeof(trpa.authblock)),
611 .authblock = {
612 .handle = cpu_to_be32(TPM2_RS_PW),
613 .noncesize = cpu_to_be16(0),
614 .contsession = TPM2_YES,
615 .pwdsize = cpu_to_be16(0),
616 },
617 };
618 struct tpms_pcr_selection3 {
619 u16 hashAlg;
620 u8 sizeOfSelect;
621 u8 pcrSelect[3];
622 } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)];
623 int i = 0;
624 u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
625 u8 dontcare, suppt_banks;
626
627 tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare);
628
629 while (hashalg_flag) {
630 if ((hashalg_flag & suppt_banks)) {
631 u16 hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag);
632
633 if (hashalg) {
634 u8 mask = 0;
635 tps[i].hashAlg = cpu_to_be16(hashalg);
636 tps[i].sizeOfSelect = 3;
637
638 if (active_banks & hashalg_flag)
639 mask = 0xff;
640
641 tps[i].pcrSelect[0] = mask;
642 tps[i].pcrSelect[1] = mask;
643 tps[i].pcrSelect[2] = mask;
644 i++;
645 }
646 }
647 hashalg_flag <<= 1;
648 }
649
650 trpa.count = cpu_to_be32(i);
651 memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0]));
652 trpa.hdr.totlen = cpu_to_be32(offsetof(struct tpm2_req_pcr_allocate,
653 tpms_pcr_selections) +
654 i * sizeof(tps[0]));
655
656 struct tpm_rsp_header rsp;
657 u32 resp_length = sizeof(rsp);
658
659 int ret = tpmhw_transmit(0, &trpa.hdr, &rsp, &resp_length,
660 TPM_DURATION_TYPE_SHORT);
661 ret = ret ? -1 : be32_to_cpu(rsp.errcode);
662
663 return ret;
664}
665
666static int tpm20_activate_pcrbanks(u32 active_banks)
667{
668 int ret = tpm20_set_pcrbanks(active_banks);
669 if (!ret)
670 ret = tpm_simple_cmd(0, TPM2_CC_Shutdown,
671 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
672 if (!ret)
673 reset();
674 return ret;
675}
676
677static int
Kevin O'Connor01669932016-08-10 16:15:43 -0400678tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
679{
680 struct tpm_req_getcap trgc = {
681 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
682 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
683 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
684 .capArea = cpu_to_be32(cap),
685 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
686 .subCap = cpu_to_be32(subcap)
687 };
688 u32 resp_size = rsize;
689 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
690 TPM_DURATION_TYPE_SHORT);
691 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
692 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
693 " = %x\n", cap, subcap, ret);
694 return ret;
695}
696
697static int
698tpm12_read_permanent_flags(char *buf, int buf_len)
699{
700 memset(buf, 0, buf_len);
701
702 struct tpm_res_getcap_perm_flags pf;
703 int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
704 , &pf.hdr, sizeof(pf));
705 if (ret)
706 return -1;
707
708 memcpy(buf, &pf.perm_flags, buf_len);
709
710 return 0;
711}
712
713static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500714tpm12_determine_timeouts(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400715{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400716 struct tpm_res_getcap_timeouts timeouts;
Stefan Berger1d37d522016-02-02 13:09:11 -0500717 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
718 , &timeouts.hdr, sizeof(timeouts));
Kevin O'Connorca606362015-12-29 14:21:29 -0500719 if (ret)
720 return ret;
721
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400722 struct tpm_res_getcap_durations durations;
Stefan Berger1d37d522016-02-02 13:09:11 -0500723 ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
724 , &durations.hdr, sizeof(durations));
Kevin O'Connorca606362015-12-29 14:21:29 -0500725 if (ret)
726 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400727
Kevin O'Connorca606362015-12-29 14:21:29 -0500728 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400729 for (i = 0; i < 3; i++)
730 durations.durations[i] = be32_to_cpu(durations.durations[i]);
731
732 for (i = 0; i < 4; i++)
733 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
734
735 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
736 timeouts.timeouts[0],
737 timeouts.timeouts[1],
738 timeouts.timeouts[2],
739 timeouts.timeouts[3]);
740
741 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
742 durations.durations[0],
743 durations.durations[1],
744 durations.durations[2]);
745
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500746 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400747
748 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400749}
750
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500751static void
752tpm20_set_timeouts(void)
753{
754 u32 durations[3] = {
755 TPM2_DEFAULT_DURATION_SHORT,
756 TPM2_DEFAULT_DURATION_MEDIUM,
757 TPM2_DEFAULT_DURATION_LONG,
758 };
759 u32 timeouts[4] = {
760 TIS2_DEFAULT_TIMEOUT_A,
761 TIS2_DEFAULT_TIMEOUT_B,
762 TIS2_DEFAULT_TIMEOUT_C,
763 TIS2_DEFAULT_TIMEOUT_D,
764 };
765
766 tpmhw_set_timeouts(timeouts, durations);
767}
768
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500769static int
Stefan Bergera99de5c2016-08-05 11:07:11 -0400770tpm12_extend(struct tpm_log_entry *le, int digest_len)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500771{
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500772 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500773 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
774 .hdr.totlen = cpu_to_be32(sizeof(tre)),
775 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400776 .pcrindex = cpu_to_be32(le->hdr.pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500777 };
Stefan Bergera99de5c2016-08-05 11:07:11 -0400778 memcpy(tre.digest, le->hdr.digest, sizeof(tre.digest));
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500779
780 struct tpm_rsp_extend rsp;
781 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500782 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
783 TPM_DURATION_TYPE_SHORT);
784 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500785 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500786
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500787 return 0;
788}
789
Stefan Bergera99de5c2016-08-05 11:07:11 -0400790static int tpm20_extend(struct tpm_log_entry *le, int digest_len)
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500791{
Stefan Berger0fb23c32016-08-05 11:07:09 -0400792 struct tpm2_req_extend tmp_tre = {
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500793 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400794 .hdr.totlen = cpu_to_be32(0),
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500795 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400796 .pcrindex = cpu_to_be32(le->hdr.pcrindex),
Stefan Berger0fb23c32016-08-05 11:07:09 -0400797 .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500798 .authblock = {
799 .handle = cpu_to_be32(TPM2_RS_PW),
800 .noncesize = cpu_to_be16(0),
801 .contsession = TPM2_YES,
802 .pwdsize = cpu_to_be16(0),
803 },
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500804 };
Stefan Bergera99de5c2016-08-05 11:07:11 -0400805 u8 buffer[sizeof(tmp_tre) + sizeof(le->pad)];
Stefan Berger0fb23c32016-08-05 11:07:09 -0400806 struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;
807
808 memcpy(tre, &tmp_tre, sizeof(tmp_tre));
Stefan Bergera99de5c2016-08-05 11:07:11 -0400809 memcpy(&tre->digest[0], le->hdr.digest, digest_len);
810
811 tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len);
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500812
813 struct tpm_rsp_header rsp;
814 u32 resp_length = sizeof(rsp);
Stefan Berger0fb23c32016-08-05 11:07:09 -0400815 int ret = tpmhw_transmit(0, &tre->hdr, &rsp, &resp_length,
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500816 TPM_DURATION_TYPE_SHORT);
817 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
818 return -1;
819
820 return 0;
821}
822
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500823static int
Stefan Bergera99de5c2016-08-05 11:07:11 -0400824tpm_extend(struct tpm_log_entry *le, int digest_len)
Stefan Berger1d37d522016-02-02 13:09:11 -0500825{
Stefan Berger1d37d522016-02-02 13:09:11 -0500826 switch (TPM_version) {
827 case TPM_VERSION_1_2:
Stefan Bergera99de5c2016-08-05 11:07:11 -0400828 return tpm12_extend(le, digest_len);
Stefan Berger1d37d522016-02-02 13:09:11 -0500829 case TPM_VERSION_2:
Stefan Bergera99de5c2016-08-05 11:07:11 -0400830 return tpm20_extend(le, digest_len);
Stefan Berger1d37d522016-02-02 13:09:11 -0500831 }
832 return -1;
833}
834
Kevin O'Connor01669932016-08-10 16:15:43 -0400835static int
836tpm20_stirrandom(void)
837{
Kevin O'Connor538d9b72016-08-10 17:45:05 -0400838 struct tpm2_req_stirrandom stir = {
839 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
840 .hdr.totlen = cpu_to_be32(sizeof(stir)),
841 .hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom),
Kevin O'Connor01669932016-08-10 16:15:43 -0400842 .size = cpu_to_be16(sizeof(stir.stir)),
843 .stir = rdtscll(),
844 };
845 /* set more bits to stir with */
846 stir.stir += swab64(rdtscll());
847
Kevin O'Connor538d9b72016-08-10 17:45:05 -0400848 struct tpm_rsp_header rsp;
849 u32 resp_length = sizeof(rsp);
850 int ret = tpmhw_transmit(0, &stir.hdr, &rsp, &resp_length,
851 TPM_DURATION_TYPE_SHORT);
852 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
853 ret = -1;
Kevin O'Connor01669932016-08-10 16:15:43 -0400854
855 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
856 ret);
857
858 return ret;
859}
860
861static int
862tpm20_getrandom(u8 *buf, u16 buf_len)
863{
864 struct tpm2_res_getrandom rsp;
865
866 if (buf_len > sizeof(rsp.rnd.buffer))
867 return -1;
868
869 struct tpm2_req_getrandom trgr = {
870 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
871 .hdr.totlen = cpu_to_be32(sizeof(trgr)),
872 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
873 .bytesRequested = cpu_to_be16(buf_len),
874 };
875 u32 resp_length = sizeof(rsp);
876
877 int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
878 TPM_DURATION_TYPE_MEDIUM);
879 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
880 ret = -1;
881 else
882 memcpy(buf, rsp.rnd.buffer, buf_len);
883
884 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
885 ret);
886
887 return ret;
888}
889
890static int
891tpm20_hierarchycontrol(u32 hierarchy, u8 state)
892{
893 /* we will try to deactivate the TPM now - ignoring all errors */
894 struct tpm2_req_hierarchycontrol trh = {
895 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
896 .hdr.totlen = cpu_to_be32(sizeof(trh)),
897 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
898 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
899 .authblocksize = cpu_to_be32(sizeof(trh.authblock)),
900 .authblock = {
901 .handle = cpu_to_be32(TPM2_RS_PW),
902 .noncesize = cpu_to_be16(0),
903 .contsession = TPM2_YES,
904 .pwdsize = cpu_to_be16(0),
905 },
906 .enable = cpu_to_be32(hierarchy),
907 .state = state,
908 };
909 struct tpm_rsp_header rsp;
910 u32 resp_length = sizeof(rsp);
911 int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
912 TPM_DURATION_TYPE_MEDIUM);
913 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
914 ret = -1;
915
916 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
917 ret);
918
919 return ret;
920}
921
922static int
923tpm20_hierarchychangeauth(u8 auth[20])
924{
925 struct tpm2_req_hierarchychangeauth trhca = {
926 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
927 .hdr.totlen = cpu_to_be32(sizeof(trhca)),
928 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
929 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
930 .authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
931 .authblock = {
932 .handle = cpu_to_be32(TPM2_RS_PW),
933 .noncesize = cpu_to_be16(0),
934 .contsession = TPM2_YES,
935 .pwdsize = cpu_to_be16(0),
936 },
937 .newAuth = {
938 .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
939 },
940 };
941 memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
942
943 struct tpm_rsp_header rsp;
944 u32 resp_length = sizeof(rsp);
945 int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
946 TPM_DURATION_TYPE_MEDIUM);
947 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
948 ret = -1;
949
950 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
951 ret);
952
953 return ret;
954}
955
956
957/****************************************************************
958 * Setup and Measurements
959 ****************************************************************/
960
961static int TPM_has_physical_presence;
962u8 TPM_working VARLOW;
963
964static int
965tpm_is_working(void)
966{
967 return CONFIG_TCGBIOS && TPM_working;
968}
969
970static void
971tpm_set_failure(void)
972{
973 switch (TPM_version) {
974 case TPM_VERSION_1_2:
975 /*
976 * We will try to deactivate the TPM now - ignoring all errors
977 * Physical presence is asserted.
978 */
979
Kevin O'Connor846fd312016-08-10 18:15:13 -0400980 tpm_simple_cmd(0, TPM_ORD_SetTempDeactivated,
981 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connor01669932016-08-10 16:15:43 -0400982 break;
983 case TPM_VERSION_2:
984 tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
985 tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
986 break;
987 }
988
989 TPM_working = 0;
990}
991
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500992/*
993 * Add a measurement to the log; the data at data_seg:data/length are
994 * appended to the TCG_PCClientPCREventStruct
995 *
996 * Input parameters:
997 * pcrindex : which PCR to extend
998 * event_type : type of event; specs section on 'Event Types'
999 * event : pointer to info (e.g., string) to be added to log as-is
1000 * event_length: length of the event
1001 * hashdata : pointer to the data to be hashed
1002 * hashdata_length: length of the data to be hashed
1003 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001004static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001005tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
1006 const char *event, u32 event_length,
1007 const u8 *hashdata, u32 hashdata_length)
1008{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -05001009 if (!tpm_is_working())
1010 return;
1011
Stefan Bergera99de5c2016-08-05 11:07:11 -04001012 struct tpm_log_entry le = {
1013 .hdr.pcrindex = pcrindex,
1014 .hdr.eventtype = event_type,
1015 };
Stefan Berger1be65c52021-06-14 13:35:49 -04001016 int digest_len = tpm_build_digest(&le, hashdata, hashdata_length, 1);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001017 if (digest_len < 0)
1018 return;
1019 int ret = tpm_extend(&le, digest_len);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001020 if (ret) {
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -05001021 tpm_set_failure();
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001022 return;
1023 }
Stefan Berger1be65c52021-06-14 13:35:49 -04001024 tpm_build_digest(&le, hashdata, hashdata_length, 0);
Kevin O'Connor19e8ea62016-08-09 13:24:51 -04001025 tpm_log_event(&le.hdr, digest_len, event, event_length);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001026}
1027
Kevin O'Connora6175422015-11-22 11:28:14 -05001028// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001029static void
Kevin O'Connora6175422015-11-22 11:28:14 -05001030tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001031{
Kevin O'Connora6175422015-11-22 11:28:14 -05001032 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001033 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
1034 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001035}
1036
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001037/*
1038 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1039 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001040static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001041tpm_add_event_separators(void)
1042{
Kevin O'Connora6175422015-11-22 11:28:14 -05001043 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001044 u32 pcrIndex;
1045 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
1046 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
Stefan Bergerba949f52021-06-09 13:31:59 -04001047 (const char *)evt_separator,
1048 sizeof(evt_separator),
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001049 evt_separator,
1050 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001051}
1052
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001053static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001054tpm_smbios_measure(void)
1055{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001056 struct pcctes pcctes = {
1057 .eventid = 1,
1058 .eventdatasize = SHA1_BUFSIZE,
1059 };
1060 struct smbios_entry_point *sep = SMBiosAddr;
1061
1062 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1063
1064 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001065 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001066
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001067 sha1((const u8 *)sep->structure_table_address,
1068 sep->structure_table_length, pcctes.digest);
1069 tpm_add_measurement_to_log(1,
1070 EV_EVENT_TAG,
1071 (const char *)&pcctes, sizeof(pcctes),
1072 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001073}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001074
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001075static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001076tpm12_assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -05001077{
Kevin O'Connor846fd312016-08-10 18:15:13 -04001078 int ret = tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1079 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -05001080 if (!ret)
1081 return 0;
1082
1083 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001084 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -05001085 if (ret)
1086 return -1;
1087
Stefan Bergera2206d32016-01-07 12:02:48 -05001088 /* check if hardware physical presence is supported */
1089 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
1090 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -05001091 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -05001092 }
1093
Stefan Bergera2206d32016-01-07 12:02:48 -05001094 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
1095 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
Kevin O'Connor846fd312016-08-10 18:15:13 -04001096 tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1097 2, TPM_PP_CMD_ENABLE, TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -05001098
Kevin O'Connor846fd312016-08-10 18:15:13 -04001099 return tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1100 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -05001101 }
Stefan Bergere55e37f2016-01-07 12:02:47 -05001102 return -1;
1103}
1104
1105static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001106tpm12_startup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001107{
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001108 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Kevin O'Connor846fd312016-08-10 18:15:13 -04001109 int ret = tpm_simple_cmd(0, TPM_ORD_Startup,
1110 2, TPM_ST_CLEAR, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001111 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001112 /* with other firmware on the system the TPM may already have been
1113 * initialized
1114 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001115 ret = 0;
1116 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001117 goto err_exit;
1118
Stefan Berger115d0082016-01-07 12:02:49 -05001119 /* assertion of physical presence is only possible after startup */
Stefan Berger1d37d522016-02-02 13:09:11 -05001120 ret = tpm12_assert_physical_presence();
Stefan Berger115d0082016-01-07 12:02:49 -05001121 if (!ret)
1122 TPM_has_physical_presence = 1;
1123
Stefan Berger1d37d522016-02-02 13:09:11 -05001124 ret = tpm12_determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -05001125 if (ret)
Kevin O'Connord468d592016-08-10 16:23:02 -04001126 goto err_exit;
Stefan Bergerec42c8d2015-11-21 14:54:41 -05001127
Kevin O'Connor846fd312016-08-10 18:15:13 -04001128 ret = tpm_simple_cmd(0, TPM_ORD_SelfTestFull,
1129 0, 0, TPM_DURATION_TYPE_LONG);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001130 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001131 goto err_exit;
1132
Kevin O'Connor846fd312016-08-10 18:15:13 -04001133 ret = tpm_simple_cmd(3, TSC_ORD_ResetEstablishmentBit,
1134 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001135 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001136 goto err_exit;
1137
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001138 return 0;
1139
1140err_exit:
1141 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1142
Stefan Berger7fce1d92015-11-12 10:14:45 -05001143 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001144 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001145}
1146
Stefan Berger1d37d522016-02-02 13:09:11 -05001147static int
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001148tpm20_startup(void)
1149{
Stefan Berger0c4ad1e2016-02-02 13:09:13 -05001150 tpm20_set_timeouts();
1151
Kevin O'Connor846fd312016-08-10 18:15:13 -04001152 int ret = tpm_simple_cmd(0, TPM2_CC_Startup,
1153 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001154
1155 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
1156 ret);
1157
1158 if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
1159 /* with other firmware on the system the TPM may already have been
1160 * initialized
1161 */
1162 ret = 0;
1163
1164 if (ret)
1165 goto err_exit;
1166
Kevin O'Connor846fd312016-08-10 18:15:13 -04001167 ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
1168 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001169
1170 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
1171 ret);
1172
1173 if (ret)
1174 goto err_exit;
1175
Stefan Berger74544fa2016-08-05 11:07:08 -04001176 ret = tpm20_get_pcrbanks();
1177 if (ret)
1178 goto err_exit;
1179
Kevin O'Connor19e8ea62016-08-09 13:24:51 -04001180 ret = tpm20_write_EfiSpecIdEventStruct();
1181 if (ret)
1182 goto err_exit;
1183
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001184 return 0;
1185
1186err_exit:
1187 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1188
1189 tpm_set_failure();
1190 return -1;
1191}
1192
1193static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001194tpm_startup(void)
1195{
1196 switch (TPM_version) {
1197 case TPM_VERSION_1_2:
1198 return tpm12_startup();
1199 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001200 return tpm20_startup();
Stefan Berger1d37d522016-02-02 13:09:11 -05001201 }
1202 return -1;
1203}
1204
Kevin O'Connord6aca442015-06-10 11:00:17 -04001205void
1206tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001207{
1208 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001209 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001210
Stephen Douthit42efebd2018-03-07 13:17:36 -05001211 int ret = tpm_tpm2_probe();
1212 if (ret) {
1213 ret = tpm_tcpa_probe();
1214 if (ret)
1215 return;
1216 }
1217
Stefan Bergerefc49cf2016-02-02 13:09:09 -05001218 TPM_version = tpmhw_probe();
1219 if (TPM_version == TPM_VERSION_NONE)
Kevin O'Connor27065322015-11-28 14:25:41 -05001220 return;
1221
Stefan Bergerefc49cf2016-02-02 13:09:09 -05001222 dprintf(DEBUG_tcg,
1223 "TCGBIOS: Detected a TPM %s.\n",
1224 (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
1225
Kevin O'Connor27065322015-11-28 14:25:41 -05001226 TPM_working = 1;
1227
Quan Xu67643952015-04-30 19:43:04 -04001228 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001229 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001230
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001231 ret = tpm_startup();
1232 if (ret)
1233 return;
1234
1235 tpm_smbios_measure();
1236 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001237}
1238
Stefan Bergerd766c1a2016-02-02 13:09:14 -05001239static void
1240tpm20_prepboot(void)
1241{
1242 int ret = tpm20_stirrandom();
1243 if (ret)
1244 goto err_exit;
1245
1246 u8 auth[20];
1247 ret = tpm20_getrandom(&auth[0], sizeof(auth));
1248 if (ret)
1249 goto err_exit;
1250
1251 ret = tpm20_hierarchychangeauth(auth);
1252 if (ret)
1253 goto err_exit;
1254
1255 return;
1256
1257err_exit:
1258 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1259
1260 tpm_set_failure();
1261}
1262
Kevin O'Connord6aca442015-06-10 11:00:17 -04001263void
1264tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001265{
Stefan Berger8b902b82016-01-07 12:02:50 -05001266 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001267 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001268
Stefan Berger1d37d522016-02-02 13:09:11 -05001269 switch (TPM_version) {
1270 case TPM_VERSION_1_2:
1271 if (TPM_has_physical_presence)
Kevin O'Connor846fd312016-08-10 18:15:13 -04001272 tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1273 2, TPM_PP_NOT_PRESENT_LOCK, TPM_DURATION_TYPE_SHORT);
Stefan Berger1d37d522016-02-02 13:09:11 -05001274 break;
1275 case TPM_VERSION_2:
Stefan Bergerd766c1a2016-02-02 13:09:14 -05001276 tpm20_prepboot();
Stefan Berger1d37d522016-02-02 13:09:11 -05001277 break;
1278 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001279
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001280 tpm_add_action(4, "Calling INT 19h");
1281 tpm_add_event_separators();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001282}
1283
Stefan Berger5aa2a752015-03-23 14:22:17 -04001284/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001285 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -04001286 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001287void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001288tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -04001289{
Kevin O'Connord559a232015-11-28 08:35:26 -05001290 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001291 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -05001292
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001293 struct pcctes_romex pcctes = {
1294 .eventid = 7,
1295 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -04001296 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001297 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001298 tpm_add_measurement_to_log(2,
1299 EV_EVENT_TAG,
1300 (const char *)&pcctes, sizeof(pcctes),
1301 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -05001302}
Stefan Berger5aa2a752015-03-23 14:22:17 -04001303
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001304void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001305tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1306{
Kevin O'Connord559a232015-11-28 08:35:26 -05001307 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001308 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001309
Stefan Berger4cdbc412015-11-30 11:14:18 -05001310 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001311 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -05001312
Kevin O'Connor8bd4a082015-11-19 17:43:27 -05001313 const char *string = "Booting BCV device 00h (Floppy)";
1314 if (bootdrv == 0x80)
1315 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001316 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001317
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001318 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1319 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -05001320 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001321 tpm_add_measurement_to_log(4, EV_IPL,
1322 string, strlen(string),
1323 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001324
1325 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1326 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001327 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1328 string, strlen(string),
1329 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001330}
1331
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001332void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001333tpm_add_cdrom(u32 bootdrv, const u8 *addr, u32 length)
1334{
Kevin O'Connord559a232015-11-28 08:35:26 -05001335 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001336 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001337
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001338 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001339
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001340 /* specs: see section 'El Torito' */
1341 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001342 tpm_add_measurement_to_log(4, EV_IPL,
1343 string, strlen(string),
1344 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001345}
1346
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001347void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001348tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1349{
Kevin O'Connord559a232015-11-28 08:35:26 -05001350 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001351 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001352
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001353 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001354
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001355 /* specs: see section 'El Torito' */
1356 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001357 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1358 string, strlen(string),
1359 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001360}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001361
Kevin O'Connord6aca442015-06-10 11:00:17 -04001362void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001363tpm_s3_resume(void)
1364{
Kevin O'Connord559a232015-11-28 08:35:26 -05001365 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001366 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001367
1368 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1369
Stefan Berger1d37d522016-02-02 13:09:11 -05001370 int ret = -1;
1371
1372 switch (TPM_version) {
1373 case TPM_VERSION_1_2:
Kevin O'Connor846fd312016-08-10 18:15:13 -04001374 ret = tpm_simple_cmd(0, TPM_ORD_Startup,
1375 2, TPM_ST_STATE, TPM_DURATION_TYPE_SHORT);
Stefan Berger1d37d522016-02-02 13:09:11 -05001376 break;
1377 case TPM_VERSION_2:
Kevin O'Connor846fd312016-08-10 18:15:13 -04001378 ret = tpm_simple_cmd(0, TPM2_CC_Startup,
1379 2, TPM2_SU_STATE, TPM_DURATION_TYPE_SHORT);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001380
1381 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
1382 ret);
1383
1384 if (ret)
1385 goto err_exit;
1386
1387
Kevin O'Connor846fd312016-08-10 18:15:13 -04001388 ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
1389 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001390
1391 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
1392 ret);
1393
Stefan Berger1d37d522016-02-02 13:09:11 -05001394 break;
1395 }
1396
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001397 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001398 goto err_exit;
1399
Kevin O'Connord6aca442015-06-10 11:00:17 -04001400 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001401
1402err_exit:
1403 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1404
Stefan Berger7fce1d92015-11-12 10:14:45 -05001405 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001406}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001407
1408
1409/****************************************************************
1410 * BIOS interface
1411 ****************************************************************/
1412
Kevin O'Connor59076132015-11-28 13:55:09 -05001413u8 TPM_interface_shutdown VARLOW;
1414
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001415static inline void *input_buf32(struct bregs *regs)
1416{
1417 return MAKE_FLATPTR(regs->es, regs->di);
1418}
1419
1420static inline void *output_buf32(struct bregs *regs)
1421{
1422 return MAKE_FLATPTR(regs->ds, regs->si);
1423}
1424
1425static u32
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001426hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
1427 , void *event, int extend)
1428{
1429 if (pcpes->pcrindex >= 24)
1430 return TCG_INVALID_INPUT_PARA;
1431 if (hashdata)
1432 sha1(hashdata, hashdata_length, pcpes->digest);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001433
1434 struct tpm_log_entry le = {
1435 .hdr.pcrindex = pcpes->pcrindex,
1436 .hdr.eventtype = pcpes->eventtype,
1437 };
Stefan Berger1be65c52021-06-14 13:35:49 -04001438 int digest_len = tpm12_build_digest_direct(&le, pcpes->digest);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001439 if (digest_len < 0)
1440 return TCG_GENERAL_ERROR;
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001441 if (extend) {
Stefan Bergera99de5c2016-08-05 11:07:11 -04001442 int ret = tpm_extend(&le, digest_len);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001443 if (ret)
1444 return TCG_TCG_COMMAND_ERROR;
1445 }
Stefan Berger1be65c52021-06-14 13:35:49 -04001446 tpm12_build_digest_direct(&le, pcpes->digest);
Kevin O'Connor19e8ea62016-08-09 13:24:51 -04001447 int ret = tpm_log_event(&le.hdr, digest_len
1448 , pcpes->event, pcpes->eventdatasize);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001449 if (ret)
1450 return TCG_PC_LOGOVERFLOW;
1451 return 0;
1452}
1453
1454static u32
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001455hash_log_extend_event_int(const struct hleei_short *hleei_s,
1456 struct hleeo *hleeo)
1457{
1458 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001459 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
1460 const void *logdataptr;
1461 u32 logdatalen;
1462 struct pcpes *pcpes;
1463 u32 pcrindex;
1464
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001465 /* short or long version? */
1466 switch (hleei_s->ipblength) {
1467 case sizeof(struct hleei_short):
1468 /* short */
1469 logdataptr = hleei_s->logdataptr;
1470 logdatalen = hleei_s->logdatalen;
1471 pcrindex = hleei_s->pcrindex;
1472 break;
1473
1474 case sizeof(struct hleei_long):
1475 /* long */
1476 logdataptr = hleei_l->logdataptr;
1477 logdatalen = hleei_l->logdatalen;
1478 pcrindex = hleei_l->pcrindex;
1479 break;
1480
1481 default:
1482 /* bad input block */
1483 rc = TCG_INVALID_INPUT_PARA;
1484 goto err_exit;
1485 }
1486
1487 pcpes = (struct pcpes *)logdataptr;
1488
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001489 if (pcpes->pcrindex != pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001490 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001491 rc = TCG_INVALID_INPUT_PARA;
1492 goto err_exit;
1493 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001494 rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
1495 , pcpes->event, 1);
1496 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001497 goto err_exit;
1498
1499 hleeo->opblength = sizeof(struct hleeo);
1500 hleeo->reserved = 0;
Kevin O'Connor1ef72ab2017-09-02 21:42:12 -04001501 hleeo->eventnumber = tpm_state.entry_count;
Stefan Berger2b237502016-01-07 12:02:46 -05001502 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001503
1504err_exit:
1505 if (rc != 0) {
1506 hleeo->opblength = 4;
1507 hleeo->reserved = 0;
1508 }
1509
1510 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001511}
1512
1513static u32
1514pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1515{
1516 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001517 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001518
Stefan Berger7092de32016-02-02 13:09:19 -05001519 if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001520 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
1521 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001522 rc = TCG_INVALID_INPUT_PARA;
1523 goto err_exit;
1524 }
1525
Stefan Berger7092de32016-02-02 13:09:19 -05001526 u16 tag = be16_to_cpu(trh->tag);
1527
1528 switch (TPM_version) {
1529 case TPM_VERSION_1_2:
1530 if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
1531 && tag != TPM_TAG_RQU_AUTH2_CMD) {
1532 rc = TCG_INVALID_INPUT_PARA;
1533 goto err_exit;
1534 }
1535 break;
1536 case TPM_VERSION_2:
1537 if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
1538 rc = TCG_INVALID_INPUT_PARA;
1539 goto err_exit;
1540 }
1541 }
1542
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001543 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001544 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
1545 TPM_DURATION_TYPE_LONG /* worst case */);
1546 if (ret) {
1547 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001548 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001549 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001550
1551 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1552 pttto->reserved = 0;
1553
1554err_exit:
1555 if (rc != 0) {
1556 pttto->opblength = 4;
1557 pttto->reserved = 0;
1558 }
1559
1560 return rc;
1561}
1562
1563static u32
1564shutdown_preboot_interface(void)
1565{
Kevin O'Connor59076132015-11-28 13:55:09 -05001566 TPM_interface_shutdown = 1;
1567 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001568}
1569
1570static u32
1571hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1572{
1573 u32 rc = 0;
1574 u16 size;
1575 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001576
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001577 size = hlei->ipblength;
1578 if (size != sizeof(*hlei)) {
1579 rc = TCG_INVALID_INPUT_PARA;
1580 goto err_exit;
1581 }
1582
1583 pcpes = (struct pcpes *)hlei->logdataptr;
1584
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001585 if (pcpes->pcrindex != hlei->pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001586 || pcpes->eventtype != hlei->logeventtype
1587 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001588 rc = TCG_INVALID_INPUT_PARA;
1589 goto err_exit;
1590 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001591 rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
1592 , pcpes->event, 0);
1593 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001594 goto err_exit;
1595
1596 /* updating the log was fine */
1597 hleo->opblength = sizeof(struct hleo);
1598 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001599 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001600
1601err_exit:
1602 if (rc != 0) {
1603 hleo->opblength = 2;
1604 hleo->reserved = 0;
1605 }
1606
1607 return rc;
1608}
1609
1610static u32
1611hash_all_int(const struct hai *hai, u8 *hash)
1612{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001613 if (hai->ipblength != sizeof(struct hai) ||
1614 hai->hashdataptr == 0 ||
1615 hai->hashdatalen == 0 ||
1616 hai->algorithmid != TPM_ALG_SHA)
1617 return TCG_INVALID_INPUT_PARA;
1618
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001619 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1620 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001621}
1622
1623static u32
1624tss_int(struct ti *ti, struct to *to)
1625{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001626 to->opblength = sizeof(struct to);
1627 to->reserved = 0;
1628
Kevin O'Connor59076132015-11-28 13:55:09 -05001629 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001630}
1631
1632static u32
1633compact_hash_log_extend_event_int(u8 *buffer,
1634 u32 info,
1635 u32 length,
1636 u32 pcrindex,
1637 u32 *edx_ptr)
1638{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001639 struct pcpes pcpes = {
1640 .pcrindex = pcrindex,
1641 .eventtype = EV_COMPACT_HASH,
1642 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001643 };
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001644 u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
1645 if (rc)
1646 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001647
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001648 *edx_ptr = tpm_state.entry_count;
1649 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001650}
1651
1652void VISIBLE32FLAT
1653tpm_interrupt_handler32(struct bregs *regs)
1654{
1655 if (!CONFIG_TCGBIOS)
1656 return;
1657
1658 set_cf(regs, 0);
1659
Kevin O'Connor59076132015-11-28 13:55:09 -05001660 if (TPM_interface_shutdown && regs->al) {
1661 regs->eax = TCG_INTERFACE_SHUTDOWN;
1662 return;
1663 }
1664
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001665 switch ((enum irq_ids)regs->al) {
1666 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -05001667 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001668 /* no TPM available */
1669 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1670 } else {
1671 regs->eax = 0;
1672 regs->ebx = TCG_MAGIC;
1673 regs->ch = TCG_VERSION_MAJOR;
1674 regs->cl = TCG_VERSION_MINOR;
1675 regs->edx = 0x0;
1676 regs->esi = (u32)tpm_state.log_area_start_address;
1677 regs->edi = (u32)tpm_state.log_area_last_entry;
1678 }
1679 break;
1680
1681 case TCG_HashLogExtendEvent:
1682 regs->eax =
1683 hash_log_extend_event_int(
1684 (struct hleei_short *)input_buf32(regs),
1685 (struct hleeo *)output_buf32(regs));
1686 break;
1687
1688 case TCG_PassThroughToTPM:
1689 regs->eax =
1690 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1691 (struct pttto *)output_buf32(regs));
1692 break;
1693
1694 case TCG_ShutdownPreBootInterface:
1695 regs->eax = shutdown_preboot_interface();
1696 break;
1697
1698 case TCG_HashLogEvent:
1699 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1700 (struct hleo*)output_buf32(regs));
1701 break;
1702
1703 case TCG_HashAll:
1704 regs->eax =
1705 hash_all_int((struct hai*)input_buf32(regs),
1706 (u8 *)output_buf32(regs));
1707 break;
1708
1709 case TCG_TSS:
1710 regs->eax = tss_int((struct ti*)input_buf32(regs),
1711 (struct to*)output_buf32(regs));
1712 break;
1713
1714 case TCG_CompactHashLogExtendEvent:
1715 regs->eax =
1716 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1717 regs->esi,
1718 regs->ecx,
1719 regs->edx,
1720 &regs->edx);
1721 break;
1722
1723 default:
1724 set_cf(regs, 1);
1725 }
1726
1727 return;
1728}
Stefan Berger320df852015-11-30 11:14:19 -05001729
Kevin O'Connor26e36172015-12-29 12:20:23 -05001730
1731/****************************************************************
1732 * TPM Configuration Menu
1733 ****************************************************************/
1734
Kevin O'Connor01669932016-08-10 16:15:43 -04001735typedef u8 tpm_ppi_code;
1736
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001737static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001738tpm12_read_has_owner(int *has_owner)
Stefan Berger320df852015-11-30 11:14:19 -05001739{
Stefan Berger320df852015-11-30 11:14:19 -05001740 struct tpm_res_getcap_ownerauth oauth;
Stefan Berger1d37d522016-02-02 13:09:11 -05001741 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1742 , &oauth.hdr, sizeof(oauth));
Kevin O'Connorca606362015-12-29 14:21:29 -05001743 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001744 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001745
1746 *has_owner = oauth.flag;
1747
1748 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001749}
1750
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001751static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001752tpm12_enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001753{
Stefan Berger320df852015-11-30 11:14:19 -05001754 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001755 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001756 if (ret)
1757 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001758
1759 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1760 return 0;
1761
Kevin O'Connor846fd312016-08-10 18:15:13 -04001762 ret = tpm_simple_cmd(0, enable ? TPM_ORD_PhysicalEnable
1763 : TPM_ORD_PhysicalDisable,
1764 0, 0, TPM_DURATION_TYPE_SHORT);
Stefan Berger44250252016-01-07 12:02:51 -05001765 if (ret) {
1766 if (enable)
1767 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1768 else
1769 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1770 }
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001771 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001772}
1773
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001774static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001775tpm12_activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001776{
Stefan Berger320df852015-11-30 11:14:19 -05001777 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001778 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001779 if (ret)
1780 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001781
1782 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1783 return 0;
1784
1785 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1786 return 0;
1787
Kevin O'Connor846fd312016-08-10 18:15:13 -04001788 ret = tpm_simple_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1789 1, activate ? 0x00 : 0x01, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001790 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001791 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001792
1793 if (activate && allow_reset) {
1794 if (verbose) {
1795 printf("Requiring a reboot to activate the TPM.\n");
1796
1797 msleep(2000);
1798 }
1799 reset();
1800 }
1801
1802 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001803}
1804
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001805static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001806tpm12_enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001807{
Stefan Berger1d37d522016-02-02 13:09:11 -05001808 int ret = tpm12_enable_tpm(1, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001809 if (ret)
1810 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001811
Stefan Berger1d37d522016-02-02 13:09:11 -05001812 return tpm12_activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001813}
1814
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001815static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001816tpm12_force_clear(int enable_activate_before, int enable_activate_after,
1817 int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001818{
Stefan Berger320df852015-11-30 11:14:19 -05001819 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001820 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001821 if (ret)
1822 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001823 if (!has_owner) {
1824 if (verbose)
1825 printf("TPM does not have an owner.\n");
1826 return 0;
1827 }
1828
1829 if (enable_activate_before) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001830 ret = tpm12_enable_activate(0, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001831 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001832 dprintf(DEBUG_tcg,
1833 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001834 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001835 }
1836 }
1837
Kevin O'Connor846fd312016-08-10 18:15:13 -04001838 ret = tpm_simple_cmd(0, TPM_ORD_ForceClear,
1839 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001840 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001841 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001842
1843 if (!enable_activate_after) {
1844 if (verbose)
1845 printf("Owner successfully cleared.\n"
1846 "You will need to enable/activate the TPM again.\n\n");
1847 return 0;
1848 }
1849
Stefan Berger1d37d522016-02-02 13:09:11 -05001850 return tpm12_enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001851}
1852
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001853static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001854tpm12_set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001855{
Stefan Berger320df852015-11-30 11:14:19 -05001856 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001857 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001858 if (ret)
1859 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001860 if (has_owner) {
1861 if (verbose)
1862 printf("Must first remove owner.\n");
1863 return 0;
1864 }
1865
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001866 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001867 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001868 if (ret)
1869 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001870
1871 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1872 if (verbose)
1873 printf("TPM must first be enable.\n");
1874 return 0;
1875 }
1876
Kevin O'Connor846fd312016-08-10 18:15:13 -04001877 ret = tpm_simple_cmd(0, TPM_ORD_SetOwnerInstall,
1878 1, allow ? 0x01 : 0x00, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001879 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001880 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001881
1882 if (verbose)
1883 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1884
1885 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001886}
1887
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001888static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001889tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001890{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001891 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001892
1893 switch (msgCode) {
1894 case TPM_PPI_OP_NOOP: /* no-op */
1895 break;
1896
1897 case TPM_PPI_OP_ENABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001898 ret = tpm12_enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001899 break;
1900
1901 case TPM_PPI_OP_DISABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001902 ret = tpm12_enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001903 break;
1904
1905 case TPM_PPI_OP_ACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001906 ret = tpm12_activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001907 break;
1908
1909 case TPM_PPI_OP_DEACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001910 ret = tpm12_activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001911 break;
1912
1913 case TPM_PPI_OP_CLEAR:
Stefan Berger1d37d522016-02-02 13:09:11 -05001914 ret = tpm12_force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001915 break;
1916
1917 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001918 ret = tpm12_set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001919 break;
1920
1921 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001922 ret = tpm12_set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001923 break;
1924
1925 default:
1926 break;
1927 }
1928
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001929 if (ret)
1930 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001931
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001932 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001933}
1934
1935static int
Stefan Berger7d596dc2016-02-02 13:09:16 -05001936tpm20_clearcontrol(u8 disable, int verbose)
1937{
1938 struct tpm2_req_clearcontrol trc = {
1939 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1940 .hdr.totlen = cpu_to_be32(sizeof(trc)),
1941 .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1942 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1943 .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1944 .authblock = {
1945 .handle = cpu_to_be32(TPM2_RS_PW),
1946 .noncesize = cpu_to_be16(0),
1947 .contsession = TPM2_YES,
1948 .pwdsize = cpu_to_be16(0),
1949 },
1950 .disable = disable,
1951 };
1952 struct tpm_rsp_header rsp;
1953 u32 resp_length = sizeof(rsp);
1954 int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
1955 TPM_DURATION_TYPE_SHORT);
1956 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1957 ret = -1;
1958
1959 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1960 ret);
1961
1962 return ret;
1963}
1964
1965static int
1966tpm20_clear(void)
1967{
1968 struct tpm2_req_clear trq = {
1969 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1970 .hdr.totlen = cpu_to_be32(sizeof(trq)),
1971 .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1972 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1973 .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1974 .authblock = {
1975 .handle = cpu_to_be32(TPM2_RS_PW),
1976 .noncesize = cpu_to_be16(0),
1977 .contsession = TPM2_YES,
1978 .pwdsize = cpu_to_be16(0),
1979 },
1980 };
1981 struct tpm_rsp_header rsp;
1982 u32 resp_length = sizeof(rsp);
1983 int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
1984 TPM_DURATION_TYPE_MEDIUM);
1985 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1986 ret = -1;
1987
1988 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1989 ret);
1990
1991 return ret;
1992}
1993
1994static int
1995tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
1996{
1997 int ret = 0;
1998
1999 switch (msgCode) {
2000 case TPM_PPI_OP_NOOP: /* no-op */
2001 break;
2002
2003 case TPM_PPI_OP_CLEAR:
2004 ret = tpm20_clearcontrol(0, verbose);
2005 if (!ret)
2006 ret = tpm20_clear();
2007 break;
2008 }
2009
2010 if (ret)
2011 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
2012
2013 return ret;
2014}
2015
2016static int
Stefan Berger1d37d522016-02-02 13:09:11 -05002017tpm12_get_tpm_state(void)
Stefan Berger320df852015-11-30 11:14:19 -05002018{
2019 int state = 0;
2020 struct tpm_permanent_flags pf;
2021 int has_owner;
2022
Stefan Berger1d37d522016-02-02 13:09:11 -05002023 if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
2024 tpm12_read_has_owner(&has_owner))
Stefan Berger320df852015-11-30 11:14:19 -05002025 return ~0;
2026
2027 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
2028 state |= TPM_STATE_ENABLED;
2029
2030 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
2031 state |= TPM_STATE_ACTIVE;
2032
2033 if (has_owner) {
2034 state |= TPM_STATE_OWNED;
2035 } else {
2036 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
2037 state |= TPM_STATE_OWNERINSTALL;
2038 }
2039
2040 return state;
2041}
2042
2043static void
Stefan Berger1d37d522016-02-02 13:09:11 -05002044tpm12_show_tpm_menu(int state, int next_scancodes[7])
Stefan Berger320df852015-11-30 11:14:19 -05002045{
2046 int i = 0;
2047
2048 printf("\nThe current state of the TPM is:\n");
2049
2050 if (state & TPM_STATE_ENABLED)
2051 printf(" Enabled");
2052 else
2053 printf(" Disabled");
2054
2055 if (state & TPM_STATE_ACTIVE)
2056 printf(" and active\n");
2057 else
2058 printf(" and deactivated\n");
2059
2060 if (state & TPM_STATE_OWNED)
2061 printf(" Ownership has been taken\n");
2062 else {
2063 printf(" Ownership has not been taken\n");
2064 if (state & TPM_STATE_OWNERINSTALL)
2065 printf(" A user can take ownership of the TPM\n");
2066 else
2067 printf(" Taking ownership of the TPM has been disabled\n