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