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