xref: /rk3399_rockchip-uboot/lib/tpm.c (revision 11db3abe6609e08e2df4ecc9353d2c0a2b061be2)
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 <stdarg.h>
10 #include <u-boot/sha1.h>
11 #include <tpm.h>
12 #include <asm/unaligned.h>
13 
14 /* Internal error of TPM command library */
15 #define TPM_LIB_ERROR	((uint32_t)~0u)
16 
17 /* Useful constants */
18 enum {
19 	COMMAND_BUFFER_SIZE		= 256,
20 	TPM_PUBEK_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 	err = tis_sendrecv(command, tpm_command_size(command),
244 			response, &response_length);
245 	if (err)
246 		return TPM_LIB_ERROR;
247 	if (size_ptr)
248 		*size_ptr = response_length;
249 
250 	return tpm_return_code(response);
251 }
252 
253 uint32_t tpm_init(void)
254 {
255 	uint32_t err;
256 
257 	err = tis_init();
258 	if (err)
259 		return err;
260 
261 	return tis_open();
262 }
263 
264 uint32_t tpm_startup(enum tpm_startup_type mode)
265 {
266 	const uint8_t command[12] = {
267 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
268 	};
269 	const size_t mode_offset = 10;
270 	uint8_t buf[COMMAND_BUFFER_SIZE];
271 
272 	if (pack_byte_string(buf, sizeof(buf), "sw",
273 				0, command, sizeof(command),
274 				mode_offset, mode))
275 		return TPM_LIB_ERROR;
276 
277 	return tpm_sendrecv_command(buf, NULL, NULL);
278 }
279 
280 uint32_t tpm_self_test_full(void)
281 {
282 	const uint8_t command[10] = {
283 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
284 	};
285 	return tpm_sendrecv_command(command, NULL, NULL);
286 }
287 
288 uint32_t tpm_continue_self_test(void)
289 {
290 	const uint8_t command[10] = {
291 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
292 	};
293 	return tpm_sendrecv_command(command, NULL, NULL);
294 }
295 
296 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
297 {
298 	const uint8_t command[101] = {
299 		0x0, 0xc1,		/* TPM_TAG */
300 		0x0, 0x0, 0x0, 0x65,	/* parameter size */
301 		0x0, 0x0, 0x0, 0xcc,	/* TPM_COMMAND_CODE */
302 		/* TPM_NV_DATA_PUBLIC->... */
303 		0x0, 0x18,		/* ...->TPM_STRUCTURE_TAG */
304 		0, 0, 0, 0,		/* ...->TPM_NV_INDEX */
305 		/* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
306 		0x0, 0x3,
307 		0, 0, 0,
308 		0x1f,
309 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
310 		/* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
311 		0x0, 0x3,
312 		0, 0, 0,
313 		0x1f,
314 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
315 		/* TPM_NV_ATTRIBUTES->... */
316 		0x0, 0x17,		/* ...->TPM_STRUCTURE_TAG */
317 		0, 0, 0, 0,		/* ...->attributes */
318 		/* End of TPM_NV_ATTRIBUTES */
319 		0,			/* bReadSTClear */
320 		0,			/* bWriteSTClear */
321 		0,			/* bWriteDefine */
322 		0, 0, 0, 0,		/* size */
323 	};
324 	const size_t index_offset = 12;
325 	const size_t perm_offset = 70;
326 	const size_t size_offset = 77;
327 	uint8_t buf[COMMAND_BUFFER_SIZE];
328 
329 	if (pack_byte_string(buf, sizeof(buf), "sddd",
330 				0, command, sizeof(command),
331 				index_offset, index,
332 				perm_offset, perm,
333 				size_offset, size))
334 		return TPM_LIB_ERROR;
335 
336 	return tpm_sendrecv_command(buf, NULL, NULL);
337 }
338 
339 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
340 {
341 	const uint8_t command[22] = {
342 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
343 	};
344 	const size_t index_offset = 10;
345 	const size_t length_offset = 18;
346 	const size_t data_size_offset = 10;
347 	const size_t data_offset = 14;
348 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
349 	size_t response_length = sizeof(response);
350 	uint32_t data_size;
351 	uint32_t err;
352 
353 	if (pack_byte_string(buf, sizeof(buf), "sdd",
354 				0, command, sizeof(command),
355 				index_offset, index,
356 				length_offset, count))
357 		return TPM_LIB_ERROR;
358 	err = tpm_sendrecv_command(buf, response, &response_length);
359 	if (err)
360 		return err;
361 	if (unpack_byte_string(response, response_length, "d",
362 				data_size_offset, &data_size))
363 		return TPM_LIB_ERROR;
364 	if (data_size > count)
365 		return TPM_LIB_ERROR;
366 	if (unpack_byte_string(response, response_length, "s",
367 				data_offset, data, data_size))
368 		return TPM_LIB_ERROR;
369 
370 	return 0;
371 }
372 
373 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
374 {
375 	const uint8_t command[256] = {
376 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
377 	};
378 	const size_t command_size_offset = 2;
379 	const size_t index_offset = 10;
380 	const size_t length_offset = 18;
381 	const size_t data_offset = 22;
382 	const size_t write_info_size = 12;
383 	const uint32_t total_length =
384 		TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
385 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
386 	size_t response_length = sizeof(response);
387 	uint32_t err;
388 
389 	if (pack_byte_string(buf, sizeof(buf), "sddds",
390 				0, command, sizeof(command),
391 				command_size_offset, total_length,
392 				index_offset, index,
393 				length_offset, length,
394 				data_offset, data, length))
395 		return TPM_LIB_ERROR;
396 	err = tpm_sendrecv_command(buf, response, &response_length);
397 	if (err)
398 		return err;
399 
400 	return 0;
401 }
402 
403 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
404 {
405 	const uint8_t command[34] = {
406 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
407 	};
408 	const size_t index_offset = 10;
409 	const size_t in_digest_offset = 14;
410 	const size_t out_digest_offset = 10;
411 	uint8_t buf[COMMAND_BUFFER_SIZE];
412 	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
413 	size_t response_length = sizeof(response);
414 	uint32_t err;
415 
416 	if (pack_byte_string(buf, sizeof(buf), "sds",
417 				0, command, sizeof(command),
418 				index_offset, index,
419 				in_digest_offset, in_digest,
420 				PCR_DIGEST_LENGTH))
421 		return TPM_LIB_ERROR;
422 	err = tpm_sendrecv_command(buf, response, &response_length);
423 	if (err)
424 		return err;
425 
426 	if (unpack_byte_string(response, response_length, "s",
427 				out_digest_offset, out_digest,
428 				PCR_DIGEST_LENGTH))
429 		return TPM_LIB_ERROR;
430 
431 	return 0;
432 }
433 
434 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
435 {
436 	const uint8_t command[14] = {
437 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
438 	};
439 	const size_t index_offset = 10;
440 	const size_t out_digest_offset = 10;
441 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
442 	size_t response_length = sizeof(response);
443 	uint32_t err;
444 
445 	if (count < PCR_DIGEST_LENGTH)
446 		return TPM_LIB_ERROR;
447 
448 	if (pack_byte_string(buf, sizeof(buf), "sd",
449 				0, command, sizeof(command),
450 				index_offset, index))
451 		return TPM_LIB_ERROR;
452 	err = tpm_sendrecv_command(buf, response, &response_length);
453 	if (err)
454 		return err;
455 	if (unpack_byte_string(response, response_length, "s",
456 				out_digest_offset, data, PCR_DIGEST_LENGTH))
457 		return TPM_LIB_ERROR;
458 
459 	return 0;
460 }
461 
462 uint32_t tpm_tsc_physical_presence(uint16_t presence)
463 {
464 	const uint8_t command[12] = {
465 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
466 	};
467 	const size_t presence_offset = 10;
468 	uint8_t buf[COMMAND_BUFFER_SIZE];
469 
470 	if (pack_byte_string(buf, sizeof(buf), "sw",
471 				0, command, sizeof(command),
472 				presence_offset, presence))
473 		return TPM_LIB_ERROR;
474 
475 	return tpm_sendrecv_command(buf, NULL, NULL);
476 }
477 
478 uint32_t tpm_read_pubek(void *data, size_t count)
479 {
480 	const uint8_t command[30] = {
481 		0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
482 	};
483 	const size_t response_size_offset = 2;
484 	const size_t data_offset = 10;
485 	const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
486 	uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
487 	size_t response_length = sizeof(response);
488 	uint32_t data_size;
489 	uint32_t err;
490 
491 	err = tpm_sendrecv_command(command, response, &response_length);
492 	if (err)
493 		return err;
494 	if (unpack_byte_string(response, response_length, "d",
495 				response_size_offset, &data_size))
496 		return TPM_LIB_ERROR;
497 	if (data_size < header_and_checksum_size)
498 		return TPM_LIB_ERROR;
499 	data_size -= header_and_checksum_size;
500 	if (data_size > count)
501 		return TPM_LIB_ERROR;
502 	if (unpack_byte_string(response, response_length, "s",
503 				data_offset, data, data_size))
504 		return TPM_LIB_ERROR;
505 
506 	return 0;
507 }
508 
509 uint32_t tpm_force_clear(void)
510 {
511 	const uint8_t command[10] = {
512 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
513 	};
514 
515 	return tpm_sendrecv_command(command, NULL, NULL);
516 }
517 
518 uint32_t tpm_physical_enable(void)
519 {
520 	const uint8_t command[10] = {
521 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
522 	};
523 
524 	return tpm_sendrecv_command(command, NULL, NULL);
525 }
526 
527 uint32_t tpm_physical_disable(void)
528 {
529 	const uint8_t command[10] = {
530 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
531 	};
532 
533 	return tpm_sendrecv_command(command, NULL, NULL);
534 }
535 
536 uint32_t tpm_physical_set_deactivated(uint8_t state)
537 {
538 	const uint8_t command[11] = {
539 		0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
540 	};
541 	const size_t state_offset = 10;
542 	uint8_t buf[COMMAND_BUFFER_SIZE];
543 
544 	if (pack_byte_string(buf, sizeof(buf), "sb",
545 				0, command, sizeof(command),
546 				state_offset, state))
547 		return TPM_LIB_ERROR;
548 
549 	return tpm_sendrecv_command(buf, NULL, NULL);
550 }
551 
552 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
553 		void *cap, size_t count)
554 {
555 	const uint8_t command[22] = {
556 		0x0, 0xc1,		/* TPM_TAG */
557 		0x0, 0x0, 0x0, 0x16,	/* parameter size */
558 		0x0, 0x0, 0x0, 0x65,	/* TPM_COMMAND_CODE */
559 		0x0, 0x0, 0x0, 0x0,	/* TPM_CAPABILITY_AREA */
560 		0x0, 0x0, 0x0, 0x4,	/* subcap size */
561 		0x0, 0x0, 0x0, 0x0,	/* subcap value */
562 	};
563 	const size_t cap_area_offset = 10;
564 	const size_t sub_cap_offset = 18;
565 	const size_t cap_offset = 14;
566 	const size_t cap_size_offset = 10;
567 	uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
568 	size_t response_length = sizeof(response);
569 	uint32_t cap_size;
570 	uint32_t err;
571 
572 	if (pack_byte_string(buf, sizeof(buf), "sdd",
573 				0, command, sizeof(command),
574 				cap_area_offset, cap_area,
575 				sub_cap_offset, sub_cap))
576 		return TPM_LIB_ERROR;
577 	err = tpm_sendrecv_command(buf, response, &response_length);
578 	if (err)
579 		return err;
580 	if (unpack_byte_string(response, response_length, "d",
581 				cap_size_offset, &cap_size))
582 		return TPM_LIB_ERROR;
583 	if (cap_size > response_length || cap_size > count)
584 		return TPM_LIB_ERROR;
585 	if (unpack_byte_string(response, response_length, "s",
586 				cap_offset, cap, cap_size))
587 		return TPM_LIB_ERROR;
588 
589 	return 0;
590 }
591 
592 #ifdef CONFIG_TPM_AUTH_SESSIONS
593 
594 /**
595  * Fill an authentication block in a request.
596  * This func can create the first as well as the second auth block (for
597  * double authorized commands).
598  *
599  * @param request	pointer to the request (w/ uninitialised auth data)
600  * @param request_len0	length of the request without auth data
601  * @param handles_len	length of the handles area in request
602  * @param auth_session	pointer to the (valid) auth session to be used
603  * @param request_auth	pointer to the auth block of the request to be filled
604  * @param auth		authentication data (HMAC key)
605  */
606 static uint32_t create_request_auth(const void *request, size_t request_len0,
607 	size_t handles_len,
608 	struct session_data *auth_session,
609 	void *request_auth, const void *auth)
610 {
611 	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
612 	sha1_context hash_ctx;
613 	const size_t command_code_offset = 6;
614 	const size_t auth_nonce_odd_offset = 4;
615 	const size_t auth_continue_offset = 24;
616 	const size_t auth_auth_offset = 25;
617 
618 	if (!auth_session || !auth_session->valid)
619 		return TPM_LIB_ERROR;
620 
621 	sha1_starts(&hash_ctx);
622 	sha1_update(&hash_ctx, request + command_code_offset, 4);
623 	if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
624 		sha1_update(&hash_ctx,
625 			    request + TPM_REQUEST_HEADER_LENGTH + handles_len,
626 			    request_len0 - TPM_REQUEST_HEADER_LENGTH
627 			    - handles_len);
628 	sha1_finish(&hash_ctx, hmac_data);
629 
630 	sha1_starts(&hash_ctx);
631 	sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
632 	sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
633 	sha1_finish(&hash_ctx, auth_session->nonce_odd);
634 
635 	if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
636 			     0, auth_session->handle,
637 			     auth_nonce_odd_offset, auth_session->nonce_odd,
638 			     DIGEST_LENGTH,
639 			     auth_continue_offset, 1))
640 		return TPM_LIB_ERROR;
641 	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
642 			     DIGEST_LENGTH,
643 			     auth_session->nonce_even,
644 			     DIGEST_LENGTH,
645 			     2 * DIGEST_LENGTH,
646 			     request_auth + auth_nonce_odd_offset,
647 			     DIGEST_LENGTH + 1))
648 		return TPM_LIB_ERROR;
649 	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
650 		  request_auth + auth_auth_offset);
651 
652 	return TPM_SUCCESS;
653 }
654 
655 /**
656  * Verify an authentication block in a response.
657  * Since this func updates the nonce_even in the session data it has to be
658  * called when receiving a succesfull AUTH response.
659  * This func can verify the first as well as the second auth block (for
660  * double authorized commands).
661  *
662  * @param command_code	command code of the request
663  * @param response	pointer to the request (w/ uninitialised auth data)
664  * @param handles_len	length of the handles area in response
665  * @param auth_session	pointer to the (valid) auth session to be used
666  * @param response_auth	pointer to the auth block of the response to be verified
667  * @param auth		authentication data (HMAC key)
668  */
669 static uint32_t verify_response_auth(uint32_t command_code,
670 	const void *response, size_t response_len0,
671 	size_t handles_len,
672 	struct session_data *auth_session,
673 	const void *response_auth, const void *auth)
674 {
675 	uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
676 	uint8_t computed_auth[DIGEST_LENGTH];
677 	sha1_context hash_ctx;
678 	const size_t return_code_offset = 6;
679 	const size_t auth_continue_offset = 20;
680 	const size_t auth_auth_offset = 21;
681 	uint8_t auth_continue;
682 
683 	if (!auth_session || !auth_session->valid)
684 		return TPM_AUTHFAIL;
685 	if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
686 			     0, command_code))
687 		return TPM_LIB_ERROR;
688 	if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
689 		return TPM_LIB_ERROR;
690 
691 	sha1_starts(&hash_ctx);
692 	sha1_update(&hash_ctx, response + return_code_offset, 4);
693 	sha1_update(&hash_ctx, hmac_data, 4);
694 	if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
695 		sha1_update(&hash_ctx,
696 			    response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
697 			    response_len0 - TPM_RESPONSE_HEADER_LENGTH
698 			    - handles_len);
699 	sha1_finish(&hash_ctx, hmac_data);
700 
701 	memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
702 	auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
703 	if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
704 			     DIGEST_LENGTH,
705 			     response_auth,
706 			     DIGEST_LENGTH,
707 			     2 * DIGEST_LENGTH,
708 			     auth_session->nonce_odd,
709 			     DIGEST_LENGTH,
710 			     3 * DIGEST_LENGTH,
711 			     auth_continue))
712 		return TPM_LIB_ERROR;
713 
714 	sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
715 		  computed_auth);
716 
717 	if (memcmp(computed_auth, response_auth + auth_auth_offset,
718 		   DIGEST_LENGTH))
719 		return TPM_AUTHFAIL;
720 
721 	return TPM_SUCCESS;
722 }
723 
724 
725 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
726 {
727 	const uint8_t command[18] = {
728 		0x00, 0xc1,		/* TPM_TAG */
729 		0x00, 0x00, 0x00, 0x00,	/* parameter size */
730 		0x00, 0x00, 0x00, 0xba,	/* TPM_COMMAND_CODE */
731 		0x00, 0x00, 0x00, 0x00,	/* TPM_HANDLE */
732 		0x00, 0x00, 0x00, 0x02,	/* TPM_RESSOURCE_TYPE */
733 	};
734 	const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
735 	uint8_t request[COMMAND_BUFFER_SIZE];
736 
737 	if (pack_byte_string(request, sizeof(request), "sd",
738 			     0, command, sizeof(command),
739 			     req_handle_offset, auth_handle))
740 		return TPM_LIB_ERROR;
741 	if (oiap_session.valid && oiap_session.handle == auth_handle)
742 		oiap_session.valid = 0;
743 
744 	return tpm_sendrecv_command(request, NULL, NULL);
745 }
746 
747 uint32_t tpm_end_oiap(void)
748 {
749 	uint32_t err = TPM_SUCCESS;
750 	if (oiap_session.valid)
751 		err = tpm_terminate_auth_session(oiap_session.handle);
752 	return err;
753 }
754 
755 uint32_t tpm_oiap(uint32_t *auth_handle)
756 {
757 	const uint8_t command[10] = {
758 		0x00, 0xc1,		/* TPM_TAG */
759 		0x00, 0x00, 0x00, 0x0a,	/* parameter size */
760 		0x00, 0x00, 0x00, 0x0a,	/* TPM_COMMAND_CODE */
761 	};
762 	const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
763 	const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
764 	uint8_t response[COMMAND_BUFFER_SIZE];
765 	size_t response_length = sizeof(response);
766 	uint32_t err;
767 
768 	if (oiap_session.valid)
769 		tpm_terminate_auth_session(oiap_session.handle);
770 
771 	err = tpm_sendrecv_command(command, response, &response_length);
772 	if (err)
773 		return err;
774 	if (unpack_byte_string(response, response_length, "ds",
775 			       res_auth_handle_offset, &oiap_session.handle,
776 			       res_nonce_even_offset, &oiap_session.nonce_even,
777 			       (uint32_t)DIGEST_LENGTH))
778 		return TPM_LIB_ERROR;
779 	oiap_session.valid = 1;
780 	if (auth_handle)
781 		*auth_handle = oiap_session.handle;
782 	return 0;
783 }
784 
785 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
786 		const void *key, size_t key_length,
787 		const void *parent_key_usage_auth,
788 		uint32_t *key_handle)
789 {
790 	const uint8_t command[14] = {
791 		0x00, 0xc2,		/* TPM_TAG */
792 		0x00, 0x00, 0x00, 0x00,	/* parameter size */
793 		0x00, 0x00, 0x00, 0x41,	/* TPM_COMMAND_CODE */
794 		0x00, 0x00, 0x00, 0x00,	/* parent handle */
795 	};
796 	const size_t req_size_offset = 2;
797 	const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
798 	const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
799 	const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
800 	uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
801 			+ TPM_REQUEST_AUTH_LENGTH];
802 	uint8_t response[COMMAND_BUFFER_SIZE];
803 	size_t response_length = sizeof(response);
804 	uint32_t err;
805 
806 	if (!oiap_session.valid) {
807 		err = tpm_oiap(NULL);
808 		if (err)
809 			return err;
810 	}
811 	if (pack_byte_string(request, sizeof(request), "sdds",
812 			     0, command, sizeof(command),
813 			     req_size_offset,
814 			     sizeof(command) + key_length
815 			     + TPM_REQUEST_AUTH_LENGTH,
816 			     req_parent_handle_offset, parent_handle,
817 			     req_key_offset, key, key_length
818 		))
819 		return TPM_LIB_ERROR;
820 
821 	err = create_request_auth(request, sizeof(command) + key_length, 4,
822 				&oiap_session,
823 				request + sizeof(command) + key_length,
824 				parent_key_usage_auth);
825 	if (err)
826 		return err;
827 	err = tpm_sendrecv_command(request, response, &response_length);
828 	if (err) {
829 		if (err == TPM_AUTHFAIL)
830 			oiap_session.valid = 0;
831 		return err;
832 	}
833 
834 	err = verify_response_auth(0x00000041, response,
835 			response_length - TPM_RESPONSE_AUTH_LENGTH,
836 			4, &oiap_session,
837 			response + response_length - TPM_RESPONSE_AUTH_LENGTH,
838 			parent_key_usage_auth);
839 	if (err)
840 		return err;
841 
842 	if (key_handle) {
843 		if (unpack_byte_string(response, response_length, "d",
844 				       res_handle_offset, key_handle))
845 			return TPM_LIB_ERROR;
846 	}
847 
848 	return 0;
849 }
850 
851 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
852 			void *pubkey, size_t *pubkey_len)
853 {
854 	const uint8_t command[14] = {
855 		0x00, 0xc2,		/* TPM_TAG */
856 		0x00, 0x00, 0x00, 0x00,	/* parameter size */
857 		0x00, 0x00, 0x00, 0x21,	/* TPM_COMMAND_CODE */
858 		0x00, 0x00, 0x00, 0x00,	/* key handle */
859 	};
860 	const size_t req_size_offset = 2;
861 	const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
862 	const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
863 	uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
864 	uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
865 			+ TPM_RESPONSE_AUTH_LENGTH];
866 	size_t response_length = sizeof(response);
867 	uint32_t err;
868 
869 	if (!oiap_session.valid) {
870 		err = tpm_oiap(NULL);
871 		if (err)
872 			return err;
873 	}
874 	if (pack_byte_string(request, sizeof(request), "sdd",
875 			     0, command, sizeof(command),
876 			     req_size_offset,
877 			     (uint32_t)(sizeof(command)
878 			     + TPM_REQUEST_AUTH_LENGTH),
879 			     req_key_handle_offset, key_handle
880 		))
881 		return TPM_LIB_ERROR;
882 	err = create_request_auth(request, sizeof(command), 4, &oiap_session,
883 			request + sizeof(command), usage_auth);
884 	if (err)
885 		return err;
886 	err = tpm_sendrecv_command(request, response, &response_length);
887 	if (err) {
888 		if (err == TPM_AUTHFAIL)
889 			oiap_session.valid = 0;
890 		return err;
891 	}
892 	err = verify_response_auth(0x00000021, response,
893 			response_length - TPM_RESPONSE_AUTH_LENGTH,
894 			0, &oiap_session,
895 			response + response_length - TPM_RESPONSE_AUTH_LENGTH,
896 			usage_auth);
897 	if (err)
898 		return err;
899 
900 	if (pubkey) {
901 		if ((response_length - TPM_RESPONSE_HEADER_LENGTH
902 			- TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
903 			return TPM_LIB_ERROR;
904 		*pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
905 			- TPM_RESPONSE_AUTH_LENGTH;
906 		memcpy(pubkey, response + res_pubkey_offset,
907 		       response_length - TPM_RESPONSE_HEADER_LENGTH
908 		       - TPM_RESPONSE_AUTH_LENGTH);
909 	}
910 
911 	return 0;
912 }
913 
914 #endif /* CONFIG_TPM_AUTH_SESSIONS */
915