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