blob: a9d62c847405910cc6dac56e342cc4c4bafbbb21 [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 Bergerb7dbd202019-01-30 14:06:06 -0500170} hash_parameters[] = {
171 {
172 .hashalg = TPM2_ALG_SHA1,
Stefan Berger171fc892019-01-30 14:06:07 -0500173 .hashalg_flag = TPM2_ALG_SHA1_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500174 .hash_buffersize = SHA1_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500175 .name = "SHA1",
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500176 }, {
177 .hashalg = TPM2_ALG_SHA256,
Stefan Berger171fc892019-01-30 14:06:07 -0500178 .hashalg_flag = TPM2_ALG_SHA256_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500179 .hash_buffersize = SHA256_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500180 .name = "SHA256",
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500181 }, {
182 .hashalg = TPM2_ALG_SHA384,
Stefan Berger171fc892019-01-30 14:06:07 -0500183 .hashalg_flag = TPM2_ALG_SHA384_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500184 .hash_buffersize = SHA384_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500185 .name = "SHA384",
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500186 }, {
187 .hashalg = TPM2_ALG_SHA512,
Stefan Berger171fc892019-01-30 14:06:07 -0500188 .hashalg_flag = TPM2_ALG_SHA512_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500189 .hash_buffersize = SHA512_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500190 .name = "SHA512",
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500191 }, {
192 .hashalg = TPM2_ALG_SM3_256,
Stefan Berger171fc892019-01-30 14:06:07 -0500193 .hashalg_flag = TPM2_ALG_SM3_256_FLAG,
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500194 .hash_buffersize = SM3_256_BUFSIZE,
Stefan Berger171fc892019-01-30 14:06:07 -0500195 .name = "SM3-256",
Stefan Bergereaaf7262020-03-30 07:55:57 -0400196 }, {
197 .hashalg = TPM2_ALG_SHA3_256,
198 .hashalg_flag = TPM2_ALG_SHA3_256_FLAG,
199 .hash_buffersize = SHA3_256_BUFSIZE,
200 .name = "SHA3-256",
201 }, {
202 .hashalg = TPM2_ALG_SHA3_384,
203 .hashalg_flag = TPM2_ALG_SHA3_384_FLAG,
204 .hash_buffersize = SHA3_384_BUFSIZE,
205 .name = "SHA3-384",
206 }, {
207 .hashalg = TPM2_ALG_SHA3_512,
208 .hashalg_flag = TPM2_ALG_SHA3_512_FLAG,
209 .hash_buffersize = SHA3_512_BUFSIZE,
210 .name = "SHA3-512",
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500211 }
212};
213
Stefan Bergera99de5c2016-08-05 11:07:11 -0400214static int
215tpm20_get_hash_buffersize(u16 hashAlg)
216{
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500217 unsigned i;
218
219 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
220 if (hash_parameters[i].hashalg == hashAlg)
221 return hash_parameters[i].hash_buffersize;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400222 }
Stefan Bergerb7dbd202019-01-30 14:06:06 -0500223 return -1;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400224}
225
Stefan Berger171fc892019-01-30 14:06:07 -0500226static u8
227tpm20_hashalg_to_flag(u16 hashAlg)
228{
229 unsigned i;
230
231 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
232 if (hash_parameters[i].hashalg == hashAlg)
233 return hash_parameters[i].hashalg_flag;
234 }
235 return 0;
236}
237
238static u16
239tpm20_hashalg_flag_to_hashalg(u8 hashalg_flag)
240{
241 unsigned i;
242
243 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
244 if (hash_parameters[i].hashalg_flag == hashalg_flag)
245 return hash_parameters[i].hashalg;
246 }
247 return 0;
248}
249
250static const char *
251tpm20_hashalg_flag_to_name(u8 hashalg_flag)
252{
253 unsigned i;
254
255 for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
256 if (hash_parameters[i].hashalg_flag == hashalg_flag)
257 return hash_parameters[i].name;
258 }
259 return NULL;
260}
261
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400262// Add an entry at the start of the log describing digest formats
263static int
264tpm20_write_EfiSpecIdEventStruct(void)
265{
266 if (!tpm20_pcr_selection)
267 return -1;
268
269 struct {
270 struct TCG_EfiSpecIdEventStruct hdr;
Stefan Bergereaaf7262020-03-30 07:55:57 -0400271 u8 pad[sizeof(struct tpm_log_entry) + sizeof(u8)];
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400272 } event = {
273 .hdr.signature = "Spec ID Event03",
274 .hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
275 .hdr.specVersionMinor = 0,
276 .hdr.specVersionMajor = 2,
Stefan Bergerba949f52021-06-09 13:31:59 -0400277 .hdr.specErrata = 2,
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400278 .hdr.uintnSize = 2,
279 };
280
281 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
282 void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
283
Stefan Berger80fce2c2020-03-30 07:55:55 -0400284 u32 count, numAlgs = 0;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400285 for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
286 u8 sizeOfSelect = sel->sizeOfSelect;
287
288 nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
289 if (nsel > end)
290 break;
291
Stefan Berger80fce2c2020-03-30 07:55:55 -0400292 if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
293 sel = nsel;
294 continue;
295 }
296
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400297 int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
298 if (hsize < 0) {
299 dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
300 be16_to_cpu(sel->hashAlg));
301 return -1;
302 }
303
304 int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
305 , digestSizes[count+1]);
Stefan Bergeradaf9882020-03-30 07:55:56 -0400306 if (event_size > sizeof(event) - sizeof(u8)) {
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400307 dprintf(DEBUG_tcg, "EfiSpecIdEventStruct pad too small\n");
308 return -1;
309 }
310
Stefan Berger80fce2c2020-03-30 07:55:55 -0400311 event.hdr.digestSizes[numAlgs].algorithmId = be16_to_cpu(sel->hashAlg);
312 event.hdr.digestSizes[numAlgs].digestSize = hsize;
313 numAlgs++;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400314
315 sel = nsel;
316 }
317
318 if (sel != end) {
319 dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
320 return -1;
321 }
322
Stefan Berger80fce2c2020-03-30 07:55:55 -0400323 event.hdr.numberOfAlgorithms = numAlgs;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400324 int event_size = offsetof(struct TCG_EfiSpecIdEventStruct
Stefan Berger80fce2c2020-03-30 07:55:55 -0400325 , digestSizes[numAlgs]);
Stefan Bergeradaf9882020-03-30 07:55:56 -0400326 u8 *vendorInfoSize = (void*)&event + event_size;
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400327 *vendorInfoSize = 0;
328 event_size += sizeof(*vendorInfoSize);
329
330 struct tpm_log_entry le = {
331 .hdr.eventtype = EV_NO_ACTION,
332 };
333 return tpm_log_event(&le.hdr, SHA1_BUFSIZE, &event, event_size);
334}
335
Stefan Bergera99de5c2016-08-05 11:07:11 -0400336/*
337 * Build the TPM2 tpm2_digest_values data structure from the given hash.
338 * Follow the PCR bank configuration of the TPM and write the same hash
339 * in either truncated or zero-padded form in the areas of all the other
340 * hashes. For example, write the sha1 hash in the area of the sha256
341 * hash and fill the remaining bytes with zeros. Or truncate the sha256
342 * hash when writing it in the area of the sha1 hash.
343 *
344 * le: the log entry to build the digest in
345 * sha1: the sha1 hash value to use
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500346 * bigEndian: whether to build in big endian format for the TPM or
347 * little endian for the log
Stefan Bergera99de5c2016-08-05 11:07:11 -0400348 *
349 * Returns the digest size; -1 on fatal error
350 */
351static int
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500352tpm20_build_digest(struct tpm_log_entry *le, const u8 *sha1, int bigEndian)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400353{
354 if (!tpm20_pcr_selection)
355 return -1;
356
357 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
358 void *nsel, *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
359 void *dest = le->hdr.digest + sizeof(struct tpm2_digest_values);
360
Stefan Berger80fce2c2020-03-30 07:55:55 -0400361 u32 count, numAlgs = 0;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400362 for (count = 0; count < be32_to_cpu(tpm20_pcr_selection->count); count++) {
363 u8 sizeOfSelect = sel->sizeOfSelect;
364
365 nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
366 if (nsel > end)
367 break;
368
Stefan Berger80fce2c2020-03-30 07:55:55 -0400369 /* PCR 0-7 unused? -- skip */
370 if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
371 sel = nsel;
372 continue;
373 }
374
Stefan Bergera99de5c2016-08-05 11:07:11 -0400375 int hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
376 if (hsize < 0) {
377 dprintf(DEBUG_tcg, "TPM is using an unsupported hash: %d\n",
378 be16_to_cpu(sel->hashAlg));
379 return -1;
380 }
381
382 /* buffer size sanity check before writing */
383 struct tpm2_digest_value *v = dest;
384 if (dest + sizeof(*v) + hsize > (void*)le + sizeof(*le)) {
385 dprintf(DEBUG_tcg, "tpm_log_entry is too small\n");
386 return -1;
387 }
388
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500389 if (bigEndian)
390 v->hashAlg = sel->hashAlg;
391 else
392 v->hashAlg = be16_to_cpu(sel->hashAlg);
393
Stefan Bergera99de5c2016-08-05 11:07:11 -0400394 memset(v->hash, 0, hsize);
395 memcpy(v->hash, sha1, hsize > SHA1_BUFSIZE ? SHA1_BUFSIZE : hsize);
396
397 dest += sizeof(*v) + hsize;
398 sel = nsel;
Stefan Berger80fce2c2020-03-30 07:55:55 -0400399
400 numAlgs++;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400401 }
402
403 if (sel != end) {
404 dprintf(DEBUG_tcg, "Malformed pcr selection structure fron TPM\n");
405 return -1;
406 }
407
408 struct tpm2_digest_values *v = (void*)le->hdr.digest;
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500409 if (bigEndian)
Stefan Berger80fce2c2020-03-30 07:55:55 -0400410 v->count = cpu_to_be32(numAlgs);
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500411 else
Stefan Berger80fce2c2020-03-30 07:55:55 -0400412 v->count = numAlgs;
Stefan Bergera99de5c2016-08-05 11:07:11 -0400413
414 return dest - (void*)le->hdr.digest;
415}
416
417static int
418tpm12_build_digest(struct tpm_log_entry *le, const u8 *sha1)
419{
420 // On TPM 1.2 the digest contains just the SHA1 hash
421 memcpy(le->hdr.digest, sha1, SHA1_BUFSIZE);
422 return SHA1_BUFSIZE;
423}
424
425static int
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500426tpm_build_digest(struct tpm_log_entry *le, const u8 *sha1, int bigEndian)
Stefan Bergera99de5c2016-08-05 11:07:11 -0400427{
428 switch (TPM_version) {
429 case TPM_VERSION_1_2:
430 return tpm12_build_digest(le, sha1);
431 case TPM_VERSION_2:
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500432 return tpm20_build_digest(le, sha1, bigEndian);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400433 }
434 return -1;
435}
436
Kevin O'Connor01669932016-08-10 16:15:43 -0400437
438/****************************************************************
439 * TPM hardware command wrappers
440 ****************************************************************/
441
Kevin O'Connor846fd312016-08-10 18:15:13 -0400442// Helper function for sending tpm commands that take a single
443// optional parameter (0, 1, or 2 bytes) and have no special response.
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500444static int
Kevin O'Connor846fd312016-08-10 18:15:13 -0400445tpm_simple_cmd(u8 locty, u32 ordinal
446 , int param_size, u16 param, enum tpmDurationType to_t)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400447{
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500448 struct {
449 struct tpm_req_header trqh;
Kevin O'Connor846fd312016-08-10 18:15:13 -0400450 u16 param;
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500451 } PACKED req = {
Kevin O'Connor846fd312016-08-10 18:15:13 -0400452 .trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size),
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500453 .trqh.ordinal = cpu_to_be32(ordinal),
Kevin O'Connor846fd312016-08-10 18:15:13 -0400454 .param = param_size == 2 ? cpu_to_be16(param) : param,
Kevin O'Connorb82bc512015-11-22 17:56:53 -0500455 };
Stefan Bergerf53b93b2016-02-02 13:09:12 -0500456 switch (TPM_version) {
457 case TPM_VERSION_1_2:
458 req.trqh.tag = cpu_to_be16(TPM_TAG_RQU_CMD);
459 break;
460 case TPM_VERSION_2:
461 req.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
462 break;
463 }
464
Stefan Bergerece25612015-11-12 10:14:46 -0500465 u8 obuffer[64];
Kevin O'Connor846fd312016-08-10 18:15:13 -0400466 struct tpm_rsp_header *trsh = (void*)obuffer;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400467 u32 obuffer_len = sizeof(obuffer);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400468 memset(obuffer, 0x0, sizeof(obuffer));
469
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500470 int ret = tpmhw_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
471 ret = ret ? -1 : be32_to_cpu(trsh->errcode);
Kevin O'Connor846fd312016-08-10 18:15:13 -0400472 dprintf(DEBUG_tcg, "Return from tpm_simple_cmd(%x, %x) = %x\n",
473 ordinal, param, ret);
Kevin O'Connorcac29f22015-12-29 17:54:37 -0500474 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400475}
476
Stefan Bergere444dce2016-02-02 13:09:17 -0500477static int
Stefan Berger74544fa2016-08-05 11:07:08 -0400478tpm20_getcapability(u32 capability, u32 property, u32 count,
479 struct tpm_rsp_header *rsp, u32 rsize)
480{
481 struct tpm2_req_getcapability trg = {
482 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
483 .hdr.totlen = cpu_to_be32(sizeof(trg)),
484 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
485 .capability = cpu_to_be32(capability),
486 .property = cpu_to_be32(property),
487 .propertycount = cpu_to_be32(count),
488 };
489
490 u32 resp_size = rsize;
491 int ret = tpmhw_transmit(0, &trg.hdr, rsp, &resp_size,
492 TPM_DURATION_TYPE_SHORT);
493 ret = (ret ||
494 rsize < be32_to_cpu(rsp->totlen)) ? -1 : be32_to_cpu(rsp->errcode);
495
496 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
497 ret);
498
499 return ret;
500}
501
502static int
503tpm20_get_pcrbanks(void)
504{
505 u8 buffer[128];
506 struct tpm2_res_getcapability *trg =
507 (struct tpm2_res_getcapability *)&buffer;
508
509 int ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
510 sizeof(buffer));
511 if (ret)
512 return ret;
513
Stefan Berger05944862019-11-06 16:36:00 -0500514 /* defend against (broken) TPM sending packets that are too short */
515 u32 resplen = be32_to_cpu(trg->hdr.totlen);
516 if (resplen <= offsetof(struct tpm2_res_getcapability, data))
517 return -1;
518
519 u32 size = resplen - offsetof(struct tpm2_res_getcapability, data);
520 /* we need a valid tpml_pcr_selection up to and including sizeOfSelect */
521 if (size < offsetof(struct tpml_pcr_selection, selections) +
522 offsetof(struct tpms_pcr_selection, pcrSelect))
523 return -1;
524
Stefan Berger74544fa2016-08-05 11:07:08 -0400525 tpm20_pcr_selection = malloc_high(size);
526 if (tpm20_pcr_selection) {
527 memcpy(tpm20_pcr_selection, &trg->data, size);
528 tpm20_pcr_selection_size = size;
529 } else {
530 warn_noalloc();
531 ret = -1;
532 }
533
534 return ret;
535}
536
537static int
Stefan Berger171fc892019-01-30 14:06:07 -0500538tpm20_get_suppt_pcrbanks(u8 *suppt_pcrbanks, u8 *active_pcrbanks)
539{
540 *suppt_pcrbanks = 0;
541 *active_pcrbanks = 0;
542
543 if (!tpm20_pcr_selection)
544 return -1;
545
546 struct tpms_pcr_selection *sel = tpm20_pcr_selection->selections;
547 void *end = (void*)tpm20_pcr_selection + tpm20_pcr_selection_size;
548
549 while (1) {
550 u8 sizeOfSelect = sel->sizeOfSelect;
551 void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
552 if (nsel > end)
553 return 0;
554
555 u16 hashalg = be16_to_cpu(sel->hashAlg);
556 u8 hashalg_flag = tpm20_hashalg_to_flag(hashalg);
557
558 *suppt_pcrbanks |= hashalg_flag;
559
560 unsigned i;
561 for (i = 0; i < sizeOfSelect; i++) {
562 if (sel->pcrSelect[i]) {
563 *active_pcrbanks |= hashalg_flag;
564 break;
565 }
566 }
567
568 sel = nsel;
569 }
570}
571
572static int
573tpm20_set_pcrbanks(u32 active_banks)
574{
575 struct tpm2_req_pcr_allocate trpa = {
576 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
577 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate),
578 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
579 .authblocksize = cpu_to_be32(sizeof(trpa.authblock)),
580 .authblock = {
581 .handle = cpu_to_be32(TPM2_RS_PW),
582 .noncesize = cpu_to_be16(0),
583 .contsession = TPM2_YES,
584 .pwdsize = cpu_to_be16(0),
585 },
586 };
587 struct tpms_pcr_selection3 {
588 u16 hashAlg;
589 u8 sizeOfSelect;
590 u8 pcrSelect[3];
591 } tps[ARRAY_SIZE(trpa.tpms_pcr_selections)];
592 int i = 0;
593 u8 hashalg_flag = TPM2_ALG_SHA1_FLAG;
594 u8 dontcare, suppt_banks;
595
596 tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare);
597
598 while (hashalg_flag) {
599 if ((hashalg_flag & suppt_banks)) {
600 u16 hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag);
601
602 if (hashalg) {
603 u8 mask = 0;
604 tps[i].hashAlg = cpu_to_be16(hashalg);
605 tps[i].sizeOfSelect = 3;
606
607 if (active_banks & hashalg_flag)
608 mask = 0xff;
609
610 tps[i].pcrSelect[0] = mask;
611 tps[i].pcrSelect[1] = mask;
612 tps[i].pcrSelect[2] = mask;
613 i++;
614 }
615 }
616 hashalg_flag <<= 1;
617 }
618
619 trpa.count = cpu_to_be32(i);
620 memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0]));
621 trpa.hdr.totlen = cpu_to_be32(offsetof(struct tpm2_req_pcr_allocate,
622 tpms_pcr_selections) +
623 i * sizeof(tps[0]));
624
625 struct tpm_rsp_header rsp;
626 u32 resp_length = sizeof(rsp);
627
628 int ret = tpmhw_transmit(0, &trpa.hdr, &rsp, &resp_length,
629 TPM_DURATION_TYPE_SHORT);
630 ret = ret ? -1 : be32_to_cpu(rsp.errcode);
631
632 return ret;
633}
634
635static int tpm20_activate_pcrbanks(u32 active_banks)
636{
637 int ret = tpm20_set_pcrbanks(active_banks);
638 if (!ret)
639 ret = tpm_simple_cmd(0, TPM2_CC_Shutdown,
640 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
641 if (!ret)
642 reset();
643 return ret;
644}
645
646static int
Kevin O'Connor01669932016-08-10 16:15:43 -0400647tpm12_get_capability(u32 cap, u32 subcap, struct tpm_rsp_header *rsp, u32 rsize)
648{
649 struct tpm_req_getcap trgc = {
650 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
651 .hdr.totlen = cpu_to_be32(sizeof(trgc)),
652 .hdr.ordinal = cpu_to_be32(TPM_ORD_GetCapability),
653 .capArea = cpu_to_be32(cap),
654 .subCapSize = cpu_to_be32(sizeof(trgc.subCap)),
655 .subCap = cpu_to_be32(subcap)
656 };
657 u32 resp_size = rsize;
658 int ret = tpmhw_transmit(0, &trgc.hdr, rsp, &resp_size,
659 TPM_DURATION_TYPE_SHORT);
660 ret = (ret || resp_size != rsize) ? -1 : be32_to_cpu(rsp->errcode);
661 dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(%d, %d)"
662 " = %x\n", cap, subcap, ret);
663 return ret;
664}
665
666static int
667tpm12_read_permanent_flags(char *buf, int buf_len)
668{
669 memset(buf, 0, buf_len);
670
671 struct tpm_res_getcap_perm_flags pf;
672 int ret = tpm12_get_capability(TPM_CAP_FLAG, TPM_CAP_FLAG_PERMANENT
673 , &pf.hdr, sizeof(pf));
674 if (ret)
675 return -1;
676
677 memcpy(buf, &pf.perm_flags, buf_len);
678
679 return 0;
680}
681
682static int
Stefan Berger1d37d522016-02-02 13:09:11 -0500683tpm12_determine_timeouts(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400684{
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400685 struct tpm_res_getcap_timeouts timeouts;
Stefan Berger1d37d522016-02-02 13:09:11 -0500686 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_TIS_TIMEOUT
687 , &timeouts.hdr, sizeof(timeouts));
Kevin O'Connorca606362015-12-29 14:21:29 -0500688 if (ret)
689 return ret;
690
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400691 struct tpm_res_getcap_durations durations;
Stefan Berger1d37d522016-02-02 13:09:11 -0500692 ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_DURATION
693 , &durations.hdr, sizeof(durations));
Kevin O'Connorca606362015-12-29 14:21:29 -0500694 if (ret)
695 return ret;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400696
Kevin O'Connorca606362015-12-29 14:21:29 -0500697 int i;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400698 for (i = 0; i < 3; i++)
699 durations.durations[i] = be32_to_cpu(durations.durations[i]);
700
701 for (i = 0; i < 4; i++)
702 timeouts.timeouts[i] = be32_to_cpu(timeouts.timeouts[i]);
703
704 dprintf(DEBUG_tcg, "TCGBIOS: timeouts: %u %u %u %u\n",
705 timeouts.timeouts[0],
706 timeouts.timeouts[1],
707 timeouts.timeouts[2],
708 timeouts.timeouts[3]);
709
710 dprintf(DEBUG_tcg, "TCGBIOS: durations: %u %u %u\n",
711 durations.durations[0],
712 durations.durations[1],
713 durations.durations[2]);
714
Kevin O'Connorba86edb2015-11-19 18:03:35 -0500715 tpmhw_set_timeouts(timeouts.timeouts, durations.durations);
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400716
717 return 0;
Stefan Bergerb310dfa2015-03-23 14:22:16 -0400718}
719
Stefan Berger0c4ad1e2016-02-02 13:09:13 -0500720static void
721tpm20_set_timeouts(void)
722{
723 u32 durations[3] = {
724 TPM2_DEFAULT_DURATION_SHORT,
725 TPM2_DEFAULT_DURATION_MEDIUM,
726 TPM2_DEFAULT_DURATION_LONG,
727 };
728 u32 timeouts[4] = {
729 TIS2_DEFAULT_TIMEOUT_A,
730 TIS2_DEFAULT_TIMEOUT_B,
731 TIS2_DEFAULT_TIMEOUT_C,
732 TIS2_DEFAULT_TIMEOUT_D,
733 };
734
735 tpmhw_set_timeouts(timeouts, durations);
736}
737
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500738static int
Stefan Bergera99de5c2016-08-05 11:07:11 -0400739tpm12_extend(struct tpm_log_entry *le, int digest_len)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500740{
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500741 struct tpm_req_extend tre = {
Kevin O'Connora0599152015-11-28 08:08:57 -0500742 .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
743 .hdr.totlen = cpu_to_be32(sizeof(tre)),
744 .hdr.ordinal = cpu_to_be32(TPM_ORD_Extend),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400745 .pcrindex = cpu_to_be32(le->hdr.pcrindex),
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500746 };
Stefan Bergera99de5c2016-08-05 11:07:11 -0400747 memcpy(tre.digest, le->hdr.digest, sizeof(tre.digest));
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500748
749 struct tpm_rsp_extend rsp;
750 u32 resp_length = sizeof(rsp);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -0500751 int ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
752 TPM_DURATION_TYPE_SHORT);
753 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -0500754 return -1;
Kevin O'Connor948f3c92015-11-22 19:16:16 -0500755
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500756 return 0;
757}
758
Stefan Bergera99de5c2016-08-05 11:07:11 -0400759static int tpm20_extend(struct tpm_log_entry *le, int digest_len)
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500760{
Stefan Berger0fb23c32016-08-05 11:07:09 -0400761 struct tpm2_req_extend tmp_tre = {
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500762 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400763 .hdr.totlen = cpu_to_be32(0),
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500764 .hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
Stefan Bergera99de5c2016-08-05 11:07:11 -0400765 .pcrindex = cpu_to_be32(le->hdr.pcrindex),
Stefan Berger0fb23c32016-08-05 11:07:09 -0400766 .authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500767 .authblock = {
768 .handle = cpu_to_be32(TPM2_RS_PW),
769 .noncesize = cpu_to_be16(0),
770 .contsession = TPM2_YES,
771 .pwdsize = cpu_to_be16(0),
772 },
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500773 };
Stefan Bergera99de5c2016-08-05 11:07:11 -0400774 u8 buffer[sizeof(tmp_tre) + sizeof(le->pad)];
Stefan Berger0fb23c32016-08-05 11:07:09 -0400775 struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;
776
777 memcpy(tre, &tmp_tre, sizeof(tmp_tre));
Stefan Bergera99de5c2016-08-05 11:07:11 -0400778 memcpy(&tre->digest[0], le->hdr.digest, digest_len);
779
780 tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len);
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500781
782 struct tpm_rsp_header rsp;
783 u32 resp_length = sizeof(rsp);
Stefan Berger0fb23c32016-08-05 11:07:09 -0400784 int ret = tpmhw_transmit(0, &tre->hdr, &rsp, &resp_length,
Stefan Berger8b7a0ad2016-02-02 13:09:15 -0500785 TPM_DURATION_TYPE_SHORT);
786 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
787 return -1;
788
789 return 0;
790}
791
Stefan Berger35fbe3b2016-02-02 13:09:10 -0500792static int
Stefan Bergera99de5c2016-08-05 11:07:11 -0400793tpm_extend(struct tpm_log_entry *le, int digest_len)
Stefan Berger1d37d522016-02-02 13:09:11 -0500794{
Stefan Berger1d37d522016-02-02 13:09:11 -0500795 switch (TPM_version) {
796 case TPM_VERSION_1_2:
Stefan Bergera99de5c2016-08-05 11:07:11 -0400797 return tpm12_extend(le, digest_len);
Stefan Berger1d37d522016-02-02 13:09:11 -0500798 case TPM_VERSION_2:
Stefan Bergera99de5c2016-08-05 11:07:11 -0400799 return tpm20_extend(le, digest_len);
Stefan Berger1d37d522016-02-02 13:09:11 -0500800 }
801 return -1;
802}
803
Kevin O'Connor01669932016-08-10 16:15:43 -0400804static int
805tpm20_stirrandom(void)
806{
Kevin O'Connor538d9b72016-08-10 17:45:05 -0400807 struct tpm2_req_stirrandom stir = {
808 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
809 .hdr.totlen = cpu_to_be32(sizeof(stir)),
810 .hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom),
Kevin O'Connor01669932016-08-10 16:15:43 -0400811 .size = cpu_to_be16(sizeof(stir.stir)),
812 .stir = rdtscll(),
813 };
814 /* set more bits to stir with */
815 stir.stir += swab64(rdtscll());
816
Kevin O'Connor538d9b72016-08-10 17:45:05 -0400817 struct tpm_rsp_header rsp;
818 u32 resp_length = sizeof(rsp);
819 int ret = tpmhw_transmit(0, &stir.hdr, &rsp, &resp_length,
820 TPM_DURATION_TYPE_SHORT);
821 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
822 ret = -1;
Kevin O'Connor01669932016-08-10 16:15:43 -0400823
824 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
825 ret);
826
827 return ret;
828}
829
830static int
831tpm20_getrandom(u8 *buf, u16 buf_len)
832{
833 struct tpm2_res_getrandom rsp;
834
835 if (buf_len > sizeof(rsp.rnd.buffer))
836 return -1;
837
838 struct tpm2_req_getrandom trgr = {
839 .hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
840 .hdr.totlen = cpu_to_be32(sizeof(trgr)),
841 .hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
842 .bytesRequested = cpu_to_be16(buf_len),
843 };
844 u32 resp_length = sizeof(rsp);
845
846 int ret = tpmhw_transmit(0, &trgr.hdr, &rsp, &resp_length,
847 TPM_DURATION_TYPE_MEDIUM);
848 if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
849 ret = -1;
850 else
851 memcpy(buf, rsp.rnd.buffer, buf_len);
852
853 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
854 ret);
855
856 return ret;
857}
858
859static int
860tpm20_hierarchycontrol(u32 hierarchy, u8 state)
861{
862 /* we will try to deactivate the TPM now - ignoring all errors */
863 struct tpm2_req_hierarchycontrol trh = {
864 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
865 .hdr.totlen = cpu_to_be32(sizeof(trh)),
866 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
867 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
868 .authblocksize = cpu_to_be32(sizeof(trh.authblock)),
869 .authblock = {
870 .handle = cpu_to_be32(TPM2_RS_PW),
871 .noncesize = cpu_to_be16(0),
872 .contsession = TPM2_YES,
873 .pwdsize = cpu_to_be16(0),
874 },
875 .enable = cpu_to_be32(hierarchy),
876 .state = state,
877 };
878 struct tpm_rsp_header rsp;
879 u32 resp_length = sizeof(rsp);
880 int ret = tpmhw_transmit(0, &trh.hdr, &rsp, &resp_length,
881 TPM_DURATION_TYPE_MEDIUM);
882 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
883 ret = -1;
884
885 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
886 ret);
887
888 return ret;
889}
890
891static int
892tpm20_hierarchychangeauth(u8 auth[20])
893{
894 struct tpm2_req_hierarchychangeauth trhca = {
895 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
896 .hdr.totlen = cpu_to_be32(sizeof(trhca)),
897 .hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
898 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
899 .authblocksize = cpu_to_be32(sizeof(trhca.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 .newAuth = {
907 .size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
908 },
909 };
910 memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
911
912 struct tpm_rsp_header rsp;
913 u32 resp_length = sizeof(rsp);
914 int ret = tpmhw_transmit(0, &trhca.hdr, &rsp, &resp_length,
915 TPM_DURATION_TYPE_MEDIUM);
916 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
917 ret = -1;
918
919 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
920 ret);
921
922 return ret;
923}
924
925
926/****************************************************************
927 * Setup and Measurements
928 ****************************************************************/
929
930static int TPM_has_physical_presence;
931u8 TPM_working VARLOW;
932
933static int
934tpm_is_working(void)
935{
936 return CONFIG_TCGBIOS && TPM_working;
937}
938
939static void
940tpm_set_failure(void)
941{
942 switch (TPM_version) {
943 case TPM_VERSION_1_2:
944 /*
945 * We will try to deactivate the TPM now - ignoring all errors
946 * Physical presence is asserted.
947 */
948
Kevin O'Connor846fd312016-08-10 18:15:13 -0400949 tpm_simple_cmd(0, TPM_ORD_SetTempDeactivated,
950 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connor01669932016-08-10 16:15:43 -0400951 break;
952 case TPM_VERSION_2:
953 tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
954 tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
955 break;
956 }
957
958 TPM_working = 0;
959}
960
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500961/*
962 * Add a measurement to the log; the data at data_seg:data/length are
963 * appended to the TCG_PCClientPCREventStruct
964 *
965 * Input parameters:
966 * pcrindex : which PCR to extend
967 * event_type : type of event; specs section on 'Event Types'
968 * event : pointer to info (e.g., string) to be added to log as-is
969 * event_length: length of the event
970 * hashdata : pointer to the data to be hashed
971 * hashdata_length: length of the data to be hashed
972 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -0500973static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500974tpm_add_measurement_to_log(u32 pcrindex, u32 event_type,
975 const char *event, u32 event_length,
976 const u8 *hashdata, u32 hashdata_length)
977{
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500978 if (!tpm_is_working())
979 return;
980
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400981 u8 hash[SHA1_BUFSIZE];
982 sha1(hashdata, hashdata_length, hash);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400983
984 struct tpm_log_entry le = {
985 .hdr.pcrindex = pcrindex,
986 .hdr.eventtype = event_type,
987 };
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500988 int digest_len = tpm_build_digest(&le, hash, 1);
Stefan Bergera99de5c2016-08-05 11:07:11 -0400989 if (digest_len < 0)
990 return;
991 int ret = tpm_extend(&le, digest_len);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500992 if (ret) {
Kevin O'Connor5ffcb2c2015-12-30 00:48:57 -0500993 tpm_set_failure();
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -0500994 return;
995 }
Stefan Berger7b7b49e2016-11-23 11:19:43 -0500996 tpm_build_digest(&le, hash, 0);
Kevin O'Connor19e8ea62016-08-09 13:24:51 -0400997 tpm_log_event(&le.hdr, digest_len, event, event_length);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -0500998}
999
Kevin O'Connora6175422015-11-22 11:28:14 -05001000// Add an EV_ACTION measurement to the list of measurements
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001001static void
Kevin O'Connora6175422015-11-22 11:28:14 -05001002tpm_add_action(u32 pcrIndex, const char *string)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001003{
Kevin O'Connora6175422015-11-22 11:28:14 -05001004 u32 len = strlen(string);
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001005 tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
1006 string, len, (u8 *)string, len);
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001007}
1008
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001009/*
1010 * Add event separators for PCRs 0 to 7; specs on 'Measuring Boot Events'
1011 */
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001012static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001013tpm_add_event_separators(void)
1014{
Kevin O'Connora6175422015-11-22 11:28:14 -05001015 static const u8 evt_separator[] = {0xff,0xff,0xff,0xff};
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001016 u32 pcrIndex;
1017 for (pcrIndex = 0; pcrIndex <= 7; pcrIndex++)
1018 tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
Stefan Bergerba949f52021-06-09 13:31:59 -04001019 (const char *)evt_separator,
1020 sizeof(evt_separator),
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001021 evt_separator,
1022 sizeof(evt_separator));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001023}
1024
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001025static void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001026tpm_smbios_measure(void)
1027{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001028 struct pcctes pcctes = {
1029 .eventid = 1,
1030 .eventdatasize = SHA1_BUFSIZE,
1031 };
1032 struct smbios_entry_point *sep = SMBiosAddr;
1033
1034 dprintf(DEBUG_tcg, "TCGBIOS: SMBIOS at %p\n", sep);
1035
1036 if (!sep)
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001037 return;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001038
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001039 sha1((const u8 *)sep->structure_table_address,
1040 sep->structure_table_length, pcctes.digest);
1041 tpm_add_measurement_to_log(1,
1042 EV_EVENT_TAG,
1043 (const char *)&pcctes, sizeof(pcctes),
1044 (u8 *)&pcctes, sizeof(pcctes));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001045}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001046
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001047static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001048tpm12_assert_physical_presence(void)
Stefan Bergere55e37f2016-01-07 12:02:47 -05001049{
Kevin O'Connor846fd312016-08-10 18:15:13 -04001050 int ret = tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1051 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -05001052 if (!ret)
1053 return 0;
1054
1055 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001056 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Stefan Bergere55e37f2016-01-07 12:02:47 -05001057 if (ret)
1058 return -1;
1059
Stefan Bergera2206d32016-01-07 12:02:48 -05001060 /* check if hardware physical presence is supported */
1061 if (pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]) {
1062 /* HW phys. presence may not be asserted... */
Stefan Bergere55e37f2016-01-07 12:02:47 -05001063 return 0;
Stefan Bergere55e37f2016-01-07 12:02:47 -05001064 }
1065
Stefan Bergera2206d32016-01-07 12:02:48 -05001066 if (!pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]
1067 && !pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]) {
Kevin O'Connor846fd312016-08-10 18:15:13 -04001068 tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1069 2, TPM_PP_CMD_ENABLE, TPM_DURATION_TYPE_SHORT);
Stefan Bergera2206d32016-01-07 12:02:48 -05001070
Kevin O'Connor846fd312016-08-10 18:15:13 -04001071 return tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1072 2, TPM_PP_PRESENT, TPM_DURATION_TYPE_SHORT);
Stefan Bergere55e37f2016-01-07 12:02:47 -05001073 }
Stefan Bergere55e37f2016-01-07 12:02:47 -05001074 return -1;
1075}
1076
1077static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001078tpm12_startup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001079{
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001080 dprintf(DEBUG_tcg, "TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
Kevin O'Connor846fd312016-08-10 18:15:13 -04001081 int ret = tpm_simple_cmd(0, TPM_ORD_Startup,
1082 2, TPM_ST_CLEAR, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001083 if (CONFIG_COREBOOT && ret == TPM_INVALID_POSTINIT)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001084 /* with other firmware on the system the TPM may already have been
1085 * initialized
1086 */
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001087 ret = 0;
1088 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001089 goto err_exit;
1090
Stefan Berger115d0082016-01-07 12:02:49 -05001091 /* assertion of physical presence is only possible after startup */
Stefan Berger1d37d522016-02-02 13:09:11 -05001092 ret = tpm12_assert_physical_presence();
Stefan Berger115d0082016-01-07 12:02:49 -05001093 if (!ret)
1094 TPM_has_physical_presence = 1;
1095
Stefan Berger1d37d522016-02-02 13:09:11 -05001096 ret = tpm12_determine_timeouts();
Kevin O'Connorca606362015-12-29 14:21:29 -05001097 if (ret)
Kevin O'Connord468d592016-08-10 16:23:02 -04001098 goto err_exit;
Stefan Bergerec42c8d2015-11-21 14:54:41 -05001099
Kevin O'Connor846fd312016-08-10 18:15:13 -04001100 ret = tpm_simple_cmd(0, TPM_ORD_SelfTestFull,
1101 0, 0, TPM_DURATION_TYPE_LONG);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001102 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001103 goto err_exit;
1104
Kevin O'Connor846fd312016-08-10 18:15:13 -04001105 ret = tpm_simple_cmd(3, TSC_ORD_ResetEstablishmentBit,
1106 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001107 if (ret && ret != TPM_BAD_LOCALITY)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001108 goto err_exit;
1109
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001110 return 0;
1111
1112err_exit:
1113 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1114
Stefan Berger7fce1d92015-11-12 10:14:45 -05001115 tpm_set_failure();
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001116 return -1;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001117}
1118
Stefan Berger1d37d522016-02-02 13:09:11 -05001119static int
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001120tpm20_startup(void)
1121{
Stefan Berger0c4ad1e2016-02-02 13:09:13 -05001122 tpm20_set_timeouts();
1123
Kevin O'Connor846fd312016-08-10 18:15:13 -04001124 int ret = tpm_simple_cmd(0, TPM2_CC_Startup,
1125 2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001126
1127 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
1128 ret);
1129
1130 if (CONFIG_COREBOOT && ret == TPM2_RC_INITIALIZE)
1131 /* with other firmware on the system the TPM may already have been
1132 * initialized
1133 */
1134 ret = 0;
1135
1136 if (ret)
1137 goto err_exit;
1138
Kevin O'Connor846fd312016-08-10 18:15:13 -04001139 ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
1140 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001141
1142 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest = 0x%08x\n",
1143 ret);
1144
1145 if (ret)
1146 goto err_exit;
1147
Stefan Berger74544fa2016-08-05 11:07:08 -04001148 ret = tpm20_get_pcrbanks();
1149 if (ret)
1150 goto err_exit;
1151
Kevin O'Connor19e8ea62016-08-09 13:24:51 -04001152 ret = tpm20_write_EfiSpecIdEventStruct();
1153 if (ret)
1154 goto err_exit;
1155
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001156 return 0;
1157
1158err_exit:
1159 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1160
1161 tpm_set_failure();
1162 return -1;
1163}
1164
1165static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001166tpm_startup(void)
1167{
1168 switch (TPM_version) {
1169 case TPM_VERSION_1_2:
1170 return tpm12_startup();
1171 case TPM_VERSION_2:
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001172 return tpm20_startup();
Stefan Berger1d37d522016-02-02 13:09:11 -05001173 }
1174 return -1;
1175}
1176
Kevin O'Connord6aca442015-06-10 11:00:17 -04001177void
1178tpm_setup(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001179{
1180 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001181 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001182
Stephen Douthit42efebd2018-03-07 13:17:36 -05001183 int ret = tpm_tpm2_probe();
1184 if (ret) {
1185 ret = tpm_tcpa_probe();
1186 if (ret)
1187 return;
1188 }
1189
Stefan Bergerefc49cf2016-02-02 13:09:09 -05001190 TPM_version = tpmhw_probe();
1191 if (TPM_version == TPM_VERSION_NONE)
Kevin O'Connor27065322015-11-28 14:25:41 -05001192 return;
1193
Stefan Bergerefc49cf2016-02-02 13:09:09 -05001194 dprintf(DEBUG_tcg,
1195 "TCGBIOS: Detected a TPM %s.\n",
1196 (TPM_version == TPM_VERSION_1_2) ? "1.2" : "2");
1197
Kevin O'Connor27065322015-11-28 14:25:41 -05001198 TPM_working = 1;
1199
Quan Xu67643952015-04-30 19:43:04 -04001200 if (runningOnXen())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001201 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001202
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001203 ret = tpm_startup();
1204 if (ret)
1205 return;
1206
1207 tpm_smbios_measure();
1208 tpm_add_action(2, "Start Option ROM Scan");
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001209}
1210
Stefan Bergerd766c1a2016-02-02 13:09:14 -05001211static void
1212tpm20_prepboot(void)
1213{
1214 int ret = tpm20_stirrandom();
1215 if (ret)
1216 goto err_exit;
1217
1218 u8 auth[20];
1219 ret = tpm20_getrandom(&auth[0], sizeof(auth));
1220 if (ret)
1221 goto err_exit;
1222
1223 ret = tpm20_hierarchychangeauth(auth);
1224 if (ret)
1225 goto err_exit;
1226
1227 return;
1228
1229err_exit:
1230 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1231
1232 tpm_set_failure();
1233}
1234
Kevin O'Connord6aca442015-06-10 11:00:17 -04001235void
1236tpm_prepboot(void)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001237{
Stefan Berger8b902b82016-01-07 12:02:50 -05001238 if (!CONFIG_TCGBIOS)
Kevin O'Connord6aca442015-06-10 11:00:17 -04001239 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001240
Stefan Berger1d37d522016-02-02 13:09:11 -05001241 switch (TPM_version) {
1242 case TPM_VERSION_1_2:
1243 if (TPM_has_physical_presence)
Kevin O'Connor846fd312016-08-10 18:15:13 -04001244 tpm_simple_cmd(0, TPM_ORD_PhysicalPresence,
1245 2, TPM_PP_NOT_PRESENT_LOCK, TPM_DURATION_TYPE_SHORT);
Stefan Berger1d37d522016-02-02 13:09:11 -05001246 break;
1247 case TPM_VERSION_2:
Stefan Bergerd766c1a2016-02-02 13:09:14 -05001248 tpm20_prepboot();
Stefan Berger1d37d522016-02-02 13:09:11 -05001249 break;
1250 }
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001251
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001252 tpm_add_action(4, "Calling INT 19h");
1253 tpm_add_event_separators();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001254}
1255
Stefan Berger5aa2a752015-03-23 14:22:17 -04001256/*
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001257 * Add measurement to the log about an option rom
Stefan Berger5aa2a752015-03-23 14:22:17 -04001258 */
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001259void
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001260tpm_option_rom(const void *addr, u32 len)
Stefan Berger5aa2a752015-03-23 14:22:17 -04001261{
Kevin O'Connord559a232015-11-28 08:35:26 -05001262 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001263 return;
Stefan Berger7fce1d92015-11-12 10:14:45 -05001264
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001265 struct pcctes_romex pcctes = {
1266 .eventid = 7,
1267 .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
Stefan Berger5aa2a752015-03-23 14:22:17 -04001268 };
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001269 sha1((const u8 *)addr, len, pcctes.digest);
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001270 tpm_add_measurement_to_log(2,
1271 EV_EVENT_TAG,
1272 (const char *)&pcctes, sizeof(pcctes),
1273 (u8 *)&pcctes, sizeof(pcctes));
Stefan Berger6c376b42015-11-12 10:14:49 -05001274}
Stefan Berger5aa2a752015-03-23 14:22:17 -04001275
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001276void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001277tpm_add_bcv(u32 bootdrv, const u8 *addr, u32 length)
1278{
Kevin O'Connord559a232015-11-28 08:35:26 -05001279 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001280 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001281
Stefan Berger4cdbc412015-11-30 11:14:18 -05001282 if (length < 0x200)
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001283 return;
Stefan Berger4cdbc412015-11-30 11:14:18 -05001284
Kevin O'Connor8bd4a082015-11-19 17:43:27 -05001285 const char *string = "Booting BCV device 00h (Floppy)";
1286 if (bootdrv == 0x80)
1287 string = "Booting BCV device 80h (HDD)";
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001288 tpm_add_action(4, string);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001289
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001290 /* specs: see section 'Hard Disk Device or Hard Disk-Like Devices' */
1291 /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
Kevin O'Connor8bd4a082015-11-19 17:43:27 -05001292 string = "MBR";
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001293 tpm_add_measurement_to_log(4, EV_IPL,
1294 string, strlen(string),
1295 addr, 0x1b8);
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001296
1297 /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
1298 string = "MBR PARTITION_TABLE";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001299 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1300 string, strlen(string),
1301 addr + 0x1b8, 0x48);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001302}
1303
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001304void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001305tpm_add_cdrom(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
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001310 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001311
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001312 /* specs: see section 'El Torito' */
1313 const char *string = "EL TORITO IPL";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001314 tpm_add_measurement_to_log(4, EV_IPL,
1315 string, strlen(string),
1316 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001317}
1318
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001319void
Stefan Berger2aff1c12015-05-26 15:48:33 -04001320tpm_add_cdrom_catalog(const u8 *addr, u32 length)
1321{
Kevin O'Connord559a232015-11-28 08:35:26 -05001322 if (!tpm_is_working())
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001323 return;
Stefan Berger2aff1c12015-05-26 15:48:33 -04001324
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001325 tpm_add_action(4, "Booting from CD ROM device");
Stefan Berger2aff1c12015-05-26 15:48:33 -04001326
Kevin O'Connor7ea191b2015-11-22 11:15:51 -05001327 /* specs: see section 'El Torito' */
1328 const char *string = "BOOT CATALOG";
Kevin O'Connore98fafa2015-12-29 23:14:22 -05001329 tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1330 string, strlen(string),
1331 addr, length);
Stefan Berger2aff1c12015-05-26 15:48:33 -04001332}
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001333
Kevin O'Connord6aca442015-06-10 11:00:17 -04001334void
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001335tpm_s3_resume(void)
1336{
Kevin O'Connord559a232015-11-28 08:35:26 -05001337 if (!tpm_is_working())
Kevin O'Connord6aca442015-06-10 11:00:17 -04001338 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001339
1340 dprintf(DEBUG_tcg, "TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
1341
Stefan Berger1d37d522016-02-02 13:09:11 -05001342 int ret = -1;
1343
1344 switch (TPM_version) {
1345 case TPM_VERSION_1_2:
Kevin O'Connor846fd312016-08-10 18:15:13 -04001346 ret = tpm_simple_cmd(0, TPM_ORD_Startup,
1347 2, TPM_ST_STATE, TPM_DURATION_TYPE_SHORT);
Stefan Berger1d37d522016-02-02 13:09:11 -05001348 break;
1349 case TPM_VERSION_2:
Kevin O'Connor846fd312016-08-10 18:15:13 -04001350 ret = tpm_simple_cmd(0, TPM2_CC_Startup,
1351 2, TPM2_SU_STATE, TPM_DURATION_TYPE_SHORT);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001352
1353 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Startup(SU_STATE) = 0x%08x\n",
1354 ret);
1355
1356 if (ret)
1357 goto err_exit;
1358
1359
Kevin O'Connor846fd312016-08-10 18:15:13 -04001360 ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
1361 1, TPM2_YES, TPM_DURATION_TYPE_LONG);
Stefan Bergerf53b93b2016-02-02 13:09:12 -05001362
1363 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_SelfTest() = 0x%08x\n",
1364 ret);
1365
Stefan Berger1d37d522016-02-02 13:09:11 -05001366 break;
1367 }
1368
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001369 if (ret)
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001370 goto err_exit;
1371
Kevin O'Connord6aca442015-06-10 11:00:17 -04001372 return;
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001373
1374err_exit:
1375 dprintf(DEBUG_tcg, "TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
1376
Stefan Berger7fce1d92015-11-12 10:14:45 -05001377 tpm_set_failure();
Stefan Bergerb310dfa2015-03-23 14:22:16 -04001378}
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001379
1380
1381/****************************************************************
1382 * BIOS interface
1383 ****************************************************************/
1384
Kevin O'Connor59076132015-11-28 13:55:09 -05001385u8 TPM_interface_shutdown VARLOW;
1386
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001387static inline void *input_buf32(struct bregs *regs)
1388{
1389 return MAKE_FLATPTR(regs->es, regs->di);
1390}
1391
1392static inline void *output_buf32(struct bregs *regs)
1393{
1394 return MAKE_FLATPTR(regs->ds, regs->si);
1395}
1396
1397static u32
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001398hash_log_extend(struct pcpes *pcpes, const void *hashdata, u32 hashdata_length
1399 , void *event, int extend)
1400{
1401 if (pcpes->pcrindex >= 24)
1402 return TCG_INVALID_INPUT_PARA;
1403 if (hashdata)
1404 sha1(hashdata, hashdata_length, pcpes->digest);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001405
1406 struct tpm_log_entry le = {
1407 .hdr.pcrindex = pcpes->pcrindex,
1408 .hdr.eventtype = pcpes->eventtype,
1409 };
Stefan Berger7b7b49e2016-11-23 11:19:43 -05001410 int digest_len = tpm_build_digest(&le, pcpes->digest, 1);
Stefan Bergera99de5c2016-08-05 11:07:11 -04001411 if (digest_len < 0)
1412 return TCG_GENERAL_ERROR;
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001413 if (extend) {
Stefan Bergera99de5c2016-08-05 11:07:11 -04001414 int ret = tpm_extend(&le, digest_len);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001415 if (ret)
1416 return TCG_TCG_COMMAND_ERROR;
1417 }
Stefan Berger7b7b49e2016-11-23 11:19:43 -05001418 tpm_build_digest(&le, pcpes->digest, 0);
Kevin O'Connor19e8ea62016-08-09 13:24:51 -04001419 int ret = tpm_log_event(&le.hdr, digest_len
1420 , pcpes->event, pcpes->eventdatasize);
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001421 if (ret)
1422 return TCG_PC_LOGOVERFLOW;
1423 return 0;
1424}
1425
1426static u32
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001427hash_log_extend_event_int(const struct hleei_short *hleei_s,
1428 struct hleeo *hleeo)
1429{
1430 u32 rc = 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001431 struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
1432 const void *logdataptr;
1433 u32 logdatalen;
1434 struct pcpes *pcpes;
1435 u32 pcrindex;
1436
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001437 /* short or long version? */
1438 switch (hleei_s->ipblength) {
1439 case sizeof(struct hleei_short):
1440 /* short */
1441 logdataptr = hleei_s->logdataptr;
1442 logdatalen = hleei_s->logdatalen;
1443 pcrindex = hleei_s->pcrindex;
1444 break;
1445
1446 case sizeof(struct hleei_long):
1447 /* long */
1448 logdataptr = hleei_l->logdataptr;
1449 logdatalen = hleei_l->logdatalen;
1450 pcrindex = hleei_l->pcrindex;
1451 break;
1452
1453 default:
1454 /* bad input block */
1455 rc = TCG_INVALID_INPUT_PARA;
1456 goto err_exit;
1457 }
1458
1459 pcpes = (struct pcpes *)logdataptr;
1460
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001461 if (pcpes->pcrindex != pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001462 || logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001463 rc = TCG_INVALID_INPUT_PARA;
1464 goto err_exit;
1465 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001466 rc = hash_log_extend(pcpes, hleei_s->hashdataptr, hleei_s->hashdatalen
1467 , pcpes->event, 1);
1468 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001469 goto err_exit;
1470
1471 hleeo->opblength = sizeof(struct hleeo);
1472 hleeo->reserved = 0;
Kevin O'Connor1ef72ab2017-09-02 21:42:12 -04001473 hleeo->eventnumber = tpm_state.entry_count;
Stefan Berger2b237502016-01-07 12:02:46 -05001474 memcpy(hleeo->digest, pcpes->digest, sizeof(hleeo->digest));
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001475
1476err_exit:
1477 if (rc != 0) {
1478 hleeo->opblength = 4;
1479 hleeo->reserved = 0;
1480 }
1481
1482 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001483}
1484
1485static u32
1486pass_through_to_tpm_int(struct pttti *pttti, struct pttto *pttto)
1487{
1488 u32 rc = 0;
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001489 struct tpm_req_header *trh = (void*)pttti->tpmopin;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001490
Stefan Berger7092de32016-02-02 13:09:19 -05001491 if (pttti->ipblength < sizeof(struct pttti) + sizeof(*trh)
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001492 || pttti->ipblength != sizeof(struct pttti) + be32_to_cpu(trh->totlen)
1493 || pttti->opblength < sizeof(struct pttto)) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001494 rc = TCG_INVALID_INPUT_PARA;
1495 goto err_exit;
1496 }
1497
Stefan Berger7092de32016-02-02 13:09:19 -05001498 u16 tag = be16_to_cpu(trh->tag);
1499
1500 switch (TPM_version) {
1501 case TPM_VERSION_1_2:
1502 if (tag != TPM_TAG_RQU_CMD && tag != TPM_TAG_RQU_AUTH1_CMD
1503 && tag != TPM_TAG_RQU_AUTH2_CMD) {
1504 rc = TCG_INVALID_INPUT_PARA;
1505 goto err_exit;
1506 }
1507 break;
1508 case TPM_VERSION_2:
1509 if (tag != TPM2_ST_NO_SESSIONS && tag != TPM2_ST_SESSIONS) {
1510 rc = TCG_INVALID_INPUT_PARA;
1511 goto err_exit;
1512 }
1513 }
1514
Kevin O'Connor7ba05682015-11-22 18:21:45 -05001515 u32 resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001516 int ret = tpmhw_transmit(0, trh, pttto->tpmopout, &resbuflen,
1517 TPM_DURATION_TYPE_LONG /* worst case */);
1518 if (ret) {
1519 rc = TCG_FATAL_COM_ERROR;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001520 goto err_exit;
Kevin O'Connorb8631ea2015-12-30 12:51:27 -05001521 }
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001522
1523 pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
1524 pttto->reserved = 0;
1525
1526err_exit:
1527 if (rc != 0) {
1528 pttto->opblength = 4;
1529 pttto->reserved = 0;
1530 }
1531
1532 return rc;
1533}
1534
1535static u32
1536shutdown_preboot_interface(void)
1537{
Kevin O'Connor59076132015-11-28 13:55:09 -05001538 TPM_interface_shutdown = 1;
1539 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001540}
1541
1542static u32
1543hash_log_event_int(const struct hlei *hlei, struct hleo *hleo)
1544{
1545 u32 rc = 0;
1546 u16 size;
1547 struct pcpes *pcpes;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001548
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001549 size = hlei->ipblength;
1550 if (size != sizeof(*hlei)) {
1551 rc = TCG_INVALID_INPUT_PARA;
1552 goto err_exit;
1553 }
1554
1555 pcpes = (struct pcpes *)hlei->logdataptr;
1556
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001557 if (pcpes->pcrindex != hlei->pcrindex
Kevin O'Connor7bf77382015-11-22 17:28:36 -05001558 || pcpes->eventtype != hlei->logeventtype
1559 || hlei->logdatalen != sizeof(*pcpes) + pcpes->eventdatasize) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001560 rc = TCG_INVALID_INPUT_PARA;
1561 goto err_exit;
1562 }
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001563 rc = hash_log_extend(pcpes, hlei->hashdataptr, hlei->hashdatalen
1564 , pcpes->event, 0);
1565 if (rc)
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001566 goto err_exit;
1567
1568 /* updating the log was fine */
1569 hleo->opblength = sizeof(struct hleo);
1570 hleo->reserved = 0;
Kevin O'Connor5afdced2015-11-22 16:39:59 -05001571 hleo->eventnumber = tpm_state.entry_count;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001572
1573err_exit:
1574 if (rc != 0) {
1575 hleo->opblength = 2;
1576 hleo->reserved = 0;
1577 }
1578
1579 return rc;
1580}
1581
1582static u32
1583hash_all_int(const struct hai *hai, u8 *hash)
1584{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001585 if (hai->ipblength != sizeof(struct hai) ||
1586 hai->hashdataptr == 0 ||
1587 hai->hashdatalen == 0 ||
1588 hai->algorithmid != TPM_ALG_SHA)
1589 return TCG_INVALID_INPUT_PARA;
1590
Kevin O'Connored8d55d2015-12-30 00:15:10 -05001591 sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
1592 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001593}
1594
1595static u32
1596tss_int(struct ti *ti, struct to *to)
1597{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001598 to->opblength = sizeof(struct to);
1599 to->reserved = 0;
1600
Kevin O'Connor59076132015-11-28 13:55:09 -05001601 return TCG_PC_UNSUPPORTED;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001602}
1603
1604static u32
1605compact_hash_log_extend_event_int(u8 *buffer,
1606 u32 info,
1607 u32 length,
1608 u32 pcrindex,
1609 u32 *edx_ptr)
1610{
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001611 struct pcpes pcpes = {
1612 .pcrindex = pcrindex,
1613 .eventtype = EV_COMPACT_HASH,
1614 .eventdatasize = sizeof(info),
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001615 };
Kevin O'Connorecd7c5d2016-02-05 21:05:27 -05001616 u32 rc = hash_log_extend(&pcpes, buffer, length, &info, 1);
1617 if (rc)
1618 return rc;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001619
Kevin O'Connor9ddea3b2015-12-30 12:40:11 -05001620 *edx_ptr = tpm_state.entry_count;
1621 return 0;
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001622}
1623
1624void VISIBLE32FLAT
1625tpm_interrupt_handler32(struct bregs *regs)
1626{
1627 if (!CONFIG_TCGBIOS)
1628 return;
1629
1630 set_cf(regs, 0);
1631
Kevin O'Connor59076132015-11-28 13:55:09 -05001632 if (TPM_interface_shutdown && regs->al) {
1633 regs->eax = TCG_INTERFACE_SHUTDOWN;
1634 return;
1635 }
1636
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001637 switch ((enum irq_ids)regs->al) {
1638 case TCG_StatusCheck:
Kevin O'Connord559a232015-11-28 08:35:26 -05001639 if (!tpmhw_is_present()) {
Kevin O'Connorf51c50a2015-11-22 10:57:52 -05001640 /* no TPM available */
1641 regs->eax = TCG_PC_TPM_NOT_PRESENT;
1642 } else {
1643 regs->eax = 0;
1644 regs->ebx = TCG_MAGIC;
1645 regs->ch = TCG_VERSION_MAJOR;
1646 regs->cl = TCG_VERSION_MINOR;
1647 regs->edx = 0x0;
1648 regs->esi = (u32)tpm_state.log_area_start_address;
1649 regs->edi = (u32)tpm_state.log_area_last_entry;
1650 }
1651 break;
1652
1653 case TCG_HashLogExtendEvent:
1654 regs->eax =
1655 hash_log_extend_event_int(
1656 (struct hleei_short *)input_buf32(regs),
1657 (struct hleeo *)output_buf32(regs));
1658 break;
1659
1660 case TCG_PassThroughToTPM:
1661 regs->eax =
1662 pass_through_to_tpm_int((struct pttti *)input_buf32(regs),
1663 (struct pttto *)output_buf32(regs));
1664 break;
1665
1666 case TCG_ShutdownPreBootInterface:
1667 regs->eax = shutdown_preboot_interface();
1668 break;
1669
1670 case TCG_HashLogEvent:
1671 regs->eax = hash_log_event_int((struct hlei*)input_buf32(regs),
1672 (struct hleo*)output_buf32(regs));
1673 break;
1674
1675 case TCG_HashAll:
1676 regs->eax =
1677 hash_all_int((struct hai*)input_buf32(regs),
1678 (u8 *)output_buf32(regs));
1679 break;
1680
1681 case TCG_TSS:
1682 regs->eax = tss_int((struct ti*)input_buf32(regs),
1683 (struct to*)output_buf32(regs));
1684 break;
1685
1686 case TCG_CompactHashLogExtendEvent:
1687 regs->eax =
1688 compact_hash_log_extend_event_int((u8 *)input_buf32(regs),
1689 regs->esi,
1690 regs->ecx,
1691 regs->edx,
1692 &regs->edx);
1693 break;
1694
1695 default:
1696 set_cf(regs, 1);
1697 }
1698
1699 return;
1700}
Stefan Berger320df852015-11-30 11:14:19 -05001701
Kevin O'Connor26e36172015-12-29 12:20:23 -05001702
1703/****************************************************************
1704 * TPM Configuration Menu
1705 ****************************************************************/
1706
Kevin O'Connor01669932016-08-10 16:15:43 -04001707typedef u8 tpm_ppi_code;
1708
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001709static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001710tpm12_read_has_owner(int *has_owner)
Stefan Berger320df852015-11-30 11:14:19 -05001711{
Stefan Berger320df852015-11-30 11:14:19 -05001712 struct tpm_res_getcap_ownerauth oauth;
Stefan Berger1d37d522016-02-02 13:09:11 -05001713 int ret = tpm12_get_capability(TPM_CAP_PROPERTY, TPM_CAP_PROP_OWNER
1714 , &oauth.hdr, sizeof(oauth));
Kevin O'Connorca606362015-12-29 14:21:29 -05001715 if (ret)
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001716 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001717
1718 *has_owner = oauth.flag;
1719
1720 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001721}
1722
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001723static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001724tpm12_enable_tpm(int enable, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001725{
Stefan Berger320df852015-11-30 11:14:19 -05001726 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001727 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001728 if (ret)
1729 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001730
1731 if (pf.flags[PERM_FLAG_IDX_DISABLE] && !enable)
1732 return 0;
1733
Kevin O'Connor846fd312016-08-10 18:15:13 -04001734 ret = tpm_simple_cmd(0, enable ? TPM_ORD_PhysicalEnable
1735 : TPM_ORD_PhysicalDisable,
1736 0, 0, TPM_DURATION_TYPE_SHORT);
Stefan Berger44250252016-01-07 12:02:51 -05001737 if (ret) {
1738 if (enable)
1739 dprintf(DEBUG_tcg, "TCGBIOS: Enabling the TPM failed.\n");
1740 else
1741 dprintf(DEBUG_tcg, "TCGBIOS: Disabling the TPM failed.\n");
1742 }
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001743 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001744}
1745
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001746static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001747tpm12_activate_tpm(int activate, int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001748{
Stefan Berger320df852015-11-30 11:14:19 -05001749 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001750 int ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001751 if (ret)
1752 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001753
1754 if (pf.flags[PERM_FLAG_IDX_DEACTIVATED] && !activate)
1755 return 0;
1756
1757 if (pf.flags[PERM_FLAG_IDX_DISABLE])
1758 return 0;
1759
Kevin O'Connor846fd312016-08-10 18:15:13 -04001760 ret = tpm_simple_cmd(0, TPM_ORD_PhysicalSetDeactivated,
1761 1, activate ? 0x00 : 0x01, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001762 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001763 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001764
1765 if (activate && allow_reset) {
1766 if (verbose) {
1767 printf("Requiring a reboot to activate the TPM.\n");
1768
1769 msleep(2000);
1770 }
1771 reset();
1772 }
1773
1774 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001775}
1776
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001777static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001778tpm12_enable_activate(int allow_reset, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001779{
Stefan Berger1d37d522016-02-02 13:09:11 -05001780 int ret = tpm12_enable_tpm(1, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001781 if (ret)
1782 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001783
Stefan Berger1d37d522016-02-02 13:09:11 -05001784 return tpm12_activate_tpm(1, allow_reset, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001785}
1786
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001787static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001788tpm12_force_clear(int enable_activate_before, int enable_activate_after,
1789 int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001790{
Stefan Berger320df852015-11-30 11:14:19 -05001791 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001792 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001793 if (ret)
1794 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001795 if (!has_owner) {
1796 if (verbose)
1797 printf("TPM does not have an owner.\n");
1798 return 0;
1799 }
1800
1801 if (enable_activate_before) {
Stefan Berger1d37d522016-02-02 13:09:11 -05001802 ret = tpm12_enable_activate(0, verbose);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001803 if (ret) {
Stefan Berger320df852015-11-30 11:14:19 -05001804 dprintf(DEBUG_tcg,
1805 "TCGBIOS: Enabling/activating the TPM failed.\n");
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001806 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001807 }
1808 }
1809
Kevin O'Connor846fd312016-08-10 18:15:13 -04001810 ret = tpm_simple_cmd(0, TPM_ORD_ForceClear,
1811 0, 0, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001812 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001813 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001814
1815 if (!enable_activate_after) {
1816 if (verbose)
1817 printf("Owner successfully cleared.\n"
1818 "You will need to enable/activate the TPM again.\n\n");
1819 return 0;
1820 }
1821
Stefan Berger1d37d522016-02-02 13:09:11 -05001822 return tpm12_enable_activate(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001823}
1824
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001825static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001826tpm12_set_owner_install(int allow, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001827{
Stefan Berger320df852015-11-30 11:14:19 -05001828 int has_owner;
Stefan Berger1d37d522016-02-02 13:09:11 -05001829 int ret = tpm12_read_has_owner(&has_owner);
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001830 if (ret)
1831 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001832 if (has_owner) {
1833 if (verbose)
1834 printf("Must first remove owner.\n");
1835 return 0;
1836 }
1837
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001838 struct tpm_permanent_flags pf;
Stefan Berger1d37d522016-02-02 13:09:11 -05001839 ret = tpm12_read_permanent_flags((char *)&pf, sizeof(pf));
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001840 if (ret)
1841 return -1;
Stefan Berger320df852015-11-30 11:14:19 -05001842
1843 if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
1844 if (verbose)
1845 printf("TPM must first be enable.\n");
1846 return 0;
1847 }
1848
Kevin O'Connor846fd312016-08-10 18:15:13 -04001849 ret = tpm_simple_cmd(0, TPM_ORD_SetOwnerInstall,
1850 1, allow ? 0x01 : 0x00, TPM_DURATION_TYPE_SHORT);
Kevin O'Connorcac29f22015-12-29 17:54:37 -05001851 if (ret)
Stefan Berger44250252016-01-07 12:02:51 -05001852 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001853
1854 if (verbose)
1855 printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
1856
1857 return 0;
Stefan Berger320df852015-11-30 11:14:19 -05001858}
1859
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001860static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001861tpm12_process_cfg(tpm_ppi_code msgCode, int verbose)
Stefan Berger320df852015-11-30 11:14:19 -05001862{
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001863 int ret = 0;
Stefan Berger320df852015-11-30 11:14:19 -05001864
1865 switch (msgCode) {
1866 case TPM_PPI_OP_NOOP: /* no-op */
1867 break;
1868
1869 case TPM_PPI_OP_ENABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001870 ret = tpm12_enable_tpm(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001871 break;
1872
1873 case TPM_PPI_OP_DISABLE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001874 ret = tpm12_enable_tpm(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001875 break;
1876
1877 case TPM_PPI_OP_ACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001878 ret = tpm12_activate_tpm(1, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001879 break;
1880
1881 case TPM_PPI_OP_DEACTIVATE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001882 ret = tpm12_activate_tpm(0, 1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001883 break;
1884
1885 case TPM_PPI_OP_CLEAR:
Stefan Berger1d37d522016-02-02 13:09:11 -05001886 ret = tpm12_force_clear(1, 0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001887 break;
1888
1889 case TPM_PPI_OP_SET_OWNERINSTALL_TRUE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001890 ret = tpm12_set_owner_install(1, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001891 break;
1892
1893 case TPM_PPI_OP_SET_OWNERINSTALL_FALSE:
Stefan Berger1d37d522016-02-02 13:09:11 -05001894 ret = tpm12_set_owner_install(0, verbose);
Stefan Berger320df852015-11-30 11:14:19 -05001895 break;
1896
1897 default:
1898 break;
1899 }
1900
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001901 if (ret)
1902 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
Stefan Berger320df852015-11-30 11:14:19 -05001903
Kevin O'Connor16a9e792015-12-29 23:04:15 -05001904 return ret;
Stefan Berger320df852015-11-30 11:14:19 -05001905}
1906
1907static int
Stefan Berger7d596dc2016-02-02 13:09:16 -05001908tpm20_clearcontrol(u8 disable, int verbose)
1909{
1910 struct tpm2_req_clearcontrol trc = {
1911 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1912 .hdr.totlen = cpu_to_be32(sizeof(trc)),
1913 .hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1914 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1915 .authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1916 .authblock = {
1917 .handle = cpu_to_be32(TPM2_RS_PW),
1918 .noncesize = cpu_to_be16(0),
1919 .contsession = TPM2_YES,
1920 .pwdsize = cpu_to_be16(0),
1921 },
1922 .disable = disable,
1923 };
1924 struct tpm_rsp_header rsp;
1925 u32 resp_length = sizeof(rsp);
1926 int ret = tpmhw_transmit(0, &trc.hdr, &rsp, &resp_length,
1927 TPM_DURATION_TYPE_SHORT);
1928 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1929 ret = -1;
1930
1931 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1932 ret);
1933
1934 return ret;
1935}
1936
1937static int
1938tpm20_clear(void)
1939{
1940 struct tpm2_req_clear trq = {
1941 .hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1942 .hdr.totlen = cpu_to_be32(sizeof(trq)),
1943 .hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1944 .authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1945 .authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1946 .authblock = {
1947 .handle = cpu_to_be32(TPM2_RS_PW),
1948 .noncesize = cpu_to_be16(0),
1949 .contsession = TPM2_YES,
1950 .pwdsize = cpu_to_be16(0),
1951 },
1952 };
1953 struct tpm_rsp_header rsp;
1954 u32 resp_length = sizeof(rsp);
1955 int ret = tpmhw_transmit(0, &trq.hdr, &rsp, &resp_length,
1956 TPM_DURATION_TYPE_MEDIUM);
1957 if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1958 ret = -1;
1959
1960 dprintf(DEBUG_tcg, "TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1961 ret);
1962
1963 return ret;
1964}
1965
1966static int
1967tpm20_process_cfg(tpm_ppi_code msgCode, int verbose)
1968{
1969 int ret = 0;
1970
1971 switch (msgCode) {
1972 case TPM_PPI_OP_NOOP: /* no-op */
1973 break;
1974
1975 case TPM_PPI_OP_CLEAR:
1976 ret = tpm20_clearcontrol(0, verbose);
1977 if (!ret)
1978 ret = tpm20_clear();
1979 break;
1980 }
1981
1982 if (ret)
1983 printf("Op %d: An error occurred: 0x%x\n", msgCode, ret);
1984
1985 return ret;
1986}
1987
1988static int
Stefan Berger1d37d522016-02-02 13:09:11 -05001989tpm12_get_tpm_state(void)
Stefan Berger320df852015-11-30 11:14:19 -05001990{
1991 int state = 0;
1992 struct tpm_permanent_flags pf;
1993 int has_owner;
1994
Stefan Berger1d37d522016-02-02 13:09:11 -05001995 if (tpm12_read_permanent_flags((char *)&pf, sizeof(pf)) ||
1996 tpm12_read_has_owner(&has_owner))
Stefan Berger320df852015-11-30 11:14:19 -05001997 return ~0;
1998
1999 if (!pf.flags[PERM_FLAG_IDX_DISABLE])
2000 state |= TPM_STATE_ENABLED;
2001
2002 if (!pf.flags[PERM_FLAG_IDX_DEACTIVATED])
2003 state |= TPM_STATE_ACTIVE;
2004
2005 if (has_owner) {
2006 state |= TPM_STATE_OWNED;
2007 } else {
2008 if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
2009 state |= TPM_STATE_OWNERINSTALL;
2010 }
2011
2012 return state;
2013}
2014
2015static void
Stefan Berger1d37d522016-02-02 13:09:11 -05002016tpm12_show_tpm_menu(int state, int next_scancodes[7])
Stefan Berger320df852015-11-30 11:14:19 -05002017{
2018 int i = 0;
2019
2020 printf("\nThe current state of the TPM is:\n");
2021
2022 if (state & TPM_STATE_ENABLED)
2023 printf(" Enabled");
2024 else
2025 printf(" Disabled");
2026
2027 if (state & TPM_STATE_ACTIVE)
2028 printf(" and active\n");
2029 else
2030 printf(" and deactivated\n");
2031
2032 if (state & TPM_STATE_OWNED)
2033 printf(" Ownership has been taken\n");
2034 else {
2035 printf(" Ownership has not been taken\n");
2036 if (state & TPM_STATE_OWNERINSTALL)
2037 printf(" A user can take ownership of the TPM\n");
2038 else
2039 printf(" Taking ownership of the TPM has been disabled\n");
2040 }
2041
2042 if ((state & (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) !=
2043 (TPM_STATE_ENABLED | TPM_STATE_ACTIVE)) {
2044 printf("\nNote: To make use of all functionality, the TPM must be "
2045 "enabled and active.\n");
2046 }
2047
2048 printf("\nAvailable options are:\n");
2049 if (state & TPM_STATE_ENABLED) {
2050 printf(" d. Disable the TPM\n");
2051 next_scancodes[i++] = 32;
2052
2053 if (state & TPM_STATE_ACTIVE) {
2054 printf(" v. Deactivate the TPM\n");
2055 next_scancodes[i++] = 47;
2056
2057 if (state & TPM_STATE_OWNERINSTALL) {
2058 printf(" p. Prevent installation of an owner\n");
2059 next_scancodes[i++] = 25;
2060 } else {
2061 printf(" s. Allow installation of an owner\n");
2062 next_scancodes[i++] = 31;
2063 }
2064 } else {
2065 printf(" a. Activate the TPM\n");
2066 next_scancodes[i++] = 30;
2067 }
2068
2069 } else {
2070 printf(" e. Enable the TPM\n");
2071 next_scancodes[i++] = 18;
2072 }
2073
2074 if (state & TPM_STATE_OWNED) {
2075 printf(" c. Clear ownership\n");
2076 next_scancodes[i++] = 46;
2077 }
2078
2079 next_scancodes[i++] = 0;
2080}
2081
Stefan Berger1d37d522016-02-02 13:09:11 -05002082static void
2083tpm12_menu(