From 3e716caac24e8cdc42127526ed07cbd4373d57cd Mon Sep 17 00:00:00 2001 From: Thomas Furtner Date: Fri, 7 Apr 2017 08:11:32 +0200 Subject: [PATCH] Add files via upload --- License.txt | 27 + Makefile | 13 + README.txt | 324 +++++++++++ eltt2.c | 1474 +++++++++++++++++++++++++++++++++++++++++++++++++++ eltt2.h | 527 ++++++++++++++++++ 5 files changed, 2365 insertions(+) create mode 100644 License.txt create mode 100644 Makefile create mode 100644 README.txt create mode 100644 eltt2.c create mode 100644 eltt2.h diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..e577cd6 --- /dev/null +++ b/License.txt @@ -0,0 +1,27 @@ +Copyright (c) 2014, Infineon Technologies AG +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c9d95da --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +# Makefile for Embedded Linux TPM Toolbox 2 (ELTT2) +# Copyright (c) Infineon Technologies AG + +CC=gcc +CFLAGS=-Wall -Wextra + +all: eltt2 + +eltt2: eltt2.c eltt2.h + $(CC) $(CFLAGS) eltt2.c -o eltt2 + +clean: + rm -rf eltt2 \ No newline at end of file diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..9904bdb --- /dev/null +++ b/README.txt @@ -0,0 +1,324 @@ +-------------------------------------------------------------------------------- + Infineon Embedded Linux TPM Toolbox 2 (ELTT2) for TPM 2.0 v1.0 + Infineon Technologies AG + +All information in this document is Copyright (c) 2014, Infineon Technologies AG +All rights reserved. +-------------------------------------------------------------------------------- + +Contents: + +1. Welcome +1.1 Prerequisites +1.2 Contents of the package +1.3 Getting Started + +2. Usage of Embedded Linux TPM Toolbox 2 (ELTT2) +2.1 Generic Usage +2.2 Examples + +3. If you have questions + +4. Release Info + +5. FAQ + +================================================================================ + + + +1. Welcome + + Welcome to Embedded Linux TPM Toolbox 2 (ELTT2). + ELTT2 is a single-file executable program intended for testing, performing + diagnosis and basic state changes of the Infineon Technologies TPM 2.0. + + +1.1 Prerequisites + + To build and run ELTT2 you need GCC and a Linux system capable of hosting a + TPM. + + Tested PC platforms + - Ubuntu (R) Linux 12.04 LTS - 64 bit (Kernel 3.8.0) + with Infineon TPM 2.0 SLB9665 Firmware 5.22 + + + ELTT2 may run on many other little-endian hardware and software + configurations capable of running Linux and hosting a TPM, but this has not + been tested. + + ELTT2 does not support machines with a big-endian CPU. + + +1.2 Contents of Package + + ELTT2 consists of the following files: + - eltt2.c + Contains all method implementations of ELTT2. + - eltt2.h + Contains all constant definitions, method and command byte declarations + for the operation of ELTT2. + - License.txt + Contains the license agreement for ELTT2. + - Makefile + Contains the command to compile ELTT2. + - README.txt + This file. + + +1.3 Getting Started + + In order to execute ELTT2, you need to compile it first: + 1. Switch to the directory with the ELTT2 source code + 2. Compile the source code by typing the following command: + make + + Due to hardware (and thus TPM) access restrictions for normal users, ELTT2 + requires root (aka superuser or administrator) privileges. They can be + obtained e.g. by using the 'sudo' command on Debian Linux derivates. + + +2. Usage of ELTT2 + + +2.1 Generic Usage + + ELTT2 is operated as follows: + + Call: ./eltt2 + + For example: ./eltt2 -g or ./eltt2 -gc + + For getting an overview of the possible commands, run ./eltt2 -h + + Some options require the TPM to be in a specific state. This state is shown + in brackets ("[]") behind each command line option in the list below: + + [u]: started + + To get the TPM into the required state, call ELTT2 with the corresponding + commands ("x" for a state means that whether this state is required or not + depends on the actual command or the command parameters sent eventually to + the TPM). + + + Command line options: Preconditions: + + -a : Hash Sequence SHA-1 [u] + + -A : Hash Sequence SHA-256 [u] + + -b : Enter your own TPM command [u] + + -c: Read Clock [u] + + -d : Shutdown [u] + + -e: PCR Extend SHA-1 [u] + + -E: PCR Extend SHA-256 [u] + + -g: Get Capability 'TPM Properties' [u] + + -G : Get Random [u] + + -h: Help [-] + + -r : PCR Read SHA-1 [u] + + -R : PCR Read SHA-256 [u] + + -s : Hash SHA-1 [u] + + -S : Hash SHA-256 [u] + + -t : Self Test [u] + + -T: Get Test Result [u] + + -u : Startup [-] + + -z : PCR Reset [u] + + + Additional information: + + -a: + With the "-a" command you can hash given data with the SHA-1 hash algorithm. + This hash sequence sends 3 commands [start, update, complete] to the TPM and + allows to hash an arbitrary amount of data. + For example, use the following command to hash the byte sequence {0x41, + 0x62, 0x43, 0x64}: + ./eltt2 -a 41624364 + + -A: + With the "-A" command you can hash given data with the SHA-256 hash + algorithm. This hash sequence sends 3 commands [start, update, complete] to + the TPM and allows to hash an arbitrary amount of data. + For example, use the following command to hash the byte sequence {0x41, + 0x62, 0x43, 0x64}: + ./eltt2 -A 41624364 + + -b: + With the "-b" command you can enter your own TPM command bytes and read the + TPM response. + For example, use the following command to send a TPM2_Startup with startup + type CLEAR to the TPM: + ./eltt2 -b 80010000000C000001440000 + + -c: + With the "-c" command you can read the clock values of the TPM. + + -d: + With the "-d" command you can issue a TPM shutdown. It has 2 options: + ./eltt2 -d + or + ./eltt2 -d clear send a TPM2_Shutdown command with shutdown type CLEAR to + the TPM. + ./eltt2 -d state send a TPM2_Shutdown command with shutdown type STATE to + the TPM. + + -e: + With the "-e" command you can extend bytes in the selected PCR with SHA-1. + To do so, you have to enter the index of PCR in hexadecimal that you like to + extend and the digest you want to extend the selected PCR with. Note that + you can only extend PCRs with index 0 to 16 and PCR 23 and that the digest + must have a length of 20 bytes (will be padded with 0 if necessary). + The TPM then builds an SHA-1 hash over the PCR data in the selected PCR and + the digest you provided and writes the result back to the selected PCR. + For example, use the following command to extend PCR 23 (0x17) with the byte + sequence {0x41, 0x62, 0x43, 0x64, 0x00, ... (will be filled with 0x00)}: + ./eltt2 -e 17 41624364 + + -E: + With the "-E" command you can extend bytes in the selected PCR with SHA-256. + To do so, you have to enter the index of PCR in hexadecimal that you like to + extend and the digest you want to extend the selected PCR with. Note that + you can only extend PCRs with index 0 to 16 and PCR 23 and that the digest + must have a length of 32 bytes (will be padded with 0 if necessary). + The TPM then builds an SHA-256 hash over the PCR data in the selected PCR + and the digest you provided and writes the result back to the selected PCR. + For example, use the following command to extend PCR 23 (0x17) with the byte + sequence {0x41, 0x62, 0x43, 0x64, 0x00, ... (will be filled with 0x00)}: + ./eltt2 -E 17 41624364 + + -g: + With the "-g" command you can read the TPM's properties. + + -G: + With the "-G" command you can get a given amount of random bytes. Note that + you can only request a maximum amount of 32 random bytes at once. + For example, use the following command to get 20 (0x14) random bytes: + ./eltt2 -G 14 + + -r: + With the "-r" command you can read data from a selected SHA-1 PCR. + For example, use the following command to read data from PCR 23 (0x17): + ./eltt2 -r 17 + + -R: + With the "-R" command you can read data from a selected SHA-256 PCR. + For example, use the following command to read data from PCR 23 (0x17): + ./eltt2 -R 17 + + -s: + With the "-s" command you can hash given data with the SHA-1 hash algorithm. + This command only allows a limited amount of data to be hashed (depending on + the TPM's maximum input buffer size). + For example, use the following command to hash the byte sequence {0x41, + 0x62, 0x43, 0x64}: + ./eltt2 -s 41624364 + + -S: + With the "-S" command you can hash given data with the SHA-256 hash + algorithm. This command only allows a limited amount of data to be hashed + (depending on the TPM input buffer size). + For example, use the following command to hash the byte sequence {0x41, + 0x62, 0x43, 0x64}: + ./eltt2 -S 41624364 + + -t: + With the "-t" command you can issue a TPM selftest. It has 3 options: + ./eltt2 -t + or + ./eltt2 -t not_full Perform a partial TPM2_Selftest to test previously + untested TPM capabilities. + ./eltt2 -t full Perform a full TPM2_Selftest to test all TPM + capabilities. + ./eltt2 -t incremental Perform a test of selected algorithms. + + -T: + With the "-T" command you can read the results of a previously run selftest. + + -u: + With the "-u" command you can issue a TPM startup command. It has 2 options: + ./eltt2 -u + or + ./eltt2 -u clear send a TPM2_Startup with startup type CLEAR to the TPM. + ./eltt2 -u state send a TPM2_Startup with startup type STATE to the TPM. + + -z: + With the "-z" command you can reset a selected PCR. Note that you can only + reset PCRs 16 and 23. + For example, use the following command to reset PCR 23 (0x17): + ./eltt2 -z 17 + + +2.2 Examples: + + In order to work with the TPM, perform the following steps: + - Send the TPM2_Startup command: ./eltt2 -u + + + +3. If you have questions + + If you have any questions or problems, please read the section "FAQ and + Troubleshooting" in this document. + In case you still have questions, contact your local Infineon + Representative. + Further information is available at http://www.infineon.com/tpm. + + + +4. Release Info + + This is version 1.0. This version is a general release. + + + +5. FAQ and Troubleshooting + + If you encounter any error, please make sure that + - the TPM is properly connected. + - the TPM driver is loaded, i.e. check that "/dev/tpm0" exists. In case of + driver loading problems (e.g. shown by "Error opening device"), reboot + your system and try to load the driver again. + - ELTT2 has been started with root permissions. Please note that ELTT2 needs + root permissions for all commands. + - the TPM is started. (See section 2.2 in this document on how to do this.) + - Trousers do not run anymore. In some cases the Kernel starts Trousers by + booting. + Shut down Trousers by entering the following command: + sudo pkill tcsd + + The following list shows the most common errors and their solution: + + The ELTT2 response is "Error opening the device.": + - You need to load a TPM driver before you can work with ELTT2. + - You need to start ELTT2 with root permissions. + + The ELTT2 responds with error code 0x100. + - You need to send the TPM2_Startup command, or you did send it twice. In + case you have not sent it yet, do so with "./eltt2 -u". + + The TPM does not change any of the permanent flags shown by sending the "-g" + command , e.g. after a force clear. + - The TPM requires a reset in order to change any of the permanent flags. + Press the reset button or disconnect the TPM to do so. + + The value of a PCR does not change after sending PCR extend or reset. + - With the application permissions you cannot modify every PCR. For more + details, please refer to the description for the different PCR commands + in this file. diff --git a/eltt2.c b/eltt2.c new file mode 100644 index 0000000..bf2a095 --- /dev/null +++ b/eltt2.c @@ -0,0 +1,1474 @@ +/** + * @brief Embedded Linux TPM Toolbox 2 (ELTT2) + * @details eltt2.c implements some basic methods to communicate with the Infineon TPM 2.0 without the TDDL lib. + * @file eltt2.c + * @date 2014/06/26 + * @copyright Copyright (c) 2014, Infineon Technologies AG\n + * All rights reserved.\n + * \n + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following + * conditions are met:\n + * \n + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer.\n + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution.\n + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission.\n + * \n + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "eltt2.h" + +/** + * @brief Main entry point of the application. + * @details Handles the command line input and starts the communication with the TPM. + * @param [in] argc Counter for input parameters. + * @param [in] **argv Input parameters. + * @return One of the listed return codes, the TPM return code or the error code stored in the global errno system variable. + * @retval EXIT_SUCCESS In case of success. + * @retval ERR_BAD_CMD In case an invalid command line option. + * @retval value of errno In case of memory allocation error. + * @retval tpmtool_transmit All error codes from tpmtool_transmit. + * @retval return_error_handling All error codes from return_error_handling. + * @retval response_print All error codes from response_print. + * @retval create_hash_sequence All error codes from create_hash_sequence. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @retval pcr_extend All error codes from pcr_extend. + * @retval get_random All error codes from get_random. + * @retval pcr_read All error codes from pcr_read. + * @retval create_hash All error codes from create_hash. + * @retval pcr_reset All error codes from pcr_reset. + * @date 2014/06/26 + */ +int main(int argc, char **argv) +{ + // ---------- Local declarations ---------- + int ret_val = EXIT_SUCCESS; // Return value. + uint8_t *tpm_response_buf = NULL; // Buffer for TPM response. + ssize_t tpm_response_buf_size = 0; // Size of tpm_response_buf. + int i = 0; // Command line parsing counter. + int option = 0; // Command line option. + uint8_t *input_bytes = NULL; // Custom command bytes for transmit in case of command line options -b and -E. + size_t input_bytes_size = 0; // Size of input_bytes. + int no_transmission = 0; // Flag to skip the transmission call, e.g. in case of command line option -h. + int tpm_error = 0; // Flag to indicate whether a TPM response has returned a TPM error code or not. + + // ---------- Program flow ---------- + printf("\n"); + do // Begin of DO WHILE(FALSE) for error handling. + { + // ---------- Allocate memory for buffer containing TPM response ---------- + tpm_response_buf_size = TPM_RESP_MAX_SIZE; + tpm_response_buf = malloc(tpm_response_buf_size); + MALLOC_ERROR_CHECK(tpm_response_buf); + memset(tpm_response_buf, 0xFF, tpm_response_buf_size); + + // ---------- Check for command line parameters ---------- + if (1 == argc) + { + fprintf(stderr, "ELTT needs an option. Use '-h' for displaying help.\n"); + ret_val = ERR_BAD_CMD; + break; + } + + // ---------- Command line parsing with getopt ---------- + opterr = 0; // Disable getopt error messages in case of unknown parameters; we want to use our own error messages. + + // Loop through parameters with getopt. + while (-1 != (option = getopt(argc, argv, "cghTa:A:b:d:e:E:G:r:R:s:S:t:u:z:"))) + { + switch (option) + { + case 'a': // TPM2_HashSequenceStart SHA-1 + case 'A': // TPM2_HashSequenceStart SHA-256 + ret_val = create_hash_sequence(optarg, option, tpm_response_buf, &tpm_response_buf_size); + break; + + case 'b': // Enter your own command bytes + // Allocate the input buffer for hexstr_to_bytearray and tpmtool_transmit. + input_bytes_size = strlen(optarg) / 2 + strlen(optarg) % 2; // 2 characters == 1 byte => size of input command bytes: length of input string / 2. + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0xFF, input_bytes_size); + + // Convert the command line input to bytes. + ret_val = hexstr_to_bytearray(optarg, input_bytes, input_bytes_size); + RET_VAL_CHECK(ret_val); + + // Send bytes to TPM. + ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size); + break; + + case 'c': // TPM_CC_ReadClock + ret_val = tpmtool_transmit(tpm_cc_readclock, sizeof(tpm_cc_readclock), tpm_response_buf, &tpm_response_buf_size); + break; + + case 'd': // TPM_CC_Shutdown + if (0 == strcasecmp(optarg, "clear")) + { + ret_val = tpmtool_transmit(tpm_cc_shutdown_clear, sizeof(tpm_cc_shutdown_clear), tpm_response_buf, &tpm_response_buf_size); + } + else if (0 == strcasecmp(optarg, "state")) + { + ret_val = tpmtool_transmit(tpm_cc_shutdown_state, sizeof(tpm_cc_shutdown_state), tpm_response_buf, &tpm_response_buf_size); + } + else + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Unknown option. Use '-h' for more information.\n"); + } + break; + + case 'e': // PCR_Extend SHA-1 + case 'E': // PCR_Extend SHA-256 + if (4 > argc) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "The command '-%c' needs two arguments. Use '-h' for more information.\n", option); + + // Set the argument count to the next option for error handling. + optind += 2; + break; + } + + // Allocate the input buffer for pcr_extend and tpmtool_transmit. + if ('e' == option) + { + input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA1_DIGEST_SIZE; + } + else + { + input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA256_DIGEST_SIZE; + } + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0, input_bytes_size); + + // Create PCR_Extend TPM request. + ret_val = pcr_extend(optarg, argv[optind], input_bytes, input_bytes_size, option); + + // Set the argument count to the next option for error handling. + optind++; + RET_VAL_CHECK(ret_val); + + // Send bytes to TPM. + ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size); + break; + + case 'g': // TPM_CC_GetCapability + ret_val = tpmtool_transmit(tpm2_getcapability, sizeof(tpm2_getcapability), tpm_response_buf, &tpm_response_buf_size); + break; + + case 'G': // TPM_CC_GetRandom + // Allocate the input buffer for get_random and tpmtool_transmit. + input_bytes_size = (sizeof(tpm2_getrandom)); + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0, input_bytes_size); + + // Create GetRandom TPM request. + ret_val = get_random(optarg, input_bytes); + RET_VAL_CHECK(ret_val); + + // Send bytes to TPM. + ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size); + break; + + case 'h': // Help + print_help(); + + // Set flag to skip any TPM transmission + no_transmission = 1; + break; + + case 'r': // PCR_Read SHA-1 + case 'R': // PCR_Read SHA-256 + // Allocate the input buffer for pcr_read and tpmtool_transmit. + input_bytes_size = sizeof(tpm2_pcr_read); + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0, input_bytes_size); + + // Create PCR_Read TPM request. + ret_val = pcr_read(optarg, input_bytes, option); + RET_VAL_CHECK(ret_val); + + // Send bytes to TPM. + ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size); + break; + + case 's': // Hash SHA-1 + case 'S': // Hash SHA-256 + // Allocate the input buffer for create_hash and tpmtool_transmit. + input_bytes_size = strlen(optarg) / 2 + strlen(optarg) % 2 + sizeof(tpm2_hash); + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0, input_bytes_size); + + // Create Hash TPM request. + ret_val = create_hash(optarg, option, input_bytes, input_bytes_size); + RET_VAL_CHECK(ret_val); + + // Send bytes to TPM. + ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size); + break; + + case 't': // TPM2_SelfTest + if (0 == strcasecmp(optarg, "not_full")) + { + ret_val = tpmtool_transmit(tpm2_self_test, sizeof(tpm2_self_test), tpm_response_buf, &tpm_response_buf_size); + } + else if (0 == strcasecmp(optarg, "full")) + { + ret_val = tpmtool_transmit(tpm2_self_test_full, sizeof(tpm2_self_test_full), tpm_response_buf, &tpm_response_buf_size); + } + else if (0 == strcasecmp(optarg, "incremental")) + { + ret_val = tpmtool_transmit(tpm2_self_test_incremental, sizeof(tpm2_self_test_incremental), tpm_response_buf, &tpm_response_buf_size); + } + else + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Unknown option. Use '-h' for more information.\n"); + } + break; + + case 'T': // TPM_CC_GetTestResult + ret_val = tpmtool_transmit(tpm_cc_get_test_result, sizeof(tpm_cc_get_test_result), tpm_response_buf, &tpm_response_buf_size); + break; + + case 'u': // TPM2_Startup + if (0 == strcasecmp(optarg, "clear")) + { + ret_val = tpmtool_transmit(tpm2_startup_clear, sizeof(tpm2_startup_clear), tpm_response_buf, &tpm_response_buf_size); + } + else if (0 == strcasecmp(optarg, "state")) + { + ret_val = tpmtool_transmit(tpm2_startup_state, sizeof(tpm2_startup_state), tpm_response_buf, &tpm_response_buf_size); + } + else + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Unknown option. Use '-h' for more information.\n"); + } + break; + + case 'z': // PCR_Reset + // Allocate the input buffer for pcr_reset and tpmtool_transmit + input_bytes_size = sizeof(tpm2_pcr_reset); + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0, input_bytes_size); + + // Create PCR_Reset TPM request. + ret_val = pcr_reset(optarg, input_bytes); + RET_VAL_CHECK(ret_val); + + // Send bytes to TPM. + ret_val = tpmtool_transmit(input_bytes, input_bytes_size, tpm_response_buf, &tpm_response_buf_size); + break; + + default: + if ('a' == optopt || 'A' == optopt || 'b' == optopt || 'e' == optopt || 'E' == optopt || 'G' == optopt || + 'r' == optopt || 'R' == optopt || 's' == optopt || 'S' == optopt || 'z' == optopt) + { + // Error output if arguments are missing. + fprintf(stderr, "Option '-%c' requires additional arguments. Use '-h' for more information.\n", optopt); + ret_val = ERR_BAD_CMD; + } + else if ('d' == optopt) + { + // TPM shutdown default option without parameter (default is tpm_cc_shutdown_clear). + ret_val = tpmtool_transmit(tpm_cc_shutdown_clear, sizeof(tpm_cc_shutdown_clear), tpm_response_buf, &tpm_response_buf_size); + option='d'; // for response_print handler + } + else if ('t' == optopt) + { + // TPM shutdown default option without parameter (default is tpm2_self_test). + ret_val = tpmtool_transmit(tpm2_self_test, sizeof(tpm2_self_test), tpm_response_buf, &tpm_response_buf_size); + option='t'; // for response_print handler + } + else if ('u' == optopt) + { + // TPM startup default option without parameter (default is tpm2_startup_clear). + ret_val = tpmtool_transmit(tpm2_startup_clear, sizeof(tpm2_startup_clear), tpm_response_buf, &tpm_response_buf_size); + option='u'; // for response_print handler + } + else if (isprint(optopt)) + { + // Unknown parameter. + fprintf(stderr, "Unknown option '-%c'. Use '-h' for more information.\n", optopt); + ret_val = ERR_BAD_CMD; + } + else + { + // Non-printable character. + fprintf(stderr, "Invalid command line character. Use '-h' for more information.\n"); + ret_val = ERR_BAD_CMD; + } + break; + } // End of switch. + + // ---------- Output and error handling ---------- + // Check for transmission errors or skipped transmission. + if (EXIT_SUCCESS != ret_val || 1 == no_transmission) + { + // Exit command line parameter parsing loop. + break; + } + + // Transmission has been successful, now get TPM return code from TPM response. + ret_val = return_error_handling(tpm_response_buf); + if (EXIT_SUCCESS != ret_val) // Check for errors + { + // Set flag to indicate a TPM error. + tpm_error = 1; + + // Go out of command line parameter parsing loop. + break; + } + + // Print TPM response + ret_val = response_print(tpm_response_buf, tpm_response_buf_size, option); + RET_VAL_CHECK(ret_val); + + // Free memory for next command line option + MEMSET_FREE(input_bytes, input_bytes_size); + } // End of while (cmd line parameter parsing loop). + + // If no error has ocurred so far, handle remaining unknown parameters, if present. + RET_VAL_CHECK(ret_val); // If we do not check and break here in case of an error, we would override the previous error + for (i = optind; i < argc; i++) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Non-option argument '%s'. Use '-h' for more information.\n", argv[i]); + } + } while (0); // End of DO WHILE FALSE loop. + + // Check for non-TPM error. + if (EXIT_SUCCESS != ret_val && 1 != tpm_error) + { + fprintf(stderr, "Unexpected error: 0x%08X\n", ret_val); + } + + // Map TPM return value 0x100 (TPM_RC_INITIALIZE) to 0x101 (TPM_RC_FAILURE), since in case you + // run ELTT 2 in a python script only the lowest byte of the return code is actually being returned. + // But since the lowest byte of 0x100 is 0x00 (== TPM_RC_SUCCESS), python would not be able to + // distinguish between 0x000 and 0x100 as return code, therefore we need the mapping. + if (TPM_RC_INITIALIZE == ret_val) + { + ret_val = TPM_RC_FAILURE; + } + + // ---------- Cleanup ---------- + MEMSET_FREE(tpm_response_buf, tpm_response_buf_size); + MEMSET_FREE(input_bytes, input_bytes_size); + + printf("\n"); + return ret_val; +} + +int tpmtool_transmit(const uint8_t *buf, ssize_t length, uint8_t *response, ssize_t *resp_length) +{ + // ---------- Transmit command given in buf to device with handle given in dev_tpm ---------- + int ret_val = EXIT_SUCCESS; // Return value. + int dev_tpm = -1; // TPM device handle. + ssize_t transmit_size = 0; // Amount of bytes sent to / received from the TPM. + + do + { + // Check input parameters. + NULL_POINTER_CHECK(buf); + NULL_POINTER_CHECK(response); + NULL_POINTER_CHECK(resp_length); + + // ---------- Open TPM device ---------- + dev_tpm = open("/dev/tpm0", O_RDWR); + if (-1 == dev_tpm) + { + ret_val = errno; + perror("Error opening the device"); + break; + } + + // Send request data to TPM. + transmit_size = write(dev_tpm, buf, length); + if (transmit_size == ERR_COMMUNICATION || length != transmit_size) + { + ret_val = errno; + perror("Error sending request to TPM"); + break; + } + + // Read the TPM response header. + transmit_size = read(dev_tpm, response, TPM_RESP_MAX_SIZE); + if (transmit_size == ERR_COMMUNICATION) + { + ret_val = errno; + perror("Error reading response from TPM"); + break; + } + + // Update response buffer length with value of data length returned by TPM. + *resp_length = transmit_size; + } while (0); + + // ---------- Close TPM device ---------- + if (-1 != dev_tpm) + { + // Close file handle. + close(dev_tpm); + + // Invalidate file handle. + dev_tpm = -1; + } + + return ret_val; +} + +int return_error_handling(uint8_t *response_buf) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint32_t tpm_rc = 0; // Return code from TPM header. + + do + { + NULL_POINTER_CHECK(response_buf); + + ret_val = buf_to_uint64(response_buf, 6, sizeof(tpm_rc), (unsigned long long*)&tpm_rc); + RET_VAL_CHECK(ret_val); + + // Assign TPM return code to ret_val. + ret_val = tpm_rc; + + if (TPM_RC_SUCCESS != tpm_rc) + { + fprintf(stderr, "TPM Error 0x%08X: ", tpm_rc); + } + + // Handle some known TPM return codes. + switch (tpm_rc) + { + case TPM_RC_SUCCESS: // 0x00 + break; + + case TPM_RC_BAD_TAG: // 0x1E + fprintf(stderr, "The tag value sent to for a command is invalid.\n"); + break; + + case TPM_RC_SIZE: // 0x95 + fprintf(stderr, "Structure is the wrong size.\n"); + break; + + case TPM_RC_INITIALIZE: // 0x100 + fprintf(stderr, "TPM not initialized.\n"); + break; + + case TPM_RC_LOCALITY: // 0x907 + fprintf(stderr, "Bad locality.\n"); + break; + + default: + fprintf(stderr, "See TPM Library Specification for more information.\n"); + break; + } + } while (0); + + return ret_val; +} + +int response_print(uint8_t *response_buf, size_t resp_size, int option) +{ + int ret_val = EXIT_SUCCESS; // Return value. + + do + { + NULL_POINTER_CHECK(response_buf); + + switch (option) + { + case 'a': + case 'A': // Print the returned hash number. + ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_HASH_WITHOUT_HEADER, PRINT_RESPONSE_HASH); + break; + case 'b': // Print the response value in hex. + case 'e': + case 'E': // Print the PCR extend response. + ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS); + break; + + case 'c': // Print the TPM clock values. + ret_val = print_clock_info(response_buf); + break; + + case 'd': // Print "Shutdown works as expected." + printf("Shutdown works as expected.\n"); + break; + + case 'g': // Print the capability flags. + ret_val = print_capability_flags(response_buf); + break; + + case 'G': // Print the returned random value in hex. + printf("Random value:\n"); + ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITHOUT_HEADER, PRINT_RESPONSE_HEX_BLOCK); + break; + + case 'r': + case 'R': // Print the response value in hex. + ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_PCR_WITHOUT_HEADER, PRINT_RESPONSE_CLEAR); + break; + + case 's': + case 'S': // Print the returned hash number. + ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITHOUT_HEADER, PRINT_RESPONSE_HASH); + break; + + case 't': // Print "Successfully tested. Works as expected." + printf("Successfully tested. Works as expected.\n"); + break; + + case 'T': // Print response value hex without the header. + printf("Test Result: "); + ret_val = print_response_buf(response_buf, resp_size, PRINT_RESPONSE_WITHOUT_HEADER, PRINT_RESPONSE_CLEAR); + break; + + case 'u': // Print "Startup works as expected." + printf("Startup works as expected.\n"); + break; + + default: // Print "Done." + printf("Done.\n"); + break; + } + printf("\n"); + } while (0); + + return ret_val; +} + +int print_response_buf(uint8_t *response_buf, size_t resp_size, uint32_t offset, int format) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint32_t i = 0; // Loop variable. + unsigned long long data_size = 0; // Size of response data. + + do + { + NULL_POINTER_CHECK(response_buf); + + switch (format) + { + case PRINT_RESPONSE_CLEAR: + for (i = 0; i < resp_size - offset; i++) + { + printf("%02X ", response_buf[i + offset]); + } + break; + + case PRINT_RESPONSE_HEADERBLOCKS: + if (TPM_CMD_HEADER_SIZE > resp_size) + { + ret_val = EINVAL; + fprintf(stderr, "Response size is too small.\n"); + break; + } + + printf("TPM Response:\n"); + for (i = 0; i < resp_size - offset; i++) + { + printf("%02X ", response_buf[i + offset]); + if (i == 1) // Bytes 0 and 1 are TPM TAG. + { + printf(" TPM TAG\n"); + } + else if (i == 5) // Bytes 2 to 5 are the response length. + { + printf(" RESPONSE SIZE\n"); + } + else if (i == 9) // Last 4 bytes in header are the TPM return code. + { + printf(" RETURN CODE\n"); + if (i + 1 < resp_size - offset) + { + printf(" Command-specific response Data:\n"); + } + } + else if (i >= 10 && (i+1) % 10 == 0) // After all 10 header bytes have been printed, start new line after every 10 bytes of data. + { + printf("\n"); + } + } + break; + + case PRINT_RESPONSE_HEX_BLOCK: + for (i = 0; i < resp_size - offset; i++) + { + if (i % 16 == 0) + { + printf("\n0x%08X: ", i); + } + printf("0x%02X ", response_buf[i + offset]); + } + break; + + case PRINT_RESPONSE_HASH: + ret_val = buf_to_uint64(response_buf, offset - 2, 2, &data_size); // Data size always should be stored right before the actual data + if (data_size > resp_size - offset) + { + ret_val = EINVAL; + fprintf(stderr, "Invalid response data size.\n"); + break; + } + for (i = 0; i < data_size; i++) + { + if (i % 8 == 0) + { + printf("\n0x%08X: ", i); + } + printf("%02X ", response_buf[i + offset]); + } + break; + + default: + ret_val = EINVAL; + fprintf(stderr, "Unknown output format.\n"); + break; + } + } while (0); + + return ret_val; +} + +void print_help() +{ + printf("'-a ': Hash Sequence SHA1\n"); + printf(" -> Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n"); + printf("'-A ': Hash Sequence SHA256\n"); + printf(" -> Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n"); + printf("'-b ': Enter your own TPM command\n"); + printf(" -> Command bytes: Enter your command bytes in hex like '0f56...' for {0x0f, 0x56, ...}\n"); + printf("'-c': Read Clock\n"); + printf("'-d ': Shutdown\n"); + printf(" -> Shutdown types: clear [default], state\n"); + printf("'-e ': PCR Extend SHA1\n"); + printf(" -> PCR index: Enter the PCR index in hex like '17' for 0x17\n"); + printf(" PCR digest: Enter the value to extend the PCR with in hex like '0f56...' for {0x0f, 0x56, ...}\n"); + printf("'-E ': PCR Extend SHA256\n"); + printf(" -> PCR index: Enter the PCR index in hex like '17' for 0x17\n"); + printf(" PCR digest: Enter the value to extend the PCR with in hex like '0f56...' for {0x0f, 0x56, ...}\n"); + printf("'-g': Get Capability\n"); + printf("'-G ': Get Random\n"); + printf(" -> Enter desired number of random bytes in hex like '32' for 0x32\n"); + printf("'-h': Help\n"); + printf("'-r ': PCR Read SHA1\n"); + printf(" -> PCR index: Enter PCR number in hex like '17' for 0x17\n"); + printf("'-R ': PCR Read SHA256\n"); + printf(" -> PCR index: Enter PCR number in hex like '17' for 0x17\n"); + printf("'-s ': Hash SHA1\n"); + printf(" -> Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n"); + printf("'-S ': Hash SHA256\n"); + printf(" -> Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n"); + printf("'-t ': SelfTest\n"); + printf(" -> Selftest type: not_full [default], full, incremental\n"); + printf("'-T': Get Test Result\n"); + printf("'-u ': Startup\n"); + printf(" -> Startup types: clear [default], state\n"); + printf("'-z ': PCR Reset\n"); + printf(" -> PCR index: Enter PCR number in hex like '17' for 0x17\n"); +} + +int print_capability_flags(uint8_t *response_buf) +{ + int ret_val = EXIT_SUCCESS; // Return value. + unsigned long long propertyValue = 0; // Value of the read property. + unsigned long long i = 0, j = 0; // Position counter. + int tmp = 0; // Temporary buffer. + + do + { + NULL_POINTER_CHECK(response_buf); + + printf("\nTPM capability information:\n"); + printf("=========================================================\n"); + printf("TPM_PT_FAMILY_INDICATOR: %c%c%c%c\n", response_buf[23], response_buf[24], response_buf[25], response_buf[26]); + + ret_val = buf_to_uint64(response_buf, 31, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("TPM_PT_LEVEL: %llu\n", propertyValue); + + ret_val = buf_to_uint64(response_buf, 39, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("TPM_PT_REVISION: %llu\n", propertyValue); + + ret_val = buf_to_uint64(response_buf, 47, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("TPM_PT_DAY_OF_YEAR: %llu\n", propertyValue); + + ret_val = buf_to_uint64(response_buf, 55, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("TPM_PT_YEAR: %llu\n", propertyValue); + + printf("TPM_PT_MANUFACTURER: %c%c%c%c\n", response_buf[63], response_buf[64], response_buf[65], response_buf[66]); + + printf("TPM_PT_VENDOR_STRING: "); + printf("%c%c%c%c", response_buf[71], response_buf[72], response_buf[73], response_buf[74]); + printf("%c%c%c%c", response_buf[79], response_buf[80], response_buf[81], response_buf[82]); + printf("%c%c%c%c", response_buf[87], response_buf[88], response_buf[89], response_buf[90]); + printf("%c%c%c%c\n", response_buf[95], response_buf[96], response_buf[97], response_buf[98]); + + ret_val = buf_to_uint64(response_buf, 103, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("TPM_PT_VENDOR_TPM_TYPE: %llu\n", propertyValue); + + ret_val = buf_to_uint64(response_buf, 111, 2, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("TPM_PT_FIRMWARE_VERSION: %llu", propertyValue); + ret_val = buf_to_uint64(response_buf, 113, 2, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf(".%llu", propertyValue); + ret_val = buf_to_uint64(response_buf, 119, 2, &propertyValue); // Check for output version. + RET_VAL_CHECK(ret_val); + + if (2 <= propertyValue) // Print the new FIRMWARE_VERSION output. + { + ret_val = buf_to_uint64(response_buf, 120, 2, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf(".%llu", propertyValue); + ret_val = buf_to_uint64(response_buf, 122, 1, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf(".%llu\n", propertyValue); + + } + else // Print the old FIRMWARE_VERSION output. + { + ret_val = buf_to_uint64(response_buf, 119, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf(".%llu\n", propertyValue); + } + + printf("\nTPM_PT_MEMORY:\n"); + printf("=========================================================\n"); + + ret_val = buf_to_uint64(response_buf, 207, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + i = 1; // bit 0 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 0 value. + printf("Shared RAM: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i + i; // bit 1 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 1 value. + printf("Shared NV: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i * 2; // bit 2 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 2 value. + printf("Object Copied To Ram: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + //bit 31:3 = reserved + + printf("\nTPM_PT_PERMANENT:\n"); + printf("=========================================================\n"); + ret_val = buf_to_uint64(response_buf, 367, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + i = 1; // bit 0 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 0 value. + printf("Owner Auth Set: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i + i; // bit 1 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 1 value. + printf("Sendorsement Auth Set: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i * 2; // bit 2 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 2 value. + printf("Lockout Auth Set: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i * 2; // bit 3 + i = i * 2; // bit 4 + i = i * 2; // bit 5 + i = i * 2; // bit 6 + i = i * 2; // bit 7 + //bit 7:3 = reserved + + i = i * 2; // bit 8 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 8 value. + printf("Disable Clear: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i * 2; // bit 9 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 9 value. + printf("In Lockout: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i * 2; // bit 10 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 10 value. + printf("TPM Generated EPS: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + //bit 31:11 = reserved + + printf("\nTPM_PT_STARTUP_CLEAR:\n"); + printf("=========================================================\n"); + ret_val = buf_to_uint64(response_buf, 375, 4, &propertyValue); + RET_VAL_CHECK(ret_val); + + i = 1; // bit 0 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 0 value. + printf("Ph Enable: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i + i; // bit 1 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 1 value. + printf("Sh Enable: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + i = i * 2; // bit 2 + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 2 value. + printf("Eh Enable: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + //bit 30:3 = reserved + for(j = 2; j < 31; j++) // go to bit 31. + { + i = i * 2; + } + tmp = ((propertyValue & i) == 0? 0:1); // Check bit 31 value. + printf("Orderly: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + } while (0); + + return ret_val; +} + +int print_clock_info(uint8_t *response_buf) +{ + int ret_val = EXIT_SUCCESS; // Return value. + unsigned long long propertyValue = 0; // Value of the read property. + unsigned long long tmp_value = 0; // Helper variable for calculating actual values. + unsigned long long sec = 0; // Value for seconds. + unsigned long long tmp = 0; // buf_to_uint64 return value. + + do + { + NULL_POINTER_CHECK(response_buf); + + printf("\nClock info:\n"); + printf("=========================================================\n"); + + ret_val = buf_to_uint64(response_buf, 10, 8, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("Time since the last TPM_Init:\n%llu ms = ", propertyValue); + + sec = propertyValue / MILISECOND_TO_SECOND; + tmp_value = sec / YEAR_SECONDS; + printf("%llu y, ", tmp_value); + + tmp_value = (sec % YEAR_SECONDS) / DAY_SECONDS; + printf("%llu d, ", tmp_value); + + tmp_value = ((sec % YEAR_SECONDS) % DAY_SECONDS) / HOUR_SECONDS; + printf("%llu h, ", tmp_value); + + tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) / MINUTE_SECONDS; + printf("%llu min, ", tmp_value); + + tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) % MINUTE_SECONDS; + printf("%llu s, ", tmp_value); + + tmp_value = propertyValue % MILISECOND_TO_SECOND; + printf("%llu ms\n\n", tmp_value); + + ret_val = buf_to_uint64(response_buf, 18, 8, &propertyValue); + RET_VAL_CHECK(ret_val); + + printf("Time during which the TPM has been powered:\n%llu ms = ", propertyValue); + + sec = propertyValue / MILISECOND_TO_SECOND; + tmp_value = sec / YEAR_SECONDS; + printf("%llu y, ", tmp_value); + + tmp_value = (sec % YEAR_SECONDS) / DAY_SECONDS; + printf("%llu d, ", tmp_value); + + tmp_value = ((sec % YEAR_SECONDS) % DAY_SECONDS) / HOUR_SECONDS; + printf("%llu h, ", tmp_value); + + tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) / MINUTE_SECONDS; + printf("%llu min, ", tmp_value); + + tmp_value = (((sec % YEAR_SECONDS) % DAY_SECONDS) % HOUR_SECONDS) % MINUTE_SECONDS; + printf("%llu s, ", tmp_value); + + tmp_value = propertyValue % MILISECOND_TO_SECOND; + printf("%llu ms\n\n", tmp_value); + + ret_val = buf_to_uint64(response_buf, 26, 4, &tmp); + RET_VAL_CHECK(ret_val); + + printf("TPM Reset since the last TPM2_Clear: %llu\n", tmp); + + ret_val = buf_to_uint64(response_buf, 30, 4, &tmp); + RET_VAL_CHECK(ret_val); + + printf("Number of times that TPM2_Shutdown: %llu\n", tmp); + + printf("Safe: %i = %s", response_buf[34], (response_buf[34]? "Yes\n" : "No\n")); + } while (0); + + return ret_val; +} + +int buf_to_uint64(uint8_t *input_buffer, uint32_t offset, uint8_t length, unsigned long long *output_value) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint32_t i = 0; // Loop variable. + unsigned long long tmp = 0; // Temporary variable for value calculation. + + do + { + NULL_POINTER_CHECK(input_buffer); + NULL_POINTER_CHECK(output_value); + + if (8 >= length) + { + for (i = 0; i < length; i++) + { + tmp = (tmp << 8) + input_buffer[offset + i]; + } + *output_value = tmp; + } + else + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Requested conversion amount of %i is to high. The maximum possible amount is 8 bytes.\n", length); + } + } while (0); + + return ret_val; +} + +int hexstr_to_bytearray(char *byte_string, uint8_t *byte_values, size_t byte_values_size) +{ + int ret_val = EXIT_SUCCESS; // Return value. + char hex_byte[3] = {0}; // Temporary buffer for input bytes. + char* invalidChars = NULL; // Pointer to target buffer where method stores invalid characters. + uint32_t i = 0; // Loop variable. + + do + { + NULL_POINTER_CHECK(byte_string); + NULL_POINTER_CHECK(byte_values); + + if (strlen(byte_string) / 2 + strlen(byte_string) % 2 > byte_values_size) + { + ret_val = EINVAL; + fprintf(stderr, "Input character string is too long for output buffer.\n"); + break; + } + + // Loop "bytewise" through string + for (i = 0; i < strlen(byte_string); i += 2) + { + // Split input string into "bytes" + if (1 == strlen(byte_string + i)) + { + // Assemble a single digit in the hex byte string. + hex_byte[0] = byte_string[i]; + hex_byte[1] = '\0'; + } + else + { + // Assemble a digit pair in the hex byte string. + hex_byte[0] = byte_string[i]; + hex_byte[1] = byte_string[i + 1]; + hex_byte[2] = '\0'; + } + + // Convert the hex string to an integer. + errno = 0; + byte_values[i / 2] = strtoul(hex_byte, &invalidChars, 16); + if (0 != errno) + { + ret_val = errno; + perror("Error parsing string"); + break; + } + if ('\0' != *invalidChars) + { + ret_val = EINVAL; + fprintf(stderr, "Invalid character(s) '%s' while trying to parse '%s' to a byte array.\n", invalidChars, byte_string); + break; + } + } + } while (0); + + return ret_val; +} + +int int_to_bytearray(uint64_t input, uint32_t input_size, uint8_t *output_byte) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint32_t i; // For-while-loop counter. + + do + { + NULL_POINTER_CHECK(output_byte); + + for (i = 0; i < input_size; i++) + { + output_byte[i] = input >> ((input_size - 1 - i) * 8); + } + } while (0); + + return ret_val; +} + +int get_random(char *data_length_string, uint8_t *response_buf) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint8_t bytes_requested = 0; // Amount of random bytes requested by the user. + size_t byte_string_size = 0; // Size of user input. + + do + { + NULL_POINTER_CHECK(data_length_string); + NULL_POINTER_CHECK(response_buf); + + // Get length of command line input. + byte_string_size = strlen(data_length_string) / 2 + strlen(data_length_string) % 2; + if (1 != byte_string_size) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n"); + break; + } + + // Convert the command line input string for requested random data length to byte. + ret_val = hexstr_to_bytearray(data_length_string, &bytes_requested, 1); + RET_VAL_CHECK(ret_val); + if (32 < bytes_requested || 0 == bytes_requested) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a hex value between 0x01 and 0x20.\n"); + break; + } + + // Copy command bytes. + memcpy(response_buf, tpm2_getrandom, sizeof(tpm2_getrandom)); + + // Store amount of requested bytes at the correct byte index in the command byte stream. + response_buf[sizeof(tpm2_getrandom) - 1] = bytes_requested; + } while (0); + + return ret_val; + } + +int create_hash(char *data_string, char option, uint8_t *hash_cmd_buf, uint32_t hash_cmd_buf_size) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint32_t offset = 0; // Helper offset for generating command request. + uint16_t data_string_size = 0; // Size of user input data. + unsigned long max_data_size = 0; // Maximum supported size for input data. + const uint8_t *tpm_hash_alg = NULL; // Pointer to hash algorithm identifier. + + do + { + NULL_POINTER_CHECK(data_string); + NULL_POINTER_CHECK(hash_cmd_buf); + if ('s' != option && 'S' != option) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Option argument must be 's' or 'S'.\n"); + break; + } + + // Check input string size. + data_string_size = strlen(data_string) / 2 + strlen(data_string) % 2; + max_data_size = TPM_REQ_MAX_SIZE - sizeof(tpm2_hash); + if (data_string_size > max_data_size) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Maximum input data size is %lu byte (%lu characters).\n", max_data_size, max_data_size * 2); + break; + } + + // Copy basic command bytes. + memcpy(hash_cmd_buf, tpm2_hash, sizeof(tpm2_hash)); + + // Set hash algorithm, command and data sizes depending on user input option at the correct byte index in the command byte stream. + if ('s' == option) + { + tpm_hash_alg = sha1_alg; + printf("\nTPM2_Hash of '%s' with SHA-1:\n", data_string); + } + else + { + tpm_hash_alg = sha256_alg; + printf("\nTPM2_Hash of '%s' with SHA-256:\n", data_string); + } + + offset = 2; + ret_val = int_to_bytearray(sizeof(tpm2_hash) + data_string_size, sizeof(uint32_t), hash_cmd_buf + offset); + RET_VAL_CHECK(ret_val); + offset = 10; + ret_val = int_to_bytearray(data_string_size, sizeof(data_string_size), hash_cmd_buf + offset); + RET_VAL_CHECK(ret_val); + offset += sizeof(data_string_size); + + // Copy hash data to TPM request. + ret_val = hexstr_to_bytearray(data_string, hash_cmd_buf + offset, hash_cmd_buf_size - offset); + RET_VAL_CHECK(ret_val); + offset += data_string_size; + + // Set hash algorithm and hierarchy. + memcpy(hash_cmd_buf + offset, tpm_hash_alg, 2); + offset += 2; + memcpy(hash_cmd_buf + offset, tpm_cc_hash_hierarchy, sizeof(tpm_cc_hash_hierarchy)); + } while (0); + + return ret_val; +} + +int create_hash_sequence(char *data_string, char option, uint8_t *tpm_response_buf, ssize_t *tpm_response_buf_size) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint16_t data_string_bytes_size = 0; // Size of user input data string in bytes. + uint8_t *data_string_bytes = NULL; // Buffer for user input data string as bytes. + uint32_t update_request_size = 0; // Size of user input string. + uint16_t transfer_bytes = 0; // Amount of bytes to be transmitted to the TPM. + uint16_t remaining_bytes = 0; // Amount of bytes not yet transmitted to the TPM. + uint32_t offset = 0; // Helper offset for generating command request. + unsigned long long tpm_rc = TPM_RC_SUCCESS; // TPM return code. + uint8_t *update_request = NULL; // Buffer for update sequence command. + uint8_t sequence_handle[4]; // Buffer for tpmi response. + ssize_t original_response_buf_size = 0; // Backup of the original response buffer size + + do + { + NULL_POINTER_CHECK(tpm_response_buf); + NULL_POINTER_CHECK(data_string); + NULL_POINTER_CHECK(tpm_response_buf_size); + if ('a' != option && 'A' != option) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Option argument must be 'a' or 'A'.\n"); + break; + } + original_response_buf_size = *tpm_response_buf_size; + + // Set hash algorithm depending on user input option at the correct byte index in the command byte stream. + if ('a' == option) + { + printf("\nTPM2_HashSequenceStart of '%s' with SHA-1:\n", data_string); + memcpy(tpm2_hash_sequence_start + 12, sha1_alg, sizeof(sha1_alg)); + } + else + { + printf("\nTPM2_HashSequenceStart of '%s' with SHA-256:\n", data_string); + memcpy(tpm2_hash_sequence_start + 12, sha256_alg, sizeof(sha256_alg)); + } + + // Send the TPM2_HashSequenceStart command to the TPM. + ret_val = tpmtool_transmit(tpm2_hash_sequence_start, sizeof(tpm2_hash_sequence_start), tpm_response_buf, tpm_response_buf_size); + RET_VAL_CHECK(ret_val); + + // Print the TPM response. + NULL_POINTER_CHECK(tpm_response_buf_size); + ret_val = print_response_buf(tpm_response_buf, (size_t)*tpm_response_buf_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS); + RET_VAL_CHECK(ret_val); + + // Abort in case of TPM error. + ret_val = buf_to_uint64(tpm_response_buf, 6, 4, &tpm_rc); + RET_VAL_CHECK(ret_val); + if (TPM_RC_SUCCESS != tpm_rc) + { + break; + } + + // Get sequence handle from TPM response. + memcpy(sequence_handle, tpm_response_buf + 10, sizeof(sequence_handle)); + + // Calculate byte sizes of hash input string. + data_string_bytes_size = strlen(data_string) / 2 + strlen(data_string) % 2; + + // Allocate memory for conversion of hash input string. + data_string_bytes = malloc(data_string_bytes_size); + MALLOC_ERROR_CHECK(data_string_bytes); + memset(data_string_bytes, 0, data_string_bytes_size); + + // Convert hash input string to bytes. + ret_val = hexstr_to_bytearray(data_string, data_string_bytes, data_string_bytes_size); + RET_VAL_CHECK(ret_val); + + // If necessary split input bytes into multiple TPM2_SequenceUpdate commands + remaining_bytes = data_string_bytes_size; + while (remaining_bytes > 0) + { + // Calculate amount of bytes to be transmitted next + if (remaining_bytes <= TPM_REQ_MAX_SIZE - sizeof(tpm2_sequence_update)) + { + transfer_bytes = remaining_bytes; + } + else + { + transfer_bytes = TPM_REQ_MAX_SIZE - sizeof(tpm2_sequence_update); + } + update_request_size = transfer_bytes + sizeof(tpm2_sequence_update); + + // Compose the TPM2_SequenceUpdate command. + update_request = malloc(update_request_size); + MALLOC_ERROR_CHECK(update_request); + memset(update_request, 0, update_request_size); + memcpy(update_request, tpm2_sequence_update, sizeof(tpm2_sequence_update)); + offset = 2; + ret_val = int_to_bytearray(update_request_size, sizeof(update_request_size), update_request + offset); + RET_VAL_CHECK(ret_val); + offset = 10; + memcpy(update_request + offset, sequence_handle, sizeof(sequence_handle)); + offset = sizeof(tpm2_sequence_update) - sizeof(transfer_bytes); + ret_val = int_to_bytearray(transfer_bytes, sizeof(transfer_bytes), update_request + offset); + RET_VAL_CHECK(ret_val); + memcpy(update_request + sizeof(tpm2_sequence_update), data_string_bytes + data_string_bytes_size - remaining_bytes, transfer_bytes); + + // Send the TPM2_SequenceUpdate command to the TPM. + printf("\n\nTPM2_SequenceUpdate:\n"); + *tpm_response_buf_size = original_response_buf_size; + ret_val = tpmtool_transmit(update_request, update_request_size, tpm_response_buf, tpm_response_buf_size); + RET_VAL_CHECK(ret_val); + + // Free allocated memory + MEMSET_FREE(update_request, update_request_size); + + // Print the TPM response. + NULL_POINTER_CHECK(tpm_response_buf_size); + ret_val = print_response_buf(tpm_response_buf, (size_t)*tpm_response_buf_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS); + RET_VAL_CHECK(ret_val); + + // Abort in case of TPM error. + ret_val = buf_to_uint64(tpm_response_buf, 6, 4, &tpm_rc); + RET_VAL_CHECK(ret_val); + if (TPM_RC_SUCCESS != tpm_rc) + { + break; + } + + remaining_bytes = remaining_bytes - transfer_bytes; + } + RET_VAL_CHECK(ret_val); + if (TPM_RC_SUCCESS != tpm_rc) + { + break; + } + + // Set the sequence handle in the TPM2_SequenceComplete command. + memcpy(tpm2_sequence_complete + 10, sequence_handle, sizeof(sequence_handle)); + + // Send the TPM2_SequenceComplete command to the TPM. + printf("\n\nTPM2_SequenceComplete:\n"); + *tpm_response_buf_size = original_response_buf_size; + ret_val = tpmtool_transmit(tpm2_sequence_complete, sizeof(tpm2_sequence_complete), tpm_response_buf, tpm_response_buf_size); + RET_VAL_CHECK(ret_val); + + // Print the TPM response. + NULL_POINTER_CHECK(tpm_response_buf_size); + ret_val = print_response_buf(tpm_response_buf, (size_t)*tpm_response_buf_size, PRINT_RESPONSE_WITH_HEADER, PRINT_RESPONSE_HEADERBLOCKS); + printf("\n\nHash value extracted from TPM response:\n"); + } while (0); + + MEMSET_FREE(data_string_bytes, data_string_bytes_size); + MEMSET_FREE(update_request, update_request_size); + + return ret_val; +} + +int pcr_extend(char *pcr_index_str, char *pcr_digest_str, uint8_t *pcr_cmd_buf, size_t pcr_cmd_buf_size, char option) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint8_t pcr_index = 0; // PCR index user input byte. + uint32_t pcr_digest_size = 0; // Sizeof PCR digest user input. + + do + { + NULL_POINTER_CHECK(pcr_index_str); + NULL_POINTER_CHECK(pcr_digest_str); + NULL_POINTER_CHECK(pcr_cmd_buf); + if ('e' != option && 'E' != option) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Option argument must be 'e' or 'E'.\n"); + break; + } + + // Check and convert the command line input (PCR index) to bytes. + if (1 != strlen(pcr_index_str) / 2 + strlen(pcr_index_str) % 2) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n"); + break; + } + ret_val = hexstr_to_bytearray(pcr_index_str, &pcr_index, 1); + RET_VAL_CHECK(ret_val); + if (23 < pcr_index) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a hex value between 0x00 and 0x17 in hex without leading '0x'.\n"); + break; + } + + // Check the command line input (PCR digest). + pcr_digest_size = strlen(pcr_digest_str) / 2 + strlen(pcr_digest_str) % 2; + if ('e' == option && TPM_SHA1_DIGEST_SIZE < pcr_digest_size) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Maximum SHA-1 PCR digest size is 20 byte (40 characters), but you entered %u byte.\n", pcr_digest_size); + break; + } + if ('E' == option && TPM_SHA256_DIGEST_SIZE < pcr_digest_size) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Maximum SHA-256 PCR digest size is 32 byte (64 characters), but you entered %u byte.\n", pcr_digest_size); + break; + } + + // Copy basic command bytes. + memcpy(pcr_cmd_buf, tpm2_pcr_extend, sizeof(tpm2_pcr_extend)); + + // Store PCR index at the correct byte index in the command byte stream. + pcr_cmd_buf[13] = pcr_index; + + // Convert the PCR digest to bytes and store it at the correct byte index in the command byte stream. + ret_val = hexstr_to_bytearray(pcr_digest_str, pcr_cmd_buf + sizeof(tpm2_pcr_extend), pcr_cmd_buf_size - sizeof(tpm2_pcr_extend)); + RET_VAL_CHECK(ret_val); + + // Set hash algorithm and command length depending on user input option at the correct byte index in the command byte stream. + if ('e' == option) + { + pcr_cmd_buf[5] = sizeof(tpm2_pcr_extend) + TPM_SHA1_DIGEST_SIZE; + memcpy(pcr_cmd_buf + 31, sha1_alg, sizeof(sha1_alg)); + printf("Extend PCR %i (SHA-1) with digest { ", pcr_index); + } + else if ('E' == option) + { + pcr_cmd_buf[5] = sizeof(tpm2_pcr_extend) + TPM_SHA256_DIGEST_SIZE; + memcpy(pcr_cmd_buf + 31, sha256_alg, sizeof(sha256_alg)); + printf("Extend PCR %i (SHA-256) with digest { ", pcr_index); + } + print_response_buf(pcr_cmd_buf, pcr_cmd_buf_size, sizeof(tpm2_pcr_extend), PRINT_RESPONSE_CLEAR); + printf("}:\n"); + } while (0); + + return ret_val; +} + +int pcr_read(char *pcr_index_str, uint8_t *pcr_cmd_buf, char option) +{ + int ret_val = EXIT_SUCCESS; // Return value. + int pcr_byte_index = 0; // The location for pcr_select on pcr_cmd_buf. + uint8_t pcr_select = 0; // PCR index as mapped bit value. + uint8_t pcr_index = 0; // PCR user input byte. + + do + { + NULL_POINTER_CHECK(pcr_index_str); + NULL_POINTER_CHECK(pcr_cmd_buf); + if ('r' != option && 'R' != option) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Option argument must be 'r' or 'R'.\n"); + break; + } + + // Convert the command line input to bytes. + if (1 != strlen(pcr_index_str) / 2 + strlen(pcr_index_str) % 2) + { + // Current implementation only supports selection of one PCR at a time. + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n"); + break; + } + ret_val = hexstr_to_bytearray(pcr_index_str, &pcr_index, 1); + RET_VAL_CHECK(ret_val); + if (23 < pcr_index) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a hex value between 0x00 and 0x17 in hex without leading '0x'.\n"); + break; + } + + // Copy basic command bytes. + memcpy(pcr_cmd_buf, tpm2_pcr_read, sizeof(tpm2_pcr_read)); + + // Calculate the location of PCR index in command byte stream depends on the PCR index value: 0 for PCRs 0-7, 1 for PCRs 8-15 and 2 for PCRs 16-23. + pcr_byte_index = pcr_index / 8; + + // Set corresponding bit in PCR selection byte to 1: bit 0 for PCRs 0, 8 or 16, bit 1 for PCRs 1, 9 or 17, ... (etc.), and bit 7 for PCRs 7, 15 or 23. + // Note: This would allow to read multiple PCRs at once. For simplicity reasons, ELTT only supports reading one PCR at a time. + pcr_select = (1 << (pcr_index % 8)); + + // Store pcr_select at the correct byte index in the command byte stream. + pcr_cmd_buf[17 + pcr_byte_index] = pcr_select; + + // Set hash algorithm depending on user input option at the correct byte index in the command byte stream. + if ('r' == option) + { + memcpy(pcr_cmd_buf + 14, sha1_alg, sizeof(sha1_alg)); + printf("Read PCR %i (SHA-1):\n", pcr_index); + } + else if ('R' == option) + { + memcpy(pcr_cmd_buf + 14, sha256_alg, sizeof(sha256_alg)); + printf("Read PCR %i (SHA-256):\n", pcr_index); + } + } while (0); + + return ret_val; +} + +int pcr_reset(char *pcr_index_str, uint8_t *pcr_cmd_buf) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint8_t pcr_index = 0; // PCR user input byte. + + do + { + NULL_POINTER_CHECK(pcr_index_str); + NULL_POINTER_CHECK(pcr_cmd_buf); + + // Convert the command line input to bytes. + if (1 != strlen(pcr_index_str) / 2 + strlen(pcr_index_str) % 2) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a single hex value (2 characters) without leading '0x'.\n"); + break; + } + ret_val = hexstr_to_bytearray(pcr_index_str, &pcr_index, 1); + RET_VAL_CHECK(ret_val); + if (23 < pcr_index) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Enter a hex value between 0x00 and 0x17 in hex without leading '0x'.\n"); + break; + } + + // Copy command bytes. + memcpy(pcr_cmd_buf, tpm2_pcr_reset, sizeof(tpm2_pcr_reset)); + + // Store pcr_index at the correct byte index in the command byte stream. + pcr_cmd_buf[13] = pcr_index; + + printf("Reset PCR %i:\n", pcr_index); + } while (0); + + return ret_val; +} diff --git a/eltt2.h b/eltt2.h new file mode 100644 index 0000000..7b12f7b --- /dev/null +++ b/eltt2.h @@ -0,0 +1,527 @@ +#ifndef _ELTT2_H_ +#define _ELTT2_H_ +/** + * @brief Infineon Embedded Linux TPM Toolbox 2 (ELTT2) for TPM 2.0 + * @details eltt2.h implements all TPM byte commands and the prototype declarations for eltt2.c. + * @file eltt2.h + * @date 2014/06/26 + * @copyright Copyright (c) 2014, Infineon Technologies AG\n + * All rights reserved.\n + * \n + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following + * conditions are met:\n + * \n + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer.\n + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution.\n + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission.\n + * \n + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// this is the main page for doxygen documentation. +/** @mainpage Infineon Embedded Linux TPM Toolbox 2 (ELTT2) for TPM 2.0 Documentation + * + * @section Welcome + * Welcome to Infineon TPM 2.0 Software-Tool "Embedded Linux TPM Toolbox 2 (ELTT2)".\n + * \n + * @section Introduction + * ELTT2 is a single file-executable program + * intended for test, diagnosis and basic state changes of the Infineon + * Technologies TPM 2.0.\n + * \n + * @section Copyright + * Copyright (c) 2014, Infineon Technologies AG\n + * All rights reserved.\n + * \n + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following + * conditions are met:\n + * \n + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer.\n + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided with the distribution.\n + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission.\n + * \n + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +//-------------"Defines"------------- +#define TPM_RESP_MAX_SIZE 4096 ///< This is the maximum possible TPM response size in bytes. +#define TPM_REQ_MAX_SIZE 1024 ///< This is the maximum possible TPM request size in bytes. TBD: Find out correct value. +#define ERR_COMMUNICATION -1 ///< Return error check for read and write to the TPM. +#define ERR_BAD_CMD -2 ///< Error code for a bad command line argument or option. +#define TPM_SHA1_DIGEST_SIZE 20 ///< For all SHA-1 operations the digest's size is always 20 bytes. +#define TPM_SHA256_DIGEST_SIZE 32 ///< For all SHA-256 operations the digest's size is always 32 bytes. +#define TPM_CMD_HEADER_SIZE 10 ///< The size of a standard TPM command header is 10 bytes. +// TPM Return codes +#define TPM_RC_SUCCESS 0x00000000 ///< The response error code for TPM_SUCCESS. +#define TPM_RC_BAD_TAG 0x0000001E ///< The response error code for TPM_RC_BAD_TAG. +#define TPM_RC_SIZE 0x00000095 ///< The response error code for TPM_RC_SIZE. +#define TPM_RC_INITIALIZE 0x00000100 ///< The response error code for TPM_RC_INITIALIZE. +#define TPM_RC_FAILURE 0x00000101 ///< The response error code for TPM_RC_FAILURE. +#define TPM_RC_LOCALITY 0x00000907 ///< The response error code for TPM_RC_LOCALITY. +#define FU_FIRMWARE_VALID_FLAG 4 ///< If this flag is set, the firmware is valid. +#define FU_OWNER_FLAG 1 ///< If this flag is set, the owner is set. +// print_response_buf options +#define PRINT_RESPONSE_CLEAR 1 ///< Prints response unformatted. +#define PRINT_RESPONSE_HEADERBLOCKS 2 ///< Prints response in commented blocks. +#define PRINT_RESPONSE_HEX_BLOCK 3 ///< Prints response in rows of 16 bytes and shows the line number. +#define PRINT_RESPONSE_HASH 4 ///< Prints response of Hash +#define PRINT_RESPONSE_WITHOUT_HEADER 12 ///< Prints the response buffer from byte 12. +#define PRINT_RESPONSE_HASH_WITHOUT_HEADER 16 ///< Prints the response buffer from byte 16. +#define PRINT_RESPONSE_WITH_HEADER 0 ///< Prints the response buffer from byte 0. +#define PRINT_RESPONSE_PCR_WITHOUT_HEADER 30 ///< Prints the pcr buffer from pcr_read. +// time conversion +#define YEAR_SECONDS 31536000 ///< Number of seconds in one year +#define DAY_SECONDS 86400 ///< Number of seconds in one day +#define HOUR_SECONDS 3600 ///< Number of seconds in one hour +#define MINUTE_SECONDS 60 ///< Number of seconds in one minute +#define MILISECOND_TO_SECOND 1000 ///< Convertion from miliseconds to seconds +// hash +#define STD_CC_HASH_SIZE 18 ///< Hash command size + +//-------------"Macros"------------- +// Null pointer check +#define NULL_POINTER_CHECK(x) if (NULL == x) { ret_val = EINVAL; fprintf(stderr, "Error: Invalid argument.\n"); break; } ///< Argument NULL check. +#define MALLOC_ERROR_CHECK(x) if (NULL == x) { ret_val = errno; fprintf(stderr, "Error (re)allocating memory.\n"); break; } ///< Malloc error check. +#define MEMSET_FREE(x, y) if (NULL != x) { memset(x, 0, y); free(x); x = NULL; } ///< Sets memory to 0, frees memory and sets pointer to NULL. +// Return value check +#define RET_VAL_CHECK(x) if (EXIT_SUCCESS != x) { break; } ///< Return value check + +//-------------"Methods"------------- +/** + * @brief Convert (max.) 8 byte buffer to an unsigned long long integer. + * @param [in] *input_buffer Input buffer. Make sure that its size is at least as high as offset + length. + * @param [in] offset Start byte for conversion. + * @param [in] length Amount of bytes to be converted. + * @param [out] *output_value Return the converted unsigned long long integer. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer or length is greater than 8. + * @retval EXIT_SUCCESS In case of success. + * @date 2014/06/26 + */ +int buf_to_uint64(uint8_t *input_buffer, uint32_t offset, uint8_t length, unsigned long long *output_value); + +/** + * @brief Convert a hexadecimal string representation of bytes like "0A1F" and returns an array containing the actual byte values as an array (e.g. { 0x0A, 0x1F }). + * @param [in] *byte_string Incoming bytes as string. + * @param [out] *byte_values Byte array representation of given input string. Must be allocated by caller with the length given in byte_values_size. + * @param [in] byte_values_size Size of byte_values array. + * @return One of the listed return codes. + * @retval EXIT_SUCCESS In case of success. + * @retval EINVAL In case of a NULL pointer. + * @retval value of errno In case parsing error. + * @date 2014/06/26 + */ +int hexstr_to_bytearray(char *byte_string, uint8_t *byte_values, size_t byte_values_size); + +/** + * @brief Convert a number to a byte buffer. + * @param [in] input User input. + * @param [in] input_size Size of input data type in bytes. + * @param [out] *output_byte Return buffer for the converted integer. Must be allocated by the caller with at least a size of 'input_size'. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @date 2014/06/26 + */ +int int_to_bytearray(uint64_t input, uint32_t input_size, uint8_t *output_byte); + +/** + * @brief Create the PCR_Extend command. + * @param [in] *pcr_index_str User input string for PCR index. + * @param [in] *pcr_digest_str User input string of value to extend the selected PCR with. + * @param [out] *pcr_cmd_buf Return buffer for the complete command. Must be allocated by caller. + * @param [in] *pcr_cmd_buf_size Size of memory allocated at pcr_cmd_buf in bytes. + * @param [in] *option Set to 'e' for extending with SHA-1 and to 'E' for SHA-256. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer or an invalid option. + * @retval EXIT_SUCCESS In case of success. + * @retval ERR_BAD_CMD In case of bad user input. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @date 2014/06/26 + */ +int pcr_extend(char *pcr_index_str, char *pcr_digest_str, uint8_t *pcr_cmd_buf, size_t pcr_cmd_buf_size, char option); + +/** + * @brief Create the PCR_Read command. + * @param [in] *pcr_index_str User input string for PCR index. + * @param [out] *pcr_cmd_buf Return buffer for the complete command. + * @param [in] *option Set to 'r' for reading with SHA-1 and to 'R' for SHA-256. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer or an invalid option. + * @retval EXIT_SUCCESS In case of success. + * @retval ERR_BAD_CMD In case of bad user input. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @date 2014/06/26 + */ +int pcr_read(char *pcr_index_str, uint8_t *pcr_cmd_buf, char option); + +/** + * @brief Create the PCR_Reset command. + * @param [in] *pcr_index_str User input string for PCR index. + * @param [out] *pcr_cmd_buf Return buffer for the complete command. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval ERR_BAD_CMD In case of bad user input. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @date 2014/06/26 + */ +int pcr_reset(char *pcr_index_str, uint8_t *pcr_cmd_buf); + +/** + * @brief Print the command line usage and switches. + * @date 2014/06/26 + */ +void print_help(); + +/** + * @brief Print the response buffer in different formats. + * @param [in] *response_buf TPM response. + * @param [in] resp_size TPM response size. + * @param [in] offset Starting point for printing buffer. + * @param [in] format Select the output format. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer or an unknown output format has been transfered. + * @retval EXIT_SUCCESS In case of success. + * @retval buf_to_uint64 All error codes from buf_to_uint64. + * @date 2014/06/26 + */ +int print_response_buf(uint8_t *response_buf, size_t resp_size, uint32_t offset, int format); + +/** + * @brief Print a TPM response. + * @param [in] *response_buf TPM response. + * @param [in] resp_size TPM response size. + * @param [in] option Defines appearance of output. Can have the following values:\n + - PRINT_RESPONSE_CLEAR + - PRINT_RESPONSE_HEADERBLOCKS + - PRINT_RESPONSE_HEX_BLOCK + - PRINT_RESPONSE_WITHOUT_HEADER + - PRINT_RESPONSE_WITH_HEADER + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval print_response_buf All error codes from print_response_buf. + * @retval print_clock_info All error codes from print_clock_info. + * @retval print_capability_flags All error codes from print_capability_flags. + * @date 2014/06/26 + */ +int response_print(uint8_t *response_buf, size_t resp_size, int option); + +/** + * @brief Check a TPM response for errors. + * @param [in] *response_buf TPM response. Must have at least a size of TPM_CMD_HEADER_SIZE bytes. + * @return Returns the TPM return code extracted from the given TPM response or one of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval buf_to_uint64 All error codes from buf_to_uint64. + * @retval EXIT_SUCCESS In case of success. + * @date 2014/06/26 + */ +int return_error_handling(uint8_t *response_buf); + +/** + * @brief Transmit TPM command to /dev/tpm0 and get the response. + * @param [in] *buf TPM request. + * @param [in] length TPM request length. + * @param [out] *response TPM response. + * @param [out] *resp_length TPM response length. + * @return One of the listed return codes or the error code stored in the global errno system variable. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @date 2014/06/26 + */ +int tpmtool_transmit(const uint8_t *buf, ssize_t length, uint8_t *response, ssize_t *resp_length); + +/** + * @brief Print the capability flags. + * @param [in] *response_buf TPM response. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval buf_to_uint64 All error codes from buf_to_uint64. + * @date 2014/06/26 + */ +int print_capability_flags(uint8_t *response_buf); + +/** + * @brief Print the clock info. + * @param [in] *response_buf TPM response. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval buf_to_uint64 All error codes from buf_to_uint64. + * @date 2014/06/26 + */ +int print_clock_info(uint8_t *response_buf); + +/** + * @brief Create the get_random command. + * @param [in] *data_length_string User input string for random data length. + * @param [out] *response_buf Return buffer for the complete command. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval ERR_BAD_CMD In case of bad user input. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @date 2014/06/26 + */ +int get_random(char *data_length_string, uint8_t *response_buf); + +/** + * @brief Create the simple hash command. + * @param [in] *data_string User input string of data to be hashed. + * @param [in] option Set to 's' for hashing with SHA-1 and to 'S' for SHA-256. + * @param [out] *hash_cmd_buf Return buffer for the complete command. + * @param [in] hash_cmd_buf_size Return buffer size. + * @return One of the listed return codes. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @retval int_to_bytearray All error codes from int_to_bytearray. + * @date 2014/06/26 + */ +int create_hash(char *data_string, char option, uint8_t *hash_cmd_buf, uint32_t hash_cmd_buf_size); + +/** + * @brief Create and transmit a sequence of TPM commands for hashing larger amounts of data. + * @param [in] *data_string User input string of data to be hashed. + * @param [in] option Set to 'a' for hashing with SHA-1 and to 'A' for SHA-256. + * @param [out] *tpm_response_buf TPM response. + * @param [out] *tpm_response_buf_size Size of tpm_response_buf. + * @return One of the listed return codes or the error code stored in the global errno system variable. + * @retval EINVAL In case of a NULL pointer. + * @retval EXIT_SUCCESS In case of success. + * @retval value of errno In case of memory allocation error. + * @retval buf_to_uint64 All error codes from buf_to_uint64. + * @retval hexstr_to_bytearray All error codes from hexstr_to_bytearray. + * @retval int_to_bytearray All error codes from int_to_bytearray. + * @retval tpmtool_transmit All error codes from tpmtool_transmit. + * @retval print_response_buf All error codes from print_response_buf + * @date 2014/06/26 + */ +int create_hash_sequence(char *data_string, char option, uint8_t *tpm_response_buf, ssize_t *tpm_response_buf_size); + +//-------------"command bytes"------------- +static const uint8_t tpm2_startup_clear[] ={ + // TPM2_Startup(SU_CLEAR) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup + 0x00, 0x00 // TPM_ST_CLEAR +}; + +static const uint8_t tpm2_startup_state[] ={ + // TPM2_Startup(SU_STATE) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup + 0x00, 0x01 // TPM_ST_STATE +}; + +static const uint8_t tpm_cc_shutdown_clear[] ={ + // TPM_CC_Shutdown(CLEAR) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x45, // TPM_CC_Shutdown + 0x00, 0x00 // TPM_SU_CLEAR +}; + +static const uint8_t tpm_cc_shutdown_state[] ={ + // TPM_CC_Shutdown(STATE) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x45, // TPM_CC_Shutdown + 0x00, 0x01 // TPM_SU_STATE +}; + +static const uint8_t tpm2_self_test[] ={ + // TPM2_SelfTest(fullTest=No) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0B, // commandSize + 0x00, 0x00, 0x01, 0x43, // TPM_CC_SelfTest + 0x00 // fullTest=No +}; + +static const uint8_t tpm2_self_test_full[] ={ + // TPM2_SelfTest(fullTest=YES) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0B, // commandSize + 0x00, 0x00, 0x01, 0x43, // TPM_CC_SelfTest + 0x01 // fullTest=Yes +}; + +static const uint8_t tpm_cc_get_test_result[] ={ + // TPM_CC_GetTestResult + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0A, // commandSize + 0x00, 0x00, 0x01, 0x7C // TPM_CC_GetTestResult +}; + +static const uint8_t tpm2_self_test_incremental[] ={ + // TPM_CC_IncrementalSelfTest + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x2A, // commandSize + 0x00, 0x00, 0x01, 0x42, // TPM_CC_IncrementalSelfTest + 0x00, 0x00, 0x00, 0x0E, // Count of Algorithm + 0x00, 0x01, 0x00, 0x04, // Algorithm two per line + 0x00, 0x05, 0x00, 0x06, + 0x00, 0x08, 0x00, 0x0A, + 0x00, 0x0B, 0x00, 0x14, + 0x00, 0x15, 0x00, 0x16, + 0x00, 0x17, 0x00, 0x22, + 0x00, 0x25, 0x00, 0x43 +}; + +static const uint8_t tpm2_getrandom[] ={ + // TPM_CC_GetRandom + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x7B, // TPM_CC_GetRandom + 0x00, 0x00 // bytesRequested (will be set later) +}; + +static const uint8_t tpm_cc_readclock[] ={ + // TPM_CC_ReadClock + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0A, // commandSize + 0x00, 0x00, 0x01, 0x81 // TPM_CC_ReadClock +}; + +static const uint8_t tpm2_getcapability[] ={ + // TPM2_GetCapability (TPM_CAP_TPM_PROPERTIES, -- ) + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x16, // commandSize + 0x00, 0x00, 0x01, 0x7A, // TPM_CC_GetCapability + 0x00, 0x00, 0x00, 0x06, // TPM_CAP_TPM_PROPERTIES (Property Type: TPM_PT) + 0x00, 0x00, 0x01, 0x00, // Property: TPM_PT_FAMILY_INDICATOR: PT_GROUP * 1 + 0 + 0x00, 0x00, 0x00, 0x2D // PropertyCount 2D (from 100 - 201) +}; + +// Hash +static const uint8_t tpm2_hash[] ={ + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0e, // commandSize + 0x00, 0x00, 0x01, 0x7D, // TPM_CC_Hash + 0x00, 0x00, // size (will be set later) + // buffer (will be added later) + 0x00, 0x00, // hashAlg (will be added later) + 0x00, 0x00, 0x00, 0x00 // hierarchy of the ticket (TPM_RH_NULL; will be added later) +}; + +// HashSequence +static uint8_t tpm2_hash_sequence_start[] ={ + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0e, // commandSize + 0x00, 0x00, 0x01, 0x86, // TPM_CC_HashSequenceStart + 0x00, 0x00, // authSize (NULL Password) + // null (indicate a NULL Password) + 0x00, 0x00 // hashAlg (will be set later) +}; + +static uint8_t tpm2_sequence_update[] ={ + 0x80, 0x02, // TPM_ST_SESSIONS + 0x00, 0x00, 0x00, 0x00, // commandSize (will be set later) + 0x00, 0x00, 0x01, 0x5c, // TPM_CC_SequenceUpdate + 0x00, 0x00, 0x00, 0x00, // sequenceHandle (will be set later) + 0x00, 0x00, // authSize (NULL Password) + // null (indicate a NULL Password) + 0x00, 0x09, // authSize (password authorization session) + 0x40, 0x00, 0x00, 0x09, // TPM_RS_PW (indicate a password authorization session) + 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00 // size (will be set later) + // buffer (will be added later) +}; + +static uint8_t tpm2_sequence_complete[] ={ + 0x80, 0x02, // TPM_ST_SESSIONS + 0x00, 0x00, 0x00, 0x21, // commandSize + 0x00, 0x00, 0x01, 0x3e, // TPM_CC_SequenceComplete + 0x00, 0x00, 0x00, 0x00, // sequenceHandle (will be set later) + 0x00, 0x00, // authSize (NULL Password) + // null (indicate a NULL Password) + 0x00, 0x09, // authSize (password authorization session) + 0x40, 0x00, 0x00, 0x09, // TPM_RS_PW (indicate a password authorization session) + 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, // size (NULL buffer) + // null (indicate an empty buffer buffer) + 0x40, 0x00, 0x00, 0x07 // hierarchy of the ticket (TPM_RH_NULL) +}; + +static const uint8_t sha1_alg[] ={ + 0x00, 0x04 // command for sha1 alg +}; + +static const uint8_t sha256_alg[] ={ + 0x00, 0x0B // command for sha256 alg +}; + +static const uint8_t tpm_cc_hash_hierarchy[] ={ + 0x40, 0x00, 0x00, 0x07 // hierarchy of the ticket (TPM_RH_NULL) +}; + +//PCR_Command +static const uint8_t tpm2_pcr_read[] ={ + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x14, // commandSize + 0x00, 0x00, 0x01, 0x7E, // TPM_CC_PCR_Read + 0x00, 0x00, 0x00, 0x01, // count (TPML_PCR_SELECTION) + 0x00, 0x00, // hash (TPMS_PCR_SELECTION; will be set later) + 0x03, // sizeofSelect (TPMS_PCR_SELECTION) + 0x00, 0x00, 0x00 // pcrSelect (TPMS_PCR_SELECTION) +}; + +static const uint8_t tpm2_pcr_extend[] ={ + 0x80, 0x02, // TPM_ST_SESSIONS + 0x00, 0x00, 0x00, 0x00, // commandSize (will be set later) + 0x00, 0x00, 0x01, 0x82, // TPM_CC_PCR_Extend + 0x00, 0x00, 0x00, 0x00, // {PCR_FIRST:PCR_LAST} (TPMI_DH_PCR) + 0x00, 0x00, // authSize (NULL Password) + // null (indicate a NULL Password) + 0x00, 0x09, // authSize (password authorization session) + 0x40, 0x00, 0x00, 0x09, // TPM_RS_PW (indicate a password authorization session) + 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, // count (TPML_DIGEST_VALUES) + 0x00, 0x00 // hashAlg (TPMT_HA; will be set later) + // digest (TPMT_HA; will be added later) +}; + +static const uint8_t tpm2_pcr_reset[] ={ + 0x80, 0x02, // TPM_ST_SESSIONS + 0x00, 0x00, 0x00, 0x1B, // commandSize + 0x00, 0x00, 0x01, 0x3D, // TPM_CC_PCR_Reset + 0x00, 0x00, 0x00, 0x00, // {PCR_FIRST:PCR_LAST} (TPMI_DH_PCR) + 0x00, 0x00, // authSize (NULL Password) + // null (indicate a NULL Password) + 0x00, 0x09, // authSize (password authorization session) + 0x40, 0x00, 0x00, 0x09, // TPM_RS_PW (indicate a password authorization session) + 0x00, 0x00, 0x01, 0x00, 0x00 +}; + +#endif /* _ELTT2_H_ */