2 * Copyright (c) 2013 The Chromium OS Authors.
3 * Coypright (c) 2013 Guntermann & Drunck GmbH
5 * SPDX-License-Identifier: GPL-2.0+
10 #include <u-boot/sha1.h>
12 #include <asm/unaligned.h>
14 /* Internal error of TPM command library */
15 #define TPM_LIB_ERROR ((uint32_t)~0u)
17 /* Useful constants */
19 COMMAND_BUFFER_SIZE = 256,
21 TPM_REQUEST_HEADER_LENGTH = 10,
22 TPM_RESPONSE_HEADER_LENGTH = 10,
23 PCR_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,
32 #ifdef CONFIG_TPM_AUTH_SESSIONS
35 #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
36 #endif /* !CONFIG_SHA1 */
41 uint8_t nonce_even[DIGEST_LENGTH];
42 uint8_t nonce_odd[DIGEST_LENGTH];
45 static struct session_data oiap_session = {0, };
47 #endif /* CONFIG_TPM_AUTH_SESSIONS */
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
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
64 int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
67 size_t offset = 0, length = 0;
71 va_start(args, format);
72 for (; *format; format++) {
75 offset = va_arg(args, size_t);
76 value = va_arg(args, int);
80 offset = va_arg(args, size_t);
81 value = va_arg(args, int);
85 offset = va_arg(args, size_t);
86 value = va_arg(args, uint32_t);
90 offset = va_arg(args, size_t);
91 data = va_arg(args, uint8_t *);
92 length = va_arg(args, uint32_t);
95 debug("Couldn't recognize format string\n");
99 if (offset + length > size)
107 put_unaligned_be16(value, str + offset);
110 put_unaligned_be32(value, str + offset);
113 memcpy(str + offset, data, length);
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
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
135 int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
138 size_t offset = 0, length = 0;
139 uint8_t *ptr8 = NULL;
140 uint16_t *ptr16 = NULL;
141 uint32_t *ptr32 = NULL;
143 va_start(args, format);
144 for (; *format; format++) {
147 offset = va_arg(args, size_t);
148 ptr8 = va_arg(args, uint8_t *);
152 offset = va_arg(args, size_t);
153 ptr16 = va_arg(args, uint16_t *);
157 offset = va_arg(args, size_t);
158 ptr32 = va_arg(args, uint32_t *);
162 offset = va_arg(args, size_t);
163 ptr8 = va_arg(args, uint8_t *);
164 length = va_arg(args, uint32_t);
167 debug("Couldn't recognize format string\n");
171 if (offset + length > size)
179 *ptr16 = get_unaligned_be16(str + offset);
182 *ptr32 = get_unaligned_be32(str + offset);
185 memcpy(ptr8, str + offset, length);
195 * Get TPM command size.
197 * @param command byte string of TPM command
198 * @return command size of the TPM command
200 static uint32_t tpm_command_size(const void *command)
202 const size_t command_size_offset = 2;
203 return get_unaligned_be32(command + command_size_offset);
207 * Get TPM response return code, which is one of TPM_RESULT values.
209 * @param response byte string of TPM response
210 * @return return code of the TPM response
212 static uint32_t tpm_return_code(const void *response)
214 const size_t return_code_offset = 6;
215 return get_unaligned_be32(response + return_code_offset);
219 * Send a TPM command and return response's return code, and optionally
220 * return response to caller.
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
228 * @return return code of the TPM response
230 static uint32_t tpm_sendrecv_command(const void *command,
231 void *response, size_t *size_ptr)
233 uint8_t response_buffer[COMMAND_BUFFER_SIZE];
234 size_t response_length;
238 response_length = *size_ptr;
240 response = response_buffer;
241 response_length = sizeof(response_buffer);
243 err = tis_sendrecv(command, tpm_command_size(command),
244 response, &response_length);
246 return TPM_LIB_ERROR;
248 *size_ptr = response_length;
250 return tpm_return_code(response);
253 uint32_t tpm_init(void)
264 uint32_t tpm_startup(enum tpm_startup_type mode)
266 const uint8_t command[12] = {
267 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
269 const size_t mode_offset = 10;
270 uint8_t buf[COMMAND_BUFFER_SIZE];
272 if (pack_byte_string(buf, sizeof(buf), "sw",
273 0, command, sizeof(command),
275 return TPM_LIB_ERROR;
277 return tpm_sendrecv_command(buf, NULL, NULL);
280 uint32_t tpm_self_test_full(void)
282 const uint8_t command[10] = {
283 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
285 return tpm_sendrecv_command(command, NULL, NULL);
288 uint32_t tpm_continue_self_test(void)
290 const uint8_t command[10] = {
291 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
293 return tpm_sendrecv_command(command, NULL, NULL);
296 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
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 */
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 */
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 */
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];
329 if (pack_byte_string(buf, sizeof(buf), "sddd",
330 0, command, sizeof(command),
334 return TPM_LIB_ERROR;
336 return tpm_sendrecv_command(buf, NULL, NULL);
339 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
341 const uint8_t command[22] = {
342 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
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);
353 if (pack_byte_string(buf, sizeof(buf), "sdd",
354 0, command, sizeof(command),
356 length_offset, count))
357 return TPM_LIB_ERROR;
358 err = tpm_sendrecv_command(buf, response, &response_length);
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;
373 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
375 const uint8_t command[256] = {
376 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
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);
389 if (pack_byte_string(buf, sizeof(buf), "sddds",
390 0, command, sizeof(command),
391 command_size_offset, total_length,
393 length_offset, length,
394 data_offset, data, length))
395 return TPM_LIB_ERROR;
396 err = tpm_sendrecv_command(buf, response, &response_length);
403 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
405 const uint8_t command[34] = {
406 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
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);
416 if (pack_byte_string(buf, sizeof(buf), "sds",
417 0, command, sizeof(command),
419 in_digest_offset, in_digest,
421 return TPM_LIB_ERROR;
422 err = tpm_sendrecv_command(buf, response, &response_length);
426 if (unpack_byte_string(response, response_length, "s",
427 out_digest_offset, out_digest,
429 return TPM_LIB_ERROR;
434 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
436 const uint8_t command[14] = {
437 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
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);
445 if (count < PCR_DIGEST_LENGTH)
446 return TPM_LIB_ERROR;
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);
455 if (unpack_byte_string(response, response_length, "s",
456 out_digest_offset, data, PCR_DIGEST_LENGTH))
457 return TPM_LIB_ERROR;
462 uint32_t tpm_tsc_physical_presence(uint16_t presence)
464 const uint8_t command[12] = {
465 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
467 const size_t presence_offset = 10;
468 uint8_t buf[COMMAND_BUFFER_SIZE];
470 if (pack_byte_string(buf, sizeof(buf), "sw",
471 0, command, sizeof(command),
472 presence_offset, presence))
473 return TPM_LIB_ERROR;
475 return tpm_sendrecv_command(buf, NULL, NULL);
478 uint32_t tpm_read_pubek(void *data, size_t count)
480 const uint8_t command[30] = {
481 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
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);
491 err = tpm_sendrecv_command(command, response, &response_length);
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;
509 uint32_t tpm_force_clear(void)
511 const uint8_t command[10] = {
512 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
515 return tpm_sendrecv_command(command, NULL, NULL);
518 uint32_t tpm_physical_enable(void)
520 const uint8_t command[10] = {
521 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
524 return tpm_sendrecv_command(command, NULL, NULL);
527 uint32_t tpm_physical_disable(void)
529 const uint8_t command[10] = {
530 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
533 return tpm_sendrecv_command(command, NULL, NULL);
536 uint32_t tpm_physical_set_deactivated(uint8_t state)
538 const uint8_t command[11] = {
539 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
541 const size_t state_offset = 10;
542 uint8_t buf[COMMAND_BUFFER_SIZE];
544 if (pack_byte_string(buf, sizeof(buf), "sb",
545 0, command, sizeof(command),
546 state_offset, state))
547 return TPM_LIB_ERROR;
549 return tpm_sendrecv_command(buf, NULL, NULL);
552 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
553 void *cap, size_t count)
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 */
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);
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);
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;
592 #ifdef CONFIG_TPM_AUTH_SESSIONS
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).
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)
606 static uint32_t create_request_auth(const void *request, size_t request_len0,
608 struct session_data *auth_session,
609 void *request_auth, const void *auth)
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;
618 if (!auth_session || !auth_session->valid)
619 return TPM_LIB_ERROR;
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
628 sha1_finish(&hash_ctx, hmac_data);
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);
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,
639 auth_continue_offset, 1))
640 return TPM_LIB_ERROR;
641 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
643 auth_session->nonce_even,
646 request_auth + auth_nonce_odd_offset,
648 return TPM_LIB_ERROR;
649 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
650 request_auth + auth_auth_offset);
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).
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)
669 static uint32_t verify_response_auth(uint32_t command_code,
670 const void *response, size_t response_len0,
672 struct session_data *auth_session,
673 const void *response_auth, const void *auth)
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;
683 if (!auth_session || !auth_session->valid)
685 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
687 return TPM_LIB_ERROR;
688 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
689 return TPM_LIB_ERROR;
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
699 sha1_finish(&hash_ctx, hmac_data);
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",
708 auth_session->nonce_odd,
712 return TPM_LIB_ERROR;
714 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
717 if (memcmp(computed_auth, response_auth + auth_auth_offset,
725 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
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 */
734 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
735 uint8_t request[COMMAND_BUFFER_SIZE];
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;
744 return tpm_sendrecv_command(request, NULL, NULL);
747 uint32_t tpm_end_oiap(void)
749 uint32_t err = TPM_SUCCESS;
750 if (oiap_session.valid)
751 err = tpm_terminate_auth_session(oiap_session.handle);
755 uint32_t tpm_oiap(uint32_t *auth_handle)
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 */
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);
768 if (oiap_session.valid)
769 tpm_terminate_auth_session(oiap_session.handle);
771 err = tpm_sendrecv_command(command, response, &response_length);
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;
781 *auth_handle = oiap_session.handle;
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)
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 */
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);
806 if (!oiap_session.valid) {
807 err = tpm_oiap(NULL);
811 if (pack_byte_string(request, sizeof(request), "sdds",
812 0, command, sizeof(command),
814 sizeof(command) + key_length
815 + TPM_REQUEST_AUTH_LENGTH,
816 req_parent_handle_offset, parent_handle,
817 req_key_offset, key, key_length
819 return TPM_LIB_ERROR;
821 err = create_request_auth(request, sizeof(command) + key_length, 4,
823 request + sizeof(command) + key_length,
824 parent_key_usage_auth);
827 err = tpm_sendrecv_command(request, response, &response_length);
829 if (err == TPM_AUTHFAIL)
830 oiap_session.valid = 0;
834 err = verify_response_auth(0x00000041, response,
835 response_length - TPM_RESPONSE_AUTH_LENGTH,
837 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
838 parent_key_usage_auth);
843 if (unpack_byte_string(response, response_length, "d",
844 res_handle_offset, key_handle))
845 return TPM_LIB_ERROR;
851 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
852 void *pubkey, size_t *pubkey_len)
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 */
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);
869 if (!oiap_session.valid) {
870 err = tpm_oiap(NULL);
874 if (pack_byte_string(request, sizeof(request), "sdd",
875 0, command, sizeof(command),
877 (uint32_t)(sizeof(command)
878 + TPM_REQUEST_AUTH_LENGTH),
879 req_key_handle_offset, key_handle
881 return TPM_LIB_ERROR;
882 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
883 request + sizeof(command), usage_auth);
886 err = tpm_sendrecv_command(request, response, &response_length);
888 if (err == TPM_AUTHFAIL)
889 oiap_session.valid = 0;
892 err = verify_response_auth(0x00000021, response,
893 response_length - TPM_RESPONSE_AUTH_LENGTH,
895 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
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);
914 #endif /* CONFIG_TPM_AUTH_SESSIONS */