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