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