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