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