blob: 9ab5b46df177eddf6df5491aa3bf1232a7efec77 [file] [log] [blame]
Miquel Raynalff322452018-05-15 11:57:08 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2018 Bootlin
4 * Author: Miquel Raynal <miquel.raynal@bootlin.com>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <tpm-common.h>
10#include <tpm-v2.h>
Simon Glasscd93d622020-05-10 11:40:13 -060011#include <linux/bitops.h>
Miquel Raynalff322452018-05-15 11:57:08 +020012#include "tpm-utils.h"
Miquel Raynal1922df22018-05-15 11:57:12 +020013
Simon Glassabdc7b82018-11-18 14:22:27 -070014u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
Miquel Raynal1922df22018-05-15 11:57:12 +020015{
16 const u8 command_v2[12] = {
17 tpm_u16(TPM2_ST_NO_SESSIONS),
18 tpm_u32(12),
19 tpm_u32(TPM2_CC_STARTUP),
20 tpm_u16(mode),
21 };
22 int ret;
23
24 /*
25 * Note TPM2_Startup command will return RC_SUCCESS the first time,
26 * but will return RC_INITIALIZE otherwise.
27 */
Simon Glassabdc7b82018-11-18 14:22:27 -070028 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal1922df22018-05-15 11:57:12 +020029 if (ret && ret != TPM2_RC_INITIALIZE)
30 return ret;
31
32 return 0;
33}
Miquel Raynal2dc6d972018-05-15 11:57:13 +020034
Simon Glassabdc7b82018-11-18 14:22:27 -070035u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
Miquel Raynal2dc6d972018-05-15 11:57:13 +020036{
37 const u8 command_v2[12] = {
38 tpm_u16(TPM2_ST_NO_SESSIONS),
39 tpm_u32(11),
40 tpm_u32(TPM2_CC_SELF_TEST),
41 full_test,
42 };
43
Simon Glassabdc7b82018-11-18 14:22:27 -070044 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal2dc6d972018-05-15 11:57:13 +020045}
Miquel Raynalbad8ff52018-05-15 11:57:14 +020046
Ilias Apalodimasa595be32023-01-25 12:18:36 +020047u32 tpm2_auto_start(struct udevice *dev)
48{
49 u32 rc;
50
Ilias Apalodimasa595be32023-01-25 12:18:36 +020051 rc = tpm2_self_test(dev, TPMI_YES);
52
53 if (rc == TPM2_RC_INITIALIZE) {
54 rc = tpm2_startup(dev, TPM2_SU_CLEAR);
55 if (rc)
56 return rc;
57
58 rc = tpm2_self_test(dev, TPMI_YES);
59 }
60
61 return rc;
62}
63
Simon Glassabdc7b82018-11-18 14:22:27 -070064u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
65 const ssize_t pw_sz)
Miquel Raynalbad8ff52018-05-15 11:57:14 +020066{
Simon Glass1bea7cc2021-02-06 14:23:38 -070067 /* Length of the message header, up to start of password */
68 uint offset = 27;
Miquel Raynalbad8ff52018-05-15 11:57:14 +020069 u8 command_v2[COMMAND_BUFFER_SIZE] = {
70 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass1bea7cc2021-02-06 14:23:38 -070071 tpm_u32(offset + pw_sz), /* Length */
Miquel Raynalbad8ff52018-05-15 11:57:14 +020072 tpm_u32(TPM2_CC_CLEAR), /* Command code */
73
74 /* HANDLE */
75 tpm_u32(handle), /* TPM resource handle */
76
77 /* AUTH_SESSION */
78 tpm_u32(9 + pw_sz), /* Authorization size */
79 tpm_u32(TPM2_RS_PW), /* Session handle */
80 tpm_u16(0), /* Size of <nonce> */
81 /* <nonce> (if any) */
82 0, /* Attributes: Cont/Excl/Rst */
83 tpm_u16(pw_sz), /* Size of <hmac/password> */
84 /* STRING(pw) <hmac/password> (if any) */
85 };
Miquel Raynalbad8ff52018-05-15 11:57:14 +020086 int ret;
87
88 /*
89 * Fill the command structure starting from the first buffer:
90 * - the password (if any)
91 */
92 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
93 offset, pw, pw_sz);
94 offset += pw_sz;
95 if (ret)
96 return TPM_LIB_ERROR;
97
Simon Glassabdc7b82018-11-18 14:22:27 -070098 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalbad8ff52018-05-15 11:57:14 +020099}
Miquel Raynal6284be52018-05-15 11:57:15 +0200100
Simon Glasseadcbc72021-02-06 14:23:39 -0700101u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
102 size_t space_size, u32 nv_attributes,
103 const u8 *nv_policy, size_t nv_policy_size)
104{
105 /*
106 * Calculate the offset of the nv_policy piece by adding each of the
107 * chunks below.
108 */
Simon Glass1c32eee2022-08-30 21:05:34 -0600109 const int platform_len = sizeof(u32);
110 const int session_hdr_len = 13;
111 const int message_len = 14;
112 uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
113 message_len;
Simon Glasseadcbc72021-02-06 14:23:39 -0700114 u8 command_v2[COMMAND_BUFFER_SIZE] = {
115 /* header 10 bytes */
116 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass1c32eee2022-08-30 21:05:34 -0600117 tpm_u32(offset + nv_policy_size + 2),/* Length */
Simon Glasseadcbc72021-02-06 14:23:39 -0700118 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
119
Simon Glass1c32eee2022-08-30 21:05:34 -0600120 /* handles 4 bytes */
Simon Glasseadcbc72021-02-06 14:23:39 -0700121 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
122
123 /* session header 13 bytes */
124 tpm_u32(9), /* Header size */
125 tpm_u32(TPM2_RS_PW), /* Password authorisation */
126 tpm_u16(0), /* nonce_size */
127 0, /* session_attrs */
128 tpm_u16(0), /* auth_size */
129
130 /* message 14 bytes + policy */
Simon Glass1c32eee2022-08-30 21:05:34 -0600131 tpm_u16(message_len + nv_policy_size), /* size */
Simon Glasseadcbc72021-02-06 14:23:39 -0700132 tpm_u32(space_index),
133 tpm_u16(TPM2_ALG_SHA256),
134 tpm_u32(nv_attributes),
135 tpm_u16(nv_policy_size),
Simon Glass1c32eee2022-08-30 21:05:34 -0600136 /*
137 * nv_policy
138 * space_size
139 */
Simon Glasseadcbc72021-02-06 14:23:39 -0700140 };
141 int ret;
142
143 /*
144 * Fill the command structure starting from the first buffer:
145 * - the password (if any)
146 */
Simon Glass1c32eee2022-08-30 21:05:34 -0600147 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
148 offset, nv_policy, nv_policy_size,
149 offset + nv_policy_size, space_size);
Simon Glasseadcbc72021-02-06 14:23:39 -0700150 if (ret)
151 return TPM_LIB_ERROR;
152
153 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
154}
155
Ilias Apalodimase9261362020-11-26 23:07:22 +0200156u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
157 const u8 *digest, u32 digest_len)
Miquel Raynal6284be52018-05-15 11:57:15 +0200158{
Simon Glass1bea7cc2021-02-06 14:23:38 -0700159 /* Length of the message header, up to start of digest */
160 uint offset = 33;
Miquel Raynal6284be52018-05-15 11:57:15 +0200161 u8 command_v2[COMMAND_BUFFER_SIZE] = {
162 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
Simon Glass1bea7cc2021-02-06 14:23:38 -0700163 tpm_u32(offset + digest_len), /* Length */
Miquel Raynal6284be52018-05-15 11:57:15 +0200164 tpm_u32(TPM2_CC_PCR_EXTEND), /* Command code */
165
166 /* HANDLE */
167 tpm_u32(index), /* Handle (PCR Index) */
168
169 /* AUTH_SESSION */
170 tpm_u32(9), /* Authorization size */
171 tpm_u32(TPM2_RS_PW), /* Session handle */
172 tpm_u16(0), /* Size of <nonce> */
173 /* <nonce> (if any) */
174 0, /* Attributes: Cont/Excl/Rst */
175 tpm_u16(0), /* Size of <hmac/password> */
176 /* <hmac/password> (if any) */
Simon Glass1bea7cc2021-02-06 14:23:38 -0700177
178 /* hashes */
Miquel Raynal6284be52018-05-15 11:57:15 +0200179 tpm_u32(1), /* Count (number of hashes) */
Ilias Apalodimase9261362020-11-26 23:07:22 +0200180 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal6284be52018-05-15 11:57:15 +0200181 /* STRING(digest) Digest */
182 };
Miquel Raynal6284be52018-05-15 11:57:15 +0200183 int ret;
184
Simon Glassa557d252022-08-30 21:05:32 -0600185 if (!digest)
186 return -EINVAL;
Miquel Raynal6284be52018-05-15 11:57:15 +0200187 /*
188 * Fill the command structure starting from the first buffer:
189 * - the digest
190 */
191 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
Ilias Apalodimase9261362020-11-26 23:07:22 +0200192 offset, digest, digest_len);
Miquel Raynal6284be52018-05-15 11:57:15 +0200193 if (ret)
194 return TPM_LIB_ERROR;
195
Simon Glassabdc7b82018-11-18 14:22:27 -0700196 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynal6284be52018-05-15 11:57:15 +0200197}
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200198
Simon Glass6719cbe2021-02-06 14:23:40 -0700199u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
200{
201 u8 command_v2[COMMAND_BUFFER_SIZE] = {
202 /* header 10 bytes */
203 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
204 tpm_u32(10 + 8 + 4 + 9 + 4), /* Length */
205 tpm_u32(TPM2_CC_NV_READ), /* Command code */
206
207 /* handles 8 bytes */
208 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
209 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
210
211 /* AUTH_SESSION */
212 tpm_u32(9), /* Authorization size */
213 tpm_u32(TPM2_RS_PW), /* Session handle */
214 tpm_u16(0), /* Size of <nonce> */
215 /* <nonce> (if any) */
216 0, /* Attributes: Cont/Excl/Rst */
217 tpm_u16(0), /* Size of <hmac/password> */
218 /* <hmac/password> (if any) */
219
220 tpm_u16(count), /* Number of bytes */
221 tpm_u16(0), /* Offset */
222 };
223 size_t response_len = COMMAND_BUFFER_SIZE;
224 u8 response[COMMAND_BUFFER_SIZE];
225 int ret;
226 u16 tag;
227 u32 size, code;
228
229 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
230 if (ret)
231 return log_msg_ret("read", ret);
232 if (unpack_byte_string(response, response_len, "wdds",
233 0, &tag, 2, &size, 6, &code,
234 16, data, count))
235 return TPM_LIB_ERROR;
236
237 return 0;
238}
239
240u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
241 u32 count)
242{
243 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
244 uint offset = 10 + 8 + 4 + 9 + 2;
245 uint len = offset + count + 2;
246 /* Use empty password auth if platform hierarchy is disabled */
247 u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
248 TPM2_RH_PLATFORM;
249 u8 command_v2[COMMAND_BUFFER_SIZE] = {
250 /* header 10 bytes */
251 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
252 tpm_u32(len), /* Length */
253 tpm_u32(TPM2_CC_NV_WRITE), /* Command code */
254
255 /* handles 8 bytes */
256 tpm_u32(auth), /* Primary platform seed */
257 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
258
259 /* AUTH_SESSION */
260 tpm_u32(9), /* Authorization size */
261 tpm_u32(TPM2_RS_PW), /* Session handle */
262 tpm_u16(0), /* Size of <nonce> */
263 /* <nonce> (if any) */
264 0, /* Attributes: Cont/Excl/Rst */
265 tpm_u16(0), /* Size of <hmac/password> */
266 /* <hmac/password> (if any) */
267
268 tpm_u16(count),
269 };
270 size_t response_len = COMMAND_BUFFER_SIZE;
271 u8 response[COMMAND_BUFFER_SIZE];
272 int ret;
273
274 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
275 offset, data, count,
276 offset + count, 0);
277 if (ret)
278 return TPM_LIB_ERROR;
279
280 return tpm_sendrecv_command(dev, command_v2, response, &response_len);
281}
282
Simon Glassabdc7b82018-11-18 14:22:27 -0700283u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530284 u16 algorithm, void *data, u32 digest_len,
285 unsigned int *updates)
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200286{
287 u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
288 u8 command_v2[COMMAND_BUFFER_SIZE] = {
289 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
290 tpm_u32(17 + idx_array_sz), /* Length */
291 tpm_u32(TPM2_CC_PCR_READ), /* Command code */
292
293 /* TPML_PCR_SELECTION */
294 tpm_u32(1), /* Number of selections */
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530295 tpm_u16(algorithm), /* Algorithm of the hash */
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200296 idx_array_sz, /* Array size for selection */
297 /* bitmap(idx) Selected PCR bitmap */
298 };
299 size_t response_len = COMMAND_BUFFER_SIZE;
300 u8 response[COMMAND_BUFFER_SIZE];
301 unsigned int pcr_sel_idx = idx / 8;
302 u8 pcr_sel_bit = BIT(idx % 8);
303 unsigned int counter = 0;
304 int ret;
305
306 if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
307 17 + pcr_sel_idx, pcr_sel_bit))
308 return TPM_LIB_ERROR;
309
Simon Glassabdc7b82018-11-18 14:22:27 -0700310 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200311 if (ret)
312 return ret;
313
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530314 if (digest_len > response_len)
315 return TPM_LIB_ERROR;
316
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200317 if (unpack_byte_string(response, response_len, "ds",
318 10, &counter,
Ruchika Gupta2957a1e2021-11-29 13:09:45 +0530319 response_len - digest_len, data,
320 digest_len))
Miquel Raynal1c4ea8f2018-05-15 11:57:16 +0200321 return TPM_LIB_ERROR;
322
323 if (updates)
324 *updates = counter;
325
326 return 0;
327}
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200328
Simon Glassabdc7b82018-11-18 14:22:27 -0700329u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
330 void *buf, size_t prop_count)
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200331{
332 u8 command_v2[COMMAND_BUFFER_SIZE] = {
333 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
334 tpm_u32(22), /* Length */
335 tpm_u32(TPM2_CC_GET_CAPABILITY), /* Command code */
336
337 tpm_u32(capability), /* Capability */
338 tpm_u32(property), /* Property */
339 tpm_u32(prop_count), /* Property count */
340 };
341 u8 response[COMMAND_BUFFER_SIZE];
342 size_t response_len = COMMAND_BUFFER_SIZE;
343 unsigned int properties_off;
344 int ret;
345
Simon Glassabdc7b82018-11-18 14:22:27 -0700346 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200347 if (ret)
348 return ret;
349
350 /*
351 * In the response buffer, the properties are located after the:
352 * tag (u16), response size (u32), response code (u32),
Ilias Apalodimasa322f542020-11-05 23:58:43 +0200353 * YES/NO flag (u8), TPM_CAP (u32).
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200354 */
355 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
Ilias Apalodimasa322f542020-11-05 23:58:43 +0200356 sizeof(u8) + sizeof(u32);
Miquel Raynal69cd8f02018-05-15 11:57:17 +0200357 memcpy(buf, &response[properties_off], response_len - properties_off);
358
359 return 0;
360}
Miquel Raynalda9c3392018-05-15 11:57:18 +0200361
Simon Glassabdc7b82018-11-18 14:22:27 -0700362u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
Miquel Raynalda9c3392018-05-15 11:57:18 +0200363{
364 u8 command_v2[COMMAND_BUFFER_SIZE] = {
365 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
366 tpm_u32(27 + pw_sz), /* Length */
367 tpm_u32(TPM2_CC_DAM_RESET), /* Command code */
368
369 /* HANDLE */
370 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
371
372 /* AUTH_SESSION */
373 tpm_u32(9 + pw_sz), /* Authorization size */
374 tpm_u32(TPM2_RS_PW), /* Session handle */
375 tpm_u16(0), /* Size of <nonce> */
376 /* <nonce> (if any) */
377 0, /* Attributes: Cont/Excl/Rst */
378 tpm_u16(pw_sz), /* Size of <hmac/password> */
379 /* STRING(pw) <hmac/password> (if any) */
380 };
381 unsigned int offset = 27;
382 int ret;
383
384 /*
385 * Fill the command structure starting from the first buffer:
386 * - the password (if any)
387 */
388 ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
389 offset, pw, pw_sz);
390 offset += pw_sz;
391 if (ret)
392 return TPM_LIB_ERROR;
393
Simon Glassabdc7b82018-11-18 14:22:27 -0700394 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200395}
396
Simon Glassabdc7b82018-11-18 14:22:27 -0700397u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
398 const ssize_t pw_sz, unsigned int max_tries,
399 unsigned int recovery_time,
Miquel Raynalda9c3392018-05-15 11:57:18 +0200400 unsigned int lockout_recovery)
401{
402 u8 command_v2[COMMAND_BUFFER_SIZE] = {
403 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
404 tpm_u32(27 + pw_sz + 12), /* Length */
405 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
406
407 /* HANDLE */
408 tpm_u32(TPM2_RH_LOCKOUT), /* TPM resource handle */
409
410 /* AUTH_SESSION */
411 tpm_u32(9 + pw_sz), /* Authorization size */
412 tpm_u32(TPM2_RS_PW), /* Session handle */
413 tpm_u16(0), /* Size of <nonce> */
414 /* <nonce> (if any) */
415 0, /* Attributes: Cont/Excl/Rst */
416 tpm_u16(pw_sz), /* Size of <hmac/password> */
417 /* STRING(pw) <hmac/password> (if any) */
418
419 /* LOCKOUT PARAMETERS */
420 /* tpm_u32(max_tries) Max tries (0, always lock) */
421 /* tpm_u32(recovery_time) Recovery time (0, no lock) */
422 /* tpm_u32(lockout_recovery) Lockout recovery */
423 };
424 unsigned int offset = 27;
425 int ret;
426
427 /*
428 * Fill the command structure starting from the first buffer:
429 * - the password (if any)
430 * - max tries
431 * - recovery time
432 * - lockout recovery
433 */
434 ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
435 offset, pw, pw_sz,
436 offset + pw_sz, max_tries,
437 offset + pw_sz + 4, recovery_time,
438 offset + pw_sz + 8, lockout_recovery);
439 offset += pw_sz + 12;
440 if (ret)
441 return TPM_LIB_ERROR;
442
Simon Glassabdc7b82018-11-18 14:22:27 -0700443 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalda9c3392018-05-15 11:57:18 +0200444}
Miquel Raynaldc26e912018-05-15 11:57:19 +0200445
Simon Glassabdc7b82018-11-18 14:22:27 -0700446int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
447 const ssize_t newpw_sz, const char *oldpw,
448 const ssize_t oldpw_sz)
Miquel Raynaldc26e912018-05-15 11:57:19 +0200449{
450 unsigned int offset = 27;
451 u8 command_v2[COMMAND_BUFFER_SIZE] = {
452 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
453 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
454 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
455
456 /* HANDLE */
457 tpm_u32(handle), /* TPM resource handle */
458
459 /* AUTH_SESSION */
460 tpm_u32(9 + oldpw_sz), /* Authorization size */
461 tpm_u32(TPM2_RS_PW), /* Session handle */
462 tpm_u16(0), /* Size of <nonce> */
463 /* <nonce> (if any) */
464 0, /* Attributes: Cont/Excl/Rst */
465 tpm_u16(oldpw_sz) /* Size of <hmac/password> */
466 /* STRING(oldpw) <hmac/password> (if any) */
467
468 /* TPM2B_AUTH (TPM2B_DIGEST) */
469 /* tpm_u16(newpw_sz) Digest size, new pw length */
470 /* STRING(newpw) Digest buffer, new pw */
471 };
472 int ret;
473
474 /*
475 * Fill the command structure starting from the first buffer:
476 * - the old password (if any)
477 * - size of the new password
478 * - new password
479 */
480 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
481 offset, oldpw, oldpw_sz,
482 offset + oldpw_sz, newpw_sz,
483 offset + oldpw_sz + 2, newpw, newpw_sz);
484 offset += oldpw_sz + 2 + newpw_sz;
485 if (ret)
486 return TPM_LIB_ERROR;
487
Simon Glassabdc7b82018-11-18 14:22:27 -0700488 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynaldc26e912018-05-15 11:57:19 +0200489}
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200490
Simon Glassabdc7b82018-11-18 14:22:27 -0700491u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
492 const ssize_t pw_sz, u32 index, const char *key)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200493{
494 u8 command_v2[COMMAND_BUFFER_SIZE] = {
495 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
496 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
497 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
498
499 /* HANDLE */
500 tpm_u32(TPM2_RH_PLATFORM), /* TPM resource handle */
501
502 /* AUTH_SESSION */
503 tpm_u32(9 + pw_sz), /* Authorization size */
504 tpm_u32(TPM2_RS_PW), /* session handle */
505 tpm_u16(0), /* Size of <nonce> */
506 /* <nonce> (if any) */
507 0, /* Attributes: Cont/Excl/Rst */
508 tpm_u16(pw_sz) /* Size of <hmac/password> */
509 /* STRING(pw) <hmac/password> (if any) */
510
511 /* TPM2B_AUTH (TPM2B_DIGEST) */
512 /* tpm_u16(TPM2_DIGEST_LEN) Digest size length */
513 /* STRING(key) Digest buffer (PCR key) */
514
515 /* TPMI_ALG_HASH */
516 /* tpm_u16(TPM2_ALG_SHA256) Algorithm of the hash */
517
518 /* TPMI_DH_PCR */
519 /* tpm_u32(index), PCR Index */
520 };
521 unsigned int offset = 27;
522 int ret;
523
524 /*
525 * Fill the command structure starting from the first buffer:
526 * - the password (if any)
527 * - the PCR key length
528 * - the PCR key
529 * - the hash algorithm
530 * - the PCR index
531 */
532 ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
533 offset, pw, pw_sz,
534 offset + pw_sz, TPM2_DIGEST_LEN,
535 offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
536 offset + pw_sz + 2 + TPM2_DIGEST_LEN,
537 TPM2_ALG_SHA256,
538 offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
539 offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
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 Raynalb9dd4fab2018-05-15 11:57:20 +0200544}
545
Simon Glassabdc7b82018-11-18 14:22:27 -0700546u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
547 const ssize_t pw_sz, u32 index, const char *key,
548 const ssize_t key_sz)
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200549{
550 u8 command_v2[COMMAND_BUFFER_SIZE] = {
551 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
552 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
553 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
554
555 /* HANDLE */
556 tpm_u32(index), /* Handle (PCR Index) */
557
558 /* AUTH_SESSION */
559 tpm_u32(9 + pw_sz), /* Authorization size */
560 tpm_u32(TPM2_RS_PW), /* session handle */
561 tpm_u16(0), /* Size of <nonce> */
562 /* <nonce> (if any) */
563 0, /* Attributes: Cont/Excl/Rst */
564 tpm_u16(pw_sz), /* Size of <hmac/password> */
565 /* STRING(pw) <hmac/password> (if any) */
566
567 /* TPM2B_DIGEST */
568 /* tpm_u16(key_sz) Key length */
569 /* STRING(key) Key */
570 };
571 unsigned int offset = 27;
572 int ret;
573
574 /*
575 * Fill the command structure starting from the first buffer:
576 * - the password (if any)
577 * - the number of digests, 1 in our case
578 * - the algorithm, sha256 in our case
579 * - the digest (64 bytes)
580 */
581 ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
582 offset, pw, pw_sz,
583 offset + pw_sz, key_sz,
584 offset + pw_sz + 2, key, key_sz);
585 offset += pw_sz + 2 + key_sz;
586 if (ret)
587 return TPM_LIB_ERROR;
588
Simon Glassabdc7b82018-11-18 14:22:27 -0700589 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
Miquel Raynalb9dd4fab2018-05-15 11:57:20 +0200590}
Dhananjay Phadke06bea492020-06-04 16:43:59 -0700591
592u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
593{
594 const u8 command_v2[10] = {
595 tpm_u16(TPM2_ST_NO_SESSIONS),
596 tpm_u32(12),
597 tpm_u32(TPM2_CC_GET_RANDOM),
598 };
599 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
600
601 const size_t data_size_offset = 10;
602 const size_t data_offset = 12;
603 size_t response_length = sizeof(response);
604 u32 data_size;
605 u8 *out = data;
606
607 while (count > 0) {
608 u32 this_bytes = min((size_t)count,
609 sizeof(response) - data_offset);
610 u32 err;
611
612 if (pack_byte_string(buf, sizeof(buf), "sw",
613 0, command_v2, sizeof(command_v2),
614 sizeof(command_v2), this_bytes))
615 return TPM_LIB_ERROR;
616 err = tpm_sendrecv_command(dev, buf, response,
617 &response_length);
618 if (err)
619 return err;
620 if (unpack_byte_string(response, response_length, "w",
621 data_size_offset, &data_size))
622 return TPM_LIB_ERROR;
623 if (data_size > this_bytes)
624 return TPM_LIB_ERROR;
625 if (unpack_byte_string(response, response_length, "s",
626 data_offset, out, data_size))
627 return TPM_LIB_ERROR;
628
629 count -= data_size;
630 out += data_size;
631 }
632
633 return 0;
634}
Simon Glass7785bc12021-02-06 14:23:41 -0700635
636u32 tpm2_write_lock(struct udevice *dev, u32 index)
637{
638 u8 command_v2[COMMAND_BUFFER_SIZE] = {
639 /* header 10 bytes */
640 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
641 tpm_u32(10 + 8 + 13), /* Length */
642 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
643
644 /* handles 8 bytes */
645 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
646 tpm_u32(HR_NV_INDEX + index), /* Password authorisation */
647
648 /* session header 9 bytes */
649 tpm_u32(9), /* Header size */
650 tpm_u32(TPM2_RS_PW), /* Password authorisation */
651 tpm_u16(0), /* nonce_size */
652 0, /* session_attrs */
653 tpm_u16(0), /* auth_size */
654 };
655
656 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
657}
Simon Glass63af92e2021-02-06 14:23:42 -0700658
659u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
660{
661 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
662 u8 command_v2[COMMAND_BUFFER_SIZE] = {
663 /* header 10 bytes */
664 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
665 tpm_u32(10 + 4 + 13 + 5), /* Length */
666 tpm_u32(TPM2_CC_HIER_CONTROL), /* Command code */
667
668 /* 4 bytes */
669 tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */
670
671 /* session header 9 bytes */
672 tpm_u32(9), /* Header size */
673 tpm_u32(TPM2_RS_PW), /* Password authorisation */
674 tpm_u16(0), /* nonce_size */
675 0, /* session_attrs */
676 tpm_u16(0), /* auth_size */
677
678 /* payload 5 bytes */
679 tpm_u32(TPM2_RH_PLATFORM), /* Hierarchy to disable */
680 0, /* 0=disable */
681 };
682 int ret;
683
684 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
685 log_info("ret=%s, %x\n", dev->name, ret);
686 if (ret)
687 return ret;
688
689 priv->plat_hier_disabled = true;
690
691 return 0;
692}
Masahisa Kojima7fc93ca2021-11-04 22:59:16 +0900693
694u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
695 u8 *recvbuf, size_t *recv_size)
696{
697 return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
698}
Simon Glass4c57ec72022-08-30 21:05:37 -0600699
700u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd,
701 u8 *recvbuf, size_t *recv_size)
702{
703 u8 command_v2[COMMAND_BUFFER_SIZE] = {
704 /* header 10 bytes */
705 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
706 tpm_u32(10 + 2), /* Length */
707 tpm_u32(vendor_cmd), /* Command code */
708
709 tpm_u16(vendor_subcmd),
710 };
711 int ret;
712
713 ret = tpm_sendrecv_command(dev, command_v2, recvbuf, recv_size);
714 log_debug("ret=%s, %x\n", dev->name, ret);
715 if (ret)
716 return ret;
717 if (*recv_size < 12)
718 return -ENODATA;
719 *recv_size -= 12;
720 memcpy(recvbuf, recvbuf + 12, *recv_size);
721
722 return 0;
723}
Simon Glass5208ed12022-08-30 21:05:38 -0600724
725u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd,
726 uint vendor_subcmd)
727{
728 u8 command_v2[COMMAND_BUFFER_SIZE] = {
729 /* header 10 bytes */
730 tpm_u16(TPM2_ST_NO_SESSIONS), /* TAG */
731 tpm_u32(10 + 2), /* Length */
732 tpm_u32(vendor_cmd), /* Command code */
733
734 tpm_u16(vendor_subcmd),
735 };
736 int ret;
737
738 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
739 log_debug("ret=%s, %x\n", dev->name, ret);
740 if (ret)
741 return ret;
742
743 return 0;
744}