blob: aa02a9e9611a5012d6829c26cc715db18ccb3732 [file] [log] [blame]
Miquel Raynalf3b43502018-05-15 11:57:08 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
Eddie James8ed7bb32023-10-24 10:43:49 -05003 * Copyright (c) 2023 Linaro Limited
Miquel Raynalf3b43502018-05-15 11:57:08 +02004 * Copyright (c) 2018 Bootlin
5 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
6 */
7
Miquel Raynalf3b43502018-05-15 11:57:08 +02008#include <dm.h>
Eddie James8ed7bb32023-10-24 10:43:49 -05009#include <dm/of_access.h>
10#include <tpm_api.h>
Miquel Raynalf3b43502018-05-15 11:57:08 +020011#include <tpm-common.h>
12#include <tpm-v2.h>
Ilias Apalodimasca615322024-06-23 14:48:14 +030013#include <tpm_tcg2.h>
Eddie James8ed7bb32023-10-24 10:43:49 -050014#include <u-boot/sha1.h>
15#include <u-boot/sha256.h>
16#include <u-boot/sha512.h>
17#include <version_string.h>
18#include <asm/io.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060019#include <linux/bitops.h>
Eddie James8ed7bb32023-10-24 10:43:49 -050020#include <linux/unaligned/be_byteshift.h>
21#include <linux/unaligned/generic.h>
22#include <linux/unaligned/le_byteshift.h>
23
Miquel Raynalf3b43502018-05-15 11:57:08 +020024#include "tpm-utils.h"
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020025
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -080026static int tpm2_update_active_banks(struct udevice *dev)
27{
28 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
29 struct tpml_pcr_selection pcrs;
30 int ret, i;
31
32 ret = tpm2_get_pcr_info(dev, &pcrs);
33 if (ret)
34 return ret;
35
36 priv->active_bank_count = 0;
37 for (i = 0; i < pcrs.count; i++) {
38 if (!tpm2_is_active_bank(&pcrs.selection[i]))
39 continue;
40 priv->active_banks[priv->active_bank_count] = pcrs.selection[i].hash;
41 priv->active_bank_count++;
42 }
43
44 return 0;
45}
46
Raymond Maof0c91252025-01-27 06:58:48 -080047static void tpm2_print_selected_algorithm_name(u32 selected)
48{
49 size_t i;
50 const char *str;
51
52 for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
53 const struct digest_info *algo = &hash_algo_list[i];
54
55 if (!(selected & algo->hash_mask))
56 continue;
57
58 str = tpm2_algorithm_name(algo->hash_alg);
59 if (str)
60 log_info("%s\n", str);
61 }
62}
63
64int tpm2_scan_masks(struct udevice *dev, u32 log_active, u32 *mask)
65{
66 struct tpml_pcr_selection pcrs;
67 u32 active = 0;
68 u32 supported = 0;
69 int rc, i;
70
71 *mask = 0;
72
73 rc = tpm2_get_pcr_info(dev, &pcrs);
74 if (rc)
75 return rc;
76
77 for (i = 0; i < pcrs.count; i++) {
78 struct tpms_pcr_selection *sel = &pcrs.selection[i];
79 size_t j;
80 u32 hash_mask = 0;
81
82 for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
83 if (hash_algo_list[j].hash_alg == sel->hash)
84 hash_mask = hash_algo_list[j].hash_mask;
85 }
86
87 if (tpm2_algorithm_supported(sel->hash))
88 supported |= hash_mask;
89
90 if (tpm2_is_active_bank(sel))
91 active |= hash_mask;
92 }
93
94 /* All eventlog algorithm(s) must be supported */
95 if (log_active & ~supported) {
96 log_err("EventLog contains U-Boot unsupported algorithm(s)\n");
97 tpm2_print_selected_algorithm_name(log_active & ~supported);
98 rc = -1;
99 }
100 if (log_active && active & ~log_active) {
101 log_warning("TPM active algorithm(s) not exist in eventlog\n");
102 tpm2_print_selected_algorithm_name(active & ~log_active);
103 *mask = log_active;
104 }
105
106 /* Any active algorithm(s) which are not supported must be removed */
107 if (active & ~supported) {
108 log_warning("TPM active algorithm(s) unsupported by u-boot\n");
109 tpm2_print_selected_algorithm_name(active & ~supported);
110 if (*mask)
111 *mask = active & supported & *mask;
112 else
113 *mask = active & supported;
114 }
115
116 return rc;
117}
118
119static int tpm2_pcr_allocate(struct udevice *dev, u32 algo_mask)
120{
121 struct tpml_pcr_selection pcr = { 0 };
122 u32 pcr_len = 0;
123 int rc;
124
125 rc = tpm2_get_pcr_info(dev, &pcr);
126 if (rc)
127 return rc;
128
129 rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len);
130 if (rc)
131 return rc;
132
133 /* Assume no password */
134 rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len);
135 if (rc)
136 return rc;
137
138 /* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */
139 return tpm2_startup(dev, false, TPM2_SU_CLEAR);
140}
141
142int tpm2_activate_banks(struct udevice *dev, u32 log_active)
143{
144 u32 algo_mask = 0;
145 int rc;
146
147 rc = tpm2_scan_masks(dev, log_active, &algo_mask);
148 if (rc)
149 return rc;
150
151 if (algo_mask) {
152 if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE))
153 return -1;
154
155 rc = tpm2_pcr_allocate(dev, algo_mask);
156 if (rc)
157 return rc;
158
159 log_info("PCR allocate done, shutdown TPM and reboot\n");
160 do_reset(NULL, 0, 0, NULL);
161 log_err("reset does not work!\n");
162 return -1;
163 }
164
165 return 0;
166}
167
Raymond Mao5187a642025-01-27 06:58:46 -0800168u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode)
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200169{
Raymond Mao5187a642025-01-27 06:58:46 -0800170 int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN;
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200171 const u8 command_v2[12] = {
172 tpm_u16(TPM2_ST_NO_SESSIONS),
173 tpm_u32(12),
Raymond Mao5187a642025-01-27 06:58:46 -0800174 tpm_u32(op),
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200175 tpm_u16(mode),
176 };
177 int ret;
178
179 /*
180 * Note TPM2_Startup command will return RC_SUCCESS the first time,
181 * but will return RC_INITIALIZE otherwise.
182 */
Simon Glass8ceca1d2018-11-18 14:22:27 -0700183 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Raymond Mao5187a642025-01-27 06:58:46 -0800184 if ((ret && ret != TPM2_RC_INITIALIZE) || !bon)
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200185 return ret;
186
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -0800187 return tpm2_update_active_banks(dev);
Miquel Raynal65a1a6c2018-05-15 11:57:12 +0200188}
Miquel Raynal39c76082018-05-15 11:57:13 +0200189
Simon Glass8ceca1d2018-11-18 14:22:27 -0700190u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
Miquel Raynal39c76082018-05-15 11:57:13 +0200191{
192 const u8 command_v2[12] = {
193 tpm_u16(TPM2_ST_NO_SESSIONS),
194 tpm_u32(11),
195 tpm_u32(TPM2_CC_SELF_TEST),
196 full_test,
197 };
198
Simon Glass8ceca1d2018-11-18 14:22:27 -0700199 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal39c76082018-05-15 11:57:13 +0200200}
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200201
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200202u32 tpm2_auto_start(struct udevice *dev)
203{
204 u32 rc;
205
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200206 rc = tpm2_self_test(dev, TPMI_YES);
207
208 if (rc == TPM2_RC_INITIALIZE) {
Raymond Mao5187a642025-01-27 06:58:46 -0800209 rc = tpm2_startup(dev, true, TPM2_SU_CLEAR);
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200210 if (rc)
211 return rc;
212
213 rc = tpm2_self_test(dev, TPMI_YES);
214 }
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -0800215 if (rc)
216 return rc;
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200217
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -0800218 return tpm2_update_active_banks(dev);
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +0200219}
220
Simon Glass8ceca1d2018-11-18 14:22:27 -0700221u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
222 const ssize_t pw_sz)
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200223{
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700224 /* Length of the message header, up to start of password */
225 uint offset = 27;
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200226 u8 command_v2[COMMAND_BUFFER_SIZE] = {
227 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700228 tpm_u32(offset + pw_sz), /* Length */
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200229 tpm_u32(TPM2_CC_CLEAR), /* Command code */
230
231 /* HANDLE */
232 tpm_u32(handle), /* TPM resource handle */
233
234 /* AUTH_SESSION */
235 tpm_u32(9 + pw_sz), /* Authorization size */
236 tpm_u32(TPM2_RS_PW), /* Session handle */
237 tpm_u16(0), /* Size of <nonce> */
238 /* <nonce> (if any) */
239 0, /* Attributes: Cont/Excl/Rst */
240 tpm_u16(pw_sz), /* Size of <hmac/password> */
241 /* STRING(pw) <hmac/password> (if any) */
242 };
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200243 int ret;
244
245 /*
246 * Fill the command structure starting from the first buffer:
247 * - the password (if any)
248 */
249 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
250 offset, pw, pw_sz);
251 offset += pw_sz;
252 if (ret)
253 return TPM_LIB_ERROR;
254
Simon Glass8ceca1d2018-11-18 14:22:27 -0700255 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200256}
Miquel Raynal14d72352018-05-15 11:57:15 +0200257
Simon Glass713c58a2021-02-06 14:23:39 -0700258u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
259 size_t space_size, u32 nv_attributes,
260 const u8 *nv_policy, size_t nv_policy_size)
261{
262 /*
263 * Calculate the offset of the nv_policy piece by adding each of the
264 * chunks below.
265 */
Simon Glass5252cac2022-08-30 21:05:34 -0600266 const int platform_len = sizeof(u32);
267 const int session_hdr_len = 13;
268 const int message_len = 14;
269 uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
270 message_len;
Simon Glass713c58a2021-02-06 14:23:39 -0700271 u8 command_v2[COMMAND_BUFFER_SIZE] = {
272 /* header 10 bytes */
273 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass5252cac2022-08-30 21:05:34 -0600274 tpm_u32(offset + nv_policy_size + 2),/* Length */
Simon Glass713c58a2021-02-06 14:23:39 -0700275 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
276
Simon Glass5252cac2022-08-30 21:05:34 -0600277 /* handles 4 bytes */
Simon Glass713c58a2021-02-06 14:23:39 -0700278 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
279
280 /* session header 13 bytes */
281 tpm_u32(9), /* Header size */
282 tpm_u32(TPM2_RS_PW), /* Password authorisation */
283 tpm_u16(0), /* nonce_size */
284 0, /* session_attrs */
285 tpm_u16(0), /* auth_size */
286
287 /* message 14 bytes + policy */
Simon Glass5252cac2022-08-30 21:05:34 -0600288 tpm_u16(message_len + nv_policy_size), /* size */
Simon Glass713c58a2021-02-06 14:23:39 -0700289 tpm_u32(space_index),
290 tpm_u16(TPM2_ALG_SHA256),
291 tpm_u32(nv_attributes),
292 tpm_u16(nv_policy_size),
Simon Glass5252cac2022-08-30 21:05:34 -0600293 /*
294 * nv_policy
295 * space_size
296 */
Simon Glass713c58a2021-02-06 14:23:39 -0700297 };
298 int ret;
299
300 /*
301 * Fill the command structure starting from the first buffer:
302 * - the password (if any)
303 */
Simon Glass5252cac2022-08-30 21:05:34 -0600304 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
305 offset, nv_policy, nv_policy_size,
306 offset + nv_policy_size, space_size);
Simon Glass713c58a2021-02-06 14:23:39 -0700307 if (ret)
308 return TPM_LIB_ERROR;
309
310 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
311}
312
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200313u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
314 const u8 *digest, u32 digest_len)
Miquel Raynal14d72352018-05-15 11:57:15 +0200315{
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700316 /* Length of the message header, up to start of digest */
317 uint offset = 33;
Miquel Raynal14d72352018-05-15 11:57:15 +0200318 u8 command_v2[COMMAND_BUFFER_SIZE] = {
319 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700320 tpm_u32(offset + digest_len), /* Length */
Miquel Raynal14d72352018-05-15 11:57:15 +0200321 tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */
322
323 /* HANDLE */
324 tpm_u32(index), /* Handle (PCR Index) */
325
326 /* AUTH_SESSION */
327 tpm_u32(9), /* Authorization size */
328 tpm_u32(TPM2_RS_PW), /* Session handle */
329 tpm_u16(0), /* Size of <nonce> */
330 /* <nonce> (if any) */
331 0, /* Attributes: Cont/Excl/Rst */
332 tpm_u16(0), /* Size of <hmac/password> */
333 /* <hmac/password> (if any) */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700334
335 /* hashes */
Miquel Raynal14d72352018-05-15 11:57:15 +0200336 tpm_u32(1), /* Count (number of hashes) */
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200337 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal14d72352018-05-15 11:57:15 +0200338 /* STRING(digest) Digest */
339 };
Miquel Raynal14d72352018-05-15 11:57:15 +0200340 int ret;
341
Simon Glass4927f472022-08-30 21:05:32 -0600342 if (!digest)
343 return -EINVAL;
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300344
Ilias Apalodimasd788b062024-12-24 08:01:05 -0800345 if (!tpm2_check_active_banks(dev)) {
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300346 log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n");
347 return -EINVAL;
348 }
Miquel Raynal14d72352018-05-15 11:57:15 +0200349 /*
350 * Fill the command structure starting from the first buffer:
351 * - the digest
352 */
353 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200354 offset, digest, digest_len);
Miquel Raynal14d72352018-05-15 11:57:15 +0200355 if (ret)
356 return TPM_LIB_ERROR;
357
Simon Glass8ceca1d2018-11-18 14:22:27 -0700358 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal14d72352018-05-15 11:57:15 +0200359}
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200360
Simon Glass3d930ed2021-02-06 14:23:40 -0700361u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
362{
363 u8 command_v2[COMMAND_BUFFER_SIZE] = {
364 /* header 10 bytes */
365 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
366 tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
367 tpm_u32(TPM2_CC_NV_READ), /* Command code */
368
369 /* handles 8 bytes */
370 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
371 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
372
373 /* AUTH_SESSION */
374 tpm_u32(9), /* Authorization size */
375 tpm_u32(TPM2_RS_PW), /* Session handle */
376 tpm_u16(0), /* Size of <nonce> */
377 /* <nonce> (if any) */
378 0, /* Attributes: Cont/Excl/Rst */
379 tpm_u16(0), /* Size of <hmac/password> */
380 /* <hmac/password> (if any) */
381
382 tpm_u16(count), /* Number of bytes */
383 tpm_u16(0), /* Offset */
384 };
385 size_t response_len = COMMAND_BUFFER_SIZE;
386 u8 response[COMMAND_BUFFER_SIZE];
387 int ret;
388 u16 tag;
389 u32 size, code;
390
391 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
392 if (ret)
393 return log_msg_ret("read", ret);
394 if (unpack_byte_string(response, response_len, "wdds",
395 0, &tag, 2, &size, 6, &code,
396 16, data, count))
397 return TPM_LIB_ERROR;
398
399 return 0;
400}
401
402u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
403 u32 count)
404{
405 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
406 uint offset = 10 + 8 + 4 + 9 + 2;
407 uint len = offset + count + 2;
408 /* Use empty password auth if platform hierarchy is disabled */
409 u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
410 TPM2_RH_PLATFORM;
411 u8 command_v2[COMMAND_BUFFER_SIZE] = {
412 /* header 10 bytes */
413 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
414 tpm_u32(len), /* Length */
415 tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
416
417 /* handles 8 bytes */
418 tpm_u32(auth), /* Primary platform seed */
419 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
420
421 /* AUTH_SESSION */
422 tpm_u32(9), /* Authorization size */
423 tpm_u32(TPM2_RS_PW), /* Session handle */
424 tpm_u16(0), /* Size of <nonce> */
425 /* <nonce> (if any) */
426 0, /* Attributes: Cont/Excl/Rst */
427 tpm_u16(0), /* Size of <hmac/password> */
428 /* <hmac/password> (if any) */
429
430 tpm_u16(count),
431 };
432 size_t response_len = COMMAND_BUFFER_SIZE;
433 u8 response[COMMAND_BUFFER_SIZE];
434 int ret;
435
436 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
437 offset, data, count,
438 offset + count, 0);
439 if (ret)
440 return TPM_LIB_ERROR;
441
442 return tpm_sendrecv_command(dev, command_v2, response, &response_len);
443}
444
Simon Glass8ceca1d2018-11-18 14:22:27 -0700445u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530446 u16 algorithm, void *data, u32 digest_len,
447 unsigned int *updates)
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200448{
449 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
450 u8 command_v2[COMMAND_BUFFER_SIZE] = {
451 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
452 tpm_u32(17 + idx_array_sz), /* Length */
453 tpm_u32(TPM2_CC_PCR_READ), /* Command code */
454
455 /* TPML_PCR_SELECTION */
456 tpm_u32(1), /* Number of selections */
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530457 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200458 idx_array_sz, /* Array size for selection */
459 /* bitmap(idx) Selected PCR bitmap */
460 };
461 size_t response_len = COMMAND_BUFFER_SIZE;
462 u8 response[COMMAND_BUFFER_SIZE];
463 unsigned int pcr_sel_idx = idx / 8;
464 u8 pcr_sel_bit = BIT(idx % 8);
465 unsigned int counter = 0;
466 int ret;
467
468 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
469 17 + pcr_sel_idx, pcr_sel_bit))
470 return TPM_LIB_ERROR;
471
Simon Glass8ceca1d2018-11-18 14:22:27 -0700472 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200473 if (ret)
474 return ret;
475
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530476 if (digest_len > response_len)
477 return TPM_LIB_ERROR;
478
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200479 if (unpack_byte_string(response, response_len, "ds",
480 10, &counter,
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530481 response_len - digest_len, data,
482 digest_len))
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200483 return TPM_LIB_ERROR;
484
485 if (updates)
486 *updates = counter;
487
488 return 0;
489}
Miquel Raynal2e52c062018-05-15 11:57:17 +0200490
Simon Glass8ceca1d2018-11-18 14:22:27 -0700491u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
492 void *buf, size_t prop_count)
Miquel Raynal2e52c062018-05-15 11:57:17 +0200493{
494 u8 command_v2[COMMAND_BUFFER_SIZE] = {
495 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
496 tpm_u32(22), /* Length */
497 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
498
499 tpm_u32(capability), /* Capability */
500 tpm_u32(property), /* Property */
501 tpm_u32(prop_count), /* Property count */
502 };
503 u8 response[COMMAND_BUFFER_SIZE];
504 size_t response_len = COMMAND_BUFFER_SIZE;
505 unsigned int properties_off;
506 int ret;
507
Simon Glass8ceca1d2018-11-18 14:22:27 -0700508 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal2e52c062018-05-15 11:57:17 +0200509 if (ret)
510 return ret;
511
512 /*
513 * In the response buffer, the properties are located after the:
514 * tag (u16), response size (u32), response code (u32),
Ilias Apalodimasa0789152020-11-05 23:58:43 +0200515 * YES/NO flag (u8), TPM_CAP (u32).
Miquel Raynal2e52c062018-05-15 11:57:17 +0200516 */
517 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
Ilias Apalodimasa0789152020-11-05 23:58:43 +0200518 sizeof(u8) + sizeof(u32);
Miquel Raynal2e52c062018-05-15 11:57:17 +0200519 memcpy(buf, &response[properties_off], response_len - properties_off);
520
521 return 0;
522}
Miquel Raynal228e9902018-05-15 11:57:18 +0200523
Raymond Maof69f2d72025-01-27 06:58:47 -0800524u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask,
525 struct tpml_pcr_selection *pcr, u32 *pcr_len)
526{
527 int i;
528
529 if (pcr->count > TPM2_NUM_PCR_BANKS)
530 return TPM_LIB_ERROR;
531
532 *pcr_len = sizeof(pcr->count);
533
534 for (i = 0; i < pcr->count; i++) {
535 struct tpms_pcr_selection *sel = &pcr->selection[i];
536 u8 pad = 0;
537 int j;
538
539 if (sel->size_of_select > TPM2_PCR_SELECT_MAX)
540 return TPM_LIB_ERROR;
541
542 /*
543 * Found the algorithm (bank) that matches, and enable all PCR
544 * bits.
545 * TODO: only select the bits needed
546 */
547 for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
548 if (hash_algo_list[j].hash_alg != sel->hash)
549 continue;
550
551 if (algo_mask & hash_algo_list[j].hash_mask)
552 pad = 0xff;
553 }
554
555 for (j = 0; j < sel->size_of_select; j++)
556 sel->pcr_select[j] = pad;
557
558 log_info("set bank[%d] %s %s\n", i,
559 tpm2_algorithm_name(sel->hash),
560 tpm2_is_active_bank(sel) ? "on" : "off");
561
562 *pcr_len += sizeof(sel->hash) + sizeof(sel->size_of_select) +
563 sel->size_of_select;
564 }
565
566 return 0;
567}
568
569u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw,
570 const ssize_t pw_sz, struct tpml_pcr_selection *pcr,
571 u32 pcr_len)
572{
573 /* Length of the message header, up to start of password */
574 uint offset = 27;
575 u8 command_v2[COMMAND_BUFFER_SIZE] = {
576 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
577 tpm_u32(offset + pw_sz + pcr_len), /* Length */
578 tpm_u32(TPM2_CC_PCR_ALLOCATE), /* Command code */
579
580 /* handles 4 bytes */
581 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
582
583 /* AUTH_SESSION */
584 tpm_u32(9 + pw_sz), /* Authorization size */
585 tpm_u32(TPM2_RS_PW), /* Session handle */
586 tpm_u16(0), /* Size of <nonce> */
587 /* <nonce> (if any) */
588 0, /* Attributes: Cont/Excl/Rst */
589 tpm_u16(pw_sz), /* Size of <hmac/password> */
590 /* STRING(pw) <hmac/password> (if any) */
591
592 /* TPML_PCR_SELECTION */
593 };
594 u8 response[COMMAND_BUFFER_SIZE];
595 size_t response_len = COMMAND_BUFFER_SIZE;
596 u32 i;
597 int ret;
598
599 /*
600 * Fill the command structure starting from the first buffer:
601 * the password (if any)
602 */
603 if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, pw,
604 pw_sz))
605 return TPM_LIB_ERROR;
606
607 offset += pw_sz;
608
609 /* Pack the count field */
610 if (pack_byte_string(command_v2, sizeof(command_v2), "d", offset, pcr->count))
611 return TPM_LIB_ERROR;
612
613 offset += sizeof(pcr->count);
614
615 /* Pack each tpms_pcr_selection */
616 for (i = 0; i < pcr->count; i++) {
617 struct tpms_pcr_selection *sel = &pcr->selection[i];
618
619 /* Pack hash (16-bit) */
620 if (pack_byte_string(command_v2, sizeof(command_v2), "w", offset,
621 sel->hash))
622 return TPM_LIB_ERROR;
623
624 offset += sizeof(sel->hash);
625
626 /* Pack size_of_select (8-bit) */
627 if (pack_byte_string(command_v2, sizeof(command_v2), "b", offset,
628 sel->size_of_select))
629 return TPM_LIB_ERROR;
630
631 offset += sizeof(sel->size_of_select);
632
633 /* Pack pcr_select array */
634 if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset,
635 sel->pcr_select, sel->size_of_select))
636 return TPM_LIB_ERROR;
637
638 offset += sel->size_of_select;
639 }
640
641 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
642 if (!ret)
643 tpm_init(dev);
644
645 return ret;
646}
647
Eddie James8ed7bb32023-10-24 10:43:49 -0500648static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
649{
650 u8 response[(sizeof(struct tpms_capability_data) -
651 offsetof(struct tpms_capability_data, data))];
652 u32 properties_offset =
653 offsetof(struct tpml_tagged_tpm_property, tpm_property) +
654 offsetof(struct tpms_tagged_property, value);
655 u32 ret;
656
657 memset(response, 0, sizeof(response));
658 ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
659 TPM2_PT_PCR_COUNT, response, 1);
660 if (ret)
661 return ret;
662
663 *num_pcr = get_unaligned_be32(response + properties_offset);
664 if (*num_pcr > TPM2_MAX_PCRS) {
665 printf("%s: too many pcrs: %u\n", __func__, *num_pcr);
666 return -E2BIG;
667 }
668
669 return 0;
670}
671
Ilias Apalodimascb356612024-06-23 14:48:17 +0300672int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs)
Eddie James8ed7bb32023-10-24 10:43:49 -0500673{
674 u8 response[(sizeof(struct tpms_capability_data) -
675 offsetof(struct tpms_capability_data, data))];
Eddie James8ed7bb32023-10-24 10:43:49 -0500676 u32 num_pcr;
677 size_t i;
678 u32 ret;
679
Eddie James8ed7bb32023-10-24 10:43:49 -0500680 ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
681 if (ret)
682 return ret;
683
Ilias Apalodimascb356612024-06-23 14:48:17 +0300684 pcrs->count = get_unaligned_be32(response);
Eddie James8ed7bb32023-10-24 10:43:49 -0500685 /*
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300686 * We only support 4 algorithms for now so check against that
Eddie James8ed7bb32023-10-24 10:43:49 -0500687 * instead of TPM2_NUM_PCR_BANKS
688 */
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300689 if (pcrs->count > 4 || pcrs->count < 1) {
Ilias Apalodimascb356612024-06-23 14:48:17 +0300690 printf("%s: too many pcrs: %u\n", __func__, pcrs->count);
Eddie James8ed7bb32023-10-24 10:43:49 -0500691 return -EMSGSIZE;
692 }
693
694 ret = tpm2_get_num_pcr(dev, &num_pcr);
695 if (ret)
696 return ret;
697
Ilias Apalodimascb356612024-06-23 14:48:17 +0300698 for (i = 0; i < pcrs->count; i++) {
Eddie James8ed7bb32023-10-24 10:43:49 -0500699 /*
700 * Definition of TPMS_PCR_SELECTION Structure
701 * hash: u16
702 * size_of_select: u8
703 * pcr_select: u8 array
704 *
705 * The offsets depend on the number of the device PCRs
706 * so we have to calculate them based on that
707 */
708 u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
709 i * offsetof(struct tpms_pcr_selection, pcr_select) +
710 i * ((num_pcr + 7) / 8);
711 u32 size_select_offset =
712 hash_offset + offsetof(struct tpms_pcr_selection,
713 size_of_select);
714 u32 pcr_select_offset =
715 hash_offset + offsetof(struct tpms_pcr_selection,
716 pcr_select);
717
Ilias Apalodimascb356612024-06-23 14:48:17 +0300718 pcrs->selection[i].hash =
Eddie James8ed7bb32023-10-24 10:43:49 -0500719 get_unaligned_be16(response + hash_offset);
Ilias Apalodimascb356612024-06-23 14:48:17 +0300720 pcrs->selection[i].size_of_select =
Eddie James8ed7bb32023-10-24 10:43:49 -0500721 __get_unaligned_be(response + size_select_offset);
Ilias Apalodimascb356612024-06-23 14:48:17 +0300722 if (pcrs->selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
Eddie James8ed7bb32023-10-24 10:43:49 -0500723 printf("%s: pcrs selection too large: %u\n", __func__,
Ilias Apalodimascb356612024-06-23 14:48:17 +0300724 pcrs->selection[i].size_of_select);
Eddie James8ed7bb32023-10-24 10:43:49 -0500725 return -ENOBUFS;
726 }
727 /* copy the array of pcr_select */
Ilias Apalodimascb356612024-06-23 14:48:17 +0300728 memcpy(pcrs->selection[i].pcr_select, response + pcr_select_offset,
729 pcrs->selection[i].size_of_select);
Eddie James8ed7bb32023-10-24 10:43:49 -0500730 }
731
Eddie James8ed7bb32023-10-24 10:43:49 -0500732 return 0;
733}
734
Simon Glass8ceca1d2018-11-18 14:22:27 -0700735u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynal228e9902018-05-15 11:57:18 +0200736{
737 u8 command_v2[COMMAND_BUFFER_SIZE] = {
738 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
739 tpm_u32(27 + pw_sz), /* Length */
740 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
741
742 /* HANDLE */
743 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
744
745 /* AUTH_SESSION */
746 tpm_u32(9 + pw_sz), /* Authorization size */
747 tpm_u32(TPM2_RS_PW), /* Session handle */
748 tpm_u16(0), /* Size of <nonce> */
749 /* <nonce> (if any) */
750 0, /* Attributes: Cont/Excl/Rst */
751 tpm_u16(pw_sz), /* Size of <hmac/password> */
752 /* STRING(pw) <hmac/password> (if any) */
753 };
754 unsigned int offset = 27;
755 int ret;
756
757 /*
758 * Fill the command structure starting from the first buffer:
759 * - the password (if any)
760 */
761 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
762 offset, pw, pw_sz);
763 offset += pw_sz;
764 if (ret)
765 return TPM_LIB_ERROR;
766
Simon Glass8ceca1d2018-11-18 14:22:27 -0700767 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal228e9902018-05-15 11:57:18 +0200768}
769
Simon Glass8ceca1d2018-11-18 14:22:27 -0700770u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
771 const ssize_t pw_sz, unsigned int max_tries,
772 unsigned int recovery_time,
Miquel Raynal228e9902018-05-15 11:57:18 +0200773 unsigned int lockout_recovery)
774{
775 u8 command_v2[COMMAND_BUFFER_SIZE] = {
776 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
777 tpm_u32(27 + pw_sz + 12), /* Length */
778 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
779
780 /* HANDLE */
781 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
782
783 /* AUTH_SESSION */
784 tpm_u32(9 + pw_sz), /* Authorization size */
785 tpm_u32(TPM2_RS_PW), /* Session handle */
786 tpm_u16(0), /* Size of <nonce> */
787 /* <nonce> (if any) */
788 0, /* Attributes: Cont/Excl/Rst */
789 tpm_u16(pw_sz), /* Size of <hmac/password> */
790 /* STRING(pw) <hmac/password> (if any) */
791
792 /* LOCKOUT PARAMETERS */
793 /* tpm_u32(max_tries) Max tries (0, always lock) */
794 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
795 /* tpm_u32(lockout_recovery) Lockout recovery */
796 };
797 unsigned int offset = 27;
798 int ret;
799
800 /*
801 * Fill the command structure starting from the first buffer:
802 * - the password (if any)
803 * - max tries
804 * - recovery time
805 * - lockout recovery
806 */
807 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
808 offset, pw, pw_sz,
809 offset + pw_sz, max_tries,
810 offset + pw_sz + 4, recovery_time,
811 offset + pw_sz + 8, lockout_recovery);
812 offset += pw_sz + 12;
813 if (ret)
814 return TPM_LIB_ERROR;
815
Simon Glass8ceca1d2018-11-18 14:22:27 -0700816 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal228e9902018-05-15 11:57:18 +0200817}
Miquel Raynal05d7be32018-05-15 11:57:19 +0200818
Simon Glass8ceca1d2018-11-18 14:22:27 -0700819int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
820 const ssize_t newpw_sz, const char *oldpw,
821 const ssize_t oldpw_sz)
Miquel Raynal05d7be32018-05-15 11:57:19 +0200822{
823 unsigned int offset = 27;
824 u8 command_v2[COMMAND_BUFFER_SIZE] = {
825 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
826 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
827 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
828
829 /* HANDLE */
830 tpm_u32(handle), /* TPM resource handle */
831
832 /* AUTH_SESSION */
833 tpm_u32(9 + oldpw_sz), /* Authorization size */
834 tpm_u32(TPM2_RS_PW), /* Session handle */
835 tpm_u16(0), /* Size of <nonce> */
836 /* <nonce> (if any) */
837 0, /* Attributes: Cont/Excl/Rst */
838 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
839 /* STRING(oldpw) <hmac/password> (if any) */
840
841 /* TPM2B_AUTH (TPM2B_DIGEST) */
842 /* tpm_u16(newpw_sz) Digest size, new pw length */
843 /* STRING(newpw) Digest buffer, new pw */
844 };
845 int ret;
846
847 /*
848 * Fill the command structure starting from the first buffer:
849 * - the old password (if any)
850 * - size of the new password
851 * - new password
852 */
853 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
854 offset, oldpw, oldpw_sz,
855 offset + oldpw_sz, newpw_sz,
856 offset + oldpw_sz + 2, newpw, newpw_sz);
857 offset += oldpw_sz + 2 + newpw_sz;
858 if (ret)
859 return TPM_LIB_ERROR;
860
Simon Glass8ceca1d2018-11-18 14:22:27 -0700861 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal05d7be32018-05-15 11:57:19 +0200862}
Miquel Raynal0b864f62018-05-15 11:57:20 +0200863
Simon Glass8ceca1d2018-11-18 14:22:27 -0700864u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
865 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynal0b864f62018-05-15 11:57:20 +0200866{
867 u8 command_v2[COMMAND_BUFFER_SIZE] = {
868 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
869 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
870 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
871
872 /* HANDLE */
873 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
874
875 /* AUTH_SESSION */
876 tpm_u32(9 + pw_sz), /* Authorization size */
877 tpm_u32(TPM2_RS_PW), /* session handle */
878 tpm_u16(0), /* Size of <nonce> */
879 /* <nonce> (if any) */
880 0, /* Attributes: Cont/Excl/Rst */
881 tpm_u16(pw_sz) /* Size of <hmac/password> */
882 /* STRING(pw) <hmac/password> (if any) */
883
884 /* TPM2B_AUTH (TPM2B_DIGEST) */
885 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
886 /* STRING(key) Digest buffer (PCR key) */
887
888 /* TPMI_ALG_HASH */
889 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
890
891 /* TPMI_DH_PCR */
892 /* tpm_u32(index), PCR Index */
893 };
894 unsigned int offset = 27;
895 int ret;
896
897 /*
898 * Fill the command structure starting from the first buffer:
899 * - the password (if any)
900 * - the PCR key length
901 * - the PCR key
902 * - the hash algorithm
903 * - the PCR index
904 */
905 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
906 offset, pw, pw_sz,
907 offset + pw_sz, TPM2_DIGEST_LEN,
908 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
909 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
910 TPM2_ALG_SHA256,
911 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
912 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
913 if (ret)
914 return TPM_LIB_ERROR;
915
Simon Glass8ceca1d2018-11-18 14:22:27 -0700916 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal0b864f62018-05-15 11:57:20 +0200917}
918
Simon Glass8ceca1d2018-11-18 14:22:27 -0700919u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
920 const ssize_t pw_sz, u32 index, const char *key,
921 const ssize_t key_sz)
Miquel Raynal0b864f62018-05-15 11:57:20 +0200922{
923 u8 command_v2[COMMAND_BUFFER_SIZE] = {
924 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
925 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
926 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
927
928 /* HANDLE */
929 tpm_u32(index), /* Handle (PCR Index) */
930
931 /* AUTH_SESSION */
932 tpm_u32(9 + pw_sz), /* Authorization size */
933 tpm_u32(TPM2_RS_PW), /* session handle */
934 tpm_u16(0), /* Size of <nonce> */
935 /* <nonce> (if any) */
936 0, /* Attributes: Cont/Excl/Rst */
937 tpm_u16(pw_sz), /* Size of <hmac/password> */
938 /* STRING(pw) <hmac/password> (if any) */
939
940 /* TPM2B_DIGEST */
941 /* tpm_u16(key_sz) Key length */
942 /* STRING(key) Key */
943 };
944 unsigned int offset = 27;
945 int ret;
946
947 /*
948 * Fill the command structure starting from the first buffer:
949 * - the password (if any)
950 * - the number of digests, 1 in our case
951 * - the algorithm, sha256 in our case
952 * - the digest (64 bytes)
953 */
954 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
955 offset, pw, pw_sz,
956 offset + pw_sz, key_sz,
957 offset + pw_sz + 2, key, key_sz);
958 offset += pw_sz + 2 + key_sz;
959 if (ret)
960 return TPM_LIB_ERROR;
961
Simon Glass8ceca1d2018-11-18 14:22:27 -0700962 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal0b864f62018-05-15 11:57:20 +0200963}
Dhananjay Phadke7a2cf2e2020-06-04 16:43:59 -0700964
965u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
966{
967 const u8 command_v2[10] = {
968 tpm_u16(TPM2_ST_NO_SESSIONS),
969 tpm_u32(12),
970 tpm_u32(TPM2_CC_GET_RANDOM),
971 };
972 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
973
974 const size_t data_size_offset = 10;
975 const size_t data_offset = 12;
976 size_t response_length = sizeof(response);
977 u32 data_size;
978 u8 *out = data;
979
980 while (count > 0) {
981 u32 this_bytes = min((size_t)count,
982 sizeof(response) - data_offset);
983 u32 err;
984
985 if (pack_byte_string(buf, sizeof(buf), "sw",
986 0, command_v2, sizeof(command_v2),
987 sizeof(command_v2), this_bytes))
988 return TPM_LIB_ERROR;
989 err = tpm_sendrecv_command(dev, buf, response,
990 &response_length);
991 if (err)
992 return err;
993 if (unpack_byte_string(response, response_length, "w",
994 data_size_offset, &data_size))
995 return TPM_LIB_ERROR;
996 if (data_size > this_bytes)
997 return TPM_LIB_ERROR;
998 if (unpack_byte_string(response, response_length, "s",
999 data_offset, out, data_size))
1000 return TPM_LIB_ERROR;
1001
1002 count -= data_size;
1003 out += data_size;
1004 }
1005
1006 return 0;
1007}
Simon Glasse9d3d592021-02-06 14:23:41 -07001008
1009u32 tpm2_write_lock(struct udevice *dev, u32 index)
1010{
1011 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1012 /* header 10 bytes */
1013 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1014 tpm_u32(10 + 8 + 13), /* Length */
1015 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
1016
1017 /* handles 8 bytes */
1018 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
1019 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
1020
1021 /* session header 9 bytes */
1022 tpm_u32(9), /* Header size */
1023 tpm_u32(TPM2_RS_PW), /* Password authorisation */
1024 tpm_u16(0), /* nonce_size */
1025 0, /* session_attrs */
1026 tpm_u16(0), /* auth_size */
1027 };
1028
1029 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
1030}
Simon Glass77759db2021-02-06 14:23:42 -07001031
1032u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
1033{
1034 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
1035 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1036 /* header 10 bytes */
1037 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
1038 tpm_u32(10 + 4 + 13 + 5), /* Length */
1039 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
1040
1041 /* 4 bytes */
1042 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
1043
1044 /* session header 9 bytes */
1045 tpm_u32(9), /* Header size */
1046 tpm_u32(TPM2_RS_PW), /* Password authorisation */
1047 tpm_u16(0), /* nonce_size */
1048 0, /* session_attrs */
1049 tpm_u16(0), /* auth_size */
1050
1051 /* payload 5 bytes */
1052 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
1053 0, /* 0=disable */
1054 };
1055 int ret;
1056
1057 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
1058 log_info("ret=%s, %x\n", dev->name, ret);
1059 if (ret)
1060 return ret;
1061
1062 priv->plat_hier_disabled = true;
1063
1064 return 0;
1065}
Masahisa Kojima06ef6b62021-11-04 22:59:16 +09001066
1067u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
1068 u8 *recvbuf, size_t *recv_size)
1069{
1070 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
1071}
Simon Glass3f7a73a2022-08-30 21:05:37 -06001072
1073u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
1074 u8 *recvbuf, size_t *recv_size)
1075{
1076 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1077 /* header 10 bytes */
1078 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
1079 tpm_u32(10 + 2), /* Length */
1080 tpm_u32(vendor_cmd), /* Command code */
1081
1082 tpm_u16(vendor_subcmd),
1083 };
1084 int ret;
1085
1086 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
1087 log_debug("ret=%s, %x\n", dev->name, ret);
1088 if (ret)
1089 return ret;
1090 if (*recv_size < 12)
1091 return -ENODATA;
1092 *recv_size -= 12;
Heinrich Schuchardt5b8577d2024-11-02 11:27:37 +01001093 memmove(recvbuf, recvbuf + 12, *recv_size);
Simon Glass3f7a73a2022-08-30 21:05:37 -06001094
1095 return 0;
1096}
Simon Glass3564b8e2022-08-30 21:05:38 -06001097
1098u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
1099 uint vendor_subcmd)
1100{
1101 u8 command_v2[COMMAND_BUFFER_SIZE] = {
1102 /* header 10 bytes */
1103 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
1104 tpm_u32(10 + 2), /* Length */
1105 tpm_u32(vendor_cmd), /* Command code */
1106
1107 tpm_u16(vendor_subcmd),
1108 };
1109 int ret;
1110
1111 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
1112 log_debug("ret=%s, %x\n", dev->name, ret);
1113 if (ret)
1114 return ret;
1115
1116 return 0;
1117}
Tim Harvey6ea1e052024-05-25 13:00:48 -07001118
Ilias Apalodimas9465f7a2024-12-24 08:01:04 -08001119bool tpm2_is_active_bank(struct tpms_pcr_selection *selection)
Ilias Apalodimascb356612024-06-23 14:48:17 +03001120{
1121 int i;
1122
1123 for (i = 0; i < selection->size_of_select; i++) {
1124 if (selection->pcr_select[i])
1125 return true;
1126 }
1127
1128 return false;
1129}
1130
Tim Harvey6ea1e052024-05-25 13:00:48 -07001131enum tpm2_algorithms tpm2_name_to_algorithm(const char *name)
1132{
1133 size_t i;
1134
1135 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1136 if (!strcasecmp(name, hash_algo_list[i].hash_name))
1137 return hash_algo_list[i].hash_alg;
1138 }
1139 printf("%s: unsupported algorithm %s\n", __func__, name);
1140
1141 return -EINVAL;
1142}
1143
1144const char *tpm2_algorithm_name(enum tpm2_algorithms algo)
1145{
1146 size_t i;
1147
1148 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1149 if (hash_algo_list[i].hash_alg == algo)
1150 return hash_algo_list[i].hash_name;
1151 }
1152
1153 return "";
1154}
1155
Raymond Mao43158122024-12-24 08:01:07 -08001156bool tpm2_algorithm_supported(enum tpm2_algorithms algo)
1157{
1158 size_t i;
1159
1160 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1161 if (hash_algo_list[i].hash_alg == algo)
1162 return hash_algo_list[i].supported;
1163 }
1164
1165 return false;
1166}
1167
Ilias Apalodimas1e665f92024-06-23 14:48:18 +03001168u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo)
1169{
1170 size_t i;
1171
1172 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1173 if (hash_algo_list[i].hash_alg == algo)
1174 return hash_algo_list[i].hash_len;
1175 }
1176
1177 return 0;
1178}
1179
Ilias Apalodimasd788b062024-12-24 08:01:05 -08001180bool tpm2_check_active_banks(struct udevice *dev)
Ilias Apalodimas1e665f92024-06-23 14:48:18 +03001181{
1182 struct tpml_pcr_selection pcrs;
1183 size_t i;
1184 int rc;
1185
1186 rc = tpm2_get_pcr_info(dev, &pcrs);
1187 if (rc)
1188 return false;
1189
1190 for (i = 0; i < pcrs.count; i++) {
Ilias Apalodimas9465f7a2024-12-24 08:01:04 -08001191 if (tpm2_is_active_bank(&pcrs.selection[i]) &&
Raymond Mao43158122024-12-24 08:01:07 -08001192 !tpm2_algorithm_supported(pcrs.selection[i].hash))
Ilias Apalodimas1e665f92024-06-23 14:48:18 +03001193 return false;
1194 }
1195
1196 return true;
1197}
Ilias Apalodimas7b1e5222024-12-24 08:01:08 -08001198
1199void tpm2_print_active_banks(struct udevice *dev)
1200{
1201 struct tpml_pcr_selection pcrs;
1202 size_t i;
1203 int rc;
1204
1205 rc = tpm2_get_pcr_info(dev, &pcrs);
1206 if (rc) {
1207 log_err("Can't retrieve active PCRs\n");
1208 return;
1209 }
1210
1211 for (i = 0; i < pcrs.count; i++) {
1212 if (tpm2_is_active_bank(&pcrs.selection[i])) {
1213 const char *str;
1214
1215 str = tpm2_algorithm_name(pcrs.selection[i].hash);
1216 if (str)
1217 log_info("%s\n", str);
1218 }
1219 }
1220}