xref: /rk3399_rockchip-uboot/lib/tpm.c (revision f3488bb39d0ffe274cefdc7c42e3e63a636d9cd6)
1 /*
2  * Copyright (c) 2013 The Chromium OS Authors.
3  * Coypright (c) 2013 Guntermann & Drunck GmbH
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <dm.h>
10 #include <tis.h>
11 #include <tpm.h>
12 #include <asm/unaligned.h>
13 #include <u-boot/sha1.h>
14 
15 /* Internal error of TPM command library */
16 #define TPM_LIB_ERROR	((uint32_t)~0u)
17 
18 /* Useful constants */
19 enum {
20 	COMMAND_BUFFER_SIZE		= 256,
21 	TPM_REQUEST_HEADER_LENGTH	= 10,
22 	TPM_RESPONSE_HEADER_LENGTH	= 10,
23 	PCR_DIGEST_LENGTH		= 20,
24 	DIGEST_LENGTH			= 20,
25 	TPM_REQUEST_AUTH_LENGTH		= 45,
26 	TPM_RESPONSE_AUTH_LENGTH	= 41,
27 	/* some max lengths, valid for RSA keys <= 2048 bits */
28 	TPM_KEY12_MAX_LENGTH		= 618,
29 	TPM_PUBKEY_MAX_LENGTH		= 288,
30 };
31 
32 #ifdef CONFIG_TPM_AUTH_SESSIONS
33 
34 #ifndef CONFIG_SHA1
35 #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
36 #endif /* !CONFIG_SHA1 */
37 
38 struct session_data {
39 	int		valid;
40 	uint32_t	handle;
41 	uint8_t		nonce_even[DIGEST_LENGTH];
42 	uint8_t		nonce_odd[DIGEST_LENGTH];
43 };
44 
45 static struct session_data oiap_session = {0, };
46 
47 #endif /* CONFIG_TPM_AUTH_SESSIONS */
48 
49 /**
50  * Pack data into a byte string.  The data types are specified in
51  * the format string: 'b' means unsigned byte, 'w' unsigned word,
52  * 'd' unsigned double word, and 's' byte string.  The data are a
53  * series of offsets and values (for type byte string there are also
54  * lengths).  The data values are packed into the byte string
55  * sequentially, and so a latter value could over-write a former
56  * value.
57  *
58  * @param str		output string
59  * @param size		size of output string
60  * @param format	format string
61  * @param ...		data points
62  * @return 0 on success, non-0 on error
63  */
64 int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
65 {
66 	va_list args;
67 	size_t offset = 0, length = 0;
68 	uint8_t *data = NULL;
69 	uint32_t value = 0;
70 
71 	va_start(args, format);
72 	for (; *format; format++) {
73 		switch (*format) {
74 		case 'b':
75 			offset = va_arg(args, size_t);
76 			value = va_arg(args, int);
77 			length = 1;
78 			break;
79 		case 'w':
80 			offset = va_arg(args, size_t);
81 			value = va_arg(args, int);
82 			length = 2;
83 			break;
84 		case 'd':
85 			offset = va_arg(args, size_t);
86 			value = va_arg(args, uint32_t);
87 			length = 4;
88 			break;
89 		case 's':
90 			offset = va_arg(args, size_t);
91 			data = va_arg(args, uint8_t *);
92 			length = va_arg(args, uint32_t);
93 			break;
94 		default:
95 			debug("Couldn't recognize format string\n");
96 			return -1;
97 		}
98 
99 		if (offset + length > size)
100 			return -1;
101 
102 		switch (*format) {
103 		case 'b':
104 			str[offset] = value;
105 			break;
106 		case 'w':
107 			put_unaligned_be16(value, str + offset);
108 			break;
109 		case 'd':
110 			put_unaligned_be32(value, str + offset);
111 			break;
112 		case 's':
113 			memcpy(str + offset, data, length);
114 			break;
115 		}
116 	}
117 	va_end(args);
118 
119 	return 0;
120 }
121 
122 /**
123  * Unpack data from a byte string.  The data types are specified in
124  * the format string: 'b' means unsigned byte, 'w' unsigned word,
125  * 'd' unsigned double word, and 's' byte string.  The data are a
126  * series of offsets and pointers (for type byte string there are also
127  * lengths).
128  *
129  * @param str		output string
130  * @param size		size of output string
131  * @param format	format string
132  * @param ...		data points
133  * @return 0 on success, non-0 on error
134  */
135 int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
136 {
137 	va_list args;
138 	size_t offset = 0, length = 0;
139 	uint8_t *ptr8 = NULL;
140 	uint16_t *ptr16 = NULL;
141 	uint32_t *ptr32 = NULL;
142 
143 	va_start(args, format);
144 	for (; *format; format++) {
145 		switch (*format) {
146 		case 'b':
147 			offset = va_arg(args, size_t);
148 			ptr8 = va_arg(args, uint8_t *);
149 			length = 1;
150 			break;
151 		case 'w':
152 			offset = va_arg(args, size_t);
153 			ptr16 = va_arg(args, uint16_t *);
154 			length = 2;
155 			break;
156 		case 'd':
157 			offset = va_arg(args, size_t);
158 			ptr32 = va_arg(args, uint32_t *);
159 			length = 4;
160 			break;
161 		case 's':
162 			offset = va_arg(args, size_t);
163 			ptr8 = va_arg(args, uint8_t *);
164 			length = va_arg(args, uint32_t);
165 			break;
166 		default:
167 			debug("Couldn't recognize format string\n");
168 			return -1;
169 		}
170 
171 		if (offset + length > size)
172 			return -1;
173 
174 		switch (*format) {
175 		case 'b':
176 			*ptr8 = str[offset];
177 			break;
178 		case 'w':
179 			*ptr16 = get_unaligned_be16(str + offset);
180 			break;
181 		case 'd':
182 			*ptr32 = get_unaligned_be32(str + offset);
183 			break;
184 		case 's':
185 			memcpy(ptr8, str + offset, length);
186 			break;
187 		}
188 	}
189 	va_end(args);
190 
191 	return 0;
192 }
193 
194 /**
195  * Get TPM command size.
196  *
197  * @param command	byte string of TPM command
198  * @return command size of the TPM command
199  */
200 static uint32_t tpm_command_size(const void *command)
201 {
202 	const size_t command_size_offset = 2;
203 	return get_unaligned_be32(command + command_size_offset);
204 }
205 
206 /**
207  * Get TPM response return code, which is one of TPM_RESULT values.
208  *
209  * @param response	byte string of TPM response
210  * @return return code of the TPM response
211  */
212 static uint32_t tpm_return_code(const void *response)
213 {
214 	const size_t return_code_offset = 6;
215 	return get_unaligned_be32(response + return_code_offset);
216 }
217 
218 /**
219  * Send a TPM command and return response's return code, and optionally
220  * return response to caller.
221  *
222  * @param command	byte string of TPM command
223  * @param response	output buffer for TPM response, or NULL if the
224  *			caller does not care about it
225  * @param size_ptr	output buffer size (input parameter) and TPM
226  *			response length (output parameter); this parameter
227  *			is a bidirectional
228  * @return return code of the TPM response
229  */
230 static uint32_t tpm_sendrecv_command(const void *command,
231 		void *response, size_t *size_ptr)
232 {
233 	uint8_t response_buffer[COMMAND_BUFFER_SIZE];
234 	size_t response_length;
235 	uint32_t err;
236 
237 	if (response) {
238 		response_length = *size_ptr;
239 	} else {
240 		response = response_buffer;
241 		response_length = sizeof(response_buffer);
242 	}
243 #ifdef CONFIG_DM_TPM
244 	struct udevice *dev;
245 	int ret;
246 
247 	ret = uclass_first_device(UCLASS_TPM, &dev);
248 	if (ret)
249 		return ret;
250 	err = tpm_xfer(dev, command, tpm_command_size(command),
251 		       response, &response_length);
252 #else
253 	err = tis_sendrecv(command, tpm_command_size(command),
254 			response, &response_length);
255 #endif
256 	if (err < 0)
257 		return TPM_LIB_ERROR;
258 	if (size_ptr)
259 		*size_ptr = response_length;
260 
261 	return tpm_return_code(response);
262 }
263 
264 int tpm_init(void)
265 {
266 	int err;
267 
268 #ifdef CONFIG_DM_TPM
269 	struct udevice *dev;
270 
271 	err = uclass_first_device(UCLASS_TPM, &dev);
272 	if (err)
273 		return err;
274 	return tpm_open(dev);
275 #else
276 	err = tis_init();
277 	if (err)
278 		return err;
279 
280 	return tis_open();
281 #endif
282 }
283 
284 uint32_t tpm_startup(enum tpm_startup_type mode)
285 {
286 	const uint8_t command[12] = {
287 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
288 	};
289 	const size_t mode_offset = 10;
290 	uint8_t buf[COMMAND_BUFFER_SIZE];
291 
292 	if (pack_byte_string(buf, sizeof(buf), "sw",
293 				0, command, sizeof(command),
294 				mode_offset, mode))
295 		return TPM_LIB_ERROR;
296 
297 	return tpm_sendrecv_command(buf, NULL, NULL);
298 }
299 
300 uint32_t tpm_self_test_full(void)
301 {
302 	const uint8_t command[10] = {
303 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
304 	};
305 	return tpm_sendrecv_command(command, NULL, NULL);
306 }
307 
308 uint32_t tpm_continue_self_test(void)
309 {
310 	const uint8_t command[10] = {
311 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
312 	};
313 	return tpm_sendrecv_command(command, NULL, NULL);
314 }
315 
316 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
317 {
318 	const uint8_t command[101] = {
319 		0x0, 0xc1,		/* TPM_TAG */
320 		0x0, 0x0, 0x0, 0x65,	/* parameter size */
321 		0x0, 0x0, 0x0, 0xcc,	/* TPM_COMMAND_CODE */
322 		/* TPM_NV_DATA_PUBLIC->... */
323 		0x0, 0x18,		/* ...->TPM_STRUCTURE_TAG */
324 		0, 0, 0, 0,		/* ...->TPM_NV_INDEX */
325 		/* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
326 		0x0, 0x3,
327 		0, 0, 0,
328 		0x1f,
329 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
330 		/* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
331 		0x0, 0x3,
332 		0, 0, 0,
333 		0x1f,
334 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
335 		/* TPM_NV_ATTRIBUTES->... */
336 		0x0, 0x17,		/* ...->TPM_STRUCTURE_TAG */
337 		0, 0, 0, 0,		/* ...->attributes */
338 		/* End of TPM_NV_ATTRIBUTES */
339 		0,			/* bReadSTClear */
340 		0,			/* bWriteSTClear */
341 		0,			/* bWriteDefine */
342 		0, 0, 0, 0,		/* size */
343 	};
344 	const size_t index_offset = 12;
345 	const size_t perm_offset = 70;
346 	const size_t size_offset = 77;
347 	uint8_t buf[COMMAND_BUFFER_SIZE];
348 
349 	if (pack_byte_string(buf, sizeof(buf), "sddd",
350 				0, command, sizeof(command),
351 				index_offset, index,
352 				perm_offset, perm,
353 				size_offset, size))
354 		return TPM_LIB_ERROR;
355 
356 	return tpm_sendrecv_command(buf, NULL, NULL);
357 }
358 
359 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
360 {
361 	const uint8_t command[22] = {
362 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
363 	};
364 	const size_t index_offset = 10;
365 	const size_t length_offset = 18;
366 	const size_t data_size_offset = 10;
367 	const size_t data_offset = 14;
368 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
369 	size_t response_length = sizeof(response);
370 	uint32_t data_size;
371 	uint32_t err;
372 
373 	if (pack_byte_string(buf, sizeof(buf), "sdd",
374 				0, command, sizeof(command),
375 				index_offset, index,
376 				length_offset, count))
377 		return TPM_LIB_ERROR;
378 	err = tpm_sendrecv_command(buf, response, &response_length);
379 	if (err)
380 		return err;
381 	if (unpack_byte_string(response, response_length, "d",
382 				data_size_offset, &data_size))
383 		return TPM_LIB_ERROR;
384 	if (data_size > count)
385 		return TPM_LIB_ERROR;
386 	if (unpack_byte_string(response, response_length, "s",
387 				data_offset, data, data_size))
388 		return TPM_LIB_ERROR;
389 
390 	return 0;
391 }
392 
393 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
394 {
395 	const uint8_t command[256] = {
396 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
397 	};
398 	const size_t command_size_offset = 2;
399 	const size_t index_offset = 10;
400 	const size_t length_offset = 18;
401 	const size_t data_offset = 22;
402 	const size_t write_info_size = 12;
403 	const uint32_t total_length =
404 		TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
405 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
406 	size_t response_length = sizeof(response);
407 	uint32_t err;
408 
409 	if (pack_byte_string(buf, sizeof(buf), "sddds",
410 				0, command, sizeof(command),
411 				command_size_offset, total_length,
412 				index_offset, index,
413 				length_offset, length,
414 				data_offset, data, length))
415 		return TPM_LIB_ERROR;
416 	err = tpm_sendrecv_command(buf, response, &response_length);
417 	if (err)
418 		return err;
419 
420 	return 0;
421 }
422 
423 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
424 {
425 	const uint8_t command[34] = {
426 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
427 	};
428 	const size_t index_offset = 10;
429 	const size_t in_digest_offset = 14;
430 	const size_t out_digest_offset = 10;
431 	uint8_t buf[COMMAND_BUFFER_SIZE];
432 	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
433 	size_t response_length = sizeof(response);
434 	uint32_t err;
435 
436 	if (pack_byte_string(buf, sizeof(buf), "sds",
437 				0, command, sizeof(command),
438 				index_offset, index,
439 				in_digest_offset, in_digest,
440 				PCR_DIGEST_LENGTH))
441 		return TPM_LIB_ERROR;
442 	err = tpm_sendrecv_command(buf, response, &response_length);
443 	if (err)
444 		return err;
445 
446 	if (unpack_byte_string(response, response_length, "s",
447 				out_digest_offset, out_digest,
448 				PCR_DIGEST_LENGTH))
449 		return TPM_LIB_ERROR;
450 
451 	return 0;
452 }
453 
454 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
455 {
456 	const uint8_t command[14] = {
457 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
458 	};
459 	const size_t index_offset = 10;
460 	const size_t out_digest_offset = 10;
461 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
462 	size_t response_length = sizeof(response);
463 	uint32_t err;
464 
465 	if (count < PCR_DIGEST_LENGTH)
466 		return TPM_LIB_ERROR;
467 
468 	if (pack_byte_string(buf, sizeof(buf), "sd",
469 				0, command, sizeof(command),
470 				index_offset, index))
471 		return TPM_LIB_ERROR;
472 	err = tpm_sendrecv_command(buf, response, &response_length);
473 	if (err)
474 		return err;
475 	if (unpack_byte_string(response, response_length, "s",
476 				out_digest_offset, data, PCR_DIGEST_LENGTH))
477 		return TPM_LIB_ERROR;
478 
479 	return 0;
480 }
481 
482 uint32_t tpm_tsc_physical_presence(uint16_t presence)
483 {
484 	const uint8_t command[12] = {
485 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
486 	};
487 	const size_t presence_offset = 10;
488 	uint8_t buf[COMMAND_BUFFER_SIZE];
489 
490 	if (pack_byte_string(buf, sizeof(buf), "sw",
491 				0, command, sizeof(command),
492 				presence_offset, presence))
493 		return TPM_LIB_ERROR;
494 
495 	return tpm_sendrecv_command(buf, NULL, NULL);
496 }
497 
498 uint32_t tpm_read_pubek(void *data, size_t count)
499 {
500 	const uint8_t command[30] = {
501 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
502 	};
503 	const size_t response_size_offset = 2;
504 	const size_t data_offset = 10;
505 	const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
506 	uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
507 	size_t response_length = sizeof(response);
508 	uint32_t data_size;
509 	uint32_t err;
510 
511 	err = tpm_sendrecv_command(command, response, &response_length);
512 	if (err)
513 		return err;
514 	if (unpack_byte_string(response, response_length, "d",
515 				response_size_offset, &data_size))
516 		return TPM_LIB_ERROR;
517 	if (data_size < header_and_checksum_size)
518 		return TPM_LIB_ERROR;
519 	data_size -= header_and_checksum_size;
520 	if (data_size > count)
521 		return TPM_LIB_ERROR;
522 	if (unpack_byte_string(response, response_length, "s",
523 				data_offset, data, data_size))
524 		return TPM_LIB_ERROR;
525 
526 	return 0;
527 }
528 
529 uint32_t tpm_force_clear(void)
530 {
531 	const uint8_t command[10] = {
532 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
533 	};
534 
535 	return tpm_sendrecv_command(command, NULL, NULL);
536 }
537 
538 uint32_t tpm_physical_enable(void)
539 {
540 	const uint8_t command[10] = {
541 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
542 	};
543 
544 	return tpm_sendrecv_command(command, NULL, NULL);
545 }
546 
547 uint32_t tpm_physical_disable(void)
548 {
549 	const uint8_t command[10] = {
550 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
551 	};
552 
553 	return tpm_sendrecv_command(command, NULL, NULL);
554 }
555 
556 uint32_t tpm_physical_set_deactivated(uint8_t state)
557 {
558 	const uint8_t command[11] = {
559 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
560 	};
561 	const size_t state_offset = 10;
562 	uint8_t buf[COMMAND_BUFFER_SIZE];
563 
564 	if (pack_byte_string(buf, sizeof(buf), "sb",
565 				0, command, sizeof(command),
566 				state_offset, state))
567 		return TPM_LIB_ERROR;
568 
569 	return tpm_sendrecv_command(buf, NULL, NULL);
570 }
571 
572 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
573 		void *cap, size_t count)
574 {
575 	const uint8_t command[22] = {
576 		0x0, 0xc1,		/* TPM_TAG */
577 		0x0, 0x0, 0x0, 0x16,	/* parameter size */
578 		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */
579 		0x0, 0x0, 0x0, 0x0,	/* TPM_CAPABILITY_AREA */
580 		0x0, 0x0, 0x0, 0x4,	/* subcap size */
581 		0x0, 0x0, 0x0, 0x0,	/* subcap value */
582 	};
583 	const size_t cap_area_offset = 10;
584 	const size_t sub_cap_offset = 18;
585 	const size_t cap_offset = 14;
586 	const size_t cap_size_offset = 10;
587 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
588 	size_t response_length = sizeof(response);
589 	uint32_t cap_size;
590 	uint32_t err;
591 
592 	if (pack_byte_string(buf, sizeof(buf), "sdd",
593 				0, command, sizeof(command),
594 				cap_area_offset, cap_area,
595 				sub_cap_offset, sub_cap))
596 		return TPM_LIB_ERROR;
597 	err = tpm_sendrecv_command(buf, response, &response_length);
598 	if (err)
599 		return err;
600 	if (unpack_byte_string(response, response_length, "d",
601 				cap_size_offset, &cap_size))
602 		return TPM_LIB_ERROR;
603 	if (cap_size > response_length || cap_size > count)
604 		return TPM_LIB_ERROR;
605 	if (unpack_byte_string(response, response_length, "s",
606 				cap_offset, cap, cap_size))
607 		return TPM_LIB_ERROR;
608 
609 	return 0;
610 }
611 
612 uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
613 {
614 	const uint8_t command[22] = {
615 		0x0, 0xc1,		/* TPM_TAG */
616 		0x0, 0x0, 0x0, 0x16,	/* parameter size */
617 		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */
618 		0x0, 0x0, 0x0, 0x4,	/* TPM_CAP_FLAG_PERM */
619 		0x0, 0x0, 0x0, 0x4,	/* subcap size */
620 		0x0, 0x0, 0x1, 0x8,	/* subcap value */
621 	};
622 	uint8_t response[COMMAND_BUFFER_SIZE];
623 	size_t response_length = sizeof(response);
624 	uint32_t err;
625 
626 	err = tpm_sendrecv_command(command, response, &response_length);
627 	if (err)
628 		return err;
629 	memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
630 
631 	return 0;
632 }
633 
634 uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
635 {
636 	const uint8_t command[22] = {
637 		0x0, 0xc1,		/* TPM_TAG */
638 		0x0, 0x0, 0x0, 0x16,	/* parameter size */
639 		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */
640 		0x0, 0x0, 0x0, 0x11,
641 		0x0, 0x0, 0x0, 0x4,
642 	};
643 	const size_t index_offset = 18;
644 	const size_t perm_offset = 60;
645 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
646 	size_t response_length = sizeof(response);
647 	uint32_t err;
648 
649 	if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
650 			     index_offset, index))
651 		return TPM_LIB_ERROR;
652 	err = tpm_sendrecv_command(buf, response, &response_length);
653 	if (err)
654 		return err;
655 	if (unpack_byte_string(response, response_length, "d",
656 			       perm_offset, perm))
657 		return TPM_LIB_ERROR;
658 
659 	return 0;
660 }
661 
662 #ifdef CONFIG_TPM_AUTH_SESSIONS
663 
664 /**
665  * Fill an authentication block in a request.
666  * This func can create the first as well as the second auth block (for
667  * double authorized commands).
668  *
669  * @param request	pointer to the request (w/ uninitialised auth data)
670  * @param request_len0	length of the request without auth data
671  * @param handles_len	length of the handles area in request
672  * @param auth_session	pointer to the (valid) auth session to be used
673  * @param request_auth	pointer to the auth block of the request to be filled
674  * @param auth		authentication data (HMAC key)
675  */
676 static uint32_t create_request_auth(const void *request, size_t request_len0,
677 	size_t handles_len,
678 	struct session_data *auth_session,
679 	void *request_auth, const void *auth)
680 {
681 	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
682 	sha1_context hash_ctx;
683 	const size_t command_code_offset = 6;
684 	const size_t auth_nonce_odd_offset = 4;
685 	const size_t auth_continue_offset = 24;
686 	const size_t auth_auth_offset = 25;
687 
688 	if (!auth_session || !auth_session->valid)
689 		return TPM_LIB_ERROR;
690 
691 	sha1_starts(&hash_ctx);
692 	sha1_update(&hash_ctx, request + command_code_offset, 4);
693 	if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
694 		sha1_update(&hash_ctx,
695 			    request + TPM_REQUEST_HEADER_LENGTH + handles_len,
696 			    request_len0 - TPM_REQUEST_HEADER_LENGTH
697 			    - handles_len);
698 	sha1_finish(&hash_ctx, hmac_data);
699 
700 	sha1_starts(&hash_ctx);
701 	sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
702 	sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
703 	sha1_finish(&hash_ctx, auth_session->nonce_odd);
704 
705 	if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
706 			     0, auth_session->handle,
707 			     auth_nonce_odd_offset, auth_session->nonce_odd,
708 			     DIGEST_LENGTH,
709 			     auth_continue_offset, 1))
710 		return TPM_LIB_ERROR;
711 	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
712 			     DIGEST_LENGTH,
713 			     auth_session->nonce_even,
714 			     DIGEST_LENGTH,
715 			     2 * DIGEST_LENGTH,
716 			     request_auth + auth_nonce_odd_offset,
717 			     DIGEST_LENGTH + 1))
718 		return TPM_LIB_ERROR;
719 	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
720 		  request_auth + auth_auth_offset);
721 
722 	return TPM_SUCCESS;
723 }
724 
725 /**
726  * Verify an authentication block in a response.
727  * Since this func updates the nonce_even in the session data it has to be
728  * called when receiving a succesfull AUTH response.
729  * This func can verify the first as well as the second auth block (for
730  * double authorized commands).
731  *
732  * @param command_code	command code of the request
733  * @param response	pointer to the request (w/ uninitialised auth data)
734  * @param handles_len	length of the handles area in response
735  * @param auth_session	pointer to the (valid) auth session to be used
736  * @param response_auth	pointer to the auth block of the response to be verified
737  * @param auth		authentication data (HMAC key)
738  */
739 static uint32_t verify_response_auth(uint32_t command_code,
740 	const void *response, size_t response_len0,
741 	size_t handles_len,
742 	struct session_data *auth_session,
743 	const void *response_auth, const void *auth)
744 {
745 	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
746 	uint8_t computed_auth[DIGEST_LENGTH];
747 	sha1_context hash_ctx;
748 	const size_t return_code_offset = 6;
749 	const size_t auth_continue_offset = 20;
750 	const size_t auth_auth_offset = 21;
751 	uint8_t auth_continue;
752 
753 	if (!auth_session || !auth_session->valid)
754 		return TPM_AUTHFAIL;
755 	if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
756 			     0, command_code))
757 		return TPM_LIB_ERROR;
758 	if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
759 		return TPM_LIB_ERROR;
760 
761 	sha1_starts(&hash_ctx);
762 	sha1_update(&hash_ctx, response + return_code_offset, 4);
763 	sha1_update(&hash_ctx, hmac_data, 4);
764 	if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
765 		sha1_update(&hash_ctx,
766 			    response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
767 			    response_len0 - TPM_RESPONSE_HEADER_LENGTH
768 			    - handles_len);
769 	sha1_finish(&hash_ctx, hmac_data);
770 
771 	memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
772 	auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
773 	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
774 			     DIGEST_LENGTH,
775 			     response_auth,
776 			     DIGEST_LENGTH,
777 			     2 * DIGEST_LENGTH,
778 			     auth_session->nonce_odd,
779 			     DIGEST_LENGTH,
780 			     3 * DIGEST_LENGTH,
781 			     auth_continue))
782 		return TPM_LIB_ERROR;
783 
784 	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
785 		  computed_auth);
786 
787 	if (memcmp(computed_auth, response_auth + auth_auth_offset,
788 		   DIGEST_LENGTH))
789 		return TPM_AUTHFAIL;
790 
791 	return TPM_SUCCESS;
792 }
793 
794 
795 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
796 {
797 	const uint8_t command[18] = {
798 		0x00, 0xc1,		/* TPM_TAG */
799 		0x00, 0x00, 0x00, 0x00,	/* parameter size */
800 		0x00, 0x00, 0x00, 0xba,	/* TPM_COMMAND_CODE */
801 		0x00, 0x00, 0x00, 0x00,	/* TPM_HANDLE */
802 		0x00, 0x00, 0x00, 0x02,	/* TPM_RESSOURCE_TYPE */
803 	};
804 	const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
805 	uint8_t request[COMMAND_BUFFER_SIZE];
806 
807 	if (pack_byte_string(request, sizeof(request), "sd",
808 			     0, command, sizeof(command),
809 			     req_handle_offset, auth_handle))
810 		return TPM_LIB_ERROR;
811 	if (oiap_session.valid && oiap_session.handle == auth_handle)
812 		oiap_session.valid = 0;
813 
814 	return tpm_sendrecv_command(request, NULL, NULL);
815 }
816 
817 uint32_t tpm_end_oiap(void)
818 {
819 	uint32_t err = TPM_SUCCESS;
820 	if (oiap_session.valid)
821 		err = tpm_terminate_auth_session(oiap_session.handle);
822 	return err;
823 }
824 
825 uint32_t tpm_oiap(uint32_t *auth_handle)
826 {
827 	const uint8_t command[10] = {
828 		0x00, 0xc1,		/* TPM_TAG */
829 		0x00, 0x00, 0x00, 0x0a,	/* parameter size */
830 		0x00, 0x00, 0x00, 0x0a,	/* TPM_COMMAND_CODE */
831 	};
832 	const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
833 	const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
834 	uint8_t response[COMMAND_BUFFER_SIZE];
835 	size_t response_length = sizeof(response);
836 	uint32_t err;
837 
838 	if (oiap_session.valid)
839 		tpm_terminate_auth_session(oiap_session.handle);
840 
841 	err = tpm_sendrecv_command(command, response, &response_length);
842 	if (err)
843 		return err;
844 	if (unpack_byte_string(response, response_length, "ds",
845 			       res_auth_handle_offset, &oiap_session.handle,
846 			       res_nonce_even_offset, &oiap_session.nonce_even,
847 			       (uint32_t)DIGEST_LENGTH))
848 		return TPM_LIB_ERROR;
849 	oiap_session.valid = 1;
850 	if (auth_handle)
851 		*auth_handle = oiap_session.handle;
852 	return 0;
853 }
854 
855 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
856 		const void *key, size_t key_length,
857 		const void *parent_key_usage_auth,
858 		uint32_t *key_handle)
859 {
860 	const uint8_t command[14] = {
861 		0x00, 0xc2,		/* TPM_TAG */
862 		0x00, 0x00, 0x00, 0x00,	/* parameter size */
863 		0x00, 0x00, 0x00, 0x41,	/* TPM_COMMAND_CODE */
864 		0x00, 0x00, 0x00, 0x00,	/* parent handle */
865 	};
866 	const size_t req_size_offset = 2;
867 	const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
868 	const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
869 	const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
870 	uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
871 			+ TPM_REQUEST_AUTH_LENGTH];
872 	uint8_t response[COMMAND_BUFFER_SIZE];
873 	size_t response_length = sizeof(response);
874 	uint32_t err;
875 
876 	if (!oiap_session.valid) {
877 		err = tpm_oiap(NULL);
878 		if (err)
879 			return err;
880 	}
881 	if (pack_byte_string(request, sizeof(request), "sdds",
882 			     0, command, sizeof(command),
883 			     req_size_offset,
884 			     sizeof(command) + key_length
885 			     + TPM_REQUEST_AUTH_LENGTH,
886 			     req_parent_handle_offset, parent_handle,
887 			     req_key_offset, key, key_length
888 		))
889 		return TPM_LIB_ERROR;
890 
891 	err = create_request_auth(request, sizeof(command) + key_length, 4,
892 				&oiap_session,
893 				request + sizeof(command) + key_length,
894 				parent_key_usage_auth);
895 	if (err)
896 		return err;
897 	err = tpm_sendrecv_command(request, response, &response_length);
898 	if (err) {
899 		if (err == TPM_AUTHFAIL)
900 			oiap_session.valid = 0;
901 		return err;
902 	}
903 
904 	err = verify_response_auth(0x00000041, response,
905 			response_length - TPM_RESPONSE_AUTH_LENGTH,
906 			4, &oiap_session,
907 			response + response_length - TPM_RESPONSE_AUTH_LENGTH,
908 			parent_key_usage_auth);
909 	if (err)
910 		return err;
911 
912 	if (key_handle) {
913 		if (unpack_byte_string(response, response_length, "d",
914 				       res_handle_offset, key_handle))
915 			return TPM_LIB_ERROR;
916 	}
917 
918 	return 0;
919 }
920 
921 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
922 			void *pubkey, size_t *pubkey_len)
923 {
924 	const uint8_t command[14] = {
925 		0x00, 0xc2,		/* TPM_TAG */
926 		0x00, 0x00, 0x00, 0x00,	/* parameter size */
927 		0x00, 0x00, 0x00, 0x21,	/* TPM_COMMAND_CODE */
928 		0x00, 0x00, 0x00, 0x00,	/* key handle */
929 	};
930 	const size_t req_size_offset = 2;
931 	const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
932 	const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
933 	uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
934 	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
935 			+ TPM_RESPONSE_AUTH_LENGTH];
936 	size_t response_length = sizeof(response);
937 	uint32_t err;
938 
939 	if (!oiap_session.valid) {
940 		err = tpm_oiap(NULL);
941 		if (err)
942 			return err;
943 	}
944 	if (pack_byte_string(request, sizeof(request), "sdd",
945 			     0, command, sizeof(command),
946 			     req_size_offset,
947 			     (uint32_t)(sizeof(command)
948 			     + TPM_REQUEST_AUTH_LENGTH),
949 			     req_key_handle_offset, key_handle
950 		))
951 		return TPM_LIB_ERROR;
952 	err = create_request_auth(request, sizeof(command), 4, &oiap_session,
953 			request + sizeof(command), usage_auth);
954 	if (err)
955 		return err;
956 	err = tpm_sendrecv_command(request, response, &response_length);
957 	if (err) {
958 		if (err == TPM_AUTHFAIL)
959 			oiap_session.valid = 0;
960 		return err;
961 	}
962 	err = verify_response_auth(0x00000021, response,
963 			response_length - TPM_RESPONSE_AUTH_LENGTH,
964 			0, &oiap_session,
965 			response + response_length - TPM_RESPONSE_AUTH_LENGTH,
966 			usage_auth);
967 	if (err)
968 		return err;
969 
970 	if (pubkey) {
971 		if ((response_length - TPM_RESPONSE_HEADER_LENGTH
972 			- TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
973 			return TPM_LIB_ERROR;
974 		*pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
975 			- TPM_RESPONSE_AUTH_LENGTH;
976 		memcpy(pubkey, response + res_pubkey_offset,
977 		       response_length - TPM_RESPONSE_HEADER_LENGTH
978 		       - TPM_RESPONSE_AUTH_LENGTH);
979 	}
980 
981 	return 0;
982 }
983 
984 #endif /* CONFIG_TPM_AUTH_SESSIONS */
985