blob: 59e6cbafafaa1f86196ea7a17226fd7861cfe7ae [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;
Ilias Apalodimase7505b32024-06-23 14:48:18 +0300199
200 if (!tpm2_allow_extend(dev)) {
201 log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n");
202 return -EINVAL;
203 }
Miquel Raynal6284be52018-05-15 11:57:15 +0200204 /*
205 * Fill the command structure starting from the first buffer:
206 * - the digest
207 */
208 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
Ilias Apalodimase9261362020-11-26 23:07:22 +0200209 offset, digest, digest_len);
Miquel Raynal6284be52018-05-15 11:57:15 +0200210 if (ret)
211 return TPM_LIB_ERROR;
212
Simon Glassabdc7b82018-11-18 14:22:27 -0700213 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal6284be52018-05-15 11:57:15 +0200214}
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200215
Simon Glass6719cbe2021-02-06 14:23:40 -0700216u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
217{
218 u8 command_v2[COMMAND_BUFFER_SIZE] = {
219 /* header 10 bytes */
220 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
221 tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
222 tpm_u32(TPM2_CC_NV_READ), /* Command code */
223
224 /* handles 8 bytes */
225 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
226 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
227
228 /* AUTH_SESSION */
229 tpm_u32(9), /* Authorization size */
230 tpm_u32(TPM2_RS_PW), /* Session handle */
231 tpm_u16(0), /* Size of <nonce> */
232 /* <nonce> (if any) */
233 0, /* Attributes: Cont/Excl/Rst */
234 tpm_u16(0), /* Size of <hmac/password> */
235 /* <hmac/password> (if any) */
236
237 tpm_u16(count), /* Number of bytes */
238 tpm_u16(0), /* Offset */
239 };
240 size_t response_len = COMMAND_BUFFER_SIZE;
241 u8 response[COMMAND_BUFFER_SIZE];
242 int ret;
243 u16 tag;
244 u32 size, code;
245
246 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
247 if (ret)
248 return log_msg_ret("read", ret);
249 if (unpack_byte_string(response, response_len, "wdds",
250 0, &tag, 2, &size, 6, &code,
251 16, data, count))
252 return TPM_LIB_ERROR;
253
254 return 0;
255}
256
257u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
258 u32 count)
259{
260 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
261 uint offset = 10 + 8 + 4 + 9 + 2;
262 uint len = offset + count + 2;
263 /* Use empty password auth if platform hierarchy is disabled */
264 u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
265 TPM2_RH_PLATFORM;
266 u8 command_v2[COMMAND_BUFFER_SIZE] = {
267 /* header 10 bytes */
268 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
269 tpm_u32(len), /* Length */
270 tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
271
272 /* handles 8 bytes */
273 tpm_u32(auth), /* Primary platform seed */
274 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
275
276 /* AUTH_SESSION */
277 tpm_u32(9), /* Authorization size */
278 tpm_u32(TPM2_RS_PW), /* Session handle */
279 tpm_u16(0), /* Size of <nonce> */
280 /* <nonce> (if any) */
281 0, /* Attributes: Cont/Excl/Rst */
282 tpm_u16(0), /* Size of <hmac/password> */
283 /* <hmac/password> (if any) */
284
285 tpm_u16(count),
286 };
287 size_t response_len = COMMAND_BUFFER_SIZE;
288 u8 response[COMMAND_BUFFER_SIZE];
289 int ret;
290
291 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
292 offset, data, count,
293 offset + count, 0);
294 if (ret)
295 return TPM_LIB_ERROR;
296
297 return tpm_sendrecv_command(dev, command_v2, response, &response_len);
298}
299
Simon Glassabdc7b82018-11-18 14:22:27 -0700300u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530301 u16 algorithm, void *data, u32 digest_len,
302 unsigned int *updates)
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200303{
304 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
305 u8 command_v2[COMMAND_BUFFER_SIZE] = {
306 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
307 tpm_u32(17 + idx_array_sz), /* Length */
308 tpm_u32(TPM2_CC_PCR_READ), /* Command code */
309
310 /* TPML_PCR_SELECTION */
311 tpm_u32(1), /* Number of selections */
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530312 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200313 idx_array_sz, /* Array size for selection */
314 /* bitmap(idx) Selected PCR bitmap */
315 };
316 size_t response_len = COMMAND_BUFFER_SIZE;
317 u8 response[COMMAND_BUFFER_SIZE];
318 unsigned int pcr_sel_idx = idx / 8;
319 u8 pcr_sel_bit = BIT(idx % 8);
320 unsigned int counter = 0;
321 int ret;
322
323 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
324 17 + pcr_sel_idx, pcr_sel_bit))
325 return TPM_LIB_ERROR;
326
Simon Glassabdc7b82018-11-18 14:22:27 -0700327 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200328 if (ret)
329 return ret;
330
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530331 if (digest_len > response_len)
332 return TPM_LIB_ERROR;
333
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200334 if (unpack_byte_string(response, response_len, "ds",
335 10, &counter,
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530336 response_len - digest_len, data,
337 digest_len))
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200338 return TPM_LIB_ERROR;
339
340 if (updates)
341 *updates = counter;
342
343 return 0;
344}
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200345
Simon Glassabdc7b82018-11-18 14:22:27 -0700346u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
347 void *buf, size_t prop_count)
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200348{
349 u8 command_v2[COMMAND_BUFFER_SIZE] = {
350 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
351 tpm_u32(22), /* Length */
352 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
353
354 tpm_u32(capability), /* Capability */
355 tpm_u32(property), /* Property */
356 tpm_u32(prop_count), /* Property count */
357 };
358 u8 response[COMMAND_BUFFER_SIZE];
359 size_t response_len = COMMAND_BUFFER_SIZE;
360 unsigned int properties_off;
361 int ret;
362
Simon Glassabdc7b82018-11-18 14:22:27 -0700363 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200364 if (ret)
365 return ret;
366
367 /*
368 * In the response buffer, the properties are located after the:
369 * tag (u16), response size (u32), response code (u32),
Ilias Apalodimasa322f542020-11-05 23:58:43 +0200370 * YES/NO flag (u8), TPM_CAP (u32).
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200371 */
372 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
Ilias Apalodimasa322f542020-11-05 23:58:43 +0200373 sizeof(u8) + sizeof(u32);
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200374 memcpy(buf, &response[properties_off], response_len - properties_off);
375
376 return 0;
377}
Miquel Raynalda9c3392018-05-15 11:57:18 +0200378
Eddie James97707f12023-10-24 10:43:49 -0500379static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr)
380{
381 u8 response[(sizeof(struct tpms_capability_data) -
382 offsetof(struct tpms_capability_data, data))];
383 u32 properties_offset =
384 offsetof(struct tpml_tagged_tpm_property, tpm_property) +
385 offsetof(struct tpms_tagged_property, value);
386 u32 ret;
387
388 memset(response, 0, sizeof(response));
389 ret = tpm2_get_capability(dev, TPM2_CAP_TPM_PROPERTIES,
390 TPM2_PT_PCR_COUNT, response, 1);
391 if (ret)
392 return ret;
393
394 *num_pcr = get_unaligned_be32(response + properties_offset);
395 if (*num_pcr > TPM2_MAX_PCRS) {
396 printf("%s: too many pcrs: %u\n", __func__, *num_pcr);
397 return -E2BIG;
398 }
399
400 return 0;
401}
402
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300403int tpm2_get_pcr_info(struct udevice *dev, struct tpml_pcr_selection *pcrs)
Eddie James97707f12023-10-24 10:43:49 -0500404{
405 u8 response[(sizeof(struct tpms_capability_data) -
406 offsetof(struct tpms_capability_data, data))];
Eddie James97707f12023-10-24 10:43:49 -0500407 u32 num_pcr;
408 size_t i;
409 u32 ret;
410
Eddie James97707f12023-10-24 10:43:49 -0500411 ret = tpm2_get_capability(dev, TPM2_CAP_PCRS, 0, response, 1);
412 if (ret)
413 return ret;
414
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300415 pcrs->count = get_unaligned_be32(response);
Eddie James97707f12023-10-24 10:43:49 -0500416 /*
Ilias Apalodimase7505b32024-06-23 14:48:18 +0300417 * We only support 4 algorithms for now so check against that
Eddie James97707f12023-10-24 10:43:49 -0500418 * instead of TPM2_NUM_PCR_BANKS
419 */
Ilias Apalodimase7505b32024-06-23 14:48:18 +0300420 if (pcrs->count > 4 || pcrs->count < 1) {
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300421 printf("%s: too many pcrs: %u\n", __func__, pcrs->count);
Eddie James97707f12023-10-24 10:43:49 -0500422 return -EMSGSIZE;
423 }
424
425 ret = tpm2_get_num_pcr(dev, &num_pcr);
426 if (ret)
427 return ret;
428
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300429 for (i = 0; i < pcrs->count; i++) {
Eddie James97707f12023-10-24 10:43:49 -0500430 /*
431 * Definition of TPMS_PCR_SELECTION Structure
432 * hash: u16
433 * size_of_select: u8
434 * pcr_select: u8 array
435 *
436 * The offsets depend on the number of the device PCRs
437 * so we have to calculate them based on that
438 */
439 u32 hash_offset = offsetof(struct tpml_pcr_selection, selection) +
440 i * offsetof(struct tpms_pcr_selection, pcr_select) +
441 i * ((num_pcr + 7) / 8);
442 u32 size_select_offset =
443 hash_offset + offsetof(struct tpms_pcr_selection,
444 size_of_select);
445 u32 pcr_select_offset =
446 hash_offset + offsetof(struct tpms_pcr_selection,
447 pcr_select);
448
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300449 pcrs->selection[i].hash =
Eddie James97707f12023-10-24 10:43:49 -0500450 get_unaligned_be16(response + hash_offset);
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300451 pcrs->selection[i].size_of_select =
Eddie James97707f12023-10-24 10:43:49 -0500452 __get_unaligned_be(response + size_select_offset);
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300453 if (pcrs->selection[i].size_of_select > TPM2_PCR_SELECT_MAX) {
Eddie James97707f12023-10-24 10:43:49 -0500454 printf("%s: pcrs selection too large: %u\n", __func__,
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300455 pcrs->selection[i].size_of_select);
Eddie James97707f12023-10-24 10:43:49 -0500456 return -ENOBUFS;
457 }
458 /* copy the array of pcr_select */
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300459 memcpy(pcrs->selection[i].pcr_select, response + pcr_select_offset,
460 pcrs->selection[i].size_of_select);
Eddie James97707f12023-10-24 10:43:49 -0500461 }
462
Eddie James97707f12023-10-24 10:43:49 -0500463 return 0;
464}
465
Simon Glassabdc7b82018-11-18 14:22:27 -0700466u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynalda9c3392018-05-15 11:57:18 +0200467{
468 u8 command_v2[COMMAND_BUFFER_SIZE] = {
469 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
470 tpm_u32(27 + pw_sz), /* Length */
471 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
472
473 /* HANDLE */
474 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
475
476 /* AUTH_SESSION */
477 tpm_u32(9 + pw_sz), /* Authorization size */
478 tpm_u32(TPM2_RS_PW), /* Session handle */
479 tpm_u16(0), /* Size of <nonce> */
480 /* <nonce> (if any) */
481 0, /* Attributes: Cont/Excl/Rst */
482 tpm_u16(pw_sz), /* Size of <hmac/password> */
483 /* STRING(pw) <hmac/password> (if any) */
484 };
485 unsigned int offset = 27;
486 int ret;
487
488 /*
489 * Fill the command structure starting from the first buffer:
490 * - the password (if any)
491 */
492 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
493 offset, pw, pw_sz);
494 offset += pw_sz;
495 if (ret)
496 return TPM_LIB_ERROR;
497
Simon Glassabdc7b82018-11-18 14:22:27 -0700498 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200499}
500
Simon Glassabdc7b82018-11-18 14:22:27 -0700501u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
502 const ssize_t pw_sz, unsigned int max_tries,
503 unsigned int recovery_time,
Miquel Raynalda9c3392018-05-15 11:57:18 +0200504 unsigned int lockout_recovery)
505{
506 u8 command_v2[COMMAND_BUFFER_SIZE] = {
507 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
508 tpm_u32(27 + pw_sz + 12), /* Length */
509 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
510
511 /* HANDLE */
512 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
513
514 /* AUTH_SESSION */
515 tpm_u32(9 + pw_sz), /* Authorization size */
516 tpm_u32(TPM2_RS_PW), /* Session handle */
517 tpm_u16(0), /* Size of <nonce> */
518 /* <nonce> (if any) */
519 0, /* Attributes: Cont/Excl/Rst */
520 tpm_u16(pw_sz), /* Size of <hmac/password> */
521 /* STRING(pw) <hmac/password> (if any) */
522
523 /* LOCKOUT PARAMETERS */
524 /* tpm_u32(max_tries) Max tries (0, always lock) */
525 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
526 /* tpm_u32(lockout_recovery) Lockout recovery */
527 };
528 unsigned int offset = 27;
529 int ret;
530
531 /*
532 * Fill the command structure starting from the first buffer:
533 * - the password (if any)
534 * - max tries
535 * - recovery time
536 * - lockout recovery
537 */
538 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
539 offset, pw, pw_sz,
540 offset + pw_sz, max_tries,
541 offset + pw_sz + 4, recovery_time,
542 offset + pw_sz + 8, lockout_recovery);
543 offset += pw_sz + 12;
544 if (ret)
545 return TPM_LIB_ERROR;
546
Simon Glassabdc7b82018-11-18 14:22:27 -0700547 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200548}
Miquel Raynaldc26e912018-05-15 11:57:19 +0200549
Simon Glassabdc7b82018-11-18 14:22:27 -0700550int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
551 const ssize_t newpw_sz, const char *oldpw,
552 const ssize_t oldpw_sz)
Miquel Raynaldc26e912018-05-15 11:57:19 +0200553{
554 unsigned int offset = 27;
555 u8 command_v2[COMMAND_BUFFER_SIZE] = {
556 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
557 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
558 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
559
560 /* HANDLE */
561 tpm_u32(handle), /* TPM resource handle */
562
563 /* AUTH_SESSION */
564 tpm_u32(9 + oldpw_sz), /* Authorization size */
565 tpm_u32(TPM2_RS_PW), /* Session handle */
566 tpm_u16(0), /* Size of <nonce> */
567 /* <nonce> (if any) */
568 0, /* Attributes: Cont/Excl/Rst */
569 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
570 /* STRING(oldpw) <hmac/password> (if any) */
571
572 /* TPM2B_AUTH (TPM2B_DIGEST) */
573 /* tpm_u16(newpw_sz) Digest size, new pw length */
574 /* STRING(newpw) Digest buffer, new pw */
575 };
576 int ret;
577
578 /*
579 * Fill the command structure starting from the first buffer:
580 * - the old password (if any)
581 * - size of the new password
582 * - new password
583 */
584 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
585 offset, oldpw, oldpw_sz,
586 offset + oldpw_sz, newpw_sz,
587 offset + oldpw_sz + 2, newpw, newpw_sz);
588 offset += oldpw_sz + 2 + newpw_sz;
589 if (ret)
590 return TPM_LIB_ERROR;
591
Simon Glassabdc7b82018-11-18 14:22:27 -0700592 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynaldc26e912018-05-15 11:57:19 +0200593}
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200594
Simon Glassabdc7b82018-11-18 14:22:27 -0700595u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
596 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200597{
598 u8 command_v2[COMMAND_BUFFER_SIZE] = {
599 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
600 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
601 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
602
603 /* HANDLE */
604 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
605
606 /* AUTH_SESSION */
607 tpm_u32(9 + pw_sz), /* Authorization size */
608 tpm_u32(TPM2_RS_PW), /* session handle */
609 tpm_u16(0), /* Size of <nonce> */
610 /* <nonce> (if any) */
611 0, /* Attributes: Cont/Excl/Rst */
612 tpm_u16(pw_sz) /* Size of <hmac/password> */
613 /* STRING(pw) <hmac/password> (if any) */
614
615 /* TPM2B_AUTH (TPM2B_DIGEST) */
616 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
617 /* STRING(key) Digest buffer (PCR key) */
618
619 /* TPMI_ALG_HASH */
620 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
621
622 /* TPMI_DH_PCR */
623 /* tpm_u32(index), PCR Index */
624 };
625 unsigned int offset = 27;
626 int ret;
627
628 /*
629 * Fill the command structure starting from the first buffer:
630 * - the password (if any)
631 * - the PCR key length
632 * - the PCR key
633 * - the hash algorithm
634 * - the PCR index
635 */
636 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
637 offset, pw, pw_sz,
638 offset + pw_sz, TPM2_DIGEST_LEN,
639 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
640 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
641 TPM2_ALG_SHA256,
642 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
643 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
644 if (ret)
645 return TPM_LIB_ERROR;
646
Simon Glassabdc7b82018-11-18 14:22:27 -0700647 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200648}
649
Simon Glassabdc7b82018-11-18 14:22:27 -0700650u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
651 const ssize_t pw_sz, u32 index, const char *key,
652 const ssize_t key_sz)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200653{
654 u8 command_v2[COMMAND_BUFFER_SIZE] = {
655 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
656 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
657 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
658
659 /* HANDLE */
660 tpm_u32(index), /* Handle (PCR Index) */
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 /* TPM2B_DIGEST */
672 /* tpm_u16(key_sz) Key length */
673 /* STRING(key) Key */
674 };
675 unsigned int offset = 27;
676 int ret;
677
678 /*
679 * Fill the command structure starting from the first buffer:
680 * - the password (if any)
681 * - the number of digests, 1 in our case
682 * - the algorithm, sha256 in our case
683 * - the digest (64 bytes)
684 */
685 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
686 offset, pw, pw_sz,
687 offset + pw_sz, key_sz,
688 offset + pw_sz + 2, key, key_sz);
689 offset += pw_sz + 2 + key_sz;
690 if (ret)
691 return TPM_LIB_ERROR;
692
Simon Glassabdc7b82018-11-18 14:22:27 -0700693 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200694}
Dhananjay Phadke06bea492020-06-04 16:43:59 -0700695
696u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
697{
698 const u8 command_v2[10] = {
699 tpm_u16(TPM2_ST_NO_SESSIONS),
700 tpm_u32(12),
701 tpm_u32(TPM2_CC_GET_RANDOM),
702 };
703 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
704
705 const size_t data_size_offset = 10;
706 const size_t data_offset = 12;
707 size_t response_length = sizeof(response);
708 u32 data_size;
709 u8 *out = data;
710
711 while (count > 0) {
712 u32 this_bytes = min((size_t)count,
713 sizeof(response) - data_offset);
714 u32 err;
715
716 if (pack_byte_string(buf, sizeof(buf), "sw",
717 0, command_v2, sizeof(command_v2),
718 sizeof(command_v2), this_bytes))
719 return TPM_LIB_ERROR;
720 err = tpm_sendrecv_command(dev, buf, response,
721 &response_length);
722 if (err)
723 return err;
724 if (unpack_byte_string(response, response_length, "w",
725 data_size_offset, &data_size))
726 return TPM_LIB_ERROR;
727 if (data_size > this_bytes)
728 return TPM_LIB_ERROR;
729 if (unpack_byte_string(response, response_length, "s",
730 data_offset, out, data_size))
731 return TPM_LIB_ERROR;
732
733 count -= data_size;
734 out += data_size;
735 }
736
737 return 0;
738}
Simon Glass7785bc12021-02-06 14:23:41 -0700739
740u32 tpm2_write_lock(struct udevice *dev, u32 index)
741{
742 u8 command_v2[COMMAND_BUFFER_SIZE] = {
743 /* header 10 bytes */
744 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
745 tpm_u32(10 + 8 + 13), /* Length */
746 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
747
748 /* handles 8 bytes */
749 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
750 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
751
752 /* session header 9 bytes */
753 tpm_u32(9), /* Header size */
754 tpm_u32(TPM2_RS_PW), /* Password authorisation */
755 tpm_u16(0), /* nonce_size */
756 0, /* session_attrs */
757 tpm_u16(0), /* auth_size */
758 };
759
760 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
761}
Simon Glass63af92e2021-02-06 14:23:42 -0700762
763u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
764{
765 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
766 u8 command_v2[COMMAND_BUFFER_SIZE] = {
767 /* header 10 bytes */
768 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
769 tpm_u32(10 + 4 + 13 + 5), /* Length */
770 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
771
772 /* 4 bytes */
773 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
774
775 /* session header 9 bytes */
776 tpm_u32(9), /* Header size */
777 tpm_u32(TPM2_RS_PW), /* Password authorisation */
778 tpm_u16(0), /* nonce_size */
779 0, /* session_attrs */
780 tpm_u16(0), /* auth_size */
781
782 /* payload 5 bytes */
783 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
784 0, /* 0=disable */
785 };
786 int ret;
787
788 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
789 log_info("ret=%s, %x\n", dev->name, ret);
790 if (ret)
791 return ret;
792
793 priv->plat_hier_disabled = true;
794
795 return 0;
796}
Masahisa Kojima7fc93ca2021-11-04 22:59:16 +0900797
798u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
799 u8 *recvbuf, size_t *recv_size)
800{
801 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
802}
Simon Glass4c57ec72022-08-30 21:05:37 -0600803
804u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
805 u8 *recvbuf, size_t *recv_size)
806{
807 u8 command_v2[COMMAND_BUFFER_SIZE] = {
808 /* header 10 bytes */
809 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
810 tpm_u32(10 + 2), /* Length */
811 tpm_u32(vendor_cmd), /* Command code */
812
813 tpm_u16(vendor_subcmd),
814 };
815 int ret;
816
817 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
818 log_debug("ret=%s, %x\n", dev->name, ret);
819 if (ret)
820 return ret;
821 if (*recv_size < 12)
822 return -ENODATA;
823 *recv_size -= 12;
824 memcpy(recvbuf, recvbuf + 12, *recv_size);
825
826 return 0;
827}
Simon Glass5208ed12022-08-30 21:05:38 -0600828
829u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
830 uint vendor_subcmd)
831{
832 u8 command_v2[COMMAND_BUFFER_SIZE] = {
833 /* header 10 bytes */
834 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
835 tpm_u32(10 + 2), /* Length */
836 tpm_u32(vendor_cmd), /* Command code */
837
838 tpm_u16(vendor_subcmd),
839 };
840 int ret;
841
842 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
843 log_debug("ret=%s, %x\n", dev->name, ret);
844 if (ret)
845 return ret;
846
847 return 0;
848}
Tim Harvey954b95e2024-05-25 13:00:48 -0700849
Ilias Apalodimascba3fa92024-06-23 14:48:17 +0300850bool tpm2_is_active_pcr(struct tpms_pcr_selection *selection)
851{
852 int i;
853
854 for (i = 0; i < selection->size_of_select; i++) {
855 if (selection->pcr_select[i])
856 return true;
857 }
858
859 return false;
860}
861
Tim Harvey954b95e2024-05-25 13:00:48 -0700862enum tpm2_algorithms tpm2_name_to_algorithm(const char *name)
863{
864 size_t i;
865
866 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
867 if (!strcasecmp(name, hash_algo_list[i].hash_name))
868 return hash_algo_list[i].hash_alg;
869 }
870 printf("%s: unsupported algorithm %s\n", __func__, name);
871
872 return -EINVAL;
873}
874
875const char *tpm2_algorithm_name(enum tpm2_algorithms algo)
876{
877 size_t i;
878
879 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
880 if (hash_algo_list[i].hash_alg == algo)
881 return hash_algo_list[i].hash_name;
882 }
883
884 return "";
885}
886
Ilias Apalodimase7505b32024-06-23 14:48:18 +0300887u16 tpm2_algorithm_to_len(enum tpm2_algorithms algo)
888{
889 size_t i;
890
891 for (i = 0; i < ARRAY_SIZE(hash_algo_list); ++i) {
892 if (hash_algo_list[i].hash_alg == algo)
893 return hash_algo_list[i].hash_len;
894 }
895
896 return 0;
897}
898
899bool tpm2_allow_extend(struct udevice *dev)
900{
901 struct tpml_pcr_selection pcrs;
902 size_t i;
903 int rc;
904
905 rc = tpm2_get_pcr_info(dev, &pcrs);
906 if (rc)
907 return false;
908
909 for (i = 0; i < pcrs.count; i++) {
910 if (tpm2_is_active_pcr(&pcrs.selection[i]) &&
911 !tpm2_algorithm_to_len(pcrs.selection[i].hash))
912 return false;
913 }
914
915 return true;
916}