18732b070SChe-liang Chiou /* 28732b070SChe-liang Chiou * Copyright (c) 2013 The Chromium OS Authors. 3*be6c1529SReinhard Pfau * Coypright (c) 2013 Guntermann & Drunck GmbH 48732b070SChe-liang Chiou * 58732b070SChe-liang Chiou * See file CREDITS for list of people who contributed to this 68732b070SChe-liang Chiou * project. 78732b070SChe-liang Chiou * 88732b070SChe-liang Chiou * This program is free software; you can redistribute it and/or 98732b070SChe-liang Chiou * modify it under the terms of the GNU General Public License as 108732b070SChe-liang Chiou * published by the Free Software Foundation; either version 2 of 118732b070SChe-liang Chiou * the License, or (at your option) any later version. 128732b070SChe-liang Chiou * 138732b070SChe-liang Chiou * This program is distributed in the hope that it will be useful, 148732b070SChe-liang Chiou * but WITHOUT ANY WARRANTY; without even the implied warranty of 158732b070SChe-liang Chiou * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 168732b070SChe-liang Chiou * GNU General Public License for more details. 178732b070SChe-liang Chiou * 188732b070SChe-liang Chiou * You should have received a copy of the GNU General Public License 198732b070SChe-liang Chiou * along with this program; if not, write to the Free Software 208732b070SChe-liang Chiou * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 218732b070SChe-liang Chiou * MA 02111-1307 USA 228732b070SChe-liang Chiou */ 238732b070SChe-liang Chiou 248732b070SChe-liang Chiou #include <common.h> 258732b070SChe-liang Chiou #include <stdarg.h> 26*be6c1529SReinhard Pfau #include <sha1.h> 278732b070SChe-liang Chiou #include <tpm.h> 288732b070SChe-liang Chiou #include <asm/unaligned.h> 298732b070SChe-liang Chiou 308732b070SChe-liang Chiou /* Internal error of TPM command library */ 318732b070SChe-liang Chiou #define TPM_LIB_ERROR ((uint32_t)~0u) 328732b070SChe-liang Chiou 338732b070SChe-liang Chiou /* Useful constants */ 348732b070SChe-liang Chiou enum { 358732b070SChe-liang Chiou COMMAND_BUFFER_SIZE = 256, 368732b070SChe-liang Chiou TPM_PUBEK_SIZE = 256, 378732b070SChe-liang Chiou TPM_REQUEST_HEADER_LENGTH = 10, 388732b070SChe-liang Chiou TPM_RESPONSE_HEADER_LENGTH = 10, 398732b070SChe-liang Chiou PCR_DIGEST_LENGTH = 20, 40*be6c1529SReinhard Pfau DIGEST_LENGTH = 20, 41*be6c1529SReinhard Pfau TPM_REQUEST_AUTH_LENGTH = 45, 42*be6c1529SReinhard Pfau TPM_RESPONSE_AUTH_LENGTH = 41, 43*be6c1529SReinhard Pfau /* some max lengths, valid for RSA keys <= 2048 bits */ 44*be6c1529SReinhard Pfau TPM_KEY12_MAX_LENGTH = 618, 45*be6c1529SReinhard Pfau TPM_PUBKEY_MAX_LENGTH = 288, 468732b070SChe-liang Chiou }; 478732b070SChe-liang Chiou 48*be6c1529SReinhard Pfau #ifdef CONFIG_TPM_AUTH_SESSIONS 49*be6c1529SReinhard Pfau 50*be6c1529SReinhard Pfau #ifndef CONFIG_SHA1 51*be6c1529SReinhard Pfau #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too" 52*be6c1529SReinhard Pfau #endif /* !CONFIG_SHA1 */ 53*be6c1529SReinhard Pfau 54*be6c1529SReinhard Pfau struct session_data { 55*be6c1529SReinhard Pfau int valid; 56*be6c1529SReinhard Pfau uint32_t handle; 57*be6c1529SReinhard Pfau uint8_t nonce_even[DIGEST_LENGTH]; 58*be6c1529SReinhard Pfau uint8_t nonce_odd[DIGEST_LENGTH]; 59*be6c1529SReinhard Pfau }; 60*be6c1529SReinhard Pfau 61*be6c1529SReinhard Pfau static struct session_data oiap_session = {0, }; 62*be6c1529SReinhard Pfau 63*be6c1529SReinhard Pfau #endif /* CONFIG_TPM_AUTH_SESSIONS */ 64*be6c1529SReinhard Pfau 658732b070SChe-liang Chiou /** 668732b070SChe-liang Chiou * Pack data into a byte string. The data types are specified in 678732b070SChe-liang Chiou * the format string: 'b' means unsigned byte, 'w' unsigned word, 688732b070SChe-liang Chiou * 'd' unsigned double word, and 's' byte string. The data are a 698732b070SChe-liang Chiou * series of offsets and values (for type byte string there are also 708732b070SChe-liang Chiou * lengths). The data values are packed into the byte string 718732b070SChe-liang Chiou * sequentially, and so a latter value could over-write a former 728732b070SChe-liang Chiou * value. 738732b070SChe-liang Chiou * 748732b070SChe-liang Chiou * @param str output string 758732b070SChe-liang Chiou * @param size size of output string 768732b070SChe-liang Chiou * @param format format string 778732b070SChe-liang Chiou * @param ... data points 788732b070SChe-liang Chiou * @return 0 on success, non-0 on error 798732b070SChe-liang Chiou */ 808732b070SChe-liang Chiou int pack_byte_string(uint8_t *str, size_t size, const char *format, ...) 818732b070SChe-liang Chiou { 828732b070SChe-liang Chiou va_list args; 838732b070SChe-liang Chiou size_t offset = 0, length = 0; 848732b070SChe-liang Chiou uint8_t *data = NULL; 858732b070SChe-liang Chiou uint32_t value = 0; 868732b070SChe-liang Chiou 878732b070SChe-liang Chiou va_start(args, format); 888732b070SChe-liang Chiou for (; *format; format++) { 898732b070SChe-liang Chiou switch (*format) { 908732b070SChe-liang Chiou case 'b': 918732b070SChe-liang Chiou offset = va_arg(args, size_t); 928732b070SChe-liang Chiou value = va_arg(args, int); 938732b070SChe-liang Chiou length = 1; 948732b070SChe-liang Chiou break; 958732b070SChe-liang Chiou case 'w': 968732b070SChe-liang Chiou offset = va_arg(args, size_t); 978732b070SChe-liang Chiou value = va_arg(args, int); 988732b070SChe-liang Chiou length = 2; 998732b070SChe-liang Chiou break; 1008732b070SChe-liang Chiou case 'd': 1018732b070SChe-liang Chiou offset = va_arg(args, size_t); 1028732b070SChe-liang Chiou value = va_arg(args, uint32_t); 1038732b070SChe-liang Chiou length = 4; 1048732b070SChe-liang Chiou break; 1058732b070SChe-liang Chiou case 's': 1068732b070SChe-liang Chiou offset = va_arg(args, size_t); 1078732b070SChe-liang Chiou data = va_arg(args, uint8_t *); 1088732b070SChe-liang Chiou length = va_arg(args, uint32_t); 1098732b070SChe-liang Chiou break; 1108732b070SChe-liang Chiou default: 1118732b070SChe-liang Chiou debug("Couldn't recognize format string\n"); 1128732b070SChe-liang Chiou return -1; 1138732b070SChe-liang Chiou } 1148732b070SChe-liang Chiou 1158732b070SChe-liang Chiou if (offset + length > size) 1168732b070SChe-liang Chiou return -1; 1178732b070SChe-liang Chiou 1188732b070SChe-liang Chiou switch (*format) { 1198732b070SChe-liang Chiou case 'b': 1208732b070SChe-liang Chiou str[offset] = value; 1218732b070SChe-liang Chiou break; 1228732b070SChe-liang Chiou case 'w': 1238732b070SChe-liang Chiou put_unaligned_be16(value, str + offset); 1248732b070SChe-liang Chiou break; 1258732b070SChe-liang Chiou case 'd': 1268732b070SChe-liang Chiou put_unaligned_be32(value, str + offset); 1278732b070SChe-liang Chiou break; 1288732b070SChe-liang Chiou case 's': 1298732b070SChe-liang Chiou memcpy(str + offset, data, length); 1308732b070SChe-liang Chiou break; 1318732b070SChe-liang Chiou } 1328732b070SChe-liang Chiou } 1338732b070SChe-liang Chiou va_end(args); 1348732b070SChe-liang Chiou 1358732b070SChe-liang Chiou return 0; 1368732b070SChe-liang Chiou } 1378732b070SChe-liang Chiou 1388732b070SChe-liang Chiou /** 1398732b070SChe-liang Chiou * Unpack data from a byte string. The data types are specified in 1408732b070SChe-liang Chiou * the format string: 'b' means unsigned byte, 'w' unsigned word, 1418732b070SChe-liang Chiou * 'd' unsigned double word, and 's' byte string. The data are a 1428732b070SChe-liang Chiou * series of offsets and pointers (for type byte string there are also 1438732b070SChe-liang Chiou * lengths). 1448732b070SChe-liang Chiou * 1458732b070SChe-liang Chiou * @param str output string 1468732b070SChe-liang Chiou * @param size size of output string 1478732b070SChe-liang Chiou * @param format format string 1488732b070SChe-liang Chiou * @param ... data points 1498732b070SChe-liang Chiou * @return 0 on success, non-0 on error 1508732b070SChe-liang Chiou */ 1518732b070SChe-liang Chiou int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...) 1528732b070SChe-liang Chiou { 1538732b070SChe-liang Chiou va_list args; 1548732b070SChe-liang Chiou size_t offset = 0, length = 0; 1558732b070SChe-liang Chiou uint8_t *ptr8 = NULL; 1568732b070SChe-liang Chiou uint16_t *ptr16 = NULL; 1578732b070SChe-liang Chiou uint32_t *ptr32 = NULL; 1588732b070SChe-liang Chiou 1598732b070SChe-liang Chiou va_start(args, format); 1608732b070SChe-liang Chiou for (; *format; format++) { 1618732b070SChe-liang Chiou switch (*format) { 1628732b070SChe-liang Chiou case 'b': 1638732b070SChe-liang Chiou offset = va_arg(args, size_t); 1648732b070SChe-liang Chiou ptr8 = va_arg(args, uint8_t *); 1658732b070SChe-liang Chiou length = 1; 1668732b070SChe-liang Chiou break; 1678732b070SChe-liang Chiou case 'w': 1688732b070SChe-liang Chiou offset = va_arg(args, size_t); 1698732b070SChe-liang Chiou ptr16 = va_arg(args, uint16_t *); 1708732b070SChe-liang Chiou length = 2; 1718732b070SChe-liang Chiou break; 1728732b070SChe-liang Chiou case 'd': 1738732b070SChe-liang Chiou offset = va_arg(args, size_t); 1748732b070SChe-liang Chiou ptr32 = va_arg(args, uint32_t *); 1758732b070SChe-liang Chiou length = 4; 1768732b070SChe-liang Chiou break; 1778732b070SChe-liang Chiou case 's': 1788732b070SChe-liang Chiou offset = va_arg(args, size_t); 1798732b070SChe-liang Chiou ptr8 = va_arg(args, uint8_t *); 1808732b070SChe-liang Chiou length = va_arg(args, uint32_t); 1818732b070SChe-liang Chiou break; 1828732b070SChe-liang Chiou default: 1838732b070SChe-liang Chiou debug("Couldn't recognize format string\n"); 1848732b070SChe-liang Chiou return -1; 1858732b070SChe-liang Chiou } 1868732b070SChe-liang Chiou 1878732b070SChe-liang Chiou if (offset + length > size) 1888732b070SChe-liang Chiou return -1; 1898732b070SChe-liang Chiou 1908732b070SChe-liang Chiou switch (*format) { 1918732b070SChe-liang Chiou case 'b': 1928732b070SChe-liang Chiou *ptr8 = str[offset]; 1938732b070SChe-liang Chiou break; 1948732b070SChe-liang Chiou case 'w': 1958732b070SChe-liang Chiou *ptr16 = get_unaligned_be16(str + offset); 1968732b070SChe-liang Chiou break; 1978732b070SChe-liang Chiou case 'd': 1988732b070SChe-liang Chiou *ptr32 = get_unaligned_be32(str + offset); 1998732b070SChe-liang Chiou break; 2008732b070SChe-liang Chiou case 's': 2018732b070SChe-liang Chiou memcpy(ptr8, str + offset, length); 2028732b070SChe-liang Chiou break; 2038732b070SChe-liang Chiou } 2048732b070SChe-liang Chiou } 2058732b070SChe-liang Chiou va_end(args); 2068732b070SChe-liang Chiou 2078732b070SChe-liang Chiou return 0; 2088732b070SChe-liang Chiou } 2098732b070SChe-liang Chiou 2108732b070SChe-liang Chiou /** 2118732b070SChe-liang Chiou * Get TPM command size. 2128732b070SChe-liang Chiou * 2138732b070SChe-liang Chiou * @param command byte string of TPM command 2148732b070SChe-liang Chiou * @return command size of the TPM command 2158732b070SChe-liang Chiou */ 2168732b070SChe-liang Chiou static uint32_t tpm_command_size(const void *command) 2178732b070SChe-liang Chiou { 2188732b070SChe-liang Chiou const size_t command_size_offset = 2; 2198732b070SChe-liang Chiou return get_unaligned_be32(command + command_size_offset); 2208732b070SChe-liang Chiou } 2218732b070SChe-liang Chiou 2228732b070SChe-liang Chiou /** 2238732b070SChe-liang Chiou * Get TPM response return code, which is one of TPM_RESULT values. 2248732b070SChe-liang Chiou * 2258732b070SChe-liang Chiou * @param response byte string of TPM response 2268732b070SChe-liang Chiou * @return return code of the TPM response 2278732b070SChe-liang Chiou */ 2288732b070SChe-liang Chiou static uint32_t tpm_return_code(const void *response) 2298732b070SChe-liang Chiou { 2308732b070SChe-liang Chiou const size_t return_code_offset = 6; 2318732b070SChe-liang Chiou return get_unaligned_be32(response + return_code_offset); 2328732b070SChe-liang Chiou } 2338732b070SChe-liang Chiou 2348732b070SChe-liang Chiou /** 2358732b070SChe-liang Chiou * Send a TPM command and return response's return code, and optionally 2368732b070SChe-liang Chiou * return response to caller. 2378732b070SChe-liang Chiou * 2388732b070SChe-liang Chiou * @param command byte string of TPM command 2398732b070SChe-liang Chiou * @param response output buffer for TPM response, or NULL if the 2408732b070SChe-liang Chiou * caller does not care about it 2418732b070SChe-liang Chiou * @param size_ptr output buffer size (input parameter) and TPM 2428732b070SChe-liang Chiou * response length (output parameter); this parameter 2438732b070SChe-liang Chiou * is a bidirectional 2448732b070SChe-liang Chiou * @return return code of the TPM response 2458732b070SChe-liang Chiou */ 2468732b070SChe-liang Chiou static uint32_t tpm_sendrecv_command(const void *command, 2478732b070SChe-liang Chiou void *response, size_t *size_ptr) 2488732b070SChe-liang Chiou { 2498732b070SChe-liang Chiou uint8_t response_buffer[COMMAND_BUFFER_SIZE]; 2508732b070SChe-liang Chiou size_t response_length; 2518732b070SChe-liang Chiou uint32_t err; 2528732b070SChe-liang Chiou 2538732b070SChe-liang Chiou if (response) { 2548732b070SChe-liang Chiou response_length = *size_ptr; 2558732b070SChe-liang Chiou } else { 2568732b070SChe-liang Chiou response = response_buffer; 2578732b070SChe-liang Chiou response_length = sizeof(response_buffer); 2588732b070SChe-liang Chiou } 2598732b070SChe-liang Chiou err = tis_sendrecv(command, tpm_command_size(command), 2608732b070SChe-liang Chiou response, &response_length); 2618732b070SChe-liang Chiou if (err) 2628732b070SChe-liang Chiou return TPM_LIB_ERROR; 263*be6c1529SReinhard Pfau if (size_ptr) 2648732b070SChe-liang Chiou *size_ptr = response_length; 2658732b070SChe-liang Chiou 2668732b070SChe-liang Chiou return tpm_return_code(response); 2678732b070SChe-liang Chiou } 2688732b070SChe-liang Chiou 2698732b070SChe-liang Chiou uint32_t tpm_init(void) 2708732b070SChe-liang Chiou { 2718732b070SChe-liang Chiou uint32_t err; 2728732b070SChe-liang Chiou 2738732b070SChe-liang Chiou err = tis_init(); 2748732b070SChe-liang Chiou if (err) 2758732b070SChe-liang Chiou return err; 2768732b070SChe-liang Chiou 2778732b070SChe-liang Chiou return tis_open(); 2788732b070SChe-liang Chiou } 2798732b070SChe-liang Chiou 2808732b070SChe-liang Chiou uint32_t tpm_startup(enum tpm_startup_type mode) 2818732b070SChe-liang Chiou { 2828732b070SChe-liang Chiou const uint8_t command[12] = { 2838732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, 2848732b070SChe-liang Chiou }; 2858732b070SChe-liang Chiou const size_t mode_offset = 10; 2868732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 2878732b070SChe-liang Chiou 2888732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sw", 2898732b070SChe-liang Chiou 0, command, sizeof(command), 2908732b070SChe-liang Chiou mode_offset, mode)) 2918732b070SChe-liang Chiou return TPM_LIB_ERROR; 2928732b070SChe-liang Chiou 2938732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 2948732b070SChe-liang Chiou } 2958732b070SChe-liang Chiou 2968732b070SChe-liang Chiou uint32_t tpm_self_test_full(void) 2978732b070SChe-liang Chiou { 2988732b070SChe-liang Chiou const uint8_t command[10] = { 2998732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, 3008732b070SChe-liang Chiou }; 3018732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 3028732b070SChe-liang Chiou } 3038732b070SChe-liang Chiou 3048732b070SChe-liang Chiou uint32_t tpm_continue_self_test(void) 3058732b070SChe-liang Chiou { 3068732b070SChe-liang Chiou const uint8_t command[10] = { 3078732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, 3088732b070SChe-liang Chiou }; 3098732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 3108732b070SChe-liang Chiou } 3118732b070SChe-liang Chiou 3128732b070SChe-liang Chiou uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size) 3138732b070SChe-liang Chiou { 3148732b070SChe-liang Chiou const uint8_t command[101] = { 3158732b070SChe-liang Chiou 0x0, 0xc1, /* TPM_TAG */ 3168732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x65, /* parameter size */ 3178732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */ 3188732b070SChe-liang Chiou /* TPM_NV_DATA_PUBLIC->... */ 3198732b070SChe-liang Chiou 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */ 3208732b070SChe-liang Chiou 0, 0, 0, 0, /* ...->TPM_NV_INDEX */ 3218732b070SChe-liang Chiou /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ 3228732b070SChe-liang Chiou 0x0, 0x3, 3238732b070SChe-liang Chiou 0, 0, 0, 3248732b070SChe-liang Chiou 0x1f, 3258732b070SChe-liang Chiou 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3268732b070SChe-liang Chiou /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ 3278732b070SChe-liang Chiou 0x0, 0x3, 3288732b070SChe-liang Chiou 0, 0, 0, 3298732b070SChe-liang Chiou 0x1f, 3308732b070SChe-liang Chiou 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3318732b070SChe-liang Chiou /* TPM_NV_ATTRIBUTES->... */ 3328732b070SChe-liang Chiou 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */ 3338732b070SChe-liang Chiou 0, 0, 0, 0, /* ...->attributes */ 3348732b070SChe-liang Chiou /* End of TPM_NV_ATTRIBUTES */ 3358732b070SChe-liang Chiou 0, /* bReadSTClear */ 3368732b070SChe-liang Chiou 0, /* bWriteSTClear */ 3378732b070SChe-liang Chiou 0, /* bWriteDefine */ 3388732b070SChe-liang Chiou 0, 0, 0, 0, /* size */ 3398732b070SChe-liang Chiou }; 3408732b070SChe-liang Chiou const size_t index_offset = 12; 3418732b070SChe-liang Chiou const size_t perm_offset = 70; 3428732b070SChe-liang Chiou const size_t size_offset = 77; 3438732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 3448732b070SChe-liang Chiou 3458732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sddd", 3468732b070SChe-liang Chiou 0, command, sizeof(command), 3478732b070SChe-liang Chiou index_offset, index, 3488732b070SChe-liang Chiou perm_offset, perm, 3498732b070SChe-liang Chiou size_offset, size)) 3508732b070SChe-liang Chiou return TPM_LIB_ERROR; 3518732b070SChe-liang Chiou 3528732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 3538732b070SChe-liang Chiou } 3548732b070SChe-liang Chiou 3558732b070SChe-liang Chiou uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count) 3568732b070SChe-liang Chiou { 3578732b070SChe-liang Chiou const uint8_t command[22] = { 3588732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, 3598732b070SChe-liang Chiou }; 3608732b070SChe-liang Chiou const size_t index_offset = 10; 3618732b070SChe-liang Chiou const size_t length_offset = 18; 3628732b070SChe-liang Chiou const size_t data_size_offset = 10; 3638732b070SChe-liang Chiou const size_t data_offset = 14; 3648732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 3658732b070SChe-liang Chiou size_t response_length = sizeof(response); 3668732b070SChe-liang Chiou uint32_t data_size; 3678732b070SChe-liang Chiou uint32_t err; 3688732b070SChe-liang Chiou 3698732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sdd", 3708732b070SChe-liang Chiou 0, command, sizeof(command), 3718732b070SChe-liang Chiou index_offset, index, 3728732b070SChe-liang Chiou length_offset, count)) 3738732b070SChe-liang Chiou return TPM_LIB_ERROR; 3748732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 3758732b070SChe-liang Chiou if (err) 3768732b070SChe-liang Chiou return err; 3778732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "d", 3788732b070SChe-liang Chiou data_size_offset, &data_size)) 3798732b070SChe-liang Chiou return TPM_LIB_ERROR; 3808732b070SChe-liang Chiou if (data_size > count) 3818732b070SChe-liang Chiou return TPM_LIB_ERROR; 3828732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 3838732b070SChe-liang Chiou data_offset, data, data_size)) 3848732b070SChe-liang Chiou return TPM_LIB_ERROR; 3858732b070SChe-liang Chiou 3868732b070SChe-liang Chiou return 0; 3878732b070SChe-liang Chiou } 3888732b070SChe-liang Chiou 3898732b070SChe-liang Chiou uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length) 3908732b070SChe-liang Chiou { 3918732b070SChe-liang Chiou const uint8_t command[256] = { 3928732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, 3938732b070SChe-liang Chiou }; 3948732b070SChe-liang Chiou const size_t command_size_offset = 2; 3958732b070SChe-liang Chiou const size_t index_offset = 10; 3968732b070SChe-liang Chiou const size_t length_offset = 18; 3978732b070SChe-liang Chiou const size_t data_offset = 22; 3988732b070SChe-liang Chiou const size_t write_info_size = 12; 3998732b070SChe-liang Chiou const uint32_t total_length = 4008732b070SChe-liang Chiou TPM_REQUEST_HEADER_LENGTH + write_info_size + length; 4018732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 4028732b070SChe-liang Chiou size_t response_length = sizeof(response); 4038732b070SChe-liang Chiou uint32_t err; 4048732b070SChe-liang Chiou 4058732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sddds", 4068732b070SChe-liang Chiou 0, command, sizeof(command), 4078732b070SChe-liang Chiou command_size_offset, total_length, 4088732b070SChe-liang Chiou index_offset, index, 4098732b070SChe-liang Chiou length_offset, length, 4108732b070SChe-liang Chiou data_offset, data, length)) 4118732b070SChe-liang Chiou return TPM_LIB_ERROR; 4128732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 4138732b070SChe-liang Chiou if (err) 4148732b070SChe-liang Chiou return err; 4158732b070SChe-liang Chiou 4168732b070SChe-liang Chiou return 0; 4178732b070SChe-liang Chiou } 4188732b070SChe-liang Chiou 4198732b070SChe-liang Chiou uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest) 4208732b070SChe-liang Chiou { 4218732b070SChe-liang Chiou const uint8_t command[34] = { 4228732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, 4238732b070SChe-liang Chiou }; 4248732b070SChe-liang Chiou const size_t index_offset = 10; 4258732b070SChe-liang Chiou const size_t in_digest_offset = 14; 4268732b070SChe-liang Chiou const size_t out_digest_offset = 10; 4278732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 4288732b070SChe-liang Chiou uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; 4298732b070SChe-liang Chiou size_t response_length = sizeof(response); 4308732b070SChe-liang Chiou uint32_t err; 4318732b070SChe-liang Chiou 4328732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sds", 4338732b070SChe-liang Chiou 0, command, sizeof(command), 4348732b070SChe-liang Chiou index_offset, index, 4358732b070SChe-liang Chiou in_digest_offset, in_digest, 4368732b070SChe-liang Chiou PCR_DIGEST_LENGTH)) 4378732b070SChe-liang Chiou return TPM_LIB_ERROR; 4388732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 4398732b070SChe-liang Chiou if (err) 4408732b070SChe-liang Chiou return err; 4418732b070SChe-liang Chiou 4428732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 4438732b070SChe-liang Chiou out_digest_offset, out_digest, 4448732b070SChe-liang Chiou PCR_DIGEST_LENGTH)) 4458732b070SChe-liang Chiou return TPM_LIB_ERROR; 4468732b070SChe-liang Chiou 4478732b070SChe-liang Chiou return 0; 4488732b070SChe-liang Chiou } 4498732b070SChe-liang Chiou 4508732b070SChe-liang Chiou uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count) 4518732b070SChe-liang Chiou { 4528732b070SChe-liang Chiou const uint8_t command[14] = { 4538732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, 4548732b070SChe-liang Chiou }; 4558732b070SChe-liang Chiou const size_t index_offset = 10; 4568732b070SChe-liang Chiou const size_t out_digest_offset = 10; 4578732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 4588732b070SChe-liang Chiou size_t response_length = sizeof(response); 4598732b070SChe-liang Chiou uint32_t err; 4608732b070SChe-liang Chiou 4618732b070SChe-liang Chiou if (count < PCR_DIGEST_LENGTH) 4628732b070SChe-liang Chiou return TPM_LIB_ERROR; 4638732b070SChe-liang Chiou 4648732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sd", 4658732b070SChe-liang Chiou 0, command, sizeof(command), 4668732b070SChe-liang Chiou index_offset, index)) 4678732b070SChe-liang Chiou return TPM_LIB_ERROR; 4688732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 4698732b070SChe-liang Chiou if (err) 4708732b070SChe-liang Chiou return err; 4718732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 4728732b070SChe-liang Chiou out_digest_offset, data, PCR_DIGEST_LENGTH)) 4738732b070SChe-liang Chiou return TPM_LIB_ERROR; 4748732b070SChe-liang Chiou 4758732b070SChe-liang Chiou return 0; 4768732b070SChe-liang Chiou } 4778732b070SChe-liang Chiou 4788732b070SChe-liang Chiou uint32_t tpm_tsc_physical_presence(uint16_t presence) 4798732b070SChe-liang Chiou { 4808732b070SChe-liang Chiou const uint8_t command[12] = { 4818732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, 4828732b070SChe-liang Chiou }; 4838732b070SChe-liang Chiou const size_t presence_offset = 10; 4848732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 4858732b070SChe-liang Chiou 4868732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sw", 4878732b070SChe-liang Chiou 0, command, sizeof(command), 4888732b070SChe-liang Chiou presence_offset, presence)) 4898732b070SChe-liang Chiou return TPM_LIB_ERROR; 4908732b070SChe-liang Chiou 4918732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 4928732b070SChe-liang Chiou } 4938732b070SChe-liang Chiou 4948732b070SChe-liang Chiou uint32_t tpm_read_pubek(void *data, size_t count) 4958732b070SChe-liang Chiou { 4968732b070SChe-liang Chiou const uint8_t command[30] = { 4978732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, 4988732b070SChe-liang Chiou }; 4998732b070SChe-liang Chiou const size_t response_size_offset = 2; 5008732b070SChe-liang Chiou const size_t data_offset = 10; 5018732b070SChe-liang Chiou const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20; 5028732b070SChe-liang Chiou uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; 5038732b070SChe-liang Chiou size_t response_length = sizeof(response); 5048732b070SChe-liang Chiou uint32_t data_size; 5058732b070SChe-liang Chiou uint32_t err; 5068732b070SChe-liang Chiou 5078732b070SChe-liang Chiou err = tpm_sendrecv_command(command, response, &response_length); 5088732b070SChe-liang Chiou if (err) 5098732b070SChe-liang Chiou return err; 5108732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "d", 5118732b070SChe-liang Chiou response_size_offset, &data_size)) 5128732b070SChe-liang Chiou return TPM_LIB_ERROR; 5138732b070SChe-liang Chiou if (data_size < header_and_checksum_size) 5148732b070SChe-liang Chiou return TPM_LIB_ERROR; 5158732b070SChe-liang Chiou data_size -= header_and_checksum_size; 5168732b070SChe-liang Chiou if (data_size > count) 5178732b070SChe-liang Chiou return TPM_LIB_ERROR; 5188732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 5198732b070SChe-liang Chiou data_offset, data, data_size)) 5208732b070SChe-liang Chiou return TPM_LIB_ERROR; 5218732b070SChe-liang Chiou 5228732b070SChe-liang Chiou return 0; 5238732b070SChe-liang Chiou } 5248732b070SChe-liang Chiou 5258732b070SChe-liang Chiou uint32_t tpm_force_clear(void) 5268732b070SChe-liang Chiou { 5278732b070SChe-liang Chiou const uint8_t command[10] = { 5288732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, 5298732b070SChe-liang Chiou }; 5308732b070SChe-liang Chiou 5318732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 5328732b070SChe-liang Chiou } 5338732b070SChe-liang Chiou 5348732b070SChe-liang Chiou uint32_t tpm_physical_enable(void) 5358732b070SChe-liang Chiou { 5368732b070SChe-liang Chiou const uint8_t command[10] = { 5378732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, 5388732b070SChe-liang Chiou }; 5398732b070SChe-liang Chiou 5408732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 5418732b070SChe-liang Chiou } 5428732b070SChe-liang Chiou 5438732b070SChe-liang Chiou uint32_t tpm_physical_disable(void) 5448732b070SChe-liang Chiou { 5458732b070SChe-liang Chiou const uint8_t command[10] = { 5468732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, 5478732b070SChe-liang Chiou }; 5488732b070SChe-liang Chiou 5498732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 5508732b070SChe-liang Chiou } 5518732b070SChe-liang Chiou 5528732b070SChe-liang Chiou uint32_t tpm_physical_set_deactivated(uint8_t state) 5538732b070SChe-liang Chiou { 5548732b070SChe-liang Chiou const uint8_t command[11] = { 5558732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, 5568732b070SChe-liang Chiou }; 5578732b070SChe-liang Chiou const size_t state_offset = 10; 5588732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 5598732b070SChe-liang Chiou 5608732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sb", 5618732b070SChe-liang Chiou 0, command, sizeof(command), 5628732b070SChe-liang Chiou state_offset, state)) 5638732b070SChe-liang Chiou return TPM_LIB_ERROR; 5648732b070SChe-liang Chiou 5658732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 5668732b070SChe-liang Chiou } 5678732b070SChe-liang Chiou 5688732b070SChe-liang Chiou uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, 5698732b070SChe-liang Chiou void *cap, size_t count) 5708732b070SChe-liang Chiou { 5718732b070SChe-liang Chiou const uint8_t command[22] = { 5728732b070SChe-liang Chiou 0x0, 0xc1, /* TPM_TAG */ 5738732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x16, /* parameter size */ 5748732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ 5758732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */ 5768732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x4, /* subcap size */ 5778732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x0, /* subcap value */ 5788732b070SChe-liang Chiou }; 5798732b070SChe-liang Chiou const size_t cap_area_offset = 10; 5808732b070SChe-liang Chiou const size_t sub_cap_offset = 18; 5818732b070SChe-liang Chiou const size_t cap_offset = 14; 5828732b070SChe-liang Chiou const size_t cap_size_offset = 10; 5838732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 5848732b070SChe-liang Chiou size_t response_length = sizeof(response); 5858732b070SChe-liang Chiou uint32_t cap_size; 5868732b070SChe-liang Chiou uint32_t err; 5878732b070SChe-liang Chiou 5888732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sdd", 5898732b070SChe-liang Chiou 0, command, sizeof(command), 5908732b070SChe-liang Chiou cap_area_offset, cap_area, 5918732b070SChe-liang Chiou sub_cap_offset, sub_cap)) 5928732b070SChe-liang Chiou return TPM_LIB_ERROR; 5938732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 5948732b070SChe-liang Chiou if (err) 5958732b070SChe-liang Chiou return err; 5968732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "d", 5978732b070SChe-liang Chiou cap_size_offset, &cap_size)) 5988732b070SChe-liang Chiou return TPM_LIB_ERROR; 5998732b070SChe-liang Chiou if (cap_size > response_length || cap_size > count) 6008732b070SChe-liang Chiou return TPM_LIB_ERROR; 6018732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 6028732b070SChe-liang Chiou cap_offset, cap, cap_size)) 6038732b070SChe-liang Chiou return TPM_LIB_ERROR; 6048732b070SChe-liang Chiou 6058732b070SChe-liang Chiou return 0; 6068732b070SChe-liang Chiou } 607*be6c1529SReinhard Pfau 608*be6c1529SReinhard Pfau #ifdef CONFIG_TPM_AUTH_SESSIONS 609*be6c1529SReinhard Pfau 610*be6c1529SReinhard Pfau /** 611*be6c1529SReinhard Pfau * Fill an authentication block in a request. 612*be6c1529SReinhard Pfau * This func can create the first as well as the second auth block (for 613*be6c1529SReinhard Pfau * double authorized commands). 614*be6c1529SReinhard Pfau * 615*be6c1529SReinhard Pfau * @param request pointer to the request (w/ uninitialised auth data) 616*be6c1529SReinhard Pfau * @param request_len0 length of the request without auth data 617*be6c1529SReinhard Pfau * @param handles_len length of the handles area in request 618*be6c1529SReinhard Pfau * @param auth_session pointer to the (valid) auth session to be used 619*be6c1529SReinhard Pfau * @param request_auth pointer to the auth block of the request to be filled 620*be6c1529SReinhard Pfau * @param auth authentication data (HMAC key) 621*be6c1529SReinhard Pfau */ 622*be6c1529SReinhard Pfau static uint32_t create_request_auth(const void *request, size_t request_len0, 623*be6c1529SReinhard Pfau size_t handles_len, 624*be6c1529SReinhard Pfau struct session_data *auth_session, 625*be6c1529SReinhard Pfau void *request_auth, const void *auth) 626*be6c1529SReinhard Pfau { 627*be6c1529SReinhard Pfau uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; 628*be6c1529SReinhard Pfau sha1_context hash_ctx; 629*be6c1529SReinhard Pfau const size_t command_code_offset = 6; 630*be6c1529SReinhard Pfau const size_t auth_nonce_odd_offset = 4; 631*be6c1529SReinhard Pfau const size_t auth_continue_offset = 24; 632*be6c1529SReinhard Pfau const size_t auth_auth_offset = 25; 633*be6c1529SReinhard Pfau 634*be6c1529SReinhard Pfau if (!auth_session || !auth_session->valid) 635*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 636*be6c1529SReinhard Pfau 637*be6c1529SReinhard Pfau sha1_starts(&hash_ctx); 638*be6c1529SReinhard Pfau sha1_update(&hash_ctx, request + command_code_offset, 4); 639*be6c1529SReinhard Pfau if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len) 640*be6c1529SReinhard Pfau sha1_update(&hash_ctx, 641*be6c1529SReinhard Pfau request + TPM_REQUEST_HEADER_LENGTH + handles_len, 642*be6c1529SReinhard Pfau request_len0 - TPM_REQUEST_HEADER_LENGTH 643*be6c1529SReinhard Pfau - handles_len); 644*be6c1529SReinhard Pfau sha1_finish(&hash_ctx, hmac_data); 645*be6c1529SReinhard Pfau 646*be6c1529SReinhard Pfau sha1_starts(&hash_ctx); 647*be6c1529SReinhard Pfau sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH); 648*be6c1529SReinhard Pfau sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data)); 649*be6c1529SReinhard Pfau sha1_finish(&hash_ctx, auth_session->nonce_odd); 650*be6c1529SReinhard Pfau 651*be6c1529SReinhard Pfau if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb", 652*be6c1529SReinhard Pfau 0, auth_session->handle, 653*be6c1529SReinhard Pfau auth_nonce_odd_offset, auth_session->nonce_odd, 654*be6c1529SReinhard Pfau DIGEST_LENGTH, 655*be6c1529SReinhard Pfau auth_continue_offset, 1)) 656*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 657*be6c1529SReinhard Pfau if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss", 658*be6c1529SReinhard Pfau DIGEST_LENGTH, 659*be6c1529SReinhard Pfau auth_session->nonce_even, 660*be6c1529SReinhard Pfau DIGEST_LENGTH, 661*be6c1529SReinhard Pfau 2 * DIGEST_LENGTH, 662*be6c1529SReinhard Pfau request_auth + auth_nonce_odd_offset, 663*be6c1529SReinhard Pfau DIGEST_LENGTH + 1)) 664*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 665*be6c1529SReinhard Pfau sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), 666*be6c1529SReinhard Pfau request_auth + auth_auth_offset); 667*be6c1529SReinhard Pfau 668*be6c1529SReinhard Pfau return TPM_SUCCESS; 669*be6c1529SReinhard Pfau } 670*be6c1529SReinhard Pfau 671*be6c1529SReinhard Pfau /** 672*be6c1529SReinhard Pfau * Verify an authentication block in a response. 673*be6c1529SReinhard Pfau * Since this func updates the nonce_even in the session data it has to be 674*be6c1529SReinhard Pfau * called when receiving a succesfull AUTH response. 675*be6c1529SReinhard Pfau * This func can verify the first as well as the second auth block (for 676*be6c1529SReinhard Pfau * double authorized commands). 677*be6c1529SReinhard Pfau * 678*be6c1529SReinhard Pfau * @param command_code command code of the request 679*be6c1529SReinhard Pfau * @param response pointer to the request (w/ uninitialised auth data) 680*be6c1529SReinhard Pfau * @param handles_len length of the handles area in response 681*be6c1529SReinhard Pfau * @param auth_session pointer to the (valid) auth session to be used 682*be6c1529SReinhard Pfau * @param response_auth pointer to the auth block of the response to be verified 683*be6c1529SReinhard Pfau * @param auth authentication data (HMAC key) 684*be6c1529SReinhard Pfau */ 685*be6c1529SReinhard Pfau static uint32_t verify_response_auth(uint32_t command_code, 686*be6c1529SReinhard Pfau const void *response, size_t response_len0, 687*be6c1529SReinhard Pfau size_t handles_len, 688*be6c1529SReinhard Pfau struct session_data *auth_session, 689*be6c1529SReinhard Pfau const void *response_auth, const void *auth) 690*be6c1529SReinhard Pfau { 691*be6c1529SReinhard Pfau uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; 692*be6c1529SReinhard Pfau uint8_t computed_auth[DIGEST_LENGTH]; 693*be6c1529SReinhard Pfau sha1_context hash_ctx; 694*be6c1529SReinhard Pfau const size_t return_code_offset = 6; 695*be6c1529SReinhard Pfau const size_t auth_continue_offset = 20; 696*be6c1529SReinhard Pfau const size_t auth_auth_offset = 21; 697*be6c1529SReinhard Pfau uint8_t auth_continue; 698*be6c1529SReinhard Pfau 699*be6c1529SReinhard Pfau if (!auth_session || !auth_session->valid) 700*be6c1529SReinhard Pfau return TPM_AUTHFAIL; 701*be6c1529SReinhard Pfau if (pack_byte_string(hmac_data, sizeof(hmac_data), "d", 702*be6c1529SReinhard Pfau 0, command_code)) 703*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 704*be6c1529SReinhard Pfau if (response_len0 < TPM_RESPONSE_HEADER_LENGTH) 705*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 706*be6c1529SReinhard Pfau 707*be6c1529SReinhard Pfau sha1_starts(&hash_ctx); 708*be6c1529SReinhard Pfau sha1_update(&hash_ctx, response + return_code_offset, 4); 709*be6c1529SReinhard Pfau sha1_update(&hash_ctx, hmac_data, 4); 710*be6c1529SReinhard Pfau if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len) 711*be6c1529SReinhard Pfau sha1_update(&hash_ctx, 712*be6c1529SReinhard Pfau response + TPM_RESPONSE_HEADER_LENGTH + handles_len, 713*be6c1529SReinhard Pfau response_len0 - TPM_RESPONSE_HEADER_LENGTH 714*be6c1529SReinhard Pfau - handles_len); 715*be6c1529SReinhard Pfau sha1_finish(&hash_ctx, hmac_data); 716*be6c1529SReinhard Pfau 717*be6c1529SReinhard Pfau memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH); 718*be6c1529SReinhard Pfau auth_continue = ((uint8_t *)response_auth)[auth_continue_offset]; 719*be6c1529SReinhard Pfau if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", 720*be6c1529SReinhard Pfau DIGEST_LENGTH, 721*be6c1529SReinhard Pfau response_auth, 722*be6c1529SReinhard Pfau DIGEST_LENGTH, 723*be6c1529SReinhard Pfau 2 * DIGEST_LENGTH, 724*be6c1529SReinhard Pfau auth_session->nonce_odd, 725*be6c1529SReinhard Pfau DIGEST_LENGTH, 726*be6c1529SReinhard Pfau 3 * DIGEST_LENGTH, 727*be6c1529SReinhard Pfau auth_continue)) 728*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 729*be6c1529SReinhard Pfau 730*be6c1529SReinhard Pfau sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), 731*be6c1529SReinhard Pfau computed_auth); 732*be6c1529SReinhard Pfau 733*be6c1529SReinhard Pfau if (memcmp(computed_auth, response_auth + auth_auth_offset, 734*be6c1529SReinhard Pfau DIGEST_LENGTH)) 735*be6c1529SReinhard Pfau return TPM_AUTHFAIL; 736*be6c1529SReinhard Pfau 737*be6c1529SReinhard Pfau return TPM_SUCCESS; 738*be6c1529SReinhard Pfau } 739*be6c1529SReinhard Pfau 740*be6c1529SReinhard Pfau 741*be6c1529SReinhard Pfau uint32_t tpm_terminate_auth_session(uint32_t auth_handle) 742*be6c1529SReinhard Pfau { 743*be6c1529SReinhard Pfau const uint8_t command[18] = { 744*be6c1529SReinhard Pfau 0x00, 0xc1, /* TPM_TAG */ 745*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parameter size */ 746*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ 747*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */ 748*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */ 749*be6c1529SReinhard Pfau }; 750*be6c1529SReinhard Pfau const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH; 751*be6c1529SReinhard Pfau uint8_t request[COMMAND_BUFFER_SIZE]; 752*be6c1529SReinhard Pfau 753*be6c1529SReinhard Pfau if (pack_byte_string(request, sizeof(request), "sd", 754*be6c1529SReinhard Pfau 0, command, sizeof(command), 755*be6c1529SReinhard Pfau req_handle_offset, auth_handle)) 756*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 757*be6c1529SReinhard Pfau if (oiap_session.valid && oiap_session.handle == auth_handle) 758*be6c1529SReinhard Pfau oiap_session.valid = 0; 759*be6c1529SReinhard Pfau 760*be6c1529SReinhard Pfau return tpm_sendrecv_command(request, NULL, NULL); 761*be6c1529SReinhard Pfau } 762*be6c1529SReinhard Pfau 763*be6c1529SReinhard Pfau uint32_t tpm_end_oiap(void) 764*be6c1529SReinhard Pfau { 765*be6c1529SReinhard Pfau uint32_t err = TPM_SUCCESS; 766*be6c1529SReinhard Pfau if (oiap_session.valid) 767*be6c1529SReinhard Pfau err = tpm_terminate_auth_session(oiap_session.handle); 768*be6c1529SReinhard Pfau return err; 769*be6c1529SReinhard Pfau } 770*be6c1529SReinhard Pfau 771*be6c1529SReinhard Pfau uint32_t tpm_oiap(uint32_t *auth_handle) 772*be6c1529SReinhard Pfau { 773*be6c1529SReinhard Pfau const uint8_t command[10] = { 774*be6c1529SReinhard Pfau 0x00, 0xc1, /* TPM_TAG */ 775*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x0a, /* parameter size */ 776*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */ 777*be6c1529SReinhard Pfau }; 778*be6c1529SReinhard Pfau const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH; 779*be6c1529SReinhard Pfau const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4; 780*be6c1529SReinhard Pfau uint8_t response[COMMAND_BUFFER_SIZE]; 781*be6c1529SReinhard Pfau size_t response_length = sizeof(response); 782*be6c1529SReinhard Pfau uint32_t err; 783*be6c1529SReinhard Pfau 784*be6c1529SReinhard Pfau if (oiap_session.valid) 785*be6c1529SReinhard Pfau tpm_terminate_auth_session(oiap_session.handle); 786*be6c1529SReinhard Pfau 787*be6c1529SReinhard Pfau err = tpm_sendrecv_command(command, response, &response_length); 788*be6c1529SReinhard Pfau if (err) 789*be6c1529SReinhard Pfau return err; 790*be6c1529SReinhard Pfau if (unpack_byte_string(response, response_length, "ds", 791*be6c1529SReinhard Pfau res_auth_handle_offset, &oiap_session.handle, 792*be6c1529SReinhard Pfau res_nonce_even_offset, &oiap_session.nonce_even, 793*be6c1529SReinhard Pfau (uint32_t)DIGEST_LENGTH)) 794*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 795*be6c1529SReinhard Pfau oiap_session.valid = 1; 796*be6c1529SReinhard Pfau if (auth_handle) 797*be6c1529SReinhard Pfau *auth_handle = oiap_session.handle; 798*be6c1529SReinhard Pfau return 0; 799*be6c1529SReinhard Pfau } 800*be6c1529SReinhard Pfau 801*be6c1529SReinhard Pfau uint32_t tpm_load_key2_oiap(uint32_t parent_handle, 802*be6c1529SReinhard Pfau const void *key, size_t key_length, 803*be6c1529SReinhard Pfau const void *parent_key_usage_auth, 804*be6c1529SReinhard Pfau uint32_t *key_handle) 805*be6c1529SReinhard Pfau { 806*be6c1529SReinhard Pfau const uint8_t command[14] = { 807*be6c1529SReinhard Pfau 0x00, 0xc2, /* TPM_TAG */ 808*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parameter size */ 809*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */ 810*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parent handle */ 811*be6c1529SReinhard Pfau }; 812*be6c1529SReinhard Pfau const size_t req_size_offset = 2; 813*be6c1529SReinhard Pfau const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH; 814*be6c1529SReinhard Pfau const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4; 815*be6c1529SReinhard Pfau const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH; 816*be6c1529SReinhard Pfau uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH 817*be6c1529SReinhard Pfau + TPM_REQUEST_AUTH_LENGTH]; 818*be6c1529SReinhard Pfau uint8_t response[COMMAND_BUFFER_SIZE]; 819*be6c1529SReinhard Pfau size_t response_length = sizeof(response); 820*be6c1529SReinhard Pfau uint32_t err; 821*be6c1529SReinhard Pfau 822*be6c1529SReinhard Pfau if (!oiap_session.valid) { 823*be6c1529SReinhard Pfau err = tpm_oiap(NULL); 824*be6c1529SReinhard Pfau if (err) 825*be6c1529SReinhard Pfau return err; 826*be6c1529SReinhard Pfau } 827*be6c1529SReinhard Pfau if (pack_byte_string(request, sizeof(request), "sdds", 828*be6c1529SReinhard Pfau 0, command, sizeof(command), 829*be6c1529SReinhard Pfau req_size_offset, 830*be6c1529SReinhard Pfau sizeof(command) + key_length 831*be6c1529SReinhard Pfau + TPM_REQUEST_AUTH_LENGTH, 832*be6c1529SReinhard Pfau req_parent_handle_offset, parent_handle, 833*be6c1529SReinhard Pfau req_key_offset, key, key_length 834*be6c1529SReinhard Pfau )) 835*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 836*be6c1529SReinhard Pfau 837*be6c1529SReinhard Pfau err = create_request_auth(request, sizeof(command) + key_length, 4, 838*be6c1529SReinhard Pfau &oiap_session, 839*be6c1529SReinhard Pfau request + sizeof(command) + key_length, 840*be6c1529SReinhard Pfau parent_key_usage_auth); 841*be6c1529SReinhard Pfau if (err) 842*be6c1529SReinhard Pfau return err; 843*be6c1529SReinhard Pfau err = tpm_sendrecv_command(request, response, &response_length); 844*be6c1529SReinhard Pfau if (err) { 845*be6c1529SReinhard Pfau if (err == TPM_AUTHFAIL) 846*be6c1529SReinhard Pfau oiap_session.valid = 0; 847*be6c1529SReinhard Pfau return err; 848*be6c1529SReinhard Pfau } 849*be6c1529SReinhard Pfau 850*be6c1529SReinhard Pfau err = verify_response_auth(0x00000041, response, 851*be6c1529SReinhard Pfau response_length - TPM_RESPONSE_AUTH_LENGTH, 852*be6c1529SReinhard Pfau 4, &oiap_session, 853*be6c1529SReinhard Pfau response + response_length - TPM_RESPONSE_AUTH_LENGTH, 854*be6c1529SReinhard Pfau parent_key_usage_auth); 855*be6c1529SReinhard Pfau if (err) 856*be6c1529SReinhard Pfau return err; 857*be6c1529SReinhard Pfau 858*be6c1529SReinhard Pfau if (key_handle) { 859*be6c1529SReinhard Pfau if (unpack_byte_string(response, response_length, "d", 860*be6c1529SReinhard Pfau res_handle_offset, key_handle)) 861*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 862*be6c1529SReinhard Pfau } 863*be6c1529SReinhard Pfau 864*be6c1529SReinhard Pfau return 0; 865*be6c1529SReinhard Pfau } 866*be6c1529SReinhard Pfau 867*be6c1529SReinhard Pfau uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, 868*be6c1529SReinhard Pfau void *pubkey, size_t *pubkey_len) 869*be6c1529SReinhard Pfau { 870*be6c1529SReinhard Pfau const uint8_t command[14] = { 871*be6c1529SReinhard Pfau 0x00, 0xc2, /* TPM_TAG */ 872*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parameter size */ 873*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */ 874*be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* key handle */ 875*be6c1529SReinhard Pfau }; 876*be6c1529SReinhard Pfau const size_t req_size_offset = 2; 877*be6c1529SReinhard Pfau const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH; 878*be6c1529SReinhard Pfau const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH; 879*be6c1529SReinhard Pfau uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; 880*be6c1529SReinhard Pfau uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH 881*be6c1529SReinhard Pfau + TPM_RESPONSE_AUTH_LENGTH]; 882*be6c1529SReinhard Pfau size_t response_length = sizeof(response); 883*be6c1529SReinhard Pfau uint32_t err; 884*be6c1529SReinhard Pfau 885*be6c1529SReinhard Pfau if (!oiap_session.valid) { 886*be6c1529SReinhard Pfau err = tpm_oiap(NULL); 887*be6c1529SReinhard Pfau if (err) 888*be6c1529SReinhard Pfau return err; 889*be6c1529SReinhard Pfau } 890*be6c1529SReinhard Pfau if (pack_byte_string(request, sizeof(request), "sdd", 891*be6c1529SReinhard Pfau 0, command, sizeof(command), 892*be6c1529SReinhard Pfau req_size_offset, 893*be6c1529SReinhard Pfau (uint32_t)(sizeof(command) 894*be6c1529SReinhard Pfau + TPM_REQUEST_AUTH_LENGTH), 895*be6c1529SReinhard Pfau req_key_handle_offset, key_handle 896*be6c1529SReinhard Pfau )) 897*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 898*be6c1529SReinhard Pfau err = create_request_auth(request, sizeof(command), 4, &oiap_session, 899*be6c1529SReinhard Pfau request + sizeof(command), usage_auth); 900*be6c1529SReinhard Pfau if (err) 901*be6c1529SReinhard Pfau return err; 902*be6c1529SReinhard Pfau err = tpm_sendrecv_command(request, response, &response_length); 903*be6c1529SReinhard Pfau if (err) { 904*be6c1529SReinhard Pfau if (err == TPM_AUTHFAIL) 905*be6c1529SReinhard Pfau oiap_session.valid = 0; 906*be6c1529SReinhard Pfau return err; 907*be6c1529SReinhard Pfau } 908*be6c1529SReinhard Pfau err = verify_response_auth(0x00000021, response, 909*be6c1529SReinhard Pfau response_length - TPM_RESPONSE_AUTH_LENGTH, 910*be6c1529SReinhard Pfau 0, &oiap_session, 911*be6c1529SReinhard Pfau response + response_length - TPM_RESPONSE_AUTH_LENGTH, 912*be6c1529SReinhard Pfau usage_auth); 913*be6c1529SReinhard Pfau if (err) 914*be6c1529SReinhard Pfau return err; 915*be6c1529SReinhard Pfau 916*be6c1529SReinhard Pfau if (pubkey) { 917*be6c1529SReinhard Pfau if ((response_length - TPM_RESPONSE_HEADER_LENGTH 918*be6c1529SReinhard Pfau - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) 919*be6c1529SReinhard Pfau return TPM_LIB_ERROR; 920*be6c1529SReinhard Pfau *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH 921*be6c1529SReinhard Pfau - TPM_RESPONSE_AUTH_LENGTH; 922*be6c1529SReinhard Pfau memcpy(pubkey, response + res_pubkey_offset, 923*be6c1529SReinhard Pfau response_length - TPM_RESPONSE_HEADER_LENGTH 924*be6c1529SReinhard Pfau - TPM_RESPONSE_AUTH_LENGTH); 925*be6c1529SReinhard Pfau } 926*be6c1529SReinhard Pfau 927*be6c1529SReinhard Pfau return 0; 928*be6c1529SReinhard Pfau } 929*be6c1529SReinhard Pfau 930*be6c1529SReinhard Pfau #endif /* CONFIG_TPM_AUTH_SESSIONS */ 931