18732b070SChe-liang Chiou /* 28732b070SChe-liang Chiou * Copyright (c) 2013 The Chromium OS Authors. 3be6c1529SReinhard Pfau * Coypright (c) 2013 Guntermann & Drunck GmbH 48732b070SChe-liang Chiou * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 68732b070SChe-liang Chiou */ 78732b070SChe-liang Chiou 88732b070SChe-liang Chiou #include <common.h> 9c8a8c510SSimon Glass #include <dm.h> 108732b070SChe-liang Chiou #include <tpm.h> 118732b070SChe-liang Chiou #include <asm/unaligned.h> 12c8a8c510SSimon Glass #include <u-boot/sha1.h> 138732b070SChe-liang Chiou 148732b070SChe-liang Chiou /* Internal error of TPM command library */ 158732b070SChe-liang Chiou #define TPM_LIB_ERROR ((uint32_t)~0u) 168732b070SChe-liang Chiou 178732b070SChe-liang Chiou /* Useful constants */ 188732b070SChe-liang Chiou enum { 198732b070SChe-liang Chiou COMMAND_BUFFER_SIZE = 256, 208732b070SChe-liang Chiou TPM_REQUEST_HEADER_LENGTH = 10, 218732b070SChe-liang Chiou TPM_RESPONSE_HEADER_LENGTH = 10, 228732b070SChe-liang Chiou PCR_DIGEST_LENGTH = 20, 23be6c1529SReinhard Pfau DIGEST_LENGTH = 20, 24be6c1529SReinhard Pfau TPM_REQUEST_AUTH_LENGTH = 45, 25be6c1529SReinhard Pfau TPM_RESPONSE_AUTH_LENGTH = 41, 26be6c1529SReinhard Pfau /* some max lengths, valid for RSA keys <= 2048 bits */ 27be6c1529SReinhard Pfau TPM_KEY12_MAX_LENGTH = 618, 28be6c1529SReinhard Pfau TPM_PUBKEY_MAX_LENGTH = 288, 298732b070SChe-liang Chiou }; 308732b070SChe-liang Chiou 31be6c1529SReinhard Pfau #ifdef CONFIG_TPM_AUTH_SESSIONS 32be6c1529SReinhard Pfau 33be6c1529SReinhard Pfau #ifndef CONFIG_SHA1 34be6c1529SReinhard Pfau #error "TPM_AUTH_SESSIONS require SHA1 to be configured, too" 35be6c1529SReinhard Pfau #endif /* !CONFIG_SHA1 */ 36be6c1529SReinhard Pfau 37be6c1529SReinhard Pfau struct session_data { 38be6c1529SReinhard Pfau int valid; 39be6c1529SReinhard Pfau uint32_t handle; 40be6c1529SReinhard Pfau uint8_t nonce_even[DIGEST_LENGTH]; 41be6c1529SReinhard Pfau uint8_t nonce_odd[DIGEST_LENGTH]; 42be6c1529SReinhard Pfau }; 43be6c1529SReinhard Pfau 44be6c1529SReinhard Pfau static struct session_data oiap_session = {0, }; 45be6c1529SReinhard Pfau 46be6c1529SReinhard Pfau #endif /* CONFIG_TPM_AUTH_SESSIONS */ 47be6c1529SReinhard Pfau 488732b070SChe-liang Chiou /** 498732b070SChe-liang Chiou * Pack data into a byte string. The data types are specified in 508732b070SChe-liang Chiou * the format string: 'b' means unsigned byte, 'w' unsigned word, 518732b070SChe-liang Chiou * 'd' unsigned double word, and 's' byte string. The data are a 528732b070SChe-liang Chiou * series of offsets and values (for type byte string there are also 538732b070SChe-liang Chiou * lengths). The data values are packed into the byte string 548732b070SChe-liang Chiou * sequentially, and so a latter value could over-write a former 558732b070SChe-liang Chiou * value. 568732b070SChe-liang Chiou * 578732b070SChe-liang Chiou * @param str output string 588732b070SChe-liang Chiou * @param size size of output string 598732b070SChe-liang Chiou * @param format format string 608732b070SChe-liang Chiou * @param ... data points 618732b070SChe-liang Chiou * @return 0 on success, non-0 on error 628732b070SChe-liang Chiou */ 638732b070SChe-liang Chiou int pack_byte_string(uint8_t *str, size_t size, const char *format, ...) 648732b070SChe-liang Chiou { 658732b070SChe-liang Chiou va_list args; 668732b070SChe-liang Chiou size_t offset = 0, length = 0; 678732b070SChe-liang Chiou uint8_t *data = NULL; 688732b070SChe-liang Chiou uint32_t value = 0; 698732b070SChe-liang Chiou 708732b070SChe-liang Chiou va_start(args, format); 718732b070SChe-liang Chiou for (; *format; format++) { 728732b070SChe-liang Chiou switch (*format) { 738732b070SChe-liang Chiou case 'b': 748732b070SChe-liang Chiou offset = va_arg(args, size_t); 758732b070SChe-liang Chiou value = va_arg(args, int); 768732b070SChe-liang Chiou length = 1; 778732b070SChe-liang Chiou break; 788732b070SChe-liang Chiou case 'w': 798732b070SChe-liang Chiou offset = va_arg(args, size_t); 808732b070SChe-liang Chiou value = va_arg(args, int); 818732b070SChe-liang Chiou length = 2; 828732b070SChe-liang Chiou break; 838732b070SChe-liang Chiou case 'd': 848732b070SChe-liang Chiou offset = va_arg(args, size_t); 858732b070SChe-liang Chiou value = va_arg(args, uint32_t); 868732b070SChe-liang Chiou length = 4; 878732b070SChe-liang Chiou break; 888732b070SChe-liang Chiou case 's': 898732b070SChe-liang Chiou offset = va_arg(args, size_t); 908732b070SChe-liang Chiou data = va_arg(args, uint8_t *); 918732b070SChe-liang Chiou length = va_arg(args, uint32_t); 928732b070SChe-liang Chiou break; 938732b070SChe-liang Chiou default: 948732b070SChe-liang Chiou debug("Couldn't recognize format string\n"); 958732b070SChe-liang Chiou return -1; 968732b070SChe-liang Chiou } 978732b070SChe-liang Chiou 98*36d35345Sxypron.glpk@gmx.de if (offset + length > size) { 99*36d35345Sxypron.glpk@gmx.de va_end(args); 1008732b070SChe-liang Chiou return -1; 101*36d35345Sxypron.glpk@gmx.de } 1028732b070SChe-liang Chiou 1038732b070SChe-liang Chiou switch (*format) { 1048732b070SChe-liang Chiou case 'b': 1058732b070SChe-liang Chiou str[offset] = value; 1068732b070SChe-liang Chiou break; 1078732b070SChe-liang Chiou case 'w': 1088732b070SChe-liang Chiou put_unaligned_be16(value, str + offset); 1098732b070SChe-liang Chiou break; 1108732b070SChe-liang Chiou case 'd': 1118732b070SChe-liang Chiou put_unaligned_be32(value, str + offset); 1128732b070SChe-liang Chiou break; 1138732b070SChe-liang Chiou case 's': 1148732b070SChe-liang Chiou memcpy(str + offset, data, length); 1158732b070SChe-liang Chiou break; 1168732b070SChe-liang Chiou } 1178732b070SChe-liang Chiou } 1188732b070SChe-liang Chiou va_end(args); 1198732b070SChe-liang Chiou 1208732b070SChe-liang Chiou return 0; 1218732b070SChe-liang Chiou } 1228732b070SChe-liang Chiou 1238732b070SChe-liang Chiou /** 1248732b070SChe-liang Chiou * Unpack data from a byte string. The data types are specified in 1258732b070SChe-liang Chiou * the format string: 'b' means unsigned byte, 'w' unsigned word, 1268732b070SChe-liang Chiou * 'd' unsigned double word, and 's' byte string. The data are a 1278732b070SChe-liang Chiou * series of offsets and pointers (for type byte string there are also 1288732b070SChe-liang Chiou * lengths). 1298732b070SChe-liang Chiou * 1308732b070SChe-liang Chiou * @param str output string 1318732b070SChe-liang Chiou * @param size size of output string 1328732b070SChe-liang Chiou * @param format format string 1338732b070SChe-liang Chiou * @param ... data points 1348732b070SChe-liang Chiou * @return 0 on success, non-0 on error 1358732b070SChe-liang Chiou */ 1368732b070SChe-liang Chiou int unpack_byte_string(const uint8_t *str, size_t size, const char *format, ...) 1378732b070SChe-liang Chiou { 1388732b070SChe-liang Chiou va_list args; 1398732b070SChe-liang Chiou size_t offset = 0, length = 0; 1408732b070SChe-liang Chiou uint8_t *ptr8 = NULL; 1418732b070SChe-liang Chiou uint16_t *ptr16 = NULL; 1428732b070SChe-liang Chiou uint32_t *ptr32 = NULL; 1438732b070SChe-liang Chiou 1448732b070SChe-liang Chiou va_start(args, format); 1458732b070SChe-liang Chiou for (; *format; format++) { 1468732b070SChe-liang Chiou switch (*format) { 1478732b070SChe-liang Chiou case 'b': 1488732b070SChe-liang Chiou offset = va_arg(args, size_t); 1498732b070SChe-liang Chiou ptr8 = va_arg(args, uint8_t *); 1508732b070SChe-liang Chiou length = 1; 1518732b070SChe-liang Chiou break; 1528732b070SChe-liang Chiou case 'w': 1538732b070SChe-liang Chiou offset = va_arg(args, size_t); 1548732b070SChe-liang Chiou ptr16 = va_arg(args, uint16_t *); 1558732b070SChe-liang Chiou length = 2; 1568732b070SChe-liang Chiou break; 1578732b070SChe-liang Chiou case 'd': 1588732b070SChe-liang Chiou offset = va_arg(args, size_t); 1598732b070SChe-liang Chiou ptr32 = va_arg(args, uint32_t *); 1608732b070SChe-liang Chiou length = 4; 1618732b070SChe-liang Chiou break; 1628732b070SChe-liang Chiou case 's': 1638732b070SChe-liang Chiou offset = va_arg(args, size_t); 1648732b070SChe-liang Chiou ptr8 = va_arg(args, uint8_t *); 1658732b070SChe-liang Chiou length = va_arg(args, uint32_t); 1668732b070SChe-liang Chiou break; 1678732b070SChe-liang Chiou default: 168*36d35345Sxypron.glpk@gmx.de va_end(args); 1698732b070SChe-liang Chiou debug("Couldn't recognize format string\n"); 1708732b070SChe-liang Chiou return -1; 1718732b070SChe-liang Chiou } 1728732b070SChe-liang Chiou 1738732b070SChe-liang Chiou if (offset + length > size) 1748732b070SChe-liang Chiou return -1; 1758732b070SChe-liang Chiou 1768732b070SChe-liang Chiou switch (*format) { 1778732b070SChe-liang Chiou case 'b': 1788732b070SChe-liang Chiou *ptr8 = str[offset]; 1798732b070SChe-liang Chiou break; 1808732b070SChe-liang Chiou case 'w': 1818732b070SChe-liang Chiou *ptr16 = get_unaligned_be16(str + offset); 1828732b070SChe-liang Chiou break; 1838732b070SChe-liang Chiou case 'd': 1848732b070SChe-liang Chiou *ptr32 = get_unaligned_be32(str + offset); 1858732b070SChe-liang Chiou break; 1868732b070SChe-liang Chiou case 's': 1878732b070SChe-liang Chiou memcpy(ptr8, str + offset, length); 1888732b070SChe-liang Chiou break; 1898732b070SChe-liang Chiou } 1908732b070SChe-liang Chiou } 1918732b070SChe-liang Chiou va_end(args); 1928732b070SChe-liang Chiou 1938732b070SChe-liang Chiou return 0; 1948732b070SChe-liang Chiou } 1958732b070SChe-liang Chiou 1968732b070SChe-liang Chiou /** 1978732b070SChe-liang Chiou * Get TPM command size. 1988732b070SChe-liang Chiou * 1998732b070SChe-liang Chiou * @param command byte string of TPM command 2008732b070SChe-liang Chiou * @return command size of the TPM command 2018732b070SChe-liang Chiou */ 2028732b070SChe-liang Chiou static uint32_t tpm_command_size(const void *command) 2038732b070SChe-liang Chiou { 2048732b070SChe-liang Chiou const size_t command_size_offset = 2; 2058732b070SChe-liang Chiou return get_unaligned_be32(command + command_size_offset); 2068732b070SChe-liang Chiou } 2078732b070SChe-liang Chiou 2088732b070SChe-liang Chiou /** 2098732b070SChe-liang Chiou * Get TPM response return code, which is one of TPM_RESULT values. 2108732b070SChe-liang Chiou * 2118732b070SChe-liang Chiou * @param response byte string of TPM response 2128732b070SChe-liang Chiou * @return return code of the TPM response 2138732b070SChe-liang Chiou */ 2148732b070SChe-liang Chiou static uint32_t tpm_return_code(const void *response) 2158732b070SChe-liang Chiou { 2168732b070SChe-liang Chiou const size_t return_code_offset = 6; 2178732b070SChe-liang Chiou return get_unaligned_be32(response + return_code_offset); 2188732b070SChe-liang Chiou } 2198732b070SChe-liang Chiou 2208732b070SChe-liang Chiou /** 2218732b070SChe-liang Chiou * Send a TPM command and return response's return code, and optionally 2228732b070SChe-liang Chiou * return response to caller. 2238732b070SChe-liang Chiou * 2248732b070SChe-liang Chiou * @param command byte string of TPM command 2258732b070SChe-liang Chiou * @param response output buffer for TPM response, or NULL if the 2268732b070SChe-liang Chiou * caller does not care about it 2278732b070SChe-liang Chiou * @param size_ptr output buffer size (input parameter) and TPM 2288732b070SChe-liang Chiou * response length (output parameter); this parameter 2298732b070SChe-liang Chiou * is a bidirectional 2308732b070SChe-liang Chiou * @return return code of the TPM response 2318732b070SChe-liang Chiou */ 2328732b070SChe-liang Chiou static uint32_t tpm_sendrecv_command(const void *command, 2338732b070SChe-liang Chiou void *response, size_t *size_ptr) 2348732b070SChe-liang Chiou { 235c2b0f600SChristophe Ricard struct udevice *dev; 236667d6856STom Rini int err, ret; 2378732b070SChe-liang Chiou uint8_t response_buffer[COMMAND_BUFFER_SIZE]; 2388732b070SChe-liang Chiou size_t response_length; 2398732b070SChe-liang Chiou 2408732b070SChe-liang Chiou if (response) { 2418732b070SChe-liang Chiou response_length = *size_ptr; 2428732b070SChe-liang Chiou } else { 2438732b070SChe-liang Chiou response = response_buffer; 2448732b070SChe-liang Chiou response_length = sizeof(response_buffer); 2458732b070SChe-liang Chiou } 246c8a8c510SSimon Glass 2473f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_TPM, &dev); 248c8a8c510SSimon Glass if (ret) 249c8a8c510SSimon Glass return ret; 250c8a8c510SSimon Glass err = tpm_xfer(dev, command, tpm_command_size(command), 251c8a8c510SSimon Glass response, &response_length); 252c2b0f600SChristophe Ricard 253c8a8c510SSimon Glass if (err < 0) 2548732b070SChe-liang Chiou return TPM_LIB_ERROR; 255be6c1529SReinhard Pfau if (size_ptr) 2568732b070SChe-liang Chiou *size_ptr = response_length; 2578732b070SChe-liang Chiou 2588732b070SChe-liang Chiou return tpm_return_code(response); 2598732b070SChe-liang Chiou } 2608732b070SChe-liang Chiou 261c8a8c510SSimon Glass int tpm_init(void) 2628732b070SChe-liang Chiou { 263c8a8c510SSimon Glass int err; 264c8a8c510SSimon Glass struct udevice *dev; 265c8a8c510SSimon Glass 2663f603cbbSSimon Glass err = uclass_first_device_err(UCLASS_TPM, &dev); 2673f603cbbSSimon Glass if (err) 268c8a8c510SSimon Glass return err; 269c8a8c510SSimon Glass return tpm_open(dev); 2708732b070SChe-liang Chiou } 2718732b070SChe-liang Chiou 2728732b070SChe-liang Chiou uint32_t tpm_startup(enum tpm_startup_type mode) 2738732b070SChe-liang Chiou { 2748732b070SChe-liang Chiou const uint8_t command[12] = { 2758732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0, 2768732b070SChe-liang Chiou }; 2778732b070SChe-liang Chiou const size_t mode_offset = 10; 2788732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 2798732b070SChe-liang Chiou 2808732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sw", 2818732b070SChe-liang Chiou 0, command, sizeof(command), 2828732b070SChe-liang Chiou mode_offset, mode)) 2838732b070SChe-liang Chiou return TPM_LIB_ERROR; 2848732b070SChe-liang Chiou 2858732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 2868732b070SChe-liang Chiou } 2878732b070SChe-liang Chiou 2888732b070SChe-liang Chiou uint32_t tpm_self_test_full(void) 2898732b070SChe-liang Chiou { 2908732b070SChe-liang Chiou const uint8_t command[10] = { 2918732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, 2928732b070SChe-liang Chiou }; 2938732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 2948732b070SChe-liang Chiou } 2958732b070SChe-liang Chiou 2968732b070SChe-liang Chiou uint32_t tpm_continue_self_test(void) 2978732b070SChe-liang Chiou { 2988732b070SChe-liang Chiou const uint8_t command[10] = { 2998732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, 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_nv_define_space(uint32_t index, uint32_t perm, uint32_t size) 3058732b070SChe-liang Chiou { 3068732b070SChe-liang Chiou const uint8_t command[101] = { 3078732b070SChe-liang Chiou 0x0, 0xc1, /* TPM_TAG */ 3088732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x65, /* parameter size */ 3098732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */ 3108732b070SChe-liang Chiou /* TPM_NV_DATA_PUBLIC->... */ 3118732b070SChe-liang Chiou 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */ 3128732b070SChe-liang Chiou 0, 0, 0, 0, /* ...->TPM_NV_INDEX */ 3138732b070SChe-liang Chiou /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ 3148732b070SChe-liang Chiou 0x0, 0x3, 3158732b070SChe-liang Chiou 0, 0, 0, 3168732b070SChe-liang Chiou 0x1f, 3178732b070SChe-liang Chiou 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3188732b070SChe-liang Chiou /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */ 3198732b070SChe-liang Chiou 0x0, 0x3, 3208732b070SChe-liang Chiou 0, 0, 0, 3218732b070SChe-liang Chiou 0x1f, 3228732b070SChe-liang Chiou 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3238732b070SChe-liang Chiou /* TPM_NV_ATTRIBUTES->... */ 3248732b070SChe-liang Chiou 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */ 3258732b070SChe-liang Chiou 0, 0, 0, 0, /* ...->attributes */ 3268732b070SChe-liang Chiou /* End of TPM_NV_ATTRIBUTES */ 3278732b070SChe-liang Chiou 0, /* bReadSTClear */ 3288732b070SChe-liang Chiou 0, /* bWriteSTClear */ 3298732b070SChe-liang Chiou 0, /* bWriteDefine */ 3308732b070SChe-liang Chiou 0, 0, 0, 0, /* size */ 3318732b070SChe-liang Chiou }; 3328732b070SChe-liang Chiou const size_t index_offset = 12; 3338732b070SChe-liang Chiou const size_t perm_offset = 70; 3348732b070SChe-liang Chiou const size_t size_offset = 77; 3358732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 3368732b070SChe-liang Chiou 3378732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sddd", 3388732b070SChe-liang Chiou 0, command, sizeof(command), 3398732b070SChe-liang Chiou index_offset, index, 3408732b070SChe-liang Chiou perm_offset, perm, 3418732b070SChe-liang Chiou size_offset, size)) 3428732b070SChe-liang Chiou return TPM_LIB_ERROR; 3438732b070SChe-liang Chiou 3448732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 3458732b070SChe-liang Chiou } 3468732b070SChe-liang Chiou 3478732b070SChe-liang Chiou uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count) 3488732b070SChe-liang Chiou { 3498732b070SChe-liang Chiou const uint8_t command[22] = { 3508732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, 3518732b070SChe-liang Chiou }; 3528732b070SChe-liang Chiou const size_t index_offset = 10; 3538732b070SChe-liang Chiou const size_t length_offset = 18; 3548732b070SChe-liang Chiou const size_t data_size_offset = 10; 3558732b070SChe-liang Chiou const size_t data_offset = 14; 3568732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 3578732b070SChe-liang Chiou size_t response_length = sizeof(response); 3588732b070SChe-liang Chiou uint32_t data_size; 3598732b070SChe-liang Chiou uint32_t err; 3608732b070SChe-liang Chiou 3618732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sdd", 3628732b070SChe-liang Chiou 0, command, sizeof(command), 3638732b070SChe-liang Chiou index_offset, index, 3648732b070SChe-liang Chiou length_offset, count)) 3658732b070SChe-liang Chiou return TPM_LIB_ERROR; 3668732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 3678732b070SChe-liang Chiou if (err) 3688732b070SChe-liang Chiou return err; 3698732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "d", 3708732b070SChe-liang Chiou data_size_offset, &data_size)) 3718732b070SChe-liang Chiou return TPM_LIB_ERROR; 3728732b070SChe-liang Chiou if (data_size > count) 3738732b070SChe-liang Chiou return TPM_LIB_ERROR; 3748732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 3758732b070SChe-liang Chiou data_offset, data, data_size)) 3768732b070SChe-liang Chiou return TPM_LIB_ERROR; 3778732b070SChe-liang Chiou 3788732b070SChe-liang Chiou return 0; 3798732b070SChe-liang Chiou } 3808732b070SChe-liang Chiou 3818732b070SChe-liang Chiou uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length) 3828732b070SChe-liang Chiou { 3838732b070SChe-liang Chiou const uint8_t command[256] = { 3848732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, 3858732b070SChe-liang Chiou }; 3868732b070SChe-liang Chiou const size_t command_size_offset = 2; 3878732b070SChe-liang Chiou const size_t index_offset = 10; 3888732b070SChe-liang Chiou const size_t length_offset = 18; 3898732b070SChe-liang Chiou const size_t data_offset = 22; 3908732b070SChe-liang Chiou const size_t write_info_size = 12; 3918732b070SChe-liang Chiou const uint32_t total_length = 3928732b070SChe-liang Chiou TPM_REQUEST_HEADER_LENGTH + write_info_size + length; 3938732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 3948732b070SChe-liang Chiou size_t response_length = sizeof(response); 3958732b070SChe-liang Chiou uint32_t err; 3968732b070SChe-liang Chiou 3978732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sddds", 3988732b070SChe-liang Chiou 0, command, sizeof(command), 3998732b070SChe-liang Chiou command_size_offset, total_length, 4008732b070SChe-liang Chiou index_offset, index, 4018732b070SChe-liang Chiou length_offset, length, 4028732b070SChe-liang Chiou data_offset, data, length)) 4038732b070SChe-liang Chiou return TPM_LIB_ERROR; 4048732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 4058732b070SChe-liang Chiou if (err) 4068732b070SChe-liang Chiou return err; 4078732b070SChe-liang Chiou 4088732b070SChe-liang Chiou return 0; 4098732b070SChe-liang Chiou } 4108732b070SChe-liang Chiou 4118732b070SChe-liang Chiou uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest) 4128732b070SChe-liang Chiou { 4138732b070SChe-liang Chiou const uint8_t command[34] = { 4148732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, 4158732b070SChe-liang Chiou }; 4168732b070SChe-liang Chiou const size_t index_offset = 10; 4178732b070SChe-liang Chiou const size_t in_digest_offset = 14; 4188732b070SChe-liang Chiou const size_t out_digest_offset = 10; 4198732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 4208732b070SChe-liang Chiou uint8_t response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH]; 4218732b070SChe-liang Chiou size_t response_length = sizeof(response); 4228732b070SChe-liang Chiou uint32_t err; 4238732b070SChe-liang Chiou 4248732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sds", 4258732b070SChe-liang Chiou 0, command, sizeof(command), 4268732b070SChe-liang Chiou index_offset, index, 4278732b070SChe-liang Chiou in_digest_offset, in_digest, 4288732b070SChe-liang Chiou PCR_DIGEST_LENGTH)) 4298732b070SChe-liang Chiou return TPM_LIB_ERROR; 4308732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 4318732b070SChe-liang Chiou if (err) 4328732b070SChe-liang Chiou return err; 4338732b070SChe-liang Chiou 4348732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 4358732b070SChe-liang Chiou out_digest_offset, out_digest, 4368732b070SChe-liang Chiou PCR_DIGEST_LENGTH)) 4378732b070SChe-liang Chiou return TPM_LIB_ERROR; 4388732b070SChe-liang Chiou 4398732b070SChe-liang Chiou return 0; 4408732b070SChe-liang Chiou } 4418732b070SChe-liang Chiou 4428732b070SChe-liang Chiou uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count) 4438732b070SChe-liang Chiou { 4448732b070SChe-liang Chiou const uint8_t command[14] = { 4458732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, 4468732b070SChe-liang Chiou }; 4478732b070SChe-liang Chiou const size_t index_offset = 10; 4488732b070SChe-liang Chiou const size_t out_digest_offset = 10; 4498732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 4508732b070SChe-liang Chiou size_t response_length = sizeof(response); 4518732b070SChe-liang Chiou uint32_t err; 4528732b070SChe-liang Chiou 4538732b070SChe-liang Chiou if (count < PCR_DIGEST_LENGTH) 4548732b070SChe-liang Chiou return TPM_LIB_ERROR; 4558732b070SChe-liang Chiou 4568732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sd", 4578732b070SChe-liang Chiou 0, command, sizeof(command), 4588732b070SChe-liang Chiou index_offset, index)) 4598732b070SChe-liang Chiou return TPM_LIB_ERROR; 4608732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 4618732b070SChe-liang Chiou if (err) 4628732b070SChe-liang Chiou return err; 4638732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 4648732b070SChe-liang Chiou out_digest_offset, data, PCR_DIGEST_LENGTH)) 4658732b070SChe-liang Chiou return TPM_LIB_ERROR; 4668732b070SChe-liang Chiou 4678732b070SChe-liang Chiou return 0; 4688732b070SChe-liang Chiou } 4698732b070SChe-liang Chiou 4708732b070SChe-liang Chiou uint32_t tpm_tsc_physical_presence(uint16_t presence) 4718732b070SChe-liang Chiou { 4728732b070SChe-liang Chiou const uint8_t command[12] = { 4738732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0, 4748732b070SChe-liang Chiou }; 4758732b070SChe-liang Chiou const size_t presence_offset = 10; 4768732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 4778732b070SChe-liang Chiou 4788732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sw", 4798732b070SChe-liang Chiou 0, command, sizeof(command), 4808732b070SChe-liang Chiou presence_offset, presence)) 4818732b070SChe-liang Chiou return TPM_LIB_ERROR; 4828732b070SChe-liang Chiou 4838732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 4848732b070SChe-liang Chiou } 4858732b070SChe-liang Chiou 4868732b070SChe-liang Chiou uint32_t tpm_read_pubek(void *data, size_t count) 4878732b070SChe-liang Chiou { 4888732b070SChe-liang Chiou const uint8_t command[30] = { 4898732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, 4908732b070SChe-liang Chiou }; 4918732b070SChe-liang Chiou const size_t response_size_offset = 2; 4928732b070SChe-liang Chiou const size_t data_offset = 10; 4938732b070SChe-liang Chiou const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20; 4948732b070SChe-liang Chiou uint8_t response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE]; 4958732b070SChe-liang Chiou size_t response_length = sizeof(response); 4968732b070SChe-liang Chiou uint32_t data_size; 4978732b070SChe-liang Chiou uint32_t err; 4988732b070SChe-liang Chiou 4998732b070SChe-liang Chiou err = tpm_sendrecv_command(command, response, &response_length); 5008732b070SChe-liang Chiou if (err) 5018732b070SChe-liang Chiou return err; 5028732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "d", 5038732b070SChe-liang Chiou response_size_offset, &data_size)) 5048732b070SChe-liang Chiou return TPM_LIB_ERROR; 5058732b070SChe-liang Chiou if (data_size < header_and_checksum_size) 5068732b070SChe-liang Chiou return TPM_LIB_ERROR; 5078732b070SChe-liang Chiou data_size -= header_and_checksum_size; 5088732b070SChe-liang Chiou if (data_size > count) 5098732b070SChe-liang Chiou return TPM_LIB_ERROR; 5108732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 5118732b070SChe-liang Chiou data_offset, data, data_size)) 5128732b070SChe-liang Chiou return TPM_LIB_ERROR; 5138732b070SChe-liang Chiou 5148732b070SChe-liang Chiou return 0; 5158732b070SChe-liang Chiou } 5168732b070SChe-liang Chiou 5178732b070SChe-liang Chiou uint32_t tpm_force_clear(void) 5188732b070SChe-liang Chiou { 5198732b070SChe-liang Chiou const uint8_t command[10] = { 5208732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, 5218732b070SChe-liang Chiou }; 5228732b070SChe-liang Chiou 5238732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 5248732b070SChe-liang Chiou } 5258732b070SChe-liang Chiou 5268732b070SChe-liang Chiou uint32_t tpm_physical_enable(void) 5278732b070SChe-liang Chiou { 5288732b070SChe-liang Chiou const uint8_t command[10] = { 5298732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, 5308732b070SChe-liang Chiou }; 5318732b070SChe-liang Chiou 5328732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 5338732b070SChe-liang Chiou } 5348732b070SChe-liang Chiou 5358732b070SChe-liang Chiou uint32_t tpm_physical_disable(void) 5368732b070SChe-liang Chiou { 5378732b070SChe-liang Chiou const uint8_t command[10] = { 5388732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, 5398732b070SChe-liang Chiou }; 5408732b070SChe-liang Chiou 5418732b070SChe-liang Chiou return tpm_sendrecv_command(command, NULL, NULL); 5428732b070SChe-liang Chiou } 5438732b070SChe-liang Chiou 5448732b070SChe-liang Chiou uint32_t tpm_physical_set_deactivated(uint8_t state) 5458732b070SChe-liang Chiou { 5468732b070SChe-liang Chiou const uint8_t command[11] = { 5478732b070SChe-liang Chiou 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, 5488732b070SChe-liang Chiou }; 5498732b070SChe-liang Chiou const size_t state_offset = 10; 5508732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE]; 5518732b070SChe-liang Chiou 5528732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sb", 5538732b070SChe-liang Chiou 0, command, sizeof(command), 5548732b070SChe-liang Chiou state_offset, state)) 5558732b070SChe-liang Chiou return TPM_LIB_ERROR; 5568732b070SChe-liang Chiou 5578732b070SChe-liang Chiou return tpm_sendrecv_command(buf, NULL, NULL); 5588732b070SChe-liang Chiou } 5598732b070SChe-liang Chiou 5608732b070SChe-liang Chiou uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, 5618732b070SChe-liang Chiou void *cap, size_t count) 5628732b070SChe-liang Chiou { 5638732b070SChe-liang Chiou const uint8_t command[22] = { 5648732b070SChe-liang Chiou 0x0, 0xc1, /* TPM_TAG */ 5658732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x16, /* parameter size */ 5668732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ 5678732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */ 5688732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x4, /* subcap size */ 5698732b070SChe-liang Chiou 0x0, 0x0, 0x0, 0x0, /* subcap value */ 5708732b070SChe-liang Chiou }; 5718732b070SChe-liang Chiou const size_t cap_area_offset = 10; 5728732b070SChe-liang Chiou const size_t sub_cap_offset = 18; 5738732b070SChe-liang Chiou const size_t cap_offset = 14; 5748732b070SChe-liang Chiou const size_t cap_size_offset = 10; 5758732b070SChe-liang Chiou uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 5768732b070SChe-liang Chiou size_t response_length = sizeof(response); 5778732b070SChe-liang Chiou uint32_t cap_size; 5788732b070SChe-liang Chiou uint32_t err; 5798732b070SChe-liang Chiou 5808732b070SChe-liang Chiou if (pack_byte_string(buf, sizeof(buf), "sdd", 5818732b070SChe-liang Chiou 0, command, sizeof(command), 5828732b070SChe-liang Chiou cap_area_offset, cap_area, 5838732b070SChe-liang Chiou sub_cap_offset, sub_cap)) 5848732b070SChe-liang Chiou return TPM_LIB_ERROR; 5858732b070SChe-liang Chiou err = tpm_sendrecv_command(buf, response, &response_length); 5868732b070SChe-liang Chiou if (err) 5878732b070SChe-liang Chiou return err; 5888732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "d", 5898732b070SChe-liang Chiou cap_size_offset, &cap_size)) 5908732b070SChe-liang Chiou return TPM_LIB_ERROR; 5918732b070SChe-liang Chiou if (cap_size > response_length || cap_size > count) 5928732b070SChe-liang Chiou return TPM_LIB_ERROR; 5938732b070SChe-liang Chiou if (unpack_byte_string(response, response_length, "s", 5948732b070SChe-liang Chiou cap_offset, cap, cap_size)) 5958732b070SChe-liang Chiou return TPM_LIB_ERROR; 5968732b070SChe-liang Chiou 5978732b070SChe-liang Chiou return 0; 5988732b070SChe-liang Chiou } 599be6c1529SReinhard Pfau 6002132f971SSimon Glass uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags) 6012132f971SSimon Glass { 6022132f971SSimon Glass const uint8_t command[22] = { 6032132f971SSimon Glass 0x0, 0xc1, /* TPM_TAG */ 6042132f971SSimon Glass 0x0, 0x0, 0x0, 0x16, /* parameter size */ 6052132f971SSimon Glass 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ 6062132f971SSimon Glass 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */ 6072132f971SSimon Glass 0x0, 0x0, 0x0, 0x4, /* subcap size */ 6082132f971SSimon Glass 0x0, 0x0, 0x1, 0x8, /* subcap value */ 6092132f971SSimon Glass }; 6102132f971SSimon Glass uint8_t response[COMMAND_BUFFER_SIZE]; 6112132f971SSimon Glass size_t response_length = sizeof(response); 6122132f971SSimon Glass uint32_t err; 6132132f971SSimon Glass 6142132f971SSimon Glass err = tpm_sendrecv_command(command, response, &response_length); 6152132f971SSimon Glass if (err) 6162132f971SSimon Glass return err; 6172132f971SSimon Glass memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags)); 6182132f971SSimon Glass 6192132f971SSimon Glass return 0; 6202132f971SSimon Glass } 6212132f971SSimon Glass 6222132f971SSimon Glass uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm) 6232132f971SSimon Glass { 6242132f971SSimon Glass const uint8_t command[22] = { 6252132f971SSimon Glass 0x0, 0xc1, /* TPM_TAG */ 6262132f971SSimon Glass 0x0, 0x0, 0x0, 0x16, /* parameter size */ 6272132f971SSimon Glass 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */ 6282132f971SSimon Glass 0x0, 0x0, 0x0, 0x11, 6292132f971SSimon Glass 0x0, 0x0, 0x0, 0x4, 6302132f971SSimon Glass }; 6312132f971SSimon Glass const size_t index_offset = 18; 6322132f971SSimon Glass const size_t perm_offset = 60; 6332132f971SSimon Glass uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 6342132f971SSimon Glass size_t response_length = sizeof(response); 6352132f971SSimon Glass uint32_t err; 6362132f971SSimon Glass 6372132f971SSimon Glass if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command), 6382132f971SSimon Glass index_offset, index)) 6392132f971SSimon Glass return TPM_LIB_ERROR; 6402132f971SSimon Glass err = tpm_sendrecv_command(buf, response, &response_length); 6412132f971SSimon Glass if (err) 6422132f971SSimon Glass return err; 6432132f971SSimon Glass if (unpack_byte_string(response, response_length, "d", 6442132f971SSimon Glass perm_offset, perm)) 6452132f971SSimon Glass return TPM_LIB_ERROR; 6462132f971SSimon Glass 6472132f971SSimon Glass return 0; 6482132f971SSimon Glass } 6492132f971SSimon Glass 6507690be35SMario Six #ifdef CONFIG_TPM_FLUSH_RESOURCES 6517690be35SMario Six uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type) 6527690be35SMario Six { 6537690be35SMario Six const uint8_t command[18] = { 6547690be35SMario Six 0x00, 0xc1, /* TPM_TAG */ 6557690be35SMario Six 0x00, 0x00, 0x00, 0x12, /* parameter size */ 6567690be35SMario Six 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ 6577690be35SMario Six 0x00, 0x00, 0x00, 0x00, /* key handle */ 6587690be35SMario Six 0x00, 0x00, 0x00, 0x00, /* resource type */ 6597690be35SMario Six }; 6607690be35SMario Six const size_t key_handle_offset = 10; 6617690be35SMario Six const size_t resource_type_offset = 14; 6627690be35SMario Six uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE]; 6637690be35SMario Six size_t response_length = sizeof(response); 6647690be35SMario Six uint32_t err; 6657690be35SMario Six 6667690be35SMario Six if (pack_byte_string(buf, sizeof(buf), "sdd", 6677690be35SMario Six 0, command, sizeof(command), 6687690be35SMario Six key_handle_offset, key_handle, 6697690be35SMario Six resource_type_offset, resource_type)) 6707690be35SMario Six return TPM_LIB_ERROR; 6717690be35SMario Six 6727690be35SMario Six err = tpm_sendrecv_command(buf, response, &response_length); 6737690be35SMario Six if (err) 6747690be35SMario Six return err; 6757690be35SMario Six return 0; 6767690be35SMario Six } 6777690be35SMario Six #endif /* CONFIG_TPM_FLUSH_RESOURCES */ 6787690be35SMario Six 679be6c1529SReinhard Pfau #ifdef CONFIG_TPM_AUTH_SESSIONS 680be6c1529SReinhard Pfau 681be6c1529SReinhard Pfau /** 682be6c1529SReinhard Pfau * Fill an authentication block in a request. 683be6c1529SReinhard Pfau * This func can create the first as well as the second auth block (for 684be6c1529SReinhard Pfau * double authorized commands). 685be6c1529SReinhard Pfau * 686be6c1529SReinhard Pfau * @param request pointer to the request (w/ uninitialised auth data) 687be6c1529SReinhard Pfau * @param request_len0 length of the request without auth data 688be6c1529SReinhard Pfau * @param handles_len length of the handles area in request 689be6c1529SReinhard Pfau * @param auth_session pointer to the (valid) auth session to be used 690be6c1529SReinhard Pfau * @param request_auth pointer to the auth block of the request to be filled 691be6c1529SReinhard Pfau * @param auth authentication data (HMAC key) 692be6c1529SReinhard Pfau */ 693be6c1529SReinhard Pfau static uint32_t create_request_auth(const void *request, size_t request_len0, 694be6c1529SReinhard Pfau size_t handles_len, 695be6c1529SReinhard Pfau struct session_data *auth_session, 696be6c1529SReinhard Pfau void *request_auth, const void *auth) 697be6c1529SReinhard Pfau { 698be6c1529SReinhard Pfau uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; 699be6c1529SReinhard Pfau sha1_context hash_ctx; 700be6c1529SReinhard Pfau const size_t command_code_offset = 6; 701be6c1529SReinhard Pfau const size_t auth_nonce_odd_offset = 4; 702be6c1529SReinhard Pfau const size_t auth_continue_offset = 24; 703be6c1529SReinhard Pfau const size_t auth_auth_offset = 25; 704be6c1529SReinhard Pfau 705be6c1529SReinhard Pfau if (!auth_session || !auth_session->valid) 706be6c1529SReinhard Pfau return TPM_LIB_ERROR; 707be6c1529SReinhard Pfau 708be6c1529SReinhard Pfau sha1_starts(&hash_ctx); 709be6c1529SReinhard Pfau sha1_update(&hash_ctx, request + command_code_offset, 4); 710be6c1529SReinhard Pfau if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len) 711be6c1529SReinhard Pfau sha1_update(&hash_ctx, 712be6c1529SReinhard Pfau request + TPM_REQUEST_HEADER_LENGTH + handles_len, 713be6c1529SReinhard Pfau request_len0 - TPM_REQUEST_HEADER_LENGTH 714be6c1529SReinhard Pfau - handles_len); 715be6c1529SReinhard Pfau sha1_finish(&hash_ctx, hmac_data); 716be6c1529SReinhard Pfau 717be6c1529SReinhard Pfau sha1_starts(&hash_ctx); 718be6c1529SReinhard Pfau sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH); 719be6c1529SReinhard Pfau sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data)); 720be6c1529SReinhard Pfau sha1_finish(&hash_ctx, auth_session->nonce_odd); 721be6c1529SReinhard Pfau 722be6c1529SReinhard Pfau if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb", 723be6c1529SReinhard Pfau 0, auth_session->handle, 724be6c1529SReinhard Pfau auth_nonce_odd_offset, auth_session->nonce_odd, 725be6c1529SReinhard Pfau DIGEST_LENGTH, 726be6c1529SReinhard Pfau auth_continue_offset, 1)) 727be6c1529SReinhard Pfau return TPM_LIB_ERROR; 728be6c1529SReinhard Pfau if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss", 729be6c1529SReinhard Pfau DIGEST_LENGTH, 730be6c1529SReinhard Pfau auth_session->nonce_even, 731be6c1529SReinhard Pfau DIGEST_LENGTH, 732be6c1529SReinhard Pfau 2 * DIGEST_LENGTH, 733be6c1529SReinhard Pfau request_auth + auth_nonce_odd_offset, 734be6c1529SReinhard Pfau DIGEST_LENGTH + 1)) 735be6c1529SReinhard Pfau return TPM_LIB_ERROR; 736be6c1529SReinhard Pfau sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), 737be6c1529SReinhard Pfau request_auth + auth_auth_offset); 738be6c1529SReinhard Pfau 739be6c1529SReinhard Pfau return TPM_SUCCESS; 740be6c1529SReinhard Pfau } 741be6c1529SReinhard Pfau 742be6c1529SReinhard Pfau /** 743be6c1529SReinhard Pfau * Verify an authentication block in a response. 744be6c1529SReinhard Pfau * Since this func updates the nonce_even in the session data it has to be 745be6c1529SReinhard Pfau * called when receiving a succesfull AUTH response. 746be6c1529SReinhard Pfau * This func can verify the first as well as the second auth block (for 747be6c1529SReinhard Pfau * double authorized commands). 748be6c1529SReinhard Pfau * 749be6c1529SReinhard Pfau * @param command_code command code of the request 750be6c1529SReinhard Pfau * @param response pointer to the request (w/ uninitialised auth data) 751be6c1529SReinhard Pfau * @param handles_len length of the handles area in response 752be6c1529SReinhard Pfau * @param auth_session pointer to the (valid) auth session to be used 753be6c1529SReinhard Pfau * @param response_auth pointer to the auth block of the response to be verified 754be6c1529SReinhard Pfau * @param auth authentication data (HMAC key) 755be6c1529SReinhard Pfau */ 756be6c1529SReinhard Pfau static uint32_t verify_response_auth(uint32_t command_code, 757be6c1529SReinhard Pfau const void *response, size_t response_len0, 758be6c1529SReinhard Pfau size_t handles_len, 759be6c1529SReinhard Pfau struct session_data *auth_session, 760be6c1529SReinhard Pfau const void *response_auth, const void *auth) 761be6c1529SReinhard Pfau { 762be6c1529SReinhard Pfau uint8_t hmac_data[DIGEST_LENGTH * 3 + 1]; 763be6c1529SReinhard Pfau uint8_t computed_auth[DIGEST_LENGTH]; 764be6c1529SReinhard Pfau sha1_context hash_ctx; 765be6c1529SReinhard Pfau const size_t return_code_offset = 6; 766be6c1529SReinhard Pfau const size_t auth_continue_offset = 20; 767be6c1529SReinhard Pfau const size_t auth_auth_offset = 21; 768be6c1529SReinhard Pfau uint8_t auth_continue; 769be6c1529SReinhard Pfau 770be6c1529SReinhard Pfau if (!auth_session || !auth_session->valid) 771be6c1529SReinhard Pfau return TPM_AUTHFAIL; 772be6c1529SReinhard Pfau if (pack_byte_string(hmac_data, sizeof(hmac_data), "d", 773be6c1529SReinhard Pfau 0, command_code)) 774be6c1529SReinhard Pfau return TPM_LIB_ERROR; 775be6c1529SReinhard Pfau if (response_len0 < TPM_RESPONSE_HEADER_LENGTH) 776be6c1529SReinhard Pfau return TPM_LIB_ERROR; 777be6c1529SReinhard Pfau 778be6c1529SReinhard Pfau sha1_starts(&hash_ctx); 779be6c1529SReinhard Pfau sha1_update(&hash_ctx, response + return_code_offset, 4); 780be6c1529SReinhard Pfau sha1_update(&hash_ctx, hmac_data, 4); 781be6c1529SReinhard Pfau if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len) 782be6c1529SReinhard Pfau sha1_update(&hash_ctx, 783be6c1529SReinhard Pfau response + TPM_RESPONSE_HEADER_LENGTH + handles_len, 784be6c1529SReinhard Pfau response_len0 - TPM_RESPONSE_HEADER_LENGTH 785be6c1529SReinhard Pfau - handles_len); 786be6c1529SReinhard Pfau sha1_finish(&hash_ctx, hmac_data); 787be6c1529SReinhard Pfau 788be6c1529SReinhard Pfau memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH); 789be6c1529SReinhard Pfau auth_continue = ((uint8_t *)response_auth)[auth_continue_offset]; 790be6c1529SReinhard Pfau if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb", 791be6c1529SReinhard Pfau DIGEST_LENGTH, 792be6c1529SReinhard Pfau response_auth, 793be6c1529SReinhard Pfau DIGEST_LENGTH, 794be6c1529SReinhard Pfau 2 * DIGEST_LENGTH, 795be6c1529SReinhard Pfau auth_session->nonce_odd, 796be6c1529SReinhard Pfau DIGEST_LENGTH, 797be6c1529SReinhard Pfau 3 * DIGEST_LENGTH, 798be6c1529SReinhard Pfau auth_continue)) 799be6c1529SReinhard Pfau return TPM_LIB_ERROR; 800be6c1529SReinhard Pfau 801be6c1529SReinhard Pfau sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data), 802be6c1529SReinhard Pfau computed_auth); 803be6c1529SReinhard Pfau 804be6c1529SReinhard Pfau if (memcmp(computed_auth, response_auth + auth_auth_offset, 805be6c1529SReinhard Pfau DIGEST_LENGTH)) 806be6c1529SReinhard Pfau return TPM_AUTHFAIL; 807be6c1529SReinhard Pfau 808be6c1529SReinhard Pfau return TPM_SUCCESS; 809be6c1529SReinhard Pfau } 810be6c1529SReinhard Pfau 811be6c1529SReinhard Pfau 812be6c1529SReinhard Pfau uint32_t tpm_terminate_auth_session(uint32_t auth_handle) 813be6c1529SReinhard Pfau { 814be6c1529SReinhard Pfau const uint8_t command[18] = { 815be6c1529SReinhard Pfau 0x00, 0xc1, /* TPM_TAG */ 816be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parameter size */ 817be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */ 818be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */ 819be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x02, /* TPM_RESSOURCE_TYPE */ 820be6c1529SReinhard Pfau }; 821be6c1529SReinhard Pfau const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH; 822be6c1529SReinhard Pfau uint8_t request[COMMAND_BUFFER_SIZE]; 823be6c1529SReinhard Pfau 824be6c1529SReinhard Pfau if (pack_byte_string(request, sizeof(request), "sd", 825be6c1529SReinhard Pfau 0, command, sizeof(command), 826be6c1529SReinhard Pfau req_handle_offset, auth_handle)) 827be6c1529SReinhard Pfau return TPM_LIB_ERROR; 828be6c1529SReinhard Pfau if (oiap_session.valid && oiap_session.handle == auth_handle) 829be6c1529SReinhard Pfau oiap_session.valid = 0; 830be6c1529SReinhard Pfau 831be6c1529SReinhard Pfau return tpm_sendrecv_command(request, NULL, NULL); 832be6c1529SReinhard Pfau } 833be6c1529SReinhard Pfau 834be6c1529SReinhard Pfau uint32_t tpm_end_oiap(void) 835be6c1529SReinhard Pfau { 836be6c1529SReinhard Pfau uint32_t err = TPM_SUCCESS; 837be6c1529SReinhard Pfau if (oiap_session.valid) 838be6c1529SReinhard Pfau err = tpm_terminate_auth_session(oiap_session.handle); 839be6c1529SReinhard Pfau return err; 840be6c1529SReinhard Pfau } 841be6c1529SReinhard Pfau 842be6c1529SReinhard Pfau uint32_t tpm_oiap(uint32_t *auth_handle) 843be6c1529SReinhard Pfau { 844be6c1529SReinhard Pfau const uint8_t command[10] = { 845be6c1529SReinhard Pfau 0x00, 0xc1, /* TPM_TAG */ 846be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x0a, /* parameter size */ 847be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */ 848be6c1529SReinhard Pfau }; 849be6c1529SReinhard Pfau const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH; 850be6c1529SReinhard Pfau const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4; 851be6c1529SReinhard Pfau uint8_t response[COMMAND_BUFFER_SIZE]; 852be6c1529SReinhard Pfau size_t response_length = sizeof(response); 853be6c1529SReinhard Pfau uint32_t err; 854be6c1529SReinhard Pfau 855be6c1529SReinhard Pfau if (oiap_session.valid) 856be6c1529SReinhard Pfau tpm_terminate_auth_session(oiap_session.handle); 857be6c1529SReinhard Pfau 858be6c1529SReinhard Pfau err = tpm_sendrecv_command(command, response, &response_length); 859be6c1529SReinhard Pfau if (err) 860be6c1529SReinhard Pfau return err; 861be6c1529SReinhard Pfau if (unpack_byte_string(response, response_length, "ds", 862be6c1529SReinhard Pfau res_auth_handle_offset, &oiap_session.handle, 863be6c1529SReinhard Pfau res_nonce_even_offset, &oiap_session.nonce_even, 864be6c1529SReinhard Pfau (uint32_t)DIGEST_LENGTH)) 865be6c1529SReinhard Pfau return TPM_LIB_ERROR; 866be6c1529SReinhard Pfau oiap_session.valid = 1; 867be6c1529SReinhard Pfau if (auth_handle) 868be6c1529SReinhard Pfau *auth_handle = oiap_session.handle; 869be6c1529SReinhard Pfau return 0; 870be6c1529SReinhard Pfau } 871be6c1529SReinhard Pfau 872be6c1529SReinhard Pfau uint32_t tpm_load_key2_oiap(uint32_t parent_handle, 873be6c1529SReinhard Pfau const void *key, size_t key_length, 874be6c1529SReinhard Pfau const void *parent_key_usage_auth, 875be6c1529SReinhard Pfau uint32_t *key_handle) 876be6c1529SReinhard Pfau { 877be6c1529SReinhard Pfau const uint8_t command[14] = { 878be6c1529SReinhard Pfau 0x00, 0xc2, /* TPM_TAG */ 879be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parameter size */ 880be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */ 881be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parent handle */ 882be6c1529SReinhard Pfau }; 883be6c1529SReinhard Pfau const size_t req_size_offset = 2; 884be6c1529SReinhard Pfau const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH; 885be6c1529SReinhard Pfau const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4; 886be6c1529SReinhard Pfau const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH; 887be6c1529SReinhard Pfau uint8_t request[sizeof(command) + TPM_KEY12_MAX_LENGTH 888be6c1529SReinhard Pfau + TPM_REQUEST_AUTH_LENGTH]; 889be6c1529SReinhard Pfau uint8_t response[COMMAND_BUFFER_SIZE]; 890be6c1529SReinhard Pfau size_t response_length = sizeof(response); 891be6c1529SReinhard Pfau uint32_t err; 892be6c1529SReinhard Pfau 893be6c1529SReinhard Pfau if (!oiap_session.valid) { 894be6c1529SReinhard Pfau err = tpm_oiap(NULL); 895be6c1529SReinhard Pfau if (err) 896be6c1529SReinhard Pfau return err; 897be6c1529SReinhard Pfau } 898be6c1529SReinhard Pfau if (pack_byte_string(request, sizeof(request), "sdds", 899be6c1529SReinhard Pfau 0, command, sizeof(command), 900be6c1529SReinhard Pfau req_size_offset, 901be6c1529SReinhard Pfau sizeof(command) + key_length 902be6c1529SReinhard Pfau + TPM_REQUEST_AUTH_LENGTH, 903be6c1529SReinhard Pfau req_parent_handle_offset, parent_handle, 904be6c1529SReinhard Pfau req_key_offset, key, key_length 905be6c1529SReinhard Pfau )) 906be6c1529SReinhard Pfau return TPM_LIB_ERROR; 907be6c1529SReinhard Pfau 908be6c1529SReinhard Pfau err = create_request_auth(request, sizeof(command) + key_length, 4, 909be6c1529SReinhard Pfau &oiap_session, 910be6c1529SReinhard Pfau request + sizeof(command) + key_length, 911be6c1529SReinhard Pfau parent_key_usage_auth); 912be6c1529SReinhard Pfau if (err) 913be6c1529SReinhard Pfau return err; 914be6c1529SReinhard Pfau err = tpm_sendrecv_command(request, response, &response_length); 915be6c1529SReinhard Pfau if (err) { 916be6c1529SReinhard Pfau if (err == TPM_AUTHFAIL) 917be6c1529SReinhard Pfau oiap_session.valid = 0; 918be6c1529SReinhard Pfau return err; 919be6c1529SReinhard Pfau } 920be6c1529SReinhard Pfau 921be6c1529SReinhard Pfau err = verify_response_auth(0x00000041, response, 922be6c1529SReinhard Pfau response_length - TPM_RESPONSE_AUTH_LENGTH, 923be6c1529SReinhard Pfau 4, &oiap_session, 924be6c1529SReinhard Pfau response + response_length - TPM_RESPONSE_AUTH_LENGTH, 925be6c1529SReinhard Pfau parent_key_usage_auth); 926be6c1529SReinhard Pfau if (err) 927be6c1529SReinhard Pfau return err; 928be6c1529SReinhard Pfau 929be6c1529SReinhard Pfau if (key_handle) { 930be6c1529SReinhard Pfau if (unpack_byte_string(response, response_length, "d", 931be6c1529SReinhard Pfau res_handle_offset, key_handle)) 932be6c1529SReinhard Pfau return TPM_LIB_ERROR; 933be6c1529SReinhard Pfau } 934be6c1529SReinhard Pfau 935be6c1529SReinhard Pfau return 0; 936be6c1529SReinhard Pfau } 937be6c1529SReinhard Pfau 938be6c1529SReinhard Pfau uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, 939be6c1529SReinhard Pfau void *pubkey, size_t *pubkey_len) 940be6c1529SReinhard Pfau { 941be6c1529SReinhard Pfau const uint8_t command[14] = { 942be6c1529SReinhard Pfau 0x00, 0xc2, /* TPM_TAG */ 943be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* parameter size */ 944be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */ 945be6c1529SReinhard Pfau 0x00, 0x00, 0x00, 0x00, /* key handle */ 946be6c1529SReinhard Pfau }; 947be6c1529SReinhard Pfau const size_t req_size_offset = 2; 948be6c1529SReinhard Pfau const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH; 949be6c1529SReinhard Pfau const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH; 950be6c1529SReinhard Pfau uint8_t request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH]; 951be6c1529SReinhard Pfau uint8_t response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH 952be6c1529SReinhard Pfau + TPM_RESPONSE_AUTH_LENGTH]; 953be6c1529SReinhard Pfau size_t response_length = sizeof(response); 954be6c1529SReinhard Pfau uint32_t err; 955be6c1529SReinhard Pfau 956be6c1529SReinhard Pfau if (!oiap_session.valid) { 957be6c1529SReinhard Pfau err = tpm_oiap(NULL); 958be6c1529SReinhard Pfau if (err) 959be6c1529SReinhard Pfau return err; 960be6c1529SReinhard Pfau } 961be6c1529SReinhard Pfau if (pack_byte_string(request, sizeof(request), "sdd", 962be6c1529SReinhard Pfau 0, command, sizeof(command), 963be6c1529SReinhard Pfau req_size_offset, 964be6c1529SReinhard Pfau (uint32_t)(sizeof(command) 965be6c1529SReinhard Pfau + TPM_REQUEST_AUTH_LENGTH), 966be6c1529SReinhard Pfau req_key_handle_offset, key_handle 967be6c1529SReinhard Pfau )) 968be6c1529SReinhard Pfau return TPM_LIB_ERROR; 969be6c1529SReinhard Pfau err = create_request_auth(request, sizeof(command), 4, &oiap_session, 970be6c1529SReinhard Pfau request + sizeof(command), usage_auth); 971be6c1529SReinhard Pfau if (err) 972be6c1529SReinhard Pfau return err; 973be6c1529SReinhard Pfau err = tpm_sendrecv_command(request, response, &response_length); 974be6c1529SReinhard Pfau if (err) { 975be6c1529SReinhard Pfau if (err == TPM_AUTHFAIL) 976be6c1529SReinhard Pfau oiap_session.valid = 0; 977be6c1529SReinhard Pfau return err; 978be6c1529SReinhard Pfau } 979be6c1529SReinhard Pfau err = verify_response_auth(0x00000021, response, 980be6c1529SReinhard Pfau response_length - TPM_RESPONSE_AUTH_LENGTH, 981be6c1529SReinhard Pfau 0, &oiap_session, 982be6c1529SReinhard Pfau response + response_length - TPM_RESPONSE_AUTH_LENGTH, 983be6c1529SReinhard Pfau usage_auth); 984be6c1529SReinhard Pfau if (err) 985be6c1529SReinhard Pfau return err; 986be6c1529SReinhard Pfau 987be6c1529SReinhard Pfau if (pubkey) { 988be6c1529SReinhard Pfau if ((response_length - TPM_RESPONSE_HEADER_LENGTH 989be6c1529SReinhard Pfau - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len) 990be6c1529SReinhard Pfau return TPM_LIB_ERROR; 991be6c1529SReinhard Pfau *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH 992be6c1529SReinhard Pfau - TPM_RESPONSE_AUTH_LENGTH; 993be6c1529SReinhard Pfau memcpy(pubkey, response + res_pubkey_offset, 994be6c1529SReinhard Pfau response_length - TPM_RESPONSE_HEADER_LENGTH 995be6c1529SReinhard Pfau - TPM_RESPONSE_AUTH_LENGTH); 996be6c1529SReinhard Pfau } 997be6c1529SReinhard Pfau 998be6c1529SReinhard Pfau return 0; 999be6c1529SReinhard Pfau } 1000be6c1529SReinhard Pfau 10010f4b2ba1Smario.six@gdsys.cc #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 10020f4b2ba1Smario.six@gdsys.cc uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t 10030f4b2ba1Smario.six@gdsys.cc pubkey_digest[20], uint32_t *handle) 10040f4b2ba1Smario.six@gdsys.cc { 10050f4b2ba1Smario.six@gdsys.cc uint16_t key_count; 10060f4b2ba1Smario.six@gdsys.cc uint32_t key_handles[10]; 10070f4b2ba1Smario.six@gdsys.cc uint8_t buf[288]; 10080f4b2ba1Smario.six@gdsys.cc uint8_t *ptr; 10090f4b2ba1Smario.six@gdsys.cc uint32_t err; 10100f4b2ba1Smario.six@gdsys.cc uint8_t digest[20]; 10110f4b2ba1Smario.six@gdsys.cc size_t buf_len; 10120f4b2ba1Smario.six@gdsys.cc unsigned int i; 10130f4b2ba1Smario.six@gdsys.cc 10140f4b2ba1Smario.six@gdsys.cc /* fetch list of already loaded keys in the TPM */ 10150f4b2ba1Smario.six@gdsys.cc err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf)); 10160f4b2ba1Smario.six@gdsys.cc if (err) 10170f4b2ba1Smario.six@gdsys.cc return -1; 10180f4b2ba1Smario.six@gdsys.cc key_count = get_unaligned_be16(buf); 10190f4b2ba1Smario.six@gdsys.cc ptr = buf + 2; 10200f4b2ba1Smario.six@gdsys.cc for (i = 0; i < key_count; ++i, ptr += 4) 10210f4b2ba1Smario.six@gdsys.cc key_handles[i] = get_unaligned_be32(ptr); 10220f4b2ba1Smario.six@gdsys.cc 10230f4b2ba1Smario.six@gdsys.cc /* now search a(/ the) key which we can access with the given auth */ 10240f4b2ba1Smario.six@gdsys.cc for (i = 0; i < key_count; ++i) { 10250f4b2ba1Smario.six@gdsys.cc buf_len = sizeof(buf); 10260f4b2ba1Smario.six@gdsys.cc err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len); 10270f4b2ba1Smario.six@gdsys.cc if (err && err != TPM_AUTHFAIL) 10280f4b2ba1Smario.six@gdsys.cc return -1; 10290f4b2ba1Smario.six@gdsys.cc if (err) 10300f4b2ba1Smario.six@gdsys.cc continue; 10310f4b2ba1Smario.six@gdsys.cc sha1_csum(buf, buf_len, digest); 10320f4b2ba1Smario.six@gdsys.cc if (!memcmp(digest, pubkey_digest, 20)) { 10330f4b2ba1Smario.six@gdsys.cc *handle = key_handles[i]; 10340f4b2ba1Smario.six@gdsys.cc return 0; 10350f4b2ba1Smario.six@gdsys.cc } 10360f4b2ba1Smario.six@gdsys.cc } 10370f4b2ba1Smario.six@gdsys.cc return 1; 10380f4b2ba1Smario.six@gdsys.cc } 10390f4b2ba1Smario.six@gdsys.cc #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ 10400f4b2ba1Smario.six@gdsys.cc 1041be6c1529SReinhard Pfau #endif /* CONFIG_TPM_AUTH_SESSIONS */ 1042