1 /*****************************************************************************
2  * Copyright (c) 2015-2020 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *     Stefan Berger, stefanb@linux.ibm.com
12  *     Kevin O'Connor, kevin@koconnor.net
13  *****************************************************************************/
14 
15 /*
16  *  Implementation of the TPM BIOS extension according to the specification
17  *  described in the IBM VTPM Firmware document and the TCG Specification
18  *  that can be found here under the following link:
19  *  https://trustedcomputinggroup.org/resource/pc-client-work-group-specific-implementation-specification-for-conventional-bios/
20  */
21 
22 #include <stddef.h>
23 #include <stdlib.h>
24 
25 #include "types.h"
26 #include "byteorder.h"
27 #include "tpm_drivers.h"
28 #include "string.h"
29 #include "tcgbios.h"
30 #include "tcgbios_int.h"
31 #include "stdio.h"
32 #include "sha256.h"
33 #include "helpers.h"
34 #include "version.h"
35 #include "OF.h"
36 #include "libelf.h"
37 
38 #undef TCGBIOS_DEBUG
39 //#define TCGBIOS_DEBUG
40 #ifdef TCGBIOS_DEBUG
41 #define dprintf(_x ...) do { printf("TCGBIOS: " _x); } while(0)
42 #else
43 #define dprintf(_x ...)
44 #endif
45 
46 static struct {
47 	unsigned tpm_probed:1;
48 	unsigned tpm_found:1;
49 	unsigned tpm_working:1;
50 
51 	/* base address of the log area */
52 	uint8_t *log_base;
53 
54 	/* size of the logging area */
55 	size_t log_area_size;
56 
57 	/* where to write the next log entry to */
58 	uint8_t *log_area_next_entry;
59 
60 	/* PCR selection as received from TPM */
61 	uint32_t tpm20_pcr_selection_size;
62 	struct tpml_pcr_selection *tpm20_pcr_selection;
63 } tpm_state;
64 
65 #define TPM2_ALG_SHA1_FLAG          (1 << 0)
66 #define TPM2_ALG_SHA256_FLAG        (1 << 1)
67 #define TPM2_ALG_SHA384_FLAG        (1 << 2)
68 #define TPM2_ALG_SHA512_FLAG        (1 << 3)
69 #define TPM2_ALG_SM3_256_FLAG       (1 << 4)
70 #define TPM2_ALG_SHA3_256_FLAG      (1 << 5)
71 #define TPM2_ALG_SHA3_384_FLAG      (1 << 6)
72 #define TPM2_ALG_SHA3_512_FLAG      (1 << 7)
73 
74 static const uint8_t ZeroGuid[16] = { 0 };
75 
76 static UEFI_GPT_DATA *uefi_gpt_data;
77 static size_t uefi_gpt_data_size;
78 
79 /*
80  * TPM 2 logs are written in little endian format.
81  */
log32_to_cpu(uint32_t val)82 static inline uint32_t log32_to_cpu(uint32_t val)
83 {
84 	return le32_to_cpu(val);
85 }
86 
cpu_to_log32(uint32_t val)87 static inline uint32_t cpu_to_log32(uint32_t val)
88 {
89 	return cpu_to_le32(val);
90 }
91 
cpu_to_log16(uint16_t val)92 static inline uint16_t cpu_to_log16(uint16_t val)
93 {
94 	return cpu_to_le16(val);
95 }
96 
97 /********************************************************
98   Extensions for TCG-enabled BIOS
99  *******************************************************/
100 
probe_tpm(void)101 static void probe_tpm(void)
102 {
103 	tpm_state.tpm_probed = true;
104 	tpm_state.tpm_found = spapr_is_vtpm_present();
105 	tpm_state.tpm_working = tpm_state.tpm_found;
106 }
107 
108 /****************************************************************
109  * Digest formatting
110  ****************************************************************/
111 
112 /* A 'struct tpm_log_entry' is a local data structure containing a
113  * 'TCG_PCR_EVENT2_Header' followed by space for the maximum supported
114  * digest. The digest is a series of TPMT_HA structs on tpm2.0.
115  */
116 struct tpm_log_entry {
117 	TCG_PCR_EVENT2_Header hdr;
118 	uint8_t pad[sizeof(struct TPML_DIGEST_VALUES)
119 	   + 8 * sizeof(struct TPMT_HA)
120 	   + SHA1_BUFSIZE + SHA256_BUFSIZE + SHA384_BUFSIZE
121 	   + SHA512_BUFSIZE + SM3_256_BUFSIZE + SHA3_256_BUFSIZE
122 	   + SHA3_384_BUFSIZE + SHA3_512_BUFSIZE];
123 } __attribute__((packed));
124 
125 static const struct hash_parameters {
126 	uint16_t hashalg;
127 	uint8_t  hashalg_flag;
128 	uint8_t  hash_buffersize;
129 	const char *name;
130 } hash_parameters[] = {
131 	{
132 		.hashalg = TPM2_ALG_SHA1,
133 		.hashalg_flag = TPM2_ALG_SHA1_FLAG,
134 		.hash_buffersize = SHA1_BUFSIZE,
135 		.name = "SHA1",
136 	}, {
137 		.hashalg = TPM2_ALG_SHA256,
138 		.hashalg_flag = TPM2_ALG_SHA256_FLAG,
139 		.hash_buffersize = SHA256_BUFSIZE,
140 		.name = "SHA256",
141 	}, {
142 		.hashalg = TPM2_ALG_SHA384,
143 		.hashalg_flag = TPM2_ALG_SHA384_FLAG,
144 		.hash_buffersize = SHA384_BUFSIZE,
145 		.name = "SHA384",
146 
147 	}, {
148 		.hashalg = TPM2_ALG_SHA512,
149 		.hashalg_flag = TPM2_ALG_SHA512_FLAG,
150 		.hash_buffersize = SHA512_BUFSIZE,
151 		.name = "SHA512",
152 	}, {
153 		.hashalg = TPM2_ALG_SM3_256,
154 		.hashalg_flag = TPM2_ALG_SM3_256_FLAG,
155 		.hash_buffersize = SM3_256_BUFSIZE,
156 		.name = "SM3-256",
157 	}, {
158 		.hashalg = TPM2_ALG_SHA3_256,
159 		.hashalg_flag = TPM2_ALG_SHA3_256_FLAG,
160 		.hash_buffersize = SHA3_256_BUFSIZE,
161 		.name = "SHA3-256",
162 	}, {
163 		.hashalg = TPM2_ALG_SHA3_384,
164 		.hashalg_flag = TPM2_ALG_SHA3_384_FLAG,
165 		.hash_buffersize = SHA3_384_BUFSIZE,
166 		.name = "SHA3-384",
167 	}, {
168 		.hashalg = TPM2_ALG_SHA3_512,
169 		.hashalg_flag = TPM2_ALG_SHA3_512_FLAG,
170 		.hash_buffersize = SHA3_512_BUFSIZE,
171 		.name = "SHA3-512",
172 	}
173 };
174 
tpm20_find_by_hashalg(uint16_t hashAlg)175 static const struct hash_parameters *tpm20_find_by_hashalg(uint16_t hashAlg)
176 {
177 	unsigned i;
178 
179 	for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
180 		if (hash_parameters[i].hashalg == hashAlg)
181 			return &hash_parameters[i];
182 	}
183 	return NULL;
184 }
185 
186 static const struct hash_parameters *
tpm20_find_by_hashalg_flag(uint16_t hashalg_flag)187 tpm20_find_by_hashalg_flag(uint16_t hashalg_flag)
188 {
189 	unsigned i;
190 
191 	for (i = 0; i < ARRAY_SIZE(hash_parameters); i++) {
192 		if (hash_parameters[i].hashalg_flag == hashalg_flag)
193 			return &hash_parameters[i];
194 	}
195 	return NULL;
196 }
197 
tpm20_get_hash_buffersize(uint16_t hashAlg)198 static inline int tpm20_get_hash_buffersize(uint16_t hashAlg)
199 {
200 	const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg);
201 
202 	if (hp)
203 		return hp->hash_buffersize;
204 	return -1;
205 }
206 
tpm20_hashalg_to_flag(uint16_t hashAlg)207 static inline uint8_t tpm20_hashalg_to_flag(uint16_t hashAlg)
208 {
209 	const struct hash_parameters *hp = tpm20_find_by_hashalg(hashAlg);
210 
211 	if (hp)
212 		return hp->hashalg_flag;
213 	return 0;
214 }
215 
tpm20_hashalg_flag_to_hashalg(uint8_t hashalg_flag)216 static uint16_t tpm20_hashalg_flag_to_hashalg(uint8_t hashalg_flag)
217 {
218 	const struct hash_parameters *hp;
219 
220 	hp = tpm20_find_by_hashalg_flag(hashalg_flag);
221 	if (hp)
222 		return hp->hashalg;
223 	return 0;
224 }
225 
tpm20_hashalg_flag_to_name(uint8_t hashalg_flag)226 static const char * tpm20_hashalg_flag_to_name(uint8_t hashalg_flag)
227 {
228 	const struct hash_parameters *hp;
229 
230 	hp = tpm20_find_by_hashalg_flag(hashalg_flag);
231 	if (hp)
232 		return hp->name;
233 	return NULL;
234 }
235 
236 /*
237  * Build the TPM2 TPML_DIGEST_VALUES data structure from the given hash.
238  * Follow the PCR bank configuration of the TPM and write the same hash
239  * in either truncated or zero-padded form in the areas of all the other
240  * hashes. For example, write the sha256 hash in the area of the sha384
241  * hash and fill the remaining bytes with zeros. Or truncate the sha256
242  * hash when writing it in the area of the sha1 hash.
243  *
244  * le: the log entry to build the digest in
245  * sha1: the sha1 hash value to use
246  * bigEndian: whether to build in big endian format for the TPM or log
247  *            little endian for the log (TPM 2.0)
248  *
249  * Returns the digest size; -1 on fatal error
250  */
tpm20_build_digest(struct tpm_log_entry * le,const uint8_t * sha256,bool bigEndian)251 static int tpm20_build_digest(struct tpm_log_entry *le, const uint8_t *sha256,
252 			      bool bigEndian)
253 {
254 	struct tpms_pcr_selection *sel;
255 	void *nsel, *end;
256 	void *dest = le->hdr.digests + sizeof(struct TPML_DIGEST_VALUES);
257 	uint32_t count, numAlgs;
258 	struct TPMT_HA *v;
259 	struct TPML_DIGEST_VALUES *vs;
260 
261 	sel = tpm_state.tpm20_pcr_selection->selections;
262 	end = (void *)tpm_state.tpm20_pcr_selection +
263 		tpm_state.tpm20_pcr_selection_size;
264 
265 	for (count = 0, numAlgs = 0;
266 	     count < be32_to_cpu(tpm_state.tpm20_pcr_selection->count);
267 	     count++) {
268 		int hsize;
269 		uint8_t sizeOfSelect = sel->sizeOfSelect;
270 
271 		nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
272 		if (nsel > end)
273 			break;
274 
275 		/* PCR 0-7 unused ? -- skip */
276 		if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
277 			sel = nsel;
278 			continue;
279 		}
280 
281 		hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
282 		if (hsize < 0) {
283 			dprintf("TPM is using an unsupported hash: %d\n",
284 				be16_to_cpu(sel->hashAlg));
285 			return -1;
286 		}
287 
288 		/* buffer size sanity check before writing */
289 		v = dest;
290 		if (dest + sizeof(*v) + hsize > (void*)le + sizeof(*le)) {
291 			dprintf("tpm_log_entry is too small\n");
292 			return -1;
293 		}
294 
295 		if (bigEndian)
296 			v->hashAlg = sel->hashAlg;
297 		else
298 			v->hashAlg = cpu_to_le16(be16_to_cpu(sel->hashAlg));
299 
300 		memset(v->hash, 0, hsize);
301 		memcpy(v->hash, sha256,
302 		       hsize < SHA256_BUFSIZE ? hsize : SHA256_BUFSIZE);
303 
304 		dest += sizeof(*v) + hsize;
305 		sel = nsel;
306 
307 		numAlgs++;
308 	}
309 
310 	if (sel != end) {
311 		dprintf("Malformed pcr selection structure fron TPM\n");
312 		return -1;
313 	}
314 
315 	vs = (void*)le->hdr.digests;
316 	if (bigEndian)
317 		vs->count = cpu_to_be32(numAlgs);
318 	else
319 		vs->count = cpu_to_le32(numAlgs);
320 
321 	return dest - (void*)le->hdr.digests;
322 }
323 
324 /****************************************************************
325  * TPM hardware command wrappers
326  ****************************************************************/
327 
328 /* Helper function for sending TPM commands that take a single
329  * optional parameter (0, 1, or 2 bytes) and have no special response.
330  */
331 static int
tpm_simple_cmd(uint8_t locty,uint32_t ordinal,int param_size,uint16_t param,enum tpm_duration_type to_t)332 tpm_simple_cmd(uint8_t locty, uint32_t ordinal, int param_size, uint16_t param,
333 	       enum tpm_duration_type to_t)
334 {
335 	struct {
336 		struct tpm_req_header trqh;
337 		uint16_t param;
338 	} __attribute__((packed)) req = {
339 		.trqh.totlen = cpu_to_be32(sizeof(req.trqh) + param_size),
340 		.trqh.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
341 		.trqh.ordinal = cpu_to_be32(ordinal),
342 	};
343 	uint8_t obuffer[64];
344 	struct tpm_rsp_header *trsh = (void *)obuffer;
345 	uint32_t obuffer_len = sizeof(obuffer);
346 	int ret;
347 
348 	switch (param_size) {
349 	case 2:
350 		req.param = cpu_to_be16(param);
351 		break;
352 	case 1:
353 		*(uint8_t *)&req.param = param;
354 		break;
355 	}
356 
357 	memset(obuffer, 0, sizeof(obuffer));
358 	ret = spapr_transmit(locty, &req.trqh, obuffer, &obuffer_len, to_t);
359 	ret = ret ? -1 : (int) be32_to_cpu(trsh->errcode);
360 	dprintf("Return from tpm_simple_cmd(%x, %x) = %x\n",
361 		ordinal, param, ret);
362 
363 	return ret;
364 }
365 
366 static int
tpm20_getcapability(uint32_t capability,uint32_t property,uint32_t count,struct tpm_rsp_header * rsp,uint32_t rsize)367 tpm20_getcapability(uint32_t capability, uint32_t property, uint32_t count,
368 	            struct tpm_rsp_header *rsp, uint32_t rsize)
369 {
370 	struct tpm2_req_getcapability trg = {
371 		.hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
372 		.hdr.totlen = cpu_to_be32(sizeof(trg)),
373 		.hdr.ordinal = cpu_to_be32(TPM2_CC_GetCapability),
374 		.capability = cpu_to_be32(capability),
375 		.property = cpu_to_be32(property),
376 		.propertycount = cpu_to_be32(count),
377 	};
378 	uint32_t resp_size = rsize;
379 	int ret;
380 
381 	ret = spapr_transmit(0, &trg.hdr, rsp, &resp_size,
382 			     TPM_DURATION_TYPE_SHORT);
383 	ret = (ret ||
384 	       rsize < be32_to_cpu(rsp->totlen)) ? -1
385 						 : (int) be32_to_cpu(rsp->errcode);
386 
387 	dprintf("TCGBIOS: Return value from sending TPM2_CC_GetCapability = 0x%08x\n",
388 		ret);
389 
390 	return ret;
391 }
392 
393 static int
tpm20_get_pcrbanks(void)394 tpm20_get_pcrbanks(void)
395 {
396 	uint8_t buffer[128];
397 	uint32_t size;
398 	struct tpm2_res_getcapability *trg =
399 		(struct tpm2_res_getcapability *)&buffer;
400 	uint32_t resplen;
401 	int ret;
402 
403 	ret = tpm20_getcapability(TPM2_CAP_PCRS, 0, 8, &trg->hdr,
404 				  sizeof(buffer));
405 	if (ret)
406 		return ret;
407 
408 	/* defend against (broken) TPM sending packets that are too short */
409 	resplen = be32_to_cpu(trg->hdr.totlen);
410 	if (resplen <= offset_of(struct tpm2_res_getcapability, data))
411 		return -1;
412 
413 	size = resplen - offset_of(struct tpm2_res_getcapability, data);
414 	/* we need a valid tpml_pcr_selection up to and including sizeOfSelect*/
415 	if (size < offset_of(struct tpml_pcr_selection, selections) +
416 		   offset_of(struct tpms_pcr_selection, pcrSelect))
417 		return -1;
418 
419 	tpm_state.tpm20_pcr_selection = SLOF_alloc_mem(size);
420 	if (tpm_state.tpm20_pcr_selection) {
421 		memcpy(tpm_state.tpm20_pcr_selection, &trg->data, size);
422 		tpm_state.tpm20_pcr_selection_size = size;
423 	} else {
424 		printf("TCGBIOS: Failed to allocated %u bytes.\n", size);
425 		return -1;
426 	}
427 
428 	return 0;
429 }
430 
tpm20_extend(struct tpm_log_entry * le,int digest_len)431 static int tpm20_extend(struct tpm_log_entry *le, int digest_len)
432 {
433 	struct tpm2_req_extend tmp_tre = {
434 		.hdr.tag     = cpu_to_be16(TPM2_ST_SESSIONS),
435 		.hdr.totlen  = cpu_to_be32(0),
436 		.hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Extend),
437 		.pcrindex    = cpu_to_be32(log32_to_cpu(le->hdr.pcrindex)),
438 		.authblocksize = cpu_to_be32(sizeof(tmp_tre.authblock)),
439 		.authblock = {
440 			.handle = cpu_to_be32(TPM2_RS_PW),
441 			.noncesize = cpu_to_be16(0),
442 			.contsession = TPM2_YES,
443 			.pwdsize = cpu_to_be16(0),
444 		},
445 	};
446 	uint8_t buffer[sizeof(tmp_tre) + sizeof(le->pad)];
447 	struct tpm2_req_extend *tre = (struct tpm2_req_extend *)buffer;
448 	struct tpm_rsp_header rsp;
449 	uint32_t resp_length = sizeof(rsp);
450 	int ret;
451 
452 	memcpy(tre, &tmp_tre, sizeof(tmp_tre));
453 	memcpy(&tre->digest[0], le->hdr.digests, digest_len);
454 
455 	tre->hdr.totlen = cpu_to_be32(sizeof(tmp_tre) + digest_len);
456 
457 	ret = spapr_transmit(0, &tre->hdr, &rsp, &resp_length,
458 			     TPM_DURATION_TYPE_SHORT);
459 	if (ret || resp_length != sizeof(rsp) || rsp.errcode)
460 		return -1;
461 
462 	return 0;
463 }
464 
tpm20_stirrandom(void)465 static int tpm20_stirrandom(void)
466 {
467 	struct tpm2_req_stirrandom stir = {
468 		.hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
469 		.hdr.totlen = cpu_to_be32(sizeof(stir)),
470 		.hdr.ordinal = cpu_to_be32(TPM2_CC_StirRandom),
471 		.size = cpu_to_be16(sizeof(stir.stir)),
472 		.stir = rand(),
473 	};
474 	struct tpm_rsp_header rsp;
475 	uint32_t resp_length = sizeof(rsp);
476 	int ret = spapr_transmit(0, &stir.hdr, &rsp, &resp_length,
477 				 TPM_DURATION_TYPE_SHORT);
478 
479 	if (ret || resp_length != sizeof(rsp) || rsp.errcode)
480 		ret = -1;
481 
482 	dprintf("TCGBIOS: Return value from sending TPM2_CC_StirRandom = 0x%08x\n",
483 		ret);
484 
485 	return ret;
486 }
487 
tpm20_getrandom(uint8_t * buf,uint16_t buf_len)488 static int tpm20_getrandom(uint8_t *buf, uint16_t buf_len)
489 {
490 	struct tpm2_res_getrandom rsp;
491 	struct tpm2_req_getrandom trgr = {
492 		.hdr.tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
493 		.hdr.totlen = cpu_to_be32(sizeof(trgr)),
494 		.hdr.ordinal = cpu_to_be32(TPM2_CC_GetRandom),
495 		.bytesRequested = cpu_to_be16(buf_len),
496 	};
497 	uint32_t resp_length = sizeof(rsp);
498 	int ret;
499 
500 	if (buf_len > sizeof(rsp.rnd.buffer))
501 		return -1;
502 
503 	ret = spapr_transmit(0, &trgr.hdr, &rsp, &resp_length,
504 			     TPM_DURATION_TYPE_MEDIUM);
505 	if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode)
506 		ret = -1;
507 	else
508 		memcpy(buf, rsp.rnd.buffer, buf_len);
509 
510 	dprintf("TCGBIOS: Return value from sending TPM2_CC_GetRandom = 0x%08x\n",
511 		ret);
512 
513 	return ret;
514 }
515 
tpm20_hierarchychangeauth(uint8_t auth[20])516 static int tpm20_hierarchychangeauth(uint8_t auth[20])
517 {
518 	struct tpm2_req_hierarchychangeauth trhca = {
519 		.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
520 		.hdr.totlen = cpu_to_be32(sizeof(trhca)),
521 		.hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyChangeAuth),
522 		.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
523 		.authblocksize = cpu_to_be32(sizeof(trhca.authblock)),
524 		.authblock = {
525 			.handle = cpu_to_be32(TPM2_RS_PW),
526 			.noncesize = cpu_to_be16(0),
527 			.contsession = TPM2_YES,
528 			.pwdsize = cpu_to_be16(0),
529 		},
530 		.newAuth = {
531 			.size = cpu_to_be16(sizeof(trhca.newAuth.buffer)),
532 		},
533 	};
534 	struct tpm_rsp_header rsp;
535 	uint32_t resp_length = sizeof(rsp);
536 	int ret;
537 
538 	memcpy(trhca.newAuth.buffer, auth, sizeof(trhca.newAuth.buffer));
539 
540 	ret = spapr_transmit(0, &trhca.hdr, &rsp, &resp_length,
541 			     TPM_DURATION_TYPE_MEDIUM);
542 	if (ret || resp_length != sizeof(rsp) || rsp.errcode)
543 		ret = -1;
544 
545 	dprintf("TCGBIOS: Return value from sending TPM2_CC_HierarchyChangeAuth = 0x%08x\n",
546 		ret);
547 
548 	return ret;
549 }
550 
tpm20_hierarchycontrol(uint32_t hierarchy,uint8_t state)551 static int tpm20_hierarchycontrol(uint32_t hierarchy, uint8_t state)
552 {
553 	struct tpm2_req_hierarchycontrol trh = {
554 		.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
555 		.hdr.totlen = cpu_to_be32(sizeof(trh)),
556 		.hdr.ordinal = cpu_to_be32(TPM2_CC_HierarchyControl),
557 		.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
558 		.authblocksize = cpu_to_be32(sizeof(trh.authblock)),
559 		.authblock = {
560 			.handle = cpu_to_be32(TPM2_RS_PW),
561 			.noncesize = cpu_to_be16(0),
562 			.contsession = TPM2_YES,
563 			.pwdsize = cpu_to_be16(0),
564 		},
565 		.enable = cpu_to_be32(hierarchy),
566 		.state = state,
567 	};
568 	struct tpm_rsp_header rsp;
569 	uint32_t resp_length = sizeof(rsp);
570 	int ret;
571 
572 	ret = spapr_transmit(0, &trh.hdr, &rsp, &resp_length,
573 			     TPM_DURATION_TYPE_MEDIUM);
574 	if (ret || resp_length != sizeof(rsp) || rsp.errcode)
575 		ret = -1;
576 
577 	dprintf("TCGBIOS: Return value from sending TPM2_CC_HierarchyControl = 0x%08x\n",
578 		ret);
579 
580 	return ret;
581 }
582 
583 /****************************************************************
584  * Setup and Measurements
585  ****************************************************************/
586 
tpm_is_working(void)587 bool tpm_is_working(void)
588 {
589 	if (!tpm_state.tpm_probed)
590 		probe_tpm();
591 
592 	return tpm_state.tpm_working;
593 }
594 
tpm_set_failure(void)595 static void tpm_set_failure(void)
596 {
597 	tpm20_hierarchycontrol(TPM2_RH_ENDORSEMENT, TPM2_NO);
598 	tpm20_hierarchycontrol(TPM2_RH_OWNER, TPM2_NO);
599 
600 	tpm_state.tpm_working = false;
601 }
602 
603 /*
604  * Extend the OFDT log with the given entry by copying the
605  * entry data into the log.
606  *
607  * @pcpes: Pointer to the structure to be copied into the log
608  * @event: The event to be appended to 'pcpes'
609  * @event_length: The length of the event
610  *
611  * Returns 0 on success, an error code otherwise.
612  */
tpm_log_event_long(TCG_PCR_EVENT2_Header * entry,int digest_len,const void * event,uint32_t event_length)613 static uint32_t tpm_log_event_long(TCG_PCR_EVENT2_Header *entry,
614 				   int digest_len,
615 				   const void *event, uint32_t event_length)
616 {
617 	size_t size, logsize;
618 	void *dest;
619 	TCG_PCR_EVENT2_Trailer *t;
620 
621 	dprintf("log base address = %p, next entry = %p\n",
622 		tpm_state.log_base, tpm_state.log_area_next_entry);
623 
624 	if (tpm_state.log_area_next_entry == NULL)
625 		return TCGBIOS_LOGOVERFLOW;
626 
627 	size = sizeof(*entry) + digest_len +
628 	       sizeof(TCG_PCR_EVENT2_Trailer) + event_length;
629 	logsize = (tpm_state.log_area_next_entry + size -
630 	           tpm_state.log_base);
631 	if (logsize > tpm_state.log_area_size) {
632 		dprintf("TCGBIOS: LOG OVERFLOW: size = %zu\n", size);
633 		return TCGBIOS_LOGOVERFLOW;
634 	}
635 
636 	dest = tpm_state.log_area_next_entry;
637 	memcpy(dest, entry, sizeof(*entry) + digest_len);
638 
639 	t = dest + sizeof(*entry) + digest_len;
640 	t->eventdatasize = cpu_to_log32(event_length);
641 	if (event_length)
642 		memcpy(t->event, event, event_length);
643 
644 	tpm_state.log_area_next_entry += size;
645 
646 	return 0;
647 }
648 
649 /* Add an entry at the start of the log describing digest formats
650  */
tpm20_write_EfiSpecIdEventStruct(void)651 static int tpm20_write_EfiSpecIdEventStruct(void)
652 {
653 	struct {
654 		struct TCG_EfiSpecIdEventStruct hdr;
655 		uint32_t pad[sizeof(struct tpm_log_entry) +
656 		             sizeof(uint8_t)];
657 	} event = {
658 		.hdr.signature = "Spec ID Event03",
659 		.hdr.platformClass = TPM_TCPA_ACPI_CLASS_CLIENT,
660 		.hdr.specVersionMinor = 0,
661 		.hdr.specVersionMajor = 2,
662 		.hdr.specErrata = 0,
663 		.hdr.uintnSize = 2,
664 	};
665 	struct tpms_pcr_selection *sel;
666 	void *nsel, *end;
667 	unsigned event_size;
668 	uint8_t *vendorInfoSize;
669 	struct tpm_log_entry le = {
670 		.hdr.eventtype = cpu_to_log32(EV_NO_ACTION),
671 	};
672 	uint32_t count, numAlgs;
673 
674 	sel = tpm_state.tpm20_pcr_selection->selections;
675 	end = (void*)tpm_state.tpm20_pcr_selection +
676 	      tpm_state.tpm20_pcr_selection_size;
677 
678 	for (count = 0, numAlgs = 0;
679 	     count < be32_to_cpu(tpm_state.tpm20_pcr_selection->count);
680 	     count++) {
681 		int hsize;
682 		uint8_t sizeOfSelect = sel->sizeOfSelect;
683 
684 		nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
685 		if (nsel > end)
686 			break;
687 
688 		/* PCR 0-7 unused ? -- skip */
689 		if (!sizeOfSelect || sel->pcrSelect[0] == 0) {
690 			sel = nsel;
691 			continue;
692 		}
693 
694 		hsize = tpm20_get_hash_buffersize(be16_to_cpu(sel->hashAlg));
695 		if (hsize < 0) {
696 			dprintf("TPM is using an unsupported hash: %d\n",
697 				be16_to_cpu(sel->hashAlg));
698 			return -1;
699 		}
700 
701 		event_size = offset_of(struct TCG_EfiSpecIdEventStruct,
702 				       digestSizes[count+1]);
703 		if (event_size > sizeof(event) - sizeof(uint8_t)) {
704 			dprintf("EfiSpecIdEventStruct pad too small\n");
705 			return -1;
706 		}
707 
708 		event.hdr.digestSizes[numAlgs].algorithmId =
709 			cpu_to_log16(be16_to_cpu(sel->hashAlg));
710 		event.hdr.digestSizes[numAlgs].digestSize = cpu_to_log16(hsize);
711 		numAlgs++;
712 
713 		sel = nsel;
714 	}
715 
716 	if (sel != end) {
717 		dprintf("Malformed pcr selection structure fron TPM\n");
718 		return -1;
719 	}
720 
721 	event.hdr.numberOfAlgorithms = cpu_to_log32(numAlgs);
722 	event_size = offset_of(struct TCG_EfiSpecIdEventStruct,
723 			       digestSizes[numAlgs]);
724 	vendorInfoSize = (void*)&event + event_size;
725 	*vendorInfoSize = 0;
726 	event_size += sizeof(*vendorInfoSize);
727 
728 	return tpm_log_event_long(&le.hdr, SHA1_BUFSIZE, &event, event_size);
729 }
730 
tpm20_startup(void)731 static int tpm20_startup(void)
732 {
733 	int ret;
734 
735 	ret = tpm_simple_cmd(0, TPM2_CC_Startup,
736 			     2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
737 	dprintf("TCGBIOS: Return value from sending TPM2_CC_Startup(SU_CLEAR) = 0x%08x\n",
738 		ret);
739 
740 	if (ret)
741 		goto err_exit;
742 
743 	ret = tpm_simple_cmd(0, TPM2_CC_SelfTest,
744 			     1, TPM2_YES, TPM_DURATION_TYPE_LONG);
745 
746 	dprintf("TCGBIOS: Return value from sending TPM2_CC_SELF_TEST = 0x%08x\n",
747 		ret);
748 
749 	if (ret)
750 		goto err_exit;
751 
752 	ret = tpm20_get_pcrbanks();
753 	if (ret)
754 		goto err_exit;
755 
756 	/* the log parameters will be passed from Forth layer */
757 
758 	return 0;
759 
760 err_exit:
761 	dprintf("TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
762 
763 	tpm_set_failure();
764 	return -1;
765 }
766 
tpm_start(void)767 uint32_t tpm_start(void)
768 {
769 	probe_tpm();
770 
771 	if (!tpm_is_working()) {
772 		dprintf("%s: Machine does not have a working TPM\n",
773 			__func__);
774 		return TCGBIOS_FATAL_COM_ERROR;
775 	}
776 
777 	return tpm20_startup();
778 }
779 
tpm_finalize(void)780 void tpm_finalize(void)
781 {
782 	spapr_vtpm_finalize();
783 }
784 
tpm20_prepboot(void)785 static void tpm20_prepboot(void)
786 {
787 	uint8_t auth[20];
788 	int ret;
789 
790 	ret = tpm20_stirrandom();
791 	if (ret)
792 		 goto err_exit;
793 
794 	ret = tpm20_getrandom(&auth[0], sizeof(auth));
795 	if (ret)
796 		goto err_exit;
797 
798 	ret = tpm20_hierarchychangeauth(auth);
799 	if (ret)
800 		goto err_exit;
801 
802 	return;
803 
804 err_exit:
805 	dprintf("TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
806 
807 	tpm_set_failure();
808 }
809 
810 /*
811  * Prepare TPM for boot; this function has to be called before
812  * the firmware transitions to the boot loader.
813  */
tpm_leave_firmware(void)814 uint32_t tpm_leave_firmware(void)
815 {
816 	tpm20_prepboot();
817 
818 	return 0;
819 }
820 
821 /****************************************************************
822  * Forth interface
823  ****************************************************************/
824 
tpm_set_log_parameters(void * addr,size_t size)825 void tpm_set_log_parameters(void *addr, size_t size)
826 {
827 	int ret;
828 
829 	dprintf("Log is at 0x%llx; size is %zu bytes\n",
830 		(uint64_t)addr, size);
831 	tpm_state.log_base = addr;
832 	tpm_state.log_area_next_entry = addr;
833 	tpm_state.log_area_size = size;
834 
835 	ret = tpm20_write_EfiSpecIdEventStruct();
836 	if (ret)
837 		tpm_set_failure();
838 }
839 
tpm_get_logsize(void)840 uint32_t tpm_get_logsize(void)
841 {
842 	uint32_t logsize = tpm_state.log_area_next_entry - tpm_state.log_base;
843 
844 	dprintf("log size: %u\n", logsize);
845 
846 	return logsize;
847 }
848 
849 /*
850  * Add a measurement to the log;
851  *
852  * Input parameters:
853  *  @pcrindex : PCR to extend
854  *  @event_type : type of event
855  *  @info : pointer to info (i.e., string) to be added to the log as-is
856  *  @info_length: length of the info
857  *  @hashdata : pointer to data to be hashed
858  *  @hashdata_length: length of the data
859  *
860  */
tpm_add_measurement_to_log(uint32_t pcrindex,uint32_t eventtype,const char * info,uint32_t infolen,const uint8_t * hashdata,uint32_t hashdatalen)861 static uint32_t tpm_add_measurement_to_log(uint32_t pcrindex,
862 					   uint32_t eventtype,
863 					   const char *info,
864 					   uint32_t infolen,
865 					   const uint8_t *hashdata,
866 					   uint32_t hashdatalen)
867 {
868 	uint8_t hash[SHA256_BUFSIZE];
869 	struct tpm_log_entry le = {
870 		.hdr.pcrindex = cpu_to_log32(pcrindex),
871 		.hdr.eventtype = cpu_to_log32(eventtype),
872 	};
873 	int digest_len;
874 	int ret;
875 
876 	sha256(hashdata, hashdatalen, hash);
877 	digest_len = tpm20_build_digest(&le, hash, true);
878 	if (digest_len < 0)
879 		return TCGBIOS_GENERAL_ERROR;
880 	ret = tpm20_extend(&le, digest_len);
881 	if (ret) {
882 		tpm_set_failure();
883 		return TCGBIOS_COMMAND_ERROR;
884 	}
885 	tpm20_build_digest(&le, hash, false);
886 	return tpm_log_event_long(&le.hdr, digest_len, info, infolen);
887 }
888 
889 /*
890  * Measure the contents of a buffer into the given PCR and log it with the
891  * given eventtype. If is_elf is true, try to determine the size of the
892  * ELF file in the buffer and use its size rather than the much larger data
893  * buffer it is held in. In case of failure to detect the ELF file size,
894  * log an error.
895  *
896  * Input parameters:
897  *  @pcrindex : PCR to extend
898  *  @eventtype : type of event
899  *  @data: the buffer to measure
900  *  @datalen: length of the buffer
901  *  @desc: The description to log
902  *  @desclen: The length of the description
903  *  @is_elf: Whether data buffer holds an ELF file and we should determine
904  *           the original file size.
905  *
906  *  Returns 0 on success, an error code otherwise.
907  */
tpm_hash_log_extend_event_buffer(uint32_t pcrindex,uint32_t eventtype,const void * data,uint64_t datalen,const char * desc,uint32_t desclen,bool is_elf)908 uint32_t tpm_hash_log_extend_event_buffer(uint32_t pcrindex, uint32_t eventtype,
909 					  const void *data, uint64_t datalen,
910 					  const char *desc, uint32_t desclen,
911 					  bool is_elf)
912 {
913 	long len;
914 	char buf[256];
915 
916 	if (is_elf) {
917 		len = elf_get_file_size(data, datalen);
918 		if (len > 0) {
919 			datalen = len;
920 		} else {
921 			snprintf(buf, sizeof(buf), "BAD ELF FILE: %s", desc);
922 			return tpm_add_measurement_to_log(pcrindex, eventtype,
923 					  buf, strlen(buf),
924 					  (uint8_t *)buf, strlen(buf));
925 		}
926 	}
927 	return tpm_add_measurement_to_log(pcrindex, eventtype,
928 					  desc, desclen,
929 					  data, datalen);
930 }
931 
932 /*
933  * Add an EV_ACTION measurement to the list of measurements
934  */
tpm_add_action(uint32_t pcrIndex,const char * string)935 static uint32_t tpm_add_action(uint32_t pcrIndex, const char *string)
936 {
937 	uint32_t len = strlen(string);
938 
939 	return tpm_add_measurement_to_log(pcrIndex, EV_ACTION,
940 					  string, len, (uint8_t *)string, len);
941 }
942 
943 /*
944  * Add event separators for a range of PCRs
945  */
tpm_add_event_separators(uint32_t start_pcr,uint32_t end_pcr)946 uint32_t tpm_add_event_separators(uint32_t start_pcr, uint32_t end_pcr)
947 {
948 	static const uint8_t evt_separator[] = {0xff,0xff,0xff,0xff};
949 	uint32_t pcrIndex;
950 	int rc;
951 
952 	if (!tpm_is_working())
953 		return TCGBIOS_GENERAL_ERROR;
954 
955 	if (start_pcr >= 24 || start_pcr > end_pcr)
956 		return TCGBIOS_INVALID_INPUT_PARA;
957 
958 	/* event separators need to be extended and logged for PCRs 0-7 */
959 	for (pcrIndex = start_pcr; pcrIndex <= end_pcr; pcrIndex++) {
960 		rc = tpm_add_measurement_to_log(pcrIndex, EV_SEPARATOR,
961 						NULL, 0,
962 						evt_separator,
963 						sizeof(evt_separator));
964 		if (rc)
965 			return rc;
966 	}
967 
968 	return 0;
969 }
970 
tpm_measure_bcv_mbr(uint32_t bootdrv,const uint8_t * addr,uint32_t length)971 uint32_t tpm_measure_bcv_mbr(uint32_t bootdrv, const uint8_t *addr,
972 			     uint32_t length)
973 {
974 	uint32_t rc;
975 	const char *string;
976 
977 	if (!tpm_is_working())
978 		return TCGBIOS_GENERAL_ERROR;
979 
980 	if (length < 0x200)
981 		return TCGBIOS_INVALID_INPUT_PARA;
982 
983 	string = "Booting BCV device 00h (Floppy)";
984 	if (bootdrv == BCV_DEVICE_HDD)
985 		string = "Booting BCV device 80h (HDD)";
986 
987 	rc = tpm_add_action(4, string);
988 	if (rc)
989 		return rc;
990 
991 	/*
992 	 * equivalent to: dd if=/dev/hda ibs=1 count=440 | sha256sum
993 	 */
994 	string = "MBR";
995 	rc = tpm_add_measurement_to_log(4, EV_IPL,
996 					string, strlen(string),
997 					addr, 0x1b8);
998 	if (rc)
999 		return rc;
1000 
1001 	/*
1002 	 * equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha256sum
1003 	 */
1004 	string = "MBR PARTITION TABLE";
1005 	return tpm_add_measurement_to_log(5, EV_IPL_PARTITION_DATA,
1006 					  string, strlen(string),
1007 					  addr + 0x1b8, 0x48);
1008 }
1009 
1010 /*
1011  * This is the first function to call when measuring a GPT table.
1012  * It allocates memory for the data to log which are 'measured' later on.
1013  */
tpm_gpt_set_lba1(const uint8_t * addr,uint32_t length)1014 void tpm_gpt_set_lba1(const uint8_t *addr, uint32_t length)
1015 {
1016 	if (!tpm_is_working())
1017 		return;
1018 
1019 	SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size);
1020 
1021 	uefi_gpt_data_size = sizeof(UEFI_GPT_DATA);
1022 	uefi_gpt_data = SLOF_alloc_mem(uefi_gpt_data_size);
1023 	if (!uefi_gpt_data)
1024 		return;
1025 
1026 	memcpy(&uefi_gpt_data->EfiPartitionHeader,
1027 	       addr, MIN(sizeof(uefi_gpt_data->EfiPartitionHeader), length));
1028 	uefi_gpt_data->NumberOfPartitions = 0;
1029 }
1030 
1031 /*
1032  * This function adds a GPT entry to the data to measure. It must
1033  * be called after tpm_gpt_set_lba1.
1034  */
tpm_gpt_add_entry(const uint8_t * addr,uint32_t length)1035 void tpm_gpt_add_entry(const uint8_t *addr, uint32_t length)
1036 {
1037 	size_t sz;
1038 	UEFI_PARTITION_ENTRY *upe = (void *)addr;
1039 	void *tmp;
1040 
1041 	if (!tpm_is_working() ||
1042 	    !uefi_gpt_data ||
1043 	    length < sizeof(*upe) ||
1044 	    !memcmp(upe->partTypeGuid, ZeroGuid, sizeof(ZeroGuid)))
1045 		return;
1046 
1047 	sz = offset_of(UEFI_GPT_DATA, Partitions) +
1048 	       (uefi_gpt_data->NumberOfPartitions + 1)
1049 	       * sizeof(UEFI_PARTITION_ENTRY);
1050 	if (sz > uefi_gpt_data_size) {
1051 		tmp = SLOF_alloc_mem(sz);
1052 		if (!tmp)
1053 			goto err_no_mem;
1054 
1055 		memcpy(tmp, uefi_gpt_data, uefi_gpt_data_size);
1056 		SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size);
1057 		uefi_gpt_data = tmp;
1058 		uefi_gpt_data_size = sz;
1059 	}
1060 
1061 	memcpy(&uefi_gpt_data->Partitions[uefi_gpt_data->NumberOfPartitions],
1062 	       addr,
1063 	       sizeof(UEFI_PARTITION_ENTRY));
1064 	uefi_gpt_data->NumberOfPartitions++;
1065 
1066 	return;
1067 
1068 err_no_mem:
1069 	SLOF_free_mem(uefi_gpt_data, uefi_gpt_data_size);
1070 	uefi_gpt_data_size = 0;
1071 	uefi_gpt_data = NULL;
1072 }
1073 
1074 /*
1075  * tpm_measure_gpt finally measures the GPT table and adds an entry
1076  * to the log.
1077  */
tpm_measure_gpt(void)1078 uint32_t tpm_measure_gpt(void)
1079 {
1080 	size_t sz;
1081 
1082 	if (!tpm_is_working())
1083 		return TCGBIOS_GENERAL_ERROR;
1084 
1085 	sz = offset_of(UEFI_GPT_DATA, Partitions) +
1086 	     uefi_gpt_data->NumberOfPartitions * sizeof(UEFI_PARTITION_ENTRY);
1087 
1088 	return tpm_add_measurement_to_log(5, EV_EFI_GPT_EVENT,
1089 					  (const char *)uefi_gpt_data, sz,
1090 					  (const uint8_t *)uefi_gpt_data, sz);
1091 }
1092 
tpm_measure_scrtm(void)1093 uint32_t tpm_measure_scrtm(void)
1094 {
1095 	uint32_t rc;
1096 	char *version_start = strstr((char *)&print_version, "FW Version");
1097 	char *version_end;
1098 	uint32_t version_length;
1099 	char *slof_text_start = (char *)&_slof_text;
1100 	uint32_t slof_text_length = (long)&_slof_text_end - (long)&_slof_text;
1101 	const char *scrtm = "S-CRTM Contents";
1102 
1103 	version_end = strchr(version_start, '\r');
1104 	version_length = version_end - version_start;
1105 
1106 	dprintf("Measure S-CRTM Version: addr = %p, length = %d\n",
1107 		version_start, version_length);
1108 
1109 	rc = tpm_add_measurement_to_log(0, EV_S_CRTM_VERSION,
1110 					version_start, version_length,
1111 					(uint8_t *)version_start,
1112 					version_length);
1113 	if (rc)
1114 		return rc;
1115 
1116 	dprintf("Measure S-CRTM Content (text): start = %p, length = %d\n",
1117 		slof_text_start, slof_text_length);
1118 
1119 	rc = tpm_add_measurement_to_log(0, EV_S_CRTM_CONTENTS,
1120 					scrtm, strlen(scrtm),
1121 					(uint8_t *)slof_text_start,
1122 					slof_text_length);
1123 
1124 	return rc;
1125 }
1126 
1127 /*
1128  * tpm_driver_get_failure_reason: Function for interfacing with the firmware
1129  *                                API
1130  */
tpm_driver_get_failure_reason(void)1131 uint32_t tpm_driver_get_failure_reason(void)
1132 {
1133 	/* do not check for a working TPM here */
1134 	if (!tpm_state.tpm_found)
1135 		return VTPM_DRV_STATE_INVALID;
1136 
1137 	return spapr_vtpm_get_error();
1138 }
1139 
1140 /*
1141  * tpm_driver_set_failure_reason: Function for interfacing with the firmware
1142  *                                API
1143  */
tpm_driver_set_failure_reason(uint32_t errcode)1144 void tpm_driver_set_failure_reason(uint32_t errcode)
1145 {
1146 	if (!tpm_state.tpm_found)
1147 		return;
1148 
1149 	spapr_vtpm_set_error(errcode);
1150 }
1151 
1152 /****************************************************************
1153  * TPM Configuration Menu
1154  ****************************************************************/
1155 
1156 static int
tpm20_get_suppt_pcrbanks(uint8_t * suppt_pcrbanks,uint8_t * active_pcrbanks)1157 tpm20_get_suppt_pcrbanks(uint8_t *suppt_pcrbanks, uint8_t *active_pcrbanks)
1158 {
1159 	struct tpms_pcr_selection *sel;
1160 	void *end;
1161 
1162 	*suppt_pcrbanks = 0;
1163 	*active_pcrbanks = 0;
1164 
1165 	sel = tpm_state.tpm20_pcr_selection->selections;
1166 	end = (void*)tpm_state.tpm20_pcr_selection +
1167 		tpm_state.tpm20_pcr_selection_size;
1168 
1169 	while (1) {
1170 		uint16_t hashalg;
1171 		uint8_t hashalg_flag;
1172 		unsigned i;
1173 		uint8_t sizeOfSelect = sel->sizeOfSelect;
1174 		void *nsel = (void*)sel + sizeof(*sel) + sizeOfSelect;
1175 
1176 		if (nsel > end)
1177 			return 0;
1178 
1179 		hashalg = be16_to_cpu(sel->hashAlg);
1180 		hashalg_flag = tpm20_hashalg_to_flag(hashalg);
1181 
1182 		*suppt_pcrbanks |= hashalg_flag;
1183 
1184 		for (i = 0; i < sizeOfSelect; i++) {
1185 			if (sel->pcrSelect[i]) {
1186 				*active_pcrbanks |= hashalg_flag;
1187 				break;
1188 			}
1189 		}
1190 
1191 		sel = nsel;
1192 	}
1193 }
1194 
1195 static int
tpm20_set_pcrbanks(uint32_t active_banks)1196 tpm20_set_pcrbanks(uint32_t active_banks)
1197 {
1198 	struct tpm2_req_pcr_allocate trpa = {
1199 		.hdr.tag = cpu_to_be16(TPM2_ST_SESSIONS),
1200 		.hdr.ordinal = cpu_to_be32(TPM2_CC_PCR_Allocate),
1201 		.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1202 		.authblocksize = cpu_to_be32(sizeof(trpa.authblock)),
1203 		.authblock = {
1204 			.handle = cpu_to_be32(TPM2_RS_PW),
1205 			.noncesize = cpu_to_be16(0),
1206 			.contsession = TPM2_YES,
1207 			.pwdsize = cpu_to_be16(0),
1208 		},
1209 	};
1210 	struct tpms_pcr_selection3 {
1211 		uint16_t hashAlg;
1212 		uint8_t sizeOfSelect;
1213 		uint8_t pcrSelect[3];
1214 	} tps[ARRAY_SIZE(trpa.tpms_pcr_selections)];
1215 	int i = 0;
1216 	uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG;
1217 	uint8_t dontcare, suppt_banks;
1218 	struct tpm_rsp_header rsp;
1219 	uint32_t resp_length = sizeof(rsp);
1220 	uint16_t hashalg;
1221 	int ret;
1222 
1223 	tpm20_get_suppt_pcrbanks(&suppt_banks, &dontcare);
1224 
1225 	while (hashalg_flag) {
1226 		if ((hashalg_flag & suppt_banks)) {
1227 			hashalg = tpm20_hashalg_flag_to_hashalg(hashalg_flag);
1228 
1229 			if (hashalg) {
1230 				uint8_t mask = 0;
1231 
1232 				tps[i].hashAlg = cpu_to_be16(hashalg);
1233 				tps[i].sizeOfSelect = 3;
1234 
1235 				if (active_banks & hashalg_flag)
1236 					mask = 0xff;
1237 
1238 				tps[i].pcrSelect[0] = mask;
1239 				tps[i].pcrSelect[1] = mask;
1240 				tps[i].pcrSelect[2] = mask;
1241 				i++;
1242 			}
1243 		}
1244 		hashalg_flag <<= 1;
1245 	}
1246 
1247 	trpa.count = cpu_to_be32(i);
1248 	memcpy(trpa.tpms_pcr_selections, tps, i * sizeof(tps[0]));
1249 	trpa.hdr.totlen = cpu_to_be32(offset_of(struct tpm2_req_pcr_allocate,
1250 						tpms_pcr_selections) +
1251 				      i * sizeof(tps[0]));
1252 
1253 	ret = spapr_transmit(0, &trpa.hdr, &rsp, &resp_length,
1254 			     TPM_DURATION_TYPE_SHORT);
1255 	ret = ret ? -1 : (int) be32_to_cpu(rsp.errcode);
1256 
1257 	return ret;
1258 }
1259 
tpm20_activate_pcrbanks(uint32_t active_banks)1260 static int tpm20_activate_pcrbanks(uint32_t active_banks)
1261 {
1262 	int ret;
1263 
1264 	ret = tpm20_set_pcrbanks(active_banks);
1265 	if (!ret)
1266 		ret = tpm_simple_cmd(0, TPM2_CC_Shutdown,
1267 				     2, TPM2_SU_CLEAR, TPM_DURATION_TYPE_SHORT);
1268 	if (!ret)
1269 		SLOF_reset();
1270 	return ret;
1271 }
1272 
1273 static int
tpm20_clearcontrol(uint8_t disable)1274 tpm20_clearcontrol(uint8_t disable)
1275 {
1276 	struct tpm2_req_clearcontrol trc = {
1277 		.hdr.tag     = cpu_to_be16(TPM2_ST_SESSIONS),
1278 		.hdr.totlen  = cpu_to_be32(sizeof(trc)),
1279 		.hdr.ordinal = cpu_to_be32(TPM2_CC_ClearControl),
1280 		.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1281 		.authblocksize = cpu_to_be32(sizeof(trc.authblock)),
1282 		.authblock = {
1283 			.handle = cpu_to_be32(TPM2_RS_PW),
1284 			.noncesize = cpu_to_be16(0),
1285 			.contsession = TPM2_YES,
1286 			.pwdsize = cpu_to_be16(0),
1287 		},
1288 		.disable = disable,
1289 	};
1290 	struct tpm_rsp_header rsp;
1291 	uint32_t resp_length = sizeof(rsp);
1292 	int ret;
1293 
1294 	ret = spapr_transmit(0, &trc.hdr, &rsp, &resp_length,
1295 			     TPM_DURATION_TYPE_SHORT);
1296 	if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1297 		ret = -1;
1298 
1299 	dprintf("TCGBIOS: Return value from sending TPM2_CC_ClearControl = 0x%08x\n",
1300 		ret);
1301 
1302 	return ret;
1303 }
1304 
1305 static int
tpm20_clear(void)1306 tpm20_clear(void)
1307 {
1308 	struct tpm2_req_clear trq = {
1309 		.hdr.tag	 = cpu_to_be16(TPM2_ST_SESSIONS),
1310 		.hdr.totlen  = cpu_to_be32(sizeof(trq)),
1311 		.hdr.ordinal = cpu_to_be32(TPM2_CC_Clear),
1312 		.authhandle = cpu_to_be32(TPM2_RH_PLATFORM),
1313 		.authblocksize = cpu_to_be32(sizeof(trq.authblock)),
1314 		.authblock = {
1315 			.handle = cpu_to_be32(TPM2_RS_PW),
1316 			.noncesize = cpu_to_be16(0),
1317 			.contsession = TPM2_YES,
1318 			.pwdsize = cpu_to_be16(0),
1319 		},
1320 	};
1321 	struct tpm_rsp_header rsp;
1322 	uint32_t resp_length = sizeof(rsp);
1323 	int ret;
1324 
1325 	ret = spapr_transmit(0, &trq.hdr, &rsp, &resp_length,
1326 			     TPM_DURATION_TYPE_MEDIUM);
1327 	if (ret || resp_length != sizeof(rsp) || rsp.errcode)
1328 		ret = -1;
1329 
1330 	dprintf("TCGBIOS: Return value from sending TPM2_CC_Clear = 0x%08x\n",
1331 		ret);
1332 
1333 	return ret;
1334 }
1335 
tpm20_menu_change_active_pcrbanks(void)1336 static int tpm20_menu_change_active_pcrbanks(void)
1337 {
1338 	uint8_t active_banks, suppt_banks, activate_banks;
1339 
1340 	tpm20_get_suppt_pcrbanks(&suppt_banks, &active_banks);
1341 
1342 	activate_banks = active_banks;
1343 
1344 	while (1) {
1345 		uint8_t hashalg_flag = TPM2_ALG_SHA1_FLAG;
1346 		uint8_t i = 0;
1347 		uint8_t flagnum;
1348 		int show = 0;
1349 
1350 		printf("\nToggle active PCR banks by pressing number key\n\n");
1351 
1352 		while (hashalg_flag) {
1353 			uint8_t flag = hashalg_flag & suppt_banks;
1354 			const char *hashname = tpm20_hashalg_flag_to_name(flag);
1355 
1356 			i++;
1357 			if (hashname) {
1358 				printf("  %d: %s", i, hashname);
1359 				if (activate_banks & hashalg_flag)
1360 					printf(" (enabled)");
1361 				printf("\n");
1362 			}
1363 
1364 			hashalg_flag <<= 1;
1365 		}
1366 		printf("\n"
1367 		       "ESC: return to previous menu without changes\n");
1368 		if (activate_banks)
1369 			printf("a  : activate selection\n");
1370 
1371 		while (!show) {
1372 			int key_code = SLOF_get_keystroke();
1373 
1374 			switch (key_code) {
1375 			case ~0:
1376 				continue;
1377 			case 27: /* ESC */
1378 				printf("\n");
1379 				return -1;
1380 			case '1' ... '5': /* keys 1 .. 5 */
1381 				flagnum = key_code - '0';
1382 				if (flagnum > i)
1383 					continue;
1384 				if (suppt_banks & (1 << (flagnum - 1))) {
1385 					activate_banks ^= 1 << (flagnum - 1);
1386 					show = 1;
1387 				}
1388 				break;
1389 			case 'a': /* a */
1390 				if (activate_banks)
1391 					tpm20_activate_pcrbanks(activate_banks);
1392 			}
1393 		}
1394 	}
1395 }
1396 
tpm20_menu(void)1397 void tpm20_menu(void)
1398 {
1399 	int key_code;
1400 	int waitkey;
1401 	int ret;
1402 
1403 	for (;;) {
1404 		printf("1. Clear TPM\n");
1405 		printf("2. Change active PCR banks\n");
1406 
1407 		printf("\nIf not change is desired or if this menu was reached by "
1408 		       "mistake, press ESC to\ncontinue the boot.\n");
1409 
1410 		waitkey = 1;
1411 
1412 		while (waitkey) {
1413 			key_code = SLOF_get_keystroke();
1414 			switch (key_code) {
1415 			case 27:
1416 				// ESC
1417 				return;
1418 			case '1':
1419 				ret = tpm20_clearcontrol(false);
1420 				if (!ret)
1421 					ret = tpm20_clear();
1422 				if (ret)
1423 					printf("An error occurred clearing "
1424 					       "the TPM: 0x%x\n",
1425 					       ret);
1426 				break;
1427 			case '2':
1428 				tpm20_menu_change_active_pcrbanks();
1429 				waitkey = 0;
1430 				continue;
1431 			default:
1432 				continue;
1433 			}
1434 
1435 			waitkey = 0;
1436 		}
1437 	}
1438 }
1439