From 267147f9712f150139bdb66313d7c353a7f1b0ba Mon Sep 17 00:00:00 2001 From: John Crispin Date: Wed, 29 Mar 2023 07:41:12 +0200 Subject: [PATCH] edgecore: add TPM support Signed-off-by: John Crispin --- feeds/edgecore/eltt2/Makefile | 29 + feeds/edgecore/eltt2/src/License.txt | 27 + feeds/edgecore/eltt2/src/Makefile | 15 + feeds/edgecore/eltt2/src/README.md | 230 ++++ feeds/edgecore/eltt2/src/README.txt | 362 ++++++ feeds/edgecore/eltt2/src/eltt2.c | 1742 ++++++++++++++++++++++++++ feeds/edgecore/eltt2/src/eltt2.h | 634 ++++++++++ 7 files changed, 3039 insertions(+) create mode 100644 feeds/edgecore/eltt2/Makefile create mode 100644 feeds/edgecore/eltt2/src/License.txt create mode 100644 feeds/edgecore/eltt2/src/Makefile create mode 100644 feeds/edgecore/eltt2/src/README.md create mode 100644 feeds/edgecore/eltt2/src/README.txt create mode 100644 feeds/edgecore/eltt2/src/eltt2.c create mode 100644 feeds/edgecore/eltt2/src/eltt2.h diff --git a/feeds/edgecore/eltt2/Makefile b/feeds/edgecore/eltt2/Makefile new file mode 100644 index 000000000..e430d4c34 --- /dev/null +++ b/feeds/edgecore/eltt2/Makefile @@ -0,0 +1,29 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=eltt2 +PKG_VERSION:=1.0 +PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/eltt2 + SECTION:=base + CATEGORY:=Utilities + TITLE:=eltt2 +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Package/eltt2/install + $(INSTALL_DIR) $(1)/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/eltt2 $(1)/bin/ +endef + +define Package/eltt2/extra_provides + echo "libc.so.6"; +endef + +$(eval $(call BuildPackage,eltt2)) diff --git a/feeds/edgecore/eltt2/src/License.txt b/feeds/edgecore/eltt2/src/License.txt new file mode 100644 index 000000000..e577cd682 --- /dev/null +++ b/feeds/edgecore/eltt2/src/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/feeds/edgecore/eltt2/src/Makefile b/feeds/edgecore/eltt2/src/Makefile new file mode 100644 index 000000000..0a35f2b92 --- /dev/null +++ b/feeds/edgecore/eltt2/src/Makefile @@ -0,0 +1,15 @@ +# Makefile for Embedded Linux TPM Toolbox 2 (ELTT2) +# Copyright (c) Infineon Technologies AG + +#CROSS-COMPILE:=../../../../../qsdk/staging_dir/toolchain-arm/bin/arm-openwrt-linux- +#CC:=$(CROSS-COMPILE)gcc +CC = gcc +CFLAGS=-Wall -Wextra -std=c99 -g + +all: eltt2 + +eltt2: eltt2.c eltt2.h + $(CC) $(CFLAGS) eltt2.c -o eltt2 + +clean: + rm -rf eltt2 diff --git a/feeds/edgecore/eltt2/src/README.md b/feeds/edgecore/eltt2/src/README.md new file mode 100644 index 000000000..32d87d35e --- /dev/null +++ b/feeds/edgecore/eltt2/src/README.md @@ -0,0 +1,230 @@ +# ELTT2 - Infineon Embedded Linux TPM Toolbox 2 for TPM 2.0 + + +All information in this document is Copyright (c) 2014-2022, Infineon Technologies AG
+All rights reserved. + + +# 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. + +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 Getting Started + +A TPM 2.0 evaluation board can be ordered in the [Hitex Webshop](https://www.ehitex.de/evaluation-boards/infineon/2564/iridium-9670-tpm2.0-spi). + + +

+ +

+ +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. + +The Infineon [TPM 2.0 Application Note](https://www.infineon.com/dgdl/Infineon-App-Note-SLx9670-TPM2.0_Embedded_RPi_DI_SLx-AN-v01_20-EN.pdf?fileId=5546d46267c74c9a01684b96e69f5d7b) shows how the TPM device driver can be set up (e.g. for Linux Kernel 4.14). + + + +# 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: + +\[-\]: none
+\[\*\]: the TPM platform hierarchy authorization value is not set (i.e., empty buffer)
+\[l\]: the required PCR bank is allocated
+\[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 option | Explanation | Precondition + --- | --- | --- + `-a [hash algorithm] ` | Hash Sequence SHA-1/256/384 \[default: SHA-1\] | \[u\] + `-A ` | Hash Sequence SHA-256 | \[u\] + `-b ` | Enter your own TPM command | \[u\] + `-c` | Read Clock | \[u\] + `-d ` | Shutdown | \[u\] + `-e [hash algorithm] ` | PCR Extend SHA-1/256/384 \[default: SHA-1\] | \[u\], \[l\] + `-E ` | PCR Extend SHA-256 | \[u\], \[l\] + `-g` | Get fixed capability values | \[u\] + `-v` | Get variable capability values | \[u\] + `-G ` | Get Random | \[u\] + `-h` | Help | \[-\] + `-l ` | PCR Allocate SHA-1/256/384 | \[u\], \[\*\] + `-r [hash algorithm] ` | PCR Read SHA-1/256/384 \[default: SHA-1\] | \[u\], \[l\] + `-R ` | PCR Read SHA-256 | \[u\], \[l\] + `-s [hash algorithm] ` | Hash SHA-1/256/384 \[default: 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/256/384 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` Hash given data with SHA-1 hash algorithm.
+or
+`./eltt2 -a sha1 41624364` Hash given data with SHA-1 hash algorithm.
+`./eltt2 -a sha256 41624364` Hash given data with SHA-256 hash algorithm.
+`./eltt2 -a sha384 41624364` Hash given data with SHA-384 hash algorithm.
+ +`-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/256/384. 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/32/48 bytes (will be padded with 0 if necessary). The TPM then builds an SHA-1/256/384 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` Extend bytes in PCR 23 with SHA-1.
+or
+`./eltt2 -e sha1 17 41624364` Extend bytes in PCR 23 with SHA-1.
+`./eltt2 -e sha256 17 41624364` Extend bytes in PCR 23 with SHA-256.
+`./eltt2 -e sha384 17 41624364` Extend bytes in PCR 23 with SHA-384.
+ +`-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 fixed properties. + +`-v`:
+With the "-v" command you can read the TPM's variable 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` + +`-l`:
+With the "-l" command you can allocate the SHA-1/256/384 PCR bank. Take note of two things. Firstly, the command requires a platform authorization value and it is set to an empty buffer; hence the command cannot be used if the TPM platform authorization value is set (e.g., by UEFI). Secondly, when the command is executed successfully a TPM reset has to follow for it to take effect. For example, use the following command to allocate a PCR bank:
+`./eltt2 -l sha1` Allocate SHA-1 PCR bank.
+`./eltt2 -l sha256` Allocate SHA-256 PCR bank.
+`./eltt2 -l sha384` Allocate SHA-384 PCR bank.
+ +`-r`:
+With the "-r" command you can read data from a selected SHA-1/256/384 PCR. For example, use the following command to read data from PCR 23 (0x17):
+`./eltt2 -r 17` Read data from SHA-1 PCR 23.
+or
+`./eltt2 -r sha1 17` Read data from SHA-1 PCR 23.
+`./eltt2 -r sha256 17` Read data from SHA-256 PCR 23.
+`./eltt2 -r sha384 17` Read data from SHA-384 PCR 23.
+ +`-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/256/384 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` Hash given data with SHA-1 hash algorithm.
+or
+`./eltt2 -s sha1 41624364` Hash given data with SHA-1 hash algorithm.
+`./eltt2 -s sha256 41624364` Hash given data with SHA-256 hash algorithm.
+`./eltt2 -s sha384 41624364` Hash given data with SHA-384 hash algorithm.
+ +`-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 . + + +# 4. 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.) + + +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/feeds/edgecore/eltt2/src/README.txt b/feeds/edgecore/eltt2/src/README.txt new file mode 100644 index 000000000..9643321ae --- /dev/null +++ b/feeds/edgecore/eltt2/src/README.txt @@ -0,0 +1,362 @@ +-------------------------------------------------------------------------------- + Infineon Embedded Linux TPM Toolbox 2 (ELTT2) for TPM 2.0 v1.1 + 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 2.0. + + Tested PC Platforms (x86): + - Ubuntu (R) Linux 12.04 LTS - 64 bit (modified Kernel 3.15.4) + with Infineon TPM 2.0 SLB9665 Firmware 5.22 + + Tested Embedded Platforms (ARM): + - Android 6.0 "Marshmallow" - 64 bit (modified Kernel 3.18.0+) on HiKey + with Prototype Infineon I2C TPM 2.0 for Embedded Platforms + + ELTT2 may run on many other little-endian hardware and software + configurations capable of running Linux and hosting a TPM 2.0, 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: + + [-]: none + [*]: the TPM platform hierarchy authorization value is not set (i.e., empty buffer) + [l]: the required PCR bank is allocated + [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 algorithm] : Hash Sequence SHA-1/256/384 [default: SHA-1] [u] + + -A : Hash Sequence SHA-256 [u] + + -b : Enter your own TPM command [u] + + -c: Read Clock [u] + + -d : Shutdown [u] + + -e [hash algorithm] : PCR Extend SHA-1/256/384 [default: SHA-1] [u], [l] + + -E : PCR Extend SHA-256 [u], [l] + + -g: Get fixed capability values [u] + + -v: Get variable capability values [u] + + -G : Get Random [u] + + -h: Help [-] + + -l : PCR Allocate SHA-1/256/384 [u], [*] + + -r [hash algorithm] : PCR Read SHA-1/256/384 [default: SHA-1] [u], [l] + + -R : PCR Read SHA-256 [u], [l] + + -s [hash algorithm] : Hash SHA-1/SHA256 [default: 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/256/384 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 Hash given data with SHA-1 hash algorithm. + or + ./eltt2 -a sha1 41624364 Hash given data with SHA-1 hash algorithm. + ./eltt2 -a sha256 41624364 Hash given data with SHA-256 hash algorithm. + + -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/256/384. + 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/32/48 bytes (will be padded with 0 if necessary). + The TPM then builds an SHA-1/256/384 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 Extend bytes in PCR 23 with SHA-1. + or + ./eltt2 -e sha1 17 41624364 Extend bytes in PCR 23 with SHA-1. + ./eltt2 -e sha256 17 41624364 Extend bytes in PCR 23 with SHA-256. + + -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 fixed properties. + + -v: + With the "-v" command you can read the TPM's variable 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 + + -l: + With the "-l" command you can allocate the SHA-1/256/384 PCR bank. + Take note of two things. Firstly, the command requires a platform + authorization value and it is set to an empty buffer; hence the command + cannot be used if the TPM platform authorization value is set (e.g., by UEFI). + Secondly, when the command is executed successfully a TPM reset has to + follow for it to take effect. For example, use the following command to + allocate a PCR bank: + ./eltt2 -l sha1 Allocate SHA-1 PCR bank. + ./eltt2 -l sha256 Allocate SHA-256 PCR bank. + ./eltt2 -l sha384 Allocate SHA-384 PCR bank. + + -r: + With the "-r" command you can read data from a selected SHA-1/256/384 PCR. + For example, use the following command to read data from PCR 23 (0x17): + ./eltt2 -r 17 Read data from SHA-1 PCR 23. + or + ./eltt2 -r sha1 17 Read data from SHA-1 PCR 23. + ./eltt2 -r sha256 17 Read data from SHA-256 PCR 23. + + -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/256/384 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 Hash given data with SHA-1 hash algorithm. + or + ./eltt2 -s sha1 41624364 Hash given data with SHA-1 hash algorithm. + ./eltt2 -s sha256 41624364 Hash given data with SHA-256 hash algorithm. + + -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 and that the PCR is going to be reset in both banks + (SHA-1 and SHA-256). + 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.1. 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/feeds/edgecore/eltt2/src/eltt2.c b/feeds/edgecore/eltt2/src/eltt2.c new file mode 100644 index 000000000..644fc554a --- /dev/null +++ b/feeds/edgecore/eltt2/src/eltt2.c @@ -0,0 +1,1742 @@ +/** + * @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 + * @copyright Copyright (c) 2014 - 2017 Infineon Technologies AG ( www.infineon.com ).\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. + */ +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. + hash_algo_enum hash_algo = ALG_NULL; // Variable to indicate the selected hash algorithm. + + // ---------- 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, "cgvhTa:A:b:d:e:E:G:l:r:R:s:S:t:u:z:"))) + { + switch (option) + { + case 'a': // TPM2_HashSequenceStart SHA-1/256/384 + case 'A': // TPM2_HashSequenceStart SHA-256 + HASH_ALG_PARSER('a', 3); + + ret_val = create_hash_sequence(optarg, hash_algo, 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) / HEX_BYTE_STRING_LENGTH + strlen(optarg) % HEX_BYTE_STRING_LENGTH; // 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/256/384 + case 'E': // PCR_Extend SHA-256 + if (4 > argc) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "The command '-%c' needs minimum two arguments. Use '-h' for more information.\n", option); + + // Set the argument count to the next option for error handling. + optind += 2; + break; + } + + HASH_ALG_PARSER('e', 4); + + // Allocate the input buffer for pcr_extend and tpmtool_transmit. + if (ALG_SHA1 == hash_algo) + { + input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA1_DIGEST_SIZE; + } + else if (ALG_SHA256 == hash_algo) + { + input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA256_DIGEST_SIZE; + } + else + { + input_bytes_size = sizeof(tpm2_pcr_extend) + TPM_SHA384_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, hash_algo); + + // 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_fixed, sizeof(tpm2_getcapability_fixed), tpm_response_buf, &tpm_response_buf_size); + break; + + case 'v': // TPM_CC_GetCapability + ret_val = tpmtool_transmit(tpm2_getcapability_var, sizeof(tpm2_getcapability_var), 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 'l': // PCR_Allocate SHA-1/256/384 + HASH_ALG_PARSER('l', -1); + + // Allocate the input buffer for pcr_read and tpmtool_transmit. + input_bytes_size = sizeof(tpm2_pcr_allocate); + input_bytes = malloc(input_bytes_size); + MALLOC_ERROR_CHECK(input_bytes); + memset(input_bytes, 0, input_bytes_size); + + // Create PCR_Allocate TPM request. + ret_val = pcr_allocate(input_bytes, hash_algo); + 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 'r': // PCR_Read SHA-1/256/384 + case 'R': // PCR_Read SHA-256 + HASH_ALG_PARSER('r', 3); + + // 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, hash_algo); + 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/256/384 + case 'S': // Hash SHA-256 + HASH_ALG_PARSER('s', 3); + + // Allocate the input buffer for create_hash and tpmtool_transmit. + input_bytes_size = strlen(optarg) / HEX_BYTE_STRING_LENGTH + strlen(optarg) % HEX_BYTE_STRING_LENGTH + 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, hash_algo, 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 || + 'l' == 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 (command line parameter parsing loop). + + // If no error has occurred 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); + + if (0 >= length) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'length' must be larger than 0."); + break; + } + if (TPM_REQ_MAX_SIZE < length) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'length' must be smaller than or equal to %u.", TPM_REQ_MAX_SIZE); + break; + } + if (TPM_CMD_HEADER_SIZE >= *resp_length) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter '*resp_length' must be at least %u.", TPM_CMD_HEADER_SIZE); + break; + } + if (TPM_RESP_MAX_SIZE < *resp_length) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter '*resp_length' must be smaller than or equal to %u.", TPM_RESP_MAX_SIZE); + break; + } + + memset(response, 0, *resp_length); + + // ---------- Open TPM device ---------- + dev_tpm = open("/dev/tpm0", O_RDWR); + if (-1 == dev_tpm) + { + ret_val = errno; + fprintf(stderr, "Error opening the device.\n"); + break; + } + + // Send request data to TPM. + transmit_size = write(dev_tpm, buf, length); + if (transmit_size == ERR_COMMUNICATION || length != transmit_size) + { + ret_val = errno; + fprintf(stderr, "Error sending request to TPM.\n"); + break; + } + + // Read the TPM response header. + transmit_size = read(dev_tpm, response, TPM_RESP_MAX_SIZE); + if (transmit_size == ERR_COMMUNICATION) + { + ret_val = errno; + fprintf(stderr, "Error reading response from TPM.\n"); + 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; +} + +static int return_error_handling(uint8_t *response_buf) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint64_t tpm_rc = 0; // Return code from TPM header. + + do + { + NULL_POINTER_CHECK(response_buf); + + ret_val = buf_to_uint64(response_buf, 6, sizeof(uint32_t), &tpm_rc, TPM_RESP_MAX_SIZE); // TPM Return code type is 32 bit unsigned int! + 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%.8" PRIx64 ": ", 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; +} + +static 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); + + if (0 >= resp_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be larger than 0."); + break; + } + if (TPM_RESP_MAX_SIZE < resp_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be smaller than or equal to %u.\n", TPM_RESP_MAX_SIZE); + break; + } + + 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 fixed capability flags. + ret_val = print_capability_flags(response_buf, PT_FIXED_SELECTOR); + break; + + case 'v': // Print the variable capability flags. + ret_val = print_capability_flags(response_buf, PT_VAR_SELECTOR); + 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; +} + +static 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. + uint64_t data_size = 0; // Size of response data. + + do + { + NULL_POINTER_CHECK(response_buf); + + if (0 >= resp_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be larger than 0."); + break; + } + if (TPM_RESP_MAX_SIZE < resp_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'resp_size' must be smaller than or equal to %u.\n", TPM_RESP_MAX_SIZE); + break; + } + if (resp_size <= offset) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Offset %u cannot be equal or larger than input buffer size %zu.\n", offset, resp_size); + break; + } + + 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 >= TPM_CMD_HEADER_SIZE && (i+1) % 10 == 0) // After all 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 - sizeof(uint16_t), sizeof(uint16_t), &data_size, resp_size); // Data size actually is only an uint16_t and should always 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; +} + +static void print_help() +{ + printf("'-a [hash algorithm] ': Hash Sequence SHA-1/256/384 [default: SHA-1]\n"); + printf(" -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n"); + printf(" Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n"); + printf("'-A ': Hash Sequence SHA-256\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 [hash algorithm] ': PCR Extend SHA-1/256/384 [default: SHA-1]\n"); + printf(" -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\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 SHA-256\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 fixed capability values\n"); + printf("'-v': Get variable capability values\n"); + printf("'-G ': Get Random\n"); + printf(" -> Enter desired number of random bytes in hex like '20' for 0x20 (=32 bytes, maximum)\n"); + printf("'-h': Help\n"); + printf("'-l ': PCR allocate SHA-1/256/384\n"); + printf(" -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n"); + printf("'-r [hash algorithm] ': PCR Read SHA-1/256/384 [default: SHA-1]\n"); + printf(" -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n"); + printf(" PCR index: Enter PCR number in hex like '17' for 0x17\n"); + printf("'-R ': PCR Read SHA-256\n"); + printf(" -> PCR index: Enter PCR number in hex like '17' for 0x17\n"); + printf("'-s [hash algorithm] ': Hash SHA-1/256/384 [default: SHA-1]\n"); + printf(" -> Hash algorithm: Enter hash algorithm like 'sha1', 'sha256', 'sha384'\n"); + printf(" Data bytes: Enter a byte sequence like '0F56...' for {0x0f, 0x56, ...}\n"); + printf("'-S ': Hash SHA-256\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 SHA-1, SHA-256, and SHA-384\n"); + printf(" -> PCR index: Enter PCR number in hex like '17' for 0x17\n"); +} + +static int print_capability_flags(uint8_t *response_buf, uint8_t cap_selector) +{ + int ret_val = EXIT_SUCCESS; // Return value. + uint64_t propertyValue = 0; // Value of the read property. + uint64_t propertyKey = 0; // Key of the property. + int tmp = 0; // Temporary buffer. + + do + { + NULL_POINTER_CHECK(response_buf); + if(cap_selector == PT_FIXED_SELECTOR) + { + printf("\nTPM capability information of fixed properties:\n"); + printf("=========================================================\n"); + + for(int x = 0x13; x<(TPM_RESP_MAX_SIZE-8); x+=8) + { //Iterate over each property key/value pair + ret_val = buf_to_uint64(response_buf, x, 4, &propertyKey, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + ret_val = buf_to_uint64(response_buf, x+4, 4, &propertyValue, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + + switch(propertyKey) + { + case 0x100: + printf("TPM_PT_FAMILY_INDICATOR: %c%c%c%c\n", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]); + break; + case 0x100+1: + printf("TPM_PT_LEVEL: %" PRIu64 "\n", propertyValue); + break; + case 0x100+2: + printf("TPM_PT_REVISION: %" PRIu64 "\n", propertyValue); + break; + case 0x100+3: + printf("TPM_PT_DAY_OF_YEAR: %" PRIu64 "\n", propertyValue); + break; + case 0x100+4: + printf("TPM_PT_YEAR: %" PRIu64 "\n", propertyValue); + break; + case 0x100+5: + printf("TPM_PT_MANUFACTURER: %c%c%c%c\n", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]); + break; + case 0x100+6: + printf("TPM_PT_VENDOR_STRING: "); + printf("%c%c%c%c", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]); + break; + case 0x100+7: // it is assumed that TPM_PT_VENDOR_STRING_2 follows _1 + printf("%c%c%c%c", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]); + break; + case 0x100+8: + printf("%c%c%c%c", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]); + break; + case 0x100+9: + printf("%c%c%c%c\n", response_buf[x+4], response_buf[x+5], response_buf[x+6], response_buf[x+7]); + break; + case 0x100+10: + printf("TPM_PT_VENDOR_TPM_TYPE: %" PRIu64 "\n", propertyValue); + break; + case 0x100+11: + // special handling for firmware version XX.xx.xxxx.x + ret_val = buf_to_uint64(response_buf, x+4, 2, &propertyValue, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + printf("TPM_PT_FIRMWARE_VERSION: %" PRIu64 "", propertyValue); + + ret_val = buf_to_uint64(response_buf, x+6, 2, &propertyValue, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + printf(".%" PRIu64 "", propertyValue); + break; + case 0x100+12: + // special handling for firmware version XX.xx.xxxx.x + ret_val = buf_to_uint64(response_buf, x+4, 2, &propertyValue, TPM_RESP_MAX_SIZE); // Check for output version. + RET_VAL_CHECK(ret_val); + + if (2 <= propertyValue) // Infineon custom format + { + ret_val = buf_to_uint64(response_buf, x+5, 2, &propertyValue, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + printf(".%" PRIu64 "", propertyValue); + + ret_val = buf_to_uint64(response_buf, x+7, 1, &propertyValue, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + printf(".%" PRIu64 "\n", propertyValue); + } + else + { + ret_val = buf_to_uint64(response_buf, x+4, 4, &propertyValue, TPM_RESP_MAX_SIZE); + RET_VAL_CHECK(ret_val); + printf(".%" PRIu64 "\n", propertyValue); + } + break; + + case 0x100+24: + printf("\nTPM_PT_MEMORY:\n"); + printf("=========================================================\n"); + tmp = ((propertyValue & (1<<0)) == 0? 0:1); // Check bit 0 value. + printf("Shared RAM: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + tmp = ((propertyValue & (1<<1)) == 0? 0:1); // Check bit 1 value. + printf("Shared NV: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + tmp = ((propertyValue & (1<<2)) == 0? 0:1); // Check bit 2 value. + printf("Object Copied To Ram: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + //bit 31:3 = reserved + break; + + case 0x200: + printf("\nTPM_PT_PERMANENT:\n"); + printf("=========================================================\n"); + + tmp = ((propertyValue & (1<<0)) == 0? 0:1); // Check bit 0 value. + printf("Owner Auth Set: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + tmp = ((propertyValue & (1<<1)) == 0? 0:1); // Check bit 1 value. + printf("Sendorsement Auth Set: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + tmp = ((propertyValue & (1<<2)) == 0? 0:1); // Check bit 2 value. + printf("Lockout Auth Set: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + //bit 7:3 = reserved + + tmp = ((propertyValue & (1<<8)) == 0? 0:1); // Check bit 8 value. + printf("Disable Clear: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + tmp = ((propertyValue & (1<<9)) == 0? 0:1); // Check bit 9 value. + printf("In Lockout: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + + tmp = ((propertyValue & (1<<10)) == 0? 0:1); // Check bit 10 value. + printf("TPM Generated EPS: %i %s", (tmp), ((tmp)? "SET\n" : "CLEAR\n")); + //bit 31:11 = reserved + break; + default: + // Unknown attribute - ignore + break; + } + } + } + else if (cap_selector == PT_VAR_SELECTOR) + { + NULL_POINTER_CHECK(response_buf); + + printf("\nTPM capability information of variable properties:\n"); + for(int x = 0x13; x= input_buffer_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'input_buffer_size' must be larger than %u.\n", offset); + break; + } + if (INT_MAX < input_buffer_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'input_buffer_size' must be smaller or equal to %u.\n", INT_MAX); + break; + } + if (0 >= length) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'length' must be larger than 0.\n"); + break; + } + if (length > input_buffer_size - offset) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'length' must be smaller or equal to %i.\n", input_buffer_size - offset); + break; + } + if (sizeof(uint64_t) < length) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Input buffer length remaining from offset must be smaller than %zu.\n", sizeof(uint64_t)); + break; + } + + for (i = 0; i < length; i++) + { + tmp = (tmp << 8) + input_buffer[offset + i]; + } + *output_value = tmp; + } while (0); + + return ret_val; +} + +static 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. + uint32_t unStrLen = 0; // Temporary store for byte string length. + + do + { + NULL_POINTER_CHECK(byte_string); + NULL_POINTER_CHECK(byte_values); + + if (0 >= byte_values_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'byte_values_size' must be larger than 0.\n"); + break; + } + if (INT_MAX < byte_values_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'byte_values_size' must be smaller or equal to %u.\n", INT_MAX); + break; + } + + memset(byte_values, 0, byte_values_size); + + unStrLen = strlen(byte_string); + if ((unStrLen / HEX_BYTE_STRING_LENGTH + unStrLen % HEX_BYTE_STRING_LENGTH) > (uint32_t)byte_values_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Input character string is too long for output buffer.\n"); + break; + } + + // Loop "byte-wise" through string + for (i = 0; i < unStrLen; i += HEX_BYTE_STRING_LENGTH) + { + // 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'; + hex_byte[2] = '\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 / HEX_BYTE_STRING_LENGTH] = (uint8_t)strtoul(hex_byte, &invalidChars, 16); + if (0 != errno) + { + ret_val = errno; + fprintf(stderr, "Error parsing string.\n"); + 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; +} + +static 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); + if (0 >= input_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'input_size' must be larger than 0.\n"); + break; + } + if (sizeof(uint64_t) < input_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'input_size' must be smaller or equal to %zu.\n", sizeof(uint64_t)); + break; + } + + for (i = 0; i < input_size; i++) + { + output_byte[i] = input >> ((input_size - 1 - i) * 8); + } + } while (0); + + return ret_val; +} + +static 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) / HEX_BYTE_STRING_LENGTH + strlen(data_length_string) % HEX_BYTE_STRING_LENGTH; + 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; +} + +static int create_hash(char *data_string, hash_algo_enum hash_algo, 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. + 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 (TPM_REQ_MAX_SIZE < hash_cmd_buf_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'hash_cmd_buf_size' must be smaller or equal to %u.\n", TPM_REQ_MAX_SIZE); + break; + } + if (sizeof(tpm2_hash) > hash_cmd_buf_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'hash_cmd_buf_size' must be at least %zu.\n", sizeof(tpm2_hash)); + break; + } + data_string_size = strlen(data_string) / HEX_BYTE_STRING_LENGTH + strlen(data_string) % HEX_BYTE_STRING_LENGTH; + if (0 == data_string_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. data_string is empty.\n"); + break; + } + if (hash_cmd_buf_size - sizeof(tpm2_hash) < data_string_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Input data size must be smaller or equal to %zu.\n", hash_cmd_buf_size - sizeof(tpm2_hash)); + break; + } + + memset(hash_cmd_buf, 0, hash_cmd_buf_size); + + // 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 (ALG_SHA1 == hash_algo) + { + tpm_hash_alg = sha1_alg; + printf("\nTPM2_Hash of '%s' with SHA-1:\n", data_string); + } + else if (ALG_SHA256 == hash_algo) + { + tpm_hash_alg = sha256_alg; + printf("\nTPM2_Hash of '%s' with SHA-256:\n", data_string); + } + else + { + tpm_hash_alg = sha384_alg; + printf("\nTPM2_Hash of '%s' with SHA-384:\n", data_string); + } + + offset = TPM_CMD_SIZE_OFFSET; + ret_val = int_to_bytearray(sizeof(tpm2_hash) + data_string_size, sizeof(uint32_t), hash_cmd_buf + offset); + RET_VAL_CHECK(ret_val); + offset = TPM_CMD_HEADER_SIZE; + 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, sizeof(sha1_alg)); + offset += sizeof(sha1_alg); + memcpy(hash_cmd_buf + offset, tpm_cc_hash_hierarchy, sizeof(tpm_cc_hash_hierarchy)); + } while (0); + + return ret_val; +} + +static int create_hash_sequence(char *data_string, hash_algo_enum hash_algo, 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. + uint64_t 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 sequence handle. + ssize_t original_response_buf_size = 0; // Backup of the original response buffer size. + // Minimum success response buffer size (TPM command header + sequence handle) + ssize_t minimum_response_buf_size = TPM_CMD_HEADER_SIZE + sizeof(sequence_handle); + + do + { + NULL_POINTER_CHECK(tpm_response_buf); + NULL_POINTER_CHECK(data_string); + NULL_POINTER_CHECK(tpm_response_buf_size); + + memset(tpm_response_buf, 0, *tpm_response_buf_size); + memset(sequence_handle, 0, 4); + + if (TPM_RESP_MAX_SIZE < *tpm_response_buf_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter '*tpm_response_buf_size' must be smaller or equal to %u.\n", TPM_RESP_MAX_SIZE); + break; + } + if (minimum_response_buf_size > *tpm_response_buf_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter '*tpm_response_buf_size' must be at least %zu.\n", minimum_response_buf_size); + 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 (ALG_SHA1 == hash_algo) + { + printf("\nTPM2_HashSequenceStart of '%s' with SHA-1:\n", data_string); + memcpy(tpm2_hash_sequence_start + 12, sha1_alg, sizeof(sha1_alg)); + } + else if (ALG_SHA256 == hash_algo) + { + printf("\nTPM2_HashSequenceStart of '%s' with SHA-256:\n", data_string); + memcpy(tpm2_hash_sequence_start + 12, sha256_alg, sizeof(sha256_alg)); + } + else + { + printf("\nTPM2_HashSequenceStart of '%s' with SHA-384:\n", data_string); + memcpy(tpm2_hash_sequence_start + 12, sha384_alg, sizeof(sha384_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, *tpm_response_buf_size); + RET_VAL_CHECK(ret_val); + if (TPM_RC_SUCCESS != tpm_rc) + { + break; + } + + // Get sequence handle from TPM response. + memcpy(sequence_handle, tpm_response_buf + TPM_CMD_HEADER_SIZE, sizeof(sequence_handle)); + + // Calculate byte sizes of hash input string. + data_string_bytes_size = strlen(data_string) / HEX_BYTE_STRING_LENGTH + strlen(data_string) % HEX_BYTE_STRING_LENGTH; + + // 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 = TPM_CMD_SIZE_OFFSET; + ret_val = int_to_bytearray(update_request_size, sizeof(update_request_size), update_request + offset); + RET_VAL_CHECK(ret_val); + offset = TPM_CMD_HEADER_SIZE; + 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, *tpm_response_buf_size); + 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 + TPM_CMD_HEADER_SIZE, 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; +} + +static int pcr_extend(char *pcr_index_str, char *pcr_digest_str, uint8_t *pcr_cmd_buf, size_t pcr_cmd_buf_size, hash_algo_enum hash_algo) +{ + 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 (TPM_REQ_MAX_SIZE < pcr_cmd_buf_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'pcr_cmd_buf_size' size must be smaller or equal to %u.\n", TPM_REQ_MAX_SIZE); + break; + } + if (sizeof(tpm2_pcr_extend) > pcr_cmd_buf_size) + { + ret_val = EINVAL; + fprintf(stderr, "Bad parameter. Value of parameter 'pcr_cmd_buf_size' must be at least %zu.\n", sizeof(tpm2_pcr_extend)); + break; + } + + memset(pcr_cmd_buf, 0, pcr_cmd_buf_size); + + // Check and convert the command line input (PCR index) to bytes. + if (1 != strlen(pcr_index_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_index_str) % HEX_BYTE_STRING_LENGTH) + { + 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) / HEX_BYTE_STRING_LENGTH + strlen(pcr_digest_str) % HEX_BYTE_STRING_LENGTH; + if (ALG_SHA1 == hash_algo && 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 (ALG_SHA256 == hash_algo && 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; + } + if (ALG_SHA384 == hash_algo && TPM_SHA384_DIGEST_SIZE < pcr_digest_size) + { + ret_val = ERR_BAD_CMD; + fprintf(stderr, "Bad option. Maximum SHA-384 PCR digest size is 48 byte (96 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 (ALG_SHA1 == hash_algo) + { + 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 (ALG_SHA256 == hash_algo) + { + 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); + } + else if (ALG_SHA384 == hash_algo) + { + pcr_cmd_buf[5] = sizeof(tpm2_pcr_extend) + TPM_SHA384_DIGEST_SIZE; + memcpy(pcr_cmd_buf + 31, sha384_alg, sizeof(sha384_alg)); + printf("Extend PCR %i (SHA-384) 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; +} + +static int pcr_allocate(uint8_t *pcr_cmd_buf, hash_algo_enum hash_algo) +{ + int ret_val = EXIT_SUCCESS; // Return value. + unsigned char set[] = {0xFF, 0xFF, 0xFF}; + unsigned char clear[] = {0x00, 0x00, 0x00}; + + do + { + NULL_POINTER_CHECK(pcr_cmd_buf); + + // Copy basic command bytes. + memcpy(pcr_cmd_buf, tpm2_pcr_allocate, sizeof(tpm2_pcr_allocate)); + + // Set hash algorithm depending on user input option at the correct byte index in the command byte stream. + if (ALG_SHA1 == hash_algo) + { + memcpy(pcr_cmd_buf + 34, set, sizeof(set)); + memcpy(pcr_cmd_buf + 40, clear, sizeof(clear)); + memcpy(pcr_cmd_buf + 46, clear, sizeof(clear)); + printf("PCR allocate SHA-1 bank\n"); + } + else if (ALG_SHA256 == hash_algo) + { + memcpy(pcr_cmd_buf + 34, clear, sizeof(clear)); + memcpy(pcr_cmd_buf + 40, set, sizeof(set)); + memcpy(pcr_cmd_buf + 46, clear, sizeof(clear)); + printf("PCR allocate SHA-256 bank\n"); + } + else if (ALG_SHA384 == hash_algo) + { + memcpy(pcr_cmd_buf + 34, clear, sizeof(clear)); + memcpy(pcr_cmd_buf + 40, clear, sizeof(clear)); + memcpy(pcr_cmd_buf + 46, set, sizeof(set)); + printf("PCR allocate SHA-384 bank\n"); + } + } while (0); + + return ret_val; +} + +static int pcr_read(char *pcr_index_str, uint8_t *pcr_cmd_buf, hash_algo_enum hash_algo) +{ + 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); + + memset(pcr_cmd_buf, 0, 20); + + // Convert the command line input to bytes. + if (1 != strlen(pcr_index_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_index_str) % HEX_BYTE_STRING_LENGTH) + { + // 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 (ALG_SHA1 == hash_algo) + { + memcpy(pcr_cmd_buf + 14, sha1_alg, sizeof(sha1_alg)); + printf("Read PCR %i (SHA-1):\n", pcr_index); + } + else if (ALG_SHA256 == hash_algo) + { + memcpy(pcr_cmd_buf + 14, sha256_alg, sizeof(sha256_alg)); + printf("Read PCR %i (SHA-256):\n", pcr_index); + } + else if (ALG_SHA384 == hash_algo) + { + memcpy(pcr_cmd_buf + 14, sha384_alg, sizeof(sha384_alg)); + printf("Read PCR %i (SHA-384):\n", pcr_index); + } + } while (0); + + return ret_val; +} + +static 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); + + memset(pcr_cmd_buf, 0, 27); + + // Convert the command line input to bytes. + if (1 != strlen(pcr_index_str) / HEX_BYTE_STRING_LENGTH + strlen(pcr_index_str) % HEX_BYTE_STRING_LENGTH) + { + 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 (SHA-1, SHA-256, and SHA-384):\n", pcr_index); + } while (0); + + return ret_val; +} diff --git a/feeds/edgecore/eltt2/src/eltt2.h b/feeds/edgecore/eltt2/src/eltt2.h new file mode 100644 index 000000000..12d7a797f --- /dev/null +++ b/feeds/edgecore/eltt2/src/eltt2.h @@ -0,0 +1,634 @@ +#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 - 2017 Infineon Technologies AG ( www.infineon.com ).\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 - 2017 Infineon Technologies AG ( www.infineon.com ).\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 +#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_SHA384_DIGEST_SIZE 48 ///< For all SHA-384 operations the digest's size is always 48 bytes. +#define TPM_CMD_HEADER_SIZE 10 ///< The size of a standard TPM command header is 10 bytes. +#define TPM_CMD_SIZE_OFFSET 2 ///< The offset of a TPM command's size value is 2 bytes. +#define HEX_BYTE_STRING_LENGTH 2 ///< A byte can be represented by two hexadecimal characters. +#ifndef INT_MAX +#define INT_MAX 0x7FFFFFF ///< The maximum value of a signed 32-bit integer. +#endif +// 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 +// TPM_PT constants +#define PT_FIXED_SELECTOR 1 ///< Fixed GetCapability Flags +#define PT_VAR_SELECTOR 2 ///< Variable GetCapability Flags + +//-------------"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 +// Command line option parser for hash algorithm +#define HASH_ALG_PARSER(o, c) \ + do { \ + if (o == option) \ + { \ + if (c == argc) \ + { \ + hash_algo = ALG_SHA1; \ + } \ + else \ + { \ + if (0 == strcasecmp(optarg, "sha1")) \ + { \ + hash_algo = ALG_SHA1; \ + } \ + else if (0 == strcasecmp(optarg, "sha256")) \ + { \ + hash_algo = ALG_SHA256; \ + } \ + else if (0 == strcasecmp(optarg, "sha384")) \ + { \ + hash_algo = ALG_SHA384; \ + } \ + else \ + { \ + ret_val = ERR_BAD_CMD; \ + fprintf(stderr, "Unknown option. Use '-h' for more information.\n"); \ + break; \ + } \ + if (argc > optind) \ + { \ + optarg = argv[optind++]; \ + } \ + } \ + } \ + else \ + { \ + hash_algo = ALG_SHA256; \ + } \ + } while (0) + +//--------------"Enums"-------------- +// Hash algorithms +typedef enum hash_algo_enum +{ + ALG_NULL, + ALG_SHA1, + ALG_SHA256, + ALG_SHA384, +} hash_algo_enum; + +//-------------"Methods"------------- +/** + * @brief Convert (max.) 8 byte buffer to an unsigned 64-bit 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 64-bit integer. + * @param [in] input_buffer_size Size of input_buffer in bytes. + * @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 + */ +static int buf_to_uint64(uint8_t *input_buffer, uint32_t offset, uint32_t length, uint64_t *output_value, uint32_t input_buffer_size); + +/** + * @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 + */ +static 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 + */ +static 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] hash_algo Set to ALG_SHA1 for extending with SHA-1, + ALG_SHA256 for SHA-256, and ALG_SHA384 for SHA-384. + * @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 + */ +static int pcr_extend(char *pcr_index_str, char *pcr_digest_str, uint8_t *pcr_cmd_buf, size_t pcr_cmd_buf_size, hash_algo_enum hash_algo); + +/** + * @brief Create the PCR_Allocate command. + * @param [out] *pcr_cmd_buf Return buffer for the complete command. + * @param [in] hash_algo Set to ALG_SHA1 to allocate SHA-1, + ALG_SHA256 for SHA-256, and ALG_SHA384 for SHA-384. + * @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. + * @date 2022/05/09 + */ +static int pcr_allocate(uint8_t *pcr_cmd_buf, hash_algo_enum hash_algo); + +/** + * @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] hash_algo Set to ALG_SHA1 for reading with SHA-1, + ALG_SHA256 for SHA-256, and ALG_SHA384 for SHA-384. + * @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 + */ +static int pcr_read(char *pcr_index_str, uint8_t *pcr_cmd_buf, hash_algo_enum hash_algo); + +/** + * @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 + */ +static int pcr_reset(char *pcr_index_str, uint8_t *pcr_cmd_buf); + +/** + * @brief Print the command line usage and switches. + * @date 2014/06/26 + */ +static 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 + */ +static 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 + */ +static 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 + */ +static 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 + */ +static 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. + * @param [in] cap_selector Type of capabilities to print. + * @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 + */ +static int print_capability_flags(uint8_t *response_buf, uint8_t cap_selector); + +/** + * @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 + */ +static 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 + */ +static 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] hash_algo Set to ALG_SHA1 for hashing with SHA-1, + ALG_SHA256 for SHA-256, and ALG_SHA384 for SHA-384. + * @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 + */ +static int create_hash(char *data_string, hash_algo_enum hash_algo, 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] hash_algo Set to ALG_SHA1 for hashing with SHA-1, + ALG_SHA256 for SHA-256, and ALG_SHA384 for SHA-384. + * @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 + */ +static int create_hash_sequence(char *data_string, hash_algo_enum hash_algo, uint8_t *tpm_response_buf, ssize_t *tpm_response_buf_size); + +//-------------"command bytes"------------- +static const uint8_t tpm2_startup_clear[] = { + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup + 0x00, 0x00 // TPM_SU_CLEAR +}; + +static const uint8_t tpm2_startup_state[] = { + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0C, // commandSize + 0x00, 0x00, 0x01, 0x44, // TPM_CC_Startup + 0x00, 0x01 // TPM_SU_STATE +}; + +static const uint8_t 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[] = { + 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[] = { + 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[] = { + 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[] = { + 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[] = { + 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[] = { + 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[] = { + 0x80, 0x01, // TPM_ST_NO_SESSIONS + 0x00, 0x00, 0x00, 0x0A, // commandSize + 0x00, 0x00, 0x01, 0x81 // TPM_CC_ReadClock +}; + +static const uint8_t tpm2_getcapability_fixed[] ={ + 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, 0x66 // PropertyCount 102 (from 100 - 201) +}; + +static const uint8_t tpm2_getcapability_var[] ={ + 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, 0x02, 0x00, // Property: TPM_PT_FAMILY_INDICATOR: PT_GROUP * 2 + 0 + 0x00, 0x00, 0x00, 0x02 // PropertyCount 02 (from 200 - 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 sha384_alg[] = { + 0x00, 0x0C // command for sha384 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_allocate[] = { + 0x80, 0x02, // TPM_ST_SESSIONS + 0x00, 0x00, 0x00, 0x31, // commandSize + 0x00, 0x00, 0x01, 0x2B, // TPM_CC_PCR_Allocate + 0x40, 0x00, 0x00, 0x0C, // TPM_RH_PLATFORM + 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, 0x03, // count (TPML_PCR_SELECTION) + 0x00, 0x04, // hash (TPMS_PCR_SELECTION; SHA-1) + 0x03, // sizeofSelect (TPMS_PCR_SELECTION) + 0x00, 0x00, 0x00, // pcrSelect (TPMS_PCR_SELECTION; will be set later) + 0x00, 0x0B, // hash (TPMS_PCR_SELECTION; SHA-256) + 0x03, // sizeofSelect (TPMS_PCR_SELECTION) + 0x00, 0x00, 0x00, // pcrSelect (TPMS_PCR_SELECTION; will be set later) + 0x00, 0x0C, // hash (TPMS_PCR_SELECTION; SHA-384) + 0x03, // sizeofSelect (TPMS_PCR_SELECTION) + 0x00, 0x00, 0x00 // pcrSelect (TPMS_PCR_SELECTION; will be set later) +}; + +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_ */