blob: 045b5dd9ebd2366651b7f147948aecd3326dcc26 [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 Mao5187a642025-01-27 06:58:46 -080047u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode)
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020048{
Raymond Mao5187a642025-01-27 06:58:46 -080049 int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN;
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020050 const u8 command_v2[12] = {
51 tpm_u16(TPM2_ST_NO_SESSIONS),
52 tpm_u32(12),
Raymond Mao5187a642025-01-27 06:58:46 -080053 tpm_u32(op),
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020054 tpm_u16(mode),
55 };
56 int ret;
57
58 /*
59 * Note TPM2_Startup command will return RC_SUCCESS the first time,
60 * but will return RC_INITIALIZE otherwise.
61 */
Simon Glass8ceca1d2018-11-18 14:22:27 -070062 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Raymond Mao5187a642025-01-27 06:58:46 -080063 if ((ret && ret != TPM2_RC_INITIALIZE) || !bon)
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020064 return ret;
65
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -080066 return tpm2_update_active_banks(dev);
Miquel Raynal65a1a6c2018-05-15 11:57:12 +020067}
Miquel Raynal39c76082018-05-15 11:57:13 +020068
Simon Glass8ceca1d2018-11-18 14:22:27 -070069u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
Miquel Raynal39c76082018-05-15 11:57:13 +020070{
71 const u8 command_v2[12] = {
72 tpm_u16(TPM2_ST_NO_SESSIONS),
73 tpm_u32(11),
74 tpm_u32(TPM2_CC_SELF_TEST),
75 full_test,
76 };
77
Simon Glass8ceca1d2018-11-18 14:22:27 -070078 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal39c76082018-05-15 11:57:13 +020079}
Miquel Raynal8df6f8d2018-05-15 11:57:14 +020080
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +020081u32 tpm2_auto_start(struct udevice *dev)
82{
83 u32 rc;
84
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +020085 rc = tpm2_self_test(dev, TPMI_YES);
86
87 if (rc == TPM2_RC_INITIALIZE) {
Raymond Mao5187a642025-01-27 06:58:46 -080088 rc = tpm2_startup(dev, true, TPM2_SU_CLEAR);
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +020089 if (rc)
90 return rc;
91
92 rc = tpm2_self_test(dev, TPMI_YES);
93 }
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -080094 if (rc)
95 return rc;
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +020096
Ilias Apalodimas2f7ad7e2024-12-24 08:01:09 -080097 return tpm2_update_active_banks(dev);
Ilias Apalodimas42d7bdf2023-01-25 12:18:36 +020098}
99
Simon Glass8ceca1d2018-11-18 14:22:27 -0700100u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
101 const ssize_t pw_sz)
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200102{
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700103 /* Length of the message header, up to start of password */
104 uint offset = 27;
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200105 u8 command_v2[COMMAND_BUFFER_SIZE] = {
106 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700107 tpm_u32(offset + pw_sz), /* Length */
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200108 tpm_u32(TPM2_CC_CLEAR), /* Command code */
109
110 /* HANDLE */
111 tpm_u32(handle), /* TPM resource handle */
112
113 /* AUTH_SESSION */
114 tpm_u32(9 + pw_sz), /* Authorization size */
115 tpm_u32(TPM2_RS_PW), /* Session handle */
116 tpm_u16(0), /* Size of <nonce> */
117 /* <nonce> (if any) */
118 0, /* Attributes: Cont/Excl/Rst */
119 tpm_u16(pw_sz), /* Size of <hmac/password> */
120 /* STRING(pw) <hmac/password> (if any) */
121 };
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200122 int ret;
123
124 /*
125 * Fill the command structure starting from the first buffer:
126 * - the password (if any)
127 */
128 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
129 offset, pw, pw_sz);
130 offset += pw_sz;
131 if (ret)
132 return TPM_LIB_ERROR;
133
Simon Glass8ceca1d2018-11-18 14:22:27 -0700134 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal8df6f8d2018-05-15 11:57:14 +0200135}
Miquel Raynal14d72352018-05-15 11:57:15 +0200136
Simon Glass713c58a2021-02-06 14:23:39 -0700137u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
138 size_t space_size, u32 nv_attributes,
139 const u8 *nv_policy, size_t nv_policy_size)
140{
141 /*
142 * Calculate the offset of the nv_policy piece by adding each of the
143 * chunks below.
144 */
Simon Glass5252cac2022-08-30 21:05:34 -0600145 const int platform_len = sizeof(u32);
146 const int session_hdr_len = 13;
147 const int message_len = 14;
148 uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
149 message_len;
Simon Glass713c58a2021-02-06 14:23:39 -0700150 u8 command_v2[COMMAND_BUFFER_SIZE] = {
151 /* header 10 bytes */
152 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass5252cac2022-08-30 21:05:34 -0600153 tpm_u32(offset + nv_policy_size + 2),/* Length */
Simon Glass713c58a2021-02-06 14:23:39 -0700154 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
155
Simon Glass5252cac2022-08-30 21:05:34 -0600156 /* handles 4 bytes */
Simon Glass713c58a2021-02-06 14:23:39 -0700157 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
158
159 /* session header 13 bytes */
160 tpm_u32(9), /* Header size */
161 tpm_u32(TPM2_RS_PW), /* Password authorisation */
162 tpm_u16(0), /* nonce_size */
163 0, /* session_attrs */
164 tpm_u16(0), /* auth_size */
165
166 /* message 14 bytes + policy */
Simon Glass5252cac2022-08-30 21:05:34 -0600167 tpm_u16(message_len + nv_policy_size), /* size */
Simon Glass713c58a2021-02-06 14:23:39 -0700168 tpm_u32(space_index),
169 tpm_u16(TPM2_ALG_SHA256),
170 tpm_u32(nv_attributes),
171 tpm_u16(nv_policy_size),
Simon Glass5252cac2022-08-30 21:05:34 -0600172 /*
173 * nv_policy
174 * space_size
175 */
Simon Glass713c58a2021-02-06 14:23:39 -0700176 };
177 int ret;
178
179 /*
180 * Fill the command structure starting from the first buffer:
181 * - the password (if any)
182 */
Simon Glass5252cac2022-08-30 21:05:34 -0600183 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
184 offset, nv_policy, nv_policy_size,
185 offset + nv_policy_size, space_size);
Simon Glass713c58a2021-02-06 14:23:39 -0700186 if (ret)
187 return TPM_LIB_ERROR;
188
189 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
190}
191
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200192u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
193 const u8 *digest, u32 digest_len)
Miquel Raynal14d72352018-05-15 11:57:15 +0200194{
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700195 /* Length of the message header, up to start of digest */
196 uint offset = 33;
Miquel Raynal14d72352018-05-15 11:57:15 +0200197 u8 command_v2[COMMAND_BUFFER_SIZE] = {
198 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700199 tpm_u32(offset + digest_len), /* Length */
Miquel Raynal14d72352018-05-15 11:57:15 +0200200 tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */
201
202 /* HANDLE */
203 tpm_u32(index), /* Handle (PCR Index) */
204
205 /* AUTH_SESSION */
206 tpm_u32(9), /* Authorization size */
207 tpm_u32(TPM2_RS_PW), /* Session handle */
208 tpm_u16(0), /* Size of <nonce> */
209 /* <nonce> (if any) */
210 0, /* Attributes: Cont/Excl/Rst */
211 tpm_u16(0), /* Size of <hmac/password> */
212 /* <hmac/password> (if any) */
Simon Glass3b3ac8b2021-02-06 14:23:38 -0700213
214 /* hashes */
Miquel Raynal14d72352018-05-15 11:57:15 +0200215 tpm_u32(1), /* Count (number of hashes) */
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200216 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal14d72352018-05-15 11:57:15 +0200217 /* STRING(digest) Digest */
218 };
Miquel Raynal14d72352018-05-15 11:57:15 +0200219 int ret;
220
Simon Glass4927f472022-08-30 21:05:32 -0600221 if (!digest)
222 return -EINVAL;
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300223
Ilias Apalodimasd788b062024-12-24 08:01:05 -0800224 if (!tpm2_check_active_banks(dev)) {
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300225 log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n");
226 return -EINVAL;
227 }
Miquel Raynal14d72352018-05-15 11:57:15 +0200228 /*
229 * Fill the command structure starting from the first buffer:
230 * - the digest
231 */
232 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
Ilias Apalodimas7f59c712020-11-26 23:07:22 +0200233 offset, digest, digest_len);
Miquel Raynal14d72352018-05-15 11:57:15 +0200234 if (ret)
235 return TPM_LIB_ERROR;
236
Simon Glass8ceca1d2018-11-18 14:22:27 -0700237 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal14d72352018-05-15 11:57:15 +0200238}
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200239
Simon Glass3d930ed2021-02-06 14:23:40 -0700240u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
241{
242 u8 command_v2[COMMAND_BUFFER_SIZE] = {
243 /* header 10 bytes */
244 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
245 tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
246 tpm_u32(TPM2_CC_NV_READ), /* Command code */
247
248 /* handles 8 bytes */
249 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
250 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
251
252 /* AUTH_SESSION */
253 tpm_u32(9), /* Authorization size */
254 tpm_u32(TPM2_RS_PW), /* Session handle */
255 tpm_u16(0), /* Size of <nonce> */
256 /* <nonce> (if any) */
257 0, /* Attributes: Cont/Excl/Rst */
258 tpm_u16(0), /* Size of <hmac/password> */
259 /* <hmac/password> (if any) */
260
261 tpm_u16(count), /* Number of bytes */
262 tpm_u16(0), /* Offset */
263 };
264 size_t response_len = COMMAND_BUFFER_SIZE;
265 u8 response[COMMAND_BUFFER_SIZE];
266 int ret;
267 u16 tag;
268 u32 size, code;
269
270 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
271 if (ret)
272 return log_msg_ret("read", ret);
273 if (unpack_byte_string(response, response_len, "wdds",
274 0, &tag, 2, &size, 6, &code,
275 16, data, count))
276 return TPM_LIB_ERROR;
277
278 return 0;
279}
280
281u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
282 u32 count)
283{
284 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
285 uint offset = 10 + 8 + 4 + 9 + 2;
286 uint len = offset + count + 2;
287 /* Use empty password auth if platform hierarchy is disabled */
288 u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
289 TPM2_RH_PLATFORM;
290 u8 command_v2[COMMAND_BUFFER_SIZE] = {
291 /* header 10 bytes */
292 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
293 tpm_u32(len), /* Length */
294 tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
295
296 /* handles 8 bytes */
297 tpm_u32(auth), /* Primary platform seed */
298 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
299
300 /* AUTH_SESSION */
301 tpm_u32(9), /* Authorization size */
302 tpm_u32(TPM2_RS_PW), /* Session handle */
303 tpm_u16(0), /* Size of <nonce> */
304 /* <nonce> (if any) */
305 0, /* Attributes: Cont/Excl/Rst */
306 tpm_u16(0), /* Size of <hmac/password> */
307 /* <hmac/password> (if any) */
308
309 tpm_u16(count),
310 };
311 size_t response_len = COMMAND_BUFFER_SIZE;
312 u8 response[COMMAND_BUFFER_SIZE];
313 int ret;
314
315 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
316 offset, data, count,
317 offset + count, 0);
318 if (ret)
319 return TPM_LIB_ERROR;
320
321 return tpm_sendrecv_command(dev, command_v2, response, &response_len);
322}
323
Simon Glass8ceca1d2018-11-18 14:22:27 -0700324u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530325 u16 algorithm, void *data, u32 digest_len,
326 unsigned int *updates)
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200327{
328 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
329 u8 command_v2[COMMAND_BUFFER_SIZE] = {
330 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
331 tpm_u32(17 + idx_array_sz), /* Length */
332 tpm_u32(TPM2_CC_PCR_READ), /* Command code */
333
334 /* TPML_PCR_SELECTION */
335 tpm_u32(1), /* Number of selections */
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530336 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200337 idx_array_sz, /* Array size for selection */
338 /* bitmap(idx) Selected PCR bitmap */
339 };
340 size_t response_len = COMMAND_BUFFER_SIZE;
341 u8 response[COMMAND_BUFFER_SIZE];
342 unsigned int pcr_sel_idx = idx / 8;
343 u8 pcr_sel_bit = BIT(idx % 8);
344 unsigned int counter = 0;
345 int ret;
346
347 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
348 17 + pcr_sel_idx, pcr_sel_bit))
349 return TPM_LIB_ERROR;
350
Simon Glass8ceca1d2018-11-18 14:22:27 -0700351 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200352 if (ret)
353 return ret;
354
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530355 if (digest_len > response_len)
356 return TPM_LIB_ERROR;
357
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200358 if (unpack_byte_string(response, response_len, "ds",
359 10, &counter,
Ruchika Gupta686bedb2021-11-29 13:09:45 +0530360 response_len - digest_len, data,
361 digest_len))
Miquel Raynal4c1a5852018-05-15 11:57:16 +0200362 return TPM_LIB_ERROR;
363
364 if (updates)
365 *updates = counter;
366
367 return 0;
368}
Miquel Raynal2e52c062018-05-15 11:57:17 +0200369
Simon Glass8ceca1d2018-11-18 14:22:27 -0700370u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
371 void *buf, size_t prop_count)
Miquel Raynal2e52c062018-05-15 11:57:17 +0200372{
373 u8 command_v2[COMMAND_BUFFER_SIZE] = {
374 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
375 tpm_u32(22), /* Length */
376 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
377
378 tpm_u32(capability), /* Capability */
379 tpm_u32(property), /* Property */
380 tpm_u32(prop_count), /* Property count */
381 };
382 u8 response[COMMAND_BUFFER_SIZE];
383 size_t response_len = COMMAND_BUFFER_SIZE;
384 unsigned int properties_off;
385 int ret;
386
Simon Glass8ceca1d2018-11-18 14:22:27 -0700387 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal2e52c062018-05-15 11:57:17 +0200388 if (ret)
389 return ret;
390
391 /*
392 * In the response buffer, the properties are located after the:
393 * tag (u16), response size (u32), response code (u32),
Ilias Apalodimasa0789152020-11-05 23:58:43 +0200394 * YES/NO flag (u8), TPM_CAP (u32).
Miquel Raynal2e52c062018-05-15 11:57:17 +0200395 */
396 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
Ilias Apalodimasa0789152020-11-05 23:58:43 +0200397 sizeof(u8) + sizeof(u32);
Miquel Raynal2e52c062018-05-15 11:57:17 +0200398 memcpy(buf, &response[properties_off], response_len - properties_off);
399
400 return 0;
401}
Miquel Raynal228e9902018-05-15 11:57:18 +0200402
Raymond Maof69f2d72025-01-27 06:58:47 -0800403u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask,
404 struct tpml_pcr_selection *pcr, u32 *pcr_len)
405{
406 int i;
407
408 if (pcr->count > TPM2_NUM_PCR_BANKS)
409 return TPM_LIB_ERROR;
410
411 *pcr_len = sizeof(pcr->count);
412
413 for (i = 0; i < pcr->count; i++) {
414 struct tpms_pcr_selection *sel = &pcr->selection[i];
415 u8 pad = 0;
416 int j;
417
418 if (sel->size_of_select > TPM2_PCR_SELECT_MAX)
419 return TPM_LIB_ERROR;
420
421 /*
422 * Found the algorithm (bank) that matches, and enable all PCR
423 * bits.
424 * TODO: only select the bits needed
425 */
426 for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
427 if (hash_algo_list[j].hash_alg != sel->hash)
428 continue;
429
430 if (algo_mask & hash_algo_list[j].hash_mask)
431 pad = 0xff;
432 }
433
434 for (j = 0; j < sel->size_of_select; j++)
435 sel->pcr_select[j] = pad;
436
437 log_info("set bank[%d] %s %s\n", i,
438 tpm2_algorithm_name(sel->hash),
439 tpm2_is_active_bank(sel) ? "on" : "off");
440
441 *pcr_len += sizeof(sel->hash) + sizeof(sel->size_of_select) +
442 sel->size_of_select;
443 }
444
445 return 0;
446}
447
448u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw,
449 const ssize_t pw_sz, struct tpml_pcr_selection *pcr,
450 u32 pcr_len)
451{
452 /* Length of the message header, up to start of password */
453 uint offset = 27;
454 u8 command_v2[COMMAND_BUFFER_SIZE] = {
455 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
456 tpm_u32(offset + pw_sz + pcr_len), /* Length */
457 tpm_u32(TPM2_CC_PCR_ALLOCATE), /* Command code */
458
459 /* handles 4 bytes */
460 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
461
462 /* AUTH_SESSION */
463 tpm_u32(9 + pw_sz), /* Authorization size */
464 tpm_u32(TPM2_RS_PW), /* Session handle */
465 tpm_u16(0), /* Size of <nonce> */
466 /* <nonce> (if any) */
467 0, /* Attributes: Cont/Excl/Rst */
468 tpm_u16(pw_sz), /* Size of <hmac/password> */
469 /* STRING(pw) <hmac/password> (if any) */
470
471 /* TPML_PCR_SELECTION */
472 };
473 u8 response[COMMAND_BUFFER_SIZE];
474 size_t response_len = COMMAND_BUFFER_SIZE;
475 u32 i;
476 int ret;
477
478 /*
479 * Fill the command structure starting from the first buffer:
480 * the password (if any)
481 */
482 if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, pw,
483 pw_sz))
484 return TPM_LIB_ERROR;
485
486 offset += pw_sz;
487
488 /* Pack the count field */
489 if (pack_byte_string(command_v2, sizeof(command_v2), "d", offset, pcr->count))
490 return TPM_LIB_ERROR;
491
492 offset += sizeof(pcr->count);
493
494 /* Pack each tpms_pcr_selection */
495 for (i = 0; i < pcr->count; i++) {
496 struct tpms_pcr_selection *sel = &pcr->selection[i];
497
498 /* Pack hash (16-bit) */
499 if (pack_byte_string(command_v2, sizeof(command_v2), "w", offset,
500 sel->hash))
501 return TPM_LIB_ERROR;
502
503 offset += sizeof(sel->hash);
504
505 /* Pack size_of_select (8-bit) */
506 if (pack_byte_string(command_v2, sizeof(command_v2), "b", offset,
507 sel->size_of_select))
508 return TPM_LIB_ERROR;
509
510 offset += sizeof(sel->size_of_select);
511
512 /* Pack pcr_select array */
513 if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset,
514 sel->pcr_select, sel->size_of_select))
515 return TPM_LIB_ERROR;
516
517 offset += sel->size_of_select;
518 }
519
520 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
521 if (!ret)
522 tpm_init(dev);
523
524 return ret;
525}
526
Eddie James8ed7bb32023-10-24 10:43:49 -0500527static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
528{
529 u8 response[(sizeof(struct tpms_capability_data) -
530 offsetof(struct tpms_capability_data, data))];
531 u32 properties_offset =
532 offsetof(struct tpml_tagged_tpm_property, tpm_property) +
533 offsetof(struct tpms_tagged_property, value);
534 u32 ret;
535
536 memset(response, 0, sizeof(response));
537 ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
538 TPM2_PT_PCR_COUNT, response, 1);
539 if (ret)
540 return ret;
541
542 *num_pcr = get_unaligned_be32(response + properties_offset);
543 if (*num_pcr > TPM2_MAX_PCRS) {
544 printf("%s: too many pcrs: %u\n", __func__, *num_pcr);
545 return -E2BIG;
546 }
547
548 return 0;
549}
550
Ilias Apalodimascb356612024-06-23 14:48:17 +0300551int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs)
Eddie James8ed7bb32023-10-24 10:43:49 -0500552{
553 u8 response[(sizeof(struct tpms_capability_data) -
554 offsetof(struct tpms_capability_data, data))];
Eddie James8ed7bb32023-10-24 10:43:49 -0500555 u32 num_pcr;
556 size_t i;
557 u32 ret;
558
Eddie James8ed7bb32023-10-24 10:43:49 -0500559 ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
560 if (ret)
561 return ret;
562
Ilias Apalodimascb356612024-06-23 14:48:17 +0300563 pcrs->count = get_unaligned_be32(response);
Eddie James8ed7bb32023-10-24 10:43:49 -0500564 /*
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300565 * We only support 4 algorithms for now so check against that
Eddie James8ed7bb32023-10-24 10:43:49 -0500566 * instead of TPM2_NUM_PCR_BANKS
567 */
Ilias Apalodimas1e665f92024-06-23 14:48:18 +0300568 if (pcrs->count > 4 || pcrs->count < 1) {
Ilias Apalodimascb356612024-06-23 14:48:17 +0300569 printf("%s: too many pcrs: %u\n", __func__, pcrs->count);
Eddie James8ed7bb32023-10-24 10:43:49 -0500570 return -EMSGSIZE;
571 }
572
573 ret = tpm2_get_num_pcr(dev, &num_pcr);
574 if (ret)
575 return ret;
576
Ilias Apalodimascb356612024-06-23 14:48:17 +0300577 for (i = 0; i < pcrs->count; i++) {
Eddie James8ed7bb32023-10-24 10:43:49 -0500578 /*
579 * Definition of TPMS_PCR_SELECTION Structure
580 * hash: u16
581 * size_of_select: u8
582 * pcr_select: u8 array
583 *
584 * The offsets depend on the number of the device PCRs
585 * so we have to calculate them based on that
586 */
587 u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
588 i * offsetof(struct tpms_pcr_selection, pcr_select) +
589 i * ((num_pcr + 7) / 8);
590 u32 size_select_offset =
591 hash_offset + offsetof(struct tpms_pcr_selection,
592 size_of_select);
593 u32 pcr_select_offset =
594 hash_offset + offsetof(struct tpms_pcr_selection,
595 pcr_select);
596
Ilias Apalodimascb356612024-06-23 14:48:17 +0300597 pcrs->selection[i].hash =
Eddie James8ed7bb32023-10-24 10:43:49 -0500598 get_unaligned_be16(response + hash_offset);
Ilias Apalodimascb356612024-06-23 14:48:17 +0300599 pcrs->selection[i].size_of_select =
Eddie James8ed7bb32023-10-24 10:43:49 -0500600 __get_unaligned_be(response + size_select_offset);
Ilias Apalodimascb356612024-06-23 14:48:17 +0300601 if (pcrs->selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
Eddie James8ed7bb32023-10-24 10:43:49 -0500602 printf("%s: pcrs selection too large: %u\n", __func__,
Ilias Apalodimascb356612024-06-23 14:48:17 +0300603 pcrs->selection[i].size_of_select);
Eddie James8ed7bb32023-10-24 10:43:49 -0500604 return -ENOBUFS;
605 }
606 /* copy the array of pcr_select */
Ilias Apalodimascb356612024-06-23 14:48:17 +0300607 memcpy(pcrs->selection[i].pcr_select, response + pcr_select_offset,
608 pcrs->selection[i].size_of_select);
Eddie James8ed7bb32023-10-24 10:43:49 -0500609 }
610
Eddie James8ed7bb32023-10-24 10:43:49 -0500611 return 0;
612}
613
Simon Glass8ceca1d2018-11-18 14:22:27 -0700614u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynal228e9902018-05-15 11:57:18 +0200615{
616 u8 command_v2[COMMAND_BUFFER_SIZE] = {
617 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
618 tpm_u32(27 + pw_sz), /* Length */
619 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
620
621 /* HANDLE */
622 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
623
624 /* AUTH_SESSION */
625 tpm_u32(9 + pw_sz), /* Authorization size */
626 tpm_u32(TPM2_RS_PW), /* Session handle */
627 tpm_u16(0), /* Size of <nonce> */
628 /* <nonce> (if any) */
629 0, /* Attributes: Cont/Excl/Rst */
630 tpm_u16(pw_sz), /* Size of <hmac/password> */
631 /* STRING(pw) <hmac/password> (if any) */
632 };
633 unsigned int offset = 27;
634 int ret;
635
636 /*
637 * Fill the command structure starting from the first buffer:
638 * - the password (if any)
639 */
640 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
641 offset, pw, pw_sz);
642 offset += pw_sz;
643 if (ret)
644 return TPM_LIB_ERROR;
645
Simon Glass8ceca1d2018-11-18 14:22:27 -0700646 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal228e9902018-05-15 11:57:18 +0200647}
648
Simon Glass8ceca1d2018-11-18 14:22:27 -0700649u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
650 const ssize_t pw_sz, unsigned int max_tries,
651 unsigned int recovery_time,
Miquel Raynal228e9902018-05-15 11:57:18 +0200652 unsigned int lockout_recovery)
653{
654 u8 command_v2[COMMAND_BUFFER_SIZE] = {
655 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
656 tpm_u32(27 + pw_sz + 12), /* Length */
657 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
658
659 /* HANDLE */
660 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
661
662 /* AUTH_SESSION */
663 tpm_u32(9 + pw_sz), /* Authorization size */
664 tpm_u32(TPM2_RS_PW), /* Session handle */
665 tpm_u16(0), /* Size of <nonce> */
666 /* <nonce> (if any) */
667 0, /* Attributes: Cont/Excl/Rst */
668 tpm_u16(pw_sz), /* Size of <hmac/password> */
669 /* STRING(pw) <hmac/password> (if any) */
670
671 /* LOCKOUT PARAMETERS */
672 /* tpm_u32(max_tries) Max tries (0, always lock) */
673 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
674 /* tpm_u32(lockout_recovery) Lockout recovery */
675 };
676 unsigned int offset = 27;
677 int ret;
678
679 /*
680 * Fill the command structure starting from the first buffer:
681 * - the password (if any)
682 * - max tries
683 * - recovery time
684 * - lockout recovery
685 */
686 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
687 offset, pw, pw_sz,
688 offset + pw_sz, max_tries,
689 offset + pw_sz + 4, recovery_time,
690 offset + pw_sz + 8, lockout_recovery);
691 offset += pw_sz + 12;
692 if (ret)
693 return TPM_LIB_ERROR;
694
Simon Glass8ceca1d2018-11-18 14:22:27 -0700695 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal228e9902018-05-15 11:57:18 +0200696}
Miquel Raynal05d7be32018-05-15 11:57:19 +0200697
Simon Glass8ceca1d2018-11-18 14:22:27 -0700698int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
699 const ssize_t newpw_sz, const char *oldpw,
700 const ssize_t oldpw_sz)
Miquel Raynal05d7be32018-05-15 11:57:19 +0200701{
702 unsigned int offset = 27;
703 u8 command_v2[COMMAND_BUFFER_SIZE] = {
704 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
705 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
706 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
707
708 /* HANDLE */
709 tpm_u32(handle), /* TPM resource handle */
710
711 /* AUTH_SESSION */
712 tpm_u32(9 + oldpw_sz), /* Authorization size */
713 tpm_u32(TPM2_RS_PW), /* Session handle */
714 tpm_u16(0), /* Size of <nonce> */
715 /* <nonce> (if any) */
716 0, /* Attributes: Cont/Excl/Rst */
717 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
718 /* STRING(oldpw) <hmac/password> (if any) */
719
720 /* TPM2B_AUTH (TPM2B_DIGEST) */
721 /* tpm_u16(newpw_sz) Digest size, new pw length */
722 /* STRING(newpw) Digest buffer, new pw */
723 };
724 int ret;
725
726 /*
727 * Fill the command structure starting from the first buffer:
728 * - the old password (if any)
729 * - size of the new password
730 * - new password
731 */
732 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
733 offset, oldpw, oldpw_sz,
734 offset + oldpw_sz, newpw_sz,
735 offset + oldpw_sz + 2, newpw, newpw_sz);
736 offset += oldpw_sz + 2 + newpw_sz;
737 if (ret)
738 return TPM_LIB_ERROR;
739
Simon Glass8ceca1d2018-11-18 14:22:27 -0700740 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal05d7be32018-05-15 11:57:19 +0200741}
Miquel Raynal0b864f62018-05-15 11:57:20 +0200742
Simon Glass8ceca1d2018-11-18 14:22:27 -0700743u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
744 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynal0b864f62018-05-15 11:57:20 +0200745{
746 u8 command_v2[COMMAND_BUFFER_SIZE] = {
747 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
748 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
749 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
750
751 /* HANDLE */
752 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
753
754 /* AUTH_SESSION */
755 tpm_u32(9 + pw_sz), /* Authorization size */
756 tpm_u32(TPM2_RS_PW), /* session handle */
757 tpm_u16(0), /* Size of <nonce> */
758 /* <nonce> (if any) */
759 0, /* Attributes: Cont/Excl/Rst */
760 tpm_u16(pw_sz) /* Size of <hmac/password> */
761 /* STRING(pw) <hmac/password> (if any) */
762
763 /* TPM2B_AUTH (TPM2B_DIGEST) */
764 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
765 /* STRING(key) Digest buffer (PCR key) */
766
767 /* TPMI_ALG_HASH */
768 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
769
770 /* TPMI_DH_PCR */
771 /* tpm_u32(index), PCR Index */
772 };
773 unsigned int offset = 27;
774 int ret;
775
776 /*
777 * Fill the command structure starting from the first buffer:
778 * - the password (if any)
779 * - the PCR key length
780 * - the PCR key
781 * - the hash algorithm
782 * - the PCR index
783 */
784 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
785 offset, pw, pw_sz,
786 offset + pw_sz, TPM2_DIGEST_LEN,
787 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
788 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
789 TPM2_ALG_SHA256,
790 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
791 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
792 if (ret)
793 return TPM_LIB_ERROR;
794
Simon Glass8ceca1d2018-11-18 14:22:27 -0700795 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal0b864f62018-05-15 11:57:20 +0200796}
797
Simon Glass8ceca1d2018-11-18 14:22:27 -0700798u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
799 const ssize_t pw_sz, u32 index, const char *key,
800 const ssize_t key_sz)
Miquel Raynal0b864f62018-05-15 11:57:20 +0200801{
802 u8 command_v2[COMMAND_BUFFER_SIZE] = {
803 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
804 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
805 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
806
807 /* HANDLE */
808 tpm_u32(index), /* Handle (PCR Index) */
809
810 /* AUTH_SESSION */
811 tpm_u32(9 + pw_sz), /* Authorization size */
812 tpm_u32(TPM2_RS_PW), /* session handle */
813 tpm_u16(0), /* Size of <nonce> */
814 /* <nonce> (if any) */
815 0, /* Attributes: Cont/Excl/Rst */
816 tpm_u16(pw_sz), /* Size of <hmac/password> */
817 /* STRING(pw) <hmac/password> (if any) */
818
819 /* TPM2B_DIGEST */
820 /* tpm_u16(key_sz) Key length */
821 /* STRING(key) Key */
822 };
823 unsigned int offset = 27;
824 int ret;
825
826 /*
827 * Fill the command structure starting from the first buffer:
828 * - the password (if any)
829 * - the number of digests, 1 in our case
830 * - the algorithm, sha256 in our case
831 * - the digest (64 bytes)
832 */
833 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
834 offset, pw, pw_sz,
835 offset + pw_sz, key_sz,
836 offset + pw_sz + 2, key, key_sz);
837 offset += pw_sz + 2 + key_sz;
838 if (ret)
839 return TPM_LIB_ERROR;
840
Simon Glass8ceca1d2018-11-18 14:22:27 -0700841 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal0b864f62018-05-15 11:57:20 +0200842}
Dhananjay Phadke7a2cf2e2020-06-04 16:43:59 -0700843
844u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
845{
846 const u8 command_v2[10] = {
847 tpm_u16(TPM2_ST_NO_SESSIONS),
848 tpm_u32(12),
849 tpm_u32(TPM2_CC_GET_RANDOM),
850 };
851 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
852
853 const size_t data_size_offset = 10;
854 const size_t data_offset = 12;
855 size_t response_length = sizeof(response);
856 u32 data_size;
857 u8 *out = data;
858
859 while (count > 0) {
860 u32 this_bytes = min((size_t)count,
861 sizeof(response) - data_offset);
862 u32 err;
863
864 if (pack_byte_string(buf, sizeof(buf), "sw",
865 0, command_v2, sizeof(command_v2),
866 sizeof(command_v2), this_bytes))
867 return TPM_LIB_ERROR;
868 err = tpm_sendrecv_command(dev, buf, response,
869 &response_length);
870 if (err)
871 return err;
872 if (unpack_byte_string(response, response_length, "w",
873 data_size_offset, &data_size))
874 return TPM_LIB_ERROR;
875 if (data_size > this_bytes)
876 return TPM_LIB_ERROR;
877 if (unpack_byte_string(response, response_length, "s",
878 data_offset, out, data_size))
879 return TPM_LIB_ERROR;
880
881 count -= data_size;
882 out += data_size;
883 }
884
885 return 0;
886}
Simon Glasse9d3d592021-02-06 14:23:41 -0700887
888u32 tpm2_write_lock(struct udevice *dev, u32 index)
889{
890 u8 command_v2[COMMAND_BUFFER_SIZE] = {
891 /* header 10 bytes */
892 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
893 tpm_u32(10 + 8 + 13), /* Length */
894 tpm_u32(TPM2_CC_NV_WRITELOCK), /* 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 /* session header 9 bytes */
901 tpm_u32(9), /* Header size */
902 tpm_u32(TPM2_RS_PW), /* Password authorisation */
903 tpm_u16(0), /* nonce_size */
904 0, /* session_attrs */
905 tpm_u16(0), /* auth_size */
906 };
907
908 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
909}
Simon Glass77759db2021-02-06 14:23:42 -0700910
911u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
912{
913 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
914 u8 command_v2[COMMAND_BUFFER_SIZE] = {
915 /* header 10 bytes */
916 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
917 tpm_u32(10 + 4 + 13 + 5), /* Length */
918 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
919
920 /* 4 bytes */
921 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
922
923 /* session header 9 bytes */
924 tpm_u32(9), /* Header size */
925 tpm_u32(TPM2_RS_PW), /* Password authorisation */
926 tpm_u16(0), /* nonce_size */
927 0, /* session_attrs */
928 tpm_u16(0), /* auth_size */
929
930 /* payload 5 bytes */
931 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
932 0, /* 0=disable */
933 };
934 int ret;
935
936 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
937 log_info("ret=%s, %x\n", dev->name, ret);
938 if (ret)
939 return ret;
940
941 priv->plat_hier_disabled = true;
942
943 return 0;
944}
Masahisa Kojima06ef6b62021-11-04 22:59:16 +0900945
946u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
947 u8 *recvbuf, size_t *recv_size)
948{
949 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
950}
Simon Glass3f7a73a2022-08-30 21:05:37 -0600951
952u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
953 u8 *recvbuf, size_t *recv_size)
954{
955 u8 command_v2[COMMAND_BUFFER_SIZE] = {
956 /* header 10 bytes */
957 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
958 tpm_u32(10 + 2), /* Length */
959 tpm_u32(vendor_cmd), /* Command code */
960
961 tpm_u16(vendor_subcmd),
962 };
963 int ret;
964
965 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
966 log_debug("ret=%s, %x\n", dev->name, ret);
967 if (ret)
968 return ret;
969 if (*recv_size < 12)
970 return -ENODATA;
971 *recv_size -= 12;
Heinrich Schuchardt5b8577d2024-11-02 11:27:37 +0100972 memmove(recvbuf, recvbuf + 12, *recv_size);
Simon Glass3f7a73a2022-08-30 21:05:37 -0600973
974 return 0;
975}
Simon Glass3564b8e2022-08-30 21:05:38 -0600976
977u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
978 uint vendor_subcmd)
979{
980 u8 command_v2[COMMAND_BUFFER_SIZE] = {
981 /* header 10 bytes */
982 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
983 tpm_u32(10 + 2), /* Length */
984 tpm_u32(vendor_cmd), /* Command code */
985
986 tpm_u16(vendor_subcmd),
987 };
988 int ret;
989
990 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
991 log_debug("ret=%s, %x\n", dev->name, ret);
992 if (ret)
993 return ret;
994
995 return 0;
996}
Tim Harvey6ea1e052024-05-25 13:00:48 -0700997
Ilias Apalodimas9465f7a2024-12-24 08:01:04 -0800998bool tpm2_is_active_bank(struct tpms_pcr_selection *selection)
Ilias Apalodimascb356612024-06-23 14:48:17 +0300999{
1000 int i;
1001
1002 for (i = 0; i < selection->size_of_select; i++) {
1003 if (selection->pcr_select[i])
1004 return true;
1005 }
1006
1007 return false;
1008}
1009
Tim Harvey6ea1e052024-05-25 13:00:48 -07001010enum tpm2_algorithms tpm2_name_to_algorithm(const char *name)
1011{
1012 size_t i;
1013
1014 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1015 if (!strcasecmp(name, hash_algo_list[i].hash_name))
1016 return hash_algo_list[i].hash_alg;
1017 }
1018 printf("%s: unsupported algorithm %s\n", __func__, name);
1019
1020 return -EINVAL;
1021}
1022
1023const char *tpm2_algorithm_name(enum tpm2_algorithms algo)
1024{
1025 size_t i;
1026
1027 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1028 if (hash_algo_list[i].hash_alg == algo)
1029 return hash_algo_list[i].hash_name;
1030 }
1031
1032 return "";
1033}
1034
Raymond Mao43158122024-12-24 08:01:07 -08001035bool tpm2_algorithm_supported(enum tpm2_algorithms algo)
1036{
1037 size_t i;
1038
1039 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1040 if (hash_algo_list[i].hash_alg == algo)
1041 return hash_algo_list[i].supported;
1042 }
1043
1044 return false;
1045}
1046
Ilias Apalodimas1e665f92024-06-23 14:48:18 +03001047u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo)
1048{
1049 size_t i;
1050
1051 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
1052 if (hash_algo_list[i].hash_alg == algo)
1053 return hash_algo_list[i].hash_len;
1054 }
1055
1056 return 0;
1057}
1058
Ilias Apalodimasd788b062024-12-24 08:01:05 -08001059bool tpm2_check_active_banks(struct udevice *dev)
Ilias Apalodimas1e665f92024-06-23 14:48:18 +03001060{
1061 struct tpml_pcr_selection pcrs;
1062 size_t i;
1063 int rc;
1064
1065 rc = tpm2_get_pcr_info(dev, &pcrs);
1066 if (rc)
1067 return false;
1068
1069 for (i = 0; i < pcrs.count; i++) {
Ilias Apalodimas9465f7a2024-12-24 08:01:04 -08001070 if (tpm2_is_active_bank(&pcrs.selection[i]) &&
Raymond Mao43158122024-12-24 08:01:07 -08001071 !tpm2_algorithm_supported(pcrs.selection[i].hash))
Ilias Apalodimas1e665f92024-06-23 14:48:18 +03001072 return false;
1073 }
1074
1075 return true;
1076}
Ilias Apalodimas7b1e5222024-12-24 08:01:08 -08001077
1078void tpm2_print_active_banks(struct udevice *dev)
1079{
1080 struct tpml_pcr_selection pcrs;
1081 size_t i;
1082 int rc;
1083
1084 rc = tpm2_get_pcr_info(dev, &pcrs);
1085 if (rc) {
1086 log_err("Can't retrieve active PCRs\n");
1087 return;
1088 }
1089
1090 for (i = 0; i < pcrs.count; i++) {
1091 if (tpm2_is_active_bank(&pcrs.selection[i])) {
1092 const char *str;
1093
1094 str = tpm2_algorithm_name(pcrs.selection[i].hash);
1095 if (str)
1096 log_info("%s\n", str);
1097 }
1098 }
1099}