blob: 68eaaa639f89d97965eaccda5d67ff3723f6c4ea [file] [log] [blame]
Miquel Raynalf3b43502018-05-15 11:57:08 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
Eddie James8ed7bb32023-10-24 10:43:49 -05003 * Copyright (c) 2023 Linaro Limited
Miquel Raynalf3b43502018-05-15 11:57:08 +02004 * Copyright (c) 2018 Bootlin
5 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
6 */
7
Miquel Raynalf3b43502018-05-15 11:57:08 +02008#include <dm.h>
Eddie James8ed7bb32023-10-24 10:43:49 -05009#include <dm/of_access.h>
10#include <tpm_api.h>
Miquel Raynalf3b43502018-05-15 11:57:08 +020011#include <tpm-common.h>
12#include <tpm-v2.h>
Eddie James8ed7bb32023-10-24 10:43:49 -050013#include <u-boot/sha1.h>
14#include <u-boot/sha256.h>
15#include <u-boot/sha512.h>
16#include <version_string.h>
17#include <asm/io.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060018#include <linux/bitops.h>
Eddie James8ed7bb32023-10-24 10:43:49 -050019#include <linux/unaligned/be_byteshift.h>
20#include <linux/unaligned/generic.h>
21#include <linux/unaligned/le_byteshift.h>
22
Miquel Raynalf3b43502018-05-15 11:57:08 +020023#include "tpm-utils.h"
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020024
Eddie James8ed7bb32023-10-24 10:43:49 -050025const enum tpm2_algorithms tpm2_supported_algorithms[4] = {
26 TPM2_ALG_SHA1,
27 TPM2_ALG_SHA256,
28 TPM2_ALG_SHA384,
29 TPM2_ALG_SHA512,
30};
31
32int tcg2_get_active_pcr_banks(struct udevice *dev, u32 *active_pcr_banks)
33{
34 u32 supported = 0;
35 u32 pcr_banks = 0;
36 u32 active = 0;
37 int rc;
38
39 rc = tpm2_get_pcr_info(dev, &supported, &active, &pcr_banks);
40 if (rc)
41 return rc;
42
43 *active_pcr_banks = active;
44
45 return 0;
46}
47
48u32 tcg2_event_get_size(struct tpml_digest_values *digest_list)
49{
50 u32 len;
51 size_t i;
52
53 len = offsetof(struct tcg_pcr_event2, digests);
54 len += offsetof(struct tpml_digest_values, digests);
55 for (i = 0; i < digest_list->count; ++i) {
56 u16 l = tpm2_algorithm_to_len(digest_list->digests[i].hash_alg);
57
58 if (!l)
59 continue;
60
61 len += l + offsetof(struct tpmt_ha, digest);
62 }
63 len += sizeof(u32);
64
65 return len;
66}
67
68int tcg2_create_digest(struct udevice *dev, const u8 *input, u32 length,
69 struct tpml_digest_values *digest_list)
70{
71 u8 final[sizeof(union tpmu_ha)];
72 sha256_context ctx_256;
73 sha512_context ctx_512;
74 sha1_context ctx;
75 u32 active;
76 size_t i;
77 u32 len;
78 int rc;
79
80 rc = tcg2_get_active_pcr_banks(dev, &active);
81 if (rc)
82 return rc;
83
84 digest_list->count = 0;
85 for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) {
86 u32 mask =
87 tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]);
88
89 if (!(active & mask))
90 continue;
91
92 switch (tpm2_supported_algorithms[i]) {
93 case TPM2_ALG_SHA1:
94 sha1_starts(&ctx);
95 sha1_update(&ctx, input, length);
96 sha1_finish(&ctx, final);
97 len = TPM2_SHA1_DIGEST_SIZE;
98 break;
99 case TPM2_ALG_SHA256:
100 sha256_starts(&ctx_256);
101 sha256_update(&ctx_256, input, length);
102 sha256_finish(&ctx_256, final);
103 len = TPM2_SHA256_DIGEST_SIZE;
104 break;
105 case TPM2_ALG_SHA384:
106 sha384_starts(&ctx_512);
107 sha384_update(&ctx_512, input, length);
108 sha384_finish(&ctx_512, final);
109 len = TPM2_SHA384_DIGEST_SIZE;
110 break;
111 case TPM2_ALG_SHA512:
112 sha512_starts(&ctx_512);
113 sha512_update(&ctx_512, input, length);
114 sha512_finish(&ctx_512, final);
115 len = TPM2_SHA512_DIGEST_SIZE;
116 break;
117 default:
118 printf("%s: unsupported algorithm %x\n", __func__,
119 tpm2_supported_algorithms[i]);
120 continue;
121 }
122
123 digest_list->digests[digest_list->count].hash_alg =
124 tpm2_supported_algorithms[i];
125 memcpy(&digest_list->digests[digest_list->count].digest, final,
126 len);
127 digest_list->count++;
128 }
129
130 return 0;
131}
132
133void tcg2_log_append(u32 pcr_index, u32 event_type,
134 struct tpml_digest_values *digest_list, u32 size,
135 const u8 *event, u8 *log)
136{
137 size_t len;
138 size_t pos;
139 u32 i;
140
141 pos = offsetof(struct tcg_pcr_event2, pcr_index);
142 put_unaligned_le32(pcr_index, log);
143 pos = offsetof(struct tcg_pcr_event2, event_type);
144 put_unaligned_le32(event_type, log + pos);
145 pos = offsetof(struct tcg_pcr_event2, digests) +
146 offsetof(struct tpml_digest_values, count);
147 put_unaligned_le32(digest_list->count, log + pos);
148
149 pos = offsetof(struct tcg_pcr_event2, digests) +
150 offsetof(struct tpml_digest_values, digests);
151 for (i = 0; i < digest_list->count; ++i) {
152 u16 hash_alg = digest_list->digests[i].hash_alg;
153
154 len = tpm2_algorithm_to_len(hash_alg);
155 if (!len)
156 continue;
157
158 pos += offsetof(struct tpmt_ha, hash_alg);
159 put_unaligned_le16(hash_alg, log + pos);
160 pos += offsetof(struct tpmt_ha, digest);
161 memcpy(log + pos, (u8 *)&digest_list->digests[i].digest, len);
162 pos += len;
163 }
164
165 put_unaligned_le32(size, log + pos);
166 pos += sizeof(u32);
167 memcpy(log + pos, event, size);
168}
169
170static int tcg2_log_append_check(struct tcg2_event_log *elog, u32 pcr_index,
171 u32 event_type,
172 struct tpml_digest_values *digest_list,
173 u32 size, const u8 *event)
174{
175 u32 event_size;
176 u8 *log;
177
178 event_size = size + tcg2_event_get_size(digest_list);
179 if (elog->log_position + event_size > elog->log_size) {
180 printf("%s: log too large: %u + %u > %u\n", __func__,
181 elog->log_position, event_size, elog->log_size);
182 return -ENOBUFS;
183 }
184
185 log = elog->log + elog->log_position;
186 elog->log_position += event_size;
187
188 tcg2_log_append(pcr_index, event_type, digest_list, size, event, log);
189
190 return 0;
191}
192
193static int tcg2_log_init(struct udevice *dev, struct tcg2_event_log *elog)
194{
195 struct tcg_efi_spec_id_event *ev;
196 struct tcg_pcr_event *log;
197 u32 event_size;
198 u32 count = 0;
199 u32 log_size;
200 u32 active;
201 u32 mask;
202 size_t i;
203 u16 len;
204 int rc;
205
206 rc = tcg2_get_active_pcr_banks(dev, &active);
207 if (rc)
208 return rc;
209
210 event_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes);
211 for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) {
212 mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]);
213
214 if (!(active & mask))
215 continue;
216
217 switch (tpm2_supported_algorithms[i]) {
218 case TPM2_ALG_SHA1:
219 case TPM2_ALG_SHA256:
220 case TPM2_ALG_SHA384:
221 case TPM2_ALG_SHA512:
222 count++;
223 break;
224 default:
225 continue;
226 }
227 }
228
229 event_size += 1 +
230 (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count);
231 log_size = offsetof(struct tcg_pcr_event, event) + event_size;
232
233 if (log_size > elog->log_size) {
234 printf("%s: log too large: %u > %u\n", __func__, log_size,
235 elog->log_size);
236 return -ENOBUFS;
237 }
238
239 log = (struct tcg_pcr_event *)elog->log;
240 put_unaligned_le32(0, &log->pcr_index);
241 put_unaligned_le32(EV_NO_ACTION, &log->event_type);
242 memset(&log->digest, 0, sizeof(log->digest));
243 put_unaligned_le32(event_size, &log->event_size);
244
245 ev = (struct tcg_efi_spec_id_event *)log->event;
246 strlcpy((char *)ev->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
247 sizeof(ev->signature));
248 put_unaligned_le32(0, &ev->platform_class);
249 ev->spec_version_minor = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2;
250 ev->spec_version_major = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2;
251 ev->spec_errata = TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_ERRATA_TPM2;
252 ev->uintn_size = sizeof(size_t) / sizeof(u32);
253 put_unaligned_le32(count, &ev->number_of_algorithms);
254
255 count = 0;
256 for (i = 0; i < ARRAY_SIZE(tpm2_supported_algorithms); ++i) {
257 mask = tpm2_algorithm_to_mask(tpm2_supported_algorithms[i]);
258
259 if (!(active & mask))
260 continue;
261
262 len = tpm2_algorithm_to_len(tpm2_supported_algorithms[i]);
263 if (!len)
264 continue;
265
266 put_unaligned_le16(tpm2_supported_algorithms[i],
267 &ev->digest_sizes[count].algorithm_id);
268 put_unaligned_le16(len, &ev->digest_sizes[count].digest_size);
269 count++;
270 }
271
272 *((u8 *)ev + (event_size - 1)) = 0;
273 elog->log_position = log_size;
274
275 return 0;
276}
277
278static int tcg2_replay_eventlog(struct tcg2_event_log *elog,
279 struct udevice *dev,
280 struct tpml_digest_values *digest_list,
281 u32 log_position)
282{
283 const u32 offset = offsetof(struct tcg_pcr_event2, digests) +
284 offsetof(struct tpml_digest_values, digests);
285 u32 event_size;
286 u32 count;
287 u16 algo;
288 u32 pcr;
289 u32 pos;
290 u16 len;
291 u8 *log;
292 int rc;
293 u32 i;
294
295 while (log_position + offset < elog->log_size) {
296 log = elog->log + log_position;
297
298 pos = offsetof(struct tcg_pcr_event2, pcr_index);
299 pcr = get_unaligned_le32(log + pos);
300 pos = offsetof(struct tcg_pcr_event2, event_type);
301 if (!get_unaligned_le32(log + pos))
302 return 0;
303
304 pos = offsetof(struct tcg_pcr_event2, digests) +
305 offsetof(struct tpml_digest_values, count);
306 count = get_unaligned_le32(log + pos);
307 if (count > ARRAY_SIZE(tpm2_supported_algorithms) ||
308 (digest_list->count && digest_list->count != count))
309 return 0;
310
311 pos = offsetof(struct tcg_pcr_event2, digests) +
312 offsetof(struct tpml_digest_values, digests);
313 for (i = 0; i < count; ++i) {
314 pos += offsetof(struct tpmt_ha, hash_alg);
315 if (log_position + pos + sizeof(u16) >= elog->log_size)
316 return 0;
317
318 algo = get_unaligned_le16(log + pos);
319 pos += offsetof(struct tpmt_ha, digest);
320 switch (algo) {
321 case TPM2_ALG_SHA1:
322 case TPM2_ALG_SHA256:
323 case TPM2_ALG_SHA384:
324 case TPM2_ALG_SHA512:
325 len = tpm2_algorithm_to_len(algo);
326 break;
327 default:
328 return 0;
329 }
330
331 if (digest_list->count) {
332 if (algo != digest_list->digests[i].hash_alg ||
333 log_position + pos + len >= elog->log_size)
334 return 0;
335
336 memcpy(digest_list->digests[i].digest.sha512,
337 log + pos, len);
338 }
339
340 pos += len;
341 }
342
343 if (log_position + pos + sizeof(u32) >= elog->log_size)
344 return 0;
345
346 event_size = get_unaligned_le32(log + pos);
347 pos += event_size + sizeof(u32);
348 if (log_position + pos > elog->log_size)
349 return 0;
350
351 if (digest_list->count) {
352 rc = tcg2_pcr_extend(dev, pcr, digest_list);
353 if (rc)
354 return rc;
355 }
356
357 log_position += pos;
358 }
359
360 elog->log_position = log_position;
361 elog->found = true;
362 return 0;
363}
364
365static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog)
366{
367 struct tpml_digest_values digest_list;
368 struct tcg_efi_spec_id_event *event;
369 struct tcg_pcr_event *log;
370 u32 log_active;
371 u32 calc_size;
372 u32 active;
373 u32 count;
374 u32 evsz;
375 u32 mask;
376 u16 algo;
377 u16 len;
378 int rc;
379 u32 i;
380 u16 j;
381
382 if (elog->log_size <= offsetof(struct tcg_pcr_event, event))
383 return 0;
384
385 log = (struct tcg_pcr_event *)elog->log;
386 if (get_unaligned_le32(&log->pcr_index) != 0 ||
387 get_unaligned_le32(&log->event_type) != EV_NO_ACTION)
388 return 0;
389
390 for (i = 0; i < sizeof(log->digest); i++) {
391 if (log->digest[i])
392 return 0;
393 }
394
395 evsz = get_unaligned_le32(&log->event_size);
396 if (evsz < offsetof(struct tcg_efi_spec_id_event, digest_sizes) ||
397 evsz + offsetof(struct tcg_pcr_event, event) > elog->log_size)
398 return 0;
399
400 event = (struct tcg_efi_spec_id_event *)log->event;
401 if (memcmp(event->signature, TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03,
402 sizeof(TCG_EFI_SPEC_ID_EVENT_SIGNATURE_03)))
403 return 0;
404
405 if (event->spec_version_minor != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MINOR_TPM2 ||
406 event->spec_version_major != TCG_EFI_SPEC_ID_EVENT_SPEC_VERSION_MAJOR_TPM2)
407 return 0;
408
409 count = get_unaligned_le32(&event->number_of_algorithms);
410 if (count > ARRAY_SIZE(tpm2_supported_algorithms))
411 return 0;
412
413 calc_size = offsetof(struct tcg_efi_spec_id_event, digest_sizes) +
414 (sizeof(struct tcg_efi_spec_id_event_algorithm_size) * count) +
415 1;
416 if (evsz != calc_size)
417 return 0;
418
419 rc = tcg2_get_active_pcr_banks(dev, &active);
420 if (rc)
421 return rc;
422
423 digest_list.count = 0;
424 log_active = 0;
425
426 for (i = 0; i < count; ++i) {
427 algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id);
428 mask = tpm2_algorithm_to_mask(algo);
429
430 if (!(active & mask))
431 return 0;
432
433 switch (algo) {
434 case TPM2_ALG_SHA1:
435 case TPM2_ALG_SHA256:
436 case TPM2_ALG_SHA384:
437 case TPM2_ALG_SHA512:
438 len = get_unaligned_le16(&event->digest_sizes[i].digest_size);
439 if (tpm2_algorithm_to_len(algo) != len)
440 return 0;
441 digest_list.digests[digest_list.count++].hash_alg = algo;
442 break;
443 default:
444 return 0;
445 }
446
447 log_active |= mask;
448 }
449
450 /* Ensure the previous firmware extended all the PCRs. */
451 if (log_active != active)
452 return 0;
453
454 /* Read PCR0 to check if previous firmware extended the PCRs or not. */
455 rc = tcg2_pcr_read(dev, 0, &digest_list);
456 if (rc)
457 return rc;
458
459 for (i = 0; i < digest_list.count; ++i) {
460 len = tpm2_algorithm_to_len(digest_list.digests[i].hash_alg);
461 for (j = 0; j < len; ++j) {
462 if (digest_list.digests[i].digest.sha512[j])
463 break;
464 }
465
466 /* PCR is non-zero; it has been extended, so skip extending. */
467 if (j != len) {
468 digest_list.count = 0;
469 break;
470 }
471 }
472
473 return tcg2_replay_eventlog(elog, dev, &digest_list,
474 offsetof(struct tcg_pcr_event, event) +
475 evsz);
476}
477
478int tcg2_pcr_extend(struct udevice *dev, u32 pcr_index,
479 struct tpml_digest_values *digest_list)
480{
481 u32 rc;
482 u32 i;
483
484 for (i = 0; i < digest_list->count; i++) {
485 u32 alg = digest_list->digests[i].hash_alg;
486
487 rc = tpm2_pcr_extend(dev, pcr_index, alg,
488 (u8 *)&digest_list->digests[i].digest,
489 tpm2_algorithm_to_len(alg));
490 if (rc) {
491 printf("%s: error pcr:%u alg:%08x\n", __func__,
492 pcr_index, alg);
493 return rc;
494 }
495 }
496
497 return 0;
498}
499
500int tcg2_pcr_read(struct udevice *dev, u32 pcr_index,
501 struct tpml_digest_values *digest_list)
502{
503 struct tpm_chip_priv *priv;
504 u32 rc;
505 u32 i;
506
507 priv = dev_get_uclass_priv(dev);
508 if (!priv)
509 return -ENODEV;
510
511 for (i = 0; i < digest_list->count; i++) {
512 u32 alg = digest_list->digests[i].hash_alg;
513 u8 *digest = (u8 *)&digest_list->digests[i].digest;
514
515 rc = tpm2_pcr_read(dev, pcr_index, priv->pcr_select_min, alg,
516 digest, tpm2_algorithm_to_len(alg), NULL);
517 if (rc) {
518 printf("%s: error pcr:%u alg:%08x\n", __func__,
519 pcr_index, alg);
520 return rc;
521 }
522 }
523
524 return 0;
525}
526
527int tcg2_measure_data(struct udevice *dev, struct tcg2_event_log *elog,
528 u32 pcr_index, u32 size, const u8 *data, u32 event_type,
529 u32 event_size, const u8 *event)
530{
531 struct tpml_digest_values digest_list;
532 int rc;
533
534 if (data)
535 rc = tcg2_create_digest(dev, data, size, &digest_list);
536 else
537 rc = tcg2_create_digest(dev, event, event_size, &digest_list);
538 if (rc)
539 return rc;
540
541 rc = tcg2_pcr_extend(dev, pcr_index, &digest_list);
542 if (rc)
543 return rc;
544
545 return tcg2_log_append_check(elog, pcr_index, event_type, &digest_list,
546 event_size, event);
547}
548
549int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog,
550 bool ignore_existing_log)
551{
552 struct tcg2_event_log log;
553 int rc;
554
555 elog->log_position = 0;
556 elog->found = false;
557
558 rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size);
559 if (!rc) {
560 log.log_position = 0;
561 log.found = false;
562
563 if (!ignore_existing_log) {
564 rc = tcg2_log_parse(dev, &log);
565 if (rc)
566 return rc;
567 }
568
569 if (elog->log_size) {
570 if (log.found) {
571 if (elog->log_size < log.log_position)
572 return -ENOSPC;
573
574 /*
575 * Copy the discovered log into the user buffer
576 * if there's enough space.
577 */
578 memcpy(elog->log, log.log, log.log_position);
579 }
580
581 unmap_physmem(log.log, MAP_NOCACHE);
582 } else {
583 elog->log = log.log;
584 elog->log_size = log.log_size;
585 }
586
587 elog->log_position = log.log_position;
588 elog->found = log.found;
589 }
590
591 /*
592 * Initialize the log buffer if no log was discovered and the buffer is
593 * valid. User's can pass in their own buffer as a fallback if no
594 * memory region is found.
595 */
596 if (!elog->found && elog->log_size)
597 rc = tcg2_log_init(dev, elog);
598
599 return rc;
600}
601
602int tcg2_measurement_init(struct udevice **dev, struct tcg2_event_log *elog,
603 bool ignore_existing_log)
604{
605 int rc;
606
607 rc = tcg2_platform_get_tpm2(dev);
608 if (rc)
609 return rc;
610
611 rc = tpm_auto_start(*dev);
612 if (rc)
613 return rc;
614
615 rc = tcg2_log_prepare_buffer(*dev, elog, ignore_existing_log);
616 if (rc) {
617 tcg2_measurement_term(*dev, elog, true);
618 return rc;
619 }
620
621 rc = tcg2_measure_event(*dev, elog, 0, EV_S_CRTM_VERSION,
622 strlen(version_string) + 1,
623 (u8 *)version_string);
624 if (rc) {
625 tcg2_measurement_term(*dev, elog, true);
626 return rc;
627 }
628
629 return 0;
630}
631
632void tcg2_measurement_term(struct udevice *dev, struct tcg2_event_log *elog,
633 bool error)
634{
635 u32 event = error ? 0x1 : 0xffffffff;
636 int i;
637
638 for (i = 0; i < 8; ++i)
639 tcg2_measure_event(dev, elog, i, EV_SEPARATOR, sizeof(event),
640 (const u8 *)&event);
641
642 if (elog->log)
643 unmap_physmem(elog->log, MAP_NOCACHE);
644}
645
646__weak int tcg2_platform_get_log(struct udevice *dev, void **addr, u32 *size)
647{
648 const __be32 *addr_prop;
649 const __be32 *size_prop;
650 int asize;
651 int ssize;
652
653 *addr = NULL;
654 *size = 0;
655
656 addr_prop = dev_read_prop(dev, "tpm_event_log_addr", &asize);
657 if (!addr_prop)
658 addr_prop = dev_read_prop(dev, "linux,sml-base", &asize);
659
660 size_prop = dev_read_prop(dev, "tpm_event_log_size", &ssize);
661 if (!size_prop)
662 size_prop = dev_read_prop(dev, "linux,sml-size", &ssize);
663
664 if (addr_prop && size_prop) {
665 u64 a = of_read_number(addr_prop, asize / sizeof(__be32));
666 u64 s = of_read_number(size_prop, ssize / sizeof(__be32));
667
668 *addr = map_physmem(a, s, MAP_NOCACHE);
669 *size = (u32)s;
670 } else {
671 struct ofnode_phandle_args args;
672 phys_addr_t a;
673 fdt_size_t s;
674
675 if (dev_read_phandle_with_args(dev, "memory-region", NULL, 0,
676 0, &args))
677 return -ENODEV;
678
679 a = ofnode_get_addr_size(args.node, "reg", &s);
680 if (a == FDT_ADDR_T_NONE)
681 return -ENOMEM;
682
683 *addr = map_physmem(a, s, MAP_NOCACHE);
684 *size = (u32)s;
685 }
686
687 return 0;
688}
689
690__weak int tcg2_platform_get_tpm2(struct udevice **dev)
691{
692 for_each_tpm_device(*dev) {
693 if (tpm_get_version(*dev) == TPM_V2)
694 return 0;
695 }
696
697 return -ENODEV;
698}
699
700__weak void tcg2_platform_startup_error(struct udevice *dev, int rc) {}
701
Simon Glass8ceca1d2018-11-18 14:22:27 -0700702u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200703{
704 const u8 command_v2[12] = {
705 tpm_u16(TPM2_ST_NO_SESSIONS),
706 tpm_u32(12),
707 tpm_u32(TPM2_CC_STARTUP),
708 tpm_u16(mode),
709 };
710 int ret;
711
712 /*
713 * Note TPM2_Startup command will return RC_SUCCESS the first time,
714 * but will return RC_INITIALIZE otherwise.
715 */
Simon Glass8ceca1d2018-11-18 14:22:27 -0700716 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200717 if (ret && ret != TPM2_RC_INITIALIZE)
718 return ret;
719
720 return 0;
721}
Miquel Raynal39c76082018-05-15 11:57:13 +0200722
Simon Glass8ceca1d2018-11-18 14:22:27 -0700723u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
Miquel Raynal39c76082018-05-15 11:57:13 +0200724{
725 const u8 command_v2[12] = {
726 tpm_u16(TPM2_ST_NO_SESSIONS),
727 tpm_u32(11),
728 tpm_u32(TPM2_CC_SELF_TEST),
729 full_test,
730 };
731
Simon Glass8ceca1d2018-11-18 14:22:27 -0700732 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal39c76082018-05-15 11:57:13 +0200733}
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200734
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200735u32 tpm2_auto_start(struct udevice *dev)
736{
737 u32 rc;
738
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200739 rc = tpm2_self_test(dev, TPMI_YES);
740
741 if (rc == TPM2_RC_INITIALIZE) {
742 rc = tpm2_startup(dev, TPM2_SU_CLEAR);
743 if (rc)
744 return rc;
745
746 rc = tpm2_self_test(dev, TPMI_YES);
747 }
748
749 return rc;
750}
751
Simon Glass8ceca1d2018-11-18 14:22:27 -0700752u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
753 const ssize_t pw_sz)
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200754{
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700755 /* Length of the message header, up to start of password */
756 uint offset = 27;
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200757 u8 command_v2[COMMAND_BUFFER_SIZE] = {
758 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700759 tpm_u32(offset + pw_sz), /* Length */
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200760 tpm_u32(TPM2_CC_CLEAR), /* Command code */
761
762 /* HANDLE */
763 tpm_u32(handle), /* TPM resource handle */
764
765 /* AUTH_SESSION */
766 tpm_u32(9 + pw_sz), /* Authorization size */
767 tpm_u32(TPM2_RS_PW), /* Session handle */
768 tpm_u16(0), /* Size of <nonce> */
769 /* <nonce> (if any) */
770 0, /* Attributes: Cont/Excl/Rst */
771 tpm_u16(pw_sz), /* Size of <hmac/password> */
772 /* STRING(pw) <hmac/password> (if any) */
773 };
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200774 int ret;
775
776 /*
777 * Fill the command structure starting from the first buffer:
778 * - the password (if any)
779 */
780 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
781 offset, pw, pw_sz);
782 offset += pw_sz;
783 if (ret)
784 return TPM_LIB_ERROR;
785
Simon Glass8ceca1d2018-11-18 14:22:27 -0700786 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200787}
Miquel Raynal14d72352018-05-15 11:57:15 +0200788
Simon Glass713c58a2021-02-06 14:23:39 -0700789u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
790 size_t space_size, u32 nv_attributes,
791 const u8 *nv_policy, size_t nv_policy_size)
792{
793 /*
794 * Calculate the offset of the nv_policy piece by adding each of the
795 * chunks below.
796 */
Simon Glass5252cac2022-08-30 21:05:34 -0600797 const int platform_len = sizeof(u32);
798 const int session_hdr_len = 13;
799 const int message_len = 14;
800 uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
801 message_len;
Simon Glass713c58a2021-02-06 14:23:39 -0700802 u8 command_v2[COMMAND_BUFFER_SIZE] = {
803 /* header 10 bytes */
804 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass5252cac2022-08-30 21:05:34 -0600805 tpm_u32(offset + nv_policy_size + 2),/* Length */
Simon Glass713c58a2021-02-06 14:23:39 -0700806 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
807
Simon Glass5252cac2022-08-30 21:05:34 -0600808 /* handles 4 bytes */
Simon Glass713c58a2021-02-06 14:23:39 -0700809 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
810
811 /* session header 13 bytes */
812 tpm_u32(9), /* Header size */
813 tpm_u32(TPM2_RS_PW), /* Password authorisation */
814 tpm_u16(0), /* nonce_size */
815 0, /* session_attrs */
816 tpm_u16(0), /* auth_size */
817
818 /* message 14 bytes + policy */
Simon Glass5252cac2022-08-30 21:05:34 -0600819 tpm_u16(message_len + nv_policy_size), /* size */
Simon Glass713c58a2021-02-06 14:23:39 -0700820 tpm_u32(space_index),
821 tpm_u16(TPM2_ALG_SHA256),
822 tpm_u32(nv_attributes),
823 tpm_u16(nv_policy_size),
Simon Glass5252cac2022-08-30 21:05:34 -0600824 /*
825 * nv_policy
826 * space_size
827 */
Simon Glass713c58a2021-02-06 14:23:39 -0700828 };
829 int ret;
830
831 /*
832 * Fill the command structure starting from the first buffer:
833 * - the password (if any)
834 */
Simon Glass5252cac2022-08-30 21:05:34 -0600835 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
836 offset, nv_policy, nv_policy_size,
837 offset + nv_policy_size, space_size);
Simon Glass713c58a2021-02-06 14:23:39 -0700838 if (ret)
839 return TPM_LIB_ERROR;
840
841 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
842}
843
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200844u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
845 const u8 *digest, u32 digest_len)
Miquel Raynal14d72352018-05-15 11:57:15 +0200846{
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700847 /* Length of the message header, up to start of digest */
848 uint offset = 33;
Miquel Raynal14d72352018-05-15 11:57:15 +0200849 u8 command_v2[COMMAND_BUFFER_SIZE] = {
850 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700851 tpm_u32(offset + digest_len), /* Length */
Miquel Raynal14d72352018-05-15 11:57:15 +0200852 tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */
853
854 /* HANDLE */
855 tpm_u32(index), /* Handle (PCR Index) */
856
857 /* AUTH_SESSION */
858 tpm_u32(9), /* Authorization size */
859 tpm_u32(TPM2_RS_PW), /* Session handle */
860 tpm_u16(0), /* Size of <nonce> */
861 /* <nonce> (if any) */
862 0, /* Attributes: Cont/Excl/Rst */
863 tpm_u16(0), /* Size of <hmac/password> */
864 /* <hmac/password> (if any) */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700865
866 /* hashes */
Miquel Raynal14d72352018-05-15 11:57:15 +0200867 tpm_u32(1), /* Count (number of hashes) */
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200868 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal14d72352018-05-15 11:57:15 +0200869 /* STRING(digest) Digest */
870 };
Miquel Raynal14d72352018-05-15 11:57:15 +0200871 int ret;
872
Simon Glass4927f472022-08-30 21:05:32 -0600873 if (!digest)
874 return -EINVAL;
Miquel Raynal14d72352018-05-15 11:57:15 +0200875 /*
876 * Fill the command structure starting from the first buffer:
877 * - the digest
878 */
879 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200880 offset, digest, digest_len);
Miquel Raynal14d72352018-05-15 11:57:15 +0200881 if (ret)
882 return TPM_LIB_ERROR;
883
Simon Glass8ceca1d2018-11-18 14:22:27 -0700884 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal14d72352018-05-15 11:57:15 +0200885}
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200886
Simon Glass3d930ed2021-02-06 14:23:40 -0700887u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
888{
889 u8 command_v2[COMMAND_BUFFER_SIZE] = {
890 /* header 10 bytes */
891 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
892 tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
893 tpm_u32(TPM2_CC_NV_READ), /* Command code */
894
895 /* handles 8 bytes */
896 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
897 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
898
899 /* AUTH_SESSION */
900 tpm_u32(9), /* Authorization size */
901 tpm_u32(TPM2_RS_PW), /* Session handle */
902 tpm_u16(0), /* Size of <nonce> */
903 /* <nonce> (if any) */
904 0, /* Attributes: Cont/Excl/Rst */
905 tpm_u16(0), /* Size of <hmac/password> */
906 /* <hmac/password> (if any) */
907
908 tpm_u16(count), /* Number of bytes */
909 tpm_u16(0), /* Offset */
910 };
911 size_t response_len = COMMAND_BUFFER_SIZE;
912 u8 response[COMMAND_BUFFER_SIZE];
913 int ret;
914 u16 tag;
915 u32 size, code;
916
917 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
918 if (ret)
919 return log_msg_ret("read", ret);
920 if (unpack_byte_string(response, response_len, "wdds",
921 0, &tag, 2, &size, 6, &code,
922 16, data, count))
923 return TPM_LIB_ERROR;
924
925 return 0;
926}
927
928u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
929 u32 count)
930{
931 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
932 uint offset = 10 + 8 + 4 + 9 + 2;
933 uint len = offset + count + 2;
934 /* Use empty password auth if platform hierarchy is disabled */
935 u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
936 TPM2_RH_PLATFORM;
937 u8 command_v2[COMMAND_BUFFER_SIZE] = {
938 /* header 10 bytes */
939 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
940 tpm_u32(len), /* Length */
941 tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
942
943 /* handles 8 bytes */
944 tpm_u32(auth), /* Primary platform seed */
945 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
946
947 /* AUTH_SESSION */
948 tpm_u32(9), /* Authorization size */
949 tpm_u32(TPM2_RS_PW), /* Session handle */
950 tpm_u16(0), /* Size of <nonce> */
951 /* <nonce> (if any) */
952 0, /* Attributes: Cont/Excl/Rst */
953 tpm_u16(0), /* Size of <hmac/password> */
954 /* <hmac/password> (if any) */
955
956 tpm_u16(count),
957 };
958 size_t response_len = COMMAND_BUFFER_SIZE;
959 u8 response[COMMAND_BUFFER_SIZE];
960 int ret;
961
962 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
963 offset, data, count,
964 offset + count, 0);
965 if (ret)
966 return TPM_LIB_ERROR;
967
968 return tpm_sendrecv_command(dev, command_v2, response, &response_len);
969}
970
Simon Glass8ceca1d2018-11-18 14:22:27 -0700971u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530972 u16 algorithm, void *data, u32 digest_len,
973 unsigned int *updates)
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200974{
975 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
976 u8 command_v2[COMMAND_BUFFER_SIZE] = {
977 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
978 tpm_u32(17 + idx_array_sz), /* Length */
979 tpm_u32(TPM2_CC_PCR_READ), /* Command code */
980
981 /* TPML_PCR_SELECTION */
982 tpm_u32(1), /* Number of selections */
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530983 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200984 idx_array_sz, /* Array size for selection */
985 /* bitmap(idx) Selected PCR bitmap */
986 };
987 size_t response_len = COMMAND_BUFFER_SIZE;
988 u8 response[COMMAND_BUFFER_SIZE];
989 unsigned int pcr_sel_idx = idx / 8;
990 u8 pcr_sel_bit = BIT(idx % 8);
991 unsigned int counter = 0;
992 int ret;
993
994 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
995 17 + pcr_sel_idx, pcr_sel_bit))
996 return TPM_LIB_ERROR;
997
Simon Glass8ceca1d2018-11-18 14:22:27 -0700998 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200999 if (ret)
1000 return ret;
1001
Ruchika Gupta686bedb2021-11-29 13:09:45 +05301002 if (digest_len > response_len)
1003 return TPM_LIB_ERROR;
1004
Miquel Raynal4c1a5852018-05-15 11:57:16 +02001005 if (unpack_byte_string(response, response_len, "ds",
1006 10, &counter,
Ruchika Gupta686bedb2021-11-29 13:09:45 +05301007 response_len - digest_len, data,
1008 digest_len))
Miquel Raynal4c1a5852018-05-15 11:57:16 +02001009 return TPM_LIB_ERROR;
1010
1011 if (updates)
1012 *updates = counter;
1013
1014 return 0;
1015}
Miquel Raynal2e52c062018-05-15 11:57:17 +02001016
Simon Glass8ceca1d2018-11-18 14:22:27 -07001017u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
1018 void *buf, size_t prop_count)
Miquel Raynal2e52c062018-05-15 11:57:17 +02001019{
1020 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1021 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
1022 tpm_u32(22), /* Length */
1023 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
1024
1025 tpm_u32(capability), /* Capability */
1026 tpm_u32(property), /* Property */
1027 tpm_u32(prop_count), /* Property count */
1028 };
1029 u8 response[COMMAND_BUFFER_SIZE];
1030 size_t response_len = COMMAND_BUFFER_SIZE;
1031 unsigned int properties_off;
1032 int ret;
1033
Simon Glass8ceca1d2018-11-18 14:22:27 -07001034 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal2e52c062018-05-15 11:57:17 +02001035 if (ret)
1036 return ret;
1037
1038 /*
1039 * In the response buffer, the properties are located after the:
1040 * tag (u16), response size (u32), response code (u32),
Ilias Apalodimasa0789152020-11-05 23:58:43 +02001041 * YES/NO flag (u8), TPM_CAP (u32).
Miquel Raynal2e52c062018-05-15 11:57:17 +02001042 */
1043 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
Ilias Apalodimasa0789152020-11-05 23:58:43 +02001044 sizeof(u8) + sizeof(u32);
Miquel Raynal2e52c062018-05-15 11:57:17 +02001045 memcpy(buf, &response[properties_off], response_len - properties_off);
1046
1047 return 0;
1048}
Miquel Raynal228e9902018-05-15 11:57:18 +02001049
Eddie James8ed7bb32023-10-24 10:43:49 -05001050static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
1051{
1052 u8 response[(sizeof(struct tpms_capability_data) -
1053 offsetof(struct tpms_capability_data, data))];
1054 u32 properties_offset =
1055 offsetof(struct tpml_tagged_tpm_property, tpm_property) +
1056 offsetof(struct tpms_tagged_property, value);
1057 u32 ret;
1058
1059 memset(response, 0, sizeof(response));
1060 ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
1061 TPM2_PT_PCR_COUNT, response, 1);
1062 if (ret)
1063 return ret;
1064
1065 *num_pcr = get_unaligned_be32(response + properties_offset);
1066 if (*num_pcr > TPM2_MAX_PCRS) {
1067 printf("%s: too many pcrs: %u\n", __func__, *num_pcr);
1068 return -E2BIG;
1069 }
1070
1071 return 0;
1072}
1073
1074static bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection)
1075{
1076 int i;
1077
1078 /*
1079 * check the pcr_select. If at least one of the PCRs supports the
1080 * algorithm add it on the active ones
1081 */
1082 for (i = 0; i < selection->size_of_select; i++) {
1083 if (selection->pcr_select[i])
1084 return true;
1085 }
1086
1087 return false;
1088}
1089
1090int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
1091 u32 *pcr_banks)
1092{
1093 u8 response[(sizeof(struct tpms_capability_data) -
1094 offsetof(struct tpms_capability_data, data))];
1095 struct tpml_pcr_selection pcrs;
1096 u32 num_pcr;
1097 size_t i;
1098 u32 ret;
1099
1100 *supported_pcr = 0;
1101 *active_pcr = 0;
1102 *pcr_banks = 0;
1103 memset(response, 0, sizeof(response));
1104 ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
1105 if (ret)
1106 return ret;
1107
1108 pcrs.count = get_unaligned_be32(response);
1109 /*
1110 * We only support 5 algorithms for now so check against that
1111 * instead of TPM2_NUM_PCR_BANKS
1112 */
1113 if (pcrs.count > ARRAY_SIZE(tpm2_supported_algorithms) ||
1114 pcrs.count < 1) {
1115 printf("%s: too many pcrs: %u\n", __func__, pcrs.count);
1116 return -EMSGSIZE;
1117 }
1118
1119 ret = tpm2_get_num_pcr(dev, &num_pcr);
1120 if (ret)
1121 return ret;
1122
1123 for (i = 0; i < pcrs.count; i++) {
1124 /*
1125 * Definition of TPMS_PCR_SELECTION Structure
1126 * hash: u16
1127 * size_of_select: u8
1128 * pcr_select: u8 array
1129 *
1130 * The offsets depend on the number of the device PCRs
1131 * so we have to calculate them based on that
1132 */
1133 u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
1134 i * offsetof(struct tpms_pcr_selection, pcr_select) +
1135 i * ((num_pcr + 7) / 8);
1136 u32 size_select_offset =
1137 hash_offset + offsetof(struct tpms_pcr_selection,
1138 size_of_select);
1139 u32 pcr_select_offset =
1140 hash_offset + offsetof(struct tpms_pcr_selection,
1141 pcr_select);
1142
1143 pcrs.selection[i].hash =
1144 get_unaligned_be16(response + hash_offset);
1145 pcrs.selection[i].size_of_select =
1146 __get_unaligned_be(response + size_select_offset);
1147 if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
1148 printf("%s: pcrs selection too large: %u\n", __func__,
1149 pcrs.selection[i].size_of_select);
1150 return -ENOBUFS;
1151 }
1152 /* copy the array of pcr_select */
1153 memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset,
1154 pcrs.selection[i].size_of_select);
1155 }
1156
1157 for (i = 0; i < pcrs.count; i++) {
1158 u32 hash_mask = tpm2_algorithm_to_mask(pcrs.selection[i].hash);
1159
1160 if (hash_mask) {
1161 *supported_pcr |= hash_mask;
1162 if (tpm2_is_active_pcr(&pcrs.selection[i]))
1163 *active_pcr |= hash_mask;
1164 } else {
1165 printf("%s: unknown algorithm %x\n", __func__,
1166 pcrs.selection[i].hash);
1167 }
1168 }
1169
1170 *pcr_banks = pcrs.count;
1171
1172 return 0;
1173}
1174
Simon Glass8ceca1d2018-11-18 14:22:27 -07001175u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynal228e9902018-05-15 11:57:18 +02001176{
1177 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1178 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1179 tpm_u32(27 + pw_sz), /* Length */
1180 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
1181
1182 /* HANDLE */
1183 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
1184
1185 /* AUTH_SESSION */
1186 tpm_u32(9 + pw_sz), /* Authorization size */
1187 tpm_u32(TPM2_RS_PW), /* Session handle */
1188 tpm_u16(0), /* Size of <nonce> */
1189 /* <nonce> (if any) */
1190 0, /* Attributes: Cont/Excl/Rst */
1191 tpm_u16(pw_sz), /* Size of <hmac/password> */
1192 /* STRING(pw) <hmac/password> (if any) */
1193 };
1194 unsigned int offset = 27;
1195 int ret;
1196
1197 /*
1198 * Fill the command structure starting from the first buffer:
1199 * - the password (if any)
1200 */
1201 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
1202 offset, pw, pw_sz);
1203 offset += pw_sz;
1204 if (ret)
1205 return TPM_LIB_ERROR;
1206
Simon Glass8ceca1d2018-11-18 14:22:27 -07001207 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal228e9902018-05-15 11:57:18 +02001208}
1209
Simon Glass8ceca1d2018-11-18 14:22:27 -07001210u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
1211 const ssize_t pw_sz, unsigned int max_tries,
1212 unsigned int recovery_time,
Miquel Raynal228e9902018-05-15 11:57:18 +02001213 unsigned int lockout_recovery)
1214{
1215 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1216 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1217 tpm_u32(27 + pw_sz + 12), /* Length */
1218 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
1219
1220 /* HANDLE */
1221 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
1222
1223 /* AUTH_SESSION */
1224 tpm_u32(9 + pw_sz), /* Authorization size */
1225 tpm_u32(TPM2_RS_PW), /* Session handle */
1226 tpm_u16(0), /* Size of <nonce> */
1227 /* <nonce> (if any) */
1228 0, /* Attributes: Cont/Excl/Rst */
1229 tpm_u16(pw_sz), /* Size of <hmac/password> */
1230 /* STRING(pw) <hmac/password> (if any) */
1231
1232 /* LOCKOUT PARAMETERS */
1233 /* tpm_u32(max_tries) Max tries (0, always lock) */
1234 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
1235 /* tpm_u32(lockout_recovery) Lockout recovery */
1236 };
1237 unsigned int offset = 27;
1238 int ret;
1239
1240 /*
1241 * Fill the command structure starting from the first buffer:
1242 * - the password (if any)
1243 * - max tries
1244 * - recovery time
1245 * - lockout recovery
1246 */
1247 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
1248 offset, pw, pw_sz,
1249 offset + pw_sz, max_tries,
1250 offset + pw_sz + 4, recovery_time,
1251 offset + pw_sz + 8, lockout_recovery);
1252 offset += pw_sz + 12;
1253 if (ret)
1254 return TPM_LIB_ERROR;
1255
Simon Glass8ceca1d2018-11-18 14:22:27 -07001256 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal228e9902018-05-15 11:57:18 +02001257}
Miquel Raynal05d7be32018-05-15 11:57:19 +02001258
Simon Glass8ceca1d2018-11-18 14:22:27 -07001259int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
1260 const ssize_t newpw_sz, const char *oldpw,
1261 const ssize_t oldpw_sz)
Miquel Raynal05d7be32018-05-15 11:57:19 +02001262{
1263 unsigned int offset = 27;
1264 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1265 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1266 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
1267 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
1268
1269 /* HANDLE */
1270 tpm_u32(handle), /* TPM resource handle */
1271
1272 /* AUTH_SESSION */
1273 tpm_u32(9 + oldpw_sz), /* Authorization size */
1274 tpm_u32(TPM2_RS_PW), /* Session handle */
1275 tpm_u16(0), /* Size of <nonce> */
1276 /* <nonce> (if any) */
1277 0, /* Attributes: Cont/Excl/Rst */
1278 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
1279 /* STRING(oldpw) <hmac/password> (if any) */
1280
1281 /* TPM2B_AUTH (TPM2B_DIGEST) */
1282 /* tpm_u16(newpw_sz) Digest size, new pw length */
1283 /* STRING(newpw) Digest buffer, new pw */
1284 };
1285 int ret;
1286
1287 /*
1288 * Fill the command structure starting from the first buffer:
1289 * - the old password (if any)
1290 * - size of the new password
1291 * - new password
1292 */
1293 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
1294 offset, oldpw, oldpw_sz,
1295 offset + oldpw_sz, newpw_sz,
1296 offset + oldpw_sz + 2, newpw, newpw_sz);
1297 offset += oldpw_sz + 2 + newpw_sz;
1298 if (ret)
1299 return TPM_LIB_ERROR;
1300
Simon Glass8ceca1d2018-11-18 14:22:27 -07001301 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal05d7be32018-05-15 11:57:19 +02001302}
Miquel Raynal0b864f62018-05-15 11:57:20 +02001303
Simon Glass8ceca1d2018-11-18 14:22:27 -07001304u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
1305 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynal0b864f62018-05-15 11:57:20 +02001306{
1307 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1308 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1309 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
1310 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
1311
1312 /* HANDLE */
1313 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
1314
1315 /* AUTH_SESSION */
1316 tpm_u32(9 + pw_sz), /* Authorization size */
1317 tpm_u32(TPM2_RS_PW), /* session handle */
1318 tpm_u16(0), /* Size of <nonce> */
1319 /* <nonce> (if any) */
1320 0, /* Attributes: Cont/Excl/Rst */
1321 tpm_u16(pw_sz) /* Size of <hmac/password> */
1322 /* STRING(pw) <hmac/password> (if any) */
1323
1324 /* TPM2B_AUTH (TPM2B_DIGEST) */
1325 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
1326 /* STRING(key) Digest buffer (PCR key) */
1327
1328 /* TPMI_ALG_HASH */
1329 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
1330
1331 /* TPMI_DH_PCR */
1332 /* tpm_u32(index), PCR Index */
1333 };
1334 unsigned int offset = 27;
1335 int ret;
1336
1337 /*
1338 * Fill the command structure starting from the first buffer:
1339 * - the password (if any)
1340 * - the PCR key length
1341 * - the PCR key
1342 * - the hash algorithm
1343 * - the PCR index
1344 */
1345 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
1346 offset, pw, pw_sz,
1347 offset + pw_sz, TPM2_DIGEST_LEN,
1348 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
1349 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
1350 TPM2_ALG_SHA256,
1351 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
1352 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
1353 if (ret)
1354 return TPM_LIB_ERROR;
1355
Simon Glass8ceca1d2018-11-18 14:22:27 -07001356 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal0b864f62018-05-15 11:57:20 +02001357}
1358
Simon Glass8ceca1d2018-11-18 14:22:27 -07001359u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
1360 const ssize_t pw_sz, u32 index, const char *key,
1361 const ssize_t key_sz)
Miquel Raynal0b864f62018-05-15 11:57:20 +02001362{
1363 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1364 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1365 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
1366 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
1367
1368 /* HANDLE */
1369 tpm_u32(index), /* Handle (PCR Index) */
1370
1371 /* AUTH_SESSION */
1372 tpm_u32(9 + pw_sz), /* Authorization size */
1373 tpm_u32(TPM2_RS_PW), /* session handle */
1374 tpm_u16(0), /* Size of <nonce> */
1375 /* <nonce> (if any) */
1376 0, /* Attributes: Cont/Excl/Rst */
1377 tpm_u16(pw_sz), /* Size of <hmac/password> */
1378 /* STRING(pw) <hmac/password> (if any) */
1379
1380 /* TPM2B_DIGEST */
1381 /* tpm_u16(key_sz) Key length */
1382 /* STRING(key) Key */
1383 };
1384 unsigned int offset = 27;
1385 int ret;
1386
1387 /*
1388 * Fill the command structure starting from the first buffer:
1389 * - the password (if any)
1390 * - the number of digests, 1 in our case
1391 * - the algorithm, sha256 in our case
1392 * - the digest (64 bytes)
1393 */
1394 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
1395 offset, pw, pw_sz,
1396 offset + pw_sz, key_sz,
1397 offset + pw_sz + 2, key, key_sz);
1398 offset += pw_sz + 2 + key_sz;
1399 if (ret)
1400 return TPM_LIB_ERROR;
1401
Simon Glass8ceca1d2018-11-18 14:22:27 -07001402 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal0b864f62018-05-15 11:57:20 +02001403}
Dhananjay Phadke7a2cf2e2020-06-04 16:43:59 -07001404
1405u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
1406{
1407 const u8 command_v2[10] = {
1408 tpm_u16(TPM2_ST_NO_SESSIONS),
1409 tpm_u32(12),
1410 tpm_u32(TPM2_CC_GET_RANDOM),
1411 };
1412 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
1413
1414 const size_t data_size_offset = 10;
1415 const size_t data_offset = 12;
1416 size_t response_length = sizeof(response);
1417 u32 data_size;
1418 u8 *out = data;
1419
1420 while (count > 0) {
1421 u32 this_bytes = min((size_t)count,
1422 sizeof(response) - data_offset);
1423 u32 err;
1424
1425 if (pack_byte_string(buf, sizeof(buf), "sw",
1426 0, command_v2, sizeof(command_v2),
1427 sizeof(command_v2), this_bytes))
1428 return TPM_LIB_ERROR;
1429 err = tpm_sendrecv_command(dev, buf, response,
1430 &response_length);
1431 if (err)
1432 return err;
1433 if (unpack_byte_string(response, response_length, "w",
1434 data_size_offset, &data_size))
1435 return TPM_LIB_ERROR;
1436 if (data_size > this_bytes)
1437 return TPM_LIB_ERROR;
1438 if (unpack_byte_string(response, response_length, "s",
1439 data_offset, out, data_size))
1440 return TPM_LIB_ERROR;
1441
1442 count -= data_size;
1443 out += data_size;
1444 }
1445
1446 return 0;
1447}
Simon Glasse9d3d592021-02-06 14:23:41 -07001448
1449u32 tpm2_write_lock(struct udevice *dev, u32 index)
1450{
1451 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1452 /* header 10 bytes */
1453 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1454 tpm_u32(10 + 8 + 13), /* Length */
1455 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
1456
1457 /* handles 8 bytes */
1458 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
1459 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
1460
1461 /* session header 9 bytes */
1462 tpm_u32(9), /* Header size */
1463 tpm_u32(TPM2_RS_PW), /* Password authorisation */
1464 tpm_u16(0), /* nonce_size */
1465 0, /* session_attrs */
1466 tpm_u16(0), /* auth_size */
1467 };
1468
1469 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
1470}
Simon Glass77759db2021-02-06 14:23:42 -07001471
1472u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
1473{
1474 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
1475 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1476 /* header 10 bytes */
1477 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1478 tpm_u32(10 + 4 + 13 + 5), /* Length */
1479 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
1480
1481 /* 4 bytes */
1482 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
1483
1484 /* session header 9 bytes */
1485 tpm_u32(9), /* Header size */
1486 tpm_u32(TPM2_RS_PW), /* Password authorisation */
1487 tpm_u16(0), /* nonce_size */
1488 0, /* session_attrs */
1489 tpm_u16(0), /* auth_size */
1490
1491 /* payload 5 bytes */
1492 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
1493 0, /* 0=disable */
1494 };
1495 int ret;
1496
1497 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
1498 log_info("ret=%s, %x\n", dev->name, ret);
1499 if (ret)
1500 return ret;
1501
1502 priv->plat_hier_disabled = true;
1503
1504 return 0;
1505}
Masahisa Kojima06ef6b62021-11-04 22:59:16 +09001506
1507u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
1508 u8 *recvbuf, size_t *recv_size)
1509{
1510 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
1511}
Simon Glass3f7a73a2022-08-30 21:05:37 -06001512
1513u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
1514 u8 *recvbuf, size_t *recv_size)
1515{
1516 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1517 /* header 10 bytes */
1518 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
1519 tpm_u32(10 + 2), /* Length */
1520 tpm_u32(vendor_cmd), /* Command code */
1521
1522 tpm_u16(vendor_subcmd),
1523 };
1524 int ret;
1525
1526 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
1527 log_debug("ret=%s, %x\n", dev->name, ret);
1528 if (ret)
1529 return ret;
1530 if (*recv_size < 12)
1531 return -ENODATA;
1532 *recv_size -= 12;
1533 memcpy(recvbuf, recvbuf + 12, *recv_size);
1534
1535 return 0;
1536}
Simon Glass3564b8e2022-08-30 21:05:38 -06001537
1538u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
1539 uint vendor_subcmd)
1540{
1541 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1542 /* header 10 bytes */
1543 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
1544 tpm_u32(10 + 2), /* Length */
1545 tpm_u32(vendor_cmd), /* Command code */
1546
1547 tpm_u16(vendor_subcmd),
1548 };
1549 int ret;
1550
1551 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
1552 log_debug("ret=%s, %x\n", dev->name, ret);
1553 if (ret)
1554 return ret;
1555
1556 return 0;
1557}