blob: 62ab804b4b38f80c511ed8a21ee029cc251d99dd [file] [log] [blame]
Miquel Raynalff322452018-05-15 11:57:08 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
Eddie James97707f12023-10-24 10:43:49 -05003 * Copyright (c) 2023 Linaro Limited
Miquel Raynalff322452018-05-15 11:57:08 +02004 * Copyright (c) 2018 Bootlin
5 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
6 */
7
Miquel Raynalff322452018-05-15 11:57:08 +02008#include <dm.h>
Eddie James97707f12023-10-24 10:43:49 -05009#include <dm/of_access.h>
10#include <tpm_api.h>
Miquel Raynalff322452018-05-15 11:57:08 +020011#include <tpm-common.h>
12#include <tpm-v2.h>
Ilias Apalodimas27b462c2024-06-23 14:48:14 +030013#include <tpm_tcg2.h>
Eddie James97707f12023-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 Glasscd93d622020-05-10 11:40:13 -060019#include <linux/bitops.h>
Eddie James97707f12023-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 Raynalff322452018-05-15 11:57:08 +020024#include "tpm-utils.h"
Miquel Raynal1922df22018-05-15 11:57:12 +020025
Simon Glassabdc7b82018-11-18 14:22:27 -070026u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
Miquel Raynal1922df22018-05-15 11:57:12 +020027{
28 const u8 command_v2[12] = {
29 tpm_u16(TPM2_ST_NO_SESSIONS),
30 tpm_u32(12),
31 tpm_u32(TPM2_CC_STARTUP),
32 tpm_u16(mode),
33 };
34 int ret;
35
36 /*
37 * Note TPM2_Startup command will return RC_SUCCESS the first time,
38 * but will return RC_INITIALIZE otherwise.
39 */
Simon Glassabdc7b82018-11-18 14:22:27 -070040 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal1922df22018-05-15 11:57:12 +020041 if (ret && ret != TPM2_RC_INITIALIZE)
42 return ret;
43
44 return 0;
45}
Miquel Raynal2dc6d972018-05-15 11:57:13 +020046
Simon Glassabdc7b82018-11-18 14:22:27 -070047u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
Miquel Raynal2dc6d972018-05-15 11:57:13 +020048{
49 const u8 command_v2[12] = {
50 tpm_u16(TPM2_ST_NO_SESSIONS),
51 tpm_u32(11),
52 tpm_u32(TPM2_CC_SELF_TEST),
53 full_test,
54 };
55
Simon Glassabdc7b82018-11-18 14:22:27 -070056 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal2dc6d972018-05-15 11:57:13 +020057}
Miquel Raynalbad8ff52018-05-15 11:57:14 +020058
Ilias Apalodimasa595be32023-01-25 12:18:36 +020059u32 tpm2_auto_start(struct udevice *dev)
60{
61 u32 rc;
62
Ilias Apalodimasa595be32023-01-25 12:18:36 +020063 rc = tpm2_self_test(dev, TPMI_YES);
64
65 if (rc == TPM2_RC_INITIALIZE) {
66 rc = tpm2_startup(dev, TPM2_SU_CLEAR);
67 if (rc)
68 return rc;
69
70 rc = tpm2_self_test(dev, TPMI_YES);
71 }
72
73 return rc;
74}
75
Simon Glassabdc7b82018-11-18 14:22:27 -070076u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
77 const ssize_t pw_sz)
Miquel Raynalbad8ff52018-05-15 11:57:14 +020078{
Simon Glass1bea7cc2021-02-06 14:23:38 -070079 /* Length of the message header, up to start of password */
80 uint offset = 27;
Miquel Raynalbad8ff52018-05-15 11:57:14 +020081 u8 command_v2[COMMAND_BUFFER_SIZE] = {
82 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass1bea7cc2021-02-06 14:23:38 -070083 tpm_u32(offset + pw_sz), /* Length */
Miquel Raynalbad8ff52018-05-15 11:57:14 +020084 tpm_u32(TPM2_CC_CLEAR), /* Command code */
85
86 /* HANDLE */
87 tpm_u32(handle), /* TPM resource handle */
88
89 /* AUTH_SESSION */
90 tpm_u32(9 + pw_sz), /* Authorization size */
91 tpm_u32(TPM2_RS_PW), /* Session handle */
92 tpm_u16(0), /* Size of <nonce> */
93 /* <nonce> (if any) */
94 0, /* Attributes: Cont/Excl/Rst */
95 tpm_u16(pw_sz), /* Size of <hmac/password> */
96 /* STRING(pw) <hmac/password> (if any) */
97 };
Miquel Raynalbad8ff52018-05-15 11:57:14 +020098 int ret;
99
100 /*
101 * Fill the command structure starting from the first buffer:
102 * - the password (if any)
103 */
104 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
105 offset, pw, pw_sz);
106 offset += pw_sz;
107 if (ret)
108 return TPM_LIB_ERROR;
109
Simon Glassabdc7b82018-11-18 14:22:27 -0700110 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalbad8ff52018-05-15 11:57:14 +0200111}
Miquel Raynal6284be52018-05-15 11:57:15 +0200112
Simon Glasseadcbc72021-02-06 14:23:39 -0700113u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
114 size_t space_size, u32 nv_attributes,
115 const u8 *nv_policy, size_t nv_policy_size)
116{
117 /*
118 * Calculate the offset of the nv_policy piece by adding each of the
119 * chunks below.
120 */
Simon Glass1c32eee2022-08-30 21:05:34 -0600121 const int platform_len = sizeof(u32);
122 const int session_hdr_len = 13;
123 const int message_len = 14;
124 uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
125 message_len;
Simon Glasseadcbc72021-02-06 14:23:39 -0700126 u8 command_v2[COMMAND_BUFFER_SIZE] = {
127 /* header 10 bytes */
128 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass1c32eee2022-08-30 21:05:34 -0600129 tpm_u32(offset + nv_policy_size + 2),/* Length */
Simon Glasseadcbc72021-02-06 14:23:39 -0700130 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
131
Simon Glass1c32eee2022-08-30 21:05:34 -0600132 /* handles 4 bytes */
Simon Glasseadcbc72021-02-06 14:23:39 -0700133 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
134
135 /* session header 13 bytes */
136 tpm_u32(9), /* Header size */
137 tpm_u32(TPM2_RS_PW), /* Password authorisation */
138 tpm_u16(0), /* nonce_size */
139 0, /* session_attrs */
140 tpm_u16(0), /* auth_size */
141
142 /* message 14 bytes + policy */
Simon Glass1c32eee2022-08-30 21:05:34 -0600143 tpm_u16(message_len + nv_policy_size), /* size */
Simon Glasseadcbc72021-02-06 14:23:39 -0700144 tpm_u32(space_index),
145 tpm_u16(TPM2_ALG_SHA256),
146 tpm_u32(nv_attributes),
147 tpm_u16(nv_policy_size),
Simon Glass1c32eee2022-08-30 21:05:34 -0600148 /*
149 * nv_policy
150 * space_size
151 */
Simon Glasseadcbc72021-02-06 14:23:39 -0700152 };
153 int ret;
154
155 /*
156 * Fill the command structure starting from the first buffer:
157 * - the password (if any)
158 */
Simon Glass1c32eee2022-08-30 21:05:34 -0600159 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
160 offset, nv_policy, nv_policy_size,
161 offset + nv_policy_size, space_size);
Simon Glasseadcbc72021-02-06 14:23:39 -0700162 if (ret)
163 return TPM_LIB_ERROR;
164
165 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
166}
167
Ilias Apalodimase9261362020-11-26 23:07:22 +0200168u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
169 const u8 *digest, u32 digest_len)
Miquel Raynal6284be52018-05-15 11:57:15 +0200170{
Simon Glass1bea7cc2021-02-06 14:23:38 -0700171 /* Length of the message header, up to start of digest */
172 uint offset = 33;
Miquel Raynal6284be52018-05-15 11:57:15 +0200173 u8 command_v2[COMMAND_BUFFER_SIZE] = {
174 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass1bea7cc2021-02-06 14:23:38 -0700175 tpm_u32(offset + digest_len), /* Length */
Miquel Raynal6284be52018-05-15 11:57:15 +0200176 tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */
177
178 /* HANDLE */
179 tpm_u32(index), /* Handle (PCR Index) */
180
181 /* AUTH_SESSION */
182 tpm_u32(9), /* Authorization size */
183 tpm_u32(TPM2_RS_PW), /* Session handle */
184 tpm_u16(0), /* Size of <nonce> */
185 /* <nonce> (if any) */
186 0, /* Attributes: Cont/Excl/Rst */
187 tpm_u16(0), /* Size of <hmac/password> */
188 /* <hmac/password> (if any) */
Simon Glass1bea7cc2021-02-06 14:23:38 -0700189
190 /* hashes */
Miquel Raynal6284be52018-05-15 11:57:15 +0200191 tpm_u32(1), /* Count (number of hashes) */
Ilias Apalodimase9261362020-11-26 23:07:22 +0200192 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal6284be52018-05-15 11:57:15 +0200193 /* STRING(digest) Digest */
194 };
Miquel Raynal6284be52018-05-15 11:57:15 +0200195 int ret;
196
Simon Glassa557d252022-08-30 21:05:32 -0600197 if (!digest)
198 return -EINVAL;
Miquel Raynal6284be52018-05-15 11:57:15 +0200199 /*
200 * Fill the command structure starting from the first buffer:
201 * - the digest
202 */
203 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
Ilias Apalodimase9261362020-11-26 23:07:22 +0200204 offset, digest, digest_len);
Miquel Raynal6284be52018-05-15 11:57:15 +0200205 if (ret)
206 return TPM_LIB_ERROR;
207
Simon Glassabdc7b82018-11-18 14:22:27 -0700208 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal6284be52018-05-15 11:57:15 +0200209}
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200210
Simon Glass6719cbe2021-02-06 14:23:40 -0700211u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
212{
213 u8 command_v2[COMMAND_BUFFER_SIZE] = {
214 /* header 10 bytes */
215 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
216 tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
217 tpm_u32(TPM2_CC_NV_READ), /* Command code */
218
219 /* handles 8 bytes */
220 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
221 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
222
223 /* AUTH_SESSION */
224 tpm_u32(9), /* Authorization size */
225 tpm_u32(TPM2_RS_PW), /* Session handle */
226 tpm_u16(0), /* Size of <nonce> */
227 /* <nonce> (if any) */
228 0, /* Attributes: Cont/Excl/Rst */
229 tpm_u16(0), /* Size of <hmac/password> */
230 /* <hmac/password> (if any) */
231
232 tpm_u16(count), /* Number of bytes */
233 tpm_u16(0), /* Offset */
234 };
235 size_t response_len = COMMAND_BUFFER_SIZE;
236 u8 response[COMMAND_BUFFER_SIZE];
237 int ret;
238 u16 tag;
239 u32 size, code;
240
241 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
242 if (ret)
243 return log_msg_ret("read", ret);
244 if (unpack_byte_string(response, response_len, "wdds",
245 0, &tag, 2, &size, 6, &code,
246 16, data, count))
247 return TPM_LIB_ERROR;
248
249 return 0;
250}
251
252u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
253 u32 count)
254{
255 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
256 uint offset = 10 + 8 + 4 + 9 + 2;
257 uint len = offset + count + 2;
258 /* Use empty password auth if platform hierarchy is disabled */
259 u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
260 TPM2_RH_PLATFORM;
261 u8 command_v2[COMMAND_BUFFER_SIZE] = {
262 /* header 10 bytes */
263 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
264 tpm_u32(len), /* Length */
265 tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
266
267 /* handles 8 bytes */
268 tpm_u32(auth), /* Primary platform seed */
269 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
270
271 /* AUTH_SESSION */
272 tpm_u32(9), /* Authorization size */
273 tpm_u32(TPM2_RS_PW), /* Session handle */
274 tpm_u16(0), /* Size of <nonce> */
275 /* <nonce> (if any) */
276 0, /* Attributes: Cont/Excl/Rst */
277 tpm_u16(0), /* Size of <hmac/password> */
278 /* <hmac/password> (if any) */
279
280 tpm_u16(count),
281 };
282 size_t response_len = COMMAND_BUFFER_SIZE;
283 u8 response[COMMAND_BUFFER_SIZE];
284 int ret;
285
286 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
287 offset, data, count,
288 offset + count, 0);
289 if (ret)
290 return TPM_LIB_ERROR;
291
292 return tpm_sendrecv_command(dev, command_v2, response, &response_len);
293}
294
Simon Glassabdc7b82018-11-18 14:22:27 -0700295u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530296 u16 algorithm, void *data, u32 digest_len,
297 unsigned int *updates)
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200298{
299 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
300 u8 command_v2[COMMAND_BUFFER_SIZE] = {
301 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
302 tpm_u32(17 + idx_array_sz), /* Length */
303 tpm_u32(TPM2_CC_PCR_READ), /* Command code */
304
305 /* TPML_PCR_SELECTION */
306 tpm_u32(1), /* Number of selections */
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530307 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200308 idx_array_sz, /* Array size for selection */
309 /* bitmap(idx) Selected PCR bitmap */
310 };
311 size_t response_len = COMMAND_BUFFER_SIZE;
312 u8 response[COMMAND_BUFFER_SIZE];
313 unsigned int pcr_sel_idx = idx / 8;
314 u8 pcr_sel_bit = BIT(idx % 8);
315 unsigned int counter = 0;
316 int ret;
317
318 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
319 17 + pcr_sel_idx, pcr_sel_bit))
320 return TPM_LIB_ERROR;
321
Simon Glassabdc7b82018-11-18 14:22:27 -0700322 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200323 if (ret)
324 return ret;
325
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530326 if (digest_len > response_len)
327 return TPM_LIB_ERROR;
328
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200329 if (unpack_byte_string(response, response_len, "ds",
330 10, &counter,
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530331 response_len - digest_len, data,
332 digest_len))
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200333 return TPM_LIB_ERROR;
334
335 if (updates)
336 *updates = counter;
337
338 return 0;
339}
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200340
Simon Glassabdc7b82018-11-18 14:22:27 -0700341u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
342 void *buf, size_t prop_count)
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200343{
344 u8 command_v2[COMMAND_BUFFER_SIZE] = {
345 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
346 tpm_u32(22), /* Length */
347 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
348
349 tpm_u32(capability), /* Capability */
350 tpm_u32(property), /* Property */
351 tpm_u32(prop_count), /* Property count */
352 };
353 u8 response[COMMAND_BUFFER_SIZE];
354 size_t response_len = COMMAND_BUFFER_SIZE;
355 unsigned int properties_off;
356 int ret;
357
Simon Glassabdc7b82018-11-18 14:22:27 -0700358 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200359 if (ret)
360 return ret;
361
362 /*
363 * In the response buffer, the properties are located after the:
364 * tag (u16), response size (u32), response code (u32),
Ilias Apalodimasa322f542020-11-05 23:58:43 +0200365 * YES/NO flag (u8), TPM_CAP (u32).
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200366 */
367 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
Ilias Apalodimasa322f542020-11-05 23:58:43 +0200368 sizeof(u8) + sizeof(u32);
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200369 memcpy(buf, &response[properties_off], response_len - properties_off);
370
371 return 0;
372}
Miquel Raynalda9c3392018-05-15 11:57:18 +0200373
Eddie James97707f12023-10-24 10:43:49 -0500374static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
375{
376 u8 response[(sizeof(struct tpms_capability_data) -
377 offsetof(struct tpms_capability_data, data))];
378 u32 properties_offset =
379 offsetof(struct tpml_tagged_tpm_property, tpm_property) +
380 offsetof(struct tpms_tagged_property, value);
381 u32 ret;
382
383 memset(response, 0, sizeof(response));
384 ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
385 TPM2_PT_PCR_COUNT, response, 1);
386 if (ret)
387 return ret;
388
389 *num_pcr = get_unaligned_be32(response + properties_offset);
390 if (*num_pcr > TPM2_MAX_PCRS) {
391 printf("%s: too many pcrs: %u\n", __func__, *num_pcr);
392 return -E2BIG;
393 }
394
395 return 0;
396}
397
398static bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection)
399{
400 int i;
401
402 /*
403 * check the pcr_select. If at least one of the PCRs supports the
404 * algorithm add it on the active ones
405 */
406 for (i = 0; i < selection->size_of_select; i++) {
407 if (selection->pcr_select[i])
408 return true;
409 }
410
411 return false;
412}
413
414int tpm2_get_pcr_info(struct udevice *dev, u32 *supported_pcr, u32 *active_pcr,
415 u32 *pcr_banks)
416{
417 u8 response[(sizeof(struct tpms_capability_data) -
418 offsetof(struct tpms_capability_data, data))];
419 struct tpml_pcr_selection pcrs;
420 u32 num_pcr;
421 size_t i;
422 u32 ret;
423
424 *supported_pcr = 0;
425 *active_pcr = 0;
426 *pcr_banks = 0;
427 memset(response, 0, sizeof(response));
428 ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
429 if (ret)
430 return ret;
431
432 pcrs.count = get_unaligned_be32(response);
433 /*
434 * We only support 5 algorithms for now so check against that
435 * instead of TPM2_NUM_PCR_BANKS
436 */
Tim Harvey954b95e2024-05-25 13:00:48 -0700437 if (pcrs.count > ARRAY_SIZE(hash_algo_list) ||
Eddie James97707f12023-10-24 10:43:49 -0500438 pcrs.count < 1) {
439 printf("%s: too many pcrs: %u\n", __func__, pcrs.count);
440 return -EMSGSIZE;
441 }
442
443 ret = tpm2_get_num_pcr(dev, &num_pcr);
444 if (ret)
445 return ret;
446
447 for (i = 0; i < pcrs.count; i++) {
448 /*
449 * Definition of TPMS_PCR_SELECTION Structure
450 * hash: u16
451 * size_of_select: u8
452 * pcr_select: u8 array
453 *
454 * The offsets depend on the number of the device PCRs
455 * so we have to calculate them based on that
456 */
457 u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
458 i * offsetof(struct tpms_pcr_selection, pcr_select) +
459 i * ((num_pcr + 7) / 8);
460 u32 size_select_offset =
461 hash_offset + offsetof(struct tpms_pcr_selection,
462 size_of_select);
463 u32 pcr_select_offset =
464 hash_offset + offsetof(struct tpms_pcr_selection,
465 pcr_select);
466
467 pcrs.selection[i].hash =
468 get_unaligned_be16(response + hash_offset);
469 pcrs.selection[i].size_of_select =
470 __get_unaligned_be(response + size_select_offset);
471 if (pcrs.selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
472 printf("%s: pcrs selection too large: %u\n", __func__,
473 pcrs.selection[i].size_of_select);
474 return -ENOBUFS;
475 }
476 /* copy the array of pcr_select */
477 memcpy(pcrs.selection[i].pcr_select, response + pcr_select_offset,
478 pcrs.selection[i].size_of_select);
479 }
480
481 for (i = 0; i < pcrs.count; i++) {
Ilias Apalodimasa56037a2024-06-23 14:48:15 +0300482 u32 hash_mask = tcg2_algorithm_to_mask(pcrs.selection[i].hash);
Eddie James97707f12023-10-24 10:43:49 -0500483
484 if (hash_mask) {
485 *supported_pcr |= hash_mask;
486 if (tpm2_is_active_pcr(&pcrs.selection[i]))
487 *active_pcr |= hash_mask;
488 } else {
489 printf("%s: unknown algorithm %x\n", __func__,
490 pcrs.selection[i].hash);
491 }
492 }
493
494 *pcr_banks = pcrs.count;
495
496 return 0;
497}
498
Simon Glassabdc7b82018-11-18 14:22:27 -0700499u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynalda9c3392018-05-15 11:57:18 +0200500{
501 u8 command_v2[COMMAND_BUFFER_SIZE] = {
502 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
503 tpm_u32(27 + pw_sz), /* Length */
504 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
505
506 /* HANDLE */
507 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
508
509 /* AUTH_SESSION */
510 tpm_u32(9 + pw_sz), /* Authorization size */
511 tpm_u32(TPM2_RS_PW), /* Session handle */
512 tpm_u16(0), /* Size of <nonce> */
513 /* <nonce> (if any) */
514 0, /* Attributes: Cont/Excl/Rst */
515 tpm_u16(pw_sz), /* Size of <hmac/password> */
516 /* STRING(pw) <hmac/password> (if any) */
517 };
518 unsigned int offset = 27;
519 int ret;
520
521 /*
522 * Fill the command structure starting from the first buffer:
523 * - the password (if any)
524 */
525 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
526 offset, pw, pw_sz);
527 offset += pw_sz;
528 if (ret)
529 return TPM_LIB_ERROR;
530
Simon Glassabdc7b82018-11-18 14:22:27 -0700531 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200532}
533
Simon Glassabdc7b82018-11-18 14:22:27 -0700534u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
535 const ssize_t pw_sz, unsigned int max_tries,
536 unsigned int recovery_time,
Miquel Raynalda9c3392018-05-15 11:57:18 +0200537 unsigned int lockout_recovery)
538{
539 u8 command_v2[COMMAND_BUFFER_SIZE] = {
540 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
541 tpm_u32(27 + pw_sz + 12), /* Length */
542 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
543
544 /* HANDLE */
545 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
546
547 /* AUTH_SESSION */
548 tpm_u32(9 + pw_sz), /* Authorization size */
549 tpm_u32(TPM2_RS_PW), /* Session handle */
550 tpm_u16(0), /* Size of <nonce> */
551 /* <nonce> (if any) */
552 0, /* Attributes: Cont/Excl/Rst */
553 tpm_u16(pw_sz), /* Size of <hmac/password> */
554 /* STRING(pw) <hmac/password> (if any) */
555
556 /* LOCKOUT PARAMETERS */
557 /* tpm_u32(max_tries) Max tries (0, always lock) */
558 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
559 /* tpm_u32(lockout_recovery) Lockout recovery */
560 };
561 unsigned int offset = 27;
562 int ret;
563
564 /*
565 * Fill the command structure starting from the first buffer:
566 * - the password (if any)
567 * - max tries
568 * - recovery time
569 * - lockout recovery
570 */
571 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
572 offset, pw, pw_sz,
573 offset + pw_sz, max_tries,
574 offset + pw_sz + 4, recovery_time,
575 offset + pw_sz + 8, lockout_recovery);
576 offset += pw_sz + 12;
577 if (ret)
578 return TPM_LIB_ERROR;
579
Simon Glassabdc7b82018-11-18 14:22:27 -0700580 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200581}
Miquel Raynaldc26e912018-05-15 11:57:19 +0200582
Simon Glassabdc7b82018-11-18 14:22:27 -0700583int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
584 const ssize_t newpw_sz, const char *oldpw,
585 const ssize_t oldpw_sz)
Miquel Raynaldc26e912018-05-15 11:57:19 +0200586{
587 unsigned int offset = 27;
588 u8 command_v2[COMMAND_BUFFER_SIZE] = {
589 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
590 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
591 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
592
593 /* HANDLE */
594 tpm_u32(handle), /* TPM resource handle */
595
596 /* AUTH_SESSION */
597 tpm_u32(9 + oldpw_sz), /* Authorization size */
598 tpm_u32(TPM2_RS_PW), /* Session handle */
599 tpm_u16(0), /* Size of <nonce> */
600 /* <nonce> (if any) */
601 0, /* Attributes: Cont/Excl/Rst */
602 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
603 /* STRING(oldpw) <hmac/password> (if any) */
604
605 /* TPM2B_AUTH (TPM2B_DIGEST) */
606 /* tpm_u16(newpw_sz) Digest size, new pw length */
607 /* STRING(newpw) Digest buffer, new pw */
608 };
609 int ret;
610
611 /*
612 * Fill the command structure starting from the first buffer:
613 * - the old password (if any)
614 * - size of the new password
615 * - new password
616 */
617 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
618 offset, oldpw, oldpw_sz,
619 offset + oldpw_sz, newpw_sz,
620 offset + oldpw_sz + 2, newpw, newpw_sz);
621 offset += oldpw_sz + 2 + newpw_sz;
622 if (ret)
623 return TPM_LIB_ERROR;
624
Simon Glassabdc7b82018-11-18 14:22:27 -0700625 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynaldc26e912018-05-15 11:57:19 +0200626}
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200627
Simon Glassabdc7b82018-11-18 14:22:27 -0700628u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
629 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200630{
631 u8 command_v2[COMMAND_BUFFER_SIZE] = {
632 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
633 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
634 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
635
636 /* HANDLE */
637 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
638
639 /* AUTH_SESSION */
640 tpm_u32(9 + pw_sz), /* Authorization size */
641 tpm_u32(TPM2_RS_PW), /* session handle */
642 tpm_u16(0), /* Size of <nonce> */
643 /* <nonce> (if any) */
644 0, /* Attributes: Cont/Excl/Rst */
645 tpm_u16(pw_sz) /* Size of <hmac/password> */
646 /* STRING(pw) <hmac/password> (if any) */
647
648 /* TPM2B_AUTH (TPM2B_DIGEST) */
649 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
650 /* STRING(key) Digest buffer (PCR key) */
651
652 /* TPMI_ALG_HASH */
653 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
654
655 /* TPMI_DH_PCR */
656 /* tpm_u32(index), PCR Index */
657 };
658 unsigned int offset = 27;
659 int ret;
660
661 /*
662 * Fill the command structure starting from the first buffer:
663 * - the password (if any)
664 * - the PCR key length
665 * - the PCR key
666 * - the hash algorithm
667 * - the PCR index
668 */
669 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
670 offset, pw, pw_sz,
671 offset + pw_sz, TPM2_DIGEST_LEN,
672 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
673 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
674 TPM2_ALG_SHA256,
675 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
676 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
677 if (ret)
678 return TPM_LIB_ERROR;
679
Simon Glassabdc7b82018-11-18 14:22:27 -0700680 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200681}
682
Simon Glassabdc7b82018-11-18 14:22:27 -0700683u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
684 const ssize_t pw_sz, u32 index, const char *key,
685 const ssize_t key_sz)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200686{
687 u8 command_v2[COMMAND_BUFFER_SIZE] = {
688 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
689 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
690 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
691
692 /* HANDLE */
693 tpm_u32(index), /* Handle (PCR Index) */
694
695 /* AUTH_SESSION */
696 tpm_u32(9 + pw_sz), /* Authorization size */
697 tpm_u32(TPM2_RS_PW), /* session handle */
698 tpm_u16(0), /* Size of <nonce> */
699 /* <nonce> (if any) */
700 0, /* Attributes: Cont/Excl/Rst */
701 tpm_u16(pw_sz), /* Size of <hmac/password> */
702 /* STRING(pw) <hmac/password> (if any) */
703
704 /* TPM2B_DIGEST */
705 /* tpm_u16(key_sz) Key length */
706 /* STRING(key) Key */
707 };
708 unsigned int offset = 27;
709 int ret;
710
711 /*
712 * Fill the command structure starting from the first buffer:
713 * - the password (if any)
714 * - the number of digests, 1 in our case
715 * - the algorithm, sha256 in our case
716 * - the digest (64 bytes)
717 */
718 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
719 offset, pw, pw_sz,
720 offset + pw_sz, key_sz,
721 offset + pw_sz + 2, key, key_sz);
722 offset += pw_sz + 2 + key_sz;
723 if (ret)
724 return TPM_LIB_ERROR;
725
Simon Glassabdc7b82018-11-18 14:22:27 -0700726 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200727}
Dhananjay Phadke06bea492020-06-04 16:43:59 -0700728
729u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
730{
731 const u8 command_v2[10] = {
732 tpm_u16(TPM2_ST_NO_SESSIONS),
733 tpm_u32(12),
734 tpm_u32(TPM2_CC_GET_RANDOM),
735 };
736 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
737
738 const size_t data_size_offset = 10;
739 const size_t data_offset = 12;
740 size_t response_length = sizeof(response);
741 u32 data_size;
742 u8 *out = data;
743
744 while (count > 0) {
745 u32 this_bytes = min((size_t)count,
746 sizeof(response) - data_offset);
747 u32 err;
748
749 if (pack_byte_string(buf, sizeof(buf), "sw",
750 0, command_v2, sizeof(command_v2),
751 sizeof(command_v2), this_bytes))
752 return TPM_LIB_ERROR;
753 err = tpm_sendrecv_command(dev, buf, response,
754 &response_length);
755 if (err)
756 return err;
757 if (unpack_byte_string(response, response_length, "w",
758 data_size_offset, &data_size))
759 return TPM_LIB_ERROR;
760 if (data_size > this_bytes)
761 return TPM_LIB_ERROR;
762 if (unpack_byte_string(response, response_length, "s",
763 data_offset, out, data_size))
764 return TPM_LIB_ERROR;
765
766 count -= data_size;
767 out += data_size;
768 }
769
770 return 0;
771}
Simon Glass7785bc12021-02-06 14:23:41 -0700772
773u32 tpm2_write_lock(struct udevice *dev, u32 index)
774{
775 u8 command_v2[COMMAND_BUFFER_SIZE] = {
776 /* header 10 bytes */
777 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
778 tpm_u32(10 + 8 + 13), /* Length */
779 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
780
781 /* handles 8 bytes */
782 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
783 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
784
785 /* session header 9 bytes */
786 tpm_u32(9), /* Header size */
787 tpm_u32(TPM2_RS_PW), /* Password authorisation */
788 tpm_u16(0), /* nonce_size */
789 0, /* session_attrs */
790 tpm_u16(0), /* auth_size */
791 };
792
793 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
794}
Simon Glass63af92e2021-02-06 14:23:42 -0700795
796u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
797{
798 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
799 u8 command_v2[COMMAND_BUFFER_SIZE] = {
800 /* header 10 bytes */
801 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
802 tpm_u32(10 + 4 + 13 + 5), /* Length */
803 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
804
805 /* 4 bytes */
806 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
807
808 /* session header 9 bytes */
809 tpm_u32(9), /* Header size */
810 tpm_u32(TPM2_RS_PW), /* Password authorisation */
811 tpm_u16(0), /* nonce_size */
812 0, /* session_attrs */
813 tpm_u16(0), /* auth_size */
814
815 /* payload 5 bytes */
816 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
817 0, /* 0=disable */
818 };
819 int ret;
820
821 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
822 log_info("ret=%s, %x\n", dev->name, ret);
823 if (ret)
824 return ret;
825
826 priv->plat_hier_disabled = true;
827
828 return 0;
829}
Masahisa Kojima7fc93ca2021-11-04 22:59:16 +0900830
831u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
832 u8 *recvbuf, size_t *recv_size)
833{
834 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
835}
Simon Glass4c57ec72022-08-30 21:05:37 -0600836
837u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
838 u8 *recvbuf, size_t *recv_size)
839{
840 u8 command_v2[COMMAND_BUFFER_SIZE] = {
841 /* header 10 bytes */
842 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
843 tpm_u32(10 + 2), /* Length */
844 tpm_u32(vendor_cmd), /* Command code */
845
846 tpm_u16(vendor_subcmd),
847 };
848 int ret;
849
850 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
851 log_debug("ret=%s, %x\n", dev->name, ret);
852 if (ret)
853 return ret;
854 if (*recv_size < 12)
855 return -ENODATA;
856 *recv_size -= 12;
857 memcpy(recvbuf, recvbuf + 12, *recv_size);
858
859 return 0;
860}
Simon Glass5208ed12022-08-30 21:05:38 -0600861
862u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
863 uint vendor_subcmd)
864{
865 u8 command_v2[COMMAND_BUFFER_SIZE] = {
866 /* header 10 bytes */
867 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
868 tpm_u32(10 + 2), /* Length */
869 tpm_u32(vendor_cmd), /* Command code */
870
871 tpm_u16(vendor_subcmd),
872 };
873 int ret;
874
875 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
876 log_debug("ret=%s, %x\n", dev->name, ret);
877 if (ret)
878 return ret;
879
880 return 0;
881}
Tim Harvey954b95e2024-05-25 13:00:48 -0700882
883enum tpm2_algorithms tpm2_name_to_algorithm(const char *name)
884{
885 size_t i;
886
887 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
888 if (!strcasecmp(name, hash_algo_list[i].hash_name))
889 return hash_algo_list[i].hash_alg;
890 }
891 printf("%s: unsupported algorithm %s\n", __func__, name);
892
893 return -EINVAL;
894}
895
896const char *tpm2_algorithm_name(enum tpm2_algorithms algo)
897{
898 size_t i;
899
900 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
901 if (hash_algo_list[i].hash_alg == algo)
902 return hash_algo_list[i].hash_name;
903 }
904
905 return "";
906}
907