2 * Copyright (c) 2013 The Chromium OS Authors.
3 * Coypright (c) 2013 Guntermann & Drunck GmbH
5 * SPDX-License-Identifier: GPL-2.0+
12 #include <asm/unaligned.h>
13 #include <u-boot/sha1.h>
15 /* Internal error of TPM command library */
16 #define TPM_LIB_ERROR ((uint32_t)~0u)
18 /* Useful constants */
20 COMMAND_BUFFER_SIZE = 256,
22 TPM_REQUEST_HEADER_LENGTH = 10,
23 TPM_RESPONSE_HEADER_LENGTH = 10,
24 PCR_DIGEST_LENGTH = 20,
26 TPM_REQUEST_AUTH_LENGTH = 45,
27 TPM_RESPONSE_AUTH_LENGTH = 41,
28 /* some max lengths, valid for RSA keys <= 2048 bits */
29 TPM_KEY12_MAX_LENGTH = 618,
30 TPM_PUBKEY_MAX_LENGTH = 288,
33 #ifdef CONFIG_TPM_AUTH_SESSIONS
36 #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
37 #endif /* !CONFIG_SHA1 */
42 uint8_t nonce_even[DIGEST_LENGTH];
43 uint8_t nonce_odd[DIGEST_LENGTH];
46 static struct session_data oiap_session = {0, };
48 #endif /* CONFIG_TPM_AUTH_SESSIONS */
51 * Pack data into a byte string. The data types are specified in
52 * the format string: 'b' means unsigned byte, 'w' unsigned word,
53 * 'd' unsigned double word, and 's' byte string. The data are a
54 * series of offsets and values (for type byte string there are also
55 * lengths). The data values are packed into the byte string
56 * sequentially, and so a latter value could over-write a former
59 * @param str output string
60 * @param size size of output string
61 * @param format format string
62 * @param ... data points
63 * @return 0 on success, non-0 on error
65 int pack_byte_string(uint8_t *str, size_t size, const char *format, ...)
68 size_t offset = 0, length = 0;
72 va_start(args, format);
73 for (; *format; format++) {
76 offset = va_arg(args, size_t);
77 value = va_arg(args, int);
81 offset = va_arg(args, size_t);
82 value = va_arg(args, int);
86 offset = va_arg(args, size_t);
87 value = va_arg(args, uint32_t);
91 offset = va_arg(args, size_t);
92 data = va_arg(args, uint8_t *);
93 length = va_arg(args, uint32_t);
96 debug("Couldn't recognize format string\n");
100 if (offset + length > size)
108 put_unaligned_be16(value, str + offset);
111 put_unaligned_be32(value, str + offset);
114 memcpy(str + offset, data, length);
124 * Unpack data from a byte string. The data types are specified in
125 * the format string: 'b' means unsigned byte, 'w' unsigned word,
126 * 'd' unsigned double word, and 's' byte string. The data are a
127 * series of offsets and pointers (for type byte string there are also
130 * @param str output string
131 * @param size size of output string
132 * @param format format string
133 * @param ... data points
134 * @return 0 on success, non-0 on error
136 int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...)
139 size_t offset = 0, length = 0;
140 uint8_t *ptr8 = NULL;
141 uint16_t *ptr16 = NULL;
142 uint32_t *ptr32 = NULL;
144 va_start(args, format);
145 for (; *format; format++) {
148 offset = va_arg(args, size_t);
149 ptr8 = va_arg(args, uint8_t *);
153 offset = va_arg(args, size_t);
154 ptr16 = va_arg(args, uint16_t *);
158 offset = va_arg(args, size_t);
159 ptr32 = va_arg(args, uint32_t *);
163 offset = va_arg(args, size_t);
164 ptr8 = va_arg(args, uint8_t *);
165 length = va_arg(args, uint32_t);
168 debug("Couldn't recognize format string\n");
172 if (offset + length > size)
180 *ptr16 = get_unaligned_be16(str + offset);
183 *ptr32 = get_unaligned_be32(str + offset);
186 memcpy(ptr8, str + offset, length);
196 * Get TPM command size.
198 * @param command byte string of TPM command
199 * @return command size of the TPM command
201 static uint32_t tpm_command_size(const void *command)
203 const size_t command_size_offset = 2;
204 return get_unaligned_be32(command + command_size_offset);
208 * Get TPM response return code, which is one of TPM_RESULT values.
210 * @param response byte string of TPM response
211 * @return return code of the TPM response
213 static uint32_t tpm_return_code(const void *response)
215 const size_t return_code_offset = 6;
216 return get_unaligned_be32(response + return_code_offset);
220 * Send a TPM command and return response's return code, and optionally
221 * return response to caller.
223 * @param command byte string of TPM command
224 * @param response output buffer for TPM response, or NULL if the
225 * caller does not care about it
226 * @param size_ptr output buffer size (input parameter) and TPM
227 * response length (output parameter); this parameter
229 * @return return code of the TPM response
231 static uint32_t tpm_sendrecv_command(const void *command,
232 void *response, size_t *size_ptr)
234 uint8_t response_buffer[COMMAND_BUFFER_SIZE];
235 size_t response_length;
239 response_length = *size_ptr;
241 response = response_buffer;
242 response_length = sizeof(response_buffer);
248 ret = uclass_first_device(UCLASS_TPM, &dev);
251 err = tpm_xfer(dev, command, tpm_command_size(command),
252 response, &response_length);
254 err = tis_sendrecv(command, tpm_command_size(command),
255 response, &response_length);
258 return TPM_LIB_ERROR;
260 *size_ptr = response_length;
262 return tpm_return_code(response);
272 err = uclass_first_device(UCLASS_TPM, &dev);
275 return tpm_open(dev);
285 uint32_t tpm_startup(enum tpm_startup_type mode)
287 const uint8_t command[12] = {
288 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
290 const size_t mode_offset = 10;
291 uint8_t buf[COMMAND_BUFFER_SIZE];
293 if (pack_byte_string(buf, sizeof(buf), "sw",
294 0, command, sizeof(command),
296 return TPM_LIB_ERROR;
298 return tpm_sendrecv_command(buf, NULL, NULL);
301 uint32_t tpm_self_test_full(void)
303 const uint8_t command[10] = {
304 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
306 return tpm_sendrecv_command(command, NULL, NULL);
309 uint32_t tpm_continue_self_test(void)
311 const uint8_t command[10] = {
312 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
314 return tpm_sendrecv_command(command, NULL, NULL);
317 uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size)
319 const uint8_t command[101] = {
320 0x0, 0xc1, /* TPM_TAG */
321 0x0, 0x0, 0x0, 0x65, /* parameter size */
322 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
323 /* TPM_NV_DATA_PUBLIC->... */
324 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
325 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
326 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
330 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
331 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
335 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
336 /* TPM_NV_ATTRIBUTES->... */
337 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
338 0, 0, 0, 0, /* ...->attributes */
339 /* End of TPM_NV_ATTRIBUTES */
340 0, /* bReadSTClear */
341 0, /* bWriteSTClear */
342 0, /* bWriteDefine */
343 0, 0, 0, 0, /* size */
345 const size_t index_offset = 12;
346 const size_t perm_offset = 70;
347 const size_t size_offset = 77;
348 uint8_t buf[COMMAND_BUFFER_SIZE];
350 if (pack_byte_string(buf, sizeof(buf), "sddd",
351 0, command, sizeof(command),
355 return TPM_LIB_ERROR;
357 return tpm_sendrecv_command(buf, NULL, NULL);
360 uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count)
362 const uint8_t command[22] = {
363 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
365 const size_t index_offset = 10;
366 const size_t length_offset = 18;
367 const size_t data_size_offset = 10;
368 const size_t data_offset = 14;
369 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
370 size_t response_length = sizeof(response);
374 if (pack_byte_string(buf, sizeof(buf), "sdd",
375 0, command, sizeof(command),
377 length_offset, count))
378 return TPM_LIB_ERROR;
379 err = tpm_sendrecv_command(buf, response, &response_length);
382 if (unpack_byte_string(response, response_length, "d",
383 data_size_offset, &data_size))
384 return TPM_LIB_ERROR;
385 if (data_size > count)
386 return TPM_LIB_ERROR;
387 if (unpack_byte_string(response, response_length, "s",
388 data_offset, data, data_size))
389 return TPM_LIB_ERROR;
394 uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length)
396 const uint8_t command[256] = {
397 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
399 const size_t command_size_offset = 2;
400 const size_t index_offset = 10;
401 const size_t length_offset = 18;
402 const size_t data_offset = 22;
403 const size_t write_info_size = 12;
404 const uint32_t total_length =
405 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
406 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
407 size_t response_length = sizeof(response);
410 if (pack_byte_string(buf, sizeof(buf), "sddds",
411 0, command, sizeof(command),
412 command_size_offset, total_length,
414 length_offset, length,
415 data_offset, data, length))
416 return TPM_LIB_ERROR;
417 err = tpm_sendrecv_command(buf, response, &response_length);
424 uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest)
426 const uint8_t command[34] = {
427 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
429 const size_t index_offset = 10;
430 const size_t in_digest_offset = 14;
431 const size_t out_digest_offset = 10;
432 uint8_t buf[COMMAND_BUFFER_SIZE];
433 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
434 size_t response_length = sizeof(response);
437 if (pack_byte_string(buf, sizeof(buf), "sds",
438 0, command, sizeof(command),
440 in_digest_offset, in_digest,
442 return TPM_LIB_ERROR;
443 err = tpm_sendrecv_command(buf, response, &response_length);
447 if (unpack_byte_string(response, response_length, "s",
448 out_digest_offset, out_digest,
450 return TPM_LIB_ERROR;
455 uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count)
457 const uint8_t command[14] = {
458 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
460 const size_t index_offset = 10;
461 const size_t out_digest_offset = 10;
462 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
463 size_t response_length = sizeof(response);
466 if (count < PCR_DIGEST_LENGTH)
467 return TPM_LIB_ERROR;
469 if (pack_byte_string(buf, sizeof(buf), "sd",
470 0, command, sizeof(command),
471 index_offset, index))
472 return TPM_LIB_ERROR;
473 err = tpm_sendrecv_command(buf, response, &response_length);
476 if (unpack_byte_string(response, response_length, "s",
477 out_digest_offset, data, PCR_DIGEST_LENGTH))
478 return TPM_LIB_ERROR;
483 uint32_t tpm_tsc_physical_presence(uint16_t presence)
485 const uint8_t command[12] = {
486 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
488 const size_t presence_offset = 10;
489 uint8_t buf[COMMAND_BUFFER_SIZE];
491 if (pack_byte_string(buf, sizeof(buf), "sw",
492 0, command, sizeof(command),
493 presence_offset, presence))
494 return TPM_LIB_ERROR;
496 return tpm_sendrecv_command(buf, NULL, NULL);
499 uint32_t tpm_read_pubek(void *data, size_t count)
501 const uint8_t command[30] = {
502 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
504 const size_t response_size_offset = 2;
505 const size_t data_offset = 10;
506 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
507 uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
508 size_t response_length = sizeof(response);
512 err = tpm_sendrecv_command(command, response, &response_length);
515 if (unpack_byte_string(response, response_length, "d",
516 response_size_offset, &data_size))
517 return TPM_LIB_ERROR;
518 if (data_size < header_and_checksum_size)
519 return TPM_LIB_ERROR;
520 data_size -= header_and_checksum_size;
521 if (data_size > count)
522 return TPM_LIB_ERROR;
523 if (unpack_byte_string(response, response_length, "s",
524 data_offset, data, data_size))
525 return TPM_LIB_ERROR;
530 uint32_t tpm_force_clear(void)
532 const uint8_t command[10] = {
533 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
536 return tpm_sendrecv_command(command, NULL, NULL);
539 uint32_t tpm_physical_enable(void)
541 const uint8_t command[10] = {
542 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
545 return tpm_sendrecv_command(command, NULL, NULL);
548 uint32_t tpm_physical_disable(void)
550 const uint8_t command[10] = {
551 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
554 return tpm_sendrecv_command(command, NULL, NULL);
557 uint32_t tpm_physical_set_deactivated(uint8_t state)
559 const uint8_t command[11] = {
560 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
562 const size_t state_offset = 10;
563 uint8_t buf[COMMAND_BUFFER_SIZE];
565 if (pack_byte_string(buf, sizeof(buf), "sb",
566 0, command, sizeof(command),
567 state_offset, state))
568 return TPM_LIB_ERROR;
570 return tpm_sendrecv_command(buf, NULL, NULL);
573 uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
574 void *cap, size_t count)
576 const uint8_t command[22] = {
577 0x0, 0xc1, /* TPM_TAG */
578 0x0, 0x0, 0x0, 0x16, /* parameter size */
579 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
580 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
581 0x0, 0x0, 0x0, 0x4, /* subcap size */
582 0x0, 0x0, 0x0, 0x0, /* subcap value */
584 const size_t cap_area_offset = 10;
585 const size_t sub_cap_offset = 18;
586 const size_t cap_offset = 14;
587 const size_t cap_size_offset = 10;
588 uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
589 size_t response_length = sizeof(response);
593 if (pack_byte_string(buf, sizeof(buf), "sdd",
594 0, command, sizeof(command),
595 cap_area_offset, cap_area,
596 sub_cap_offset, sub_cap))
597 return TPM_LIB_ERROR;
598 err = tpm_sendrecv_command(buf, response, &response_length);
601 if (unpack_byte_string(response, response_length, "d",
602 cap_size_offset, &cap_size))
603 return TPM_LIB_ERROR;
604 if (cap_size > response_length || cap_size > count)
605 return TPM_LIB_ERROR;
606 if (unpack_byte_string(response, response_length, "s",
607 cap_offset, cap, cap_size))
608 return TPM_LIB_ERROR;
613 #ifdef CONFIG_TPM_AUTH_SESSIONS
616 * Fill an authentication block in a request.
617 * This func can create the first as well as the second auth block (for
618 * double authorized commands).
620 * @param request pointer to the request (w/ uninitialised auth data)
621 * @param request_len0 length of the request without auth data
622 * @param handles_len length of the handles area in request
623 * @param auth_session pointer to the (valid) auth session to be used
624 * @param request_auth pointer to the auth block of the request to be filled
625 * @param auth authentication data (HMAC key)
627 static uint32_t create_request_auth(const void *request, size_t request_len0,
629 struct session_data *auth_session,
630 void *request_auth, const void *auth)
632 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
633 sha1_context hash_ctx;
634 const size_t command_code_offset = 6;
635 const size_t auth_nonce_odd_offset = 4;
636 const size_t auth_continue_offset = 24;
637 const size_t auth_auth_offset = 25;
639 if (!auth_session || !auth_session->valid)
640 return TPM_LIB_ERROR;
642 sha1_starts(&hash_ctx);
643 sha1_update(&hash_ctx, request + command_code_offset, 4);
644 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
645 sha1_update(&hash_ctx,
646 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
647 request_len0 - TPM_REQUEST_HEADER_LENGTH
649 sha1_finish(&hash_ctx, hmac_data);
651 sha1_starts(&hash_ctx);
652 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
653 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
654 sha1_finish(&hash_ctx, auth_session->nonce_odd);
656 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
657 0, auth_session->handle,
658 auth_nonce_odd_offset, auth_session->nonce_odd,
660 auth_continue_offset, 1))
661 return TPM_LIB_ERROR;
662 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
664 auth_session->nonce_even,
667 request_auth + auth_nonce_odd_offset,
669 return TPM_LIB_ERROR;
670 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
671 request_auth + auth_auth_offset);
677 * Verify an authentication block in a response.
678 * Since this func updates the nonce_even in the session data it has to be
679 * called when receiving a succesfull AUTH response.
680 * This func can verify the first as well as the second auth block (for
681 * double authorized commands).
683 * @param command_code command code of the request
684 * @param response pointer to the request (w/ uninitialised auth data)
685 * @param handles_len length of the handles area in response
686 * @param auth_session pointer to the (valid) auth session to be used
687 * @param response_auth pointer to the auth block of the response to be verified
688 * @param auth authentication data (HMAC key)
690 static uint32_t verify_response_auth(uint32_t command_code,
691 const void *response, size_t response_len0,
693 struct session_data *auth_session,
694 const void *response_auth, const void *auth)
696 uint8_t hmac_data[DIGEST_LENGTH * 3 + 1];
697 uint8_t computed_auth[DIGEST_LENGTH];
698 sha1_context hash_ctx;
699 const size_t return_code_offset = 6;
700 const size_t auth_continue_offset = 20;
701 const size_t auth_auth_offset = 21;
702 uint8_t auth_continue;
704 if (!auth_session || !auth_session->valid)
706 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
708 return TPM_LIB_ERROR;
709 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
710 return TPM_LIB_ERROR;
712 sha1_starts(&hash_ctx);
713 sha1_update(&hash_ctx, response + return_code_offset, 4);
714 sha1_update(&hash_ctx, hmac_data, 4);
715 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
716 sha1_update(&hash_ctx,
717 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
718 response_len0 - TPM_RESPONSE_HEADER_LENGTH
720 sha1_finish(&hash_ctx, hmac_data);
722 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
723 auth_continue = ((uint8_t *)response_auth)[auth_continue_offset];
724 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
729 auth_session->nonce_odd,
733 return TPM_LIB_ERROR;
735 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
738 if (memcmp(computed_auth, response_auth + auth_auth_offset,
746 uint32_t tpm_terminate_auth_session(uint32_t auth_handle)
748 const uint8_t command[18] = {
749 0x00, 0xc1, /* TPM_TAG */
750 0x00, 0x00, 0x00, 0x00, /* parameter size */
751 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
752 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
753 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */
755 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
756 uint8_t request[COMMAND_BUFFER_SIZE];
758 if (pack_byte_string(request, sizeof(request), "sd",
759 0, command, sizeof(command),
760 req_handle_offset, auth_handle))
761 return TPM_LIB_ERROR;
762 if (oiap_session.valid && oiap_session.handle == auth_handle)
763 oiap_session.valid = 0;
765 return tpm_sendrecv_command(request, NULL, NULL);
768 uint32_t tpm_end_oiap(void)
770 uint32_t err = TPM_SUCCESS;
771 if (oiap_session.valid)
772 err = tpm_terminate_auth_session(oiap_session.handle);
776 uint32_t tpm_oiap(uint32_t *auth_handle)
778 const uint8_t command[10] = {
779 0x00, 0xc1, /* TPM_TAG */
780 0x00, 0x00, 0x00, 0x0a, /* parameter size */
781 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
783 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
784 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
785 uint8_t response[COMMAND_BUFFER_SIZE];
786 size_t response_length = sizeof(response);
789 if (oiap_session.valid)
790 tpm_terminate_auth_session(oiap_session.handle);
792 err = tpm_sendrecv_command(command, response, &response_length);
795 if (unpack_byte_string(response, response_length, "ds",
796 res_auth_handle_offset, &oiap_session.handle,
797 res_nonce_even_offset, &oiap_session.nonce_even,
798 (uint32_t)DIGEST_LENGTH))
799 return TPM_LIB_ERROR;
800 oiap_session.valid = 1;
802 *auth_handle = oiap_session.handle;
806 uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
807 const void *key, size_t key_length,
808 const void *parent_key_usage_auth,
809 uint32_t *key_handle)
811 const uint8_t command[14] = {
812 0x00, 0xc2, /* TPM_TAG */
813 0x00, 0x00, 0x00, 0x00, /* parameter size */
814 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
815 0x00, 0x00, 0x00, 0x00, /* parent handle */
817 const size_t req_size_offset = 2;
818 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
819 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
820 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
821 uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH
822 + TPM_REQUEST_AUTH_LENGTH];
823 uint8_t response[COMMAND_BUFFER_SIZE];
824 size_t response_length = sizeof(response);
827 if (!oiap_session.valid) {
828 err = tpm_oiap(NULL);
832 if (pack_byte_string(request, sizeof(request), "sdds",
833 0, command, sizeof(command),
835 sizeof(command) + key_length
836 + TPM_REQUEST_AUTH_LENGTH,
837 req_parent_handle_offset, parent_handle,
838 req_key_offset, key, key_length
840 return TPM_LIB_ERROR;
842 err = create_request_auth(request, sizeof(command) + key_length, 4,
844 request + sizeof(command) + key_length,
845 parent_key_usage_auth);
848 err = tpm_sendrecv_command(request, response, &response_length);
850 if (err == TPM_AUTHFAIL)
851 oiap_session.valid = 0;
855 err = verify_response_auth(0x00000041, response,
856 response_length - TPM_RESPONSE_AUTH_LENGTH,
858 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
859 parent_key_usage_auth);
864 if (unpack_byte_string(response, response_length, "d",
865 res_handle_offset, key_handle))
866 return TPM_LIB_ERROR;
872 uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
873 void *pubkey, size_t *pubkey_len)
875 const uint8_t command[14] = {
876 0x00, 0xc2, /* TPM_TAG */
877 0x00, 0x00, 0x00, 0x00, /* parameter size */
878 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
879 0x00, 0x00, 0x00, 0x00, /* key handle */
881 const size_t req_size_offset = 2;
882 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
883 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
884 uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
885 uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH
886 + TPM_RESPONSE_AUTH_LENGTH];
887 size_t response_length = sizeof(response);
890 if (!oiap_session.valid) {
891 err = tpm_oiap(NULL);
895 if (pack_byte_string(request, sizeof(request), "sdd",
896 0, command, sizeof(command),
898 (uint32_t)(sizeof(command)
899 + TPM_REQUEST_AUTH_LENGTH),
900 req_key_handle_offset, key_handle
902 return TPM_LIB_ERROR;
903 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
904 request + sizeof(command), usage_auth);
907 err = tpm_sendrecv_command(request, response, &response_length);
909 if (err == TPM_AUTHFAIL)
910 oiap_session.valid = 0;
913 err = verify_response_auth(0x00000021, response,
914 response_length - TPM_RESPONSE_AUTH_LENGTH,
916 response + response_length - TPM_RESPONSE_AUTH_LENGTH,
922 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
923 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
924 return TPM_LIB_ERROR;
925 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
926 - TPM_RESPONSE_AUTH_LENGTH;
927 memcpy(pubkey, response + res_pubkey_offset,
928 response_length - TPM_RESPONSE_HEADER_LENGTH
929 - TPM_RESPONSE_AUTH_LENGTH);
935 #endif /* CONFIG_TPM_AUTH_SESSIONS */