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