blob: 36aace03cf4ee18ed90b63c1ffae1c3c2bb573c5 [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
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300398int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs)
Eddie James97707f12023-10-24 10:43:49 -0500399{
400 u8 response[(sizeof(struct tpms_capability_data) -
401 offsetof(struct tpms_capability_data, data))];
Eddie James97707f12023-10-24 10:43:49 -0500402 u32 num_pcr;
403 size_t i;
404 u32 ret;
405
Eddie James97707f12023-10-24 10:43:49 -0500406 ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
407 if (ret)
408 return ret;
409
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300410 pcrs->count = get_unaligned_be32(response);
Eddie James97707f12023-10-24 10:43:49 -0500411 /*
412 * We only support 5 algorithms for now so check against that
413 * instead of TPM2_NUM_PCR_BANKS
414 */
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300415 if (pcrs->count > ARRAY_SIZE(hash_algo_list) ||
416 pcrs->count < 1) {
417 printf("%s: too many pcrs: %u\n", __func__, pcrs->count);
Eddie James97707f12023-10-24 10:43:49 -0500418 return -EMSGSIZE;
419 }
420
421 ret = tpm2_get_num_pcr(dev, &num_pcr);
422 if (ret)
423 return ret;
424
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300425 for (i = 0; i < pcrs->count; i++) {
Eddie James97707f12023-10-24 10:43:49 -0500426 /*
427 * Definition of TPMS_PCR_SELECTION Structure
428 * hash: u16
429 * size_of_select: u8
430 * pcr_select: u8 array
431 *
432 * The offsets depend on the number of the device PCRs
433 * so we have to calculate them based on that
434 */
435 u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
436 i * offsetof(struct tpms_pcr_selection, pcr_select) +
437 i * ((num_pcr + 7) / 8);
438 u32 size_select_offset =
439 hash_offset + offsetof(struct tpms_pcr_selection,
440 size_of_select);
441 u32 pcr_select_offset =
442 hash_offset + offsetof(struct tpms_pcr_selection,
443 pcr_select);
444
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300445 pcrs->selection[i].hash =
Eddie James97707f12023-10-24 10:43:49 -0500446 get_unaligned_be16(response + hash_offset);
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300447 pcrs->selection[i].size_of_select =
Eddie James97707f12023-10-24 10:43:49 -0500448 __get_unaligned_be(response + size_select_offset);
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300449 if (pcrs->selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
Eddie James97707f12023-10-24 10:43:49 -0500450 printf("%s: pcrs selection too large: %u\n", __func__,
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300451 pcrs->selection[i].size_of_select);
Eddie James97707f12023-10-24 10:43:49 -0500452 return -ENOBUFS;
453 }
454 /* copy the array of pcr_select */
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300455 memcpy(pcrs->selection[i].pcr_select, response + pcr_select_offset,
456 pcrs->selection[i].size_of_select);
Eddie James97707f12023-10-24 10:43:49 -0500457 }
458
Eddie James97707f12023-10-24 10:43:49 -0500459 return 0;
460}
461
Simon Glassabdc7b82018-11-18 14:22:27 -0700462u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynalda9c3392018-05-15 11:57:18 +0200463{
464 u8 command_v2[COMMAND_BUFFER_SIZE] = {
465 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
466 tpm_u32(27 + pw_sz), /* Length */
467 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
468
469 /* HANDLE */
470 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
471
472 /* AUTH_SESSION */
473 tpm_u32(9 + pw_sz), /* Authorization size */
474 tpm_u32(TPM2_RS_PW), /* Session handle */
475 tpm_u16(0), /* Size of <nonce> */
476 /* <nonce> (if any) */
477 0, /* Attributes: Cont/Excl/Rst */
478 tpm_u16(pw_sz), /* Size of <hmac/password> */
479 /* STRING(pw) <hmac/password> (if any) */
480 };
481 unsigned int offset = 27;
482 int ret;
483
484 /*
485 * Fill the command structure starting from the first buffer:
486 * - the password (if any)
487 */
488 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
489 offset, pw, pw_sz);
490 offset += pw_sz;
491 if (ret)
492 return TPM_LIB_ERROR;
493
Simon Glassabdc7b82018-11-18 14:22:27 -0700494 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200495}
496
Simon Glassabdc7b82018-11-18 14:22:27 -0700497u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
498 const ssize_t pw_sz, unsigned int max_tries,
499 unsigned int recovery_time,
Miquel Raynalda9c3392018-05-15 11:57:18 +0200500 unsigned int lockout_recovery)
501{
502 u8 command_v2[COMMAND_BUFFER_SIZE] = {
503 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
504 tpm_u32(27 + pw_sz + 12), /* Length */
505 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
506
507 /* HANDLE */
508 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
509
510 /* AUTH_SESSION */
511 tpm_u32(9 + pw_sz), /* Authorization size */
512 tpm_u32(TPM2_RS_PW), /* Session handle */
513 tpm_u16(0), /* Size of <nonce> */
514 /* <nonce> (if any) */
515 0, /* Attributes: Cont/Excl/Rst */
516 tpm_u16(pw_sz), /* Size of <hmac/password> */
517 /* STRING(pw) <hmac/password> (if any) */
518
519 /* LOCKOUT PARAMETERS */
520 /* tpm_u32(max_tries) Max tries (0, always lock) */
521 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
522 /* tpm_u32(lockout_recovery) Lockout recovery */
523 };
524 unsigned int offset = 27;
525 int ret;
526
527 /*
528 * Fill the command structure starting from the first buffer:
529 * - the password (if any)
530 * - max tries
531 * - recovery time
532 * - lockout recovery
533 */
534 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
535 offset, pw, pw_sz,
536 offset + pw_sz, max_tries,
537 offset + pw_sz + 4, recovery_time,
538 offset + pw_sz + 8, lockout_recovery);
539 offset += pw_sz + 12;
540 if (ret)
541 return TPM_LIB_ERROR;
542
Simon Glassabdc7b82018-11-18 14:22:27 -0700543 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200544}
Miquel Raynaldc26e912018-05-15 11:57:19 +0200545
Simon Glassabdc7b82018-11-18 14:22:27 -0700546int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
547 const ssize_t newpw_sz, const char *oldpw,
548 const ssize_t oldpw_sz)
Miquel Raynaldc26e912018-05-15 11:57:19 +0200549{
550 unsigned int offset = 27;
551 u8 command_v2[COMMAND_BUFFER_SIZE] = {
552 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
553 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
554 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
555
556 /* HANDLE */
557 tpm_u32(handle), /* TPM resource handle */
558
559 /* AUTH_SESSION */
560 tpm_u32(9 + oldpw_sz), /* Authorization size */
561 tpm_u32(TPM2_RS_PW), /* Session handle */
562 tpm_u16(0), /* Size of <nonce> */
563 /* <nonce> (if any) */
564 0, /* Attributes: Cont/Excl/Rst */
565 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
566 /* STRING(oldpw) <hmac/password> (if any) */
567
568 /* TPM2B_AUTH (TPM2B_DIGEST) */
569 /* tpm_u16(newpw_sz) Digest size, new pw length */
570 /* STRING(newpw) Digest buffer, new pw */
571 };
572 int ret;
573
574 /*
575 * Fill the command structure starting from the first buffer:
576 * - the old password (if any)
577 * - size of the new password
578 * - new password
579 */
580 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
581 offset, oldpw, oldpw_sz,
582 offset + oldpw_sz, newpw_sz,
583 offset + oldpw_sz + 2, newpw, newpw_sz);
584 offset += oldpw_sz + 2 + newpw_sz;
585 if (ret)
586 return TPM_LIB_ERROR;
587
Simon Glassabdc7b82018-11-18 14:22:27 -0700588 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynaldc26e912018-05-15 11:57:19 +0200589}
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200590
Simon Glassabdc7b82018-11-18 14:22:27 -0700591u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
592 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200593{
594 u8 command_v2[COMMAND_BUFFER_SIZE] = {
595 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
596 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
597 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
598
599 /* HANDLE */
600 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
601
602 /* AUTH_SESSION */
603 tpm_u32(9 + pw_sz), /* Authorization size */
604 tpm_u32(TPM2_RS_PW), /* session handle */
605 tpm_u16(0), /* Size of <nonce> */
606 /* <nonce> (if any) */
607 0, /* Attributes: Cont/Excl/Rst */
608 tpm_u16(pw_sz) /* Size of <hmac/password> */
609 /* STRING(pw) <hmac/password> (if any) */
610
611 /* TPM2B_AUTH (TPM2B_DIGEST) */
612 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
613 /* STRING(key) Digest buffer (PCR key) */
614
615 /* TPMI_ALG_HASH */
616 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
617
618 /* TPMI_DH_PCR */
619 /* tpm_u32(index), PCR Index */
620 };
621 unsigned int offset = 27;
622 int ret;
623
624 /*
625 * Fill the command structure starting from the first buffer:
626 * - the password (if any)
627 * - the PCR key length
628 * - the PCR key
629 * - the hash algorithm
630 * - the PCR index
631 */
632 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
633 offset, pw, pw_sz,
634 offset + pw_sz, TPM2_DIGEST_LEN,
635 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
636 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
637 TPM2_ALG_SHA256,
638 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
639 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
640 if (ret)
641 return TPM_LIB_ERROR;
642
Simon Glassabdc7b82018-11-18 14:22:27 -0700643 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200644}
645
Simon Glassabdc7b82018-11-18 14:22:27 -0700646u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
647 const ssize_t pw_sz, u32 index, const char *key,
648 const ssize_t key_sz)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200649{
650 u8 command_v2[COMMAND_BUFFER_SIZE] = {
651 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
652 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
653 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
654
655 /* HANDLE */
656 tpm_u32(index), /* Handle (PCR Index) */
657
658 /* AUTH_SESSION */
659 tpm_u32(9 + pw_sz), /* Authorization size */
660 tpm_u32(TPM2_RS_PW), /* session handle */
661 tpm_u16(0), /* Size of <nonce> */
662 /* <nonce> (if any) */
663 0, /* Attributes: Cont/Excl/Rst */
664 tpm_u16(pw_sz), /* Size of <hmac/password> */
665 /* STRING(pw) <hmac/password> (if any) */
666
667 /* TPM2B_DIGEST */
668 /* tpm_u16(key_sz) Key length */
669 /* STRING(key) Key */
670 };
671 unsigned int offset = 27;
672 int ret;
673
674 /*
675 * Fill the command structure starting from the first buffer:
676 * - the password (if any)
677 * - the number of digests, 1 in our case
678 * - the algorithm, sha256 in our case
679 * - the digest (64 bytes)
680 */
681 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
682 offset, pw, pw_sz,
683 offset + pw_sz, key_sz,
684 offset + pw_sz + 2, key, key_sz);
685 offset += pw_sz + 2 + key_sz;
686 if (ret)
687 return TPM_LIB_ERROR;
688
Simon Glassabdc7b82018-11-18 14:22:27 -0700689 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200690}
Dhananjay Phadke06bea492020-06-04 16:43:59 -0700691
692u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
693{
694 const u8 command_v2[10] = {
695 tpm_u16(TPM2_ST_NO_SESSIONS),
696 tpm_u32(12),
697 tpm_u32(TPM2_CC_GET_RANDOM),
698 };
699 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
700
701 const size_t data_size_offset = 10;
702 const size_t data_offset = 12;
703 size_t response_length = sizeof(response);
704 u32 data_size;
705 u8 *out = data;
706
707 while (count > 0) {
708 u32 this_bytes = min((size_t)count,
709 sizeof(response) - data_offset);
710 u32 err;
711
712 if (pack_byte_string(buf, sizeof(buf), "sw",
713 0, command_v2, sizeof(command_v2),
714 sizeof(command_v2), this_bytes))
715 return TPM_LIB_ERROR;
716 err = tpm_sendrecv_command(dev, buf, response,
717 &response_length);
718 if (err)
719 return err;
720 if (unpack_byte_string(response, response_length, "w",
721 data_size_offset, &data_size))
722 return TPM_LIB_ERROR;
723 if (data_size > this_bytes)
724 return TPM_LIB_ERROR;
725 if (unpack_byte_string(response, response_length, "s",
726 data_offset, out, data_size))
727 return TPM_LIB_ERROR;
728
729 count -= data_size;
730 out += data_size;
731 }
732
733 return 0;
734}
Simon Glass7785bc12021-02-06 14:23:41 -0700735
736u32 tpm2_write_lock(struct udevice *dev, u32 index)
737{
738 u8 command_v2[COMMAND_BUFFER_SIZE] = {
739 /* header 10 bytes */
740 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
741 tpm_u32(10 + 8 + 13), /* Length */
742 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
743
744 /* handles 8 bytes */
745 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
746 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
747
748 /* session header 9 bytes */
749 tpm_u32(9), /* Header size */
750 tpm_u32(TPM2_RS_PW), /* Password authorisation */
751 tpm_u16(0), /* nonce_size */
752 0, /* session_attrs */
753 tpm_u16(0), /* auth_size */
754 };
755
756 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
757}
Simon Glass63af92e2021-02-06 14:23:42 -0700758
759u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
760{
761 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
762 u8 command_v2[COMMAND_BUFFER_SIZE] = {
763 /* header 10 bytes */
764 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
765 tpm_u32(10 + 4 + 13 + 5), /* Length */
766 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
767
768 /* 4 bytes */
769 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
770
771 /* session header 9 bytes */
772 tpm_u32(9), /* Header size */
773 tpm_u32(TPM2_RS_PW), /* Password authorisation */
774 tpm_u16(0), /* nonce_size */
775 0, /* session_attrs */
776 tpm_u16(0), /* auth_size */
777
778 /* payload 5 bytes */
779 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
780 0, /* 0=disable */
781 };
782 int ret;
783
784 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
785 log_info("ret=%s, %x\n", dev->name, ret);
786 if (ret)
787 return ret;
788
789 priv->plat_hier_disabled = true;
790
791 return 0;
792}
Masahisa Kojima7fc93ca2021-11-04 22:59:16 +0900793
794u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
795 u8 *recvbuf, size_t *recv_size)
796{
797 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
798}
Simon Glass4c57ec72022-08-30 21:05:37 -0600799
800u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
801 u8 *recvbuf, size_t *recv_size)
802{
803 u8 command_v2[COMMAND_BUFFER_SIZE] = {
804 /* header 10 bytes */
805 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
806 tpm_u32(10 + 2), /* Length */
807 tpm_u32(vendor_cmd), /* Command code */
808
809 tpm_u16(vendor_subcmd),
810 };
811 int ret;
812
813 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
814 log_debug("ret=%s, %x\n", dev->name, ret);
815 if (ret)
816 return ret;
817 if (*recv_size < 12)
818 return -ENODATA;
819 *recv_size -= 12;
820 memcpy(recvbuf, recvbuf + 12, *recv_size);
821
822 return 0;
823}
Simon Glass5208ed12022-08-30 21:05:38 -0600824
825u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
826 uint vendor_subcmd)
827{
828 u8 command_v2[COMMAND_BUFFER_SIZE] = {
829 /* header 10 bytes */
830 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
831 tpm_u32(10 + 2), /* Length */
832 tpm_u32(vendor_cmd), /* Command code */
833
834 tpm_u16(vendor_subcmd),
835 };
836 int ret;
837
838 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
839 log_debug("ret=%s, %x\n", dev->name, ret);
840 if (ret)
841 return ret;
842
843 return 0;
844}
Tim Harvey954b95e2024-05-25 13:00:48 -0700845
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300846bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection)
847{
848 int i;
849
850 for (i = 0; i < selection->size_of_select; i++) {
851 if (selection->pcr_select[i])
852 return true;
853 }
854
855 return false;
856}
857
Tim Harvey954b95e2024-05-25 13:00:48 -0700858enum tpm2_algorithms tpm2_name_to_algorithm(const char *name)
859{
860 size_t i;
861
862 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
863 if (!strcasecmp(name, hash_algo_list[i].hash_name))
864 return hash_algo_list[i].hash_alg;
865 }
866 printf("%s: unsupported algorithm %s\n", __func__, name);
867
868 return -EINVAL;
869}
870
871const char *tpm2_algorithm_name(enum tpm2_algorithms algo)
872{
873 size_t i;
874
875 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
876 if (hash_algo_list[i].hash_alg == algo)
877 return hash_algo_list[i].hash_name;
878 }
879
880 return "";
881}
882