1 // 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>
11 #include <linux/bitops.h>
12 #include "tpm-utils.h"
13
tpm2_startup(struct udevice * dev,enum tpm2_startup_types mode)14 u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
15 {
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 */
28 ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
29 if (ret && ret != TPM2_RC_INITIALIZE)
30 return ret;
31
32 return 0;
33 }
34
tpm2_self_test(struct udevice * dev,enum tpm2_yes_no full_test)35 u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
36 {
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
44 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
45 }
46
tpm2_auto_start(struct udevice * dev)47 u32 tpm2_auto_start(struct udevice *dev)
48 {
49 u32 rc;
50
51 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
tpm2_clear(struct udevice * dev,u32 handle,const char * pw,const ssize_t pw_sz)64 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
65 const ssize_t pw_sz)
66 {
67 /* Length of the message header, up to start of password */
68 uint offset = 27;
69 u8 command_v2[COMMAND_BUFFER_SIZE] = {
70 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
71 tpm_u32(offset + pw_sz), /* Length */
72 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 };
86 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
98 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
99 }
100
tpm2_nv_define_space(struct udevice * dev,u32 space_index,size_t space_size,u32 nv_attributes,const u8 * nv_policy,size_t nv_policy_size)101 u32 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 */
109 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;
114 u8 command_v2[COMMAND_BUFFER_SIZE] = {
115 /* header 10 bytes */
116 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
117 tpm_u32(offset + nv_policy_size + 2),/* Length */
118 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
119
120 /* handles 4 bytes */
121 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 */
131 tpm_u16(message_len + nv_policy_size), /* size */
132 tpm_u32(space_index),
133 tpm_u16(TPM2_ALG_SHA256),
134 tpm_u32(nv_attributes),
135 tpm_u16(nv_policy_size),
136 /*
137 * nv_policy
138 * space_size
139 */
140 };
141 int ret;
142
143 /*
144 * Fill the command structure starting from the first buffer:
145 * - the password (if any)
146 */
147 ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
148 offset, nv_policy, nv_policy_size,
149 offset + nv_policy_size, space_size);
150 if (ret)
151 return TPM_LIB_ERROR;
152
153 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
154 }
155
tpm2_pcr_extend(struct udevice * dev,u32 index,u32 algorithm,const u8 * digest,u32 digest_len)156 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
157 const u8 *digest, u32 digest_len)
158 {
159 /* Length of the message header, up to start of digest */
160 uint offset = 33;
161 u8 command_v2[COMMAND_BUFFER_SIZE] = {
162 tpm_u16(TPM2_ST_SESSIONS), /* TAG */
163 tpm_u32(offset + digest_len), /* Length */
164 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) */
177
178 /* hashes */
179 tpm_u32(1), /* Count (number of hashes) */
180 tpm_u16(algorithm), /* Algorithm of the hash */
181 /* STRING(digest) Digest */
182 };
183 int ret;
184
185 if (!digest)
186 return -EINVAL;
187 /*
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",
192 offset, digest, digest_len);
193 if (ret)
194 return TPM_LIB_ERROR;
195
196 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
197 }
198
tpm2_nv_read_value(struct udevice * dev,u32 index,void * data,u32 count)199 u32 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
tpm2_nv_write_value(struct udevice * dev,u32 index,const void * data,u32 count)240 u32 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
tpm2_pcr_read(struct udevice * dev,u32 idx,unsigned int idx_min_sz,u16 algorithm,void * data,u32 digest_len,unsigned int * updates)283 u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
284 u16 algorithm, void *data, u32 digest_len,
285 unsigned int *updates)
286 {
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 */
295 tpm_u16(algorithm), /* Algorithm of the hash */
296 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
310 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
311 if (ret)
312 return ret;
313
314 if (digest_len > response_len)
315 return TPM_LIB_ERROR;
316
317 if (unpack_byte_string(response, response_len, "ds",
318 10, &counter,
319 response_len - digest_len, data,
320 digest_len))
321 return TPM_LIB_ERROR;
322
323 if (updates)
324 *updates = counter;
325
326 return 0;
327 }
328
tpm2_get_capability(struct udevice * dev,u32 capability,u32 property,void * buf,size_t prop_count)329 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
330 void *buf, size_t prop_count)
331 {
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
346 ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
347 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),
353 * YES/NO flag (u8), TPM_CAP (u32).
354 */
355 properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
356 sizeof(u8) + sizeof(u32);
357 memcpy(buf, &response[properties_off], response_len - properties_off);
358
359 return 0;
360 }
361
tpm2_dam_reset(struct udevice * dev,const char * pw,const ssize_t pw_sz)362 u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
363 {
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
394 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
395 }
396
tpm2_dam_parameters(struct udevice * dev,const char * pw,const ssize_t pw_sz,unsigned int max_tries,unsigned int recovery_time,unsigned int lockout_recovery)397 u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
398 const ssize_t pw_sz, unsigned int max_tries,
399 unsigned int recovery_time,
400 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
443 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
444 }
445
tpm2_change_auth(struct udevice * dev,u32 handle,const char * newpw,const ssize_t newpw_sz,const char * oldpw,const ssize_t oldpw_sz)446 int 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)
449 {
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
488 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
489 }
490
tpm2_pcr_setauthpolicy(struct udevice * dev,const char * pw,const ssize_t pw_sz,u32 index,const char * key)491 u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
492 const ssize_t pw_sz, u32 index, const char *key)
493 {
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
543 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
544 }
545
tpm2_pcr_setauthvalue(struct udevice * dev,const char * pw,const ssize_t pw_sz,u32 index,const char * key,const ssize_t key_sz)546 u32 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)
549 {
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
589 return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
590 }
591
tpm2_get_random(struct udevice * dev,void * data,u32 count)592 u32 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 }
635
tpm2_write_lock(struct udevice * dev,u32 index)636 u32 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 }
658
tpm2_disable_platform_hierarchy(struct udevice * dev)659 u32 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 }
693
tpm2_submit_command(struct udevice * dev,const u8 * sendbuf,u8 * recvbuf,size_t * recv_size)694 u32 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 }
699
tpm2_report_state(struct udevice * dev,uint vendor_cmd,uint vendor_subcmd,u8 * recvbuf,size_t * recv_size)700 u32 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 }
724
tpm2_enable_nvcommits(struct udevice * dev,uint vendor_cmd,uint vendor_subcmd)725 u32 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 }
745