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_clear(struct udevice * dev,u32 handle,const char * pw,const ssize_t pw_sz)47 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
48 	       const ssize_t pw_sz)
49 {
50 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
51 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
52 		tpm_u32(27 + pw_sz),		/* Length */
53 		tpm_u32(TPM2_CC_CLEAR),		/* Command code */
54 
55 		/* HANDLE */
56 		tpm_u32(handle),		/* TPM resource handle */
57 
58 		/* AUTH_SESSION */
59 		tpm_u32(9 + pw_sz),		/* Authorization size */
60 		tpm_u32(TPM2_RS_PW),		/* Session handle */
61 		tpm_u16(0),			/* Size of <nonce> */
62 						/* <nonce> (if any) */
63 		0,				/* Attributes: Cont/Excl/Rst */
64 		tpm_u16(pw_sz),			/* Size of <hmac/password> */
65 		/* STRING(pw)			   <hmac/password> (if any) */
66 	};
67 	unsigned int offset = 27;
68 	int ret;
69 
70 	/*
71 	 * Fill the command structure starting from the first buffer:
72 	 *     - the password (if any)
73 	 */
74 	ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
75 			       offset, pw, pw_sz);
76 	offset += pw_sz;
77 	if (ret)
78 		return TPM_LIB_ERROR;
79 
80 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
81 }
82 
tpm2_pcr_extend(struct udevice * dev,u32 index,u32 algorithm,const u8 * digest,u32 digest_len)83 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
84 		    const u8 *digest, u32 digest_len)
85 {
86 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
87 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
88 		tpm_u32(33 + digest_len),	/* Length */
89 		tpm_u32(TPM2_CC_PCR_EXTEND),	/* Command code */
90 
91 		/* HANDLE */
92 		tpm_u32(index),			/* Handle (PCR Index) */
93 
94 		/* AUTH_SESSION */
95 		tpm_u32(9),			/* Authorization size */
96 		tpm_u32(TPM2_RS_PW),		/* Session handle */
97 		tpm_u16(0),			/* Size of <nonce> */
98 						/* <nonce> (if any) */
99 		0,				/* Attributes: Cont/Excl/Rst */
100 		tpm_u16(0),			/* Size of <hmac/password> */
101 						/* <hmac/password> (if any) */
102 		tpm_u32(1),			/* Count (number of hashes) */
103 		tpm_u16(algorithm),	/* Algorithm of the hash */
104 		/* STRING(digest)		   Digest */
105 	};
106 	unsigned int offset = 33;
107 	int ret;
108 
109 	/*
110 	 * Fill the command structure starting from the first buffer:
111 	 *     - the digest
112 	 */
113 	ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
114 			       offset, digest, digest_len);
115 	offset += digest_len;
116 	if (ret)
117 		return TPM_LIB_ERROR;
118 
119 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
120 }
121 
tpm2_pcr_read(struct udevice * dev,u32 idx,unsigned int idx_min_sz,void * data,unsigned int * updates)122 u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
123 		  void *data, unsigned int *updates)
124 {
125 	u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
126 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
127 		tpm_u16(TPM2_ST_NO_SESSIONS),	/* TAG */
128 		tpm_u32(17 + idx_array_sz),	/* Length */
129 		tpm_u32(TPM2_CC_PCR_READ),	/* Command code */
130 
131 		/* TPML_PCR_SELECTION */
132 		tpm_u32(1),			/* Number of selections */
133 		tpm_u16(TPM2_ALG_SHA256),	/* Algorithm of the hash */
134 		idx_array_sz,			/* Array size for selection */
135 		/* bitmap(idx)			   Selected PCR bitmap */
136 	};
137 	size_t response_len = COMMAND_BUFFER_SIZE;
138 	u8 response[COMMAND_BUFFER_SIZE];
139 	unsigned int pcr_sel_idx = idx / 8;
140 	u8 pcr_sel_bit = BIT(idx % 8);
141 	unsigned int counter = 0;
142 	int ret;
143 
144 	if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
145 			     17 + pcr_sel_idx, pcr_sel_bit))
146 		return TPM_LIB_ERROR;
147 
148 	ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
149 	if (ret)
150 		return ret;
151 
152 	if (unpack_byte_string(response, response_len, "ds",
153 			       10, &counter,
154 			       response_len - TPM2_DIGEST_LEN, data,
155 			       TPM2_DIGEST_LEN))
156 		return TPM_LIB_ERROR;
157 
158 	if (updates)
159 		*updates = counter;
160 
161 	return 0;
162 }
163 
tpm2_get_capability(struct udevice * dev,u32 capability,u32 property,void * buf,size_t prop_count)164 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
165 			void *buf, size_t prop_count)
166 {
167 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
168 		tpm_u16(TPM2_ST_NO_SESSIONS),		/* TAG */
169 		tpm_u32(22),				/* Length */
170 		tpm_u32(TPM2_CC_GET_CAPABILITY),	/* Command code */
171 
172 		tpm_u32(capability),			/* Capability */
173 		tpm_u32(property),			/* Property */
174 		tpm_u32(prop_count),			/* Property count */
175 	};
176 	u8 response[COMMAND_BUFFER_SIZE];
177 	size_t response_len = COMMAND_BUFFER_SIZE;
178 	unsigned int properties_off;
179 	int ret;
180 
181 	ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
182 	if (ret)
183 		return ret;
184 
185 	/*
186 	 * In the response buffer, the properties are located after the:
187 	 * tag (u16), response size (u32), response code (u32),
188 	 * YES/NO flag (u8), TPM_CAP (u32).
189 	 */
190 	properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
191 			 sizeof(u8) + sizeof(u32);
192 	memcpy(buf, &response[properties_off], response_len - properties_off);
193 
194 	return 0;
195 }
196 
tpm2_dam_reset(struct udevice * dev,const char * pw,const ssize_t pw_sz)197 u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
198 {
199 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
200 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
201 		tpm_u32(27 + pw_sz),		/* Length */
202 		tpm_u32(TPM2_CC_DAM_RESET),	/* Command code */
203 
204 		/* HANDLE */
205 		tpm_u32(TPM2_RH_LOCKOUT),	/* TPM resource handle */
206 
207 		/* AUTH_SESSION */
208 		tpm_u32(9 + pw_sz),		/* Authorization size */
209 		tpm_u32(TPM2_RS_PW),		/* Session handle */
210 		tpm_u16(0),			/* Size of <nonce> */
211 						/* <nonce> (if any) */
212 		0,				/* Attributes: Cont/Excl/Rst */
213 		tpm_u16(pw_sz),			/* Size of <hmac/password> */
214 		/* STRING(pw)			   <hmac/password> (if any) */
215 	};
216 	unsigned int offset = 27;
217 	int ret;
218 
219 	/*
220 	 * Fill the command structure starting from the first buffer:
221 	 *     - the password (if any)
222 	 */
223 	ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
224 			       offset, pw, pw_sz);
225 	offset += pw_sz;
226 	if (ret)
227 		return TPM_LIB_ERROR;
228 
229 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
230 }
231 
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)232 u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
233 			const ssize_t pw_sz, unsigned int max_tries,
234 			unsigned int recovery_time,
235 			unsigned int lockout_recovery)
236 {
237 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
238 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
239 		tpm_u32(27 + pw_sz + 12),	/* Length */
240 		tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
241 
242 		/* HANDLE */
243 		tpm_u32(TPM2_RH_LOCKOUT),	/* TPM resource handle */
244 
245 		/* AUTH_SESSION */
246 		tpm_u32(9 + pw_sz),		/* Authorization size */
247 		tpm_u32(TPM2_RS_PW),		/* Session handle */
248 		tpm_u16(0),			/* Size of <nonce> */
249 						/* <nonce> (if any) */
250 		0,				/* Attributes: Cont/Excl/Rst */
251 		tpm_u16(pw_sz),			/* Size of <hmac/password> */
252 		/* STRING(pw)			   <hmac/password> (if any) */
253 
254 		/* LOCKOUT PARAMETERS */
255 		/* tpm_u32(max_tries)		   Max tries (0, always lock) */
256 		/* tpm_u32(recovery_time)	   Recovery time (0, no lock) */
257 		/* tpm_u32(lockout_recovery)	   Lockout recovery */
258 	};
259 	unsigned int offset = 27;
260 	int ret;
261 
262 	/*
263 	 * Fill the command structure starting from the first buffer:
264 	 *     - the password (if any)
265 	 *     - max tries
266 	 *     - recovery time
267 	 *     - lockout recovery
268 	 */
269 	ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
270 			       offset, pw, pw_sz,
271 			       offset + pw_sz, max_tries,
272 			       offset + pw_sz + 4, recovery_time,
273 			       offset + pw_sz + 8, lockout_recovery);
274 	offset += pw_sz + 12;
275 	if (ret)
276 		return TPM_LIB_ERROR;
277 
278 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
279 }
280 
tpm2_change_auth(struct udevice * dev,u32 handle,const char * newpw,const ssize_t newpw_sz,const char * oldpw,const ssize_t oldpw_sz)281 int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
282 		     const ssize_t newpw_sz, const char *oldpw,
283 		     const ssize_t oldpw_sz)
284 {
285 	unsigned int offset = 27;
286 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
287 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
288 		tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
289 		tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
290 
291 		/* HANDLE */
292 		tpm_u32(handle),		/* TPM resource handle */
293 
294 		/* AUTH_SESSION */
295 		tpm_u32(9 + oldpw_sz),		/* Authorization size */
296 		tpm_u32(TPM2_RS_PW),		/* Session handle */
297 		tpm_u16(0),			/* Size of <nonce> */
298 						/* <nonce> (if any) */
299 		0,				/* Attributes: Cont/Excl/Rst */
300 		tpm_u16(oldpw_sz)		/* Size of <hmac/password> */
301 		/* STRING(oldpw)		   <hmac/password> (if any) */
302 
303 		/* TPM2B_AUTH (TPM2B_DIGEST) */
304 		/* tpm_u16(newpw_sz)		   Digest size, new pw length */
305 		/* STRING(newpw)		   Digest buffer, new pw */
306 	};
307 	int ret;
308 
309 	/*
310 	 * Fill the command structure starting from the first buffer:
311 	 *     - the old password (if any)
312 	 *     - size of the new password
313 	 *     - new password
314 	 */
315 	ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
316 			       offset, oldpw, oldpw_sz,
317 			       offset + oldpw_sz, newpw_sz,
318 			       offset + oldpw_sz + 2, newpw, newpw_sz);
319 	offset += oldpw_sz + 2 + newpw_sz;
320 	if (ret)
321 		return TPM_LIB_ERROR;
322 
323 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
324 }
325 
tpm2_pcr_setauthpolicy(struct udevice * dev,const char * pw,const ssize_t pw_sz,u32 index,const char * key)326 u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
327 			   const ssize_t pw_sz, u32 index, const char *key)
328 {
329 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
330 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
331 		tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
332 		tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
333 
334 		/* HANDLE */
335 		tpm_u32(TPM2_RH_PLATFORM),	/* TPM resource handle */
336 
337 		/* AUTH_SESSION */
338 		tpm_u32(9 + pw_sz),		/* Authorization size */
339 		tpm_u32(TPM2_RS_PW),		/* session handle */
340 		tpm_u16(0),			/* Size of <nonce> */
341 						/* <nonce> (if any) */
342 		0,				/* Attributes: Cont/Excl/Rst */
343 		tpm_u16(pw_sz)			/* Size of <hmac/password> */
344 		/* STRING(pw)			   <hmac/password> (if any) */
345 
346 		/* TPM2B_AUTH (TPM2B_DIGEST) */
347 		/* tpm_u16(TPM2_DIGEST_LEN)	   Digest size length */
348 		/* STRING(key)			   Digest buffer (PCR key) */
349 
350 		/* TPMI_ALG_HASH */
351 		/* tpm_u16(TPM2_ALG_SHA256)   Algorithm of the hash */
352 
353 		/* TPMI_DH_PCR */
354 		/* tpm_u32(index),		   PCR Index */
355 	};
356 	unsigned int offset = 27;
357 	int ret;
358 
359 	/*
360 	 * Fill the command structure starting from the first buffer:
361 	 *     - the password (if any)
362 	 *     - the PCR key length
363 	 *     - the PCR key
364 	 *     - the hash algorithm
365 	 *     - the PCR index
366 	 */
367 	ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
368 			       offset, pw, pw_sz,
369 			       offset + pw_sz, TPM2_DIGEST_LEN,
370 			       offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
371 			       offset + pw_sz + 2 + TPM2_DIGEST_LEN,
372 			       TPM2_ALG_SHA256,
373 			       offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
374 	offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
375 	if (ret)
376 		return TPM_LIB_ERROR;
377 
378 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
379 }
380 
tpm2_pcr_setauthvalue(struct udevice * dev,const char * pw,const ssize_t pw_sz,u32 index,const char * key,const ssize_t key_sz)381 u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
382 			  const ssize_t pw_sz, u32 index, const char *key,
383 			  const ssize_t key_sz)
384 {
385 	u8 command_v2[COMMAND_BUFFER_SIZE] = {
386 		tpm_u16(TPM2_ST_SESSIONS),	/* TAG */
387 		tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
388 		tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
389 
390 		/* HANDLE */
391 		tpm_u32(index),			/* Handle (PCR Index) */
392 
393 		/* AUTH_SESSION */
394 		tpm_u32(9 + pw_sz),		/* Authorization size */
395 		tpm_u32(TPM2_RS_PW),		/* session handle */
396 		tpm_u16(0),			/* Size of <nonce> */
397 						/* <nonce> (if any) */
398 		0,				/* Attributes: Cont/Excl/Rst */
399 		tpm_u16(pw_sz),			/* Size of <hmac/password> */
400 		/* STRING(pw)			   <hmac/password> (if any) */
401 
402 		/* TPM2B_DIGEST */
403 		/* tpm_u16(key_sz)		   Key length */
404 		/* STRING(key)			   Key */
405 	};
406 	unsigned int offset = 27;
407 	int ret;
408 
409 	/*
410 	 * Fill the command structure starting from the first buffer:
411 	 *     - the password (if any)
412 	 *     - the number of digests, 1 in our case
413 	 *     - the algorithm, sha256 in our case
414 	 *     - the digest (64 bytes)
415 	 */
416 	ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
417 			       offset, pw, pw_sz,
418 			       offset + pw_sz, key_sz,
419 			       offset + pw_sz + 2, key, key_sz);
420 	offset += pw_sz + 2 + key_sz;
421 	if (ret)
422 		return TPM_LIB_ERROR;
423 
424 	return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
425 }
426 
tpm2_get_random(struct udevice * dev,void * data,u32 count)427 u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
428 {
429 	const u8 command_v2[10] = {
430 		tpm_u16(TPM2_ST_NO_SESSIONS),
431 		tpm_u32(12),
432 		tpm_u32(TPM2_CC_GET_RANDOM),
433 	};
434 	u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
435 
436 	const size_t data_size_offset = 10;
437 	const size_t data_offset = 12;
438 	size_t response_length = sizeof(response);
439 	u32 data_size;
440 	u8 *out = data;
441 
442 	while (count > 0) {
443 		u32 this_bytes = min((size_t)count,
444 				     sizeof(response) - data_offset);
445 		u32 err;
446 
447 		if (pack_byte_string(buf, sizeof(buf), "sw",
448 				     0, command_v2, sizeof(command_v2),
449 				     sizeof(command_v2), this_bytes))
450 			return TPM_LIB_ERROR;
451 		err = tpm_sendrecv_command(dev, buf, response,
452 					   &response_length);
453 		if (err)
454 			return err;
455 		if (unpack_byte_string(response, response_length, "w",
456 				       data_size_offset, &data_size))
457 			return TPM_LIB_ERROR;
458 		if (data_size > this_bytes)
459 			return TPM_LIB_ERROR;
460 		if (unpack_byte_string(response, response_length, "s",
461 				       data_offset, out, data_size))
462 			return TPM_LIB_ERROR;
463 
464 		count -= data_size;
465 		out += data_size;
466 	}
467 
468 	return 0;
469 }
470