diff --git a/.appveyor.yml b/.appveyor.yml index 5ea3f7c..3cd0a75 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' pull_requests: do_not_increment_build_number: true skip_tags: true -image: Visual Studio 2017 +image: Visual Studio 2019 configuration: - Debug - Release diff --git a/.ci/docker.run b/.ci/docker.run index 1653f36..c45c8ad 100755 --- a/.ci/docker.run +++ b/.ci/docker.run @@ -24,6 +24,11 @@ if [ -z "$WITH_CRYPTO" ]; then export WITH_CRYPTO="ossl" fi +little_endian=$(echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}') +if [ $little_endian -eq 0 ]; then + export CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --with-integrationtcti=libtpms" +fi + if [ "$WITH_CRYPTO" != "ossl" ]; then export CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --disable-fapi --disable-policy" fi @@ -69,7 +74,9 @@ if [[ "$CC" == "gcc" && "$ENABLE_COVERAGE" == "true" ]]; then fi if ldconfig -p 2>/dev/null| grep libasan > /dev/null && ldconfig -p 2>/dev/null| grep libubsan > /dev/null; then - SANITIZER_OPTION="--with-sanitizer=undefined,address" + if [ $little_endian -eq 1 ]; then + SANITIZER_OPTION="--with-sanitizer=undefined,address" + fi fi if [ "$SCANBUILD" == "yes" ]; then diff --git a/.cirrus.yml b/.cirrus.yml index f7d49a4..2b638f8 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -3,14 +3,17 @@ task: CFLAGS: "-I/usr/local/include -I/usr/local/openssl/include" LDFLAGS: -L/usr/local/lib ibmtpm_name: ibmtpm1637 + libusb_version: v1.0.26 freebsd_instance: matrix: - image_family: freebsd-13-1 + image_family: freebsd-13-2 install_script: + - IGNORE_OSVERSION=yes - pkg update -f - pkg upgrade -y - pkg install -y bash gmake coreutils libtool pkgconf autoconf autoconf-archive - pkg install -y automake openssl json-c cmocka uthash wget curl git util-linux + - pkg install -y libftdi1 - wget --quiet --show-progress --progress=dot:giga "https://downloads.sourceforge.net/project/ibmswtpm2/$ibmtpm_name.tar.gz" - shasum -a256 $ibmtpm_name.tar.gz | grep ^dd3a4c3f7724243bc9ebcd5c39bbf87b82c696d1c1241cb8e5883534f6e2e327 - mkdir -p $ibmtpm_name @@ -21,7 +24,13 @@ task: - gmake -j && cp tpm_server /usr/bin/ - cd - - rm -fr $ibmtpm_name $ibmtpm_name.tar.gz + - git clone --depth 1 -b $libusb_version https://github.com/libusb/libusb + - cd libusb && ./bootstrap.sh && ./configure && gmake -j install + - cd - && rm -fr libusb script: + # + # Due to a race condition that only occurs in the cirrus ci, "make distcheck" has been replaced by "make check". + # ./bootstrap && ./configure --enable-self-generated-certificate --enable-unit=yes --enable-integration=yes --with-crypto=ossl --disable-doxygen-doc --enable-tcti-swtpm=no --enable-tcti-libtpms=no --enable-tcti-mssim=yes --disable-dependency-tracking && - gmake -j distcheck || { cat /tmp/cirrus-ci-build/tpm2-tss-*/_build/sub/test-suite.log; exit 1; } + gmake -j check || { cat /tmp/cirrus-ci-build/tpm2-tss-*/_build/sub/test-suite.log; exit 1; } diff --git a/.readthedocs.yml b/.readthedocs.yml index 3a613f0..17ee241 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,6 +2,10 @@ # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 +build: + os: ubuntu-22.04 + tools: + python: "3" sphinx: builder: html configuration: sphinx/conf.py \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f82afc9..7291296 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,88 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) +## [4.1.3] - 2024-05-17 +### Fixed +- Fix name collisions during dlopen() on some linkers + +## [4.1.2] - 2024-05-14 +### Fixed +- configure.ac: Fix test of == to = to be POSIX comliant +- Remove use of which in favor of command -v + +## [4.1.1] - 2024-05-07 +### Fixed +- Fixed inclusion of .map and .def files in release tar balls + +## [4.1.0] - 2024-04-26 +### Security +- Fixed CVE-2024-29040 + +### Fixed +- fapi: Fix length check on FAPI auth callbacks +- mu: Correct error message for errors +- tss2-rc: fix unknown laer handler dropping bits. +- fapi: Fix deviation from CEL specification (template_value was used instead of template_data). +- fapi: Fix json syntax error in FAPI profiles which was ignored by json-c. +- build: fix build fail after make clean. +- mu: Fix unneeded size check in TPM2B unmarshaling. +- fapi: Fix missing parameter encryption. +- build: Fix failed build with --disable-vendor. +- fapi: Fix flush of persistent handles. +- fapi: Fix test provisioning with template with self generated certificate disabled. +- fapi: Fix error in Fapi_GetInfo it TPM supports SHA3 hash algs. +- fapi: Revert pcr extension for EV_NO_ACTION events. +- fapi: Fix strange error messages if nv, ext, or policy path does not exits. +- fapi: Fix segfault caused by wrong allocation of pcr policy. +- esys: Fix leak in Esys_EvictControl for persistent handles. +- tss2-tcti: tcti-libtpms: fix test failure on big-endian platform. +- esys: Add reference counting for Esys_TR_FromTPMPublic. +- esys: Fix HMAC error if session bind key has an auth value with a trailing 0. +- fapi: fix usage of self signed certificates in TPM. +- fapi: Usage of self signed certificates. +- fapi: A segfault after the error handling of non existing keys. +- fapi: Fix several leaks. +- fapi: Fix error handling for policy execution. +- fapi: Fix usage of persistent handles (should not be flushed) +- fapi: Fix test provisioning with template (skip test without self generated certificate). +- fapi: Fix pcr extension for EV_NO_ACTION +- test: Fix fapi-key-create-policy-signed-keyedhash with P_ECC384 profile +- tcti_spi_helper_transmit: ensure FIFO is accessed only after TPM reports commandReady bit is set +- fapi: Fix read large system eventlog (> UINT16_MAX). +- esys tests: Fix layer check for TPM2_RC_COMMAND_CODE (for /dev/tpmrm0) +- test: unit: tcti-libtpms: fix test failed at 32-bit platforms. +- fapi: Fix possible null pointer dereferencing in Fapi_List. +- sys: Fix size check in Tss2_Sys_GetCapability. +- esys: Fix leak in Esys_TR_FromTPMPublic. +- esys: fix unchecked return value in esys crypto. +- fapi: Fix wrong usage of local variable in provisioning. +- fapi: Fix memset 0 in ifapi_json_TPMS_POLICYNV_deserialize. +- fapi: Fix possible out of bound array access in IMA parser. +- tcti device: Fix possible unmarshalling from uninitialized variable. +- fapi: Fix error checking authorization of signing key. +- fapi: Fix cleanup of policy sessions. +- fapi: Eventlog H-CRTM events and different localities. +- fapi: Fix missing synchronization of quote and eventlog. +- faii: Fix invalid free in Fapi_Quote with empty eventlog. + +### Added +- tcti: LetsTrust-TPM2Go TCTI module spi-ltt2go. +- mbedtls: add sha512 hmac. +- fapi: Enable usage of external keys for Fapi_Encrypt. +- fapi: Support download of AMD certificates. +- tcti: Add USB TPM (FTDI MPSSE USB to SPI bridge) TCTI module. +- fapi: The recreation of primaries (except EK) in the owner hierarchy instead the endorsement hierarchy is fixed. +- rc: New TPM return codes added. +- fapi: Further Nuvoton certificates added. +- tpm_types/esys: Add support for Attestable TPM changes in latest TPM spec. +- tcti: Add '/dev/tcm0' to default conf +- fapi: New Nuvoton certificates added. +- esys: Fix leak in Esys_TR_FromTPMPublic. + +### Removed +- Testing on Ubuntu 18.04 as it's near EOL (May 2023). + + ## [4.0.1] - 2023-01-23 ### Fixed: - A buffer overflow in tss2-rc as CVE-2023-22745. @@ -343,7 +425,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) ### Removed - Removed libtss2-mu from "Requires" field of libtss2-esys.pc - Needs to be added explicitely now + Needs to be added explicitly now ### Fixed - All fixes from 2.2.1, 2.2.2 and 2.2.3 diff --git a/INSTALL.md b/INSTALL.md index 180d100..a0306ea 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -7,7 +7,7 @@ following sections describe them for the supported platforms. ## GNU/Linux: * GNU Autoconf -* GNU Autoconf Archive, version >= 2017.03.21 +* GNU Autoconf Archive, version >= 2019.01.06 * GNU Automake * GNU Libtool * C compiler @@ -18,6 +18,8 @@ following sections describe them for the supported platforms. * libcurl development libraries * Access Control List utility (acl) * JSON C Development library +* Package libusb-1.0-0-dev + The following are dependencies only required when building test suites. * Integration test suite (see ./configure option --enable-integration): @@ -54,30 +56,41 @@ $ sudo apt -y install \ libjson-c-dev \ libini-config-dev \ libcurl4-openssl-dev \ - libuuid-dev \ - libltdl-dev + uuid-dev \ + libltdl-dev \ + libusb-1.0-0-dev \ + libftdi-dev ``` Note: In some Ubuntu versions, the lcov and autoconf-archive packages are incompatible with each other. It is recommended to download autoconf-archive directly from upstream and copy `ax_code_coverage.m4` and `ax_prog_doxygen.m4` to the `m4/` subdirectory of your tpm2-tss directory. ### Fedora +libtool automake autoconf and autoconf-archive should be installed: +``` +$ sudo dnf install libtool automake autoconf autoconf-archive +``` + There is a package already, so the package build dependencies information can be used to make sure that the needed packages to compile from source are installed: ``` $ sudo dnf builddep tpm2-tss ``` +If you want to install a version from 4.0.0 and the default version of the release +is lower than this version you have to install libuuid-devel additionally: + +``` +$ sudo dnf install libuuid-devel +``` ## Windows -Windows dlls built using the Clang/LLVM "Platform Toolset" are currently -prototypes. We have only tested using Visual Studio 2017 with the Universal -C Runtime (UCRT) version 10.0.16299.0. Building the type marshaling library -(tss2-mu.dll) and the system API (tss2-sapi.dll) should be as simple as -loading the tpm2-tss solution (tpm2-tss.sln) with a compatible and properly -configured version of Visual Studio 2017 and pressing the 'build' button. +Windows dlls are built using the LLVM (clang-cl) toolset. We have only tested +using Visual Studio 2019, but Visual Studio 2022 should also be supported. +Building should be as simple as loading the tpm2-tss solution (tpm2-tss.sln) with +a compatible and properly configured version of Visual Studio 2019+ and pressing the 'build' button. ### References -Visual Studio 2017 with "Clang for Windows": https://blogs.msdn.microsoft.com/vcblog/2017/03/07/use-any-c-compiler-with-visual-studio/ +Visual Studio 2019+ with "Clang for Windows": https://learn.microsoft.com/en-us/cpp/build/clang-support-msbuild Universal CRT overview & setup instructions: https://docs.microsoft.com/en-us/cpp/porting/upgrade-your-code-to-the-universal-crt # Building From Source @@ -165,6 +178,12 @@ $ sudo udevadm control --reload-rules && sudo udevadm trigger If this doesn't work on your distro please consult your distro's documentation for UDEVADM(8). +Users who should have access to the TPM and the FAPI keystore should be +included in the tss group. +​``` + sudo usermod -aG tss + ``` + ## ldconfig It may be necessary to run ldconfig (as root) to update the run-time @@ -208,3 +227,40 @@ $ make doxygen-doc The generated documentation will appear here: * doxygen-doc/html HTML format (start with file doxygen-doc/html/index.html) * doxygen-doc/rtf/refman.rtf RTF format + +# Building for embedded + +The libraries SYS, ESYS, MU, RC, tctildr, tcti-spi-helper, tcti-i2c-helper +can also be build for embedded devices. The following is an example to build +for cortex-m4: +``` +./bootstrap +./configure \ + --disable-fapi \ + --disable-esys \ + --disable-policy \ + --disable-tcti-cmd \ + --disable-tcti-device \ + --disable-tcti-libtpms \ + --disable-tcti-mssim \ + --disable-tcti-pcap \ + --disable-tcti-spi-lt2go \ + --disable-tcti-spi-ftdi \ + --disable-tcti-swtpm \ + --disable-doxygen-doc \ + --enable-nodl \ + --host=arm-none-eabi \ + --prefix=/home/afuchs/tpm2-software/INSTALL.uC \ + CFLAGS='-mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mthumb' \ + LDFLAGS='--specs=nosys.specs' +make +``` + +## Test operating systems in the CI + +* ubuntu-20.04 +* fedora-32 +* opensuse-leap +* ubuntu-22.04 +* alpine-3.15 +* FreeBSD \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS deleted file mode 100644 index 84ea5c1..0000000 --- a/MAINTAINERS +++ /dev/null @@ -1,3 +0,0 @@ -Andreas Fuchs -Bill Roberts -Juergen Repp diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000..771b86f --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,5 @@ +|email|PGP Fingerprint| +| ------------- | ------------- | +| Andreas Fuchs | [D533275B0123D0A679F51FF48F4F9A45D7FFEE74](https://keys.openpgp.org/vks/v1/by-fingerprint/D533275B0123D0A679F51FF48F4F9A45D7FFEE74)| +| Bill Roberts | [5b482b8e3e19da7c978e1d016de2e9078e1f50c1](https://keys.openpgp.org/vks/v1/by-fingerprint/5B482B8E3E19DA7C978E1D016DE2E9078E1F50C1)| +| Juergen Repp | [7A8F470DA9C8B2CACED1DBAAF1B152D9441A2563](https://keys.openpgp.org/vks/v1/by-fingerprint/7A8F470DA9C8B2CACED1DBAAF1B152D9441A2563)| diff --git a/Makefile-fuzz.am b/Makefile-fuzz.am index d83d9d2..079508e 100644 --- a/Makefile-fuzz.am +++ b/Makefile-fuzz.am @@ -30,8 +30,7 @@ test_fuzz_libfuzz_utils_la_LDFLAGS = $(TESTS_LDFLAGS) test_fuzz_libfuzz_utils_la_LIBADD = $(TESTS_LIBADD) test_fuzz_libfuzz_utils_la_CFLAGS = $(AM_CFLAGS) $(FUZZ_CFLAGS) test_fuzz_libfuzz_utils_la_SOURCES = \ - test/integration/sys-context-util.c \ - test/integration/sys-test-options.c + test/integration/test-common.c test/integration/test-common.h TESTS_LDADD += $(libtss2_utils_fuzzing) FUZZLDADD = $(TESTS_LDADD) $(TESTS_LDFLAGS) $(FUZZ_LDFLAGS) diff --git a/Makefile-test.am b/Makefile-test.am index 6456558..1852897 100644 --- a/Makefile-test.am +++ b/Makefile-test.am @@ -8,19 +8,27 @@ TESTS_CFLAGS = $(AM_CFLAGS) $(CRYPTO_CFLAGS) -I$(srcdir)/include -I$(srcdir)/src -I$(srcdir)/test/data -Wno-unused-parameter -Wno-missing-field-initializers \ -DTOP_SOURCEDIR"=\"$(top_srcdir)\"" TESTS_LDADD = $(check_LTLIBRARIES) $(lib_LTLIBRARIES) \ - $(CRYPTO_LIBS) $(libutil) + $(CRYPTO_LIBS) $(libutil) $(libutilio) + +if ESYS +TESTS_CFLAGS += -DTEST_ESYS +endif +if FAPI +TESTS_CFLAGS += -DTEST_FAPI +endif check_LTLIBRARIES = # test harness configuration TEST_EXTENSIONS = .int .fint INT_LOG_COMPILER = $(srcdir)/script/int-log-compiler.sh FINT_LOG_COMPILER = $(srcdir)/script/fint-log-compiler.sh -INT_LOG_FLAGS = $(INTEGRATION_TCTI) $(INTEGRATION_ARGS) -FINT_LOG_FLAGS = $(INTEGRATION_TCTI) $(INTEGRATION_ARGS) +INT_LOG_FLAGS = $(INTEGRATION_TCTI) +FINT_LOG_FLAGS = $(INTEGRATION_TCTI) EXTRA_DIST += $(srcdir)/script/int-log-compiler.sh \ $(srcdir)/script/fint-log-compiler.sh \ $(srcdir)/script/int-log-compiler-common.sh \ $(srcdir)/script/ekca/create_ca.sh \ + $(srcdir)/script/ekca/init_ca.sh \ $(srcdir)/script/ekca/ek.cnf \ $(srcdir)/script/ekca/intermed-ca.cnf \ $(srcdir)/script/ekca/root-ca.cnf @@ -43,39 +51,6 @@ test_helper_tpm_cmd_tcti_dummy_LDFLAGS = $(TESTS_LDFLAGS) test_helper_tpm_cmd_tcti_dummy_LDADD = $(TESTS_LDADD) endif #UNIT -if ENABLE_INTEGRATION -check_PROGRAMS += test/helper/tpm_startup -test_helper_tpm_startup_CFLAGS = $(TESTS_CFLAGS) -I$(srcdir)/test/integration -test_helper_tpm_startup_LDFLAGS = $(TESTS_LDFLAGS) -test_helper_tpm_startup_LDADD = $(TESTS_LDADD) - -check_PROGRAMS += test/helper/tpm_transientempty -test_helper_tpm_transientempty_CFLAGS = $(TESTS_CFLAGS) -I$(srcdir)/test/integration -test_helper_tpm_transientempty_LDFLAGS = $(TESTS_LDFLAGS) -test_helper_tpm_transientempty_LDADD = $(TESTS_LDADD) - -check_PROGRAMS += test/helper/tpm_dumpstate -test_helper_tpm_dumpstate_CFLAGS = $(TESTS_CFLAGS) -I$(srcdir)/test/integration -test_helper_tpm_dumpstate_LDFLAGS = $(TESTS_LDFLAGS) -test_helper_tpm_dumpstate_LDADD = $(TESTS_LDADD) - -check_PROGRAMS += test/helper/tpm_getek -test_helper_tpm_getek_CFLAGS = $(TESTS_CFLAGS) -I$(srcdir)/test/integration -test_helper_tpm_getek_LDFLAGS = $(TESTS_LDFLAGS) -lcrypto -test_helper_tpm_getek_LDADD = $(TESTS_LDADD) - -check_PROGRAMS += test/helper/tpm_getek_ecc -test_helper_tpm_getek_ecc_CFLAGS = $(TESTS_CFLAGS) -I$(srcdir)/test/integration -test_helper_tpm_getek_ecc_LDFLAGS = $(TESTS_LDFLAGS) -lcrypto -test_helper_tpm_getek_ecc_LDADD = $(TESTS_LDADD) - - -check_PROGRAMS += test/helper/tpm_writeekcert -test_helper_tpm_writeekcert_CFLAGS = $(TESTS_CFLAGS) -I$(srcdir)/test/integration -test_helper_tpm_writeekcert_LDFLAGS = $(TESTS_LDFLAGS) -test_helper_tpm_writeekcert_LDADD = $(TESTS_LDADD) -endif #ENABLE_INTEGRATION - ### Rules to enerate binary test files for FAPI from b64 files. if FAPI @@ -92,7 +67,8 @@ FAPI_TEST_BINS = \ test/data/fapi/eventlog/sml-ima-sig-sha256-invalidated.bin \ test/data/fapi/eventlog/event-uefivar.bin \ test/data/fapi/eventlog/specid-vendordata.bin \ - test/data/fapi/eventlog/sml-ima-ng-sha1.bin + test/data/fapi/eventlog/sml-ima-ng-sha1.bin \ + test/data/fapi/eventlog/binary_measurements_hcrtm.bin CLEANFILES += $(FAPI_TEST_BINS) endif #FAPI @@ -155,6 +131,21 @@ endif if ENABLE_TCTI_SPI_HELPER TESTS_UNIT += test/unit/tcti-spi-helper endif +if ENABLE_TCTI_SPI_LTT2GO +TESTS_UNIT += test/unit/tcti-spi-ltt2go +endif +if ENABLE_TCTI_SPIDEV +TESTS_UNIT += test/unit/tcti-spidev +endif +if ENABLE_TCTI_SPI_FTDI +TESTS_UNIT += test/unit/tcti-spi-ftdi +endif +if ENABLE_TCTI_I2C_HELPER +TESTS_UNIT += test/unit/tcti-i2c-helper +endif +if ENABLE_TCTI_I2C_FTDI +TESTS_UNIT += test/unit/tcti-i2c-ftdi +endif if ESYS TESTS_UNIT += \ test/unit/esys-context-null \ @@ -181,7 +172,7 @@ TESTS_UNIT += \ test/unit/fapi-io \ test/unit/fapi-profiles \ test/unit/fapi-config \ - test/unit/fapi-get-intl-cert \ + test/unit/fapi-get-web-cert \ test/unit/fapi-eventlog \ test/unit/fapi-ima-eventlog \ test/unit/fapi-check-ima-log @@ -242,6 +233,7 @@ ESYS_TESTS_INTEGRATION_MANDATORY = \ test/integration/esys-certify-creation.int \ test/integration/esys-certifyX509.int \ test/integration/esys-certify.int \ + test/integration/esys-check-auth-with-trailing-zero.int \ test/integration/esys-clear-control.int \ test/integration/esys-clockset.int \ test/integration/esys-clockset-audit.int \ @@ -367,6 +359,8 @@ FAPI_TESTS_INTEGRATION = \ test/integration/fapi-get-esys-blobs.fint \ test/integration/fapi-get-random.fint \ test/integration/fapi-platform-certificates.fint \ + test/integration/fapi-import-ossl-key-ecc.fint \ + test/integration/fapi-import-ossl-key-rsa.fint \ test/integration/fapi-key-create-sign.fint \ test/integration/fapi-key-create-he-sign.fint \ test/integration/fapi-key-create-primary-sign.fint \ @@ -446,7 +440,8 @@ FAPI_TESTS_INTEGRATION += \ test/integration/fapi-quote-destructive-eventlog.fint \ test/integration/fapi-quote-destructive-eventlog-pc-client.fint \ test/integration/fapi-provisioning-with-template.fint \ - test/integration/fapi-provisioning-with-template-rsa.fint + test/integration/fapi-provisioning-with-template-rsa.fint \ + test/integration/fapi-provisioning-cert-error.fint endif #!TESTDEVICE @@ -460,18 +455,20 @@ CLEANFILES += \ test/integration/*.crt \ test/integration/*.crl \ test/integration/*.fint_state* \ + test/integration/*.fint.* \ test/integration/*.int_state* \ test/integration/*.log \ test/integration/*.fint_ek* \ test/integration/*.fint_*-ca.pem \ test/tpmclient/*.int_state* \ test/tpmclient/*.log \ - test/unit/*.log + test/unit/*.log \ + NVChip if UNIT if ENABLE_TCTI_DEVICE test_unit_tcti_device_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_device_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_tcti_device_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) $(libutilio) test_unit_tcti_device_LDFLAGS = -Wl,--wrap=read -Wl,--wrap=write -Wl,--wrap=poll \ -Wl,--wrap=open test_unit_tcti_device_SOURCES = test/unit/tcti-device.c \ @@ -481,7 +478,7 @@ endif if ENABLE_TCTI_MSSIM test_unit_tcti_mssim_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_mssim_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_tcti_mssim_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) $(libutilio) test_unit_tcti_mssim_LDFLAGS = -Wl,--wrap=connect -Wl,--wrap=read -Wl,--wrap=write -Wl,--wrap=poll test_unit_tcti_mssim_SOURCES = test/unit/tcti-mssim.c \ src/tss2-tcti/tcti-common.c \ @@ -490,7 +487,7 @@ endif if ENABLE_TCTI_SWTPM test_unit_tcti_swtpm_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_swtpm_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_tcti_swtpm_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) $(libutilio) test_unit_tcti_swtpm_LDFLAGS = -Wl,--wrap=connect,--wrap=read,--wrap=select,--wrap=write test_unit_tcti_swtpm_SOURCES = test/unit/tcti-swtpm.c \ src/tss2-tcti/tcti-common.c \ @@ -510,7 +507,7 @@ endif if ENABLE_TCTI_PCAP test_unit_tcti_pcap_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_tcti_pcap_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_tcti_pcap_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) $(libutilio) test_unit_tcti_pcap_LDFLAGS = -Wl,--wrap=getenv -Wl,--wrap=rand -Wl,--wrap=clock_gettime \ -Wl,--wrap=open -Wl,--wrap=read -Wl,--wrap=write -Wl,--wrap=close \ -Wl,--wrap=__clock_gettime64 @@ -534,6 +531,82 @@ test_unit_tcti_spi_helper_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) test_unit_tcti_spi_helper_SOURCES = test/unit/tcti-spi-helper.c endif +if ENABLE_TCTI_SPI_LTT2GO +test_unit_tcti_spi_ltt2go_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_tcti_spi_ltt2go_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spi_ltt2go_LDFLAGS = -Wl,--wrap=libusb_bulk_transfer \ + -Wl,--wrap=libusb_claim_interface \ + -Wl,--wrap=libusb_close \ + -Wl,--wrap=libusb_control_transfer \ + -Wl,--wrap=libusb_dev_mem_alloc \ + -Wl,--wrap=libusb_dev_mem_free \ + -Wl,--wrap=libusb_exit \ + -Wl,--wrap=libusb_free_config_descriptor \ + -Wl,--wrap=libusb_get_config_descriptor \ + -Wl,--wrap=libusb_get_device \ + -Wl,--wrap=libusb_init \ + -Wl,--wrap=libusb_open_device_with_vid_pid \ + -Wl,--wrap=libusb_release_interface \ + -Wl,--wrap=libusb_set_auto_detach_kernel_driver \ + -Wl,--wrap=libusb_strerror \ + -Wl,--wrap=select \ + -Wl,--wrap=gettimeofday +test_unit_tcti_spi_ltt2go_SOURCES = test/unit/tcti-spi-ltt2go.c \ + src/tss2-tcti/tcti-spi-ltt2go.c +endif + +if ENABLE_TCTI_SPIDEV +test_unit_tcti_spidev_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_tcti_spidev_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spidev_LDFLAGS = -Wl,--wrap=open \ + -Wl,--wrap=close \ + -Wl,--wrap=ioctl \ + -Wl,--wrap=select \ + -Wl,--wrap=gettimeofday +test_unit_tcti_spidev_SOURCES = test/unit/tcti-spidev.c \ + src/tss2-tcti/tcti-spidev.c +endif + +if ENABLE_TCTI_SPI_FTDI +test_unit_tcti_spi_ftdi_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_tcti_spi_ftdi_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_spi_helper) +test_unit_tcti_spi_ftdi_LDFLAGS = -Wl,--wrap=Close \ + -Wl,--wrap=MPSSE \ + -Wl,--wrap=PinHigh \ + -Wl,--wrap=PinLow \ + -Wl,--wrap=Start \ + -Wl,--wrap=Stop \ + -Wl,--wrap=Transfer \ + -Wl,--wrap=select \ + -Wl,--wrap=gettimeofday +test_unit_tcti_spi_ftdi_SOURCES = test/unit/tcti-spi-ftdi.c \ + src/tss2-tcti/tcti-spi-ftdi.c +endif + +if ENABLE_TCTI_I2C_HELPER +test_unit_tcti_i2c_helper_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_tcti_i2c_helper_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_i2c_helper) +test_unit_tcti_i2c_helper_SOURCES = test/unit/tcti-i2c-helper.c +endif + +if ENABLE_TCTI_I2C_FTDI +test_unit_tcti_i2c_ftdi_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_tcti_i2c_ftdi_LDADD = $(CMOCKA_LIBS) $(libtss2_tcti_i2c_helper) +test_unit_tcti_i2c_ftdi_LDFLAGS = -Wl,--wrap=MPSSE \ + -Wl,--wrap=Start \ + -Wl,--wrap=Stop \ + -Wl,--wrap=Close \ + -Wl,--wrap=Read \ + -Wl,--wrap=Write \ + -Wl,--wrap=GetAck \ + -Wl,--wrap=SendAcks \ + -Wl,--wrap=SendNacks \ + -Wl,--wrap=select \ + -Wl,--wrap=gettimeofday +test_unit_tcti_i2c_ftdi_SOURCES = test/unit/tcti-i2c-ftdi.c \ + src/tss2-tcti/tcti-i2c-ftdi.c +endif + test_unit_tctildr_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) test_unit_tctildr_LDADD = $(CMOCKA_LIBS) $(libutil) test_unit_tctildr_LDFLAGS = -Wl,--wrap=calloc,--wrap=free \ @@ -576,7 +649,7 @@ test_unit_tctildr_getinfo_SOURCES = test/unit/tctildr-getinfo.c \ src/tss2-tcti/tctildr.c test_unit_io_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_io_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) +test_unit_io_LDADD = $(CMOCKA_LIBS) $(libtss2_mu) $(libutil) $(libutilio) test_unit_io_LDFLAGS = -Wl,--wrap=connect,--wrap=read,--wrap=socket,--wrap=write test_unit_key_value_parse_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) @@ -733,8 +806,6 @@ test_unit_esys_crypto_LDFLAGS = $(TESTS_LDFLAGS) $(TSS2_ESYS_LDFLAGS_CRYPTO) test_unit_esys_crypto_SOURCES = test/unit/esys-crypto.c \ src/tss2-esys/esys_context.c \ src/tss2-esys/esys_iutil.c \ - src/tss2-tcti/tctildr.c \ - src/tss2-tcti/tctildr-dl.c \ src/tss2-esys/esys_crypto.c \ $(TSS2_ESYS_SRC_CRYPTO) @@ -863,13 +934,13 @@ test_unit_fapi_config_SOURCES = test/unit/fapi-config.c \ src/tss2-fapi/ifapi_keystore.c \ src/tss2-fapi/ifapi_io.c -test_unit_fapi_get_intl_cert_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) -test_unit_fapi_get_intl_cert_LDADD = $(CMOCKA_LIBS) $(TESTS_LDADD) -test_unit_fapi_get_intl_cert_LDFLAGS = $(TESTS_LDFLAGS) $(JSONC_LIBS) $(CURL_LIBS) $(UUID_LIBS) \ +test_unit_fapi_get_web_cert_CFLAGS = $(CMOCKA_CFLAGS) $(TESTS_CFLAGS) +test_unit_fapi_get_web_cert_LDADD = $(CMOCKA_LIBS) $(TESTS_LDADD) +test_unit_fapi_get_web_cert_LDFLAGS = $(TESTS_LDFLAGS) $(JSONC_LIBS) $(CURL_LIBS) $(UUID_LIBS) \ -Wl,--wrap=ifapi_get_curl_buffer \ -Wl,--wrap=EVP_DigestUpdate -test_unit_fapi_get_intl_cert_SOURCES = test/unit/fapi-get-intl-cert.c \ - src/tss2-fapi/ifapi_get_intl_cert.c \ +test_unit_fapi_get_web_cert_SOURCES = test/unit/fapi-get-web-cert.c \ + src/tss2-fapi/ifapi_get_web_cert.c \ src/tss2-fapi/ifapi_json_deserialize.c \ src/tss2-fapi/ifapi_json_serialize.c \ src/tss2-fapi/ifapi_ima_eventlog.c \ @@ -1015,11 +1086,10 @@ test_tpmclient_tpmclient_int_SOURCES = \ test_integration_libtest_utils_la_CFLAGS = $(AM_CFLAGS) $(TESTS_CFLAGS) test_integration_libtest_utils_la_SOURCES = \ - test/integration/sys-context-util.c test/integration/context-util.h \ test/integration/sys-util.c test/integration/sys-util.h \ test/integration/sys-session-util.c test/integration/session-util.h \ - test/integration/sys-test-options.c test/integration/test-options.h \ test/integration/sys-entity-util.c test/integration/test.h \ + test/integration/test-common.c test/integration/test-common.h \ src/util/log.c test_integration_sys_asymmetric_encrypt_decrypt_int_CFLAGS = $(AM_CFLAGS) $(TESTS_CFLAGS) @@ -1196,6 +1266,13 @@ test_integration_esys_change_eps_int_SOURCES = \ test/integration/esys-change-eps.int.c \ test/integration/main-esys.c test/integration/test-esys.h +test_integration_esys_check_auth_with_trailing_zero_int_CFLAGS = $(TESTS_CFLAGS) +test_integration_esys_check_auth_with_trailing_zero_int_LDADD = $(TESTS_LDADD) +test_integration_esys_check_auth_with_trailing_zero_int_LDFLAGS = $(TESTS_LDFLAGS) +test_integration_esys_check_auth_with_trailing_zero_int_SOURCES = \ + test/integration/esys-check-auth-with-trailing-zero.int.c \ + test/integration/main-esys.c test/integration/test-esys.h + test_integration_esys_clear_int_CFLAGS = $(TESTS_CFLAGS) test_integration_esys_clear_int_LDADD = $(TESTS_LDADD) test_integration_esys_clear_int_LDFLAGS = $(TESTS_LDFLAGS) @@ -1924,7 +2001,7 @@ test_integration_sys_policy_authorizeNV_int_SOURCES = test/integration/main-sys. if FAPI test_integration_dlopen_fapi_get_random_fint_CFLAGS = $(TESTS_CFLAGS) \ - -DENABLE_WARN=1 + -DENABLE_WARN=1 -DDLOPEN=1 test_integration_dlopen_fapi_get_random_fint_LDADD = $(TESTS_LDADD) $(LIBADD_DL) test_integration_dlopen_fapi_get_random_fint_LDFLAGS = $(TESTS_LDFLAGS) test_integration_dlopen_fapi_get_random_fint_SOURCES = \ @@ -2356,6 +2433,22 @@ test_integration_fapi_duplicate_fint_SOURCES = \ test/integration/fapi-duplicate.int.c \ test/integration/main-fapi.c test/integration/test-fapi.h +test_integration_fapi_import_ossl_key_ecc_fint_CFLAGS = $(TESTS_CFLAGS) \ + -DFAPI_PROFILE=\"P_ECC\" +test_integration_fapi_import_ossl_key_ecc_fint_LDADD = $(TESTS_LDADD) +test_integration_fapi_import_ossl_key_ecc_fint_LDFLAGS = $(TESTS_LDFLAGS) +test_integration_fapi_import_ossl_key_ecc_fint_SOURCES = \ + test/integration/fapi-import-ossl-key.int.c \ + test/integration/main-fapi.c test/integration/test-fapi.h + +test_integration_fapi_import_ossl_key_rsa_fint_CFLAGS = $(TESTS_CFLAGS) \ + -DFAPI_PROFILE=\"P_RSA\" +test_integration_fapi_import_ossl_key_rsa_fint_LDADD = $(TESTS_LDADD) +test_integration_fapi_import_ossl_key_rsa_fint_LDFLAGS = $(TESTS_LDFLAGS) +test_integration_fapi_import_ossl_key_rsa_fint_SOURCES = \ + test/integration/fapi-import-ossl-key.int.c \ + test/integration/main-fapi.c test/integration/test-fapi.h + test_integration_fapi_pcr_test_fint_CFLAGS = $(TESTS_CFLAGS) test_integration_fapi_pcr_test_fint_LDADD = $(TESTS_LDADD) test_integration_fapi_pcr_test_fint_LDFLAGS = $(TESTS_LDFLAGS) @@ -2462,6 +2555,14 @@ test_integration_fapi_provisioning_error_fint_SOURCES = \ test/integration/fapi-provisioning-error.int.c \ test/integration/main-fapi.c test/integration/test-fapi.h +test_integration_fapi_provisioning_cert_error_fint_CFLAGS = $(TESTS_CFLAGS) \ + -DSELF_SIGNED_CERTIFICATE +test_integration_fapi_provisioning_cert_error_fint_LDADD = $(TESTS_LDADD) +test_integration_fapi_provisioning_cert_error_fint_LDFLAGS = $(TESTS_LDFLAGS) +test_integration_fapi_provisioning_cert_error_fint_SOURCES = \ + test/integration/fapi-provisioning-cert-error.int.c \ + test/integration/main-fapi.c test/integration/test-fapi.h + test_integration_fapi_quote_destructive_fint_CFLAGS = $(TESTS_CFLAGS) test_integration_fapi_quote_destructive_fint_LDADD = $(TESTS_LDADD) test_integration_fapi_quote_destructive_fint_LDFLAGS = $(TESTS_LDFLAGS) diff --git a/Makefile.am b/Makefile.am index 2c81cfa..f03d15c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,9 +55,16 @@ GITIGNOREFILES = "" if AUTOCONF_CODE_COVERAGE_2019_01_06 include $(top_srcdir)/aminclude_static.am clean-local: code-coverage-clean + -rm -r -f $(top_builddir)/ca distclean-local: code-coverage-dist-clean + -rm -r -f $(top_builddir)/ca else @CODE_COVERAGE_RULES@ +clean-local: + -rm -r -f $(top_builddir)/ca +distclean-local: + -rm -r -f $(top_builddir)/ca + endif GITIGNOREFILES += $(TSS_GITIGNOREFILES) CODE_COVERAGE_DIRECTORY = $(top_builddir)/src $(top_builddir)/test @@ -205,7 +212,7 @@ EXTRA_DIST += \ CONTRIBUTING.md \ INSTALL.md \ LICENSE \ - MAINTAINERS \ + MAINTAINERS.md \ README.md \ RELEASE.md \ VERSION @@ -249,6 +256,12 @@ libutil = libutil.la noinst_LTLIBRARIES += $(libutil) libutil_la_SOURCES = $(UTIL_SRC) +if ENABLE_UTIL_IO +libutilio = libutil-io.la +noinst_LTLIBRARIES += $(libutilio) +libutil_io_la_SOURCES = $(UTIL_IO_SRC) +endif + ### TCG TSS Marshaling/Unmarshaling spec library ### libtss2_mu = src/tss2-mu/libtss2-mu.la tss2_HEADERS += $(srcdir)/include/tss2/tss2_mu.h @@ -301,7 +314,7 @@ pkgconfig_DATA += lib/tss2-tcti-device.pc if HAVE_LD_VERSION_SCRIPT src_tss2_tcti_libtss2_tcti_device_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-device.map endif # HAVE_LD_VERSION_SCRIPT -src_tss2_tcti_libtss2_tcti_device_la_LIBADD = $(libtss2_mu) $(libutil) +src_tss2_tcti_libtss2_tcti_device_la_LIBADD = $(libtss2_mu) $(libutil) $(libutilio) src_tss2_tcti_libtss2_tcti_device_la_SOURCES = \ src/tss2-tcti/tcti-common.c \ src/tss2-tcti/tcti-device.c @@ -318,7 +331,7 @@ pkgconfig_DATA += lib/tss2-tcti-swtpm.pc if HAVE_LD_VERSION_SCRIPT src_tss2_tcti_libtss2_tcti_swtpm_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-swtpm.map endif # HAVE_LD_VERSION_SCRIPT -src_tss2_tcti_libtss2_tcti_swtpm_la_LIBADD = $(libtss2_mu) $(libutil) +src_tss2_tcti_libtss2_tcti_swtpm_la_LIBADD = $(libtss2_mu) $(libutil) $(libutilio) src_tss2_tcti_libtss2_tcti_swtpm_la_SOURCES = \ src/tss2-tcti/tcti-common.c \ src/tss2-tcti/tcti-swtpm.c \ @@ -336,7 +349,7 @@ pkgconfig_DATA += lib/tss2-tcti-mssim.pc if HAVE_LD_VERSION_SCRIPT src_tss2_tcti_libtss2_tcti_mssim_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-mssim.map endif # HAVE_LD_VERSION_SCRIPT -src_tss2_tcti_libtss2_tcti_mssim_la_LIBADD = $(libtss2_mu) $(libutil) +src_tss2_tcti_libtss2_tcti_mssim_la_LIBADD = $(libtss2_mu) $(libutil) $(libutilio) src_tss2_tcti_libtss2_tcti_mssim_la_SOURCES = \ src/tss2-tcti/tcti-common.c \ src/tss2-tcti/tcti-mssim.c @@ -355,7 +368,7 @@ pkgconfig_DATA += lib/tss2-tcti-pcap.pc if HAVE_LD_VERSION_SCRIPT src_tss2_tcti_libtss2_tcti_pcap_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-pcap.map endif # HAVE_LD_VERSION_SCRIPT -src_tss2_tcti_libtss2_tcti_pcap_la_LIBADD = $(libtss2_tctildr) $(libtss2_mu) $(libutil) +src_tss2_tcti_libtss2_tcti_pcap_la_LIBADD = $(libtss2_tctildr) $(libtss2_mu) $(libutil) $(libutilio) src_tss2_tcti_libtss2_tcti_pcap_la_SOURCES = \ src/tss2-tcti/tcti-common.c \ src/tss2-tcti/tcti-pcap-builder.c \ @@ -408,8 +421,6 @@ libtss2_tcti_spi_helper = src/tss2-tcti/libtss2-tcti-spi-helper.la tss2_HEADERS += $(srcdir)/include/tss2/tss2_tcti_spi_helper.h lib_LTLIBRARIES += $(libtss2_tcti_spi_helper) pkgconfig_DATA += lib/tss2-tcti-spi-helper.pc -EXTRA_DIST += lib/tss2-tcti-spi-helper.map \ - lib/tss2-tcti-spi-helper.def if HAVE_LD_VERSION_SCRIPT if !UNIT @@ -422,6 +433,120 @@ src_tss2_tcti_libtss2_tcti_spi_helper_la_SOURCES = \ src/tss2-tcti/tcti-spi-helper.c \ src/tss2-tcti/tcti-spi-helper.h endif # ENABLE_TCTI_SPI_HELPER +EXTRA_DIST += lib/tss2-tcti-spi-helper.map \ + lib/tss2-tcti-spi-helper.def + +# tcti library for letstrust-tpm2go usb tpm +if ENABLE_TCTI_SPI_LTT2GO +libtss2_tcti_spi_ltt2go = src/tss2-tcti/libtss2-tcti-spi-ltt2go.la +tss2_HEADERS += $(srcdir)/include/tss2/tss2_tcti_spi_ltt2go.h +lib_LTLIBRARIES += $(libtss2_tcti_spi_ltt2go) +pkgconfig_DATA += lib/tss2-tcti-spi-ltt2go.pc + +src_tss2_tcti_libtss2_tcti_spi_ltt2go_la_LDFLAGS = -lusb-1.0 + +if HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_spi_ltt2go_la_LDFLAGS += -Wl,--version-script=$(srcdir)/lib/tss2-tcti-spi-ltt2go.map +endif # HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_spi_ltt2go_la_LIBADD = $(libutil) $(libtss2_mu) $(libtss2_tcti_spi_helper) +src_tss2_tcti_libtss2_tcti_spi_ltt2go_la_SOURCES = \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-spi-ltt2go.c \ + src/tss2-tcti/tcti-spi-ltt2go.h +endif # ENABLE_TCTI_SPI_LTT2GO +EXTRA_DIST += lib/tss2-tcti-spi-ltt2go.map \ + lib/tss2-tcti-spi-ltt2go.def + +# tcti library for letstrust-tpm2go usb tpm +if ENABLE_TCTI_SPIDEV +libtss2_tcti_spidev = src/tss2-tcti/libtss2-tcti-spidev.la +tss2_HEADERS += $(srcdir)/include/tss2/tss2_tcti_spidev.h +lib_LTLIBRARIES += $(libtss2_tcti_spidev) +pkgconfig_DATA += lib/tss2-tcti-spidev.pc + +src_tss2_tcti_libtss2_tcti_spidev_la_LDFLAGS = + +if HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_spidev_la_LDFLAGS += -Wl,--version-script=$(srcdir)/lib/tss2-tcti-spidev.map +endif # HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_spidev_la_LIBADD = $(libutil) $(libtss2_mu) $(libtss2_tcti_spi_helper) +src_tss2_tcti_libtss2_tcti_spidev_la_SOURCES = \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-spidev.c +endif # ENABLE_TCTI_SPIDEV +EXTRA_DIST += lib/tss2-tcti-spidev.map \ + lib/tss2-tcti-spidev.def + +# tcti library for ftdi connected tpm +if ENABLE_TCTI_SPI_FTDI +libtss2_tcti_spi_ftdi = src/tss2-tcti/libtss2-tcti-spi-ftdi.la +tss2_HEADERS += $(srcdir)/include/tss2/tss2_tcti_spi_ftdi.h +lib_LTLIBRARIES += $(libtss2_tcti_spi_ftdi) +pkgconfig_DATA += lib/tss2-tcti-spi-ftdi.pc + +src_tss2_tcti_libtss2_tcti_spi_ftdi_la_CFLAGS = $(AM_CFLAGS) $(LIBFTDI_CFLAGS) -Wno-deprecated-declarations +src_tss2_tcti_libtss2_tcti_spi_ftdi_la_LDFLAGS = $(LIBFTDI_LIBS) +if HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_spi_ftdi_la_LDFLAGS += -Wl,--version-script=$(srcdir)/lib/tss2-tcti-spi-ftdi.map +endif # HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_spi_ftdi_la_LIBADD = $(libutil) $(libtss2_mu) $(libtss2_tcti_spi_helper) +src_tss2_tcti_libtss2_tcti_spi_ftdi_la_SOURCES = \ + src/tss2-tcti/mpsse/support.c \ + src/tss2-tcti/mpsse/support.h \ + src/tss2-tcti/mpsse/mpsse.c \ + src/tss2-tcti/mpsse/mpsse.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-spi-ftdi.c \ + src/tss2-tcti/tcti-spi-ftdi.h +endif # ENABLE_TCTI_SPI_FTDI +EXTRA_DIST += lib/tss2-tcti-spi-ftdi.map \ + lib/tss2-tcti-spi-ftdi.def + +# tcti library for i2c connected tpms +if ENABLE_TCTI_I2C_HELPER +libtss2_tcti_i2c_helper = src/tss2-tcti/libtss2-tcti-i2c-helper.la +tss2_HEADERS += $(srcdir)/include/tss2/tss2_tcti_i2c_helper.h +lib_LTLIBRARIES += $(libtss2_tcti_i2c_helper) +pkgconfig_DATA += lib/tss2-tcti-i2c-helper.pc + +if HAVE_LD_VERSION_SCRIPT +if !UNIT +src_tss2_tcti_libtss2_tcti_i2c_helper_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-tcti-i2c-helper.map +endif # UNIT +endif # HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_i2c_helper_la_LIBADD = $(libutil) $(libtss2_mu) +src_tss2_tcti_libtss2_tcti_i2c_helper_la_SOURCES = \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-i2c-helper.c \ + src/tss2-tcti/tcti-i2c-helper.h +endif # ENABLE_TCTI_I2C_HELPER +EXTRA_DIST += lib/tss2-tcti-i2c-helper.map \ + lib/tss2-tcti-i2c-helper.def + +# tcti library for ftdi connected tpm +if ENABLE_TCTI_I2C_FTDI +libtss2_tcti_i2c_ftdi = src/tss2-tcti/libtss2-tcti-i2c-ftdi.la +tss2_HEADERS += $(srcdir)/include/tss2/tss2_tcti_i2c_ftdi.h +lib_LTLIBRARIES += $(libtss2_tcti_i2c_ftdi) +pkgconfig_DATA += lib/tss2-tcti-i2c-ftdi.pc + +src_tss2_tcti_libtss2_tcti_i2c_ftdi_la_CFLAGS = $(AM_CFLAGS) $(LIBFTDI_CFLAGS) -Wno-deprecated-declarations +src_tss2_tcti_libtss2_tcti_i2c_ftdi_la_LDFLAGS = $(LIBFTDI_LIBS) +if HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_i2c_ftdi_la_LDFLAGS += -Wl,--version-script=$(srcdir)/lib/tss2-tcti-i2c-ftdi.map +endif # HAVE_LD_VERSION_SCRIPT +src_tss2_tcti_libtss2_tcti_i2c_ftdi_la_LIBADD = $(libutil) $(libtss2_mu) $(libtss2_tcti_i2c_helper) +src_tss2_tcti_libtss2_tcti_i2c_ftdi_la_SOURCES = \ + src/tss2-tcti/mpsse/support.c \ + src/tss2-tcti/mpsse/support.h \ + src/tss2-tcti/mpsse/mpsse.c \ + src/tss2-tcti/mpsse/mpsse.h \ + src/tss2-tcti/tcti-common.c \ + src/tss2-tcti/tcti-i2c-ftdi.c \ + src/tss2-tcti/tcti-i2c-ftdi.h +endif # ENABLE_TCTI_I2C_FTDI +EXTRA_DIST += lib/tss2-tcti-i2c-ftdi.map \ + lib/tss2-tcti-i2c-ftdi.def ### TCG TSS SYS spec library ### libtss2_sys = src/tss2-sys/libtss2-sys.la @@ -483,10 +608,10 @@ else src_tss2_esys_libtss2_esys_la_LIBADD += $(LIBADD_DL) src_tss2_esys_libtss2_esys_la_SOURCES += src/tss2-tcti/tctildr-dl.c src/tss2-tcti/tctildr-dl.h endif +endif # ESYS EXTRA_DIST += lib/tss2-esys.map \ lib/tss2-esys.def \ src/tss2-esys/tss2-esys.vcxproj -endif #ESYS ### TCG TSS error decoding spec library ### libtss2_rc = src/tss2-rc/libtss2-rc.la @@ -508,8 +633,9 @@ lib_LTLIBRARIES += $(libtss2_policy) pkgconfig_DATA += lib/tss2-policy.pc src_tss2_policy_libtss2_policy_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/tss2-policy -I$(srcdir)/src/tss2-fapi \ - $(JSONC_CFLAGS) -src_tss2_policy_libtss2_policy_la_LIBADD = $(libtss2_esys) $(libtss2_mu) $(libutil) $(JSONC_LIBS) $(UUID_LIBS) + $(JSONC_CFLAGS) $(UUID_CFLAGS) $(CRYPTO_CFLAGS) +src_tss2_policy_libtss2_policy_la_LIBADD = $(libtss2_esys) $(libtss2_mu) $(libutil) $(JSONC_LIBS) $(UUID_LIBS) \ + $(CRYPTO_LIBS) if HAVE_LD_VERSION_SCRIPT src_tss2_policy_libtss2_policy_la_LDFLAGS = -Wl,--version-script=$(srcdir)/lib/tss2-policy.map @@ -535,9 +661,8 @@ src_tss2_policy_libtss2_policy_la_SOURCES = $(TSS2_POLICY_SRC) \ src/tss2-fapi/ifapi_policy_json_serialize.c \ src/tss2-fapi/ifapi_keystore.c \ src/tss2-fapi/ifapi_policy_store.c - +endif # POLICY EXTRA_DIST += lib/tss2-policy.map lib/tss2-policy.def -endif ### TCG TSS FAPI spec library ### if FAPI @@ -563,10 +688,14 @@ fapi-config.json: dist/fapi-config.json.in -e 's|[@]sysmeasurements@|$(sysmeasurements)|g' \ < "$<" > "$@" +if SYSD_SYSUSERS sysusers_DATA = dist/sysusers.d/tpm2-tss.conf -tmpfiles_DATA = tpm2-tss-fapi.conf +endif +if SYSD_TMPFILES +tmpfiles_DATA = tpm2-tss-fapi.conf CLEANFILES += tpm2-tss-fapi.conf +endif # We have to do this ourselves, in order to get absolute paths tpm2-tss-fapi.conf: dist/tmpfiles.d/tpm2-tss-fapi.conf.in @@ -577,7 +706,9 @@ tpm2-tss-fapi.conf: dist/tmpfiles.d/tpm2-tss-fapi.conf.in fapiprofilesdir = @sysconfdir@/tpm2-tss/fapi-profiles fapiprofiles_DATA = dist/fapi-profiles/P_RSA2048SHA256.json \ - dist/fapi-profiles/P_ECCP256SHA256.json + dist/fapi-profiles/P_ECCP256SHA256.json \ + dist/fapi-profiles/P_RSA3072SHA384.json \ + dist/fapi-profiles/P_ECCP384SHA384.json libtss2_fapi = src/tss2-fapi/libtss2-fapi.la tss2_HEADERS += $(srcdir)/include/tss2/tss2_fapi.h @@ -587,6 +718,8 @@ EXTRA_DIST += \ dist/fapi-config.json.in \ dist/fapi-profiles/P_RSA2048SHA256.json \ dist/fapi-profiles/P_ECCP256SHA256.json \ + dist/fapi-profiles/P_RSA3072SHA384.json \ + dist/fapi-profiles/P_ECCP384SHA384.json \ dist/sysusers.d/tpm2-tss.conf \ dist/tmpfiles.d/tpm2-tss-fapi.conf.in \ doc/fapi-config.md \ @@ -664,13 +797,15 @@ EXTRA_DIST += \ test/data/fapi/eventlog/sml-ima-ng-sha1-invalidated.b64 \ test/data/fapi/eventlog/sml-ima-ng-sha1-invalidated.b64 \ test/data/fapi/eventlog/sml-ima-sig-sha256-invalidated.b64 \ - test/data/fapi/eventlog/sml-ima-sha1-invalidated.b64 + test/data/fapi/eventlog/sml-ima-sha1-invalidated.b64 \ + test/data/fapi/eventlog/binary_measurements_hcrtm.b64 src_tss2_fapi_libtss2_fapi_la_LIBADD = $(libtss2_sys) $(libtss2_mu) $(libtss2_esys) \ $(libutil) $(libtss2_tctildr) src_tss2_fapi_libtss2_fapi_la_SOURCES = $(TSS2_FAPI_SRC) -src_tss2_fapi_libtss2_fapi_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/tss2-fapi $(CRYPTO_CFLAGS) $(JSONC_CFLAGS) $(CURL_CFLAGS) +src_tss2_fapi_libtss2_fapi_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/tss2-fapi $(CRYPTO_CFLAGS) $(JSONC_CFLAGS) \ + $(UUID_CFLAGS) src_tss2_fapi_libtss2_fapi_la_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LIBS) $(JSONC_LIBS) $(CURL_LIBS) $(UUID_LIBS) if HAVE_LD_VERSION_SCRIPT src_tss2_fapi_libtss2_fapi_la_LDFLAGS += -Wl,--version-script=$(srcdir)/lib/tss2-fapi.map @@ -772,7 +907,7 @@ define make_fapi_dirs endef define set_fapi_permissions - if test -z "${DESTDIR}"; then \ e + if test -z "${DESTDIR}"; then \ ($(call set_tss_permissions,$(DESTDIR)$(runstatedir)/tpm2-tss)) && \ ($(call set_tss_permissions,$(DESTDIR)$(localstatedir)/lib/tpm2-tss)) \ fi @@ -805,6 +940,12 @@ man7_MANS = \ man/man7/tss2-tcti-swtpm.7 \ man/man7/tss2-tcti-mssim.7 \ man/man7/tss2-tcti-cmd.7 \ + man/man7/tss2-tcti-spidev.7 \ + man/man7/tss2-tcti-spi-helper.7 \ + man/man7/tss2-tcti-spi-ltt2go.7 \ + man/man7/tss2-tcti-spi-ftdi.7 \ + man/man7/tss2-tcti-i2c-helper.7 \ + man/man7/tss2-tcti-i2c-ftdi.7 \ man/man7/tss2-tctildr.7 if FAPI @@ -864,6 +1005,15 @@ uninstall-local: [ -L Tss2_TctiLdr_Initialize_Ex.3 ] && \ rm -f Tss2_TctiLdr_Initialize_Ex.3 || true +prepare-check: +if INIT_CA + $(top_srcdir)/script/ekca/init_ca.sh $(top_builddir) + @echo "Build CI in:" 1>&2 + @echo $(top_builddir) 1>&2 +endif + +check: prepare-check + EXTRA_DIST += \ doc/doxygen.dox \ doc/coding_standard_c.md \ @@ -880,14 +1030,23 @@ EXTRA_DIST += \ man/Tss2_TctiLdr_Initialize.3.in \ man/tss2-tcti-pcap.7.in \ man/tss2-tcti-device.7.in \ - man/man7/tss2-tcti-swtpm.7 \ + man/tss2-tcti-swtpm.7.in \ man/tss2-tcti-mssim.7.in \ man/tss2-tcti-cmd.7.in \ + man/tss2-tcti-spidev.7.in \ + man/tss2-tcti-spi-helper.7.in \ + man/tss2-tcti-spi-ltt2go.7.in \ + man/tss2-tcti-spi-ftdi.7.in \ + man/tss2-tcti-i2c-helper.7.in \ + man/tss2-tcti-i2c-ftdi.7.in \ man/tss2-tctildr.7.in CLEANFILES += \ $(man3_MANS) \ - $(man7_MANS) + $(man7_MANS) \ + $(top_builddir)/ca + +DISTCLEANFILES += $(top_builddir)/ca # function to transform man .in files to man pages # $1: target diff --git a/README.md b/README.md index 4cae640..78a5b89 100644 --- a/README.md +++ b/README.md @@ -11,34 +11,20 @@ [![Gitter](https://badges.gitter.im/tpm2-software/community.svg)](https://gitter.im/tpm2-software/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) # Overview + This repository hosts source code implementing the Trusted Computing Group's (TCG) TPM2 Software Stack (TSS). This stack consists of the following layers from top to bottom: -* Feature API (FAPI) as described in the [TCG Feature API (FAPI) Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_FAPI_v0p94_r09_pub.pdf) -along with [TCG TSS 2.0 JSON Data Types and Policy Language Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_JSON_Policy_v0p7_r08_pub.pdf) -This API is designed to be very high-level API, intended to make programming with the TPM as simple as possible. -The API functions are exposed through a single library: libtss2-fapi. -* Enhanced System API (ESAPI) as described in the [TCG TSS 2.0 Enhanced System API (ESAPI) Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_ESAPI_v1p0_r08_pub.pdf) -This API is a 1-to-1 mapping of the TPM2 commands documented in Part 3 of the TPM2 specification. -Additionally there are asynchronous versions of each command. -In addition to SAPI, the ESAPI performs tracking of meta data for TPM object and automatic calculation of session based authorization and encryption values. -Both the synchronous and asynchronous API are exposed through a single library: libtss2-esys. -* System API (SAPI) as described in the [TCG TSS 2.0 System Level API (SAPI) Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_SAPI_v1p1_r29_pub_20190806.pdf) -This API is a 1-to-1 mapping of the TPM2 commands documented in Part 3 of the TPM2 specification. -Additionally there are asynchronous versions of each command. -These asynchronous variants may be useful for integration into event-driven programming environments. -Both the synchronous and asynchronous API are exposed through a single library: libtss2-sys. -* Marshaling/Unmarshaling (MU) as described in the [TCG TSS 2.0 Marshaling/Unmarshaling API Specification](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_Marshaling_Unmarshaling_API_v1p0_r07_pub.pdf) -This API provides a set of marshaling and unmarshaling functions for all data types define by the TPM library specification. -The Marshaling/Unmarshaling API is exposed through a library called libtss2-mu. -* TPM Command Transmission Interface (TCTI) as described in the [TCG TSS 2.0 TPM Command Transmission Interface (TCTI) API Specification](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_TCTI_v1p0_r18_pub.pdf). -This API provides a standard interface to transmit / receive TPM command / response buffers. -It is expected that any number of libraries implementing the TCTI API will be implemented as a way to abstract various platform specific IPC mechanisms. -Currently this repository provides several TCTI implementations: libtss2-tcti-device, -libtss2-tcti-tbs (for Windows), libtss2-tcti-swtpm and libtss2-tcti-mssim. -The former should be used for direct access to the TPM through the Linux kernel driver. -The latter implements the protocol exposed by the Microsoft software TPM2 simulator. -* The [TCG TSS 2.0 Overview and Common Structures Specification](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_Overview_Common_Structures_v0.9_r03_published.pdf) forms the basis for all implementations in this project. NOTE: We deviate from this specification by increasing the value of TPM2_NUM_PCR_BANKS from 3 to 16 to ensure compatibility with TPM2 implementations that have enabled a larger than typical number of PCR banks. This larger value for TPM2_NUM_PCR_BANKS is expected to be included in a future revision of the specification. +| Name | Libraries |                          Description                          | Specifications | +|---|---|---|---| +| Feature API (FAPI) | libtss2‑fapi | High-level API for simple TPM usage | [TCG Feature API (FAPI) Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_FAPI_v0p94_r09_pub.pdf),
[TCG TSS 2.0 JSON Data Types and Policy Language Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_JSON_Policy_v0p7_r08_pub.pdf) | +| Enhanced System API (ESAPI, sometimes ESYS) | libtss2‑esys | 1-to-1 mapping of the TPM2 commands
  • Session handling
  • Tracks meta data for TPM objects
  • Asynchronous calls
| [TCG TSS 2.0 Enhanced System API (ESAPI) Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_ESAPI_v1p0_r08_pub.pdf) | +| System API (SAPI, sometimes SYS) | libtss2‑sys | 1-to-1 mapping of the TPM2 commands
  • Asynchronous calls
| [TCG TSS 2.0 System Level API (SAPI) Specification](https://trustedcomputinggroup.org/wp-content/uploads/TSS_SAPI_v1p1_r29_pub_20190806.pdf) | +| Marshaling/Unmarshaling (MU) | libtss2‑mu | (Un)marshaling all data types in the TPM library specification | [TCG TSS 2.0 Marshaling/Unmarshaling API Specification](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_Marshaling_Unmarshaling_API_v1p0_r07_pub.pdf) | +| TPM Command Transmission Interface (TCTI) | libtss2‑tcti‑device
libtss2‑tcti‑tbs
libtss2‑tctildr
libtss2‑tcti‑swtpm
… | Standard API to transmit/receive TPM commands and responses

See [doc/tcti.md](doc/tcti.md) | [TCG TSS 2.0 TPM Command Transmission Interface (TCTI) API Specification](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_TCTI_v1p0_r18_pub.pdf) | +||| Basis for all implementations in this project. [1] | [TCG TSS 2.0 Overview and Common Structures Specification](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_Overview_Common_Structures_v0.9_r03_published.pdf) | + +[1] We currently deviate from the specification by increasing the value of `TPM2_NUM_PCR_BANKS` from 3 to 16 to ensure compatibility with TPM2 implementations that have enabled a larger than typical number of PCR banks. This is expected to be included in a future revision of the specification. # Build and Installation Instructions: Instructions to build and install tpm2-tss are available in the [INSTALL](INSTALL.md) file. diff --git a/afl-fuzzing/fuzz-ima.sh b/afl-fuzzing/fuzz-ima.sh index 988f49d..9787b87 100755 --- a/afl-fuzzing/fuzz-ima.sh +++ b/afl-fuzzing/fuzz-ima.sh @@ -7,9 +7,14 @@ function stop() { killall afl-fuzz } - trap stop +test_endian=$(echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}') +if [ $test_endian == 0 ]; then + echo "Little endian test files can't be used on big endian architecture" + exit 1 +fi + mkdir -p afl-fuzzing/ima-sml for x in sml-ima-ng-sha1.b64 sml-ima-sha1.b64 sml-ima-sha1-invalidated.b64 sml-ima-sig-sha256.b64 sml-ima-sig-sha256-invalidated.b64 do diff --git a/afl-fuzzing/fuzz-system.sh b/afl-fuzzing/fuzz-system.sh index 877dfdf..27da309 100755 --- a/afl-fuzzing/fuzz-system.sh +++ b/afl-fuzzing/fuzz-system.sh @@ -5,6 +5,12 @@ export srcdir=$(pwd) trap killall afl-fuzz +test_endian=$(echo -n I | od -to2 | awk 'FNR==1{ print substr($2,6,1)}') +if [ $test_endian == 0 ]; then + echo "Little endian test files can't be used on big endian architecture" + exit 1 +fi + mkdir -p afl-fuzzing/system-events for x in binary_measurements_nuc.b64 binary_measurements_pc_client.b64 do diff --git a/bootstrap b/bootstrap index c25c9a3..f70ff03 100755 --- a/bootstrap +++ b/bootstrap @@ -52,6 +52,10 @@ echo "Generating file lists: ${VARS_FILE}" src_listvar "src/util" "*.h" "UTIL_H" printf "UTIL_SRC = \$(UTIL_C) \$(UTIL_H)\n" + src_listvar "src/util-io" "*.c" "UTIL_IO_C" + src_listvar "src/util-io" "*.h" "UTIL_IO_H" + printf "UTIL_IO_SRC = \$(UTIL_IO_C) \$(UTIL_IO_H)\n" + src_listvar "src/tss2-sys/" "*.c" "TSS2_SYS_C" src_listvar "src/tss2-sys/" "*.h" "TSS2_SYS_H" printf "TSS2_SYS_SRC = \$(TSS2_SYS_H) \$(TSS2_SYS_C)\n" diff --git a/configure.ac b/configure.ac index b655027..eb6051e 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) #Backward compatible setti AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_FILES([Makefile Doxyfile lib/tss2-sys.pc lib/tss2-esys.pc lib/tss2-mu.pc lib/tss2-tcti-device.pc lib/tss2-tcti-mssim.pc lib/tss2-tcti-swtpm.pc lib/tss2-tcti-pcap.pc lib/tss2-tcti-libtpms.pc lib/tss2-rc.pc lib/tss2-tctildr.pc lib/tss2-fapi.pc lib/tss2-tcti-cmd.pc lib/tss2-policy.pc lib/tss2-tcti-spi-helper.pc]) +AC_CONFIG_FILES([Makefile Doxyfile lib/tss2-sys.pc lib/tss2-esys.pc lib/tss2-mu.pc lib/tss2-tcti-device.pc lib/tss2-tcti-mssim.pc lib/tss2-tcti-swtpm.pc lib/tss2-tcti-pcap.pc lib/tss2-tcti-libtpms.pc lib/tss2-rc.pc lib/tss2-tctildr.pc lib/tss2-fapi.pc lib/tss2-tcti-cmd.pc lib/tss2-policy.pc lib/tss2-tcti-spi-helper.pc lib/tss2-tcti-spi-ltt2go.pc lib/tss2-tcti-spidev.pc lib/tss2-tcti-spi-ftdi.pc lib/tss2-tcti-i2c-helper.pc lib/tss2-tcti-i2c-ftdi.pc]) # propagate configure arguments to distcheck AC_SUBST([DISTCHECK_CONFIGURE_FLAGS],[$ac_configure_args]) @@ -29,6 +29,7 @@ AC_PROG_CC AC_PROG_CXX AC_PROG_LN_S AC_USE_SYSTEM_EXTENSIONS +AC_C_BIGENDIAN LT_INIT() LT_LIB_DLLOAD PKG_INSTALLDIR() @@ -151,7 +152,7 @@ AS_IF([test "x$enable_fapi_async_tests" = "xyes"], [AC_MSG_WARN("FAPI compiled with asynchronous spinning testing. NOT FOR PRODUCTION!")]) AC_ARG_ENABLE([policy], - [AS_HELP_STRING([--enable-policy], + [AS_HELP_STRING([--disable-policy], [build the tss2-policy library (default is yes)])], [enable_policy=$enableval], [enable_policy=yes]) @@ -191,6 +192,9 @@ AS_IF([test "x$enable_esys" = xyes], AC_CHECK_LIB(crypto,[EVP_sm3], [ AC_DEFINE([HAVE_EVP_SM3], [1], [Support EVP_sm3 in openssl])], []) + AC_CHECK_LIB(crypto, [EVP_sm4_cfb128], [ + AC_DEFINE([HAVE_EVP_SM4_CFB], [1], [Support EVP_sm4_cfb in openssl])], + []) TSS2_ESYS_CFLAGS_CRYPTO="$CRYPTO_CFLAGS" TSS2_ESYS_LDFLAGS_CRYPTO="$CRYPTO_LIBS" ], [test "x$with_crypto" = xmbed], [ @@ -214,7 +218,7 @@ AS_IF([test "x$enable_policy" != xno && test "x$with_crypto" != "xossl"], [AC_MSG_ERROR([libpolicy has to be compiled with OpenSSL])]) AS_IF([test "x$enable_fapi" = xyes -o "x$enable_policy" = xyes ], - [PKG_CHECK_MODULES([JSONC], [json-c])]) + [PKG_CHECK_MODULES([JSONC], [json-c >= 0.13])]) AS_IF([test "x$enable_fapi" = xyes ], [PKG_CHECK_MODULES([CURL], [libcurl])]) @@ -223,6 +227,13 @@ AC_CHECK_LIB([curl], [curl_url_strerror], [AC_DEFINE([HAVE_CURL_URL_STRERROR],[1 AS_IF([test "x$enable_fapi" = xyes -o "x$enable_policy" = xyes ], [PKG_CHECK_MODULES([UUID], [uuid])]) +AC_ARG_ENABLE([util-io], + [AS_HELP_STRING([--disable-util-io], + [don't build the util-io])],, + [enable_util_io=yes]) + +AM_CONDITIONAL(ENABLE_UTIL_IO, test "x$enable_util_io" = "xyes") + AC_ARG_WITH([tctidefaultmodule], [AS_HELP_STRING([--with-tctidefaultmodule], [The default TCTI module for ESYS. (Default: libtss2-tcti-default.so)])], @@ -295,6 +306,90 @@ AM_CONDITIONAL([ENABLE_TCTI_SPI_HELPER], [test "x$enable_tcti_spi_helper" != xno AS_IF([test "x$enable_tcti_spi_helper" = "xyes"], [AC_DEFINE([TCTI_SPI_HELPER],[1], [TCTI HELPER FOR SPI BASED ACCESS TO TPM2 DEVICE])]) +AC_ARG_ENABLE([tcti-spi-ltt2go], + [AS_HELP_STRING([--disable-tcti-spi-ltt2go], + [don't build the tcti-spi-ltt2go module])], + [AS_IF([test "x$enable_tcti_spi_ltt2go" = "xyes"], + [PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], + [AC_CHECK_HEADER(libusb-1.0/libusb.h, + [enable_tcti_spi_ltt2go=yes], + [enable_tcti_spi_ltt2go=no] [AC_MSG_ERROR([libusb-1.0 library header is missing.])])], + [enable_tcti_spi_ltt2go=no] [AC_MSG_ERROR([libusb-1.0 library is missing.])])], + [AS_IF([test "x$enable_tcti_spi_ltt2go" = "xno"], + [enable_tcti_spi_ltt2go=no])])], + [PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], + [AC_CHECK_HEADER(libusb-1.0/libusb.h, + [enable_tcti_spi_ltt2go=yes], + [enable_tcti_spi_ltt2go=no])], + [enable_tcti_spi_ltt2go=no])]) + + +AM_CONDITIONAL([ENABLE_TCTI_SPI_LTT2GO], [test "x$enable_tcti_spi_ltt2go" != xno]) + +AS_IF([test "x$enable_tcti_spi_ltt2go" = "xyes"], + AC_DEFINE([TCTI_SPI_LTT2GO],[1], [TCTI FOR USB BASED ACCESS TO LETSTRUST-TPM2GO])) + +AC_ARG_ENABLE([tcti-spidev], + [AS_HELP_STRING([--disable-tcti-spidev], + [don't build the tcti-spidev module; Default: Auto])],, + [enable_tcti_spidev=auto]) +AS_IF([test "x$enable_tcti_spidev" = "xauto"], + AC_CHECK_HEADER(linux/ioctl.h, + [enable_tcti_spidev=yes], + [enable_tcti_spidev=no])) +AM_CONDITIONAL([ENABLE_TCTI_SPIDEV], [test "x$enable_tcti_spidev" != xno]) +AS_IF([test "x$enable_tcti_spidev" = "xyes"], + AC_DEFINE([TCTI_SPIDEV],[1], [TCTI FOR SPIDEV BASED ACCESS TO TPM])) + +PKG_CHECK_MODULES([LIBFTDI], + [libftdi], + [AC_DEFINE(LIBFTDI_VERSION, [0], [libftdi version 0.x])] + [have_libftdi=yes], + [PKG_CHECK_MODULES([LIBFTDI], + [libftdi1], + [AC_DEFINE(LIBFTDI_VERSION, [1], [libftdi version 1.x])] + [have_libftdi=yes], + [have_libftdi=no])]) + +AC_ARG_ENABLE([tcti-spi-ftdi], + [AS_HELP_STRING([--disable-tcti-spi-ftdi], + [don't build the tcti-spi-ftdi module])], + [AS_IF([test "x$enable_tcti_spi_ftdi" = "xyes"], + [AS_IF([test "x$have_libftdi" != "xyes"], + [AC_MSG_ERROR([libftdi/libftdi1 library is missing.])])])], + [AS_IF([test "x$have_libftdi" = "xyes"], + [enable_tcti_spi_ftdi=yes], + [enable_tcti_spi_ftdi=no])]) + +AM_CONDITIONAL([ENABLE_TCTI_SPI_FTDI], [test "x$enable_tcti_spi_ftdi" != xno]) + +AS_IF([test "x$enable_tcti_spi_ftdi" = "xyes"], + AC_DEFINE([TCTI_SPI_FTDI],[1], [TCTI FOR USB BASED ACCESS TO SPI BASED TPM OVER THE FTDI MPSSE USB TO SPI BRIDGE])) + +AC_ARG_ENABLE([tcti-i2c-helper], + [AS_HELP_STRING([--disable-tcti-i2c-helper], + [don't build the tcti-i2c-helper module])],, + [enable_tcti_i2c_helper=yes]) + +AM_CONDITIONAL([ENABLE_TCTI_I2C_HELPER], [test "x$enable_tcti_i2c_helper" != xno]) +AS_IF([test "x$enable_tcti_i2c_helper" = "xyes"], + [AC_DEFINE([TCTI_I2C_HELPER],[1], [TCTI HELPER FOR I2C BASED ACCESS TO TPM2 DEVICE])]) + +AC_ARG_ENABLE([tcti-i2c-ftdi], + [AS_HELP_STRING([--disable-tcti-i2c-ftdi], + [don't build the tcti-i2c-ftdi module])], + [AS_IF([test "x$enable_tcti_i2c_ftdi" = "xyes"], + [AS_IF([test "x$have_libftdi" != "xyes"], + [AC_MSG_ERROR([libftdi/libftdi1 library is missing.])])])], + [AS_IF([test "x$have_libftdi" = "xyes"], + [enable_tcti_i2c_ftdi=yes], + [enable_tcti_i2c_ftdi=no])]) + +AM_CONDITIONAL([ENABLE_TCTI_I2C_FTDI], [test "x$enable_tcti_i2c_ftdi" != xno]) + +AS_IF([test "x$enable_tcti_i2c_ftdi" = "xyes"], + AC_DEFINE([TCTI_I2C_FTDI],[1], [TCTI FOR USB BASED ACCESS TO I2C BASED TPM OVER THE FTDI MPSSE USB TO I2C BRIDGE])) + AC_ARG_ENABLE([tcti-fuzzing], [AS_HELP_STRING([--enable-tcti-fuzzing], [build the tcti-fuzzing module])],, @@ -329,13 +424,8 @@ dnl --------- Physical TPM device for testing ----------------------- AC_ARG_WITH([device], [AS_HELP_STRING([--with-device=],[TPM device for testing])], - [AS_IF([test -w "$with_device" && test -r "$with_device"], - [AC_MSG_RESULT([success]) - AX_NORMALIZE_PATH([with_device]) - with_device_set=yes], - [AC_MSG_ERROR([TPM device provided does not exist or is not writable])])], + [with_device_set=yes], [with_device_set=no]) -AM_CONDITIONAL([TESTDEVICE],[test "x$with_device_set" = xyes]) AC_ARG_WITH([devicetests], [AS_HELP_STRING([--with-devicetests=],[Comma-separated values of possible tests: destructive,mandatory,optional] default is mandatory)], @@ -363,6 +453,27 @@ AM_CONDITIONAL([DEVICEMANDATORY],[test "x$enable_device_mandatory" = "xyes"]) # # enable integration tests and check for simulator binary # + +AC_ARG_WITH([integrationtcti], + [AS_HELP_STRING([--with-integrationtcti=],[TCTI used for testing])], + [AS_IF([test x"$with_device_set" = "xyes"], + [AC_MSG_ERROR([with-device defines already the used TCTI"])], + [AS_IF([test "xdevice:" = x$(echo $with_integrationtcti | sed 's/\(device:\).*/\1/') ], + [ with_device=$(echo $with_integrationtcti | sed 's/^device\://') + with_device_set=yes + integration_tcti=$with_integrationtcti], + [ integration_tcti=$with_integrationtcti])])], + [integration_tcti=none]) + +AM_CONDITIONAL([TESTDEVICE],[test "x$with_device_set" = xyes]) + +AS_IF([test "xyes" = x"$with_device_set"], + [ AS_IF([test -w "$with_device" && test -r "$with_device"], + [AC_MSG_RESULT([success]) + AX_NORMALIZE_PATH([with_device]) + w th_device_set=yes], + [AC_MSG_ERROR([TPM device provided does not exist or is not writable])]) ]) + AC_ARG_ENABLE([integration], [AS_HELP_STRING([--enable-integration], [build and execute integration tests])],, @@ -391,12 +502,9 @@ AS_IF([test "x$enable_integration" = "xyes"], AC_CHECK_HEADER(uthash.h, [], [AC_MSG_ERROR([Can not find uthash.h. Please install uthash-dev])]) # choose tcti for testing and look for TPM simulator binary - integration_tcti="none" - integration_args="" AS_IF([test "x$with_device_set" = xyes], [# use device if --with-device was passed - integration_tcti=device - integration_args="--device=$with_device" + integration_tcti=device:$with_device AC_MSG_WARN([Using physical TPM for integration testing])]) AS_IF([test "x$integration_tcti" = "xnone" && test "x$enable_tcti_swtpm" != xyes && test "x$enable_tcti_mssim" != xyes], [AC_MSG_ERROR([No suitable TCTI for testing enabled. Please use option --enable-tcti-swtpm (recommended) or --enable-tcti-mssim (fallback) to enable a suitable TCTI or disable testing with --disable-integration.])]) @@ -417,7 +525,6 @@ AS_IF([test "x$enable_integration" = "xyes"], AS_IF([test "x$integration_tcti" = "xnone"], [AC_MSG_ERROR([No simulator executable found in PATH for testing TCTI.])]) AC_SUBST([INTEGRATION_TCTI], [$integration_tcti]) - AC_SUBST([INTEGRATION_ARGS], [$integration_args]) AC_SUBST([ENABLE_INTEGRATION], [$enable_integration])]) AM_CONDITIONAL([ENABLE_INTEGRATION],[test "x$enable_integration" = "xyes"]) # @@ -545,14 +652,16 @@ AS_IF([test "x$enable_self_generated_certificate" = xyes], [AC_DEFINE([SELF_GENERATED_CERTIFICATE], [1], [Allow usage of self generated root certificate])], [AS_IF([test "x$integration_tcti" != "xdevice"], [AC_DEFINE([FAPI_TEST_EK_CERT_LESS], [1], [Perform integration tests without EK certificate verification])])]) +AM_CONDITIONAL([INIT_CA], [test "x$enable_self_generated_certificate" = xyes]) + AS_IF([test "x$enable_integration" = "xyes" && test "x$enable_self_generated_certificate" != "xyes" && test "x$integration_tcti" != "xdevice"], [AC_MSG_WARN([Running integration tests without EK certificate verification, use --enable-self-generated-certificate for full test coverage])]) # Check for systemd helper tools used by make install AC_CHECK_PROG(systemd_sysusers, systemd-sysusers, yes) -AM_CONDITIONAL(SYSD_SYSUSERS, test "x$systemd_sysusers" = "xyes") +AM_CONDITIONAL([SYSD_SYSUSERS], [test "x$systemd_sysusers" = "xyes" && test "x$sysusersdir" != "xno"]) AC_CHECK_PROG(systemd_tmpfiles, systemd-tmpfiles, yes) -AM_CONDITIONAL(SYSD_TMPFILES, test "x$systemd_tmpfiles" = "xyes") +AM_CONDITIONAL([SYSD_TMPFILES], [test "x$systemd_tmpfiles" = "xyes" && test "x$tmpfilesdir" != "xno"]) # Check all tools used by make install AS_IF([test "$HOSTOS" = "Linux" && test "x$systemd_sysusers" != "xyes"], @@ -641,4 +750,8 @@ AC_MSG_RESULT([ userstatedir: [\$HOME/]$with_userstatedir sysmeasurements: $sysmeasurements imameasurements: $imameasurements + tcti_spi_ltt2go $enable_tcti_spi_ltt2go + tcti_spidev $enable_tcti_spidev + tcti_spi_ftdi $enable_tcti_spi_ftdi + tcti_i2c_ftdi $enable_tcti_i2c_ftdi ]) diff --git a/debian/changelog b/debian/changelog index da06959..48858cf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,17 +1,151 @@ -tpm2-tss (4.0.1-3deepin2) unstable; urgency=medium +tpm2-tss (4.1.3-6deepin2) unstable; urgency=medium - * fix CVE-2024-29040 + * revert for 64-bit time_t transition. - -- zengwei Wed, 24 Dec 2025 15:24:37 +0800 + -- lichenggang Tue, 28 Apr 2026 16:56:43 +0800 -tpm2-tss (4.0.1-3deepin1) unstable; urgency=low +tpm2-tss (4.1.3-6deepin1) unstable; urgency=low - * esys: add SM4 algorithm support - - Reference: https://github.com/tpm2-software/tpm2-tss/pull/2502 * add ecc encrypt/decrypt support * add support for udev to create tcm devices - -- chench Tue, 20 Aug 2024 21:02:02 +0800 + -- lichenggang Tue, 28 Apr 2026 16:03:50 +0800 + +tpm2-tss (4.1.3-6) unstable; urgency=medium + + * Import tpm-udev binary package from standalone source package + * Move config files (sysusers/tmpfiles/etc) from libtss2-fapi1t64 to + tpm-udev + * tpm-udev: ensure udev rules are reloaded after sysusers.d has ran + + -- Luca Boccassi Wed, 25 Feb 2026 15:12:45 +0000 + +tpm2-tss (4.1.3-5) unstable; urgency=medium + + [ Luca Boccassi ] + * Disable lto, not yet ready upstream + * Run dh-sequence-installsysusers + + -- Mario Limonciello Tue, 24 Feb 2026 23:52:20 -0600 + +tpm2-tss (4.1.3-4) unstable; urgency=medium + + [ Zaiba Sanglikar ] + * Add autopkgtest suite with upstream test suite (Closes: #1087380) + + [ Luca Boccassi ] + * libtss2-dev: drop ${shlibs:Depends} + * Add tpm2-tss metapackage that depends on all libtss2 library packages + + -- Mario Limonciello Sun, 22 Feb 2026 07:57:28 -0600 + +tpm2-tss (4.1.3-3) unstable; urgency=medium + + [ Luca Boccassi ] + * Build depend on tmpfiles and sysusers packages + * Drop tpm-udev build dependency + * Add d/s/options to ignore files in git but not in tarball + + -- Mario Limonciello Tue, 17 Feb 2026 22:56:25 -0600 + +tpm2-tss (4.1.3-2) unstable; urgency=medium + + [ Luca Boccassi ] + * Install sysusers.d conf file + + -- Mario Limonciello Mon, 16 Feb 2026 14:29:24 -0600 + +tpm2-tss (4.1.3-1.3) unstable; urgency=medium + + * Non-maintainer upload + * Drop TCG license (Closes: #1115473) + * d/copyright: Keep the upstream license for patches by default + * Fix build with cmocka 2.0.1 (Closes: #1124214) + + -- Bastian Germann Tue, 13 Jan 2026 18:07:59 +0100 + +tpm2-tss (4.1.3-1.2) unstable; urgency=medium + + * Non-maintainer upload. + * Switch from outdated libfti to libftdi1 (Closes: #1072637) + + -- Aurelien Jarno Sat, 26 Oct 2024 12:25:25 +0200 + +tpm2-tss (4.1.3-1.1) unstable; urgency=medium + + * Non-maintainer upload. + * Backport patches to fix FTBFS (Closes: #1070720) + + -- Luca Boccassi Thu, 10 Oct 2024 01:46:57 +0100 + +tpm2-tss (4.1.3-1) unstable; urgency=low + + * New upstream version 4.1.3 + - Update debian/libtss2-tcti-cmd0t64.symbols + + -- Ying-Chun Liu (PaulLiu) Fri, 31 May 2024 06:38:56 +0800 + +tpm2-tss (4.1.0-1) unstable; urgency=low + + * New upstream version 4.1.0 + - Fixed CVE-2024-29040 (Closes: #1070140) + * Refresh debian/patches/0001_disable_fapi_io_test.patch + * Remove debian/patches/0003-test-unit-tcti-*.patch: already upstreamed. + * Remove debian/patches/0004-tss2-tcti-tcti-libtpms-*.patch: already + upstreamed. + * Remove debian/patches/fix-tcti-spi-helper-big-endian.patch: already + upstreamed. + * Update debian/patches/disable-tests-on-big-endian.patch + * Remove debian/patches/skip-tests-which-fail-on-32-bit.patch: already + upstreamed + * Add libtss2-tcti-i2c-helper0, libtss2-tcti-spi-ltt2go0, + libtss2-tcti-spidev0 + * Update symbols file + + -- Ying-Chun Liu (PaulLiu) Tue, 07 May 2024 19:19:45 +0800 + +tpm2-tss (4.0.1-7.2) unstable; urgency=medium + + * Non-maintainer upload. + * debian/patches: Apply upstream patch to skip tests which fail on 32-bit + with _FILE_BITS=64 (Closes: #1067418) + + -- Sebastian Ramacher Thu, 11 Apr 2024 23:02:54 +0200 + +tpm2-tss (4.0.1-7.1) unstable; urgency=medium + + * Non-maintainer upload. + * Rename libraries for 64-bit time_t transition. Closes: #1062992 + + -- Benjamin Drung Thu, 29 Feb 2024 18:28:02 +0000 + +tpm2-tss (4.0.1-7) unstable; urgency=low + + [ Jeremy Bícha ] + * Add debian/salsa-ci.yml + + [ Ying-Chun Liu (PaulLiu) ] + * debian/control: libtss2-mu-4.0.1-0 conflicts libtss2-mu0 (Closes: #1061438) + + -- Ying-Chun Liu (PaulLiu) Thu, 25 Jan 2024 21:48:43 +0800 + +tpm2-tss (4.0.1-6) unstable; urgency=low + + * debian/control: add tpm-udev to Build-Depends. + + -- Ying-Chun Liu (PaulLiu) Tue, 23 Jan 2024 17:38:32 +0800 + +tpm2-tss (4.0.1-5) unstable; urgency=low + + * Upload 4.0.1-4 to unstable. (Closes: #1051284) + + -- Ying-Chun Liu (PaulLiu) Tue, 23 Jan 2024 01:17:51 +0800 + +tpm2-tss (4.0.1-4) experimental; urgency=low + + * ABI broken by the upstream thus we rename the package to reflect this. + + -- Ying-Chun Liu (PaulLiu) Sun, 26 Nov 2023 13:40:26 +0800 tpm2-tss (4.0.1-3) unstable; urgency=low diff --git a/debian/control b/debian/control index a635644..30e2897 100644 --- a/debian/control +++ b/debian/control @@ -9,17 +9,25 @@ Build-Depends: acl, autoconf, autoconf-archive, debhelper-compat (= 13), + dh-sequence-installsysusers, docbook-xml, docbook-xsl, doxygen, + dpkg-dev (>= 1.22.5), libcmocka-dev (>= 1.0), libcurl4-openssl-dev | libcurl-dev, + libftdi1-dev, + libini-config-dev, libjson-c-dev, libltdl-dev, libssl-dev, libtool, libtpms-dev, - pkg-config, + libusb-1.0-0-dev, + pkgconf, + systemd | systemd-standalone-tmpfiles | systemd-tmpfiles, + systemd | systemd-standalone-sysusers | systemd-sysusers, + uthash-dev, uuid-dev, xsltproc Homepage: https://github.com/tpm2-software/tpm2-tss @@ -33,12 +41,12 @@ Depends: libtss2-tcti-cmd0, libtss2-tcti-device0, libtss2-tcti-mssim0, libtss2-tcti-swtpm0, - tpm-udev, + tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.2-1) -Replaces: libtss2-esys0 (<< 3.0.2-1) +Breaks: libtss2-esys-3.0.2-0 (<< ${source:Version}), libtss2-esys0 (<< 3.0.2-1) +Replaces: libtss2-esys-3.0.2-0, libtss2-esys0 (<< 3.0.2-1) Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -54,10 +62,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-fapi1 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-fapi1 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-fapi1 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -71,12 +79,15 @@ Description: TPM2 Software stack library - TSS and TCTI libraries This package contains the TSS fapi libraries that client applications will link against when they require accessing the TPM. -Package: libtss2-mu0 +Package: libtss2-mu-4.0.1-0 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-mu-4.0.1-0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), + libtss2-mu-4.0.1-0, + libtss2-mu0 (<< 4.0.1-4) +Conflicts: libtss2-mu0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -92,10 +103,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-rc0 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-rc0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-rc0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -111,10 +122,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-sys1 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-sys1 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-sys1 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -130,10 +141,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-tcti-cmd0 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-cmd0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-cmd0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -149,10 +160,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-tcti-device0 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-device0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-device0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -168,10 +179,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-tcti-mssim0 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-mssim0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-mssim0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -187,10 +198,10 @@ Description: TPM2 Software stack library - TSS and TCTI libraries Package: libtss2-tcti-swtpm0 Architecture: any -Depends: tpm-udev, ${misc:Depends}, ${shlibs:Depends} +Depends: tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-swtpm0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-swtpm0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -208,8 +219,8 @@ Package: libtss2-tcti-pcap0 Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-pcap0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-tcti-pcap0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -224,6 +235,8 @@ Description: TPM2 Software stack library - TSS and TCTI libraries will link against when they require accessing the TPM. Package: libtss2-tcti-spi-helper0 +Replaces: libtss2-tcti-spi-helper0 +Breaks: libtss2-tcti-spi-helper0 (<< ${source:Version}) Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same @@ -240,7 +253,94 @@ Description: TPM2 Software stack library - TSS and TCTI libraries This package contains the TCTI spi helper libraries that client applications will link against when they require accessing the TPM. +Package: libtss2-tcti-spi-ftdi0 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: TPM2 Software stack library - TSS and TCTI libraries + TPM2.0 TSS (Software Stack) consists of API layers provided to support + TPM 2.0 chips. It is made out of three layers: + . + - Enhanced System API (ESAPI) + - System API (SAPI), which implements the system layer API; + - Marshaling/Unmarshaling (MU) + - TPM Command Transmission Interface (TCTI), which is used by SAPI to + allow communication with the TAB/RM layer; + . + This package contains the TCTI spi ftdi libraries that client applications + will link against when they require accessing the TPM. + +Package: libtss2-tcti-spi-ltt2go0 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: TPM2 Software stack library - TSS and TCTI libraries + TPM2.0 TSS (Software Stack) consists of API layers provided to support + TPM 2.0 chips. It is made out of three layers: + . + - Enhanced System API (ESAPI) + - System API (SAPI), which implements the system layer API; + - Marshaling/Unmarshaling (MU) + - TPM Command Transmission Interface (TCTI), which is used by SAPI to + allow communication with the TAB/RM layer; + . + This package contains the TCTI spi ltt2go libraries that client applications + will link against when they require accessing the TPM. + +Package: libtss2-tcti-spidev0 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: TPM2 Software stack library - TSS and TCTI libraries + TPM2.0 TSS (Software Stack) consists of API layers provided to support + TPM 2.0 chips. It is made out of three layers: + . + - Enhanced System API (ESAPI) + - System API (SAPI), which implements the system layer API; + - Marshaling/Unmarshaling (MU) + - TPM Command Transmission Interface (TCTI), which is used by SAPI to + allow communication with the TAB/RM layer; + . + This package contains the TCTI spidev libraries that client applications + will link against when they require accessing the TPM. + +Package: libtss2-tcti-i2c-helper0 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: TPM2 Software stack library - TSS and TCTI libraries + TPM2.0 TSS (Software Stack) consists of API layers provided to support + TPM 2.0 chips. It is made out of three layers: + . + - Enhanced System API (ESAPI) + - System API (SAPI), which implements the system layer API; + - Marshaling/Unmarshaling (MU) + - TPM Command Transmission Interface (TCTI), which is used by SAPI to + allow communication with the TAB/RM layer; + . + This package contains the TCTI i2c helper libraries that client applications + will link against when they require accessing the TPM. + +Package: libtss2-tcti-i2c-ftdi0 +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Multi-Arch: same +Description: TPM2 Software stack library - TSS and TCTI libraries + TPM2.0 TSS (Software Stack) consists of API layers provided to support + TPM 2.0 chips. It is made out of three layers: + . + - Enhanced System API (ESAPI) + - System API (SAPI), which implements the system layer API; + - Marshaling/Unmarshaling (MU) + - TPM Command Transmission Interface (TCTI), which is used by SAPI to + allow communication with the TAB/RM layer; + . + This package contains the TCTI i2c ftdi libraries that client applications + will link against when they require accessing the TPM. + Package: libtss2-tcti-libtpms0 +Replaces: libtss2-tcti-libtpms0 +Breaks: libtss2-tcti-libtpms0 (<< ${source:Version}) Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same @@ -265,12 +365,12 @@ Depends: libtss2-tcti-cmd0, libtss2-tcti-mssim0, libtss2-tcti-spi-helper0, libtss2-tcti-swtpm0, - tpm-udev, + tpm-udev (>= ${source:Version}), ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same -Breaks: libtss2-esys0 (<< 3.0.1-2) -Replaces: libtss2-esys0 (<< 3.0.1-2) +Breaks: libtss2-esys0 (<< 3.0.1-2), libtss2-tctildr0 (<< ${source:Version}) +Replaces: libtss2-esys0 (<< 3.0.1-2), libtss2-tctildr0 Description: TPM2 Software stack library - TSS and TCTI libraries TPM2.0 TSS (Software Stack) consists of API layers provided to support TPM 2.0 chips. It is made out of three layers: @@ -285,6 +385,8 @@ Description: TPM2 Software stack library - TSS and TCTI libraries will link against when they require accessing the TPM. Package: libtss2-policy0 +Replaces: libtss2-policy0 +Breaks: libtss2-policy0 (<< ${source:Version}) Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} Multi-Arch: same @@ -307,22 +409,8 @@ Section: libdevel Depends: libcurl4-openssl-dev | libcurl-ssl-dev, libjson-c-dev, libssl-dev, - libtss2-esys-3.0.2-0 (= ${binary:Version}), - libtss2-fapi1 (= ${binary:Version}), - libtss2-mu0 (= ${binary:Version}), - libtss2-policy0 (= ${binary:Version}), - libtss2-rc0 (= ${binary:Version}), - libtss2-sys1 (= ${binary:Version}), - libtss2-tcti-cmd0 (= ${binary:Version}), - libtss2-tcti-device0 (= ${binary:Version}), - libtss2-tcti-libtpms0 (= ${binary:Version}), - libtss2-tcti-mssim0 (= ${binary:Version}), - libtss2-tcti-pcap0 (= ${binary:Version}), - libtss2-tcti-spi-helper0 (= ${binary:Version}), - libtss2-tcti-swtpm0 (= ${binary:Version}), - libtss2-tctildr0 (= ${binary:Version}), + ${libtss2:All}, ${misc:Depends}, - ${shlibs:Depends} Multi-Arch: same Description: TPM2 Software stack library - development files TPM2.0 TSS (Software Stack) consists of API layers provided to support @@ -337,6 +425,36 @@ Description: TPM2 Software stack library - development files This package contains development files for use when writing applications that need access to TPM chips. +Package: tpm2-tss +Architecture: any +Depends: ${libtss2:All}, + ${misc:Depends}, +Multi-Arch: same +Description: TPM2 Software stack library - metapackage for libraries + TPM2.0 TSS (Software Stack) consists of API layers provided to support + TPM 2.0 chips. It is made out of three layers: + . + - Enhanced System API (ESAPI) + - System API (SAPI), which implements the system layer API; + - Marshaling/Unmarshaling (MU) + - TPM Command Transmission Interface (TCTI), which is used by SAPI to + allow communication with the TAB/RM layer; + . + This is a metapackage that depends on all the libtss2 binary packages, to + facilitate installing all libraries at once, independently of the changing + SONAMEs. + +Package: tpm-udev +Architecture: all +Multi-Arch: foreign +Depends: ${misc:Depends} +Breaks: libtss2-fapi1 (<< 4.1.3-6) +Replaces: libtss2-fapi1 (<< 4.1.3-6) +Enhances: udev +Description: TPM2 Software stack library - udev rules for TPM modules + This package provides udev rules for the TPM modules. Both TPM1 or TPM2 need + this package to be installed to provide proper permissions of the TPM. + Package: libtss2-doc Architecture: all Section: doc diff --git a/debian/copyright b/debian/copyright index e0a150a..582a00c 100644 --- a/debian/copyright +++ b/debian/copyright @@ -13,65 +13,22 @@ Copyright: 2016 Canonical Ltd. 2017 Ying-Chun Liu (PaulLiU) License: GPL-3 -License: TCG - Licenses and Notices - 1. Copyright Licenses: - . - Trusted Computing Group (TCG) grants to the user of the source code in - this specification (the "Source Code") a worldwide, irrevocable, - nonexclusive, - royalty free, copyright license to reproduce, create derivative works, - distribute, display and perform the Source Code and derivative works - thereof, and to grant others the rights granted herein. - . - The TCG grants to the user of the other parts of the specification - (other than the Source Code) the rights to reproduce, distribute, - display, and perform the specification solely for the purpose of - developing products based on such documents. - . - 2. Source Code Distribution Conditions: - . - Redistributions of Source Code must retain the above copyright licenses, - this list of conditions and the following disclaimers. - . - Redistributions in binary form must reproduce the above copyright - licenses, this list of conditions and the following disclaimers in - the documentation and/or other materials provided with the distribution. - . - 3. Disclaimers: - . - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF LICENSE - OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH RESPECT TO - PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) THAT MAY BE - NECESSARY - TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. Contact TCG Administration - (admin@trustedcomputinggroup.org) for information on specification - licensing - rights available through TCG membership agreements. - . - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED - WARRANTIES - WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A - PARTICULAR - PURPOSE, ACCURACY, COMPLETENESS, OR NONINFRINGEMENT OF INTELLECTUAL - PROPERTY - RIGHTS, OR ANY WARRANTY OTHERWISE ARISING OUT OF ANY PROPOSAL, - SPECIFICATION - OR SAMPLE. - . - Without limitation, TCG and its members and licensors disclaim all - liability, - including liability for infringement of any proprietary rights, relating to - use of information in this specification and to the implementation of this - specification, and TCG disclaims all liability for cost of procurement of - substitute goods or services, lost profits, loss of use, loss of data or - any - incidental, consequential, direct, indirect, or special damages, whether - under contract, tort, warranty or otherwise, arising in any way out of use - or reliance upon this specification or any information herein. - . - Any marks and brands contained herein are the property of their respective - owner. +Files: debian/patches/* + debian/tpm-udev* +Copyright: Intel Corporation and individual contributors + 2019 Ying-Chun Liu (PaulLiu) +License: BSD-2-clause + +Files: debian/patches/0001_disable_fapi_io_test.patch +Comment: Please consider licensing under BSD-2-clause to remove this paragraph +Copyright: 2017 Ying-Chun Liu (PaulLiU) +License: GPL-3 + +Files: debian/patches/0002-fix-version.patch + debian/patches/disable-tests-on-big-endian.patch +Comment: Please consider licensing under BSD-2-clause to remove this paragraph +Copyright: 2016 Canonical Ltd. +License: GPL-3 License: GPL-3 On Debian systems the full text of the GNU General Public diff --git a/debian/libtss2-fapi1.install b/debian/libtss2-fapi1.install index 4db1f49..249acae 100644 --- a/debian/libtss2-fapi1.install +++ b/debian/libtss2-fapi1.install @@ -1,4 +1 @@ -etc/tmpfiles.d/tpm2-tss-fapi.conf usr/lib/tmpfiles.d/ -etc/tpm2-tss/fapi-config.json -etc/tpm2-tss/fapi-profiles/P_*.json usr/lib/*/libtss2-fapi.so.* diff --git a/debian/libtss2-mu0.install b/debian/libtss2-mu-4.0.1-0.install similarity index 100% rename from debian/libtss2-mu0.install rename to debian/libtss2-mu-4.0.1-0.install diff --git a/debian/libtss2-mu-4.0.1-0.lintian-overrides b/debian/libtss2-mu-4.0.1-0.lintian-overrides new file mode 100644 index 0000000..f928794 --- /dev/null +++ b/debian/libtss2-mu-4.0.1-0.lintian-overrides @@ -0,0 +1 @@ +libtss2-mu-4.0.1-0: package-name-doesnt-match-sonames libtss2-mu0 diff --git a/debian/libtss2-mu0.symbols b/debian/libtss2-mu-4.0.1-0.symbols similarity index 99% rename from debian/libtss2-mu0.symbols rename to debian/libtss2-mu-4.0.1-0.symbols index b9f02bb..7e1bc25 100644 --- a/debian/libtss2-mu0.symbols +++ b/debian/libtss2-mu-4.0.1-0.symbols @@ -1,4 +1,4 @@ -libtss2-mu.so.0 libtss2-mu0 #MINVER# +libtss2-mu.so.0 libtss2-mu-4.0.1-0 #MINVER# Tss2_MU_BYTE_Marshal@Base 3.0.1 Tss2_MU_BYTE_Unmarshal@Base 3.0.1 Tss2_MU_INT16_Marshal@Base 3.0.1 diff --git a/debian/libtss2-tcti-cmd0.symbols b/debian/libtss2-tcti-cmd0.symbols index c491d5d..d43f0b8 100644 --- a/debian/libtss2-tcti-cmd0.symbols +++ b/debian/libtss2-tcti-cmd0.symbols @@ -7,14 +7,6 @@ libtss2-tcti-cmd.so.0 libtss2-tcti-cmd0 #MINVER# header_unmarshal@Base 3.0.1 parse_key_value@Base 3.0.1 parse_key_value_string@Base 3.0.1 - read_all@Base 3.0.1 - socket_close@Base 3.0.1 - socket_connect@Base 3.0.1 - socket_connect_unix@Base 3.2.0 - socket_poll@Base 3.1.0 - socket_recv_buf@Base 3.0.1 - socket_set_nonblock@Base 3.1.0 - socket_xmit_buf@Base 3.0.1 tcti_cmd_context_cast@Base 3.0.1 tcti_cmd_down_cast@Base 3.0.1 tcti_cmd_fdopen@Base 3.0.1 @@ -36,5 +28,4 @@ libtss2-tcti-cmd.so.0 libtss2-tcti-cmd0 #MINVER# tcti_common_set_locality_checks@Base 3.0.1 tcti_common_transmit_checks@Base 3.0.1 tcti_make_sticky_not_implemented@Base 3.0.1 - tss2_tcti_info@Base 3.0.1 - write_all@Base 3.0.1 + tss2_tcti_cmd_info@Base 4.1.3 diff --git a/debian/libtss2-tcti-i2c-ftdi0.install b/debian/libtss2-tcti-i2c-ftdi0.install new file mode 100644 index 0000000..bd1b307 --- /dev/null +++ b/debian/libtss2-tcti-i2c-ftdi0.install @@ -0,0 +1 @@ +usr/lib/*/libtss2-tcti-i2c-ftdi.so.* diff --git a/debian/libtss2-tcti-i2c-ftdi0.symbols b/debian/libtss2-tcti-i2c-ftdi0.symbols new file mode 100644 index 0000000..b68a604 --- /dev/null +++ b/debian/libtss2-tcti-i2c-ftdi0.symbols @@ -0,0 +1,3 @@ +libtss2-tcti-i2c-ftdi.so.0 libtss2-tcti-i2c-ftdi0 #MINVER# + Tss2_Tcti_I2c_Ftdi_Init@Base 4.1.0 + Tss2_Tcti_Info@Base 4.1.0 diff --git a/debian/libtss2-tcti-i2c-helper0.install b/debian/libtss2-tcti-i2c-helper0.install new file mode 100644 index 0000000..a6a538f --- /dev/null +++ b/debian/libtss2-tcti-i2c-helper0.install @@ -0,0 +1 @@ +usr/lib/*/libtss2-tcti-i2c-helper.so.* diff --git a/debian/libtss2-tcti-i2c-helper0.symbols b/debian/libtss2-tcti-i2c-helper0.symbols new file mode 100644 index 0000000..e29b840 --- /dev/null +++ b/debian/libtss2-tcti-i2c-helper0.symbols @@ -0,0 +1,24 @@ +libtss2-tcti-i2c-helper.so.0 libtss2-tcti-i2c-helper0 #MINVER# + Tss2_Tcti_I2c_Helper_Init@Base 4.1.0 + Tss2_Tcti_Info@Base 4.1.0 + doLog@Base 4.1.0 + doLogBlob@Base 4.1.0 + header_marshal@Base 4.1.0 + header_unmarshal@Base 4.1.0 + parse_key_value@Base 4.1.0 + parse_key_value_string@Base 4.1.0 + tcti_common_cancel_checks@Base 4.1.0 + tcti_common_context_cast@Base 4.1.0 + tcti_common_down_cast@Base 4.1.0 + tcti_common_receive_checks@Base 4.1.0 + tcti_common_set_locality_checks@Base 4.1.0 + tcti_common_transmit_checks@Base 4.1.0 + tcti_i2c_helper_cancel@Base 4.1.0 + tcti_i2c_helper_context_cast@Base 4.1.0 + tcti_i2c_helper_down_cast@Base 4.1.0 + tcti_i2c_helper_finalize@Base 4.1.0 + tcti_i2c_helper_get_poll_handles@Base 4.1.0 + tcti_i2c_helper_receive@Base 4.1.0 + tcti_i2c_helper_set_locality@Base 4.1.0 + tcti_i2c_helper_transmit@Base 4.1.0 + tcti_make_sticky_not_implemented@Base 4.1.0 diff --git a/debian/libtss2-tcti-libtpms0.symbols b/debian/libtss2-tcti-libtpms0.symbols index abf2a78..03a19ad 100644 --- a/debian/libtss2-tcti-libtpms0.symbols +++ b/debian/libtss2-tcti-libtpms0.symbols @@ -1,3 +1,4 @@ libtss2-tcti-libtpms.so.0 libtss2-tcti-libtpms0 #MINVER# Tss2_Tcti_Info@Base 4.0.1 Tss2_Tcti_Libtpms_Init@Base 4.0.1 + Tss2_Tcti_Libtpms_Reset@Base 4.1.0 diff --git a/debian/libtss2-tcti-spi-ftdi0.install b/debian/libtss2-tcti-spi-ftdi0.install new file mode 100644 index 0000000..6bd462d --- /dev/null +++ b/debian/libtss2-tcti-spi-ftdi0.install @@ -0,0 +1 @@ +usr/lib/*/libtss2-tcti-spi-ftdi.so.* diff --git a/debian/libtss2-tcti-spi-ftdi0.symbols b/debian/libtss2-tcti-spi-ftdi0.symbols new file mode 100644 index 0000000..71c2c52 --- /dev/null +++ b/debian/libtss2-tcti-spi-ftdi0.symbols @@ -0,0 +1,3 @@ +libtss2-tcti-spi-ftdi.so.0 libtss2-tcti-spi-ftdi0 #MINVER# + Tss2_Tcti_Info@Base 4.1.0 + Tss2_Tcti_Spi_Ftdi_Init@Base 4.1.0 diff --git a/debian/libtss2-tcti-spi-helper0.symbols b/debian/libtss2-tcti-spi-helper0.symbols index a50b97d..2e5c60b 100644 --- a/debian/libtss2-tcti-spi-helper0.symbols +++ b/debian/libtss2-tcti-spi-helper0.symbols @@ -7,14 +7,6 @@ libtss2-tcti-spi-helper.so.0 libtss2-tcti-spi-helper0 #MINVER# header_unmarshal@Base 4.0.1 parse_key_value@Base 4.0.1 parse_key_value_string@Base 4.0.1 - read_all@Base 4.0.1 - socket_close@Base 4.0.1 - socket_connect@Base 4.0.1 - socket_connect_unix@Base 4.0.1 - socket_poll@Base 4.0.1 - socket_recv_buf@Base 4.0.1 - socket_set_nonblock@Base 4.0.1 - socket_xmit_buf@Base 4.0.1 tcti_common_cancel_checks@Base 4.0.1 tcti_common_context_cast@Base 4.0.1 tcti_common_down_cast@Base 4.0.1 @@ -30,4 +22,3 @@ libtss2-tcti-spi-helper.so.0 libtss2-tcti-spi-helper0 #MINVER# tcti_spi_helper_receive@Base 4.0.1 tcti_spi_helper_set_locality@Base 4.0.1 tcti_spi_helper_transmit@Base 4.0.1 - write_all@Base 4.0.1 diff --git a/debian/libtss2-tcti-spi-ltt2go0.install b/debian/libtss2-tcti-spi-ltt2go0.install new file mode 100644 index 0000000..54f4184 --- /dev/null +++ b/debian/libtss2-tcti-spi-ltt2go0.install @@ -0,0 +1 @@ +usr/lib/*/libtss2-tcti-spi-ltt2go.so.* diff --git a/debian/libtss2-tcti-spi-ltt2go0.symbols b/debian/libtss2-tcti-spi-ltt2go0.symbols new file mode 100644 index 0000000..ebacd41 --- /dev/null +++ b/debian/libtss2-tcti-spi-ltt2go0.symbols @@ -0,0 +1,3 @@ +libtss2-tcti-spi-ltt2go.so.0 libtss2-tcti-spi-ltt2go0 #MINVER# + Tss2_Tcti_Info@Base 4.1.0 + Tss2_Tcti_Spi_Ltt2go_Init@Base 4.1.0 diff --git a/debian/libtss2-tcti-spidev0.install b/debian/libtss2-tcti-spidev0.install new file mode 100644 index 0000000..50afd51 --- /dev/null +++ b/debian/libtss2-tcti-spidev0.install @@ -0,0 +1 @@ +usr/lib/*/libtss2-tcti-spidev.so.* diff --git a/debian/libtss2-tcti-spidev0.symbols b/debian/libtss2-tcti-spidev0.symbols new file mode 100644 index 0000000..e7cffa9 --- /dev/null +++ b/debian/libtss2-tcti-spidev0.symbols @@ -0,0 +1,3 @@ +libtss2-tcti-spidev.so.0 libtss2-tcti-spidev0 #MINVER# + Tss2_Tcti_Info@Base 4.1.0 + Tss2_Tcti_Spidev_Init@Base 4.1.0 diff --git a/debian/libtss2-tctildr0.symbols b/debian/libtss2-tctildr0.symbols index 7b51738..c43446f 100644 --- a/debian/libtss2-tctildr0.symbols +++ b/debian/libtss2-tctildr0.symbols @@ -4,3 +4,5 @@ libtss2-tctildr.so.0 libtss2-tctildr0 #MINVER# Tss2_TctiLdr_GetInfo@Base 3.0.1 Tss2_TctiLdr_Initialize@Base 3.0.1 Tss2_TctiLdr_Initialize_Ex@Base 3.0.1 + Tss2_Tcti_Info@Base 4.1.0 + Tss2_Tcti_TctiLdr_Init@Base 4.1.0 diff --git a/debian/not-installed b/debian/not-installed index 11b0470..18a8fea 100644 --- a/debian/not-installed +++ b/debian/not-installed @@ -1,2 +1 @@ -etc/sysusers.d/tpm2-tss.conf usr/lib/${DEB_HOST_MULTIARCH}/udev/rules.d/tpm-udev.rules diff --git a/debian/patches/0001_disable_fapi_io_test.patch b/debian/patches/0001_disable_fapi_io_test.patch index b380a67..8e8d949 100644 --- a/debian/patches/0001_disable_fapi_io_test.patch +++ b/debian/patches/0001_disable_fapi_io_test.patch @@ -4,13 +4,13 @@ Description: Temporarily disable fapi-io tests Forwarded: not-needed Bug: https://github.com/tpm2-software/tpm2-tss/issues/2135 Author: Ying-Chun Liu (PaulLiu) -Index: tpm2-tss-3.2.0/test/unit/fapi-io.c +Index: tpm2-tss/test/unit/fapi-io.c =================================================================== ---- tpm2-tss-3.2.0.orig/test/unit/fapi-io.c -+++ tpm2-tss-3.2.0/test/unit/fapi-io.c -@@ -363,10 +363,6 @@ int - main(int argc, char *argv[]) - { +--- tpm2-tss.orig/test/unit/fapi-io.c ++++ tpm2-tss/test/unit/fapi-io.c +@@ -372,10 +372,6 @@ main(int argc, char *argv[]) + #endif + const struct CMUnitTest tests[] = { - cmocka_unit_test(check_io_read_async), - cmocka_unit_test(check_io_read_finish), diff --git a/debian/patches/0003-test-unit-tcti-libtpms-fix-test-failed-at-32-bit-pla.patch b/debian/patches/0003-test-unit-tcti-libtpms-fix-test-failed-at-32-bit-pla.patch deleted file mode 100644 index 97edf8b..0000000 --- a/debian/patches/0003-test-unit-tcti-libtpms-fix-test-failed-at-32-bit-pla.patch +++ /dev/null @@ -1,110 +0,0 @@ -From dae6bf57c234186651fb5e361ced5481dc4719b1 Mon Sep 17 00:00:00 2001 -From: "Ying-Chun Liu (PaulLiu)" -Date: Tue, 11 Jul 2023 00:06:42 +0800 -Subject: [PATCH] test: unit: tcti-libtpms: fix test failed at 32-bit - platforms. - -When running the test on 32-bit platforms, we should not convert -pointers to integers. expect_value() will convert the cmd to an -integer value thus we should use expect_memory() instead. - -Signed-off-by: joholl -Signed-off-by: Ying-Chun Liu (PaulLiu) ---- - test/unit/tcti-libtpms.c | 20 ++++++++++---------- - 1 file changed, 10 insertions(+), 10 deletions(-) - -Index: tpm2-tss/test/unit/tcti-libtpms.c -=================================================================== ---- tpm2-tss.orig/test/unit/tcti-libtpms.c -+++ tpm2-tss/test/unit/tcti-libtpms.c -@@ -899,7 +899,7 @@ tcti_libtpms_locality_success_test(void - rc = Tss2_Tcti_SetLocality(ctx, 4); - assert_int_equal(rc, TSS2_RC_SUCCESS); - -- expect_value(TPMLIB_Process, cmd, cmd); -+ expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); - expect_value(TPMLIB_Process, locality, 4); /* expect locality 4 */ - will_return(TPMLIB_Process, rsp); -@@ -919,7 +919,7 @@ tcti_libtpms_transmit_success_test(void - unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; - unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - -- expect_value(TPMLIB_Process, cmd, cmd); -+ expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp); -@@ -994,7 +994,7 @@ tcti_libtpms_remap_state_success_test(vo - unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; - unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - -- expect_value(TPMLIB_Process, cmd, cmd); -+ expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp); -@@ -1051,7 +1051,7 @@ tcti_libtpms_remap_state_mremap_fail_tes - unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; - unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - -- expect_value(TPMLIB_Process, cmd, cmd); -+ expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp); -@@ -1094,7 +1094,7 @@ tcti_libtpms_remap_state_posix_fallocate - unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; - unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - -- expect_value(TPMLIB_Process, cmd, cmd); -+ expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp); -@@ -1156,7 +1156,7 @@ tcti_libtpms_no_statefile_success_test(v - unsigned char rsp_out[sizeof(rsp)]; - size_t rsp_len_out = sizeof(rsp); - -- expect_value(TPMLIB_Process, cmd, cmd); -+ expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp); -@@ -1210,7 +1210,7 @@ tcti_libtpms_two_states_no_statefiles_su - tcti_common[1] = tcti_common_context_cast(ctxs[1]); - - /* ===== transmit on instance 0 ===== */ -- expect_value(TPMLIB_Process, cmd, cmd_aa); -+ expect_memory(TPMLIB_Process, cmd, cmd_aa, sizeof(cmd_aa)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_aa)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp_aa); -@@ -1231,7 +1231,7 @@ tcti_libtpms_two_states_no_statefiles_su - assert_int_equal(tcti_libtpms[0]->state_len, 0); - - /* ===== transmit on instance 1 ===== */ -- expect_value(TPMLIB_Process, cmd, cmd_bb); -+ expect_memory(TPMLIB_Process, cmd, cmd_bb, sizeof(cmd_bb)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_bb)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp_bb); -@@ -1308,7 +1308,7 @@ tcti_libtpms_two_states_success_test(voi - tcti_common[1] = tcti_common_context_cast(ctxs[1]); - - /* ===== transmit on instance 0 ===== */ -- expect_value(TPMLIB_Process, cmd, cmd_aa); -+ expect_memory(TPMLIB_Process, cmd, cmd_aa, sizeof(cmd_aa)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_aa)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp_aa); -@@ -1336,7 +1336,7 @@ tcti_libtpms_two_states_success_test(voi - assert_memory_equal(tcti_libtpms[0]->state_mmap, S1_STATE, S1_STATE_LEN); - - /* ===== transmit on instance 1 ===== */ -- expect_value(TPMLIB_Process, cmd, cmd_bb); -+ expect_memory(TPMLIB_Process, cmd, cmd_bb, sizeof(cmd_bb)); - expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_bb)); - expect_value(TPMLIB_Process, locality, 0); - will_return(TPMLIB_Process, rsp_bb); diff --git a/debian/patches/0004-ESYS-FAPI-Fix-order-of-calloc-parameters.patch b/debian/patches/0004-ESYS-FAPI-Fix-order-of-calloc-parameters.patch new file mode 100644 index 0000000..1cc2cde --- /dev/null +++ b/debian/patches/0004-ESYS-FAPI-Fix-order-of-calloc-parameters.patch @@ -0,0 +1,933 @@ +Author: Juergen Repp +Description: ESYS/FAPI: Fix order of calloc parameters. +Origin:upstream,commit:8d19bd17ae5c770653d396dffab9a2cf1984a96d) +--- a/src/tss2-esys/api/Esys_AC_GetCapability.c ++++ b/src/tss2-esys/api/Esys_AC_GetCapability.c +@@ -252,7 +252,7 @@ + + /* Allocate memory for response parameters */ + if (capabilityData != NULL) { +- *capabilityData = calloc(sizeof(TPML_AC_CAPABILITIES), 1); ++ *capabilityData = calloc(1, sizeof(TPML_AC_CAPABILITIES)); + if (*capabilityData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_AC_Send.c ++++ b/src/tss2-esys/api/Esys_AC_Send.c +@@ -261,7 +261,7 @@ + + /* Allocate memory for response parameters */ + if (acDataOut != NULL) { +- *acDataOut = calloc(sizeof(TPMS_AC_OUTPUT), 1); ++ *acDataOut = calloc(1, sizeof(TPMS_AC_OUTPUT)); + if (*acDataOut == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_ActivateCredential.c ++++ b/src/tss2-esys/api/Esys_ActivateCredential.c +@@ -281,7 +281,7 @@ + + /* Allocate memory for response parameters */ + if (certInfo != NULL) { +- *certInfo = calloc(sizeof(TPM2B_DIGEST), 1); ++ *certInfo = calloc(1, sizeof(TPM2B_DIGEST)); + if (*certInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_Certify.c ++++ b/src/tss2-esys/api/Esys_Certify.c +@@ -285,13 +285,13 @@ + + /* Allocate memory for response parameters */ + if (certifyInfo != NULL) { +- *certifyInfo = calloc(sizeof(TPM2B_ATTEST), 1); ++ *certifyInfo = calloc(1, sizeof(TPM2B_ATTEST)); + if (*certifyInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_CertifyCreation.c ++++ b/src/tss2-esys/api/Esys_CertifyCreation.c +@@ -295,13 +295,13 @@ + + /* Allocate memory for response parameters */ + if (certifyInfo != NULL) { +- *certifyInfo = calloc(sizeof(TPM2B_ATTEST), 1); ++ *certifyInfo = calloc(1, sizeof(TPM2B_ATTEST)); + if (*certifyInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_CertifyX509.c ++++ b/src/tss2-esys/api/Esys_CertifyX509.c +@@ -293,19 +293,19 @@ + + /* Allocate memory for response parameters */ + if (addedToCertificate != NULL) { +- *addedToCertificate = calloc(sizeof(TPM2B_MAX_BUFFER), 1); ++ *addedToCertificate = calloc(1, sizeof(TPM2B_MAX_BUFFER)); + if (*addedToCertificate == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (tbsDigest != NULL) { +- *tbsDigest = calloc(sizeof(TPM2B_DIGEST), 1); ++ *tbsDigest = calloc(1, sizeof(TPM2B_DIGEST)); + if (*tbsDigest == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_Commit.c ++++ b/src/tss2-esys/api/Esys_Commit.c +@@ -286,19 +286,19 @@ + + /* Allocate memory for response parameters */ + if (K != NULL) { +- *K = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *K = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*K == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (L != NULL) { +- *L = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *L = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*L == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (E != NULL) { +- *E = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *E = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*E == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_ContextSave.c ++++ b/src/tss2-esys/api/Esys_ContextSave.c +@@ -208,7 +208,7 @@ + esysContext->state = _ESYS_STATE_INTERNALERROR; + + /* Allocate memory for response parameters */ +- lcontext = calloc(sizeof(TPMS_CONTEXT), 1); ++ lcontext = calloc(1, sizeof(TPMS_CONTEXT)); + if (lcontext == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_Create.c ++++ b/src/tss2-esys/api/Esys_Create.c +@@ -335,31 +335,31 @@ + + /* Allocate memory for response parameters */ + if (outPrivate != NULL) { +- *outPrivate = calloc(sizeof(TPM2B_PRIVATE), 1); ++ *outPrivate = calloc(1, sizeof(TPM2B_PRIVATE)); + if (*outPrivate == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (outPublic != NULL) { +- *outPublic = calloc(sizeof(TPM2B_PUBLIC), 1); ++ *outPublic = calloc(1, sizeof(TPM2B_PUBLIC)); + if (*outPublic == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (creationData != NULL) { +- *creationData = calloc(sizeof(TPM2B_CREATION_DATA), 1); ++ *creationData = calloc(1, sizeof(TPM2B_CREATION_DATA)); + if (*creationData == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (creationHash != NULL) { +- *creationHash = calloc(sizeof(TPM2B_DIGEST), 1); ++ *creationHash = calloc(1, sizeof(TPM2B_DIGEST)); + if (*creationHash == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (creationTicket != NULL) { +- *creationTicket = calloc(sizeof(TPMT_TK_CREATION), 1); ++ *creationTicket = calloc(1, sizeof(TPMT_TK_CREATION)); + if (*creationTicket == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_CreateLoaded.c ++++ b/src/tss2-esys/api/Esys_CreateLoaded.c +@@ -325,12 +325,12 @@ + return r; + + if (outPrivate != NULL) { +- *outPrivate = calloc(sizeof(TPM2B_PRIVATE), 1); ++ *outPrivate = calloc(1, sizeof(TPM2B_PRIVATE)); + if (*outPrivate == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } +- loutPublic = calloc(sizeof(TPM2B_PUBLIC), 1); ++ loutPublic = calloc(1, sizeof(TPM2B_PUBLIC)); + if (loutPublic == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_CreatePrimary.c ++++ b/src/tss2-esys/api/Esys_CreatePrimary.c +@@ -344,24 +344,24 @@ + if (r != TSS2_RC_SUCCESS) + return r; + +- loutPublic = calloc(sizeof(TPM2B_PUBLIC), 1); ++ loutPublic = calloc(1, sizeof(TPM2B_PUBLIC)); + if (loutPublic == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + if (creationData != NULL) { +- *creationData = calloc(sizeof(TPM2B_CREATION_DATA), 1); ++ *creationData = calloc(1, sizeof(TPM2B_CREATION_DATA)); + if (*creationData == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (creationHash != NULL) { +- *creationHash = calloc(sizeof(TPM2B_DIGEST), 1); ++ *creationHash = calloc(1, sizeof(TPM2B_DIGEST)); + if (*creationHash == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (creationTicket != NULL) { +- *creationTicket = calloc(sizeof(TPMT_TK_CREATION), 1); ++ *creationTicket = calloc(1, sizeof(TPMT_TK_CREATION)); + if (*creationTicket == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_Duplicate.c ++++ b/src/tss2-esys/api/Esys_Duplicate.c +@@ -302,19 +302,19 @@ + + /* Allocate memory for response parameters */ + if (encryptionKeyOut != NULL) { +- *encryptionKeyOut = calloc(sizeof(TPM2B_DATA), 1); ++ *encryptionKeyOut = calloc(1, sizeof(TPM2B_DATA)); + if (*encryptionKeyOut == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (duplicate != NULL) { +- *duplicate = calloc(sizeof(TPM2B_PRIVATE), 1); ++ *duplicate = calloc(1, sizeof(TPM2B_PRIVATE)); + if (*duplicate == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (outSymSeed != NULL) { +- *outSymSeed = calloc(sizeof(TPM2B_ENCRYPTED_SECRET), 1); ++ *outSymSeed = calloc(1, sizeof(TPM2B_ENCRYPTED_SECRET)); + if (*outSymSeed == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_ECC_Parameters.c ++++ b/src/tss2-esys/api/Esys_ECC_Parameters.c +@@ -243,7 +243,7 @@ + + /* Allocate memory for response parameters */ + if (parameters != NULL) { +- *parameters = calloc(sizeof(TPMS_ALGORITHM_DETAIL_ECC), 1); ++ *parameters = calloc(1, sizeof(TPMS_ALGORITHM_DETAIL_ECC)); + if (*parameters == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_ECDH_KeyGen.c ++++ b/src/tss2-esys/api/Esys_ECDH_KeyGen.c +@@ -256,13 +256,13 @@ + + /* Allocate memory for response parameters */ + if (zPoint != NULL) { +- *zPoint = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *zPoint = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*zPoint == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (pubPoint != NULL) { +- *pubPoint = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *pubPoint = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*pubPoint == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_ECDH_ZGen.c ++++ b/src/tss2-esys/api/Esys_ECDH_ZGen.c +@@ -255,7 +255,7 @@ + + /* Allocate memory for response parameters */ + if (outPoint != NULL) { +- *outPoint = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *outPoint = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*outPoint == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_EC_Ephemeral.c ++++ b/src/tss2-esys/api/Esys_EC_Ephemeral.c +@@ -241,7 +241,7 @@ + + /* Allocate memory for response parameters */ + if (Q != NULL) { +- *Q = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *Q = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*Q == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_EncryptDecrypt.c ++++ b/src/tss2-esys/api/Esys_EncryptDecrypt.c +@@ -282,13 +282,13 @@ + + /* Allocate memory for response parameters */ + if (outData != NULL) { +- *outData = calloc(sizeof(TPM2B_MAX_BUFFER), 1); ++ *outData = calloc(1, sizeof(TPM2B_MAX_BUFFER)); + if (*outData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (ivOut != NULL) { +- *ivOut = calloc(sizeof(TPM2B_IV), 1); ++ *ivOut = calloc(1, sizeof(TPM2B_IV)); + if (*ivOut == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_EncryptDecrypt2.c ++++ b/src/tss2-esys/api/Esys_EncryptDecrypt2.c +@@ -276,13 +276,13 @@ + + /* Allocate memory for response parameters */ + if (outData != NULL) { +- *outData = calloc(sizeof(TPM2B_MAX_BUFFER), 1); ++ *outData = calloc(1, sizeof(TPM2B_MAX_BUFFER)); + if (*outData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (ivOut != NULL) { +- *ivOut = calloc(sizeof(TPM2B_IV), 1); ++ *ivOut = calloc(1, sizeof(TPM2B_IV)); + if (*ivOut == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_EventSequenceComplete.c ++++ b/src/tss2-esys/api/Esys_EventSequenceComplete.c +@@ -277,7 +277,7 @@ + + /* Allocate memory for response parameters */ + if (results != NULL) { +- *results = calloc(sizeof(TPML_DIGEST_VALUES), 1); ++ *results = calloc(1, sizeof(TPML_DIGEST_VALUES)); + if (*results == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_FieldUpgradeData.c ++++ b/src/tss2-esys/api/Esys_FieldUpgradeData.c +@@ -243,13 +243,13 @@ + + /* Allocate memory for response parameters */ + if (nextDigest != NULL) { +- *nextDigest = calloc(sizeof(TPMT_HA), 1); ++ *nextDigest = calloc(1, sizeof(TPMT_HA)); + if (*nextDigest == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (firstDigest != NULL) { +- *firstDigest = calloc(sizeof(TPMT_HA), 1); ++ *firstDigest = calloc(1, sizeof(TPMT_HA)); + if (*firstDigest == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_FirmwareRead.c ++++ b/src/tss2-esys/api/Esys_FirmwareRead.c +@@ -239,7 +239,7 @@ + + /* Allocate memory for response parameters */ + if (fuData != NULL) { +- *fuData = calloc(sizeof(TPM2B_MAX_BUFFER), 1); ++ *fuData = calloc(1, sizeof(TPM2B_MAX_BUFFER)); + if (*fuData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_GetCapability.c ++++ b/src/tss2-esys/api/Esys_GetCapability.c +@@ -261,7 +261,7 @@ + + /* Allocate memory for response parameters */ + if (capabilityData != NULL) { +- *capabilityData = calloc(sizeof(TPMS_CAPABILITY_DATA), 1); ++ *capabilityData = calloc(1, sizeof(TPMS_CAPABILITY_DATA)); + if (*capabilityData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_GetCommandAuditDigest.c ++++ b/src/tss2-esys/api/Esys_GetCommandAuditDigest.c +@@ -283,13 +283,13 @@ + + /* Allocate memory for response parameters */ + if (auditInfo != NULL) { +- *auditInfo = calloc(sizeof(TPM2B_ATTEST), 1); ++ *auditInfo = calloc(1, sizeof(TPM2B_ATTEST)); + if (*auditInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_GetRandom.c ++++ b/src/tss2-esys/api/Esys_GetRandom.c +@@ -237,7 +237,7 @@ + + /* Allocate memory for response parameters */ + if (randomBytes != NULL) { +- *randomBytes = calloc(sizeof(TPM2B_DIGEST), 1); ++ *randomBytes = calloc(1, sizeof(TPM2B_DIGEST)); + if (*randomBytes == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_GetSessionAuditDigest.c ++++ b/src/tss2-esys/api/Esys_GetSessionAuditDigest.c +@@ -297,13 +297,13 @@ + + /* Allocate memory for response parameters */ + if (auditInfo != NULL) { +- *auditInfo = calloc(sizeof(TPM2B_ATTEST), 1); ++ *auditInfo = calloc(1, sizeof(TPM2B_ATTEST)); + if (*auditInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_GetTestResult.c ++++ b/src/tss2-esys/api/Esys_GetTestResult.c +@@ -236,7 +236,7 @@ + + /* Allocate memory for response parameters */ + if (outData != NULL) { +- *outData = calloc(sizeof(TPM2B_MAX_BUFFER), 1); ++ *outData = calloc(1, sizeof(TPM2B_MAX_BUFFER)); + if (*outData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_GetTime.c ++++ b/src/tss2-esys/api/Esys_GetTime.c +@@ -281,13 +281,13 @@ + + /* Allocate memory for response parameters */ + if (timeInfo != NULL) { +- *timeInfo = calloc(sizeof(TPM2B_ATTEST), 1); ++ *timeInfo = calloc(1, sizeof(TPM2B_ATTEST)); + if (*timeInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_HMAC.c ++++ b/src/tss2-esys/api/Esys_HMAC.c +@@ -260,7 +260,7 @@ + + /* Allocate memory for response parameters */ + if (outHMAC != NULL) { +- *outHMAC = calloc(sizeof(TPM2B_DIGEST), 1); ++ *outHMAC = calloc(1, sizeof(TPM2B_DIGEST)); + if (*outHMAC == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_Hash.c ++++ b/src/tss2-esys/api/Esys_Hash.c +@@ -260,13 +260,13 @@ + + /* Allocate memory for response parameters */ + if (outHash != NULL) { +- *outHash = calloc(sizeof(TPM2B_DIGEST), 1); ++ *outHash = calloc(1, sizeof(TPM2B_DIGEST)); + if (*outHash == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (validation != NULL) { +- *validation = calloc(sizeof(TPMT_TK_HASHCHECK), 1); ++ *validation = calloc(1, sizeof(TPMT_TK_HASHCHECK)); + if (*validation == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_Import.c ++++ b/src/tss2-esys/api/Esys_Import.c +@@ -283,7 +283,7 @@ + + /* Allocate memory for response parameters */ + if (outPrivate != NULL) { +- *outPrivate = calloc(sizeof(TPM2B_PRIVATE), 1); ++ *outPrivate = calloc(1, sizeof(TPM2B_PRIVATE)); + if (*outPrivate == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_IncrementalSelfTest.c ++++ b/src/tss2-esys/api/Esys_IncrementalSelfTest.c +@@ -243,7 +243,7 @@ + + /* Allocate memory for response parameters */ + if (toDoList != NULL) { +- *toDoList = calloc(sizeof(TPML_ALG), 1); ++ *toDoList = calloc(1, sizeof(TPML_ALG)); + if (*toDoList == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_MAC.c ++++ b/src/tss2-esys/api/Esys_MAC.c +@@ -262,7 +262,7 @@ + + /* Allocate memory for response parameters */ + if (outMAC != NULL) { +- *outMAC = calloc(sizeof(TPM2B_DIGEST), 1); ++ *outMAC = calloc(1, sizeof(TPM2B_DIGEST)); + if (*outMAC == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_MakeCredential.c ++++ b/src/tss2-esys/api/Esys_MakeCredential.c +@@ -264,13 +264,13 @@ + + /* Allocate memory for response parameters */ + if (credentialBlob != NULL) { +- *credentialBlob = calloc(sizeof(TPM2B_ID_OBJECT), 1); ++ *credentialBlob = calloc(1, sizeof(TPM2B_ID_OBJECT)); + if (*credentialBlob == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (secret != NULL) { +- *secret = calloc(sizeof(TPM2B_ENCRYPTED_SECRET), 1); ++ *secret = calloc(1, sizeof(TPM2B_ENCRYPTED_SECRET)); + if (*secret == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_NV_Certify.c ++++ b/src/tss2-esys/api/Esys_NV_Certify.c +@@ -307,13 +307,13 @@ + + /* Allocate memory for response parameters */ + if (certifyInfo != NULL) { +- *certifyInfo = calloc(sizeof(TPM2B_ATTEST), 1); ++ *certifyInfo = calloc(1, sizeof(TPM2B_ATTEST)); + if (*certifyInfo == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_NV_Read.c ++++ b/src/tss2-esys/api/Esys_NV_Read.c +@@ -275,7 +275,7 @@ + + /* Allocate memory for response parameters */ + if (data != NULL) { +- *data = calloc(sizeof(TPM2B_MAX_NV_BUFFER), 1); ++ *data = calloc(1, sizeof(TPM2B_MAX_NV_BUFFER)); + if (*data == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_NV_ReadPublic.c ++++ b/src/tss2-esys/api/Esys_NV_ReadPublic.c +@@ -266,11 +266,11 @@ + esysContext->state = _ESYS_STATE_INTERNALERROR; + + /* Allocate memory for response parameters */ +- lnvPublic = calloc(sizeof(TPM2B_NV_PUBLIC), 1); ++ lnvPublic = calloc(1, sizeof(TPM2B_NV_PUBLIC)); + if (lnvPublic == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +- lnvName = calloc(sizeof(TPM2B_NAME), 1); ++ lnvName = calloc(1, sizeof(TPM2B_NAME)); + if (lnvName == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_ObjectChangeAuth.c ++++ b/src/tss2-esys/api/Esys_ObjectChangeAuth.c +@@ -284,7 +284,7 @@ + + /* Allocate memory for response parameters */ + if (outPrivate != NULL) { +- *outPrivate = calloc(sizeof(TPM2B_PRIVATE), 1); ++ *outPrivate = calloc(1, sizeof(TPM2B_PRIVATE)); + if (*outPrivate == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_PCR_Event.c ++++ b/src/tss2-esys/api/Esys_PCR_Event.c +@@ -259,7 +259,7 @@ + + /* Allocate memory for response parameters */ + if (digests != NULL) { +- *digests = calloc(sizeof(TPML_DIGEST_VALUES), 1); ++ *digests = calloc(1, sizeof(TPML_DIGEST_VALUES)); + if (*digests == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_PCR_Read.c ++++ b/src/tss2-esys/api/Esys_PCR_Read.c +@@ -258,13 +258,13 @@ + + /* Allocate memory for response parameters */ + if (pcrSelectionOut != NULL) { +- *pcrSelectionOut = calloc(sizeof(TPML_PCR_SELECTION), 1); ++ *pcrSelectionOut = calloc(1, sizeof(TPML_PCR_SELECTION)); + if (*pcrSelectionOut == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (pcrValues != NULL) { +- *pcrValues = calloc(sizeof(TPML_DIGEST), 1); ++ *pcrValues = calloc(1, sizeof(TPML_DIGEST)); + if (*pcrValues == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_PolicyGetDigest.c ++++ b/src/tss2-esys/api/Esys_PolicyGetDigest.c +@@ -253,7 +253,7 @@ + + /* Allocate memory for response parameters */ + if (policyDigest != NULL) { +- *policyDigest = calloc(sizeof(TPM2B_DIGEST), 1); ++ *policyDigest = calloc(1, sizeof(TPM2B_DIGEST)); + if (*policyDigest == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_PolicySecret.c ++++ b/src/tss2-esys/api/Esys_PolicySecret.c +@@ -297,13 +297,13 @@ + + /* Allocate memory for response parameters */ + if (timeout != NULL) { +- *timeout = calloc(sizeof(TPM2B_TIMEOUT), 1); ++ *timeout = calloc(1, sizeof(TPM2B_TIMEOUT)); + if (*timeout == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (policyTicket != NULL) { +- *policyTicket = calloc(sizeof(TPMT_TK_AUTH), 1); ++ *policyTicket = calloc(1, sizeof(TPMT_TK_AUTH)); + if (*policyTicket == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_PolicySigned.c ++++ b/src/tss2-esys/api/Esys_PolicySigned.c +@@ -297,13 +297,13 @@ + + /* Allocate memory for response parameters */ + if (timeout != NULL) { +- *timeout = calloc(sizeof(TPM2B_TIMEOUT), 1); ++ *timeout = calloc(1, sizeof(TPM2B_TIMEOUT)); + if (*timeout == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (policyTicket != NULL) { +- *policyTicket = calloc(sizeof(TPMT_TK_AUTH), 1); ++ *policyTicket = calloc(1, sizeof(TPMT_TK_AUTH)); + if (*policyTicket == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_Quote.c ++++ b/src/tss2-esys/api/Esys_Quote.c +@@ -271,13 +271,13 @@ + + /* Allocate memory for response parameters */ + if (quoted != NULL) { +- *quoted = calloc(sizeof(TPM2B_ATTEST), 1); ++ *quoted = calloc(1, sizeof(TPM2B_ATTEST)); + if (*quoted == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_RSA_Decrypt.c ++++ b/src/tss2-esys/api/Esys_RSA_Decrypt.c +@@ -265,7 +265,7 @@ + + /* Allocate memory for response parameters */ + if (message != NULL) { +- *message = calloc(sizeof(TPM2B_PUBLIC_KEY_RSA), 1); ++ *message = calloc(1, sizeof(TPM2B_PUBLIC_KEY_RSA)); + if (*message == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_RSA_Encrypt.c ++++ b/src/tss2-esys/api/Esys_RSA_Encrypt.c +@@ -262,7 +262,7 @@ + + /* Allocate memory for response parameters */ + if (outData != NULL) { +- *outData = calloc(sizeof(TPM2B_PUBLIC_KEY_RSA), 1); ++ *outData = calloc(1, sizeof(TPM2B_PUBLIC_KEY_RSA)); + if (*outData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_ReadClock.c ++++ b/src/tss2-esys/api/Esys_ReadClock.c +@@ -238,7 +238,7 @@ + + /* Allocate memory for response parameters */ + if (currentTime != NULL) { +- *currentTime = calloc(sizeof(TPMS_TIME_INFO), 1); ++ *currentTime = calloc(1, sizeof(TPMS_TIME_INFO)); + if (*currentTime == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_ReadPublic.c ++++ b/src/tss2-esys/api/Esys_ReadPublic.c +@@ -268,19 +268,19 @@ + + /* Allocate memory for response parameters */ + if (outPublic != NULL) { +- *outPublic = calloc(sizeof(TPM2B_PUBLIC), 1); ++ *outPublic = calloc(1, sizeof(TPM2B_PUBLIC)); + if (*outPublic == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (name != NULL) { +- *name = calloc(sizeof(TPM2B_NAME), 1); ++ *name = calloc(1, sizeof(TPM2B_NAME)); + if (*name == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } + } + if (qualifiedName != NULL) { +- *qualifiedName = calloc(sizeof(TPM2B_NAME), 1); ++ *qualifiedName = calloc(1, sizeof(TPM2B_NAME)); + if (*qualifiedName == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_Rewrap.c ++++ b/src/tss2-esys/api/Esys_Rewrap.c +@@ -285,13 +285,13 @@ + + /* Allocate memory for response parameters */ + if (outDuplicate != NULL) { +- *outDuplicate = calloc(sizeof(TPM2B_PRIVATE), 1); ++ *outDuplicate = calloc(1, sizeof(TPM2B_PRIVATE)); + if (*outDuplicate == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (outSymSeed != NULL) { +- *outSymSeed = calloc(sizeof(TPM2B_ENCRYPTED_SECRET), 1); ++ *outSymSeed = calloc(1, sizeof(TPM2B_ENCRYPTED_SECRET)); + if (*outSymSeed == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_SequenceComplete.c ++++ b/src/tss2-esys/api/Esys_SequenceComplete.c +@@ -287,13 +287,13 @@ + + /* Allocate memory for response parameters */ + if (result != NULL) { +- *result = calloc(sizeof(TPM2B_DIGEST), 1); ++ *result = calloc(1, sizeof(TPM2B_DIGEST)); + if (*result == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (validation != NULL) { +- *validation = calloc(sizeof(TPMT_TK_HASHCHECK), 1); ++ *validation = calloc(1, sizeof(TPMT_TK_HASHCHECK)); + if (*validation == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-esys/api/Esys_Sign.c ++++ b/src/tss2-esys/api/Esys_Sign.c +@@ -271,7 +271,7 @@ + + /* Allocate memory for response parameters */ + if (signature != NULL) { +- *signature = calloc(sizeof(TPMT_SIGNATURE), 1); ++ *signature = calloc(1, sizeof(TPMT_SIGNATURE)); + if (*signature == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_Unseal.c ++++ b/src/tss2-esys/api/Esys_Unseal.c +@@ -255,7 +255,7 @@ + + /* Allocate memory for response parameters */ + if (outData != NULL) { +- *outData = calloc(sizeof(TPM2B_SENSITIVE_DATA), 1); ++ *outData = calloc(1, sizeof(TPM2B_SENSITIVE_DATA)); + if (*outData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_Vendor_TCG_Test.c ++++ b/src/tss2-esys/api/Esys_Vendor_TCG_Test.c +@@ -231,7 +231,7 @@ + + /* Allocate memory for response parameters */ + if (outputData != NULL) { +- *outputData = calloc(sizeof(TPM2B_DATA), 1); ++ *outputData = calloc(1, sizeof(TPM2B_DATA)); + if (*outputData == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_VerifySignature.c ++++ b/src/tss2-esys/api/Esys_VerifySignature.c +@@ -262,7 +262,7 @@ + + /* Allocate memory for response parameters */ + if (validation != NULL) { +- *validation = calloc(sizeof(TPMT_TK_VERIFIED), 1); ++ *validation = calloc(1, sizeof(TPMT_TK_VERIFIED)); + if (*validation == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } +--- a/src/tss2-esys/api/Esys_ZGen_2Phase.c ++++ b/src/tss2-esys/api/Esys_ZGen_2Phase.c +@@ -278,13 +278,13 @@ + + /* Allocate memory for response parameters */ + if (outZ1 != NULL) { +- *outZ1 = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *outZ1 = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*outZ1 == NULL) { + return_error(TSS2_ESYS_RC_MEMORY, "Out of memory"); + } + } + if (outZ2 != NULL) { +- *outZ2 = calloc(sizeof(TPM2B_ECC_POINT), 1); ++ *outZ2 = calloc(1, sizeof(TPM2B_ECC_POINT)); + if (*outZ2 == NULL) { + goto_error(r, TSS2_ESYS_RC_MEMORY, "Out of memory", error_cleanup); + } +--- a/src/tss2-fapi/fapi_util.c ++++ b/src/tss2-fapi/fapi_util.c +@@ -2322,7 +2322,7 @@ + context->nv_cmd.data_idx = 0; + + /* Use calloc to ensure zero padding for write buffer. */ +- context->nv_cmd.write_data = calloc(size, 1); ++ context->nv_cmd.write_data = calloc(1, size); + goto_if_null2(context->nv_cmd.write_data, "Out of memory.", r, + TSS2_FAPI_RC_MEMORY, + error_cleanup); +@@ -2762,7 +2762,7 @@ + switch (context->get_random_state) { + statecase(context->get_random_state, GET_RANDOM_INIT); + context->get_random.numBytes = numBytes; +- context->get_random.data = calloc(context->get_random.numBytes, 1); ++ context->get_random.data = calloc(1, context->get_random.numBytes); + context->get_random.idx = 0; + return_if_null(context->get_random.data, "FAPI out of memory.", + TSS2_FAPI_RC_MEMORY); +--- a/src/tss2-fapi/ifapi_io.c ++++ b/src/tss2-fapi/ifapi_io.c +@@ -581,7 +581,7 @@ + closedir(dir); + return_if_error(r, "Out of memory"); + +- NODE_OBJECT_T *file_obj = calloc(sizeof(NODE_OBJECT_T), 1); ++ NODE_OBJECT_T *file_obj = calloc(1, sizeof(NODE_OBJECT_T)); + if (!file_obj) { + LOG_ERROR("Out of memory."); + SAFE_FREE(path); +--- a/src/tss2-fapi/ifapi_policy_callbacks.c ++++ b/src/tss2-fapi/ifapi_policy_callbacks.c +@@ -1132,7 +1132,7 @@ + } + } + /* Extend linked list.*/ +- policy_object = calloc(sizeof(struct POLICY_LIST), 1); ++ policy_object = calloc(1, sizeof(struct POLICY_LIST)); + return_if_null(policy_object, "Out of memory.", TSS2_FAPI_RC_MEMORY); + + strdup_check(policy_object->path, context->fsearch.current_path, r, cleanup); +--- a/src/tss2-fapi/ifapi_policyutil_execute.c ++++ b/src/tss2-fapi/ifapi_policyutil_execute.c +@@ -42,12 +42,12 @@ + IFAPI_POLICY_EXEC_CTX *pol_exec_ctx; + IFAPI_POLICY_EXEC_CB_CTX *pol_exec_cb_ctx; + +- *current_policy = calloc(sizeof(IFAPI_POLICYUTIL_STACK), 1); ++ *current_policy = calloc(1, sizeof(IFAPI_POLICYUTIL_STACK)); + if (!*current_policy) { + return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); + } + +- pol_exec_ctx = calloc(sizeof(IFAPI_POLICY_EXEC_CTX), 1); ++ pol_exec_ctx = calloc(1, sizeof(IFAPI_POLICY_EXEC_CTX)); + if (!pol_exec_ctx) { + SAFE_FREE(*current_policy); + return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); +@@ -73,7 +73,7 @@ + pol_exec_ctx->callbacks.cbaction = ifapi_policy_action; + pol_exec_ctx->callbacks.cbaction_userdata = context; + +- pol_exec_cb_ctx = calloc(sizeof(IFAPI_POLICY_EXEC_CB_CTX), 1); ++ pol_exec_cb_ctx = calloc(1, sizeof(IFAPI_POLICY_EXEC_CB_CTX)); + if (!pol_exec_cb_ctx) { + SAFE_FREE(*current_policy); + return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); +--- a/test/integration/main-fapi.c ++++ b/test/integration/main-fapi.c +@@ -1182,7 +1182,7 @@ + goto error_cleanup; + } + #endif +- *fingerprint = calloc(TPM2_SHA256_DIGEST_SIZE * 2 + 1, 1); ++ *fingerprint = calloc(1, TPM2_SHA256_DIGEST_SIZE * 2 + 1); + if (!(*fingerprint)) { + LOG_ERROR("Failed to allocate fingerprint."); + goto error_cleanup; +@@ -1402,7 +1402,7 @@ + int ret; + + size = sizeof(TSS2_TEST_FAPI_CONTEXT); +- *test_ctx = calloc(size, 1); ++ *test_ctx = calloc(1, size); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for the test context", size); + goto error; diff --git a/debian/patches/0004-tss2-tcti-tcti-libtpms-fix-test-failure-on-big-endia.patch b/debian/patches/0004-tss2-tcti-tcti-libtpms-fix-test-failure-on-big-endia.patch deleted file mode 100644 index 3868e44..0000000 --- a/debian/patches/0004-tss2-tcti-tcti-libtpms-fix-test-failure-on-big-endia.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 9ae85535d6383a50731ad9e70c16b55622e126ae Mon Sep 17 00:00:00 2001 -From: "Ying-Chun Liu (PaulLiu)" -Date: Sun, 6 Aug 2023 05:24:02 +0800 -Subject: [PATCH] tss2-tcti: tcti-libtpms: fix test failure on big-endian - platform - -Due to tcti_libtpms->response_len and tcti_libtpms->response_buffer_len -are size_t. We cannot convert the (size_t *) to (uint32_t *) on big-endian -platforms. Thus we create temp uint32_t variables. Make the call and -then assign it back to size_t variables. - -This commit partially fix the test failure on big-endian platforms. - -Signed-off-by: Ying-Chun Liu (PaulLiu) ---- - src/tss2-tcti/tcti-libtpms.c | 11 +++++++++-- - 1 file changed, 9 insertions(+), 2 deletions(-) - -diff --git a/src/tss2-tcti/tcti-libtpms.c b/src/tss2-tcti/tcti-libtpms.c -index 922a4402..10ed913d 100644 ---- a/src/tss2-tcti/tcti-libtpms.c -+++ b/src/tss2-tcti/tcti-libtpms.c -@@ -370,6 +370,8 @@ tcti_libtpms_transmit( - tpm_header_t header; - TSS2_RC rc; - TPM_RESULT ret; -+ uint32_t resp_size; -+ uint32_t respbufsize; - - rc = tcti_common_transmit_checks(tcti_common, cmd_buf, TCTI_LIBTPMS_MAGIC); - if (rc != TSS2_RC_SUCCESS) { -@@ -386,11 +388,16 @@ tcti_libtpms_transmit( - } - - LOGBLOB_DEBUG(cmd_buf, size, "Sending command with TPM_CC 0x%" PRIx32, header.size); -+ resp_size = (uint32_t) tcti_libtpms->response_len; -+ respbufsize = (uint32_t) tcti_libtpms->response_buffer_len; - LIBTPMS_API_CALL(fail, tcti_libtpms, TPMLIB_Process, &tcti_libtpms->response_buffer, -- (uint32_t *) &tcti_libtpms->response_len, -- (uint32_t *) &tcti_libtpms->response_buffer_len, -+ (uint32_t *) &resp_size, -+ (uint32_t *) &respbufsize, - (uint8_t *) cmd_buf, - size); -+ tcti_libtpms->response_len = resp_size; -+ tcti_libtpms->response_buffer_len = respbufsize; -+ - rc = tcti_libtpms_store_state(tcti_libtpms); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Failed to store state file"); --- -2.40.1 diff --git a/debian/patches/0005-FAPI-Fix-wrong-format-directive-in-ifap_set_auth.patch b/debian/patches/0005-FAPI-Fix-wrong-format-directive-in-ifap_set_auth.patch new file mode 100644 index 0000000..8ff2079 --- /dev/null +++ b/debian/patches/0005-FAPI-Fix-wrong-format-directive-in-ifap_set_auth.patch @@ -0,0 +1,15 @@ +Author: Juergen Repp +Description: FAPI: Fix wrong format directive in ifap_set_auth + %u was used for a 16 bit unsigned integer and %lu for sizeof. +Origin: upstream,commit:4e2fe02fca8409f875a8693ece06b8b5e5baf5ce +--- a/src/tss2-fapi/fapi_util.c ++++ b/src/tss2-fapi/fapi_util.c +@@ -441,7 +441,7 @@ + if (auth != NULL) { + authValue.size = strlen(auth); + if (authValue.size > sizeof(TPMU_HA)) { +- return_error2(TSS2_FAPI_RC_BAD_VALUE, "Size of auth value %u > %lu", ++ return_error2(TSS2_FAPI_RC_BAD_VALUE, "Size of auth value %"PRIu16" > %zu", + authValue.size, sizeof(TPMU_HA)); + } + memcpy(&authValue.buffer[0], auth, authValue.size); diff --git a/debian/patches/0006-test-skip-tcti-spidev-on-32bit-architectures-with-64.patch b/debian/patches/0006-test-skip-tcti-spidev-on-32bit-architectures-with-64.patch new file mode 100644 index 0000000..449ca28 --- /dev/null +++ b/debian/patches/0006-test-skip-tcti-spidev-on-32bit-architectures-with-64.patch @@ -0,0 +1,30 @@ +Author: Luca Boccassi +Description: test: skip tcti-spidev on 32bit architectures with 64bit time_t +Forwarded: https://github.com/tpm2-software/tpm2-tss/pull/2904 +--- a/test/unit/tcti-spidev.c ++++ b/test/unit/tcti-spidev.c +@@ -31,6 +31,11 @@ + #include "tss2-tcti/tcti-spi-helper.h" + #include "util/key-value-parse.h" + ++#define LOGMODULE tests ++#include "util/log.h" ++ ++#define EXIT_SKIP 77 ++ + typedef enum { + TPM_DID_VID_HEAD = 0, + TPM_DID_VID_DATA, +@@ -208,6 +213,12 @@ + main (int argc, + char *argv[]) + { ++#if __SIZEOF_POINTER__ == 4 && _TIME_BITS == 64 ++ // Would produce cmocka error ++ LOG_WARNING("_TIME_BITS == 64 would produce cmocka errors on this platform."); ++ return EXIT_SKIP; ++#endif ++ + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_spi_init_test), + }; diff --git a/debian/patches/0007-incorrect-pointer-casts.patch b/debian/patches/0007-incorrect-pointer-casts.patch new file mode 100644 index 0000000..af1adf7 --- /dev/null +++ b/debian/patches/0007-incorrect-pointer-casts.patch @@ -0,0 +1,39 @@ +Origin: https://github.com/tpm2-software/tpm2-tss/pull/3041 +From: Marcin Serwin +Date: Fri, 9 Jan 2026 19:42:59 +0100 +Subject: test: fix incorrect pointer casts + +When building with cmocka 2.0.1 the tests fail due to stricter type +checks, this patch fixes that. Tested with both cmocka 1.1.8 and 2.0.1. + +``` +test/unit/tcti-libtpms.c:148:5: error: initialization of 'const void *' from 'enum TPMLIB_StateType' makes pointer from integer without a cast [-Wint-conversion] + 148 | check_expected_ptr(st); + | ^~~~~~~~~~~~~~~~~~ +test/unit/tcti-libtpms.c:150:5: error: initialization of 'const void *' from 'uint32_t' {aka 'unsigned int'} makes pointer from integer without a cast [-Wint-conversion] + 150 | check_expected_ptr(buf_len); + | ^~~~~~~~~~~~~~~~~~ +``` + + +Signed-off-by: Marcin Serwin +--- + test/unit/tcti-libtpms.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/unit/tcti-libtpms.c b/test/unit/tcti-libtpms.c +index 7d7247385..d6c07f448 100644 +--- a/test/unit/tcti-libtpms.c ++++ b/test/unit/tcti-libtpms.c +@@ -145,9 +145,9 @@ TPM_RESULT TPMLIB_Process(unsigned char **resp_buf, uint32_t *resp_len, uint32_t + } + TPM_RESULT TPMLIB_SetState(enum TPMLIB_StateType st, const unsigned char *buf, uint32_t buf_len) + { +- check_expected_ptr(st); ++ check_expected(st); + check_expected_ptr(buf); +- check_expected_ptr(buf_len); ++ check_expected(buf_len); + return mock_type(int); + } + void TPMLIB_Terminate(void) diff --git a/debian/patches/CVE-2024-29040.patch b/debian/patches/CVE-2024-29040.patch deleted file mode 100644 index e079b5c..0000000 --- a/debian/patches/CVE-2024-29040.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 710cd0b6adf3a063f34a8e92da46df7a107d9a99 Mon Sep 17 00:00:00 2001 -From: Juergen Repp -Date: Tue, 31 Oct 2023 11:08:41 +0100 -Subject: [PATCH] FAPI: Fix check of magic number in verify quote. - -After deserializing the quote info it was not checked whether -the magic number in the attest is equal TPM2_GENERATED_VALUE. -So an malicious attacker could generate arbitrary quote data -which was not detected by Fapi_VerifyQuote. -Now the number magic number is checket in verify quote and also -in the deserialization of TPM2_GENERATED. -The check is also added to the Unmarshal function for TPMS_ATTEST. - -Fixes: CVE-2024-29040 - -Signed-off-by: Juergen Repp -Signed-off-by: Andreas Fuchs ---- - src/tss2-fapi/api/Fapi_VerifyQuote.c | 5 +++++ - src/tss2-fapi/tpm_json_deserialize.c | 11 +++++++++-- - src/tss2-mu/tpms-types.c | 23 ++++++++++++++++++++++- - 3 files changed, 36 insertions(+), 3 deletions(-) - -diff --git a/src/tss2-fapi/api/Fapi_VerifyQuote.c b/src/tss2-fapi/api/Fapi_VerifyQuote.c -index 8a0e119cc..50474c6bb 100644 ---- a/src/tss2-fapi/api/Fapi_VerifyQuote.c -+++ b/src/tss2-fapi/api/Fapi_VerifyQuote.c -@@ -289,6 +289,11 @@ Fapi_VerifyQuote_Finish( - &command->fapi_quote_info); - goto_if_error(r, "Get quote info.", error_cleanup); - -+ if (command->fapi_quote_info.attest.magic != TPM2_GENERATED_VALUE) { -+ goto_error(r, TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED, -+ "Attest without TPM2 generated value", error_cleanup); -+ } -+ - /* Verify the signature over the attest2b structure. */ - r = ifapi_verify_signature_quote(&key_object, - command->signature, -diff --git a/src/tss2-fapi/tpm_json_deserialize.c b/src/tss2-fapi/tpm_json_deserialize.c -index 4c45458a6..1b27a83fd 100644 ---- a/src/tss2-fapi/tpm_json_deserialize.c -+++ b/src/tss2-fapi/tpm_json_deserialize.c -@@ -698,6 +698,7 @@ ifapi_json_TPM2_GENERATED_deserialize(json_object *jso, TPM2_GENERATED *out) - const char *s = json_object_get_string(jso); - const char *str = strip_prefix(s, "TPM_", "TPM2_", "GENERATED_", NULL); - LOG_TRACE("called for %s parsing %s", s, str); -+ TSS2_RC r; - - if (str) { - for (size_t i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { -@@ -707,8 +708,14 @@ ifapi_json_TPM2_GENERATED_deserialize(json_object *jso, TPM2_GENERATED *out) - } - } - } -- -- return ifapi_json_UINT32_deserialize(jso, out); -+ r = ifapi_json_UINT32_deserialize(jso, out); -+ return_if_error(r, "Could not deserialize UINT32"); -+ if (*out != TPM2_GENERATED_VALUE) { -+ return_error2(TSS2_FAPI_RC_BAD_VALUE, -+ "Value %x not equal TPM self generated value %x", -+ *out, TPM2_GENERATED_VALUE); -+ } -+ return TSS2_RC_SUCCESS; - } - - /** Deserialize a TPM2_ALG_ID json object. -diff --git a/src/tss2-mu/tpms-types.c b/src/tss2-mu/tpms-types.c -index 3ad725203..56aca0c33 100644 ---- a/src/tss2-mu/tpms-types.c -+++ b/src/tss2-mu/tpms-types.c -@@ -22,6 +22,27 @@ - #define VAL - #define TAB_SIZE(tab) (sizeof(tab) / sizeof(tab[0])) - -+static TSS2_RC -+TPM2_GENERATED_Unmarshal( -+ uint8_t const buffer[], -+ size_t buffer_size, -+ size_t *offset, -+ TPM2_GENERATED *magic) -+{ -+ TPM2_GENERATED mymagic = 0; -+ TSS2_RC rc = Tss2_MU_UINT32_Unmarshal(buffer, buffer_size, offset, &mymagic); -+ if (rc != TSS2_RC_SUCCESS) { -+ return rc; -+ } -+ if (mymagic != TPM2_GENERATED_VALUE) { -+ LOG_ERROR("Bad magic in tpms_attest"); -+ return TSS2_SYS_RC_BAD_VALUE; -+ } -+ if (magic != NULL) -+ *magic = mymagic; -+ return TSS2_RC_SUCCESS; -+} -+ - #define TPMS_PCR_MARSHAL(type, firstFieldMarshal) \ - TSS2_RC \ - Tss2_MU_##type##_Marshal(const type *src, uint8_t buffer[], \ -@@ -1219,7 +1240,7 @@ TPMS_MARSHAL_7_U(TPMS_ATTEST, - attested, ADDR, Tss2_MU_TPMU_ATTEST_Marshal) - - TPMS_UNMARSHAL_7_U(TPMS_ATTEST, -- magic, Tss2_MU_UINT32_Unmarshal, -+ magic, TPM2_GENERATED_Unmarshal, - type, Tss2_MU_TPM2_ST_Unmarshal, - qualifiedSigner, Tss2_MU_TPM2B_NAME_Unmarshal, - extraData, Tss2_MU_TPM2B_DATA_Unmarshal, diff --git a/debian/patches/disable-tests-on-big-endian.patch b/debian/patches/disable-tests-on-big-endian.patch index 68a3670..ab4a9ba 100644 --- a/debian/patches/disable-tests-on-big-endian.patch +++ b/debian/patches/disable-tests-on-big-endian.patch @@ -8,34 +8,10 @@ Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1040521 Forwarded: not-needed Last-Update: 2023-08-22 --- ---- tpm2-tss-4.0.1.orig/test/unit/fapi-eventlog.c -+++ tpm2-tss-4.0.1/test/unit/fapi-eventlog.c -@@ -8,6 +8,7 @@ - #include - #endif - -+#include - #include - #include - #include -@@ -168,6 +169,7 @@ int - main(int argc, char *argv[]) - { - const struct CMUnitTest tests[] = { -+# if __BYTE_ORDER == __LITTLE_ENDIAN - cmocka_unit_test(check_bios_nuc), - cmocka_unit_test(check_bios_pc_client), - cmocka_unit_test(check_event_uefiservices), -@@ -175,6 +177,7 @@ main(int argc, char *argv[]) - cmocka_unit_test(check_event_uefivar), - cmocka_unit_test(check_event), - cmocka_unit_test(check_specid_vendordata), -+# endif - }; - return cmocka_run_group_tests(tests, NULL, NULL); - } ---- tpm2-tss-4.0.1.orig/test/unit/fapi-ima-eventlog.c -+++ tpm2-tss-4.0.1/test/unit/fapi-ima-eventlog.c +Index: tpm2-tss/test/unit/fapi-ima-eventlog.c +=================================================================== +--- tpm2-tss.orig/test/unit/fapi-ima-eventlog.c ++++ tpm2-tss/test/unit/fapi-ima-eventlog.c @@ -8,6 +8,7 @@ #include #endif diff --git a/debian/patches/esys-add-SM4-algorithm-support.patch b/debian/patches/esys-add-SM4-algorithm-support.patch deleted file mode 100644 index 516e20b..0000000 --- a/debian/patches/esys-add-SM4-algorithm-support.patch +++ /dev/null @@ -1,687 +0,0 @@ -From 0288dda4cec03e39a89f48333702a9301fb1ce80 Mon Sep 17 00:00:00 2001 -From: mayuanchen <94815698+mayuanchenma@users.noreply.github.com> -Date: Fri, 25 Nov 2022 18:59:26 +0800 -Subject: [PATCH 1/4] esys: add SM4 algorithm support. - -Signed-off-by: mayuanchen <94815698+mayuanchenma@users.noreply.github.com> -Change-Id: I63f61888b92dcf06fb921aec08b40ca00c40ecdf ---- - configure.ac | 3 + - include/tss2/tss2_esys.h | 54 ++++++++++ - src/tss2-esys/esys_crypto.c | 53 ++++++++++ - src/tss2-esys/esys_crypto.h | 23 +++++ - src/tss2-esys/esys_crypto_mbed.h | 2 + - src/tss2-esys/esys_crypto_ossl.c | 158 +++++++++++++++++++++++++++++ - src/tss2-esys/esys_crypto_ossl.h | 29 ++++++ - src/tss2-esys/esys_iutil.c | 66 +++++++++++- - test/integration/esys-crypto.int.c | 6 ++ - test/unit/esys-crypto.c | 62 +++++++++++ - 10 files changed, 454 insertions(+), 2 deletions(-) - -diff --git a/configure.ac b/configure.ac -index b655027..f6c254a 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -191,6 +191,9 @@ AS_IF([test "x$enable_esys" = xyes], - AC_CHECK_LIB(crypto,[EVP_sm3], [ - AC_DEFINE([HAVE_EVP_SM3], [1], [Support EVP_sm3 in openssl])], - []) -+ AC_CHECK_LIB(crypto, [EVP_sm4_cfb128], [ -+ AC_DEFINE([HAVE_EVP_SM4_CFB], [1], [Support EVP_sm4_cfb in openssl])], -+ []) - TSS2_ESYS_CFLAGS_CRYPTO="$CRYPTO_CFLAGS" - TSS2_ESYS_LDFLAGS_CRYPTO="$CRYPTO_LIBS" - ], [test "x$with_crypto" = xmbed], [ -diff --git a/include/tss2/tss2_esys.h b/include/tss2/tss2_esys.h -index 6ef910e..6641f8d 100644 ---- a/include/tss2/tss2_esys.h -+++ b/include/tss2/tss2_esys.h -@@ -315,6 +315,58 @@ typedef TSS2_RC - uint8_t *iv, - void *userdata); - -+/** Encrypt data with SM4. -+ * -+ * @param[in] key key used for SM4. -+ * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). -+ * @param[in] key_bits Key size in bits. -+ * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). -+ * For parameter encryption only CFB can be used. -+ * @param[in,out] buffer Data to be encrypted. The encrypted date will be stored -+ * in this buffer. -+ * @param[in] buffer_size size of data to be encrypted. -+ * @param[in] iv The initialization vector. -+ * @param[in/out] userdata information. -+ * @retval TSS2_RC_SUCCESS on success -+ * @retval USER_DEFINED user defined errors on failure. -+ */ -+typedef TSS2_RC -+ (*ESYS_CRYPTO_SM4_ENCRYPT_FNP)( -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *buffer, -+ size_t buffer_size, -+ uint8_t *iv, -+ void *userdata); -+ -+/** Decrypt data with SM4. -+ * -+ * @param[in] key key used for SM4. -+ * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). -+ * @param[in] key_bits Key size in bits. -+ * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). -+ * For parameter encryption only CFB can be used. -+ * @param[in,out] buffer Data to be decrypted. The decrypted date will be stored -+ * in this buffer. -+ * @param[in] buffer_size size of data to be encrypted. -+ * @param[in] iv The initialization vector. -+ * @param[in/out] userdata information. -+ * @retval TSS2_RC_SUCCESS on success -+ * @retval USER_DEFINED user defined errors on failure. -+ */ -+typedef TSS2_RC -+ (*ESYS_CRYPTO_SM4_DECRYPT_FNP)( -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *buffer, -+ size_t buffer_size, -+ uint8_t *iv, -+ void *userdata); -+ - /** Encryption of a buffer using a public (RSA) key. - * - * Encrypting a buffer using a public key is used for example during -@@ -367,6 +419,8 @@ struct ESYS_CRYPTO_CALLBACKS { - ESYS_CRYPTO_GET_ECDH_POINT_FNP get_ecdh_point; - ESYS_CRYPTO_AES_ENCRYPT_FNP aes_encrypt; - ESYS_CRYPTO_AES_DECRYPT_FNP aes_decrypt; -+ ESYS_CRYPTO_SM4_ENCRYPT_FNP sm4_encrypt; -+ ESYS_CRYPTO_SM4_DECRYPT_FNP sm4_decrypt; - ESYS_CRYPTO_INIT_FNP init; - void *userdata; - }; -diff --git a/src/tss2-esys/esys_crypto.c b/src/tss2-esys/esys_crypto.c -index e54c95c..8cfc97a 100644 ---- a/src/tss2-esys/esys_crypto.c -+++ b/src/tss2-esys/esys_crypto.c -@@ -280,6 +280,46 @@ TSS2_RC iesys_crypto_aes_decrypt( - iv); - } - -+TSS2_RC iesys_crypto_sm4_encrypt( -+ ESYS_CRYPTO_CALLBACKS *crypto_cb, -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *buffer, -+ size_t buffer_size, -+ uint8_t *iv) -+{ -+ DO_CALLBACK(sm4_encrypt, -+ key, -+ tpm_sym_alg, -+ key_bits, -+ tpm_mode, -+ buffer, -+ buffer_size, -+ iv); -+} -+ -+TSS2_RC iesys_crypto_sm4_decrypt( -+ ESYS_CRYPTO_CALLBACKS *crypto_cb, -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *buffer, -+ size_t buffer_size, -+ uint8_t *iv) -+{ -+ DO_CALLBACK(sm4_decrypt, -+ key, -+ tpm_sym_alg, -+ key_bits, -+ tpm_mode, -+ buffer, -+ buffer_size, -+ iv); -+} -+ - /** Compute the command or response parameter hash. - * - * These hashes are needed for the computation of the HMAC used for the -@@ -782,6 +822,8 @@ TSS2_RC - crypto_cb->userdata = NULL; - crypto_cb->aes_decrypt = _iesys_crypto_aes_decrypt; - crypto_cb->aes_encrypt = _iesys_crypto_aes_encrypt; -+ crypto_cb->sm4_decrypt = _iesys_crypto_sm4_decrypt; -+ crypto_cb->sm4_encrypt = _iesys_crypto_sm4_encrypt; - crypto_cb->get_ecdh_point = _iesys_crypto_get_ecdh_point; - crypto_cb->hash_abort = _iesys_crypto_hash_abort; - crypto_cb->hash_finish = _iesys_crypto_hash_finish; -@@ -799,6 +841,17 @@ TSS2_RC - - TEST_AND_SET_CALLBACK(crypto_cb, user_cb, aes_decrypt); - TEST_AND_SET_CALLBACK(crypto_cb, user_cb, aes_encrypt); -+ // sm4 is optional -+ if (user_cb->sm4_encrypt) { -+ crypto_cb->sm4_encrypt = user_cb->sm4_encrypt; -+ } else { -+ crypto_cb->sm4_encrypt = _iesys_crypto_sm4_encrypt; -+ } -+ if (user_cb->sm4_decrypt) { -+ crypto_cb->sm4_decrypt = user_cb->sm4_decrypt; -+ } else { -+ crypto_cb->sm4_decrypt = _iesys_crypto_sm4_decrypt; -+ } - TEST_AND_SET_CALLBACK(crypto_cb, user_cb, get_ecdh_point); - TEST_AND_SET_CALLBACK(crypto_cb, user_cb, get_random2b); - TEST_AND_SET_CALLBACK(crypto_cb, user_cb, rsa_pk_encrypt); -diff --git a/src/tss2-esys/esys_crypto.h b/src/tss2-esys/esys_crypto.h -index 8798bc6..c6efac1 100644 ---- a/src/tss2-esys/esys_crypto.h -+++ b/src/tss2-esys/esys_crypto.h -@@ -16,6 +16,8 @@ - #else - #define _iesys_crypto_aes_decrypt NULL; - #define _iesys_crypto_aes_encrypt NULL; -+#define _iesys_crypto_sm4_decrypt NULL; -+#define _iesys_crypto_sm4_encrypt NULL; - #define _iesys_crypto_get_ecdh_point NULL; - #define _iesys_crypto_hash_abort NULL; - #define _iesys_crypto_hash_finish NULL; -@@ -35,6 +37,7 @@ extern "C" { - #endif - - #define AES_BLOCK_SIZE_IN_BYTES 16 -+#define SM4_BLOCK_SIZE_IN_BYTES 16 - - TSS2_RC iesys_crypto_hash_get_digest_size(TPM2_ALG_ID hashAlg, size_t *size); - -@@ -163,6 +166,26 @@ TSS2_RC iesys_crypto_aes_decrypt( - size_t buffer_size, - uint8_t *iv); - -+TSS2_RC iesys_crypto_sm4_encrypt( -+ ESYS_CRYPTO_CALLBACKS *crypto_cb, -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *buffer, -+ size_t buffer_size, -+ uint8_t *iv); -+ -+TSS2_RC iesys_crypto_sm4_decrypt( -+ ESYS_CRYPTO_CALLBACKS *crypto_cb, -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *buffer, -+ size_t buffer_size, -+ uint8_t *iv); -+ - TSS2_RC iesys_crypto_authHmac( - ESYS_CRYPTO_CALLBACKS *crypto_cb, - TPM2_ALG_ID alg, -diff --git a/src/tss2-esys/esys_crypto_mbed.h b/src/tss2-esys/esys_crypto_mbed.h -index 24b1d8e..40a976b 100644 ---- a/src/tss2-esys/esys_crypto_mbed.h -+++ b/src/tss2-esys/esys_crypto_mbed.h -@@ -120,6 +120,8 @@ TSS2_RC iesys_cryptmbed_init(void *userdata); - #define _iesys_crypto_get_ecdh_point iesys_cryptmbed_get_ecdh_point - #define _iesys_crypto_aes_encrypt iesys_cryptmbed_sym_aes_encrypt - #define _iesys_crypto_aes_decrypt iesys_cryptmbed_sym_aes_decrypt -+#define _iesys_crypto_sm4_encrypt NULL -+#define _iesys_crypto_sm4_decrypt NULL - - #define _iesys_crypto_init iesys_cryptmbed_init - -diff --git a/src/tss2-esys/esys_crypto_ossl.c b/src/tss2-esys/esys_crypto_ossl.c -index 89d312f..a92ecc4 100644 ---- a/src/tss2-esys/esys_crypto_ossl.c -+++ b/src/tss2-esys/esys_crypto_ossl.c -@@ -1212,6 +1212,164 @@ iesys_cryptossl_sym_aes_decrypt(uint8_t * key, - return r; - } - -+#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) -+/** Encrypt data with SM4. -+ * -+ * @param[in] key key used for SM4. -+ * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). -+ * @param[in] key_bits Key size in bits. -+ * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). -+ * For parameter encryption only CFB can be used. -+ * @param[in,out] buffer Data to be encrypted. The encrypted date will be stored -+ * in this buffer. -+ * @param[in] buffer_size size of data to be encrypted. -+ * @param[in] iv The initialization vector. -+ * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and -+ * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters, -+ * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library. -+ */ -+TSS2_RC -+iesys_cryptossl_sym_sm4_encrypt(uint8_t * key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t * buffer, -+ size_t buffer_size, -+ uint8_t * iv, -+ void *userdata) -+{ -+ UNUSED(userdata); -+ -+ TSS2_RC r = TSS2_RC_SUCCESS; -+ const EVP_CIPHER *cipher_alg = NULL; -+ EVP_CIPHER_CTX *ctx = NULL; -+ int cipher_len; -+ -+ if (key == NULL || buffer == NULL) { -+ return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Bad reference"); -+ } -+ -+ LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 input"); -+ -+ if (key_bits == 128 && tpm_mode == TPM2_ALG_CFB) -+ cipher_alg = EVP_sm4_cfb128(); -+ else { -+ goto_error(r, TSS2_ESYS_RC_BAD_VALUE, -+ "SM4 algorithm not implemented or illegal mode (CFB expected).", -+ cleanup); -+ } -+ -+ if (tpm_sym_alg != TPM2_ALG_SM4) { -+ goto_error(r, TSS2_ESYS_RC_BAD_VALUE, -+ "SM4 encrypt called with wrong algorithm.", cleanup); -+ } -+ -+ /* Create and initialize the context */ -+ if(!(ctx = EVP_CIPHER_CTX_new())) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, -+ "Initialize cipher context", cleanup); -+ } -+ -+ if (1 != EVP_EncryptInit(ctx, cipher_alg, key, iv)) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, -+ "Initialize cipher operation", cleanup); -+ } -+ -+ /* Perform the encryption */ -+ if (1 != EVP_EncryptUpdate(ctx, buffer, &cipher_len, buffer, buffer_size)) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt update", cleanup); -+ } -+ -+ if (1 != EVP_EncryptFinal(ctx, buffer, &cipher_len)) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt final", cleanup); -+ } -+ LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 output"); -+ -+cleanup: -+ -+ OSSL_FREE(ctx,EVP_CIPHER_CTX); -+ -+ return r; -+} -+ -+/** Decrypt data with SM4. -+ * -+ * @param[in] key key used for SM4. -+ * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). -+ * @param[in] key_bits Key size in bits. -+ * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). -+ * For parameter encryption only CFB can be used. -+ * @param[in,out] buffer Data to be decrypted. The decrypted date will be stored -+ * in this buffer. -+ * @param[in] buffer_size size of data to be encrypted. -+ * @param[in] iv The initialization vector. -+ * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and -+ * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters, -+ * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library. -+ */ -+TSS2_RC -+iesys_cryptossl_sym_sm4_decrypt(uint8_t * key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t * buffer, -+ size_t buffer_size, -+ uint8_t * iv, -+ void *userdata) -+{ -+ UNUSED(userdata); -+ -+ TSS2_RC r = TSS2_RC_SUCCESS; -+ const EVP_CIPHER *cipher_alg = NULL; -+ EVP_CIPHER_CTX *ctx = NULL; -+ int cipher_len = 0; -+ -+ if (key == NULL || buffer == NULL) { -+ return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Bad reference"); -+ } -+ -+ if (tpm_sym_alg != TPM2_ALG_SM4) { -+ goto_error(r, TSS2_ESYS_RC_BAD_VALUE, -+ "SM4 decrypt called with wrong algorithm.", cleanup); -+ } -+ -+ if (key_bits == 128 && tpm_mode == TPM2_ALG_CFB) -+ cipher_alg = EVP_sm4_cfb128(); -+ else { -+ goto_error(r, TSS2_ESYS_RC_BAD_VALUE, -+ "SM4 algorithm not implemented or illegal mode (CFB expected).", -+ cleanup); -+ } -+ -+ /* Create and initialize the context */ -+ if(!(ctx = EVP_CIPHER_CTX_new())) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, -+ "Initialize cipher context", cleanup); -+ } -+ -+ LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 input"); -+ -+ if (1 != EVP_DecryptInit(ctx, cipher_alg, key, iv)) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, -+ "Initialize cipher operation", cleanup); -+ } -+ -+ /* Perform the decryption */ -+ if (1 != EVP_DecryptUpdate(ctx, buffer, &cipher_len, buffer, buffer_size)) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt update", cleanup); -+ } -+ -+ if (1 != EVP_DecryptFinal(ctx, buffer, &cipher_len)) { -+ goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt final", cleanup); -+ } -+ LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 output"); -+ -+cleanup: -+ -+ OSSL_FREE(ctx,EVP_CIPHER_CTX); -+ return r; -+} -+#endif - - /** Initialize OpenSSL crypto backend. - * -diff --git a/src/tss2-esys/esys_crypto_ossl.h b/src/tss2-esys/esys_crypto_ossl.h -index ae3c33a..d8e84d6 100644 ---- a/src/tss2-esys/esys_crypto_ossl.h -+++ b/src/tss2-esys/esys_crypto_ossl.h -@@ -109,6 +109,28 @@ TSS2_RC iesys_cryptossl_sym_aes_decrypt( - uint8_t *iv, - void *userdata); - -+#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) -+TSS2_RC iesys_cryptossl_sym_sm4_encrypt( -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *dst, -+ size_t dst_size, -+ uint8_t *iv, -+ void *userdata); -+ -+TSS2_RC iesys_cryptossl_sym_sm4_decrypt( -+ uint8_t *key, -+ TPM2_ALG_ID tpm_sym_alg, -+ TPMI_SM4_KEY_BITS key_bits, -+ TPM2_ALG_ID tpm_mode, -+ uint8_t *dst, -+ size_t dst_size, -+ uint8_t *iv, -+ void *userdata); -+#endif -+ - TSS2_RC iesys_cryptossl_get_ecdh_point( - TPM2B_PUBLIC *key, - size_t max_out_size, -@@ -122,6 +144,13 @@ TSS2_RC iesys_cryptossl_get_ecdh_point( - #define _iesys_crypto_get_ecdh_point iesys_cryptossl_get_ecdh_point - #define _iesys_crypto_aes_encrypt iesys_cryptossl_sym_aes_encrypt - #define _iesys_crypto_aes_decrypt iesys_cryptossl_sym_aes_decrypt -+#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) -+#define _iesys_crypto_sm4_encrypt iesys_cryptossl_sym_sm4_encrypt -+#define _iesys_crypto_sm4_decrypt iesys_cryptossl_sym_sm4_decrypt -+#else -+#define _iesys_crypto_sm4_encrypt NULL -+#define _iesys_crypto_sm4_decrypt NULL -+#endif - - TSS2_RC iesys_cryptossl_init(void *userdata); - -diff --git a/src/tss2-esys/esys_iutil.c b/src/tss2-esys/esys_iutil.c -index c8346b3..79e6143 100644 ---- a/src/tss2-esys/esys_iutil.c -+++ b/src/tss2-esys/esys_iutil.c -@@ -745,6 +745,31 @@ iesys_encrypt_param(ESYS_CONTEXT * esys_context, - &encrypt_buffer[0], paramSize, - &symKey[aes_off]); - return_if_error(r, "AES encryption not possible"); -+ } else if (symDef->algorithm == TPM2_ALG_SM4) { -+ /* SM4 encryption with key derived with KDFa */ -+ if (symDef->mode.sm4 != TPM2_ALG_CFB) { -+ return_error(TSS2_ESYS_RC_BAD_VALUE, -+ "Invalid symmetric mode (must be CFB)"); -+ } -+ r = iesys_crypto_KDFa(&esys_context->crypto_backend, rsrc_session->authHash, -+ &rsrc_session->sessionValue[0], -+ rsrc_session->sizeSessionValue, "CFB", -+ &rsrc_session->nonceCaller, -+ &rsrc_session->nonceTPM, -+ symDef->keyBits.sm4 + SM4_BLOCK_SIZE_IN_BYTES * 8, -+ NULL, &symKey[0], FALSE); -+ return_if_error(r, "while computing KDFa"); -+ -+ size_t sm4_off = ( symDef->keyBits.sm4 + 7) / 8; -+ r = iesys_crypto_sm4_encrypt( -+ &esys_context->crypto_backend, -+ &symKey[0], -+ symDef->algorithm, -+ symDef->keyBits.sm4, -+ symDef->mode.sm4, -+ &encrypt_buffer[0], paramSize, -+ &symKey[sm4_off]); -+ return_if_error(r, "SM4 encryption not possible"); - } - /* XOR obfuscation of parameter */ - else if (symDef->algorithm == TPM2_ALG_XOR) { -@@ -760,7 +785,7 @@ iesys_encrypt_param(ESYS_CONTEXT * esys_context, - - } else { - return_error(TSS2_ESYS_RC_BAD_VALUE, -- "Invalid symmetric algorithm (should be XOR or AES)"); -+ "Invalid symmetric algorithm (should be XOR, AES, or SM4)"); - } - r = Tss2_Sys_SetDecryptParam(esys_context->sys, paramSize, - &encrypt_buffer[0]); -@@ -848,6 +873,43 @@ iesys_decrypt_param(ESYS_CONTEXT * esys_context) - &symKey[aes_off]); - return_if_error(r, "Decryption error"); - -+ r = Tss2_Sys_SetEncryptParam(esys_context->sys, p2BSize, &plaintext[0]); -+ return_if_error(r, "Setting plaintext"); -+ } else if (symDef->algorithm == TPM2_ALG_SM4) { -+ /* Parameter decryption with a symmetric SM4 key derived by KDFa */ -+ if (symDef->mode.sm4 != TPM2_ALG_CFB) { -+ return_error(TSS2_ESYS_RC_BAD_VALUE, -+ "Invalid symmetric mode (must be CFB)"); -+ } -+ LOGBLOB_DEBUG(&rsrc_session->sessionKey.buffer[0], -+ rsrc_session->sessionKey.size, -+ "IESYS encrypt session key"); -+ -+ r = iesys_crypto_KDFa(&esys_context->crypto_backend, rsrc_session->authHash, -+ &rsrc_session->sessionValue[0], -+ rsrc_session->sizeSessionValue, -+ "CFB", &rsrc_session->nonceTPM, -+ &rsrc_session->nonceCaller, -+ symDef->keyBits.sm4 -+ + SM4_BLOCK_SIZE_IN_BYTES * 8, NULL, -+ &symKey[0], FALSE); -+ return_if_error(r, "KDFa error"); -+ LOGBLOB_DEBUG(&symKey[0], -+ ((symDef->keyBits.sm4 + -+ SM4_BLOCK_SIZE_IN_BYTES * 8) + 7) / 8, -+ "IESYS encrypt KDFa key"); -+ -+ size_t sm4_off = ( symDef->keyBits.sm4 + 7) / 8; -+ r = iesys_crypto_sm4_decrypt( -+ &esys_context->crypto_backend, -+ &symKey[0], -+ symDef->algorithm, -+ symDef->keyBits.sm4, -+ symDef->mode.sm4, -+ &plaintext[0], p2BSize, -+ &symKey[sm4_off]); -+ return_if_error(r, "Decryption error"); -+ - r = Tss2_Sys_SetEncryptParam(esys_context->sys, p2BSize, &plaintext[0]); - return_if_error(r, "Setting plaintext"); - } else if (symDef->algorithm == TPM2_ALG_XOR) { -@@ -866,7 +928,7 @@ iesys_decrypt_param(ESYS_CONTEXT * esys_context) - return_if_error(r, "Setting plaintext"); - } else { - return_error(TSS2_ESYS_RC_BAD_VALUE, -- "Invalid symmetric algorithm (should be XOR or AES)"); -+ "Invalid symmetric algorithm (should be XOR, AES, or SM4)"); - } - return TSS2_RC_SUCCESS; - } -diff --git a/test/integration/esys-crypto.int.c b/test/integration/esys-crypto.int.c -index 1618e9c..7969f54 100644 ---- a/test/integration/esys-crypto.int.c -+++ b/test/integration/esys-crypto.int.c -@@ -61,6 +61,8 @@ test_invoke_esys(ESYS_CONTEXT *esys_context) - - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_decrypt); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_encrypt); -+ CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_decrypt); -+ CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_encrypt); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_ecdh_point); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_random2b); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, rsa_pk_encrypt); -@@ -68,6 +70,8 @@ test_invoke_esys(ESYS_CONTEXT *esys_context) - ESYS_CRYPTO_CALLBACKS callbacks = { - .aes_decrypt = TEST_FN_PTR, - .aes_encrypt = TEST_FN_PTR, -+ .sm4_decrypt = TEST_FN_PTR, -+ .sm4_encrypt = TEST_FN_PTR, - .get_ecdh_point = TEST_FN_PTR, - .get_random2b = TEST_FN_PTR, - .rsa_pk_encrypt = TEST_FN_PTR, -@@ -123,6 +127,8 @@ test_invoke_esys(ESYS_CONTEXT *esys_context) - - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_decrypt); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_encrypt); -+ CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_decrypt); -+ CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_encrypt); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_ecdh_point); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_random2b); - CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, rsa_pk_encrypt); -diff --git a/test/unit/esys-crypto.c b/test/unit/esys-crypto.c -index b47cfdd..4901b91 100644 ---- a/test/unit/esys-crypto.c -+++ b/test/unit/esys-crypto.c -@@ -258,6 +258,61 @@ check_aes_encrypt(void **state) - assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); - } - -+#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) -+static void -+check_sm4_encrypt(void **state) -+{ -+ TSS2_RC rc; -+ uint8_t key[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; -+ uint8_t buffer[5] = { 1, 2, 3, 4, 5 }; -+ size_t size = sizeof(buffer); -+ -+ ESYS_CRYPTO_CALLBACKS crypto_cb = { 0 }; -+ rc = iesys_initialize_crypto_backend(&crypto_cb, NULL); -+ assert_int_equal (rc, TSS2_RC_SUCCESS); -+ -+ rc = iesys_crypto_sm4_encrypt(&crypto_cb, NULL, TPM2_ALG_SM4, 128, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_REFERENCE); -+ -+ rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], 0, 128, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); -+ -+ rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, 0, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); -+ -+ rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 999, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); -+ -+ rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_RC_SUCCESS); -+ -+ rc = iesys_crypto_sm4_decrypt(&crypto_cb, NULL, TPM2_ALG_SM4, 128, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_REFERENCE); -+ -+ rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], 0, 128, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); -+ -+ rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, 0, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); -+ -+ rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 999, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); -+ -+ rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, TPM2_ALG_CFB, -+ &buffer[0], size, &key[0]); -+ assert_int_equal (rc, TSS2_RC_SUCCESS); -+} -+#endif -+ - static void - check_free(void **state) - { -@@ -320,6 +375,8 @@ static void test_backend_set(void **state) { - - CHECK_BACKEND_FN(crypto_cb, aes_decrypt); - CHECK_BACKEND_FN(crypto_cb, aes_encrypt); -+ CHECK_BACKEND_FN(crypto_cb, sm4_decrypt); -+ CHECK_BACKEND_FN(crypto_cb, sm4_encrypt); - CHECK_BACKEND_FN(crypto_cb, get_ecdh_point); - CHECK_BACKEND_FN(crypto_cb, get_random2b); - CHECK_BACKEND_FN(crypto_cb, rsa_pk_encrypt); -@@ -328,6 +385,8 @@ static void test_backend_set(void **state) { - ESYS_CRYPTO_CALLBACKS user_cb = { - .aes_decrypt = (void *)0xBADCC0DE, - .aes_encrypt = (void *)0xBADCC0DE, -+ .sm4_decrypt = (void *)0xBADCC0DE, -+ .sm4_encrypt = (void *)0xBADCC0DE, - .get_ecdh_point = (void *)0xBADCC0DE, - .get_random2b = (void *)0xBADCC0DE, - .rsa_pk_encrypt = (void *)0xBADCC0DE, -@@ -377,6 +436,9 @@ main(int argc, char *argv[]) - cmocka_unit_test(check_random), - cmocka_unit_test(check_pk_encrypt), - cmocka_unit_test(check_aes_encrypt), -+#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) -+ cmocka_unit_test(check_sm4_encrypt), -+#endif - cmocka_unit_test(check_free), - cmocka_unit_test(check_get_sys_context), - cmocka_unit_test(test_backend_set) --- -2.17.1 - diff --git a/debian/patches/fix-tcti-spi-helper-big-endian.patch b/debian/patches/fix-tcti-spi-helper-big-endian.patch deleted file mode 100644 index 2778c78..0000000 --- a/debian/patches/fix-tcti-spi-helper-big-endian.patch +++ /dev/null @@ -1,29 +0,0 @@ -Description: uint32_t is converted to a void* buffer. - We need to convert it back to the correct endianess. -Author: Lukas Märdian -Forwarded: https://github.com/tpm2-software/tpm2-tss/pull/2686 -Bug: https://github.com/tpm2-software/tpm2-tss/issues/2531 -Bug-Ubuntu: https://bugs.launchpad.net/bugs/2031020 -Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1040521 -Last-Update: 2023-08-22 ---- ---- tpm2-tss-4.0.1.orig/src/tss2-tcti/tcti-spi-helper.c -+++ tpm2-tss-4.0.1/src/tss2-tcti/tcti-spi-helper.c -@@ -2,6 +2,8 @@ - /* - * Copyright 2020 Fraunhofer SIT. All rights reserved. - */ -+#define _BSD_SOURCE -+#include - #include - #include - #include -@@ -312,7 +314,7 @@ static uint32_t spi_tpm_helper_read_sts_ - { - uint32_t status = 0; - spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_STS_REG, &status, sizeof(status)); -- return status; -+ return le32toh(status); - } - - static void spi_tpm_helper_write_sts_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint32_t status) diff --git a/debian/patches/series b/debian/patches/series index 0eafbec..4c69260 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,10 +1,9 @@ 0001_disable_fapi_io_test.patch 0002-fix-version.patch -0003-test-unit-tcti-libtpms-fix-test-failed-at-32-bit-pla.patch -0004-tss2-tcti-tcti-libtpms-fix-test-failure-on-big-endia.patch -fix-tcti-spi-helper-big-endian.patch disable-tests-on-big-endian.patch -esys-add-SM4-algorithm-support.patch +0004-ESYS-FAPI-Fix-order-of-calloc-parameters.patch +0005-FAPI-Fix-wrong-format-directive-in-ifap_set_auth.patch +0006-test-skip-tcti-spidev-on-32bit-architectures-with-64.patch +0007-incorrect-pointer-casts.patch add-ecc-encrypt-decrypt-support.patch add-support-for-udev-to-create-tcm-de.patch -CVE-2024-29040.patch diff --git a/debian/rules b/debian/rules index a4dbd2f..b37667a 100755 --- a/debian/rules +++ b/debian/rules @@ -1,5 +1,7 @@ #!/usr/bin/make -f +export DEB_BUILD_MAINT_OPTIONS = optimize=-lto + DB2MAN = /usr/share/sgml/docbook/stylesheet/xsl/docbook-xsl/manpages/docbook.xsl XP = xsltproc -''-nonet -''-param man.charmap.use.subset "0" @@ -34,3 +36,14 @@ tpmclient.1: debian/tpmclient.xml tpmtest.1: debian/tpmtest.xml $(XP) $(DB2MAN) $< + +execute_after_dh_gencontrol: + # debian/files will not exist until dh_gencontrol has ran at least once. + # The list of libraries is everchanging, so generate the dependency lists + # automatically at build time. + tsslibs=$$(grep -E 'libtss2-*' ./debian/files | grep -v -e 'dbgsym' -e 'libtss2-dev' -e 'libtss2-meta' -e 'libtss2-doc' | tr '_' ' ' | awk '{ print $$1,"(=",$$2 ")" }' | paste -sd ',' - | sed -e 's/,/, /g'); \ + dh_gencontrol -p libtss2-dev -p tpm2-tss -- -V"libtss2:All=$${tsslibs}" + +override_dh_installsystemd: + dh_installsystemd -X tpm-udev.path --no-start --no-stop-on-upgrade + dh_installsystemd -X tpm-udev.service diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml new file mode 100644 index 0000000..2f81407 --- /dev/null +++ b/debian/salsa-ci.yml @@ -0,0 +1,7 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml + +variables: + SALSA_CI_DISABLE_BLHC: 1 diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 0000000..c28ebf0 --- /dev/null +++ b/debian/source/options @@ -0,0 +1,2 @@ +# These are in git but not in the source tarball, ignore to avoid build failures on salsa-ci +extend-diff-ignore = "(^|/)(.*\.vcxproj|.*\.sln)$" diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 0000000..dc780bc --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,10 @@ +Tests: testsuite +Restrictions: allow-stderr +Depends: @, + @builddeps@, + iproute2, + procps, + swtpm-tools, + swtpm, + tpm-udev, + udev, diff --git a/debian/tests/testsuite b/debian/tests/testsuite new file mode 100644 index 0000000..196d8c6 --- /dev/null +++ b/debian/tests/testsuite @@ -0,0 +1,9 @@ +#!/bin/sh + +set -e +set -x + +LIBDL_LDFLAGS="-ldl" ./bootstrap +./configure --enable-unit --enable-integration --enable-tcti-swtpm + +make -j$(nproc) check diff --git a/debian/tpm-udev.install b/debian/tpm-udev.install new file mode 100644 index 0000000..b05e1e7 --- /dev/null +++ b/debian/tpm-udev.install @@ -0,0 +1,4 @@ +etc/tmpfiles.d/tpm2-tss-fapi.conf usr/lib/tmpfiles.d/ +etc/sysusers.d/tpm2-tss.conf usr/lib/sysusers.d/ +etc/tpm2-tss/fapi-config.json +etc/tpm2-tss/fapi-profiles/P_*.json diff --git a/debian/tpm-udev.path b/debian/tpm-udev.path new file mode 100644 index 0000000..8bcbb73 --- /dev/null +++ b/debian/tpm-udev.path @@ -0,0 +1,9 @@ +[Unit] +ConditionVirtualization=container +Description=Handle dynamically added tpm devices + +[Path] +PathChanged=/dev + +[Install] +WantedBy=paths.target diff --git a/debian/tpm-udev.postinst b/debian/tpm-udev.postinst new file mode 100644 index 0000000..67b694a --- /dev/null +++ b/debian/tpm-udev.postinst @@ -0,0 +1,25 @@ +#!/bin/sh + +set -e + +#DEBHELPER# + +case "$1" in + configure) + # ask udev to check for new udev rules (and fix device permissions) + if udevadm --version > /dev/null; then + udevadm control --reload-rules ||: + udevadm trigger --sysname-match="tpm[0-9]*" ||: + udevadm trigger --action=add --subsystem-match=tpm ||: + udevadm trigger --action=add --subsystem-match=tpmrm ||: + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac diff --git a/debian/tpm-udev.service b/debian/tpm-udev.service new file mode 100644 index 0000000..7474c9d --- /dev/null +++ b/debian/tpm-udev.service @@ -0,0 +1,5 @@ +[Unit] +Description=Handle dynamically added tpm devices + +[Service] +ExecStart=systemd-tmpfiles --create tpm-udev.conf diff --git a/debian/tpm-udev.tmpfiles b/debian/tpm-udev.tmpfiles new file mode 100644 index 0000000..3199526 --- /dev/null +++ b/debian/tpm-udev.tmpfiles @@ -0,0 +1,4 @@ +# Handle tpm mode and owers in containers +z /dev/tpm[0-9]* 0660 tss root +z /dev/tpmrm[0-9]* 0660 tss tss +d /var/lib/tpm 0755 tss tss diff --git a/debian/tpm-udev.udev b/debian/tpm-udev.udev new file mode 100644 index 0000000..e023629 --- /dev/null +++ b/debian/tpm-udev.udev @@ -0,0 +1,4 @@ +# tpm devices can only be accessed by the tss user but the tss +# group members can access tpmrm devices +KERNEL=="tpm[0-9]*", TAG+="systemd", MODE="0660", OWNER="tss" +KERNEL=="tpmrm[0-9]*", TAG+="systemd", MODE="0660", OWNER="tss", GROUP="tss" diff --git a/dist/fapi-profiles/P_ECCP256SHA256.json b/dist/fapi-profiles/P_ECCP256SHA256.json index b5a3835..cd16508 100644 --- a/dist/fapi-profiles/P_ECCP256SHA256.json +++ b/dist/fapi-profiles/P_ECCP256SHA256.json @@ -10,7 +10,7 @@ "scheme":"TPM2_ALG_ECDSA", "details":{ "hashAlg":"TPM2_ALG_SHA256" - }, + } }, "sym_mode":"TPM2_ALG_CFB", "sym_parameters": { @@ -21,7 +21,7 @@ "sym_block_size": 16, "pcr_selection": [ { "hash": "TPM2_ALG_SHA1", - "pcrSelect": [ ], + "pcrSelect": [ ] }, { "hash": "TPM2_ALG_SHA256", "pcrSelect": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ] @@ -33,7 +33,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/dist/fapi-profiles/P_ECCP384SHA384.json b/dist/fapi-profiles/P_ECCP384SHA384.json new file mode 100644 index 0000000..b0612e2 --- /dev/null +++ b/dist/fapi-profiles/P_ECCP384SHA384.json @@ -0,0 +1,99 @@ +{ + "type": "TPM2_ALG_ECC", + "nameAlg":"TPM2_ALG_SHA384", + "srk_template": "system,restricted,decrypt,0x81000001", + "srk_description": "Storage root key SRK", + "srk_persistent": 0, + "ek_template": "system,restricted,decrypt,user", + "ek_description": "Endorsement key EK", + "ecc_signing_scheme": { + "scheme":"TPM2_ALG_ECDSA", + "details":{ + "hashAlg":"TPM2_ALG_SHA384" + } + }, + "sym_mode":"TPM2_ALG_CFB", + "sym_parameters": { + "algorithm":"TPM2_ALG_AES", + "keyBits":"256", + "mode":"TPM2_ALG_CFB" + }, + "sym_block_size": 16, + "pcr_selection": [ + { "hash": "TPM2_ALG_SHA1", + "pcrSelect": [ ] + }, + { "hash": "TPM2_ALG_SHA256", + "pcrSelect": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ] + } + ], + "curveID": "TPM2_ECC_NIST_P384", + "session_symmetric":{ + "algorithm":"TPM2_ALG_AES", + "keyBits":"256", + "mode":"TPM2_ALG_CFB" + }, + "ek_policy": { + "description": "Endorsement hierarchy used for policy secret.", + "policy":[ + { + "type": "PolicyOR", + "branches": [ + { + "name": "A", + "description": "", + "policy": [ + { + "type":"POLICYSECRET", + "objectName": "4000000b" + } + ] + }, + { + "name": "B", + "description": "", + "policy": [ + { + "type":"AUTHORIZENV", + "nvPublic": { + "size": 60, + "nvPublic": { + "nvIndex": 29392642, + "nameAlg":"SHA384", + "attributes":{ + "PPWRITE":0, + "OWNERWRITE":0, + "AUTHWRITE":0, + "POLICYWRITE":1, + "POLICY_DELETE":0, + "WRITELOCKED":0, + "WRITEALL":1, + "WRITEDEFINE":0, + "WRITE_STCLEAR":0, + "GLOBALLOCK":0, + "PPREAD":1, + "OWNERREAD":1, + "AUTHREAD":1, + "POLICYREAD":1, + "NO_DA":1, + "ORDERLY":0, + "CLEAR_STCLEAR":0, + "READLOCKED":0, + "WRITTEN":1, + "PLATFORMCREATE":0, + "READ_STCLEAR":0, + "TPM2_NT":"ORDINARY" + }, + "authPolicy":"8bbf2266537c171cb56e403c4dc1d4b64f432611dc386e6f532050c3278c930e143e8bb1133824ccb431053871c6db53", + "dataSize":50 + } + } + + } + ] + } + ] + } + ] + } +} diff --git a/dist/fapi-profiles/P_RSA2048SHA256.json b/dist/fapi-profiles/P_RSA2048SHA256.json index 2423b7b..d64a134 100644 --- a/dist/fapi-profiles/P_RSA2048SHA256.json +++ b/dist/fapi-profiles/P_RSA2048SHA256.json @@ -35,7 +35,6 @@ ], "exponent": 0, "keyBits": 2048, - "session_hash_alg": "TPM2_ALG_SHA256", "session_symmetric":{ "algorithm":"TPM2_ALG_AES", "keyBits":"128", @@ -46,7 +45,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/dist/fapi-profiles/P_RSA3072SHA384.json b/dist/fapi-profiles/P_RSA3072SHA384.json new file mode 100644 index 0000000..50486c4 --- /dev/null +++ b/dist/fapi-profiles/P_RSA3072SHA384.json @@ -0,0 +1,107 @@ +{ + "type": "TPM2_ALG_RSA", + "nameAlg":"TPM2_ALG_SHA384", + "srk_template": "system,restricted,decrypt,0x81000001", + "srk_description": "Storage root key SRK", + "srk_persistent": 1, + "ek_template": "system,restricted,decrypt,user", + "ek_description": "Endorsement key EK", + "rsa_signing_scheme": { + "scheme":"TPM2_ALG_RSAPSS", + "details":{ + "hashAlg":"TPM2_ALG_SHA384" + } + }, + "rsa_decrypt_scheme": { + "scheme":"TPM2_ALG_OAEP", + "details":{ + "hashAlg":"TPM2_ALG_SHA384" + } + }, + "sym_mode":"TPM2_ALG_CFB", + "sym_parameters": { + "algorithm":"TPM2_ALG_AES", + "keyBits":"256", + "mode":"TPM2_ALG_CFB" + }, + "sym_block_size": 16, + "pcr_selection": [ + { "hash": "TPM2_ALG_SHA1", + "pcrSelect": [ ] + }, + { "hash": "TPM2_ALG_SHA256", + "pcrSelect": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ] + } + ], + "exponent": 0, + "keyBits": 3072, + "session_symmetric":{ + "algorithm":"TPM2_ALG_AES", + "keyBits":"256", + "mode":"TPM2_ALG_CFB" + }, + "ek_policy": { + "description": "Endorsement hierarchy used for policy secret.", + "policy":[ + { + "type": "PolicyOR", + "branches": [ + { + "name": "A", + "description": "", + "policy": [ + { + "type":"POLICYSECRET", + "objectName": "4000000b" + } + ] + }, + { + "name": "B", + "description": "", + "policy": [ + { + "type":"AUTHORIZENV", + "nvPublic": { + "size": 60, + "nvPublic": { + "nvIndex": 29392642, + "nameAlg":"SHA384", + "attributes":{ + "PPWRITE":0, + "OWNERWRITE":0, + "AUTHWRITE":0, + "POLICYWRITE":1, + "POLICY_DELETE":0, + "WRITELOCKED":0, + "WRITEALL":1, + "WRITEDEFINE":0, + "WRITE_STCLEAR":0, + "GLOBALLOCK":0, + "PPREAD":1, + "OWNERREAD":1, + "AUTHREAD":1, + "POLICYREAD":1, + "NO_DA":1, + "ORDERLY":0, + "CLEAR_STCLEAR":0, + "READLOCKED":0, + "WRITTEN":1, + "PLATFORMCREATE":0, + "READ_STCLEAR":0, + "TPM2_NT":"ORDINARY" + }, + "authPolicy":"8bbf2266537c171cb56e403c4dc1d4b64f432611dc386e6f532050c3278c930e143e8bb1133824ccb431053871c6db53", + "dataSize":50 + } + } + + } + ] + } + ] + } + ] + } + +} diff --git a/dist/tmpfiles.d/tpm2-tss-fapi.conf.in b/dist/tmpfiles.d/tpm2-tss-fapi.conf.in index 7ea3c65..51ff78e 100644 --- a/dist/tmpfiles.d/tpm2-tss-fapi.conf.in +++ b/dist/tmpfiles.d/tpm2-tss-fapi.conf.in @@ -3,5 +3,5 @@ d @localstatedir@/lib/tpm2-tss/system/keystore 2775 tss tss - a+ @localstatedir@/lib/tpm2-tss/system/keystore - - - - default:group:tss:rwx d @runstatedir@/tpm2-tss/eventlog 2775 tss tss - - a+ @runstatedir@/tpm2-tss/eventlog - - - - default:group:tss:rwx -z /sys/kernel/security/tpm[0-9]/binary_bios_measurements 0440 root tss - - -z /sys/kernel/security/ima/binary_runtime_measurements 0440 root tss - - +z- /sys/kernel/security/tpm[0-9]/binary_bios_measurements 0440 root tss - - +z- /sys/kernel/security/ima/binary_runtime_measurements 0440 root tss - - diff --git a/doc/branching_strategy.md b/doc/branching_strategy.md new file mode 100644 index 0000000..99aab86 --- /dev/null +++ b/doc/branching_strategy.md @@ -0,0 +1,305 @@ +# Branching Strategy + +This document is purely for educational purposes to better understand the +rational behind when new release branches are created and how and when patches +are applied to them. + +Several senarios are covered to help the reader understand when new release get +created from existing branches versus when new releases get created from new +branches. + +## NB + +The version numbers used in this document are for example +purposes only, please see offical guidance for that the current +supported branches are. + +## References + +- https://trunkbaseddevelopment.com/branch-for-release/ + +## Basic release flow + +No users, no bugs, just incrementing off main branch + +```mermaid +graph TD + subgraph users[Users] + user_a[User A] + user_b[User B] + end + + subgraph source_branches[Branches in Git repo] + subgraph main_history + a27dbae3[a27dbae3 - feat] + e13eb557[e13eb557 - fix] + d18973ae[d18973ae - feat] + main[Current HEAD of main] + + a27dbae3 --> e13eb557 + e13eb557 --> d18973ae + d18973ae --> main + end + end + + subgraph release_tags[Release tags] + subgraph release_tag_branch_1_x[Release tags from 1.x branch] + subgraph release_tag_branch_1_0_x[Release tags from 1.0.x branch] + 1_0_0[v1.0.0] + 1_0_1[v1.0.1] + end + subgraph release_tag_branch_1_1_x[Release tags from 1.1.x branch] + 1_1_0[v1.1.0] + end + end + end + + subgraph release_branches[Release branches] + subgraph release_branch_1_x[Release branch 1.x] + subgraph release_branch_1_0_x[Release branch 1.0.x] + release_branch_1_0_x_a27dbae3[a27dbae3] + release_branch_1_0_x_e13eb557[e13eb557] + + release_branch_1_0_x_a27dbae3 --> release_branch_1_0_x_e13eb557 + + release_branch_1_0_x_a27dbae3 --> 1_0_0 + release_branch_1_0_x_e13eb557 --> 1_0_1 + end + + subgraph release_branch_1_1_x[Release branch 1.1.x] + release_branch_1_1_x_d18973ae[d18973ae] + + release_branch_1_0_x_e13eb557 --> release_branch_1_1_x_d18973ae + + release_branch_1_1_x_d18973ae --> 1_1_0 + end + end + end + + 1_0_1 --> user_a + 1_1_0 --> user_b + + a27dbae3 --> release_branch_1_0_x_a27dbae3 + e13eb557 --> release_branch_1_0_x_e13eb557 + d18973ae --> release_branch_1_1_x_d18973ae +``` + +## Bugfix in older supported branch + +Two supported branches. 1.0.x and 1.1.x. User A is using +1.0.1 and finds a bug, the bug is no longer present in main +due to a refactor from introducing a feature (`d18973ae`) causing it +to not have been present in 1.1.0. + +The user reports the bug, we root cause and implement a fix, +we apply the fix to the 1.0.x branch creating tag v1.0.2. + +```mermaid +graph TD + subgraph users[Users] + user_a[User A] + user_b[User B] + end + + subgraph bugs[Bugs] + subgraph null_pointer_dereference[Null Pointer Dereference] + null_pointer_dereference_found_in[Found] + null_pointer_dereference_fix_in[Fixed] + + null_pointer_dereference_found_in --> null_pointer_dereference_fix_in + end + end + + subgraph source_branches[Branches in Git repo] + subgraph main_history + a27dbae3[a27dbae3 - feat] + e13eb557[e13eb557 - fix] + d18973ae[d18973ae - feat] + main[Current HEAD of main] + + a27dbae3 --> e13eb557 + e13eb557 --> d18973ae + d18973ae --> main + end + end + + subgraph release_tags[Release tags] + subgraph release_tag_branch_1_0_x[Release tags from 1.0.x branch] + 1_0_0[v1.0.0] + 1_0_1[v1.0.1] + 1_0_2[v1.0.2] + end + subgraph release_tag_branch_1_1_x[Release tags from 1.1.x branch] + 1_1_0[v1.1.0] + end + end + + subgraph release_branches[Release branches] + subgraph release_branch_1_0_x[Release branch 1.0.x] + release_branch_1_0_x_a27dbae3[a27dbae3] + release_branch_1_0_x_e13eb557[e13eb557] + release_branch_1_0_x_g47ae21d[g47ae21d] + + release_branch_1_0_x_a27dbae3 --> release_branch_1_0_x_e13eb557 + release_branch_1_0_x_e13eb557 --> release_branch_1_0_x_g47ae21d + + release_branch_1_0_x_a27dbae3 --> 1_0_0 + release_branch_1_0_x_e13eb557 --> 1_0_1 + release_branch_1_0_x_g47ae21d --> 1_0_2 + end + + subgraph release_branch_1_1_x[Release branch 1.1.x] + release_branch_1_1_x_d18973ae[d18973ae] + + release_branch_1_0_x_e13eb557 --> release_branch_1_1_x_d18973ae + + release_branch_1_1_x_d18973ae --> 1_1_0 + end + end + + a27dbae3 --> release_branch_1_0_x_a27dbae3 + e13eb557 --> release_branch_1_0_x_e13eb557 + d18973ae --> release_branch_1_1_x_d18973ae + + 1_0_1 -->|Containing null pointer dereference| user_a + 1_1_0 --> user_b + + user_a -->|Using v1.0.1| null_pointer_dereference_found_in + null_pointer_dereference_fix_in --> release_branch_1_0_x_g47ae21d + + 1_0_2 -->|Fix Null Pointer Dereference| user_a +``` + + +## New minor release + +We have two branches we are supporting + +- `1.1.x` is the latest and greatest. We recently saw the `v1.1.0` commit cut + from `main~1` (`d18973ae`). A recent user, User B, has been using this + `v1.1.0` release. + +- `1.0.x` this is our stable release branch. Our initial user, User A, has been + using this `1.0` minor version due to their usage of an unexposed API which + was removed in main during a refactor while introducing a feature + (`d18973ae`). We care about keeping them on as a user and therefore we + continue to support the `1.0` branch. + +User B finds a bug in `v1.1.0` which was determinted to be fixed within the +refactor that happened when we introduced a new feature in the most recent +commit to main (`e7612ba4`). We cannot create a `v1.1.1` because something we +did in the refactor while introducing the latest new feature in main made it so +that we are unable to reproduce the bug. Therefore, we cannot create a fix and +cherry-pick it to the `1.1.x` branch. + +We are faced with a choice about if we want to support yet another one-off +branch for User B, similarly to what we are doing with User A, where we made +them a patch (`g47ae21d`) to fix an issue that was only in the branch their +releases come from (`1.0.x`) and had been resolved in main. Or if we want to cut +a new minor release branch off of main. + +We talk to User B and they inform us they are not using any internal APIs. This +means that both our project and User B understand that when we follow Semantic +Versioning, so long as users stick to exposed API calls, we won't make changes +between minor versions which will break their calling of our exposed APIs. + +We proceed to declare the `1.1.x` branch unsupported, and cut the `1.2.x` +branch off of `main` at `e7612ba4`. User B then updates their usage to pull in +the `v1.2.0` version of our software. + +```mermaid +graph TD + subgraph users[Users] + user_a[User A] + user_b[User B] + end + + subgraph bugs[Bugs] + subgraph null_pointer_dereference[Null Pointer Dereference] + null_pointer_dereference_found_in[Found] + null_pointer_dereference_fix_in[Fixed] + + null_pointer_dereference_found_in --> null_pointer_dereference_fix_in + end + subgraph input_validation[Input Validation] + input_validation_found_in[Found] + end + end + + subgraph source_branches[Branches in Git repo] + subgraph main_history + a27dbae3[a27dbae3 - feat] + e13eb557[e13eb557 - fix] + d18973ae[d18973ae - feat] + e7612ba4[e7612ba4 - feat] + main[Current HEAD of main] + + a27dbae3 --> e13eb557 + e13eb557 --> d18973ae + d18973ae --> e7612ba4 + e7612ba4 --> main + end + end + + subgraph release_tags[Release tags] + subgraph release_tag_branch_1_0_x[Release tags from 1.0.x branch] + 1_0_0[v1.0.0] + 1_0_1[v1.0.1] + 1_0_2[v1.0.2] + end + subgraph release_tag_branch_1_1_x[Release tags from 1.1.x branch] + 1_1_0[v1.1.0] + end + subgraph release_tag_branch_1_2_x[Release tags from 1.2.x branch] + 1_2_0[v1.2.0] + end + end + + subgraph release_branches[Release branches] + subgraph release_branch_1_0_x[Release branch 1.0.x] + release_branch_1_0_x_a27dbae3[a27dbae3] + release_branch_1_0_x_e13eb557[e13eb557] + release_branch_1_0_x_g47ae21d[g47ae21d] + + release_branch_1_0_x_a27dbae3 --> release_branch_1_0_x_e13eb557 + release_branch_1_0_x_e13eb557 --> release_branch_1_0_x_g47ae21d + + release_branch_1_0_x_a27dbae3 --> 1_0_0 + release_branch_1_0_x_e13eb557 --> 1_0_1 + release_branch_1_0_x_g47ae21d --> 1_0_2 + end + + subgraph release_branch_1_1_x[Release branch 1.1.x] + release_branch_1_1_x_d18973ae[d18973ae] + + release_branch_1_0_x_e13eb557 --> release_branch_1_1_x_d18973ae + + release_branch_1_1_x_d18973ae --> 1_1_0 + end + + subgraph release_branch_1_2_x[Release branch 1.2.x] + release_branch_1_2_x_e7612ba4[e7612ba4] + + release_branch_1_1_x_d18973ae --> release_branch_1_2_x_e7612ba4 + e7612ba4 --> release_branch_1_2_x_e7612ba4 + + release_branch_1_2_x_e7612ba4 --> 1_2_0 + end + end + + a27dbae3 --> release_branch_1_0_x_a27dbae3 + e13eb557 --> release_branch_1_0_x_e13eb557 + d18973ae --> release_branch_1_1_x_d18973ae + + 1_0_1 -->|Containing null pointer dereference| user_a + 1_1_0 -->|Containing input validation issue| user_b + + user_a -->|Using v1.0.1| null_pointer_dereference_found_in + null_pointer_dereference_fix_in --> release_branch_1_0_x_g47ae21d + + user_b -->|Using v1.1.0| input_validation_found_in + input_validation_found_in -->|Fixed during refactor from| e7612ba4 + + 1_0_2 -->|Fix Null Pointer Dereference| user_a + 1_2_0 -->|Fix Input Validation issue| user_b +``` diff --git a/doc/doxygen.dox b/doc/doxygen.dox index d716959..1eb06f6 100644 --- a/doc/doxygen.dox +++ b/doc/doxygen.dox @@ -906,7 +906,7 @@ Both the synchronous and asynchronous API are exposed through a single library: \fn TSS2_RC Esys_StartAuthSession_Async(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash) \fn TSS2_RC Esys_StartAuthSession(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) - \fn TSS2_RC Esys_StartAuthSession_Finish(ESYS_CONTEXT *esysContext, ESYS_TR *sessionHandle, TPM2B_NONCE **nonceTPM) + \fn TSS2_RC Esys_StartAuthSession_Finish(ESYS_CONTEXT *esysContext, ESYS_TR *sessionHandle) \} \defgroup Esys_Startup The ESAPI function for the TPM2_Startup command. * ESAPI function to invoke the TPM2_Startup command diff --git a/doc/tcti-i2c-ftdi.md b/doc/tcti-i2c-ftdi.md new file mode 100644 index 0000000..882c655 --- /dev/null +++ b/doc/tcti-i2c-ftdi.md @@ -0,0 +1,61 @@ +# I2C TCTI FTDI + +The I2C TCTI FTDI can be used for communication with an I2C-based TPM over the FTDI MPSSE +USB to I2C bridge. The FTDI module utilizes the `tcti-i2c-helper` library for handling the +PTP I2C protocol and the `libftdi-dev` library for handling the USB to I2C communication. + +Example of a FTDI MPSSE USB to I2C bridge is the product "USB 2.0 Hi-Speed to MPSSE +Cable (SPI/I2C/JTAG master) with +3.3V digital level signals", part no: C232HM-DDHSL-0. +Connect the cable to your TPM as specified in the table below: + +| C232HM-DDHSL-0 | Description | +|--------------------|-------------| +| pin 1, red, VCC | VCC | +| pin 2, orange, SCL | SCL | +| pin 3, yellow, SDA | SDA | +| pin 4, green, SDA | SDA | +| pin 10, black, GND | GND | + +**Important: both yellow and green wires need to be shorted together to create bidirectional data.** + +# EXAMPLES + +Set udev rules for the C232HM-DDHSL-0 cable by creating a file `/etc/udev/rules.d/60-c232hm.rules`: +``` +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", TAG+="uaccess" +``` + +Activate the udev rules: +```console +sudo udevadm control --reload +``` + +You should see the following after plugging in the C232HM-DDHSL-0 cable: +``` +dmesg + [74386.091721] usb 3-2: new high-speed USB device number 18 using xhci_hcd + [74386.439103] usb 3-2: New USB device found, idVendor=0403, idProduct=6014, bcdDevice= 9.00 + [74386.439117] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + [74386.439129] usb 3-2: Product: C232HM-DDHSL-0 + [74386.439140] usb 3-2: Manufacturer: FTDI + [74386.439151] usb 3-2: SerialNumber: FT1UGJKF + [74386.443996] ftdi_sio 3-2:1.0: FTDI USB Serial Device converter detected + [74386.444030] usb 3-2: Detected FT232H + [74386.446370] usb 3-2: FTDI USB Serial Device converter now attached to ttyUSB0 +``` + +Use tcti-i2c-ftdi to communicate with a I2C-based TPM: +```console +tpm2_startup -Ti2c-ftdi -c +tpm2_getrandom -Ti2c-ftdi 8 --hex +``` + +Enable abrmd: +```console +export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --session --print-address --fork` +tpm2-abrmd --allow-root --session --tcti=i2c-ftdi & + +export TPM2TOOLS_TCTI="tabrmd:bus_name=com.intel.tss2.Tabrmd,bus_type=session" +tpm2_startup -c +tpm2_getrandom 8 --hex +``` \ No newline at end of file diff --git a/doc/tcti-i2c-helper.md b/doc/tcti-i2c-helper.md new file mode 100644 index 0000000..5b56db7 --- /dev/null +++ b/doc/tcti-i2c-helper.md @@ -0,0 +1,11 @@ +# I2C TCTI Helper + +The I2C TCTI helper can be used for TPM communication over I2C e.g. in embedded systems. +It uses user supplied methods for I2C and timing operations in order to be platform independent. +These methods are supplied to `Tss2_Tcti_I2c_Helper_Init` via the `TSS2_TCTI_I2C_HELPER_PLATFORM` struct. + +## Platform methods + +Documentation detailing the implementation of platform methods can be found in `tss2_tcti_i2c_helper.h`. +For an example implementation that uses the I2C TCTI helper to communicate with an I2C-based TPM over the +FTDI MPSSE USB to I2C bridge, refer to the `tcti-i2c-ftdi` module. \ No newline at end of file diff --git a/doc/tcti-spi-ftdi.md b/doc/tcti-spi-ftdi.md new file mode 100644 index 0000000..abbe840 --- /dev/null +++ b/doc/tcti-spi-ftdi.md @@ -0,0 +1,60 @@ +# SPI TCTI FTDI + +The SPI TCTI FTDI can be used for communication with a SPI-based TPM over the FTDI MPSSE +USB to SPI bridge. The FTDI module utilizes the `tcti-spi-helper` library for handling the +PTP SPI protocol and the `libftdi-dev` library for handling the USB to SPI communication. + +Example of a FTDI MPSSE USB to SPI bridge is the product "USB 2.0 Hi-Speed to MPSSE +Cable (SPI/I2C/JTAG master) with +3.3V digital level signals", part no: C232HM-DDHSL-0. +Connect the cable to your TPM as specified in the table below: + +| C232HM-DDHSL-0 | Description | +|---------------------|-------------| +| VCC, red, pin 1 | VCC | +| SK, orange, pin 2 | SCLK | +| DO, yellow, pin 3 | MOSI | +| DI, green, pin 4 | MISO | +| CS, brown, pin 5 | CS | +| GND, black, pin 10 | GND | + +# EXAMPLES + +Set udev rules for the C232HM-DDHSL-0 cable by creating a file `/etc/udev/rules.d/60-c232hm.rules`: +``` +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", TAG+="uaccess" +``` + +Activate the udev rules: +```console +sudo udevadm control --reload +``` + +You should see the following after plugging in the C232HM-DDHSL-0 cable: +``` +dmesg + [74386.091721] usb 3-2: new high-speed USB device number 18 using xhci_hcd + [74386.439103] usb 3-2: New USB device found, idVendor=0403, idProduct=6014, bcdDevice= 9.00 + [74386.439117] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + [74386.439129] usb 3-2: Product: C232HM-DDHSL-0 + [74386.439140] usb 3-2: Manufacturer: FTDI + [74386.439151] usb 3-2: SerialNumber: FT1UGJKF + [74386.443996] ftdi_sio 3-2:1.0: FTDI USB Serial Device converter detected + [74386.444030] usb 3-2: Detected FT232H + [74386.446370] usb 3-2: FTDI USB Serial Device converter now attached to ttyUSB0 +``` + +Use tcti-spi-ftdi to communicate with a SPI-based TPM: +```console +tpm2_startup -Tspi-ftdi -c +tpm2_getrandom -Tspi-ftdi 8 --hex +``` + +Enable abrmd: +```console +export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --session --print-address --fork` +tpm2-abrmd --allow-root --session --tcti=spi-ftdi & + +export TPM2TOOLS_TCTI="tabrmd:bus_name=com.intel.tss2.Tabrmd,bus_type=session" +tpm2_startup -c +tpm2_getrandom 8 --hex +``` \ No newline at end of file diff --git a/doc/tcti-spi-helper.md b/doc/tcti-spi-helper.md index 9723b56..21907d7 100644 --- a/doc/tcti-spi-helper.md +++ b/doc/tcti-spi-helper.md @@ -222,7 +222,7 @@ TSS2_TCTI_CONTEXT* create_tcti_ctx() // Get requested TCTI context size rc = Tss2_Tcti_Spi_Helper_Init(NULL, &size, &tcti_platform); if (rc != TSS2_RC_SUCCESS) { - printf("Failed to get allocation size for device tcti context: 0x%x\n", rc); + printf("Failed to get allocation size for device tcti context: 0x%"PRIx32"\n", rc); return NULL; } @@ -236,7 +236,7 @@ TSS2_TCTI_CONTEXT* create_tcti_ctx() // Initialize TCTI context rc = Tss2_Tcti_Spi_Helper_Init(tcti_ctx, &size, &tcti_platform); if (rc != TSS2_RC_SUCCESS) { - printf("Failed to initialize device TCTI context: 0x%x\n", rc); + printf("Failed to initialize device TCTI context: 0x%"PRIx32"\n", rc); free(tcti_ctx); return NULL; } diff --git a/doc/tcti-spi-ltt2go.md b/doc/tcti-spi-ltt2go.md new file mode 100644 index 0000000..1543af6 --- /dev/null +++ b/doc/tcti-spi-ltt2go.md @@ -0,0 +1,48 @@ +# SPI TCTI LTT2GO +The SPI TCTI LTT2GO can be used for communication with LetsTrust-TPM2Go USB TPM. +The LTT2GO module utilizes the `tcti-spi-helper` library for PTP SPI protocol handling +and the `libusb-1.0-0-dev` library for USB communication. + +# EXAMPLES + +Set udev rules for LetsTrust-TPM2Go by creating a file `/etc/udev/rules.d/60-tpm2go.rules`: +``` +ATTRS{idVendor}=="365d", ATTRS{idProduct}=="1337", TAG+="uaccess" +``` + +Activate the udev rules: +```console +sudo udevadm control --reload +``` + +You should see the following after plugging in the LetsTrust-TPM2Go: +``` +dmesg + [ 1019.115823] usb 3-2: new full-speed USB device number 5 using xhci_hcd + [ 1019.480333] usb 3-2: New USB device found, idVendor=365d, idProduct=1337, bcdDevice= 0.00 + [ 1019.480360] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 + [ 1019.480382] usb 3-2: Product: LetsTrust-TPM2Go + [ 1019.480405] usb 3-2: Manufacturer: www.pi3g.com + [ 1019.480426] usb 3-2: SerialNumber: Y23CW29NR00000RND987654321012 + +sudo udevadm info -e | grep LetsTrust + E: ID_MODEL=LetsTrust-TPM2Go + E: ID_MODEL_ENC=LetsTrust-TPM2Go + E: ID_SERIAL=www.pi3g.com_LetsTrust-TPM2Go_Y23CW29NR00000RND987654321012 +``` + +Use tcti-spi-ltt2go to communicate with LetsTrust-TPM2Go: +```console +tpm2_startup -Tspi-ltt2go -c +tpm2_getrandom -Tspi-ltt2go 8 --hex +``` + +Enable abrmd: +```console +export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --session --print-address --fork` +tpm2-abrmd --allow-root --session --tcti=spi-ltt2go & + +export TPM2TOOLS_TCTI="tabrmd:bus_name=com.intel.tss2.Tabrmd,bus_type=session" +tpm2_startup -c +tpm2_getrandom 8 --hex +``` \ No newline at end of file diff --git a/doc/tcti.md b/doc/tcti.md new file mode 100644 index 0000000..cb2d0f9 --- /dev/null +++ b/doc/tcti.md @@ -0,0 +1,417 @@ +# TPM Command Transmission Interface + +- [What is a tcti?](#what-is-a-tcti) +- [tcti Loader](#tcti-loader) + - [Parameters](#parameters) +- [tcti-device](#tcti-device) + - [Parameters](#parameters-1) +- [tcti-tbs](#tcti-tbs) +- [tcti-cmd](#tcti-cmd) + - [Parameters](#parameters-2) +- [tcti-pcap](#tcti-pcap) + - [Parameters](#parameters-3) +- [tcti-spi-ftdi](#tcti-spi-ftdi) +- [tcti-i2c-ftdi](#tcti-i2c-ftdi) +- [tcti-spi-ltt2go](#tcti-spi-ltt2go) +- [tcti-spidev](#tcti-spidev) +- [TPM Simulator tctis](#tpm-simulator-tctis) + - [tcti-libtpms](#tcti-libtpms) + - [Parameters](#parameters-4) + - [tcti-swtpm](#tcti-swtpm) + - [Parameters](#parameters-5) + - [tcti-mssim](#tcti-mssim) + - [Parameters](#parameters-6) + +## What is a tcti? + +In a strict sense, the [TPM Command Transmission Interface +(TCTI)](https://trustedcomputinggroup.org/wp-content/uploads/TCG_TSS_TCTI_v1p0_r18_pub.pdf) +is the API for the lowest layer of the TSS. However, we are a bit sloppy with +our terminology, here, so we will call any library which implements the TCTI +just that: a _tcti_. + +```mermaid +flowchart TD + sapi(SAPI) -->|TCTI API| tcti(tcti) + tcti <-.-> tpm{{TPM}} + style tpm stroke-dasharray: 3, 3 +``` + +For example, the tcti-device is a library (`libtss2-tcti-device.so`) for +interacting with e.g. `/dev/tpmrm0`. + +As you can see in this example, a tcti is responsible for communicating with the +TPM. Typically, it sends TPM commands to the TPM and reads responses from the +TPM (as bytes). The path to `/dev/tpmrm0` is configured via the `conf` parameter +when initializing the tcti. + +```mermaid +flowchart TD + sapi(SAPI) -->|"conf="/dev/tpmrm0"" | tcti_device(tcti-device) + tcti_device -.->|write| tpm{{/dev/tpmrm0}} + tpm -.->|read| tcti_device + style tpm stroke-dasharray: 3, 3 +``` + +## tcti Loader + +Most of the time, you will see that the TCTI is specified via a string, like +`"device:/dev/tpmrm0"` (e.g. with the +[tpm2-tools](https://github.com/tpm2-software/tpm2-tools) argument `--tcti=...` +or the [FAPI config](fapi-config.md) param `"tcti": "..."`). This indicates that +the tcti is loaded dynamically using the tctildr (tcti loader). + +The tctildr is a tcti itself. It dynamically loads and configures +a tcti for you. For instance, it can load tcti-device: + +```mermaid +flowchart TD + invis[ ] -->|"conf="device:/dev/tpmrm0""| tctildr(tctildr) + tctildr -->|"conf="/dev/tpmrm0""| tcti_device(tcti-device) + tcti_device -.->|write| tpm{{/dev/tpmrm0}} + tpm -.->|read| tcti_device + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tpm stroke-dasharray: 3, 3 +``` + +Another example for tcti-swtpm: + +```mermaid +flowchart TD + invis[ ] -->|"conf="swtpm:host=localhost,port=2321""| tctildr(tctildr) + tctildr -->|"conf="host=localhost,port=2321""| tcti_swtpm(tcti-swtpm) + tcti_swtpm <-.->|localhost:2321| tpm{{"swtpm (TPM simulator)"}} + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tpm stroke-dasharray: 3, 3 +``` + +### Parameters + +**`conf`** + +* ``, e.g., `device` (child_conf will be `NULL`) OR +* `:`, e.g., `device:/dev/tpmrm0` OR +* `NULL`, tctildr will attempt to load a child tcti in the following order: + 1. `libtss2-tcti-default.so` + 2. `libtss2-tcti-tabrmd.so` + 3. `libtss2-tcti-device.so.0:/dev/tpmrm0` + 4. `libtss2-tcti-device.so.0:/dev/tpm0` + 5. `libtss2-tcti-device.so.0:/dev/tcm0` + 6. `libtss2-tcti-swtpm.so` + 7. `libtss2-tcti-mssim.so` + +Where: + +**`child_name`** + +* If not empty, tctildr will try to dynamically load the child tcti library in + the following order: + 1. `` + 2. `libtss2-tcti-.so.0` + 3. `libtss2-tcti-.so` + 4. `libtss2-.so.0` + 5. `libtss2-.so` + +**`child_conf`** + + * `conf` param to be passed to the child tcti + +## tcti-device + +To put it simply, tcti-device writes to and reads from a file, typically +`/dev/tpm0` or `/dev/tpmrm0` or `/dev/tcm0`. The character devices are provided by the Linux +kernel module `tpm_tis`. If no files like these are present, verify that the +kernel module is loaded (`lsmod`) and load it if necessary (`modprobe tpm_tis`). + +```mermaid +flowchart TD + invis[ ] -->|"conf="device:/dev/tpmrm0""| tctildr(tctildr) + tctildr -->|"conf="/dev/tpmrm0""| tcti_device(tcti-device) + tcti_device -.->|write| tpm{{/dev/tpmrm0}} + tpm -.->|read| tcti_device + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tpm stroke-dasharray: 3, 3 +``` + +### Parameters + +**`conf`** + +* path to the character device, typically `/dev/tpm0` or `/dev/tpmrm0` or `/dev/tcm0` + +## tcti-tbs + +The tcti-tbs is used for communicating to the TPM via the TPM Base Services +(TBS) on Windows. There might be limitations, especially if you do not have +admin rights. + +```mermaid +flowchart TD + invis[ ] -->|"conf="tbs""| tctildr(tctildr) + tctildr --> tcti_tbs(tcti-tbs) + tcti_tbs <-.->|"Tbsip_Submit_Command()"| tbs{{"TPM Base Services (TBS)"}} + tbs -.- tpm{{TPM}} + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tbs stroke-dasharray: 3, 3 + style tpm stroke-dasharray: 3, 3 +``` + +## tcti-cmd + +The tcti-cmd spawns a process and connects to its `stdin` and `stdout`. This +enables some advanced shenanigans like sending TPM traffic over the network via +ssh. + +The following example makes the TPM communication unnecessary complex, but shows +how tcti-cmd works. Here, commands are piped into `tpm2_send` and responses are +read from its `stdout`. + + +```mermaid +flowchart TD + invis[ ] -->|"conf="cmd:tpm2_send --tcti='device:/dev/tpmrm0'""| tctildr1(tctildr) + tctildr1 -->|"conf="tpm2_send --tcti='device:/dev/tpmrm0'""| tcti_cmd(tcti-cmd) + tcti_cmd -.->|stdin| process{{tpm2_send --tcti='device:/dev/tpmrm0'}} + process -.->|stdout| tcti_cmd + process -->|"conf="device:/dev/tpmrm0""| tctildr2(tctildr) + tctildr2 -->|"conf="/dev/tpmrm0""| tcti_device{{tcti-device}} + tcti_device -.->|write| tpm{{/dev/tpmrm0}} + tpm -.->|read| tcti_device + + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style process stroke-dasharray: 3, 3 + style tpm stroke-dasharray: 3, 3 +``` + +Now for a real-world example. We can communicate with a remote TPM by invoking +`tpm2_send` on another host via `ssh`. + +```mermaid +flowchart TD + invis[ ] -->|"conf="cmd:ssh 192.168.178.123 tpm2_send --tcti='device:/dev/tpmrm0'""| tctildr1(tctildr) + tctildr1 -->|"conf="ssh 192.168.178.123 tpm2_send --tcti='device:/dev/tpmrm0'""| tcti_cmd(tcti-cmd) + tcti_cmd -.->|stdin| ssh{{ssh}} + ssh -.->|stdout| tcti_cmd + + ssh -.-|network| sshd{{sshd}} + sshd -.- process{{tpm2_send -tcti='device:/dev/tpmrm0'}} + process -->|"conf="device:/dev/tpmrm0""| tctildr2(tctildr) + tctildr2 -->|"conf="/dev/tpmrm0""| tcti_device{{tcti-device}} + tcti_device -.->|write| tpm{{/dev/tpmrm0}} + tpm -.->|read| tcti_device + + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style ssh stroke-dasharray: 3, 3 + style sshd stroke-dasharray: 3, 3 + style process stroke-dasharray: 3, 3 + style tpm stroke-dasharray: 3, 3 +``` + +### Parameters + +**`conf`** + +* Command to execute. Actually, `/bin/sh -c ''` will be called. + +## tcti-pcap + +The tcti-pcap is used for logging. It is used by prepending any tctildr conf +string with `pcap:`, e.g. `pcap:device:/dev/tpmrm0`. Then, tcti-pcap will log into +a file specified by the environment variable `TCTI_PCAP_FILE` )(default: +`tpm2_log.pcap`). This file can be opened by e.g. +[wireshark](https://www.wireshark.org/) or +[tpmstream](https://github.com/joholl/tpmstream). + +Internally, tcti-pcap delegates to tctildr, again. + +```mermaid +flowchart TD + invis2[ ] -.->|"TCTI_PCAP_FILE="tpm2_log.pcap""| tcti_pcap + tcti_pcap -.->|logging| file{{tpm2_log.pcap}} + invis[ ] -->|"conf="pcap:device:/dev/tpmrm0""| tctildr1(tctildr) + tctildr1 -->|"conf="device:/dev/tpmrm0""| tcti_pcap(tcti-pcap) + tcti_pcap -->|"conf="device:/dev/tpmrm0""| tctildr2(tctildr) + tctildr2 -->|"conf="/dev/tpmrm0""| tcti_device(tcti-device) + tcti_device -.->|write| tpm{{/dev/tpmrm0}} + tpm -.->|read| tcti_device + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style invis2 fill:#FFFFFF00, stroke:#FFFFFF00; + style file stroke-dasharray: 3, 3 + style tpm stroke-dasharray: 3, 3 +``` + +### Parameters + +**`conf`** + +* `conf` which will be passed to tctildr, e.g. `device:/dev/tpmrm0` + +## tcti-spi-ftdi + +The tcti-spi-ftdi is used for communicating with a SPI-based TPM if there is no +TPM driver present (or no OS at all). + +For information, see [tcti-spi-ftdi.md](tcti-spi-ftdi.md). + +## tcti-i2c-ftdi + +The tcti-i2c-ftdi is used for communicating with a I2C-based TPM if there is no +TPM driver present (or no OS at all). + +For information, see [tcti-i2c-ftdi.md](tcti-i2c-ftdi.md). + +## tcti-spi-ltt2go + +The tcti-spi-ltt2go is used specifically for communicating to the +[LetsTrust-TPM2Go](https://buyzero.de/products/letstrust-tpm2go). The +LetsTrust-TPM2Go is basically a USB stick which houses a SPI-based TPM and +connects that to the host via libusb. + +```mermaid +flowchart TD + invis[ ] -->|"conf="libtpms""| tcti_spi_ltt2go(tcti-spi-ltt2go) + tcti_spi_ltt2go <-.->|libusb| cy7c65211a{{"USB2.0 SPI bridge"}} + cy7c65211a -.-|SPI| tpm{{"TPM"}} + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style cy7c65211a stroke-dasharray: 3, 3 + style tpm stroke-dasharray: 3, 3 +``` + +## tcti-spidev + +The tcti-spidev is used for communicating to a TPM that is connected via +a spidev device. On a Raspberry Pi for example this happens when enabling +the device tree overlay `spi0-cs2`. + +## TPM Simulator tctis + +There are multiple tctis used for testing. + +### tcti-libtpms + +The tcti-libtpms is a simple TPM simulator based on +[libtpms](https://github.com/stefanberger/libtpms), a library implementing TPM +behavior. No second process is needed. + +If no state file is passed via `conf`, all state is held in RAM and discarded +when the process dies. + +```mermaid +flowchart TD + invis[ ] -->|"conf="libtpms""| tctildr(tctildr) + tctildr --> tcti_libtpms(tcti-libtpms) + tcti_libtpms -.->|dynamically loads| tpm{{"libtpms.so (TPM simulator)"}} + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tpm stroke-dasharray: 3, 3 +``` + +If multiple processes need to work on the simulated TPM, state must be saved to +the filesystem and loaded again. This can be achieved by passing a path via +`conf`. + +```mermaid +flowchart TD + invis[ ] -->|"conf="libtpms:tpm_state.libtpms""| tctildr(tctildr) + tctildr -->|"conf="tpm_state.libtpms""| tcti_libtpms(tcti-libtpms) + tcti_libtpms <-.->|loads/saves state| file{{tpm_state.libtpms}} + tcti_libtpms -.->|dynamically loads| tpm{{"libtpms.so (TPM simulator)"}} + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style file stroke-dasharray: 3, 3 + style tpm stroke-dasharray: 3, 3 +``` + +#### Parameters + +**`conf`** + +* Path to a state file. Will be loaded on startup or created if it does not + exist. + +### tcti-swtpm + +The tcti-swtpm connects to [swtpm](https://github.com/stefanberger/swtpm), a TPM +simulator based on [libtpms](https://github.com/stefanberger/libtpms) and socket +communication. + +Just like mssim, there is a primary socket (default: `2321`) used for TPM +commands/responses and a secondary socket (default: `2322`) for controlling the +simulator, here called [control +channel](https://github.com/stefanberger/swtpm/wiki/Control-Channel-Specification). +While the primary socket is identical with that of mssim, the secondary one is +incompatible. + +```mermaid +flowchart TD + invis[ ] -->|"conf="swtpm:host=localhost,port=2321""| tctildr(tctildr) + tctildr -->|"conf="host=localhost,port=2321""| tcti_swtpm(tcti-swtpm) + tcti_swtpm <-.->|TPM commands/responses| port2321{{"localhost:2321"}} + tcti_swtpm <-.->|control channel| port2322{{"localhost:2322"}} + port2321 -.- tpm{{"swtpm (TPM simulator)"}} + port2322 -.- tpm + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tpm stroke-dasharray: 3, 3 + style port2321 stroke-dasharray: 3, 3 + style port2322 stroke-dasharray: 3, 3 +``` + +#### Parameters + +**`conf`** + +* `host=,port=`, e.g., `host=192.168.178.123,port=5000` +* `host=`, e.g., `host=192.168.178.123` +* `port=`, e.g. `port=5000` + +Where: + +**`host`** + + * Hostname or IP address to the simulator, default: `localhost` + +**`port`** + +* Port to the simulator, default: `2321`. The control channel will be ` + 1` + +### tcti-mssim + +The tcti-mssim connects to the Microsoft TPM simulator +[mssim](https://github.com/microsoft/ms-tpm-20-ref), [repackaged by +IBM](https://sourceforge.net/projects/ibmswtpm2/). + +Like with swtpm, there is a primary socket (default: `2321`) used for TPM +commands/responses and a secondary socket (default: `2322`) for sending +so-called *platform commands* which control the simulator. While the primary +socket is identical with that of swtpm, the secondary one is incompatible. + +```mermaid +flowchart TD + invis[ ] -->|"conf="mssim:host=localhost,port=2321""| tctildr(tctildr) + tctildr -->|"conf="host=localhost,port=2321""| tcti_mssim(tcti-mssim) + tcti_mssim <-.->|TPM commands/responses| port2321{{"localhost:2321"}} + tcti_mssim <-.->|platform commands| port2322{{"localhost:2322"}} + port2321 -.- tpm{{"mssim (TPM simulator)"}} + port2322 -.- tpm + style invis fill:#FFFFFF00, stroke:#FFFFFF00; + style tpm stroke-dasharray: 3, 3 + style port2321 stroke-dasharray: 3, 3 + style port2322 stroke-dasharray: 3, 3 +``` + +#### Parameters + +**`conf`** + +* `host=,port=`, e.g., `host=192.168.178.123,port=5000` +* `host=`, e.g., `host=192.168.178.123` +* `port=`, e.g. `port=5000` + +Where: + +**`host`** + + * Hostname or IP address to the simulator, default: `localhost` + +**`port`** + +* Port to the simulator, default: `2321`. The control channel will be ` + + 1` diff --git a/include/tss2/tss2_esys.h b/include/tss2/tss2_esys.h index 6ef910e..ff73842 100644 --- a/include/tss2/tss2_esys.h +++ b/include/tss2/tss2_esys.h @@ -57,6 +57,14 @@ typedef uint32_t ESYS_TR; #define ESYS_TR_RH_ENDORSEMENT 0x10BU #define ESYS_TR_RH_PLATFORM 0x10CU #define ESYS_TR_RH_PLATFORM_NV 0x10DU +#define ESYS_TR_RH_FW_OWNER 0x10EU +#define ESYS_TR_RH_FW_ENDORSEMENT 0x10FU +#define ESYS_TR_RH_FW_PLATFORM 0x110U +#define ESYS_TR_RH_FW_NULL 0x111U +#define ESYS_TR_RH_SVN_OWNER_BASE 0x1010000U +#define ESYS_TR_RH_SVN_ENDORSEMENT_BASE 0x1020000U +#define ESYS_TR_RH_SVN_PLATFORM_BASE 0x1030000U +#define ESYS_TR_RH_SVN_NULL_BASE 0x1040000U #define ESYS_TR_RH_AUTH_FIRST 0x110U #define ESYS_TR_RH_AUTH(x) (ESYS_TR_RH_AUTH_FIRST + (ESYS_TR)(x)) @@ -315,6 +323,58 @@ typedef TSS2_RC uint8_t *iv, void *userdata); +/** Encrypt data with SM4. + * + * @param[in] key key used for SM4. + * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). + * @param[in] key_bits Key size in bits. + * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). + * For parameter encryption only CFB can be used. + * @param[in,out] buffer Data to be encrypted. The encrypted date will be stored + * in this buffer. + * @param[in] buffer_size size of data to be encrypted. + * @param[in] iv The initialization vector. + * @param[in/out] userdata information. + * @retval TSS2_RC_SUCCESS on success + * @retval USER_DEFINED user defined errors on failure. + */ +typedef TSS2_RC + (*ESYS_CRYPTO_SM4_ENCRYPT_FNP)( + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *buffer, + size_t buffer_size, + uint8_t *iv, + void *userdata); + +/** Decrypt data with SM4. + * + * @param[in] key key used for SM4. + * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). + * @param[in] key_bits Key size in bits. + * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). + * For parameter encryption only CFB can be used. + * @param[in,out] buffer Data to be decrypted. The decrypted date will be stored + * in this buffer. + * @param[in] buffer_size size of data to be encrypted. + * @param[in] iv The initialization vector. + * @param[in/out] userdata information. + * @retval TSS2_RC_SUCCESS on success + * @retval USER_DEFINED user defined errors on failure. + */ +typedef TSS2_RC + (*ESYS_CRYPTO_SM4_DECRYPT_FNP)( + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *buffer, + size_t buffer_size, + uint8_t *iv, + void *userdata); + /** Encryption of a buffer using a public (RSA) key. * * Encrypting a buffer using a public key is used for example during @@ -367,6 +427,8 @@ struct ESYS_CRYPTO_CALLBACKS { ESYS_CRYPTO_GET_ECDH_POINT_FNP get_ecdh_point; ESYS_CRYPTO_AES_ENCRYPT_FNP aes_encrypt; ESYS_CRYPTO_AES_DECRYPT_FNP aes_decrypt; + ESYS_CRYPTO_SM4_ENCRYPT_FNP sm4_encrypt; + ESYS_CRYPTO_SM4_DECRYPT_FNP sm4_decrypt; ESYS_CRYPTO_INIT_FNP init; void *userdata; }; diff --git a/include/tss2/tss2_tcti_i2c_ftdi.h b/include/tss2/tss2_tcti_i2c_ftdi.h new file mode 100644 index 0000000..dfb75ea --- /dev/null +++ b/include/tss2/tss2_tcti_i2c_ftdi.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifndef TSS2_TCTI_I2C_FTDI_H +#define TSS2_TCTI_I2C_FTDI_H + +#include +#include "tss2_tcti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +TSS2_RC Tss2_Tcti_I2c_Ftdi_Init ( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + const char *config); + +#ifdef __cplusplus +} +#endif + +#endif /* TSS2_TCTI_I2C_FTDI_H */ diff --git a/include/tss2/tss2_tcti_i2c_helper.h b/include/tss2/tss2_tcti_i2c_helper.h new file mode 100644 index 0000000..7096193 --- /dev/null +++ b/include/tss2/tss2_tcti_i2c_helper.h @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifndef TSS2_TCTI_I2C_HELPER_HELPER_H +#define TSS2_TCTI_I2C_HELPER_HELPER_H + +#include +#include "tss2_tcti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Forward declaration + */ +typedef struct TSS2_TCTI_I2C_HELPER_PLATFORM TSS2_TCTI_I2C_HELPER_PLATFORM; + +/* + * Sleeps for the specified amount of microseconds + */ +typedef TSS2_RC (*TSS2_TCTI_I2C_HELPER_PLATFORM_SLEEP_US_FUNC) (void* user_data, int microseconds); + +/* + * Sleeps for the specified amount of milliseconds + */ +typedef TSS2_RC (*TSS2_TCTI_I2C_HELPER_PLATFORM_SLEEP_MS_FUNC) (void* user_data, int milliseconds); + +/* + * Starts a timeout timer which expires in the specified amount of milliseconds. + * This can be done by storing the expire time (now + milliseconds) in the userdata. + */ +typedef TSS2_RC (*TSS2_TCTI_I2C_HELPER_PLATFORM_START_TIMEOUT_FUNC) (void* user_data, int milliseconds); + +/* + * Returns true if the timeout started previously by START_TIMEOUT_FUNC already has expired, false otherwise. + * This can be done e.g. by comparing the current time and the stored timer expire time. + * This method will be called often when waiting for timeouts and should be fast. + */ +typedef TSS2_RC (*TSS2_TCTI_I2C_HELPER_PLATFORM_TIMEOUT_EXPIRED_FUNC) (void* user_data, bool *result); + +/* + * Writes cnt bytes from data buffer to the I2C slave. + */ +typedef TSS2_RC (*TSS2_TCTI_I2C_HELPER_PLATFORM_I2C_WRITE_FUNC) (void* user_data, uint8_t reg_addr, const void *data, size_t cnt); + +/* + * Reads cnt bytes from the I2C slave to data buffer. + */ +typedef TSS2_RC (*TSS2_TCTI_I2C_HELPER_PLATFORM_I2C_READ_FUNC) (void* user_data, uint8_t reg_addr, void *data, size_t cnt); + +/* + * Is called by Tss2_Tcti_Finalize right before the TCTI context is destroyed and + * should free user_data and all resources inside like e.g. I2C device handles. + */ +typedef void (*TSS2_TCTI_I2C_HELPER_PLATFORM_FINALIZE) (void* user_data); + +/* + * Contains user implemented platform methods for the I2C TCTI. + */ +struct TSS2_TCTI_I2C_HELPER_PLATFORM { + void* user_data; + TSS2_TCTI_I2C_HELPER_PLATFORM_SLEEP_US_FUNC sleep_us; + TSS2_TCTI_I2C_HELPER_PLATFORM_SLEEP_MS_FUNC sleep_ms; + TSS2_TCTI_I2C_HELPER_PLATFORM_START_TIMEOUT_FUNC start_timeout; + TSS2_TCTI_I2C_HELPER_PLATFORM_TIMEOUT_EXPIRED_FUNC timeout_expired; + TSS2_TCTI_I2C_HELPER_PLATFORM_I2C_WRITE_FUNC i2c_write; + TSS2_TCTI_I2C_HELPER_PLATFORM_I2C_READ_FUNC i2c_read; + TSS2_TCTI_I2C_HELPER_PLATFORM_FINALIZE finalize; +}; + +/* + * Initializes the I2C TCTI with a context pointer and platform methods. + * When the tctiContext pointer is NULL, the needed buffer size is written to *size. + * platform_conf contains platform methods implemented by the user for I2C + * communication and timeout handling. + */ +TSS2_RC Tss2_Tcti_I2c_Helper_Init ( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf); + +#ifdef __cplusplus +} +#endif + +#endif /* TSS2_TCTI_I2C_HELPER_HELPER_H */ diff --git a/include/tss2/tss2_tcti_libtpms.h b/include/tss2/tss2_tcti_libtpms.h index b180e00..065cf8d 100644 --- a/include/tss2/tss2_tcti_libtpms.h +++ b/include/tss2/tss2_tcti_libtpms.h @@ -17,6 +17,9 @@ TSS2_RC Tss2_Tcti_Libtpms_Init ( size_t *size, const char *conf); +TSS2_RC +Tss2_Tcti_Libtpms_Reset(TSS2_TCTI_CONTEXT *tctiCont); + #ifdef __cplusplus } #endif diff --git a/include/tss2/tss2_tcti_spi_ftdi.h b/include/tss2/tss2_tcti_spi_ftdi.h new file mode 100644 index 0000000..3843bdb --- /dev/null +++ b/include/tss2/tss2_tcti_spi_ftdi.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifndef TSS2_TCTI_SPI_FTDI_H +#define TSS2_TCTI_SPI_FTDI_H + +#include +#include "tss2_tcti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +TSS2_RC Tss2_Tcti_Spi_Ftdi_Init ( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + const char *config); + +#ifdef __cplusplus +} +#endif + +#endif /* TSS2_TCTI_SPI_FTDI_H */ diff --git a/include/tss2/tss2_tcti_spi_ltt2go.h b/include/tss2/tss2_tcti_spi_ltt2go.h new file mode 100644 index 0000000..012abab --- /dev/null +++ b/include/tss2/tss2_tcti_spi_ltt2go.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2020 Peter Huewe + */ +#ifndef TSS2_TCTI_SPI_LTT2GO_H +#define TSS2_TCTI_SPI_LTT2GO_H + +#include +#include "tss2_tcti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +TSS2_RC Tss2_Tcti_Spi_Ltt2go_Init ( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + const char *config); + + +#ifdef __cplusplus +} +#endif + +#endif /* TSS2_TCTI_SPI_LTT2GO_H */ diff --git a/include/tss2/tss2_tcti_spidev.h b/include/tss2/tss2_tcti_spidev.h new file mode 100644 index 0000000..78fb124 --- /dev/null +++ b/include/tss2/tss2_tcti_spidev.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2023 Infineon Technologies AG + */ +#ifndef TSS2_TCTI_SPIDEV_H +#define TSS2_TCTI_SPIDEV_H + +#include +#include "tss2_tcti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +TSS2_RC Tss2_Tcti_Spidev_Init ( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + const char *config); + + +#ifdef __cplusplus +} +#endif + +#endif /* TSS2_TCTI_SPIDEV_H */ diff --git a/include/tss2/tss2_tctildr.h b/include/tss2/tss2_tctildr.h index 9873038..cf71822 100644 --- a/include/tss2/tss2_tctildr.h +++ b/include/tss2/tss2_tctildr.h @@ -30,6 +30,11 @@ Tss2_TctiLdr_GetInfo (const char *name, void Tss2_TctiLdr_FreeInfo (TSS2_TCTI_INFO **info); +TSS2_RC +Tss2_Tcti_TctiLdr_Init (TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + const char *nameConf); + #ifdef __cplusplus } #endif diff --git a/include/tss2/tss2_tpm2_types.h b/include/tss2/tss2_tpm2_types.h index 1ce737e..f386333 100644 --- a/include/tss2/tss2_tpm2_types.h +++ b/include/tss2/tss2_tpm2_types.h @@ -63,7 +63,9 @@ #define TPM2_PRIVATE_VENDOR_SPECIFIC_BYTES ((TPM2_MAX_RSA_KEY_BYTES / 2) * (3 + 2)) /* Vendor Specific Defines */ +#ifndef DISABLE_VENDOR #define TPM2_MAX_PTT_PROPERTIES (TPM2_MAX_CAP_BUFFER / sizeof(UINT32)) +#endif /* Attached Component Capabilities */ #define TPM2_MAX_AC_CAPABILITIES (TPM2_MAX_CAP_BUFFER / sizeof(TPMS_AC_OUTPUT)) @@ -346,6 +348,8 @@ typedef UINT32 TPM2_RC; #define TPM2_RC_BINDING ((TPM2_RC) (TPM2_RC_FMT1 + 0x025)) /* public and sensitive portions of an object are not cryptographically bound */ #define TPM2_RC_CURVE ((TPM2_RC) (TPM2_RC_FMT1 + 0x026)) /* curve not supported */ #define TPM2_RC_ECC_POINT ((TPM2_RC) (TPM2_RC_FMT1 + 0x027)) /* point is not on the required curve. */ +#define TPM2_RC_FW_LIMITED ((TPM2_RC) (TPM2_RC_FMT1 + 0x028)) /* the command requires the firmware secret but the firmware secret is unavailable */ +#define TPM2_RC_SVN_LIMITED ((TPM2_RC) (TPM2_RC_FMT1 + 0x029)) /* the command requires the firmware SVN secret but the firmware SVN secret is unavailable */ #define TPM2_RC_WARN ((TPM2_RC) 0x900) /* set for warning response codes */ #define TPM2_RC_CONTEXT_GAP ((TPM2_RC) (TPM2_RC_WARN + 0x001)) /* gap for context ID is too large */ #define TPM2_RC_OBJECT_MEMORY ((TPM2_RC) (TPM2_RC_WARN + 0x002)) /* out of memory for object contexts */ @@ -523,6 +527,8 @@ typedef UINT32 TPM2_PT; #define TPM2_PT_NV_BUFFER_MAX ((TPM2_PT) (TPM2_PT_FIXED + 44)) /* the maximum data size in one NV write command */ #define TPM2_PT_MODES ((TPM2_PT) (TPM2_PT_FIXED + 45)) /* a TPMA_MODES value indicating that the TPM is designed for these modes. */ #define TPM2_PT_MAX_CAP_BUFFER ((TPM2_PT) (TPM2_PT_FIXED + 46)) /* the maximum size of a TPMS_CAPABILITY_DATA structure returned in TPM2_GetCapability(). */ +#define TPM_PT_FIRMWARE_SVN ((TPM2_PT) (TPM2_PT_FIXED + 47)) /* the current SVN of the TPM's firmware */ +#define TPM_PT_FIRMWARE_MAX_SVN ((TPM2_PT) (TPM2_PT_FIXED + 48)) /* the maximum value `TPM_PT_FIRMWARE_SVN` may take */ #define TPM2_PT_VAR ((TPM2_PT) (TPM2_PT_GROUP * 2)) /* the group of variable properties returned as TPMS_TAGGED_PROPERTY. The properties in this group change because of a Protected Capability other than a firmware update. The values are not necessarily persistent across all power transitions. */ #define TPM2_PT_PERMANENT ((TPM2_PT) (TPM2_PT_VAR + 0)) /* TPMA_PERMANENT */ #define TPM2_PT_STARTUP_CLEAR ((TPM2_PT) (TPM2_PT_VAR + 1)) /* TPMA_STARTUP_CLEAR */ @@ -650,20 +656,28 @@ typedef TPM2_HANDLE TPM2_RH; #define TPM2_RH_ACT_D ((TPM2_RH) 0x4000011D) #define TPM2_RH_ACT_E ((TPM2_RH) 0x4000011E) #define TPM2_RH_ACT_F ((TPM2_RH) 0x4000011F) /* A P */ -#define TPM2_RH_LAST ((TPM2_RH) 0x4000011F) /* R */ +#define TPM2_RH_FW_OWNER ((TPM2_RH) 0x40000140) /* K */ +#define TPM2_RH_FW_ENDORSEMENT ((TPM2_RH) 0x40000141) /* K */ +#define TPM2_RH_FW_PLATFORM ((TPM2_RH) 0x40000142) /* K */ +#define TPM2_RH_FW_NULL ((TPM2_RH) 0x40000143) /* K */ +#define TPM2_RH_SVN_OWNER_BASE ((TPM2_RH) 0x40010000) /* K */ +#define TPM2_RH_SVN_ENDORSEMENT_BASE ((TPM2_RH) 0x40020000) /* K */ +#define TPM2_RH_SVN_PLATFORM_BASE ((TPM2_RH) 0x40030000) /* K */ +#define TPM2_RH_SVN_NULL_BASE ((TPM2_RH) 0x40040000) /* K */ +#define TPM2_RH_LAST ((TPM2_RH) 0x4004FFFF) /* R */ /* Definition of TPM2_HANDLE TPM2_HC Constants */ typedef TPM2_HANDLE TPM2_HC; #define TPM2_HR_HANDLE_MASK ((TPM2_HC) 0x00FFFFFF) /* to mask off the HR */ #define TPM2_HR_RANGE_MASK ((TPM2_HC) 0xFF000000) /* to mask off the variable part */ #define TPM2_HR_SHIFT ((TPM2_HC) 24) -#define TPM2_HR_PCR ((TPM2_HC) (TPM2_HT_PCR << TPM2_HR_SHIFT)) -#define TPM2_HR_HMAC_SESSION ((TPM2_HC) (TPM2_HT_HMAC_SESSION << TPM2_HR_SHIFT)) -#define TPM2_HR_POLICY_SESSION ((TPM2_HC) (TPM2_HT_POLICY_SESSION << TPM2_HR_SHIFT)) -#define TPM2_HR_TRANSIENT ((TPM2_HC) (TPM2_HT_TRANSIENT << TPM2_HR_SHIFT)) -#define TPM2_HR_PERSISTENT ((TPM2_HC) (TPM2_HT_PERSISTENT << TPM2_HR_SHIFT)) -#define TPM2_HR_NV_INDEX ((TPM2_HC) (TPM2_HT_NV_INDEX << TPM2_HR_SHIFT)) -#define TPM2_HR_PERMANENT ((TPM2_HC) (TPM2_HT_PERMANENT << TPM2_HR_SHIFT)) +#define TPM2_HR_PCR (((TPM2_HC) TPM2_HT_PCR) << TPM2_HR_SHIFT) +#define TPM2_HR_HMAC_SESSION (((TPM2_HC) TPM2_HT_HMAC_SESSION) << TPM2_HR_SHIFT) +#define TPM2_HR_POLICY_SESSION (((TPM2_HC) TPM2_HT_POLICY_SESSION) << TPM2_HR_SHIFT) +#define TPM2_HR_TRANSIENT (((TPM2_HC) TPM2_HT_TRANSIENT) << TPM2_HR_SHIFT) +#define TPM2_HR_PERSISTENT (((TPM2_HC) TPM2_HT_PERSISTENT) << TPM2_HR_SHIFT) +#define TPM2_HR_NV_INDEX (((TPM2_HC) TPM2_HT_NV_INDEX) << TPM2_HR_SHIFT) +#define TPM2_HR_PERMANENT (((TPM2_HC) TPM2_HT_PERMANENT) << TPM2_HR_SHIFT) #define TPM2_PCR_FIRST ((TPM2_HC) (TPM2_HR_PCR + 0)) /* first PCR */ #define TPM2_PCR_LAST ((TPM2_HC) (TPM2_PCR_FIRST + TPM2_MAX_PCRS - 1)) /* last PCR */ #define TPM2_HMAC_SESSION_FIRST ((TPM2_HC) (TPM2_HR_HMAC_SESSION + 0)) /* first HMAC session */ @@ -711,6 +725,8 @@ typedef uint32_t TPMA_OBJECT; #define TPMA_OBJECT_SENSITIVEDATAORIGIN ((TPMA_OBJECT) 0x00000020) /* SET 1 Indicates that when the object was created with TPM2_Create or TPM2_CreatePrimary the TPM generated all of the sensitive data other than the authValue. CLEAR 0 A portion of the sensitive data other than the authValue was provided by the caller. */ #define TPMA_OBJECT_USERWITHAUTH ((TPMA_OBJECT) 0x00000040) /* SET 1 Approval of USER role actions with this object may be with an HMAC session or with a password using the authValue of the object or a policy session. CLEAR 0 Approval of USER role actions with this object may only be done with a policy session. */ #define TPMA_OBJECT_ADMINWITHPOLICY ((TPMA_OBJECT) 0x00000080) /* SET 1 Approval of ADMIN role actions with this object may only be done with a policy session. CLEAR 0 Approval of ADMIN role actions with this object may be with an HMAC session or with a password using the authValue of the object or a policy session. */ +#define TPMA_OBJECT_FIRMWARELIMITED ((TPMA_OBJECT) 0x00000100) /* SET 1 Object is in a firmware-limited hierarchy */ +#define TPMA_OBJECT_SVNLIMITED ((TPMA_OBJECT) 0x00000200) /* SET 1 Object is in an SVN-limited hierarchy */ #define TPMA_OBJECT_RESERVED3_MASK ((TPMA_OBJECT) 0x00000300) /* shall be zero */ #define TPMA_OBJECT_NODA ((TPMA_OBJECT) 0x00000400) /* SET 1 The object is not subject to dictionary attack protections. CLEAR 0 The object is subject to dictionary attack protections. */ #define TPMA_OBJECT_ENCRYPTEDDUPLICATION ((TPMA_OBJECT) 0x00000800) /* SET 1 If the object is duplicated then symmetricAlg shall not be TPM2_ALG_NULL and newParentHandle shall not be TPM2_RH_NULL. CLEAR 0 The object may be duplicated without an inner wrapper on the private portion of the object and the new parent may be TPM2_RH_NULL. */ diff --git a/lib/tss2-tcti-i2c-ftdi.def b/lib/tss2-tcti-i2c-ftdi.def new file mode 100644 index 0000000..0625f9d --- /dev/null +++ b/lib/tss2-tcti-i2c-ftdi.def @@ -0,0 +1,4 @@ +LIBRARY tss2-tcti-i2c-ftdi +EXPORTS + Tss2_Tcti_Info + Tss2_Tcti_I2c_Ftdi_Init diff --git a/lib/tss2-tcti-i2c-ftdi.map b/lib/tss2-tcti-i2c-ftdi.map new file mode 100644 index 0000000..7cff68b --- /dev/null +++ b/lib/tss2-tcti-i2c-ftdi.map @@ -0,0 +1,7 @@ +{ + global: + Tss2_Tcti_Info; + Tss2_Tcti_I2c_Ftdi_Init; + local: + *; +}; diff --git a/lib/tss2-tcti-i2c-ftdi.pc.in b/lib/tss2-tcti-i2c-ftdi.pc.in new file mode 100644 index 0000000..46d2c9b --- /dev/null +++ b/lib/tss2-tcti-i2c-ftdi.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: tss2-tcti-i2c-ftdi +Description: TCTI library for communicating with a TPM over USB-FTDI-I2C converter. +URL: https://github.com/tpm2-software/tpm2-tss +Version: @VERSION@ +Cflags: -I${includedir} -I${includedir}/tss +Libs: -ltss2-tcti-i2c-helper -ltss2-tcti-i2c-ftdi -L${libdir} -lftdi diff --git a/lib/tss2-tcti-i2c-helper.def b/lib/tss2-tcti-i2c-helper.def new file mode 100644 index 0000000..b3f9238 --- /dev/null +++ b/lib/tss2-tcti-i2c-helper.def @@ -0,0 +1,4 @@ +LIBRARY tss2-tcti-i2c-helper +EXPORTS + Tss2_Tcti_Info + Tss2_Tcti_I2c_Helper_Init diff --git a/lib/tss2-tcti-i2c-helper.map b/lib/tss2-tcti-i2c-helper.map new file mode 100644 index 0000000..3927bf0 --- /dev/null +++ b/lib/tss2-tcti-i2c-helper.map @@ -0,0 +1,7 @@ +{ + global: + Tss2_Tcti_Info; + Tss2_Tcti_I2c_Helper_Init; + local: + *; +}; diff --git a/lib/tss2-tcti-i2c-helper.pc.in b/lib/tss2-tcti-i2c-helper.pc.in new file mode 100644 index 0000000..f3033f4 --- /dev/null +++ b/lib/tss2-tcti-i2c-helper.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: tss2-tcti-i2c-helper +Description: TCTI library for communicating with the TPM over I2C. +URL: https://github.com/tpm2-software/tpm2-tss +Version: @VERSION@ +Cflags: -I${includedir} -I${includedir}/tss +Libs: -ltss2-tcti-i2c-helper -L${libdir} diff --git a/lib/tss2-tcti-libtpms.def b/lib/tss2-tcti-libtpms.def index eba207c..563f25e 100644 --- a/lib/tss2-tcti-libtpms.def +++ b/lib/tss2-tcti-libtpms.def @@ -2,3 +2,4 @@ LIBRARY tss2-tcti-libtpms EXPORTS Tss2_Tcti_Info Tss2_Tcti_Libtpms_Init + Tss2_Tcti_Libtpms_Reset diff --git a/lib/tss2-tcti-libtpms.map b/lib/tss2-tcti-libtpms.map index ba62e1f..e9c406b 100644 --- a/lib/tss2-tcti-libtpms.map +++ b/lib/tss2-tcti-libtpms.map @@ -2,6 +2,7 @@ global: Tss2_Tcti_Info; Tss2_Tcti_Libtpms_Init; + Tss2_Tcti_Libtpms_Reset; local: *; }; diff --git a/lib/tss2-tcti-spi-ftdi.def b/lib/tss2-tcti-spi-ftdi.def new file mode 100644 index 0000000..bc67f1b --- /dev/null +++ b/lib/tss2-tcti-spi-ftdi.def @@ -0,0 +1,4 @@ +LIBRARY tss2-tcti-spi-ftdi +EXPORTS + Tss2_Tcti_Info + Tss2_Tcti_Spi_Ftdi_Init diff --git a/lib/tss2-tcti-spi-ftdi.map b/lib/tss2-tcti-spi-ftdi.map new file mode 100644 index 0000000..3bec054 --- /dev/null +++ b/lib/tss2-tcti-spi-ftdi.map @@ -0,0 +1,7 @@ +{ + global: + Tss2_Tcti_Info; + Tss2_Tcti_Spi_Ftdi_Init; + local: + *; +}; diff --git a/lib/tss2-tcti-spi-ftdi.pc.in b/lib/tss2-tcti-spi-ftdi.pc.in new file mode 100644 index 0000000..c4f360f --- /dev/null +++ b/lib/tss2-tcti-spi-ftdi.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: tss2-tcti-spi-ftdi +Description: TCTI library for communicating with a TPM over USB-FTDI-SPI converter. +URL: https://github.com/tpm2-software/tpm2-tss +Version: @VERSION@ +Cflags: -I${includedir} -I${includedir}/tss +Libs: -ltss2-tcti-spi-helper -ltss2-tcti-spi-ftdi -L${libdir} -lftdi diff --git a/lib/tss2-tcti-spi-ltt2go.def b/lib/tss2-tcti-spi-ltt2go.def new file mode 100644 index 0000000..6cd1261 --- /dev/null +++ b/lib/tss2-tcti-spi-ltt2go.def @@ -0,0 +1,4 @@ +LIBRARY tss2-tcti-spi-ltt2go +EXPORTS + Tss2_Tcti_Info + Tss2_Tcti_Spi_Ltt2go_Init diff --git a/lib/tss2-tcti-spi-ltt2go.map b/lib/tss2-tcti-spi-ltt2go.map new file mode 100644 index 0000000..353e621 --- /dev/null +++ b/lib/tss2-tcti-spi-ltt2go.map @@ -0,0 +1,7 @@ +{ + global: + Tss2_Tcti_Info; + Tss2_Tcti_Spi_Ltt2go_Init; + local: + *; +}; diff --git a/lib/tss2-tcti-spi-ltt2go.pc.in b/lib/tss2-tcti-spi-ltt2go.pc.in new file mode 100644 index 0000000..857ac79 --- /dev/null +++ b/lib/tss2-tcti-spi-ltt2go.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: tss2-tcti-spi-ltt2go +Description: TCTI library for communicating with the LetsTrust-TPM2Go over USB. +URL: https://github.com/tpm2-software/tpm2-tss +Version: @VERSION@ +Cflags: -I${includedir} -I${includedir}/tss +Libs: -ltss2-tcti-spi-helper -ltss2-tcti-spi-ltt2go -L${libdir} -lusb-1.0 diff --git a/lib/tss2-tcti-spidev.def b/lib/tss2-tcti-spidev.def new file mode 100644 index 0000000..ec337b3 --- /dev/null +++ b/lib/tss2-tcti-spidev.def @@ -0,0 +1,4 @@ +LIBRARY tss2-tcti-spidev +EXPORTS + Tss2_Tcti_Info + Tss2_Tcti_Spidev_Init diff --git a/lib/tss2-tcti-spidev.map b/lib/tss2-tcti-spidev.map new file mode 100644 index 0000000..a7b068a --- /dev/null +++ b/lib/tss2-tcti-spidev.map @@ -0,0 +1,7 @@ +{ + global: + Tss2_Tcti_Info; + Tss2_Tcti_Spidev_Init; + local: + *; +}; diff --git a/lib/tss2-tcti-spidev.pc.in b/lib/tss2-tcti-spidev.pc.in new file mode 100644 index 0000000..c12e7d6 --- /dev/null +++ b/lib/tss2-tcti-spidev.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: tss2-tcti-spidev +Description: TCTI library for communicating with the TPM over spidev. +URL: https://github.com/tpm2-software/tpm2-tss +Version: @VERSION@ +Cflags: -I${includedir} -I${includedir}/tss +Libs: -ltss2-tcti-spi-helper -ltss2-tcti-spi-ltt2go -L${libdir} diff --git a/lib/tss2-tctildr.def b/lib/tss2-tctildr.def index d39fe26..66e9292 100644 --- a/lib/tss2-tctildr.def +++ b/lib/tss2-tctildr.def @@ -1,5 +1,6 @@ LIBRARY tss2-tctildr EXPORTS + Tss2_Tcti_Info Tss2_TctiLdr_Finalize Tss2_TctiLdr_FreeInfo; Tss2_TctiLdr_GetInfo; diff --git a/lib/tss2-tctildr.map b/lib/tss2-tctildr.map index 2089799..5cc30b7 100644 --- a/lib/tss2-tctildr.map +++ b/lib/tss2-tctildr.map @@ -1,10 +1,12 @@ { global: + Tss2_Tcti_Info; Tss2_TctiLdr_Finalize; Tss2_TctiLdr_FreeInfo; Tss2_TctiLdr_GetInfo; Tss2_TctiLdr_Initialize; Tss2_TctiLdr_Initialize_Ex; + Tss2_Tcti_TctiLdr_Init; local: *; }; diff --git a/man/tss2-tcti-i2c-ftdi.7.in b/man/tss2-tcti-i2c-ftdi.7.in new file mode 100644 index 0000000..0000b74 --- /dev/null +++ b/man/tss2-tcti-i2c-ftdi.7.in @@ -0,0 +1,14 @@ +.\" Process this file with +.\" groff -man -Tascii foo.1 +.\" +.TH TCTI-I2C 7 "APRIL 2023" "TPM2 Software Stack" +.SH NAME +tcti-i2c-ftdi \- USB to I2C-based TPM TCTI library +.SH SYNOPSIS +A TPM Command Transmission Interface (TCTI) module for interaction with +a I2C-based TPM over the FTDI MPSSE USB to I2C bridge. +.SH DESCRIPTION +tcti-i2c-ftdi is a library that abstracts the details of communication +with a I2C-based TPM over the FTDI MPSSE USB to I2C bridge. The interface +exposed by this library is defined in the \*(lqTSS System Level API and +and TPM Command Transmission Interface Specification\*(rq specification. diff --git a/man/tss2-tcti-i2c-helper.7.in b/man/tss2-tcti-i2c-helper.7.in new file mode 100644 index 0000000..275bab2 --- /dev/null +++ b/man/tss2-tcti-i2c-helper.7.in @@ -0,0 +1,14 @@ +.\" Process this file with +.\" groff -man -Tascii foo.1 +.\" +.TH TCTI-I2C 7 "APRIL 2023" "TPM2 Software Stack" +.SH NAME +tcti-i2c-helper \- device driver TCTI library +.SH SYNOPSIS +A TPM Command Transmission Interface (TCTI) module for communication via I2C. +TPM device driver. +.SH DESCRIPTION +tcti-i2c-helper is a library that abstracts the details of communication with a TPM +via I2C protocol. It uses user supplied methods for I2C and timing operations +in order to be platform independent. These methods are supplied to `Tss2_Tcti_I2c_Helper_Init` +via the `TSS2_TCTI_I2C_HELPER_PLATFORM` struct. diff --git a/man/tss2-tcti-spi-ftdi.7.in b/man/tss2-tcti-spi-ftdi.7.in new file mode 100644 index 0000000..de60f25 --- /dev/null +++ b/man/tss2-tcti-spi-ftdi.7.in @@ -0,0 +1,14 @@ +.\" Process this file with +.\" groff -man -Tascii foo.1 +.\" +.TH TCTI-SPI 7 "NOVEMBER 2022" "TPM2 Software Stack" +.SH NAME +tcti-spi-ftdi \- USB to SPI-based TPM TCTI library +.SH SYNOPSIS +A TPM Command Transmission Interface (TCTI) module for interaction with +a SPI-based TPM over the FTDI MPSSE USB to SPI bridge. +.SH DESCRIPTION +tcti-spi-ftdi is a library that abstracts the details of communication +with a SPI-based TPM over the FTDI MPSSE USB to SPI bridge. The interface +exposed by this library is defined in the \*(lqTSS System Level API and +and TPM Command Transmission Interface Specification\*(rq specification. diff --git a/man/tss2-tcti-spi-ltt2go.7.in b/man/tss2-tcti-spi-ltt2go.7.in new file mode 100644 index 0000000..cdb11fb --- /dev/null +++ b/man/tss2-tcti-spi-ltt2go.7.in @@ -0,0 +1,14 @@ +.\" Process this file with +.\" groff -man -Tascii foo.1 +.\" +.TH TCTI-SPI 7 "NOVEMBER 2022" "TPM2 Software Stack" +.SH NAME +tcti-spi-ltt2go \- LetsTrust-TPM2Go USB TPM TCTI library +.SH SYNOPSIS +A TPM Command Transmission Interface (TCTI) module for interaction with +the LetsTrust-TPM2Go USB TPM. +.SH DESCRIPTION +tcti-spi-ltt2go is a library that abstracts the details of communication +with the LetsTrust-TPM2Go USB TPM. The interface exposed by this library +is defined in the \*(lqTSS System Level API and TPM Command Transmission +Interface Specification\*(rq specification. diff --git a/man/tss2-tcti-spidev.7.in b/man/tss2-tcti-spidev.7.in new file mode 100644 index 0000000..9d7c345 --- /dev/null +++ b/man/tss2-tcti-spidev.7.in @@ -0,0 +1,16 @@ +.\" Process this file with +.\" groff -man -Tascii foo.1 +.\" +.TH TCTI-SPI 7 "NOVEMBER 2023" "TPM2 Software Stack" +.SH NAME +tcti-spidev \- TCTI library for accessing TPMs via spidev +.SH SYNOPSIS +A TPM Command Transmission Interface (TCTI) module for interaction with +a TPM that is attached to an spidev device node. +.SH DESCRIPTION +tcti-spidev is a library that abstracts the details of communication +with a TPM that is attached to an spidev device node.. The interface +exposed by this library is defined in the \*(lqTSS System Level API +and TPM Command Transmission Interface Specification\*(rq specification. +The configuration of this TCTI takes the filepath to the device node +(Default: /dev/spidev0.1). diff --git a/script/ekca/create_ca.sh b/script/ekca/create_ca.sh index 61d976a..3a57ec0 100755 --- a/script/ekca/create_ca.sh +++ b/script/ekca/create_ca.sh @@ -84,7 +84,7 @@ mkdir certreqs certs crl newcerts private touch intermed-ca.index echo 00 > intermed-ca.crlnum echo 2000 > intermed-ca.serial -echo "abcdef" > pass.txt +echo "123456" > pass.txt cp "${EKCADIR}/intermed-ca.cnf" ./ export OPENSSL_CONF=./intermed-ca.cnf diff --git a/script/ekca/init_ca.sh b/script/ekca/init_ca.sh new file mode 100755 index 0000000..fd18640 --- /dev/null +++ b/script/ekca/init_ca.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash + +#set -x + +#set -euf +OS=$(uname) +DATE_FMT_BEFORE="" +DATE_FMT_AFTER="" +SED_CMD="" + +if [ "$OS" == "Linux" ]; then + DATE_FMT_BEFORE="+%y%m%d000000Z -u -d -1day" + DATE_FMT_AFTER="+%y%m%d000000Z -u -d +10years+1day" + SED_CMD="sed -i" +elif [ "$OS" == "FreeBSD" ]; then + DATE_FMT_BEFORE="-u -v-1d +%y%m%d000000Z" + DATE_FMT_AFTER="-u -v+10y +%y%m%d000000Z" + SED_CMD="sed -i '' -e" +fi + +EKCADIR="$(dirname $(realpath ${0}))/" +CA_DIR="${1-.}/ca" + +if test -e $CA_DIR; then + exit +fi +mkdir -p $CA_DIR +echo "CA build in \"$CA_DIR\" realpath: \"$(realpath $CA_DIR)\"" 1>&2 + +pushd "$CA_DIR" + +mkdir root-ca +pushd root-ca + +mkdir certreqs certs crl newcerts private +touch root-ca.index +echo 00 > root-ca.crlnum +echo 1000 > root-ca.serial +echo "123456" > pass.txt + +cp "${EKCADIR}/root-ca.cnf" ./ +export OPENSSL_CONF=./root-ca.cnf +ROOT_URL="file:$ROOTCRT" +${SED_CMD} "s|ROOTCRT|$ROOT_URL|g" $OPENSSL_CONF +ROOT_URL="file:$ROOTCRL" +${SED_CMD} "s|ROOTCRL|$ROOT_URL|g" $OPENSSL_CONF +openssl req -new -out root-ca.req.pem -passout file:pass.txt + +# +# Create self signed root certificate +# + +openssl ca -selfsign \ + -in root-ca.req.pem \ + -out root-ca.cert.pem \ + -extensions root-ca_ext \ + -startdate `date ${DATE_FMT_BEFORE}` \ + -enddate `date ${DATE_FMT_AFTER}` \ + -passin file:pass.txt -batch + +openssl x509 -outform der -in root-ca.cert.pem -out root-ca.cert.crt + +openssl verify -verbose -CAfile root-ca.cert.pem \ + root-ca.cert.pem + +openssl ca -gencrl -cert root-ca.cert.pem \ + -out root-ca.cert.crl.pem -passin file:pass.txt +openssl crl -in root-ca.cert.crl.pem -outform DER -out root-ca.cert.crl + +popd #root-ca + +# +# Create intermediate certificate +# +mkdir intermed-ca +pushd intermed-ca + +mkdir certreqs certs crl newcerts private +touch intermed-ca.index +echo 00 > intermed-ca.crlnum +echo 2000 > intermed-ca.serial +echo "123456" > pass.txt + +cp "${EKCADIR}/intermed-ca.cnf" ./ +export OPENSSL_CONF=./intermed-ca.cnf + +# Adapt CRT URL to current test directory +${SED_CMD} "s|ROOTCRT|$ROOT_URL|g" $OPENSSL_CONF + +openssl req -new -out intermed-ca.req.pem -passout file:pass.txt + +openssl rsa -inform PEM -in private/intermed-ca.key.pem \ + -outform DER -out private/intermed-ca.key.der -passin file:pass.txt + +cp intermed-ca.req.pem \ + ../root-ca/certreqs/ + +INTERMED_URL="file:$INTERMEDCRT" +${SED_CMD} "s|INTERMEDCRT|$INTERMED_URL|g" $OPENSSL_CONF + +pushd ../root-ca +export OPENSSL_CONF=./root-ca.cnf + +openssl ca \ + -in certreqs/intermed-ca.req.pem \ + -out certs/intermed-ca.cert.pem \ + -extensions intermed-ca_ext \ + -startdate `date ${DATE_FMT_BEFORE}` \ + -enddate `date ${DATE_FMT_AFTER}` \ + -passin file:pass.txt -batch + +openssl x509 -outform der -in certs/intermed-ca.cert.pem \ + -out certs/intermed-ca.cert.crt + +openssl verify -verbose -CAfile root-ca.cert.pem \ + certs/intermed-ca.cert.pem + +cp certs/intermed-ca.cert.pem \ + ../intermed-ca + +cp certs/intermed-ca.cert.crt \ + ../intermed-ca + +popd #root-ca + +export OPENSSL_CONF=./intermed-ca.cnf +openssl ca -gencrl -cert ../root-ca/certs/intermed-ca.cert.pem \ + -out intermed-ca.crl.pem -passin file:pass.txt +openssl crl -in intermed-ca.crl.pem -outform DER -out intermed-ca.crl + +popd #intermed-ca +sync diff --git a/script/fint-log-compiler.sh b/script/fint-log-compiler.sh index 17139cb..d6cb30e 100755 --- a/script/fint-log-compiler.sh +++ b/script/fint-log-compiler.sh @@ -14,196 +14,66 @@ sanity_test # start simulator if needed -if [[ ${INTEGRATION_TCTI} == "mssim" || ${INTEGRATION_TCTI} == "swtpm" ]]; then +if [[ ${INTEGRATION_TCTI} == *mssim* || ${INTEGRATION_TCTI} == *swtpm* ]]; then echo "Trying to start simulator ${INTEGRATION_TCTI}" try_simulator_start - TPM20TEST_SOCKET_PORT="${SIM_PORT_DATA}" - TPM20TEST_TCTI="${INTEGRATION_TCTI}:host=${TPM20TEST_SOCKET_ADDRESS},port=${TPM20TEST_SOCKET_PORT}" -else - # Device will be used. - TPM20TEST_TCTI="${INTEGRATION_TCTI}:${TPM20TEST_DEVICE_FILE}" fi -while true; do +TPM20TEST_TCTI="${INTEGRATION_TCTI}" -# Some debug prints -echo "TPM20TEST_TCTI_NAME=${TPM20TEST_TCTI_NAME}" -echo "TPM20TEST_DEVICE_FILE=${TPM20TEST_DEVICE_FILE}" -echo "TPM20TEST_SOCKET_ADDRESS=${TPM20TEST_SOCKET_ADDRESS}" -echo "TPM20TEST_SOCKET_PORT=${TPM20TEST_SOCKET_PORT}" -echo "TPM20TEST_TCTI=${TPM20TEST_TCTI}" +# if $TPM20TEST_TCTI ends with mssim or swtpm (i.e. there is no config), add config: +TCTI_SIM_CONF="host=127.0.0.1,port=${SIM_PORT_DATA-}" +TPM20TEST_TCTI=${TPM20TEST_TCTI/%mssim/mssim:$TCTI_SIM_CONF} +TPM20TEST_TCTI=${TPM20TEST_TCTI/%swtpm/swtpm:$TCTI_SIM_CONF} -if [ "${TPM20TEST_TCTI_NAME}" != "device" ]; then - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_startup - if [ $? -ne 0 ]; then - echo "TPM_StartUp failed" - ret=99 - break - fi -else - env TPM20TEST_TCTI_NAME=${TPM20TEST_TCTI_NAME} \ - TPM20TEST_DEVICE_FILE=${TPM20TEST_DEVICE_FILE} \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_transientempty - if [ $? -ne 0 ]; then - echo "TPM transient area not empty => skipping" - ret=99 - break - fi -fi +# if $TPM20TEST_TCTI ends with libtpms (i.e. there is no config), add config: +# for FAPI, we need a state file which persists accross different processes +TCTI_LIBTPMS_CONF="${@: -1}.libtpms" +TPM20TEST_TCTI=${TPM20TEST_TCTI/%libtpms/libtpms:$TCTI_LIBTPMS_CONF} +rm -f "${TCTI_LIBTPMS_CONF}" -# Certificate generation for simulator tests -if [ "${TPM20TEST_TCTI_NAME}" != "device" ]; then - EKPUB_FILE=${TEST_BIN}_ekpub.pem - EKCERT_FILE=${TEST_BIN}_ekcert.crt - EKCERT_PEM_FILE=${TEST_BIN}_ekcert.pem +# Add pcap-tcti as wrapper +# TPM20TEST_TCTI="pcap:${TPM20TEST_TCTI}" +TCTI_PCAP_FILE="${@: -1}.pcap" +# rm -f "$TCTI_PCAP_FILE" - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_getek ${EKPUB_FILE} - if [ $? -ne 0 ]; then - echo "TPM_getek failed" - ret=99 - break - fi - - EKECCPUB_FILE=${TEST_BIN}_ekeccpub.pem - EKECCCERT_FILE=${TEST_BIN}_ekecccert.crt - EKECCCERT_PEM_FILE=${TEST_BIN}_ekecccert.pem - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_getek_ecc ${EKECCPUB_FILE} - if [ $? -ne 0 ]; then - echo "TPM_getek_ecc failed" - ret=99 - break - fi - - INTERMEDCA_FILE=${TEST_BIN}_intermedecc-ca - ROOTCA_FILE=${TEST_BIN}_root-ca - - SCRIPTDIR="$(dirname $(realpath $0))/" - ${SCRIPTDIR}/ekca/create_ca.sh "${EKPUB_FILE}" "${EKECCPUB_FILE}" "${EKCERT_FILE}" \ - "${EKECCCERT_FILE}" "${INTERMEDCA_FILE}" "${ROOTCA_FILE}" >${TEST_BIN}_ca.log 2>&1 - if [ $? -ne 0 ]; then - echo "ek-cert ca failed" - ret=99 - break - fi - - # Determine the fingerprint of the RSA EK public. - FINGERPRINT=$(openssl pkey -pubin -inform PEM -in ${EKPUB_FILE} -outform DER | shasum -a 256 | cut -f 1 -d ' ') - export FAPI_TEST_FINGERPRINT=" { \"hashAlg\" : \"sha256\", \"digest\" : \"${FINGERPRINT}\" }" - openssl x509 -inform DER -in ${EKCERT_FILE} -outform PEM -out ${EKCERT_PEM_FILE} - export FAPI_TEST_CERTIFICATE="file:${EKCERT_PEM_FILE}" - - # Determine the fingerprint of the RSA EK public. - FINGERPRINT_ECC=$(openssl pkey -pubin -inform PEM -in ${EKECCPUB_FILE} -outform DER | shasum -a 256 | cut -f 1 -d ' ') - export FAPI_TEST_FINGERPRINT_ECC=" { \"hashAlg\" : \"sha256\", \"digest\" : \"${FINGERPRINT_ECC}\" }" - openssl x509 -inform DER -in ${EKECCCERT_FILE} -outform PEM -out ${EKECCCERT_PEM_FILE} - export FAPI_TEST_CERTIFICATE_ECC="file:${EKECCCERT_PEM_FILE}" - - cat $EKCERT_FILE | \ - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_writeekcert 1C00002 - if [ $? -ne 0 ]; then - echo "TPM_writeekcert failed" - ret=99 - break - fi - - cat $EKECCCERT_FILE | \ - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_writeekcert 1C0000A - if [ $? -ne 0 ]; then - echo "TPM_writeekcert failed" - ret=99 - fi -fi # certificate generation - -TPMSTATE_FILE1=${TEST_BIN}_state1 -TPMSTATE_FILE2=${TEST_BIN}_state2 - -env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_dumpstate>${TPMSTATE_FILE1} -if [ $? -ne 0 ]; then - echo "Error during dumpstate" - ret=99 - break -fi +echo "TPM20TEST_TCTI=${TPM20TEST_TCTI}" + +while true; do + +INTERMEDCA_FILE=ca/intermed-ca/intermed-ca.cert +ROOTCA_FILE=ca/root-ca/root-ca.cert echo "Execute the test script" -if [ "${TPM20TEST_TCTI_NAME}" == "device" ]; then +if [[ ${TPM20TEST_TCTI} == *device* ]]; then # No root certificate needed - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ + env TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ + TCTI_PCAP_FILE="${TCTI_PCAP_FILE}" \ G_MESSAGES_DEBUG=all ${@: -1} else # Run test with generated certificate. - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ + + EKECCCERT_PEM_FILE=${TEST_BIN}_ekecccert.pem + export FAPI_TEST_CERTIFICATE_ECC="${EKECCCERT_PEM_FILE}" + EKCERT_PEM_FILE=${TEST_BIN}_ekcert.pem + export FAPI_TEST_CERTIFICATE="${EKCERT_PEM_FILE}" + + env TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ + TCTI_PCAP_FILE="${TCTI_PCAP_FILE}" \ FAPI_TEST_ROOT_CERT=${ROOTCA_FILE}.pem \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ + FAPI_TEST_INT_CERT=${INTERMEDCA_FILE}.pem \ G_MESSAGES_DEBUG=all ${@: -1} fi ret=$? echo "Script returned $ret" -#We check the state before a reboot to see if transients and NV were chagned. -env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_dumpstate>${TPMSTATE_FILE2} -if [ $? -ne 0 ]; then - echo "Error during dumpstate" - ret=99 - break -fi - -if [ "$(cat ${TPMSTATE_FILE1})" != "$(cat ${TPMSTATE_FILE2})" ]; then - echo "TPM changed state during test" - echo "State before ($TPMSTATE_FILE1):" - cat ${TPMSTATE_FILE1} - echo "State after ($TPMSTATE_FILE2):" - cat ${TPMSTATE_FILE2} - ret=1 - break -fi - #TODO: Add a tpm-restart/reboot here break done -if [ "${TPM20TEST_TCTI_NAME}" != "device" ]; then +if [[ ${TPM20TEST_TCTI} == *mssim* || ${TPM20TEST_TCTI} == *swtpm* ]]; then # This sleep is sadly necessary: If we kill the tabrmd w/o sleeping for a # second after the test finishes the simulator will die too. Bug in the # simulator? diff --git a/script/gen_fuzz.py b/script/gen_fuzz.py index 87807d3..d17bb7d 100755 --- a/script/gen_fuzz.py +++ b/script/gen_fuzz.py @@ -54,8 +54,6 @@ #include "tss2_tcti.h" #include "util/log.h" #include "test.h" -#include "test-options.h" -#include "context-util.h" #include "tss2-sys/sysapi_util.h" #include "tcti/tcti-fuzzing.h" diff --git a/script/int-log-compiler-common.sh b/script/int-log-compiler-common.sh index c64694a..16ab8d4 100755 --- a/script/int-log-compiler-common.sh +++ b/script/int-log-compiler-common.sh @@ -44,39 +44,7 @@ elif [ "$OS" == "FreeBSD" ]; then sock_tool_params="-l4" fi -simulator_bin="" INTEGRATION_TCTI=$1 -TPM20TEST_DEVICE_FILE="" -TPM20TEST_TCTI_NAME="" -TPM20TEST_TCTI="" -TPM20TEST_SOCKET_PORT="" -TPM20TEST_SOCKET_ADDRESS="" -SIM_PORT_DATA="" - -case ${INTEGRATION_TCTI} in - "swtpm") - simulator_bin="swtpm" - TPM20TEST_TCTI_NAME="swtpm" - TPM20TEST_SOCKET_ADDRESS="127.0.0.1" - ;; - "mssim") - simulator_bin="tpm_server" - TPM20TEST_TCTI_NAME="socket" - TPM20TEST_SOCKET_ADDRESS="127.0.0.1" - - ;; - "device") - simulator_bin="" - TPM20TEST_TCTI_NAME="device" - DEVICE_FILE=$2 - TPM20TEST_DEVICE_FILE=${DEVICE_FILE:9} - TPM20TEST_TCTI="${TPM20TEST_TCTI_NAME}:${TPM20TEST_DEVICE_FILE}" - ;; - *) - echo "Wrong INTEGRATION_TCTI exiting.." - exit 1; - ;; -esac # Verify the running shell and OS environment is sufficient to run these tests. sanity_test () @@ -87,12 +55,12 @@ sanity_test () exit 1 fi - if [ -z "$(which ${sock_tool})" ]; then + if ! command -v ${sock_tool} > /dev/null ; then echo "ss not on PATH; exiting" exit 1 fi - if [[ ! -z ${simulator_bin} && -z "$(which ${simulator_bin})" ]]; then + if [[ ! -z ${simulator_bin} && -z "$(command -v ${simulator_bin})" ]]; then echo "${simulator_bin} not on PATH; exiting" exit 1 fi @@ -157,10 +125,10 @@ simulator_start () # simulator port is a random port between 1024 and 65535 cd ${sim_tmp_dir} - if [ "${INTEGRATION_TCTI}" == "mssim" ]; then + if [[ "${INTEGRATION_TCTI}" == *mssim* ]]; then daemon_start "${sim_bin}" "-port ${sim_port}" "${sim_log_file}" \ "${sim_pid_file}" "" - elif [ "${INTEGRATION_TCTI}" == "swtpm" ]; then + elif [[ "${INTEGRATION_TCTI}" == *swtpm* ]]; then daemon_start "${sim_bin}" "socket --tpm2 -p ${sim_port} --ctrl type=tcp,port=$((${sim_port}+1)) --log fd=1,level=5 --flags not-need-init --tpmstate dir=${sim_tmp_dir} --locality allow-set-locality" \ "${sim_log_file}" "${sim_pid_file}" "" else @@ -207,6 +175,11 @@ TEST_DIR=$(dirname "${@: -1}") TEST_NAME=$(basename "${TEST_BIN}") # start an instance of the simulator for the test, have it use a random port +case ${INTEGRATION_TCTI} in + *swtpm*) simulator_bin="swtpm" ;; + *mssim*) simulator_bin="tpm_server" ;; + *) simulator_bin=""; ;; +esac SIM_LOG_FILE=${TEST_BIN}_simulator.log SIM_PID_FILE=${TEST_BIN}_simulator.pid SIM_TMP_DIR=$(mktemp -d /tmp/tpm_simulator_XXXXXX) diff --git a/script/int-log-compiler.sh b/script/int-log-compiler.sh index 544cd8e..dc5d1bd 100755 --- a/script/int-log-compiler.sh +++ b/script/int-log-compiler.sh @@ -14,101 +14,42 @@ sanity_test # start simulator if needed -if [[ ${INTEGRATION_TCTI} == "mssim" || ${INTEGRATION_TCTI} == "swtpm" ]]; then +if [[ ${INTEGRATION_TCTI} == *mssim* || ${INTEGRATION_TCTI} == *swtpm* ]]; then echo "Trying to start simulator ${INTEGRATION_TCTI}" try_simulator_start fi -TPM20TEST_SOCKET_PORT="${SIM_PORT_DATA}" -TPM20TEST_TCTI="${INTEGRATION_TCTI}:host=${TPM20TEST_SOCKET_ADDRESS},port=${TPM20TEST_SOCKET_PORT}" +TPM20TEST_TCTI="${INTEGRATION_TCTI}" -while true; do +# if $TPM20TEST_TCTI ends with mssim or swtpm (i.e. there is no config), add config: +TCTI_SIM_CONF="host=127.0.0.1,port=${SIM_PORT_DATA-}" +TPM20TEST_TCTI=${TPM20TEST_TCTI/%mssim/mssim:$TCTI_SIM_CONF} +TPM20TEST_TCTI=${TPM20TEST_TCTI/%swtpm/swtpm:$TCTI_SIM_CONF} -# Some debug prints -echo "TPM20TEST_TCTI_NAME=${TPM20TEST_TCTI_NAME}" -echo "TPM20TEST_DEVICE_FILE=${TPM20TEST_DEVICE_FILE}" -echo "TPM20TEST_SOCKET_ADDRESS=${TPM20TEST_SOCKET_ADDRESS}" -echo "TPM20TEST_SOCKET_PORT=${TPM20TEST_SOCKET_PORT}" -echo "TPM20TEST_TCTI=${TPM20TEST_TCTI}" - -if [ "${TPM20TEST_TCTI_NAME}" != "device" ]; then - env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_startup - if [ $? -ne 0 ]; then - echo "TPM_StartUp failed" - ret=99 - break - fi -else - env TPM20TEST_TCTI_NAME=${TPM20TEST_TCTI_NAME} \ - TPM20TEST_DEVICE_FILE=${TPM20TEST_DEVICE_FILE} \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_transientempty - if [ $? -ne 0 ]; then - echo "TPM transient area not empty => skipping" - ret=99 - break - fi -fi +# Add pcap-tcti as wrapper +# TPM20TEST_TCTI="pcap:${TPM20TEST_TCTI}" +TCTI_PCAP_FILE="${@: -1}.pcap" +# rm -f "$TCTI_PCAP_FILE" -TPMSTATE_FILE1=${TEST_BIN}_state1 -TPMSTATE_FILE2=${TEST_BIN}_state2 -env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_dumpstate>${TPMSTATE_FILE1} -if [ $? -ne 0 ]; then - echo "Error during dumpstate" - ret=99 - break -fi +echo "TPM20TEST_TCTI=${TPM20TEST_TCTI}" echo "Execute the test script" -env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ${@: -1} +env TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ + TCTI_PCAP_FILE="${TCTI_PCAP_FILE}" \ + G_MESSAGES_DEBUG=all \ + ${@: -1} ret=$? echo "Script returned $ret" -#We check the state before a reboot to see if transients and NV were chagned. -env TPM20TEST_TCTI_NAME="${TPM20TEST_TCTI_NAME}" \ - TPM20TEST_SOCKET_ADDRESS="${TPM20TEST_SOCKET_ADDRESS}" \ - TPM20TEST_SOCKET_PORT="${TPM20TEST_SOCKET_PORT}" \ - TPM20TEST_TCTI="${TPM20TEST_TCTI}" \ - TPM20TEST_DEVICE_FILE="${TPM20TEST_DEVICE_FILE}" \ - G_MESSAGES_DEBUG=all ./test/helper/tpm_dumpstate>${TPMSTATE_FILE2} -if [ $? -ne 0 ]; then - echo "Error during dumpstate" - ret=99 - break -fi - -if [ "$(cat ${TPMSTATE_FILE1})" != "$(cat ${TPMSTATE_FILE2})" ]; then - echo "TPM changed state during test" - echo "State before ($TPMSTATE_FILE1):" - cat ${TPMSTATE_FILE1} - echo "State after ($TPMSTATE_FILE2):" - cat ${TPMSTATE_FILE2} - ret=1 - break +if [[ ${TPM20TEST_TCTI} == *mssim* || ${TPM20TEST_TCTI} == *swtpm* ]]; then + # This sleep is sadly necessary: If we kill the tabrmd w/o sleeping for a + # second after the test finishes the simulator will die too. Bug in the + # simulator? + sleep 1 + # teardown + daemon_stop ${SIM_PID_FILE} + rm -rf ${SIM_TMP_DIR} ${SIM_PID_FILE} fi -break -done - -# This sleep is sadly necessary: If we kill the tabrmd w/o sleeping for a -# second after the test finishes the simulator will die too. Bug in the -# simulator? -sleep 1 -# teardown -daemon_stop ${SIM_PID_FILE} -rm -rf ${SIM_TMP_DIR} ${SIM_PID_FILE} exit $ret diff --git a/sphinx/conf.py b/sphinx/conf.py index 7fa75a9..9235b35 100644 --- a/sphinx/conf.py +++ b/sphinx/conf.py @@ -16,9 +16,8 @@ import subprocess # Create (unused) root file -index_rst = open("index.rst", "w") -index_rst.write(".. toctree::\n :maxdepth: 2") -index_rst.close() +with open("index.rst", "w") as index_rst: + index_rst.write(".. toctree::\n :maxdepth: 2") # Build doxygen documentation subprocess.call( diff --git a/src/tss2-esys/api/Esys_Create.c b/src/tss2-esys/api/Esys_Create.c index 7e61aec..f435688 100644 --- a/src/tss2-esys/api/Esys_Create.c +++ b/src/tss2-esys/api/Esys_Create.c @@ -206,10 +206,10 @@ Esys_Create_Async( store_input_parameters (esysContext, inSensitive); if (inPublic) { - r = iesys_hash_long_auth_values( + r = iesys_adapt_auth_value( &esysContext->crypto_backend, - &esysContext->in.Create.inSensitive->sensitive.userAuth, - inPublic->publicArea.nameAlg); + &esysContext->in.Create.inSensitive->sensitive.userAuth, + inPublic->publicArea.nameAlg); return_state_if_error(r, _ESYS_STATE_INIT, "Adapt auth value."); } diff --git a/src/tss2-esys/api/Esys_CreateLoaded.c b/src/tss2-esys/api/Esys_CreateLoaded.c index 66bb212..5b183ae 100644 --- a/src/tss2-esys/api/Esys_CreateLoaded.c +++ b/src/tss2-esys/api/Esys_CreateLoaded.c @@ -203,7 +203,7 @@ Esys_CreateLoaded_Async( &publicArea); return_if_error(r, "Unmarshalling inPublic failed"); - r = iesys_hash_long_auth_values( + r = iesys_adapt_auth_value( &esysContext->crypto_backend, &esysContext->in.CreateLoaded.inSensitive->sensitive.userAuth, publicArea.nameAlg); diff --git a/src/tss2-esys/api/Esys_CreatePrimary.c b/src/tss2-esys/api/Esys_CreatePrimary.c index 9b551ae..3a9ef83 100644 --- a/src/tss2-esys/api/Esys_CreatePrimary.c +++ b/src/tss2-esys/api/Esys_CreatePrimary.c @@ -208,7 +208,7 @@ Esys_CreatePrimary_Async( return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage"); store_input_parameters (esysContext, inSensitive); if (inPublic) { - r = iesys_hash_long_auth_values( + r = iesys_adapt_auth_value( &esysContext->crypto_backend, &esysContext->in.CreatePrimary.inSensitive->sensitive.userAuth, inPublic->publicArea.nameAlg); diff --git a/src/tss2-esys/api/Esys_EvictControl.c b/src/tss2-esys/api/Esys_EvictControl.c index b8d0097..3485900 100644 --- a/src/tss2-esys/api/Esys_EvictControl.c +++ b/src/tss2-esys/api/Esys_EvictControl.c @@ -361,6 +361,9 @@ Esys_EvictControl_Finish( /* The object was already persistent */ if (iesys_get_handle_type(objectHandleNode->rsrc.handle) == TPM2_HT_PERSISTENT) { *newObjectHandle = ESYS_TR_NONE; + r = Esys_TR_Close(esysContext, &objectHandle); + if (r != TSS2_RC_SUCCESS) + return r; } else { /* A new resource is created and updated with date from the not persistent object */ RSRC_NODE_T *newObjectHandleNode = NULL; diff --git a/src/tss2-esys/api/Esys_FlushContext.c b/src/tss2-esys/api/Esys_FlushContext.c index 4d7dc72..ff5e1ae 100644 --- a/src/tss2-esys/api/Esys_FlushContext.c +++ b/src/tss2-esys/api/Esys_FlushContext.c @@ -184,6 +184,7 @@ Esys_FlushContext_Finish( ESYS_CONTEXT *esysContext) { TSS2_RC r; + RSRC_NODE_T *flushHandleNode; LOG_TRACE("context=%p", esysContext); @@ -244,6 +245,12 @@ Esys_FlushContext_Finish( "Received error from SAPI unmarshaling" ); /* The ESYS_TR object has to be invalidated */ + + r = esys_GetResourceObject(esysContext, esysContext->in.FlushContext.flushHandle, + &flushHandleNode); + return_state_if_error(r, _ESYS_STATE_INIT, "flushHandle unknown."); + + flushHandleNode->reference_count = 0; r = Esys_TR_Close(esysContext, &esysContext->in.FlushContext.flushHandle); return_if_error(r, "invalidate object"); diff --git a/src/tss2-esys/api/Esys_HierarchyChangeAuth.c b/src/tss2-esys/api/Esys_HierarchyChangeAuth.c index 70f7210..1ab4c93 100644 --- a/src/tss2-esys/api/Esys_HierarchyChangeAuth.c +++ b/src/tss2-esys/api/Esys_HierarchyChangeAuth.c @@ -26,11 +26,13 @@ static void store_input_parameters ( const TPM2B_AUTH *newAuth) { esysContext->in.HierarchyChangeAuth.authHandle = authHandle; - if (newAuth == NULL) + if (newAuth == NULL) { memset(&esysContext->in.HierarchyChangeAuth.newAuth, 0, sizeof(esysContext->in.HierarchyChangeAuth.newAuth)); - else + } else { esysContext->in.HierarchyChangeAuth.newAuth = *newAuth; + iesys_strip_trailing_zeros(&esysContext->in.HierarchyChangeAuth.newAuth); + } } /** One-Call function for TPM2_HierarchyChangeAuth @@ -175,7 +177,9 @@ Esys_HierarchyChangeAuth_Async( /* Check input parameters */ r = check_session_feasibility(shandle1, shandle2, shandle3, 1); return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage"); + store_input_parameters(esysContext, authHandle, newAuth); + iesys_strip_trailing_zeros(&esysContext->in.HierarchyChangeAuth.newAuth); /* Retrieve the metadata objects for provided handles */ r = esys_GetResourceObject(esysContext, authHandle, &authHandleNode); @@ -186,7 +190,7 @@ Esys_HierarchyChangeAuth_Async( (authHandleNode == NULL) ? TPM2_RH_NULL : authHandleNode->rsrc.handle, - newAuth); + &esysContext->in.HierarchyChangeAuth.newAuth); return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error."); /* Calculate the cpHash Values */ diff --git a/src/tss2-esys/api/Esys_NV_ChangeAuth.c b/src/tss2-esys/api/Esys_NV_ChangeAuth.c index d555adb..b9fa139 100644 --- a/src/tss2-esys/api/Esys_NV_ChangeAuth.c +++ b/src/tss2-esys/api/Esys_NV_ChangeAuth.c @@ -159,6 +159,8 @@ Esys_NV_ChangeAuth_Async( esysContext, nvIndex, newAuth); TSS2L_SYS_AUTH_COMMAND auths; RSRC_NODE_T *nvIndexNode; + TPM2B_AUTH *authCopy; + TPMI_ALG_HASH hashAlg; /* Check context, sequence correctness and set state to error for now */ if (esysContext == NULL) { @@ -174,25 +176,32 @@ Esys_NV_ChangeAuth_Async( r = check_session_feasibility(shandle1, shandle2, shandle3, 1); return_state_if_error(r, _ESYS_STATE_INIT, "Check session usage"); store_input_parameters(esysContext, nvIndex, newAuth); + authCopy = &esysContext->in.HierarchyChangeAuth.newAuth; /* Retrieve the metadata objects for provided handles */ r = esys_GetResourceObject(esysContext, nvIndex, &nvIndexNode); return_state_if_error(r, _ESYS_STATE_INIT, "nvIndex unknown."); + if (!nvIndexNode) { + LOG_ERROR("NV Object for Esys handle %x not found.", nvIndex); + esysContext->state = _ESYS_STATE_INIT; + return TSS2_FAPI_RC_BAD_VALUE; + } + + hashAlg = nvIndexNode->rsrc.misc.rsrc_nv_pub.nvPublic.nameAlg; + r = iesys_adapt_auth_value(&esysContext->crypto_backend, authCopy, hashAlg); + return_state_if_error(r, _ESYS_STATE_INIT, "Adapt auth value"); + /* Initial invocation of SAPI to prepare the command buffer with parameters */ r = Tss2_Sys_NV_ChangeAuth_Prepare(esysContext->sys, - (nvIndexNode == NULL) ? TPM2_RH_NULL - : nvIndexNode->rsrc.handle, newAuth); + nvIndexNode->rsrc.handle, newAuth); return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error."); /* Calculate the cpHash Values */ r = init_session_tab(esysContext, shandle1, shandle2, shandle3); return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources"); - if (nvIndexNode != NULL) - iesys_compute_session_value(esysContext->session_tab[0], - &nvIndexNode->rsrc.name, &nvIndexNode->auth); - else - iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL); + iesys_compute_session_value(esysContext->session_tab[0], + &nvIndexNode->rsrc.name, &nvIndexNode->auth); iesys_compute_session_value(esysContext->session_tab[1], NULL, NULL); iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL); diff --git a/src/tss2-esys/api/Esys_NV_DefineSpace.c b/src/tss2-esys/api/Esys_NV_DefineSpace.c index fe4e212..aba3833 100644 --- a/src/tss2-esys/api/Esys_NV_DefineSpace.c +++ b/src/tss2-esys/api/Esys_NV_DefineSpace.c @@ -200,9 +200,9 @@ Esys_NV_DefineSpace_Async( store_input_parameters(esysContext, auth, publicInfo); if (publicInfo) { - r = iesys_hash_long_auth_values(&esysContext->crypto_backend, - &esysContext->in.NV.authData, - publicInfo->nvPublic.nameAlg); + r = iesys_adapt_auth_value(&esysContext->crypto_backend, + &esysContext->in.NV.authData, + publicInfo->nvPublic.nameAlg); return_state_if_error(r, _ESYS_STATE_INIT, "Adapt auth value."); } diff --git a/src/tss2-esys/api/Esys_ObjectChangeAuth.c b/src/tss2-esys/api/Esys_ObjectChangeAuth.c index c2b95d0..300afe0 100644 --- a/src/tss2-esys/api/Esys_ObjectChangeAuth.c +++ b/src/tss2-esys/api/Esys_ObjectChangeAuth.c @@ -148,6 +148,11 @@ Esys_ObjectChangeAuth_Async( TSS2L_SYS_AUTH_COMMAND auths; RSRC_NODE_T *objectHandleNode; RSRC_NODE_T *parentHandleNode; + TPM2B_AUTH authCopy = + { .size = 0, + .buffer = {} + }; + TPMI_ALG_HASH hashAlg = 0; /* Check context, sequence correctness and set state to error for now */ if (esysContext == NULL) { @@ -166,28 +171,41 @@ Esys_ObjectChangeAuth_Async( /* Retrieve the metadata objects for provided handles */ r = esys_GetResourceObject(esysContext, objectHandle, &objectHandleNode); return_state_if_error(r, _ESYS_STATE_INIT, "objectHandle unknown."); + + if (!objectHandleNode) { + LOG_ERROR("Object for Esys handle %x not found.", objectHandle); + esysContext->state = _ESYS_STATE_INIT; + return TSS2_FAPI_RC_BAD_VALUE; + } + r = esys_GetResourceObject(esysContext, parentHandle, &parentHandleNode); return_state_if_error(r, _ESYS_STATE_INIT, "parentHandle unknown."); + if (objectHandleNode->rsrc.rsrcType == IESYSC_KEY_RSRC) { + hashAlg = objectHandleNode->rsrc.misc.rsrc_key_pub.publicArea.nameAlg; + } + + if (newAuth) { + authCopy = *newAuth; + }; + + r = iesys_adapt_auth_value(&esysContext->crypto_backend, &authCopy, hashAlg); + return_state_if_error(r, _ESYS_STATE_INIT, "Adapt auth value"); + /* Initial invocation of SAPI to prepare the command buffer with parameters */ r = Tss2_Sys_ObjectChangeAuth_Prepare(esysContext->sys, - (objectHandleNode == NULL) - ? TPM2_RH_NULL - : objectHandleNode->rsrc.handle, + objectHandleNode->rsrc.handle, (parentHandleNode == NULL) ? TPM2_RH_NULL : parentHandleNode->rsrc.handle, - newAuth); + &authCopy); return_state_if_error(r, _ESYS_STATE_INIT, "SAPI Prepare returned error."); /* Calculate the cpHash Values */ r = init_session_tab(esysContext, shandle1, shandle2, shandle3); return_state_if_error(r, _ESYS_STATE_INIT, "Initialize session resources"); - if (objectHandleNode != NULL) - iesys_compute_session_value(esysContext->session_tab[0], - &objectHandleNode->rsrc.name, &objectHandleNode->auth); - else - iesys_compute_session_value(esysContext->session_tab[0], NULL, NULL); + iesys_compute_session_value(esysContext->session_tab[0], + &objectHandleNode->rsrc.name, &objectHandleNode->auth); iesys_compute_session_value(esysContext->session_tab[1], NULL, NULL); iesys_compute_session_value(esysContext->session_tab[2], NULL, NULL); diff --git a/src/tss2-esys/api/Esys_StartAuthSession.c b/src/tss2-esys/api/Esys_StartAuthSession.c index c1834e9..d9319eb 100644 --- a/src/tss2-esys/api/Esys_StartAuthSession.c +++ b/src/tss2-esys/api/Esys_StartAuthSession.c @@ -436,14 +436,14 @@ Esys_StartAuthSession_Finish( tpmKeyNode->rsrc.misc.rsrc_key_pub.publicArea.nameAlg, & keyHash_size); if (r != TSS2_RC_SUCCESS) { - LOG_ERROR("Error: initialize auth session (%x).", r); + LOG_ERROR("Error: initialize auth session (0x%08"PRIx32").", r); return r; } } r = iesys_crypto_hash_get_digest_size(esysContext->in.StartAuthSession. authHash,&authHash_size); if (r != TSS2_RC_SUCCESS) { - LOG_ERROR("Error: initialize auth session (%x).", r); + LOG_ERROR("Error: initialize auth session (0x%08"PRIx32").", r); return r; } /* compute session key except for an unbound session */ diff --git a/src/tss2-esys/esys_context.c b/src/tss2-esys/esys_context.c index 891eff1..f74af57 100644 --- a/src/tss2-esys/esys_context.c +++ b/src/tss2-esys/esys_context.c @@ -28,6 +28,7 @@ * Library libtss2-tcti-tabrmd.so (tabrmd) * Device /dev/tpmrm0 (kernel resident resource manager) * Device /dev/tpm0 (hardware TPM) + * Device /dev/tcm0 (hardware TCM) * TCP socket localhost:2321 (TPM simulator) * @param esys_context [out] The ESYS_CONTEXT. * @param tcti [in] The TCTI context used to connect to the TPM (may be NULL). diff --git a/src/tss2-esys/esys_crypto.c b/src/tss2-esys/esys_crypto.c index e54c95c..39e7584 100644 --- a/src/tss2-esys/esys_crypto.c +++ b/src/tss2-esys/esys_crypto.c @@ -280,6 +280,46 @@ TSS2_RC iesys_crypto_aes_decrypt( iv); } +TSS2_RC iesys_crypto_sm4_encrypt( + ESYS_CRYPTO_CALLBACKS *crypto_cb, + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *buffer, + size_t buffer_size, + uint8_t *iv) +{ + DO_CALLBACK(sm4_encrypt, + key, + tpm_sym_alg, + key_bits, + tpm_mode, + buffer, + buffer_size, + iv); +} + +TSS2_RC iesys_crypto_sm4_decrypt( + ESYS_CRYPTO_CALLBACKS *crypto_cb, + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *buffer, + size_t buffer_size, + uint8_t *iv) +{ + DO_CALLBACK(sm4_decrypt, + key, + tpm_sym_alg, + key_bits, + tpm_mode, + buffer, + buffer_size, + iv); +} + /** Compute the command or response parameter hash. * * These hashes are needed for the computation of the HMAC used for the @@ -426,7 +466,7 @@ iesys_crypto_authHmac(ESYS_CRYPTO_CALLBACKS *crypto_cb, } if (nonceEncrypt != NULL) { - iesys_crypto_hmac_update2b(crypto_cb, cryptoContext, (TPM2B *) nonceEncrypt); + r = iesys_crypto_hmac_update2b(crypto_cb, cryptoContext, (TPM2B *) nonceEncrypt); goto_if_error(r, "Error", error); } @@ -596,7 +636,7 @@ iesys_crypto_KDFa(ESYS_CRYPTO_CALLBACKS *crypto_cb, return_if_error(r, "Error"); } if ((bitLength % 8) != 0) - outKey[0] &= ((1 << (bitLength % 8)) - 1); + outKey[0] &= ((((BYTE)1) << (bitLength % 8)) - 1); if (counterInOut != NULL) *counterInOut = counter; LOGBLOB_DEBUG(outKey, (bitLength + 7) / 8, "IESYS KDFa key"); @@ -693,7 +733,7 @@ iesys_crypto_KDFe(ESYS_CRYPTO_CALLBACKS *crypto_cb, } LOGBLOB_DEBUG(key, bit_size/8, "Result KDFe"); if((bit_size % 8) != 0) - key[0] &= ((1 << (bit_size % 8)) - 1); + key[0] &= ((((BYTE)1) << (bit_size % 8)) - 1); return r; error: @@ -782,6 +822,8 @@ TSS2_RC crypto_cb->userdata = NULL; crypto_cb->aes_decrypt = _iesys_crypto_aes_decrypt; crypto_cb->aes_encrypt = _iesys_crypto_aes_encrypt; + crypto_cb->sm4_decrypt = _iesys_crypto_sm4_decrypt; + crypto_cb->sm4_encrypt = _iesys_crypto_sm4_encrypt; crypto_cb->get_ecdh_point = _iesys_crypto_get_ecdh_point; crypto_cb->hash_abort = _iesys_crypto_hash_abort; crypto_cb->hash_finish = _iesys_crypto_hash_finish; @@ -799,6 +841,17 @@ TSS2_RC TEST_AND_SET_CALLBACK(crypto_cb, user_cb, aes_decrypt); TEST_AND_SET_CALLBACK(crypto_cb, user_cb, aes_encrypt); + // sm4 is optional + if (user_cb->sm4_encrypt) { + crypto_cb->sm4_encrypt = user_cb->sm4_encrypt; + } else { + crypto_cb->sm4_encrypt = _iesys_crypto_sm4_encrypt; + } + if (user_cb->sm4_decrypt) { + crypto_cb->sm4_decrypt = user_cb->sm4_decrypt; + } else { + crypto_cb->sm4_decrypt = _iesys_crypto_sm4_decrypt; + } TEST_AND_SET_CALLBACK(crypto_cb, user_cb, get_ecdh_point); TEST_AND_SET_CALLBACK(crypto_cb, user_cb, get_random2b); TEST_AND_SET_CALLBACK(crypto_cb, user_cb, rsa_pk_encrypt); diff --git a/src/tss2-esys/esys_crypto.h b/src/tss2-esys/esys_crypto.h index 8798bc6..c6efac1 100644 --- a/src/tss2-esys/esys_crypto.h +++ b/src/tss2-esys/esys_crypto.h @@ -16,6 +16,8 @@ #else #define _iesys_crypto_aes_decrypt NULL; #define _iesys_crypto_aes_encrypt NULL; +#define _iesys_crypto_sm4_decrypt NULL; +#define _iesys_crypto_sm4_encrypt NULL; #define _iesys_crypto_get_ecdh_point NULL; #define _iesys_crypto_hash_abort NULL; #define _iesys_crypto_hash_finish NULL; @@ -35,6 +37,7 @@ extern "C" { #endif #define AES_BLOCK_SIZE_IN_BYTES 16 +#define SM4_BLOCK_SIZE_IN_BYTES 16 TSS2_RC iesys_crypto_hash_get_digest_size(TPM2_ALG_ID hashAlg, size_t *size); @@ -163,6 +166,26 @@ TSS2_RC iesys_crypto_aes_decrypt( size_t buffer_size, uint8_t *iv); +TSS2_RC iesys_crypto_sm4_encrypt( + ESYS_CRYPTO_CALLBACKS *crypto_cb, + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *buffer, + size_t buffer_size, + uint8_t *iv); + +TSS2_RC iesys_crypto_sm4_decrypt( + ESYS_CRYPTO_CALLBACKS *crypto_cb, + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *buffer, + size_t buffer_size, + uint8_t *iv); + TSS2_RC iesys_crypto_authHmac( ESYS_CRYPTO_CALLBACKS *crypto_cb, TPM2_ALG_ID alg, diff --git a/src/tss2-esys/esys_crypto_mbed.c b/src/tss2-esys/esys_crypto_mbed.c index ac44efc..db6a5ed 100644 --- a/src/tss2-esys/esys_crypto_mbed.c +++ b/src/tss2-esys/esys_crypto_mbed.c @@ -88,7 +88,7 @@ iesys_cryptmbed_hash_start(ESYS_CRYPTO_CONTEXT_BLOB ** context, md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); break; case TPM2_ALG_SHA512: - md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); break; } @@ -270,6 +270,9 @@ iesys_cryptmbed_hmac_start(ESYS_CRYPTO_CONTEXT_BLOB ** context, case TPM2_ALG_SHA384: md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA384); break; + case TPM2_ALG_SHA512: + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512); + break; } if (md_info == NULL) { diff --git a/src/tss2-esys/esys_crypto_mbed.h b/src/tss2-esys/esys_crypto_mbed.h index 24b1d8e..40a976b 100644 --- a/src/tss2-esys/esys_crypto_mbed.h +++ b/src/tss2-esys/esys_crypto_mbed.h @@ -120,6 +120,8 @@ TSS2_RC iesys_cryptmbed_init(void *userdata); #define _iesys_crypto_get_ecdh_point iesys_cryptmbed_get_ecdh_point #define _iesys_crypto_aes_encrypt iesys_cryptmbed_sym_aes_encrypt #define _iesys_crypto_aes_decrypt iesys_cryptmbed_sym_aes_decrypt +#define _iesys_crypto_sm4_encrypt NULL +#define _iesys_crypto_sm4_decrypt NULL #define _iesys_crypto_init iesys_cryptmbed_init diff --git a/src/tss2-esys/esys_crypto_ossl.c b/src/tss2-esys/esys_crypto_ossl.c index 89d312f..1620788 100644 --- a/src/tss2-esys/esys_crypto_ossl.c +++ b/src/tss2-esys/esys_crypto_ossl.c @@ -394,9 +394,14 @@ iesys_cryptossl_hmac_start(ESYS_CRYPTO_CONTEXT_BLOB ** context, #if OPENSSL_VERSION_NUMBER < 0x10101000L if (!(hkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, key, size))) { -#else +#elif OPENSSL_VERSION_NUMBER < 0x30000000L /* this is preferred, but available since OpenSSL 1.1.1 only */ if (!(hkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, size))) { +#else + /* this is nessecary from OpenSSL 3.0.0 to avoid using the TPM2 provider using + * OpenSSL in a circular dependency */ + if (!(hkey = EVP_PKEY_new_raw_private_key_ex(mycontext->hash.ossl_libctx, + "HMAC", NULL, key, size))) { #endif goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Failed to create HMAC key", cleanup); @@ -919,7 +924,7 @@ iesys_cryptossl_get_ecdh_point(TPM2B_PUBLIC *key, curveId = NID_secp521r1; key_size = 66; break; -#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#ifdef NID_sm2 case TPM2_ECC_SM2_P256: curveId = NID_sm2; key_size = 32; @@ -1212,6 +1217,164 @@ iesys_cryptossl_sym_aes_decrypt(uint8_t * key, return r; } +#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) +/** Encrypt data with SM4. + * + * @param[in] key key used for SM4. + * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). + * @param[in] key_bits Key size in bits. + * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). + * For parameter encryption only CFB can be used. + * @param[in,out] buffer Data to be encrypted. The encrypted date will be stored + * in this buffer. + * @param[in] buffer_size size of data to be encrypted. + * @param[in] iv The initialization vector. + * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and + * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters, + * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library. + */ +TSS2_RC +iesys_cryptossl_sym_sm4_encrypt(uint8_t * key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t * buffer, + size_t buffer_size, + uint8_t * iv, + void *userdata) +{ + UNUSED(userdata); + + TSS2_RC r = TSS2_RC_SUCCESS; + const EVP_CIPHER *cipher_alg = NULL; + EVP_CIPHER_CTX *ctx = NULL; + int cipher_len; + + if (key == NULL || buffer == NULL) { + return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Bad reference"); + } + + LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 input"); + + if (key_bits == 128 && tpm_mode == TPM2_ALG_CFB) + cipher_alg = EVP_sm4_cfb128(); + else { + goto_error(r, TSS2_ESYS_RC_BAD_VALUE, + "SM4 algorithm not implemented or illegal mode (CFB expected).", + cleanup); + } + + if (tpm_sym_alg != TPM2_ALG_SM4) { + goto_error(r, TSS2_ESYS_RC_BAD_VALUE, + "SM4 encrypt called with wrong algorithm.", cleanup); + } + + /* Create and initialize the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, + "Initialize cipher context", cleanup); + } + + if (1 != EVP_EncryptInit(ctx, cipher_alg, key, iv)) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, + "Initialize cipher operation", cleanup); + } + + /* Perform the encryption */ + if (1 != EVP_EncryptUpdate(ctx, buffer, &cipher_len, buffer, buffer_size)) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt update", cleanup); + } + + if (1 != EVP_EncryptFinal(ctx, buffer, &cipher_len)) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt final", cleanup); + } + LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 output"); + +cleanup: + + OSSL_FREE(ctx,EVP_CIPHER_CTX); + + return r; +} + +/** Decrypt data with SM4. + * + * @param[in] key key used for SM4. + * @param[in] tpm_sym_alg SM4 type in TSS2 notation (must be TPM2_ALG_SM4). + * @param[in] key_bits Key size in bits. + * @param[in] tpm_mode Block cipher mode of opertion in TSS2 notation (CFB). + * For parameter encryption only CFB can be used. + * @param[in,out] buffer Data to be decrypted. The decrypted date will be stored + * in this buffer. + * @param[in] buffer_size size of data to be encrypted. + * @param[in] iv The initialization vector. + * @retval TSS2_RC_SUCCESS on success, or TSS2_ESYS_RC_BAD_VALUE and + * @retval TSS2_ESYS_RC_BAD_REFERENCE for invalid parameters, + * @retval TSS2_ESYS_RC_GENERAL_FAILURE for errors of the crypto library. + */ +TSS2_RC +iesys_cryptossl_sym_sm4_decrypt(uint8_t * key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t * buffer, + size_t buffer_size, + uint8_t * iv, + void *userdata) +{ + UNUSED(userdata); + + TSS2_RC r = TSS2_RC_SUCCESS; + const EVP_CIPHER *cipher_alg = NULL; + EVP_CIPHER_CTX *ctx = NULL; + int cipher_len = 0; + + if (key == NULL || buffer == NULL) { + return_error(TSS2_ESYS_RC_BAD_REFERENCE, "Bad reference"); + } + + if (tpm_sym_alg != TPM2_ALG_SM4) { + goto_error(r, TSS2_ESYS_RC_BAD_VALUE, + "SM4 decrypt called with wrong algorithm.", cleanup); + } + + if (key_bits == 128 && tpm_mode == TPM2_ALG_CFB) + cipher_alg = EVP_sm4_cfb128(); + else { + goto_error(r, TSS2_ESYS_RC_BAD_VALUE, + "SM4 algorithm not implemented or illegal mode (CFB expected).", + cleanup); + } + + /* Create and initialize the context */ + if(!(ctx = EVP_CIPHER_CTX_new())) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, + "Initialize cipher context", cleanup); + } + + LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 input"); + + if (1 != EVP_DecryptInit(ctx, cipher_alg, key, iv)) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, + "Initialize cipher operation", cleanup); + } + + /* Perform the decryption */ + if (1 != EVP_DecryptUpdate(ctx, buffer, &cipher_len, buffer, buffer_size)) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt update", cleanup); + } + + if (1 != EVP_DecryptFinal(ctx, buffer, &cipher_len)) { + goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Encrypt final", cleanup); + } + LOGBLOB_TRACE(buffer, buffer_size, "IESYS SM4 output"); + +cleanup: + + OSSL_FREE(ctx,EVP_CIPHER_CTX); + return r; +} +#endif /** Initialize OpenSSL crypto backend. * diff --git a/src/tss2-esys/esys_crypto_ossl.h b/src/tss2-esys/esys_crypto_ossl.h index ae3c33a..d8e84d6 100644 --- a/src/tss2-esys/esys_crypto_ossl.h +++ b/src/tss2-esys/esys_crypto_ossl.h @@ -109,6 +109,28 @@ TSS2_RC iesys_cryptossl_sym_aes_decrypt( uint8_t *iv, void *userdata); +#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) +TSS2_RC iesys_cryptossl_sym_sm4_encrypt( + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *dst, + size_t dst_size, + uint8_t *iv, + void *userdata); + +TSS2_RC iesys_cryptossl_sym_sm4_decrypt( + uint8_t *key, + TPM2_ALG_ID tpm_sym_alg, + TPMI_SM4_KEY_BITS key_bits, + TPM2_ALG_ID tpm_mode, + uint8_t *dst, + size_t dst_size, + uint8_t *iv, + void *userdata); +#endif + TSS2_RC iesys_cryptossl_get_ecdh_point( TPM2B_PUBLIC *key, size_t max_out_size, @@ -122,6 +144,13 @@ TSS2_RC iesys_cryptossl_get_ecdh_point( #define _iesys_crypto_get_ecdh_point iesys_cryptossl_get_ecdh_point #define _iesys_crypto_aes_encrypt iesys_cryptossl_sym_aes_encrypt #define _iesys_crypto_aes_decrypt iesys_cryptossl_sym_aes_decrypt +#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) +#define _iesys_crypto_sm4_encrypt iesys_cryptossl_sym_sm4_encrypt +#define _iesys_crypto_sm4_decrypt iesys_cryptossl_sym_sm4_decrypt +#else +#define _iesys_crypto_sm4_encrypt NULL +#define _iesys_crypto_sm4_decrypt NULL +#endif TSS2_RC iesys_cryptossl_init(void *userdata); diff --git a/src/tss2-esys/esys_int.h b/src/tss2-esys/esys_int.h index 49430a6..313ef0b 100644 --- a/src/tss2-esys/esys_int.h +++ b/src/tss2-esys/esys_int.h @@ -24,6 +24,7 @@ typedef struct RSRC_NODE_T { to reference this entry. */ TPM2B_AUTH auth; /**< The authValue for this resource object. */ IESYS_RESOURCE rsrc; /**< The meta data for this resource object. */ + size_t reference_count; /**< Reference Count for Esys_TR_FromTPMPublic */ struct RSRC_NODE_T * next; /**< The next object in the linked list. */ } RSRC_NODE_T; diff --git a/src/tss2-esys/esys_iutil.c b/src/tss2-esys/esys_iutil.c index c8346b3..b1c81f2 100644 --- a/src/tss2-esys/esys_iutil.c +++ b/src/tss2-esys/esys_iutil.c @@ -382,6 +382,38 @@ iesys_handle_to_tpm_handle(ESYS_TR esys_handle, TPM2_HANDLE * tpm_handle) *tpm_handle = TPM2_RH_PLATFORM_NV; return TPM2_RC_SUCCESS; } + if (esys_handle == ESYS_TR_RH_FW_OWNER) { + *tpm_handle = TPM2_RH_FW_OWNER; + return TPM2_RC_SUCCESS; + } + if (esys_handle == ESYS_TR_RH_FW_ENDORSEMENT) { + *tpm_handle = TPM2_RH_FW_ENDORSEMENT; + return TPM2_RC_SUCCESS; + } + if (esys_handle == ESYS_TR_RH_FW_PLATFORM) { + *tpm_handle = TPM2_RH_FW_PLATFORM; + return TPM2_RC_SUCCESS; + } + if (esys_handle == ESYS_TR_RH_FW_NULL) { + *tpm_handle = TPM2_RH_FW_NULL; + return TPM2_RC_SUCCESS; + } + if ((esys_handle & 0xFFFF0000) == ESYS_TR_RH_SVN_OWNER_BASE) { + *tpm_handle = TPM2_RH_SVN_OWNER_BASE + (esys_handle & 0x0000FFFF); + return TPM2_RC_SUCCESS; + } + if ((esys_handle & 0xFFFF0000) == ESYS_TR_RH_SVN_ENDORSEMENT_BASE) { + *tpm_handle = TPM2_RH_SVN_ENDORSEMENT_BASE + (esys_handle & 0x0000FFFF); + return TPM2_RC_SUCCESS; + } + if ((esys_handle & 0xFFFF0000) == ESYS_TR_RH_SVN_PLATFORM_BASE) { + *tpm_handle = TPM2_RH_SVN_PLATFORM_BASE + (esys_handle & 0x0000FFFF); + return TPM2_RC_SUCCESS; + } + if ((esys_handle & 0xFFFF0000) == ESYS_TR_RH_SVN_NULL_BASE) { + *tpm_handle = TPM2_RH_SVN_NULL_BASE + (esys_handle & 0x0000FFFF); + return TPM2_RC_SUCCESS; + } if (esys_handle >= ESYS_TR_RH_ACT_FIRST && esys_handle <= ESYS_TR_RH_ACT_LAST) { *tpm_handle = TPM2_RH_ACT_0 + (esys_handle - ESYS_TR_RH_ACT_FIRST); @@ -392,7 +424,7 @@ iesys_handle_to_tpm_handle(ESYS_TR esys_handle, TPM2_HANDLE * tpm_handle) *tpm_handle = TPM2_NV_AC_FIRST + (esys_handle - ESYS_TR_RH_AC_FIRST); return TPM2_RC_SUCCESS; } - LOG_ERROR("Error: Esys invalid ESAPI handle (%x).", esys_handle); + LOG_ERROR("Error: Esys invalid ESAPI handle (%"PRIx32").", esys_handle); return TSS2_ESYS_RC_BAD_VALUE; } @@ -413,7 +445,7 @@ iesys_is_platform_handle(ESYS_TR handle) { case TPM2_RH_PLATFORM_NV: case TPM2_RH_ENDORSEMENT: case TPM2_RH_NULL: - LOG_WARNING("Convert handle from TPM2_RH to ESYS_TR, got: 0x%x", + LOG_WARNING("Convert handle from TPM2_RH to ESYS_TR, got: 0x%"PRIx32, handle); return true; default: @@ -574,7 +606,7 @@ iesys_gen_caller_nonces(ESYS_CONTEXT * esys_context) r = iesys_crypto_get_random2b(&esys_context->crypto_backend, &session->rsrc.misc.rsrc_session.nonceCaller, session->rsrc.misc.rsrc_session.nonceCaller.size); - return_if_error(r, "Error: computing caller nonce (%x)."); + return_if_error(r, "Error: computing caller nonce."); } return TSS2_RC_SUCCESS; } @@ -612,7 +644,7 @@ iesys_update_session_flags(ESYS_CONTEXT * esys_context, rsrc_session->sessionAttributes &= ~(TPMA_SESSION_ENCRYPT); } - LOG_DEBUG("Session Attrs 0x%x orig 0x%x", + LOG_DEBUG("Session Attrs 0x%"PRIx32" orig 0x%"PRIx32, rsrc_session->sessionAttributes, rsrc_session->origSessionAttributes); } @@ -633,7 +665,7 @@ iesys_restore_session_flags(ESYS_CONTEXT *esys_context) if (session == NULL) continue; IESYS_SESSION *rsrc_session = &session->rsrc.misc.rsrc_session; - LOG_DEBUG("Orig Session %i Attrs 0x%x, altered Attrs x%x", i, + LOG_DEBUG("Orig Session %i Attrs 0x%"PRIx8", altered Attrs x%"PRIx8, i, rsrc_session->origSessionAttributes, rsrc_session->sessionAttributes); @@ -745,6 +777,31 @@ iesys_encrypt_param(ESYS_CONTEXT * esys_context, &encrypt_buffer[0], paramSize, &symKey[aes_off]); return_if_error(r, "AES encryption not possible"); + } else if (symDef->algorithm == TPM2_ALG_SM4) { + /* SM4 encryption with key derived with KDFa */ + if (symDef->mode.sm4 != TPM2_ALG_CFB) { + return_error(TSS2_ESYS_RC_BAD_VALUE, + "Invalid symmetric mode (must be CFB)"); + } + r = iesys_crypto_KDFa(&esys_context->crypto_backend, rsrc_session->authHash, + &rsrc_session->sessionValue[0], + rsrc_session->sizeSessionValue, "CFB", + &rsrc_session->nonceCaller, + &rsrc_session->nonceTPM, + symDef->keyBits.sm4 + SM4_BLOCK_SIZE_IN_BYTES * 8, + NULL, &symKey[0], FALSE); + return_if_error(r, "while computing KDFa"); + + size_t sm4_off = ( symDef->keyBits.sm4 + 7) / 8; + r = iesys_crypto_sm4_encrypt( + &esys_context->crypto_backend, + &symKey[0], + symDef->algorithm, + symDef->keyBits.sm4, + symDef->mode.sm4, + &encrypt_buffer[0], paramSize, + &symKey[sm4_off]); + return_if_error(r, "SM4 encryption not possible"); } /* XOR obfuscation of parameter */ else if (symDef->algorithm == TPM2_ALG_XOR) { @@ -760,7 +817,7 @@ iesys_encrypt_param(ESYS_CONTEXT * esys_context, } else { return_error(TSS2_ESYS_RC_BAD_VALUE, - "Invalid symmetric algorithm (should be XOR or AES)"); + "Invalid symmetric algorithm (should be XOR, AES, or SM4)"); } r = Tss2_Sys_SetDecryptParam(esys_context->sys, paramSize, &encrypt_buffer[0]); @@ -848,6 +905,43 @@ iesys_decrypt_param(ESYS_CONTEXT * esys_context) &symKey[aes_off]); return_if_error(r, "Decryption error"); + r = Tss2_Sys_SetEncryptParam(esys_context->sys, p2BSize, &plaintext[0]); + return_if_error(r, "Setting plaintext"); + } else if (symDef->algorithm == TPM2_ALG_SM4) { + /* Parameter decryption with a symmetric SM4 key derived by KDFa */ + if (symDef->mode.sm4 != TPM2_ALG_CFB) { + return_error(TSS2_ESYS_RC_BAD_VALUE, + "Invalid symmetric mode (must be CFB)"); + } + LOGBLOB_DEBUG(&rsrc_session->sessionKey.buffer[0], + rsrc_session->sessionKey.size, + "IESYS encrypt session key"); + + r = iesys_crypto_KDFa(&esys_context->crypto_backend, rsrc_session->authHash, + &rsrc_session->sessionValue[0], + rsrc_session->sizeSessionValue, + "CFB", &rsrc_session->nonceTPM, + &rsrc_session->nonceCaller, + symDef->keyBits.sm4 + + SM4_BLOCK_SIZE_IN_BYTES * 8, NULL, + &symKey[0], FALSE); + return_if_error(r, "KDFa error"); + LOGBLOB_DEBUG(&symKey[0], + ((symDef->keyBits.sm4 + + SM4_BLOCK_SIZE_IN_BYTES * 8) + 7) / 8, + "IESYS encrypt KDFa key"); + + size_t sm4_off = ( symDef->keyBits.sm4 + 7) / 8; + r = iesys_crypto_sm4_decrypt( + &esys_context->crypto_backend, + &symKey[0], + symDef->algorithm, + symDef->keyBits.sm4, + symDef->mode.sm4, + &plaintext[0], p2BSize, + &symKey[sm4_off]); + return_if_error(r, "Decryption error"); + r = Tss2_Sys_SetEncryptParam(esys_context->sys, p2BSize, &plaintext[0]); return_if_error(r, "Setting plaintext"); } else if (symDef->algorithm == TPM2_ALG_XOR) { @@ -866,7 +960,7 @@ iesys_decrypt_param(ESYS_CONTEXT * esys_context) return_if_error(r, "Setting plaintext"); } else { return_error(TSS2_ESYS_RC_BAD_VALUE, - "Invalid symmetric algorithm (should be XOR or AES)"); + "Invalid symmetric algorithm (should be XOR, AES, or SM4)"); } return TSS2_RC_SUCCESS; } @@ -1104,7 +1198,7 @@ esys_GetResourceObject(ESYS_CONTEXT * esys_context, /* All objects with a TR-handle larger than ESYS_TR_MIN_OBJECT must have been initialized previously. Therefore the TR handle was erroneous. */ if (esys_handle >= ESYS_TR_MIN_OBJECT) { - LOG_ERROR("Error: Esys handle does not exist (%x).", + LOG_ERROR("Error: Esys handle does not exist (0x%08"PRIx32").", TSS2_ESYS_RC_BAD_TR); return TSS2_ESYS_RC_BAD_TR; } @@ -1591,11 +1685,28 @@ iesys_tpm_error(TSS2_RC r) (r & TSS2_RC_LAYER_MASK) == TSS2_RESMGR_RC_LAYER)); } +/** Remove trailing spaces includes auth value. + * + * Trailing zeros will be removed. + * + * @param[in,out] auth_value The auth value to be adapted. + */ +void iesys_strip_trailing_zeros(TPM2B_DIGEST *digest) +{ + /* Remove trailing zeroes */ + if (digest) { + while (digest->size > 0 && + digest->buffer[digest->size - 1] == 0) { + digest->size--; + } + } +} -/** Replace auth value with Hash for long auth values. +/** Adapt auth value. * * if the size of auth value exceeds hash_size the auth value * will be replaced with the hash of the auth value. + * Trailing zeros will be removed. * * @param[in,out] auth_value The auth value to be adapted. * @param[in] hash_alg The hash alg used for adaption. @@ -1606,37 +1717,46 @@ iesys_tpm_error(TSS2_RC r) * computation. */ TSS2_RC -iesys_hash_long_auth_values( +iesys_adapt_auth_value( ESYS_CRYPTO_CALLBACKS *crypto_cb, TPM2B_AUTH *auth_value, TPMI_ALG_HASH hash_alg) { - TSS2_RC r; + TSS2_RC r = TSS2_RC_SUCCESS; ESYS_CRYPTO_CONTEXT_BLOB *cryptoContext; TPM2B_AUTH hash2b; size_t hash_size; - r = iesys_crypto_hash_get_digest_size(hash_alg, &hash_size); - return_if_error(r, "Get digest size."); + /* Remove trailing zeroes */ + iesys_strip_trailing_zeros(auth_value); - if (auth_value && auth_value->size > hash_size) { - /* The auth value has to be adapted. */ - r = iesys_crypto_hash_start(crypto_cb, - &cryptoContext, hash_alg); - return_if_error(r, "crypto hash start"); + if (hash_alg) { + r = iesys_crypto_hash_get_digest_size(hash_alg, &hash_size); + return_if_error(r, "Get digest size."); - r = iesys_crypto_hash_update(crypto_cb, - cryptoContext, &auth_value->buffer[0], - auth_value->size); - goto_if_error(r, "crypto hash update", error_cleanup); + if (auth_value && auth_value->size > hash_size) { + /* The auth value has to be adapted. */ + r = iesys_crypto_hash_start(crypto_cb, + &cryptoContext, hash_alg); + return_if_error(r, "crypto hash start"); - r = iesys_crypto_hash_finish(crypto_cb, - &cryptoContext, &hash2b.buffer[0], &hash_size); - goto_if_error(r, "crypto hash finish", error_cleanup); + r = iesys_crypto_hash_update(crypto_cb, + cryptoContext, &auth_value->buffer[0], + auth_value->size); + goto_if_error(r, "crypto hash update", error_cleanup); - memcpy(&auth_value->buffer[0], &hash2b.buffer[0], hash_size); - auth_value->size = hash_size; + r = iesys_crypto_hash_finish(crypto_cb, + &cryptoContext, &hash2b.buffer[0], &hash_size); + goto_if_error(r, "crypto hash finish", error_cleanup); + + memcpy(&auth_value->buffer[0], &hash2b.buffer[0], hash_size); + auth_value->size = hash_size; + + /* Remove trailing zeroes */ + iesys_strip_trailing_zeros(auth_value); + } } + return r; error_cleanup: diff --git a/src/tss2-esys/esys_iutil.h b/src/tss2-esys/esys_iutil.h index 4e9cfd9..c7bb9af 100644 --- a/src/tss2-esys/esys_iutil.h +++ b/src/tss2-esys/esys_iutil.h @@ -171,11 +171,14 @@ TSS2_RC iesys_get_name( bool iesys_tpm_error( TSS2_RC r); -TSS2_RC iesys_hash_long_auth_values( +TSS2_RC iesys_adapt_auth_value( ESYS_CRYPTO_CALLBACKS *crypto_cb, TPM2B_AUTH *auth_value, TPMI_ALG_HASH hash_alg); +void iesys_strip_trailing_zeros( + TPM2B_AUTH *auth_value); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/tss2-esys/esys_tr.c b/src/tss2-esys/esys_tr.c index f15d42a..a81eac7 100644 --- a/src/tss2-esys/esys_tr.c +++ b/src/tss2-esys/esys_tr.c @@ -67,9 +67,9 @@ Esys_TR_Serialize(ESYS_CONTEXT * esys_context, * stored on disk for later use by a different program or context. * An object can be deserialized using Esys_TR_Deserialize. * @param esys_context [in,out] The ESYS_CONTEXT. - * @param esys_handle [out] The ESYS_TR object to deserialize. * @param buffer [in] The buffer containing the metadata of the ESYS_TR object. * @param buffer_size [in] The size of the buffer parameter. + * @param esys_handle [out] The ESYS_TR object to deserialize. * @retval TSS2_RC_SUCCESS on Success. * @retval TSS2_ESYS_RC_MEMORY if the object can not be allocated. * @retval TSS2_ESYS_RC_INSUFFICIENT_BUFFER if the buffer for unmarshalling. @@ -284,6 +284,9 @@ Esys_TR_FromTPMPublic_Finish(ESYS_CONTEXT * esys_context, ESYS_TR * object) } else { if (objectHandleNode->rsrc.name.size != name->size || memcmp(&objectHandleNode->rsrc.name.name[0], &name->name[0], name->size) != 0) { + SAFE_FREE(public); + SAFE_FREE(name); + SAFE_FREE(qualifiedName); goto_error(r, TSS2_ESYS_RC_GENERAL_FAILURE, "Name mismatch between two calls of Esys_TR_FromTPMPublic", error_cleanup); @@ -313,6 +316,7 @@ Esys_TR_FromTPMPublic_Finish(ESYS_CONTEXT * esys_context, ESYS_TR * object) return_if_error(r, "Error TR FromTPMPublic"); return TSS2_ESYS_RC_TRY_AGAIN; } else { + objectHandleNode->reference_count++; *object = objectHandle; return TSS2_RC_SUCCESS; } @@ -425,13 +429,17 @@ Esys_TR_Close(ESYS_CONTEXT * esys_context, ESYS_TR * object) node != NULL; update_ptr = &node->next, node = node->next) { if (node->esys_handle == *object) { + if (node->reference_count > 1) { + node->reference_count--; + return TSS2_RC_SUCCESS; + } *update_ptr = node->next; SAFE_FREE(node); *object = ESYS_TR_NONE; return TSS2_RC_SUCCESS; } } - LOG_ERROR("Error: Esys handle does not exist (%x).", TSS2_ESYS_RC_BAD_TR); + LOG_ERROR("Error: Esys handle does not exist (0x%08"PRIx32").", TSS2_ESYS_RC_BAD_TR); return TSS2_ESYS_RC_BAD_TR; } @@ -479,14 +487,20 @@ Esys_TR_SetAuth(ESYS_CONTEXT * esys_context, ESYS_TR esys_handle, name_alg = esys_object->rsrc.misc.rsrc_key_pub.publicArea.nameAlg; } else if (esys_object->rsrc.rsrcType == IESYSC_NV_RSRC) { name_alg = esys_object->rsrc.misc.rsrc_nv_pub.nvPublic.nameAlg; + } else { + name_alg = TPM2_ALG_NULL; } esys_object->auth = *authValue; - /* Adapt auth value to hash for large auth values. */ + + /* Adapt auth value. */ if (name_alg != TPM2_ALG_NULL) { - r = iesys_hash_long_auth_values(&esys_context->crypto_backend, + r = iesys_adapt_auth_value(&esys_context->crypto_backend, &esys_object->auth, name_alg); return_if_error(r, "Hashing overlength authValue failed."); + } else { + iesys_strip_trailing_zeros(&esys_object->auth); } + } return TSS2_RC_SUCCESS; } diff --git a/src/tss2-esys/openssl.props b/src/tss2-esys/openssl.props new file mode 100644 index 0000000..cb6e5de --- /dev/null +++ b/src/tss2-esys/openssl.props @@ -0,0 +1,11 @@ + + + + + C:\OpenSSL-v11-Win64 + C:\OpenSSL-v11-Win32 + + + + + diff --git a/src/tss2-esys/tss2-esys.vcxproj b/src/tss2-esys/tss2-esys.vcxproj index d80ce88..39bcf15 100644 --- a/src/tss2-esys/tss2-esys.vcxproj +++ b/src/tss2-esys/tss2-esys.vcxproj @@ -22,28 +22,28 @@ 15.0 {BE0516D7-994C-4133-BD91-A21239D8B087} Win32Proj - 10.0.17134.0 + 10.0 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -52,15 +52,19 @@ + + + + @@ -69,13 +73,13 @@ MultiThreadedDebugDLL Level3 Disabled - $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;C:\OpenSSL-v11-Win32\include;%(AdditionalIncludeDirectories) + $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;$(OpenSslDir32Bit)\include;%(AdditionalIncludeDirectories) MachineX86 true Windows - $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;C:\OpenSSL-v11-Win32\lib\libcrypto.lib;C:\OpenSSL-v11-Win32\lib\libcrypto.lib;%(AdditionalDependencies) + $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;$(OpenSslDir32Bit)\lib\libcrypto.lib;$(OpenSslDir32Bit)\lib\libcrypto.lib;%(AdditionalDependencies) $(SolutionDir)\lib\tss2-esys.def @@ -84,7 +88,7 @@ WIN32;NDEBUG;_WINDOWS;_USRDLL;TSS2ESYS_EXPORTS;MAXLOGLEVEL=6;strtok_r=strtok_s;OSSL;%(PreprocessorDefinitions) MultiThreadedDLL Level3 - $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;C:\OpenSSL-v11-Win32\include;%(AdditionalIncludeDirectories) + $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;$(OpenSslDir32Bit)\include;%(AdditionalIncludeDirectories) MachineX86 @@ -92,27 +96,27 @@ Windows true true - $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;C:\OpenSSL-v11-Win32\lib\libcrypto.lib;%(AdditionalDependencies) + $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;$(OpenSslDir32Bit)\lib\libcrypto.lib;%(AdditionalDependencies) $(SolutionDir)\lib\tss2-esys.def - $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;C:\OpenSSL-v11-Win64\include;%(AdditionalIncludeDirectories) + $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;$(OpenSslDir)\include;%(AdditionalIncludeDirectories) _DEBUG;_WINDOWS;_USRDLL;TSS2ESYS_EXPORTS;MAXLOGLEVEL=6;strtok_r=strtok_s;OSSL;%(PreprocessorDefinitions) - $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;C:\OpenSSL-v11-Win64\lib\libcrypto.lib;%(AdditionalDependencies) + $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;$(OpenSslDir)\lib\libcrypto.lib;%(AdditionalDependencies) $(SolutionDir)\lib\tss2-esys.def - $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;C:\OpenSSL-v11-Win64\include;%(AdditionalIncludeDirectories) + $(SolutionDir);$(SolutionDir)\src;$(SolutionDir)\include\tss2;$(SolutionDir)\src\tss2-mu;$(SolutionDir)\src\tss2-sys;$(SolutionDir)\src\tss2-esys;$(OpenSslDir)\include;%(AdditionalIncludeDirectories) NDEBUG;_WINDOWS;_USRDLL;TSS2ESYS_EXPORTS;MAXLOGLEVEL=6;strtok_r=strtok_s;OSSL;%(PreprocessorDefinitions) - $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;C:\OpenSSL-v11-Win64\lib\libcrypto.lib;%(AdditionalDependencies) + $(OutDir)\tss2-mu.lib;$(OutDir)\tss2-sys.lib;$(OutDir)\tss2-tctildr.lib;$(OpenSslDir)\lib\libcrypto.lib;%(AdditionalDependencies) $(SolutionDir)\lib\tss2-esys.def @@ -260,4 +264,4 @@ - + \ No newline at end of file diff --git a/src/tss2-fapi/api/Fapi_AuthorizePolicy.c b/src/tss2-fapi/api/Fapi_AuthorizePolicy.c index a923c03..19bde9a 100644 --- a/src/tss2-fapi/api/Fapi_AuthorizePolicy.c +++ b/src/tss2-fapi/api/Fapi_AuthorizePolicy.c @@ -366,7 +366,6 @@ Fapi_AuthorizePolicy_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", cleanup); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -383,6 +382,7 @@ Fapi_AuthorizePolicy_Finish( ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); SAFE_FREE(command->policyPath); SAFE_FREE(command->signingKeyPath); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_ChangeAuth.c b/src/tss2-fapi/api/Fapi_ChangeAuth.c index adaa3f8..42e994c 100644 --- a/src/tss2-fapi/api/Fapi_ChangeAuth.c +++ b/src/tss2-fapi/api/Fapi_ChangeAuth.c @@ -188,7 +188,7 @@ Fapi_ChangeAuth_Async( /* Get a session for further authorizing and integrity checking the subsequent ChangeAuth calls. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -352,7 +352,8 @@ Fapi_ChangeAuth_Finish( command->handle, context->loadKey.parent_handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &command->newAuthValue); goto_if_error(r, "Error: Sign", error_cleanup); @@ -444,7 +445,6 @@ Fapi_ChangeAuth_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; LOG_TRACE("success"); break; @@ -481,7 +481,7 @@ Fapi_ChangeAuth_Finish( r = Esys_NV_ChangeAuth_Async(context->esys, command->object.public.handle, auth_session, - ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), ESYS_TR_NONE, &command->newAuthValue); goto_if_error(r, "Error: NV_ChangeAuth", error_cleanup); @@ -608,5 +608,6 @@ Fapi_ChangeAuth_Finish( SAFE_FREE(command->pathlist); } LOG_TRACE("finished"); + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_CreateKey.c b/src/tss2-fapi/api/Fapi_CreateKey.c index d5549f3..a6a239e 100644 --- a/src/tss2-fapi/api/Fapi_CreateKey.c +++ b/src/tss2-fapi/api/Fapi_CreateKey.c @@ -175,6 +175,9 @@ Fapi_CreateKey_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + attributes = &context->cmd.Key_Create.public_templ.public.publicArea.objectAttributes; /* Reset all context-internal session state information. */ @@ -307,6 +310,7 @@ Fapi_CreateKey_Finish( ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_CreateNv.c b/src/tss2-fapi/api/Fapi_CreateNv.c index ad736ba..ed18269 100644 --- a/src/tss2-fapi/api/Fapi_CreateNv.c +++ b/src/tss2-fapi/api/Fapi_CreateNv.c @@ -398,8 +398,8 @@ Fapi_CreateNv_Finish( /* Start a authorization session for the NV creation. */ context->primary_state = PRIMARY_INIT; r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, - 0, 0); + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, + TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; @@ -421,7 +421,7 @@ Fapi_CreateNv_Finish( r = Esys_NV_DefineSpace_Async(context->esys, hierarchy->public.handle, auth_session, - ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), ESYS_TR_NONE, auth, publicInfo); diff --git a/src/tss2-fapi/api/Fapi_Decrypt.c b/src/tss2-fapi/api/Fapi_Decrypt.c index dcf4447..e6e8afe 100644 --- a/src/tss2-fapi/api/Fapi_Decrypt.c +++ b/src/tss2-fapi/api/Fapi_Decrypt.c @@ -168,6 +168,9 @@ Fapi_Decrypt_Async( check_not_null(keyPath); check_not_null(cipherText); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_Data_EncryptDecrypt * command = &(context->cmd.Data_EncryptDecrypt); @@ -265,7 +268,7 @@ Fapi_Decrypt_Finish( /* Initialize a session used for authorization and parameter encryption. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_ENCRYPT | TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -315,7 +318,9 @@ Fapi_Decrypt_Finish( /* Decrypt the actual data. */ r = Esys_RSA_Decrypt_Async(context->esys, context->cmd.Data_EncryptDecrypt.key_handle, - command->auth_session, ESYS_TR_NONE, ESYS_TR_NONE, + command->auth_session, + ENC_SESSION_IF_POLICY(command->auth_session), + ESYS_TR_NONE, aux_data, &command->profile->rsa_decrypt_scheme, &null_data); @@ -407,6 +412,6 @@ Fapi_Decrypt_Finish( ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); - + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_Delete.c b/src/tss2-fapi/api/Fapi_Delete.c index a0cd264..b41c108 100644 --- a/src/tss2-fapi/api/Fapi_Delete.c +++ b/src/tss2-fapi/api/Fapi_Delete.c @@ -374,6 +374,9 @@ Fapi_Delete_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_Entity_Delete * command = &(context->cmd.Entity_Delete); IFAPI_OBJECT *object = &command->object; @@ -443,7 +446,7 @@ Fapi_Delete_Async( goto_if_error(r, "Initialize Entity_Delete", error_cleanup); r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, 0, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -550,7 +553,7 @@ Fapi_Delete_Finish( /* Load the object metadata from the keystore. */ r = ifapi_keystore_load_async(&context->keystore, &context->io, path); - return_if_error2(r, "Could not open: %s", path); + goto_if_error2(r, "Could not open: %s", error_cleanup, path); fallthrough; @@ -559,7 +562,7 @@ Fapi_Delete_Finish( TPM operations; e.g. persistent key or NV index. */ r = ifapi_keystore_load_finish(&context->keystore, &context->io, object); return_try_again(r); - return_if_error_reset_state(r, "read_finish failed"); + goto_if_error(r, "read_finish failed", error_cleanup); /* Initialize the ESYS object for the persistent key or NV Index. */ r = ifapi_initialize_object(context->esys, object); @@ -579,7 +582,7 @@ Fapi_Delete_Finish( /* Check whether hierarchy file has been read. */ if (authObject->objectType == IFAPI_OBJ_NONE) { r = ifapi_keystore_load_async(&context->keystore, &context->io, "/HS"); - return_if_error2(r, "Could not open hierarchy /HS"); + goto_if_error(r, "Could not open hierarchy /HS", error_cleanup); command->auth_index = ESYS_TR_RH_OWNER; } else { @@ -624,7 +627,7 @@ Fapi_Delete_Finish( statecase(context->state, ENTITY_DELETE_KEY); if (object->misc.key.persistent_handle) { r = ifapi_keystore_load_async(&context->keystore, &context->io, "/HS"); - return_if_error2(r, "Could not open hierarchy /HS"); + goto_if_error(r, "Could not open hierarchy /HS", error_cleanup); } fallthrough; @@ -632,7 +635,7 @@ Fapi_Delete_Finish( if (object->misc.key.persistent_handle) { r = ifapi_keystore_load_finish(&context->keystore, &context->io, authObject); return_try_again(r); - return_if_error(r, "read_finish failed"); + goto_if_error(r, "read_finish failed", error_cleanup); r = ifapi_initialize_object(context->esys, authObject); goto_if_error_reset_state(r, "Initialize hierarchy object", error_cleanup); @@ -658,8 +661,9 @@ Fapi_Delete_Finish( r = Esys_EvictControl_Async(context->esys, ESYS_TR_RH_OWNER, object->public.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, - object->misc.key.persistent_handle); + ESYS_TR_NONE, + ESYS_TR_NONE, + object->misc.key.persistent_handle); goto_if_error(r, "Evict Control", error_cleanup); context->state = ENTITY_DELETE_NULL_AUTH_SENT_FOR_KEY; } @@ -785,5 +789,6 @@ Fapi_Delete_Finish( SAFE_FREE(command->pathlist); ifapi_session_clean(context); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_Encrypt.c b/src/tss2-fapi/api/Fapi_Encrypt.c index af8e2c5..e4e236a 100644 --- a/src/tss2-fapi/api/Fapi_Encrypt.c +++ b/src/tss2-fapi/api/Fapi_Encrypt.c @@ -179,12 +179,20 @@ Fapi_Encrypt_Async( check_not_null(keyPath); check_not_null(plainText); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_Data_EncryptDecrypt * command = &(context->cmd.Data_EncryptDecrypt); r = ifapi_session_init(context); return_if_error(r, "Initialize Encrypt"); + if (strncmp(keyPath, "/ext", 4) == 0) { + r = ifapi_non_tpm_mode_init(context); + return_if_error(r, "Initialize RSA Encrypt with OpenSSL"); + } + /* Copy parameters to context for use during _Finish. */ uint8_t *inData = malloc(plainTextSize); goto_if_null(inData, "Out of memory", r, error_cleanup); @@ -259,7 +267,7 @@ Fapi_Encrypt_Finish( /* Helpful alias pointers */ IFAPI_Data_EncryptDecrypt * command = &context->cmd.Data_EncryptDecrypt; - IFAPI_OBJECT *encKeyObject; + TPM2B_PUBLIC *public; TPM2B_PUBLIC_KEY_RSA *tpmCipherText = NULL; switch (context->state) { @@ -271,17 +279,26 @@ Fapi_Encrypt_Finish( return_try_again(r); goto_if_error_reset_state(r, " FAPI create session", error_cleanup); + if (strncmp(command->keyPath, "/ext", 4) == 0) { + /* Load the key for enryption from the keystore. */ + r = ifapi_keystore_load_async(&context->keystore, &context->io, command->keyPath); + goto_if_error2(r, "Could not open: %s", error_cleanup, command->keyPath); + + context->state = DATA_ENCRYPT_WAIT_FOR_EXT_KEY; + return TSS2_FAPI_RC_TRY_AGAIN; + } + /* Initialize a session used for authorization and parameter encryption. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_ENCRYPT | TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; statecase(context->state, DATA_ENCRYPT_WAIT_FOR_SESSION); - r = ifapi_get_sessions_finish(context, &context->profiles.default_profile, - context->profiles.default_profile.nameAlg); + r = ifapi_get_sessions_finish(context, &context->profiles.default_profile, + context->profiles.default_profile.nameAlg); return_try_again(r); goto_if_error(r, "Get session.", error_cleanup); @@ -298,13 +315,13 @@ Fapi_Encrypt_Finish( return_try_again(r); goto_if_error_reset_state(r, " Load key.", error_cleanup); - encKeyObject = command->key_object; + public = &command->key_object->misc.key.public; - if (encKeyObject->misc.key.public.publicArea.type == TPM2_ALG_RSA) { + if (public->publicArea.type == TPM2_ALG_RSA) { TPM2B_DATA null_data = { .size = 0, .buffer = {} }; TPM2B_PUBLIC_KEY_RSA *rsa_message = (TPM2B_PUBLIC_KEY_RSA *)&context->aux_data; size_t key_size = - encKeyObject->misc.key.public.publicArea.parameters.rsaDetail.keyBits / 8; + public->publicArea.parameters.rsaDetail.keyBits / 8; if (context->cmd.Data_EncryptDecrypt.in_dataSize > key_size) { goto_error_reset_state(r, TSS2_FAPI_RC_BAD_VALUE, "Size to big for RSA encryption.", error_cleanup); @@ -328,13 +345,13 @@ Fapi_Encrypt_Finish( goto_if_error(r, "Error esys rsa encrypt", error_cleanup); context-> state = DATA_ENCRYPT_WAIT_FOR_RSA_ENCRYPTION; - } else if (encKeyObject->misc.key.public.publicArea.type == TPM2_ALG_ECC) { + } else if (public->publicArea.type == TPM2_ALG_ECC) { goto_error(r, TSS2_FAPI_RC_NOT_IMPLEMENTED, "ECC Encryption not yet supported", error_cleanup); } else { goto_error(r, TSS2_FAPI_RC_NOT_IMPLEMENTED, "Unsupported algorithm (%" PRIu16 ")", - error_cleanup, encKeyObject->misc.key.public.publicArea.type); + error_cleanup, public->publicArea.type); } fallthrough; @@ -360,7 +377,8 @@ Fapi_Encrypt_Finish( SAFE_FREE(tpmCipherText); /* Flush the key from the TPM. */ - if (!command->key_object->misc.key.persistent_handle) { + if (strncmp(command->keyPath, "/ext", 4) == 0 || + !command->key_object->misc.key.persistent_handle) { r = Esys_FlushContext_Async(context->esys, command->key_handle); goto_if_error(r, "Error: FlushContext", error_cleanup); @@ -368,7 +386,8 @@ Fapi_Encrypt_Finish( fallthrough; statecase(context->state, DATA_ENCRYPT_WAIT_FOR_FLUSH); - if (!command->key_object->misc.key.persistent_handle) { + if (strncmp(command->keyPath, "/ext", 4) == 0 || + !command->key_object->misc.key.persistent_handle) { r = Esys_FlushContext_Finish(context->esys); return_try_again(r); @@ -387,6 +406,28 @@ Fapi_Encrypt_Finish( *cipherTextSize = command->cipherTextSize; break; + statecase(context->state, DATA_ENCRYPT_WAIT_FOR_EXT_KEY) + command->key_object = ifapi_allocate_object(context); + goto_if_null2(command->key_object, "Allocating key", r, + TSS2_FAPI_RC_MEMORY, error_cleanup); + + r = ifapi_keystore_load_finish(&context->keystore, &context->io, + command->key_object); + return_try_again(r); + return_if_error_reset_state(r, "read_finish failed"); + + r = ifapi_rsa_encrypt(command->key_object->misc.ext_pub_key.pem_ext_public, + &command->profile->rsa_decrypt_scheme, + command->in_data, command->in_dataSize, + &command->cipherText, &command->cipherTextSize); + + goto_if_error_reset_state(r, "rsa encrypt with openssl.", error_cleanup); + + *cipherText = command->cipherText; + if (cipherTextSize) + *cipherTextSize = command->cipherTextSize; + break; + statecasedefault(context->state); } @@ -394,7 +435,8 @@ Fapi_Encrypt_Finish( error_cleanup: /* Cleanup any intermediate results and state stored in the context. */ - if (command->key_handle != ESYS_TR_NONE) + if (command->key_handle != ESYS_TR_NONE && + command->key_object && !command->key_object->misc.key.persistent_handle) Esys_FlushContext(context->esys, command->key_handle); if (r) SAFE_FREE(command->cipherText); diff --git a/src/tss2-fapi/api/Fapi_ExportKey.c b/src/tss2-fapi/api/Fapi_ExportKey.c index 7b6af64..87bc5a9 100644 --- a/src/tss2-fapi/api/Fapi_ExportKey.c +++ b/src/tss2-fapi/api/Fapi_ExportKey.c @@ -182,6 +182,9 @@ Fapi_ExportKey_Async( check_not_null(context); check_not_null(pathOfKeyToDuplicate); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_ExportKey * command = &context->cmd.ExportKey; @@ -391,7 +394,8 @@ Fapi_ExportKey_Finish( command->key_object->public.handle, command->handle_ext_key, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &encryptionKey, &symmetric); goto_if_error(r, "Duplicate", cleanup); @@ -426,6 +430,8 @@ Fapi_ExportKey_Finish( return_try_again(r); goto_if_error(r, "Flush key", cleanup); + command->key_object->public.handle = ESYS_TR_NONE; + fallthrough; statecase(context->state, EXPORT_KEY_WAIT_FOR_FLUSH2); @@ -434,6 +440,8 @@ Fapi_ExportKey_Finish( return_try_again(r); goto_if_error(r, "Flush key", cleanup); + command->handle_ext_key = ESYS_TR_NONE; + fallthrough; statecase(context->state, EXPORT_KEY_CLEANUP) diff --git a/src/tss2-fapi/api/Fapi_ExportPolicy.c b/src/tss2-fapi/api/Fapi_ExportPolicy.c index 1d978af..e5885c6 100644 --- a/src/tss2-fapi/api/Fapi_ExportPolicy.c +++ b/src/tss2-fapi/api/Fapi_ExportPolicy.c @@ -136,6 +136,9 @@ Fapi_ExportPolicy_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_ExportPolicy * command = &context->cmd.ExportPolicy; @@ -287,14 +290,14 @@ Fapi_ExportPolicy_Finish( /* Load the key meta data from the keystore. */ r = ifapi_keystore_load_async(&context->keystore, &context->io, command->path); - return_if_error2(r, "Could not open: %s", command->path); + goto_if_error2(r, "Could not open: %s", error_cleanup, command->path); fallthrough; statecase(context->state, POLICY_EXPORT_READ_OBJECT_FINISH); r = ifapi_keystore_load_finish(&context->keystore, &context->io, &command->object); return_try_again(r); - return_if_error_reset_state(r, "read_finish failed"); + goto_if_error(r, "read_finish failed", error_cleanup); goto_if_null2(command->object.policy, "Object has no policy", diff --git a/src/tss2-fapi/api/Fapi_Finalize.c b/src/tss2-fapi/api/Fapi_Finalize.c index 0b28b6d..10de2ef 100644 --- a/src/tss2-fapi/api/Fapi_Finalize.c +++ b/src/tss2-fapi/api/Fapi_Finalize.c @@ -80,7 +80,7 @@ Fapi_Finalize( SAFE_FREE((*context)->config.tcti); SAFE_FREE((*context)->config.log_dir); SAFE_FREE((*context)->config.ek_cert_file); - SAFE_FREE((*context)->config.intel_cert_service); + SAFE_FREE((*context)->config.web_cert_service); SAFE_FREE((*context)->config.firmware_log_file); SAFE_FREE((*context)->config.ima_log_file); diff --git a/src/tss2-fapi/api/Fapi_GetAppData.c b/src/tss2-fapi/api/Fapi_GetAppData.c index 5d5fe8d..4eccf30 100644 --- a/src/tss2-fapi/api/Fapi_GetAppData.c +++ b/src/tss2-fapi/api/Fapi_GetAppData.c @@ -215,7 +215,6 @@ Fapi_GetAppData_Finish( if (appDataSize) *appDataSize = objAppData->size; - context->state = _FAPI_STATE_INIT; r = TSS2_RC_SUCCESS; break; @@ -228,6 +227,7 @@ Fapi_GetAppData_Finish( ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_GetCertificate.c b/src/tss2-fapi/api/Fapi_GetCertificate.c index 1444185..2086045 100644 --- a/src/tss2-fapi/api/Fapi_GetCertificate.c +++ b/src/tss2-fapi/api/Fapi_GetCertificate.c @@ -135,6 +135,10 @@ Fapi_GetCertificate_Async( check_not_null(context); check_not_null(path); + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + r = ifapi_non_tpm_mode_init(context); return_if_error(r, "Initialize GetCertificate"); @@ -183,6 +187,9 @@ Fapi_GetCertificate_Finish( check_not_null(context); check_not_null(x509certData); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_Key_SetCertificate *command = &context->cmd.Key_SetCertificate; IFAPI_OBJECT *keyObject = &command->key_object; diff --git a/src/tss2-fapi/api/Fapi_GetDescription.c b/src/tss2-fapi/api/Fapi_GetDescription.c index 035a2bb..dad5592 100644 --- a/src/tss2-fapi/api/Fapi_GetDescription.c +++ b/src/tss2-fapi/api/Fapi_GetDescription.c @@ -123,6 +123,10 @@ Fapi_GetDescription_Async( check_not_null(context); check_not_null(path); + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + /* Load the object metadata from keystore. */ r = ifapi_keystore_load_async(&context->keystore, &context->io, path); return_if_error2(r, "Could not open: %s", path); diff --git a/src/tss2-fapi/api/Fapi_GetEsysBlob.c b/src/tss2-fapi/api/Fapi_GetEsysBlob.c index 6bf80b1..2da663a 100644 --- a/src/tss2-fapi/api/Fapi_GetEsysBlob.c +++ b/src/tss2-fapi/api/Fapi_GetEsysBlob.c @@ -145,6 +145,9 @@ Fapi_GetEsysBlob_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_GetEsysBlob * command = &(context->cmd.GetEsysBlob); IFAPI_OBJECT *object = &command->object; @@ -334,10 +337,6 @@ Fapi_GetEsysBlob_Finish( SAFE_FREE(key_context); goto_if_error(r, "Marshaling context", error_cleanup); - /* Cleanup policy session if an error did occur. */ - ifapi_flush_policy_session(context, context->policy.session, r); - goto_if_error(r, "Cleanup policy session", error_cleanup); - /* Flush current object used for blob computation. */ if (!key_object->misc.key.persistent_handle) { r = Esys_FlushContext_Async(context->esys, key_object->public.handle); @@ -401,5 +400,6 @@ Fapi_GetEsysBlob_Finish( ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_GetInfo.c b/src/tss2-fapi/api/Fapi_GetInfo.c index 329d247..881b2a6 100644 --- a/src/tss2-fapi/api/Fapi_GetInfo.c +++ b/src/tss2-fapi/api/Fapi_GetInfo.c @@ -157,6 +157,9 @@ Fapi_GetInfo_Async( /* Check for NULL parameters */ check_not_null(context); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_GetInfo * command = &context->cmd.GetInfo; diff --git a/src/tss2-fapi/api/Fapi_GetRandom.c b/src/tss2-fapi/api/Fapi_GetRandom.c index bb79064..0f2e185 100644 --- a/src/tss2-fapi/api/Fapi_GetRandom.c +++ b/src/tss2-fapi/api/Fapi_GetRandom.c @@ -148,6 +148,9 @@ Fapi_GetRandom_Async( /* Check for NULL parameters */ check_not_null(context); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_GetRandom * command = &context->get_random; @@ -162,7 +165,7 @@ Fapi_GetRandom_Async( /* Start a session for integrity protection and encryption of random data. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_ENCRYPT | TPMA_SESSION_DECRYPT, 0); return_if_error_reset_state(r, "Create FAPI session"); @@ -263,6 +266,7 @@ Fapi_GetRandom_Finish( ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); ifapi_session_clean(context); SAFE_FREE(context->get_random.data); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_GetTpmBlobs.c b/src/tss2-fapi/api/Fapi_GetTpmBlobs.c index d5df8cc..4f119a0 100644 --- a/src/tss2-fapi/api/Fapi_GetTpmBlobs.c +++ b/src/tss2-fapi/api/Fapi_GetTpmBlobs.c @@ -137,6 +137,10 @@ Fapi_GetTpmBlobs_Async( check_not_null(context); check_not_null(path); + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + /* Load the object from the key store. */ r = ifapi_keystore_load_async(&context->keystore, &context->io, path); return_if_error2(r, "Could not open: %s", path); @@ -270,5 +274,6 @@ Fapi_GetTpmBlobs_Finish( ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); LOG_TRACE("finished"); + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_Import.c b/src/tss2-fapi/api/Fapi_Import.c index 09e95a6..2aa5ed7 100644 --- a/src/tss2-fapi/api/Fapi_Import.c +++ b/src/tss2-fapi/api/Fapi_Import.c @@ -19,6 +19,7 @@ #include "fapi_int.h" #include "fapi_util.h" #include "tss2_esys.h" +#include "tss2_mu.h" #include "ifapi_json_deserialize.h" #include "ifapi_policy_json_deserialize.h" #include "tpm_json_deserialize.h" @@ -148,12 +149,16 @@ Fapi_Import_Async( json_object *jso2; size_t pos = 0; TPMS_POLICY policy = { 0 }; + TPMA_OBJECT *attributes; /* Check for NULL parameters */ check_not_null(context); check_not_null(path); check_not_null(importData); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_ImportKey * command = &context->cmd.ImportKey; IFAPI_OBJECT *object = &command->object; @@ -169,6 +174,9 @@ Fapi_Import_Async( command->jso_string = NULL; strdup_check(command->out_path, path, r, cleanup_error); memset(&command->object, 0, sizeof(IFAPI_OBJECT)); + memset(&command->public_templ, 0, sizeof(IFAPI_KEY_TEMPLATE)); + command->ossl_priv = NULL; + command->profile = NULL; extPubKey->pem_ext_public = NULL; if (strncmp(importData, IFAPI_PEM_PUBLIC_STRING, @@ -202,8 +210,48 @@ Fapi_Import_Async( context->state = IMPORT_KEY_WRITE_OBJECT_PREPARE; - } else if (strcmp(importData, IFAPI_PEM_PRIVATE_KEY) == 0) { - goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Invalid importData.", cleanup_error); + } else if (strncmp(importData, IFAPI_PEM_PRIVATE_KEY, + sizeof(IFAPI_PEM_PRIVATE_KEY) - 1) == 0 || + strncmp(importData, IFAPI_PEM_ECC_PRIVATE_KEY, + sizeof(IFAPI_PEM_ECC_PRIVATE_KEY) - 1) == 0 || + strncmp(importData, IFAPI_PEM_RSA_PRIVATE_KEY, + sizeof(IFAPI_PEM_RSA_PRIVATE_KEY) - 1) == 0) { + + r = ifapi_non_tpm_mode_init(context); + goto_if_error(r, "Initialize Import in none TPM mode", cleanup_error); + + /* If the async state automata of FAPI shall be tested, then we must not set + the timeouts of ESYS to blocking mode. + During testing, the mssim tcti will ensure multiple re-invocations. + Usually however the synchronous invocations of FAPI shall instruct ESYS + to block until a result is available. */ +#ifndef TEST_FAPI_ASYNC + r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK); + goto_if_error_reset_state(r, "Set Timeout to blocking", cleanup_error); +#endif /* TEST_FAPI_ASYNC */ + + r = ifapi_session_init(context); + goto_if_error(r, "Initialize Import", cleanup_error); + + attributes = &context->cmd.ImportKey.public_templ.public.publicArea.objectAttributes; + r = ifapi_profiles_get(&context->profiles, path, &context->cmd.ImportKey.profile); + goto_if_error2(r, "Get profile for path: %s", cleanup_error, path); + + r = ifapi_merge_profile_into_template(context->cmd.ImportKey.profile, + &context->cmd.ImportKey.public_templ); + goto_if_error(r, "Merge profile", cleanup_error); + + *attributes = TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_DECRYPT | TPMA_OBJECT_USERWITHAUTH; + context->cmd.ImportKey.ossl_priv = importData; + + /* Create session for key loading. */ + r = ifapi_get_sessions_async(context, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, + TPMA_SESSION_DECRYPT, 0); + goto_if_error_reset_state(r, "Create sessions", cleanup_error); + + context->state = IMPORT_WAIT_FOR_SESSION; + return TSS2_RC_SUCCESS; } else { r = ifapi_non_tpm_mode_init(context); @@ -304,7 +352,7 @@ Fapi_Import_Async( /* Create session for key loading. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", cleanup_error); @@ -368,6 +416,8 @@ Fapi_Import_Finish( TSS2_RC r; ESYS_TR session; + size_t marshalled_sensitive_size = 0; + size_t marshalled_length = 0; /* Check for NULL parameters */ check_not_null(context); @@ -393,6 +443,7 @@ Fapi_Import_Finish( char *profile_name = context->loadKey.path_list->str; r = ifapi_profiles_get(&context->profiles, profile_name, &context->cmd.ImportKey.profile); + goto_if_error_reset_state(r, "Retrieving profile data", error_cleanup); if (object->misc.key.public.publicArea.type == TPM2_ALG_RSA) @@ -413,6 +464,39 @@ Fapi_Import_Finish( goto_if_error(r, "LoadKey finish", error_cleanup); context->loadKey.auth_object = *auth_object; + + /* Copy private OSSL PEM key to key tree. */ + if (command->ossl_priv) { + command->parent_object = &context->loadKey.auth_object; + command->public_templ.public.publicArea.nameAlg = + command->parent_object->misc.key.public.publicArea.nameAlg; + r = ifapi_openssl_load_private(command->ossl_priv, + NULL, + NULL, + &context->cmd.ImportKey.public_templ.public, + &keyTree->public, + &command->sensitive); + + goto_if_error_reset_state(r, "Fapi load OSSL Key.", error_cleanup); + + r = Tss2_MU_TPMT_SENSITIVE_Marshal(&command->sensitive.sensitiveArea, + &keyTree->duplicate.buffer[sizeof(uint16_t)], + TPM2_MAX_DIGEST_BUFFER, + &marshalled_sensitive_size); + goto_if_error_reset_state(r, "Fapi marshalling sensitive data of OSSL key failed.", + error_cleanup); + + r = Tss2_MU_UINT16_Marshal(marshalled_sensitive_size, + &keyTree->duplicate.buffer[0], sizeof(uint16_t), + &marshalled_length); + goto_if_error_reset_state(r, "Fapi marshalling size of sensitive date failed.", + error_cleanup); + + keyTree->duplicate.size = marshalled_sensitive_size + sizeof(uint16_t); + context->state = IMPORT_KEY_AUTHORIZE_PARENT; + return TSS2_FAPI_RC_TRY_AGAIN; + } + fallthrough; statecase(context->state, IMPORT_WAIT_FOR_AUTHORIZATION); @@ -427,7 +511,8 @@ Fapi_Import_Finish( r = Esys_Load_Async(context->esys, context->loadKey.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &private, &object->misc.key.public); goto_if_error(r, "Load async", error_cleanup); fallthrough; @@ -534,7 +619,8 @@ Fapi_Import_Finish( r = Esys_Import_Async(context->esys, command->parent_object->public.handle, session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(session), + ESYS_TR_NONE, NULL, &keyTree->public, &keyTree->duplicate, &keyTree->encrypted_seed, @@ -548,14 +634,16 @@ Fapi_Import_Finish( r = Esys_Import_Finish(context->esys, &command->private); try_again_or_error_goto(r, "Import", error_cleanup); - /* Concatenate keyname and parent path */ - char* ipath = NULL; - r = ifapi_asprintf(&ipath, "%s%s%s", command->parent_path, - IFAPI_FILE_DELIM, command->out_path); - goto_if_error(r, "Out of memory.", error_cleanup); + if (!command->ossl_priv) { + /* Concatenate keyname and parent path */ + char* ipath = NULL; + r = ifapi_asprintf(&ipath, "%s%s%s", command->parent_path, + IFAPI_FILE_DELIM, command->out_path); + goto_if_error(r, "Out of memory.", error_cleanup); - SAFE_FREE(command->out_path); - command->out_path = ipath; + SAFE_FREE(command->out_path); + command->out_path = ipath; + } context->state = IMPORT_KEY_WAIT_FOR_FLUSH; fallthrough; @@ -564,6 +652,8 @@ Fapi_Import_Finish( if (!command->parent_object->misc.key.persistent_handle) { r = ifapi_flush_object(context, command->parent_object->public.handle); return_try_again(r); + + command->parent_object->public.handle = ESYS_TR_NONE; ifapi_cleanup_ifapi_object(command->parent_object); goto_if_error(r, "Flush key", error_cleanup); } else { @@ -578,7 +668,9 @@ Fapi_Import_Finish( newObject->misc.key.policyInstance = NULL; newObject->misc.key.description = NULL; newObject->misc.key.certificate = NULL; - r = ifapi_get_profile_sig_scheme(&context->profiles.default_profile, + r = ifapi_get_profile_sig_scheme(context->cmd.ImportKey.profile ? + context->cmd.ImportKey.profile : + &context->profiles.default_profile, &keyTree->public.publicArea, &newObject->misc.key.signing_scheme); goto_if_error(r, "Get signing scheme.", error_cleanup); @@ -666,5 +758,6 @@ Fapi_Import_Finish( ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_List.c b/src/tss2-fapi/api/Fapi_List.c index c2dc21b..dbf5d52 100644 --- a/src/tss2-fapi/api/Fapi_List.c +++ b/src/tss2-fapi/api/Fapi_List.c @@ -183,6 +183,8 @@ Fapi_List_Finish( /* Helpful alias pointers */ IFAPI_Entities_List * command = &context->cmd.Entities_List; + check_not_null(command->searchPath); + /* Retrieve the objects along the search path. */ r = ifapi_keystore_list_all(&context->keystore, command->searchPath, &pathArray, &numPaths); diff --git a/src/tss2-fapi/api/Fapi_NvExtend.c b/src/tss2-fapi/api/Fapi_NvExtend.c index e6003b9..ca174c6 100644 --- a/src/tss2-fapi/api/Fapi_NvExtend.c +++ b/src/tss2-fapi/api/Fapi_NvExtend.c @@ -174,6 +174,9 @@ Fapi_NvExtend_Async( check_not_null(nvPath); check_not_null(data); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Check for maximum allowed dataSize. */ if (dataSize > 1024) { LOG_ERROR("dataSize exceeds allowed maximum of 1024. dataSize = %zi", dataSize); @@ -315,7 +318,7 @@ Fapi_NvExtend_Finish( /* Start a session for authorization. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -349,7 +352,7 @@ Fapi_NvExtend_Finish( command->auth_index, nvIndex, auth_session, - ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), ESYS_TR_NONE, auxData); goto_if_error_reset_state(r, " Fapi_NvExtend_Async", error_cleanup); @@ -370,7 +373,7 @@ Fapi_NvExtend_Finish( /* Compute Digest of the current event */ hashAlg = object->misc.nv.public.nvPublic.nameAlg; r = ifapi_crypto_hash_start(&cryptoContext, hashAlg); - return_if_error(r, "crypto hash start"); + goto_if_error(r, "crypto hash start", error_cleanup); HASH_UPDATE_BUFFER(cryptoContext, &auxData->buffer[0], auxData->size, @@ -380,7 +383,7 @@ Fapi_NvExtend_Finish( (uint8_t *) &event->digests.digests[0].digest, &hashSize); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", error_cleanup); event->digests.digests[0].hashAlg = hashAlg; event->digests.count = 1; @@ -407,7 +410,9 @@ Fapi_NvExtend_Finish( /* libjson-c does not deliver an array if array has only one element */ if (jsoType != json_type_array) { json_object *jsonArray = json_object_new_array(); - json_object_array_add(jsonArray, command->jso_event_log); + if (json_object_array_add(jsonArray, command->jso_event_log)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } command->jso_event_log = jsonArray; } } else { @@ -420,7 +425,9 @@ Fapi_NvExtend_Finish( r = ifapi_json_IFAPI_EVENT_serialize(&command->pcr_event, &jso); goto_if_error(r, "Error serialize event", error_cleanup); - json_object_array_add(command->jso_event_log, jso); + if (json_object_array_add(command->jso_event_log, jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } SAFE_FREE(object->misc.nv.event_log); strdup_check(object->misc.nv.event_log, json_object_to_json_string_ext(command->jso_event_log, @@ -448,7 +455,7 @@ Fapi_NvExtend_Finish( /* Finish writing the NV object to the key store */ r = ifapi_keystore_store_finish(&context->io); return_try_again(r); - return_if_error_reset_state(r, "write_finish failed"); + goto_if_error(r, "write_finish failed", error_cleanup); fallthrough; statecase(context->state, NV_EXTEND_CLEANUP) @@ -456,7 +463,6 @@ Fapi_NvExtend_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; r = TSS2_RC_SUCCESS; break; @@ -483,5 +489,6 @@ Fapi_NvExtend_Finish( SAFE_FREE(object->misc.nv.event_log); ifapi_session_clean(context); LOG_TRACE("finished"); + context->state = _FAPI_STATE_INIT; return r; } diff --git a/src/tss2-fapi/api/Fapi_NvIncrement.c b/src/tss2-fapi/api/Fapi_NvIncrement.c index a9616b3..46d304b 100644 --- a/src/tss2-fapi/api/Fapi_NvIncrement.c +++ b/src/tss2-fapi/api/Fapi_NvIncrement.c @@ -273,7 +273,7 @@ Fapi_NvIncrement_Finish( /* Prepare the session for authorization */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, 0, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -297,7 +297,8 @@ Fapi_NvIncrement_Finish( r = Esys_NV_Increment_Async(context->esys, command->auth_index, nvIndex, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE); + ESYS_TR_NONE, + ESYS_TR_NONE); goto_if_error_reset_state(r, " Fapi_NvIncrement_Async", error_cleanup); fallthrough; @@ -335,7 +336,6 @@ Fapi_NvIncrement_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -350,6 +350,7 @@ Fapi_NvIncrement_Finish( SAFE_FREE(command->nvPath); SAFE_FREE(jso); ifapi_session_clean(context); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_NvRead.c b/src/tss2-fapi/api/Fapi_NvRead.c index 1e1abd9..059511b 100644 --- a/src/tss2-fapi/api/Fapi_NvRead.c +++ b/src/tss2-fapi/api/Fapi_NvRead.c @@ -162,6 +162,9 @@ Fapi_NvRead_Async( check_not_null(context); check_not_null(nvPath); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_NV_Cmds * command = &context->nv_cmd; @@ -284,7 +287,7 @@ Fapi_NvRead_Finish( /* Prepare session for authorization and data encryption. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_ENCRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -330,7 +333,6 @@ Fapi_NvRead_Finish( *data = command->rdata; if (size) *size = command->size; - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -345,6 +347,7 @@ Fapi_NvRead_Finish( SAFE_FREE(command->nvPath); //SAFE_FREE(context->nv_cmd.tes); ifapi_session_clean(context); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_NvSetBits.c b/src/tss2-fapi/api/Fapi_NvSetBits.c index c960a2d..7db5943 100644 --- a/src/tss2-fapi/api/Fapi_NvSetBits.c +++ b/src/tss2-fapi/api/Fapi_NvSetBits.c @@ -281,8 +281,8 @@ Fapi_NvSetBits_Finish( /* Prepare session for authorization */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, - 0, 0); + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, + TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; @@ -336,7 +336,7 @@ Fapi_NvSetBits_Finish( /* Finish writing the NV object to the key store */ r = ifapi_keystore_store_finish(&context->io); return_try_again(r); - return_if_error_reset_state(r, "write_finish failed"); + goto_if_error(r, "write_finish failed", error_cleanup); fallthrough; @@ -345,9 +345,7 @@ Fapi_NvSetBits_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; LOG_DEBUG("success"); - break; statecasedefault(context->state); @@ -362,6 +360,7 @@ Fapi_NvSetBits_Finish( ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_NvWrite.c b/src/tss2-fapi/api/Fapi_NvWrite.c index e038002..c8df7cd 100644 --- a/src/tss2-fapi/api/Fapi_NvWrite.c +++ b/src/tss2-fapi/api/Fapi_NvWrite.c @@ -290,7 +290,6 @@ Fapi_NvWrite_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -307,7 +306,7 @@ Fapi_NvWrite_Finish( SAFE_FREE(command->data); SAFE_FREE(jso); ifapi_session_clean(context); - + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_PcrExtend.c b/src/tss2-fapi/api/Fapi_PcrExtend.c index 3580c1b..6081e3e 100644 --- a/src/tss2-fapi/api/Fapi_PcrExtend.c +++ b/src/tss2-fapi/api/Fapi_PcrExtend.c @@ -163,6 +163,9 @@ Fapi_PcrExtend_Async( check_not_null(context); check_not_null(data); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_PCR * command = &context->cmd.pcr; @@ -258,7 +261,7 @@ Fapi_PcrExtend_Finish( /* Construct the filename for the eventlog file */ r = ifapi_asprintf(&command->event_log_file, "%s/%s%i", context->eventlog.log_dir, IFAPI_PCR_LOG_FILE, command->pcrIndex); - return_if_error(r, "Out of memory."); + return_if_error_reset_state(r, "Out of memory."); /* Check wheter the event log has to be read. */ if (ifapi_io_path_exists(command->event_log_file)) { @@ -280,7 +283,7 @@ Fapi_PcrExtend_Finish( /* Prepare session used for integrity protecting the PCR Event operation. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, 0, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -296,7 +299,7 @@ Fapi_PcrExtend_Finish( r = Esys_PCR_Event_Async(context->esys, command->pcrIndex, context->session1, ESYS_TR_NONE, ESYS_TR_NONE, &command->event); - return_if_error(r, "Esys_PCR_Event_Async"); + goto_if_error(r, "Esys_PCR_Event_Async", error_cleanup); command->event_digests = NULL; fallthrough; @@ -333,7 +336,6 @@ Fapi_PcrExtend_Finish( r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -350,6 +352,7 @@ Fapi_PcrExtend_Finish( ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); ifapi_cleanup_event(pcrEvent); ifapi_session_clean(context); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_PcrRead.c b/src/tss2-fapi/api/Fapi_PcrRead.c index 3d826ed..e00690a 100644 --- a/src/tss2-fapi/api/Fapi_PcrRead.c +++ b/src/tss2-fapi/api/Fapi_PcrRead.c @@ -144,6 +144,9 @@ Fapi_PcrRead_Async( /* Check for NULL parameters */ check_not_null(context); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_PCR * command = &context->cmd.pcr; @@ -258,7 +261,7 @@ Fapi_PcrRead_Finish( fallthrough; statecase(context->state, PCR_READ_READ_EVENT_LIST); - r = ifapi_eventlog_get_finish(&context->eventlog, &context->io, pcrLog); + r = ifapi_eventlog_get_finish(&context->eventlog, NULL, &context->io, pcrLog); return_try_again(r); goto_if_error(r, "Error getting event log", cleanup); @@ -266,7 +269,6 @@ Fapi_PcrRead_Finish( *pcrValue = command->pcrValue; if (pcrValueSize) *pcrValueSize = command->pcrValueSize; - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -279,6 +281,7 @@ Fapi_PcrRead_Finish( SAFE_FREE(command->pcrValue); } SAFE_FREE(command->pcrValues); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_Provision.c b/src/tss2-fapi/api/Fapi_Provision.c index 11b9680..3046b90 100644 --- a/src/tss2-fapi/api/Fapi_Provision.c +++ b/src/tss2-fapi/api/Fapi_Provision.c @@ -22,7 +22,7 @@ #include "fapi_crypto.h" #include "fapi_policy.h" #include "ifapi_curl.h" -#include "ifapi_get_intl_cert.h" +#include "ifapi_get_web_cert.h" #include "ifapi_helpers.h" #include "tss2_mu.h" @@ -37,6 +37,9 @@ #define ECC_EK_TEMPLATE_NV_INDEX 0x01c0000c #define ECC_SM2_EK_TEMPLATE_NV_INDEX 0x01c0001b +#define FAPI_TEST_ROOT_CERT_FILE "./ca/root-ca/root-ca.cert.pem" +#define FAPI_TEST_INT_CERT_FILE "./ca/intermed-ca/intermed-ca.cert.pem" + /** Error cleanup of provisioning * * The profile directory will be deleted. @@ -452,7 +455,6 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) context->state = PROVISION_PREPARE_GET_CAP_AUTH_STATE; return TSS2_FAPI_RC_TRY_AGAIN; } - fallthrough; statecase(context->state, PROVISION_INIT); @@ -891,6 +893,16 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) #ifdef SELF_GENERATED_CERTIFICATE #pragma message ( "*** Allow self generated certifcate ***" ) root_ca_file = getenv("FAPI_TEST_ROOT_CERT"); + + if (root_ca_file && strcasecmp(root_ca_file, "self") == 0) { + /* The self signed root cert will be used as intermediate certificate. */ + context->state = PROVISION_PREPARE_READ_INT_CERT; + return TSS2_FAPI_RC_TRY_AGAIN; + } + + if (!root_ca_file && ifapi_io_path_exists(FAPI_TEST_ROOT_CERT_FILE)) { + root_ca_file = FAPI_TEST_ROOT_CERT_FILE; + } #endif if (!root_ca_file) { context->state = PROVISION_EK_CHECK_CERT; @@ -917,6 +929,9 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) #ifdef SELF_GENERATED_CERTIFICATE #pragma message ( "*** Allow self generated certifcate ***" ) int_ca_file = getenv("FAPI_TEST_INT_CERT"); + if (!int_ca_file && ifapi_io_path_exists(FAPI_TEST_INT_CERT_FILE)) { + int_ca_file = FAPI_TEST_INT_CERT_FILE; + } #endif if (!int_ca_file) { context->state = PROVISION_EK_CHECK_CERT; @@ -924,7 +939,8 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) } r = ifapi_io_read_async(&context->io, int_ca_file); return_try_again(r); - goto_if_error2(r, "Reading certificate %s", error_cleanup, int_ca_file); + goto_if_error2(r, "Reading certificate %s", error_cleanup, + getenv("FAPI_TEST_INT_CERT")); fallthrough; @@ -980,7 +996,8 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) statecase(context->state, PROVISION_INIT_SRK); /* Create session which will be used for SRK generation. */ context->srk_handle = context->ek_handle; - r = ifapi_get_sessions_async(context, IFAPI_SESSION1, 0, 0); + r = ifapi_get_sessions_async(context, IFAPI_SESSION_USE_SRK | IFAPI_SESSION1, + TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; @@ -1001,9 +1018,9 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) if (command->auth_state & TPMA_PERMANENT_LOCKOUTAUTHSET) { hierarchy_lockout->misc.hierarchy.with_auth = TPM2_YES; r = ifapi_get_description(hierarchy_lockout, &description); - return_if_error(r, "Get description"); + goto_if_error(r, "Get description", error_cleanup); r = ifapi_set_auth(context, hierarchy_lockout, description); - return_if_error(r, "Set auth value"); + goto_if_error(r, "Set auth value", error_cleanup); } else { hierarchy_lockout->misc.hierarchy.with_auth = TPM2_NO; } @@ -1021,7 +1038,9 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) /* Prepare the setting of the dictionary attack parameters. */ r = Esys_DictionaryAttackParameters_Async(context->esys, ESYS_TR_RH_LOCKOUT, - auth_session, ESYS_TR_NONE, ESYS_TR_NONE, + auth_session, + ESYS_TR_NONE, + ESYS_TR_NONE, defaultProfile->newMaxTries, defaultProfile->newRecoveryTime, defaultProfile->lockoutRecovery); goto_if_error(r, "Error Esys_DictionaryAttackParameters", @@ -1180,7 +1199,8 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) try_again_or_error_goto(r, "Cleanup", error_cleanup); /* Create session which will be used for parameter encryption. */ - r = ifapi_get_sessions_async(context, IFAPI_SESSION1, 0, 0); + r = ifapi_get_sessions_async(context, IFAPI_SESSION_USE_SRK | IFAPI_SESSION1, + TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; @@ -1362,7 +1382,7 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) /* Finish writing the endorsement hierarchy to the key store */ r = ifapi_keystore_store_finish(&context->io); return_try_again(r); - return_if_error_reset_state(r, "write_finish failed"); + goto_if_error_reset_state(r, "write_finish failed", error_cleanup); /* Write all endorsement hierarchies. */ command->hierarchy = hierarchy_he; @@ -1566,13 +1586,15 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) return_try_again(r); goto_if_error_reset_state(r, "GetCapablity_Finish", error_cleanup); - if ((*capabilityData)->data.tpmProperties.tpmProperty[0].value == VENDOR_INTC) { + if ((*capabilityData)->data.tpmProperties.tpmProperty[0].value == VENDOR_INTC || + (*capabilityData)->data.tpmProperties.tpmProperty[0].value == VENDOR_AMD) { /* Get INTEL certificate for EK public hash via web */ uint8_t *cert_buffer = NULL; size_t cert_size; TPM2B_PUBLIC public; - r = ifapi_get_intl_ek_certificate(context, &pkey->public, &cert_buffer, - &cert_size); + r = ifapi_get_web_ek_certificate(context, &pkey->public, + (*capabilityData)->data.tpmProperties.tpmProperty[0].value, + &cert_buffer, &cert_size); goto_if_error_reset_state(r, "Get certificates", error_cleanup); r = ifapi_cert_to_pem(cert_buffer, cert_size, &command->pem_cert, @@ -1580,6 +1602,11 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) SAFE_FREE(cert_buffer); goto_if_error_reset_state(r, "Convert certificate buffer to PEM.", error_cleanup); + + r = ifapi_curl_verify_ek_cert(NULL, NULL, command->pem_cert); + goto_if_error_reset_state(r, "Verify EK certificate.", + error_cleanup); + } else { /* No certificate was stored in the TPM and ek_cert_less was not set.*/ goto_error(r, TSS2_FAPI_RC_NO_CERT, @@ -1634,6 +1661,7 @@ Fapi_Provision_Finish(FAPI_CONTEXT *context) } SAFE_FREE(command->pathlist); } + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_Quote.c b/src/tss2-fapi/api/Fapi_Quote.c index b71267a..98c37cc 100644 --- a/src/tss2-fapi/api/Fapi_Quote.c +++ b/src/tss2-fapi/api/Fapi_Quote.c @@ -333,7 +333,7 @@ Fapi_Quote_Finish( /* Get a session for authorization of the quote operation. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -371,7 +371,9 @@ Fapi_Quote_Finish( /* Perform the Quote operation. */ r = Esys_Quote_Async(context->esys, command->handle, - auth_session, ESYS_TR_NONE, ESYS_TR_NONE, + auth_session, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &command->qualifyingData, &command->key_object->misc.key.signing_scheme, &command->pcr_selection); @@ -392,16 +394,20 @@ Fapi_Quote_Finish( goto_if_error(r, "Error: PCR_Quote", error_cleanup); /* Flush the key used for the quote. */ - r = Esys_FlushContext_Async(context->esys, command->handle); - goto_if_error(r, "Error: FlushContext", error_cleanup); + if (!command->key_object->misc.key.persistent_handle) { + r = Esys_FlushContext_Async(context->esys, command->handle); + goto_if_error(r, "Error: FlushContext", error_cleanup); + } command->handle = ESYS_TR_NONE; fallthrough; statecase(context->state, PCR_QUOTE_WAIT_FOR_FLUSH); - r = Esys_FlushContext_Finish(context->esys); - return_try_again(r); - goto_if_error(r, "Error: Sign", error_cleanup); + if (!command->key_object->misc.key.persistent_handle) { + r = Esys_FlushContext_Finish(context->esys); + return_try_again(r); + goto_if_error(r, "Error: Sign", error_cleanup); + } sig_key_object = command->key_object; /* Convert the TPM-encoded signature into something useful for the caller. */ @@ -415,12 +421,13 @@ Fapi_Quote_Finish( signed by the TPM. */ r = ifapi_compute_quote_info(sig_key_object, command->tpm_quoted, + &command->fapi_quote_info, quoteInfo); goto_if_error(r, "Create compute quote info.", error_cleanup); /* Return the key's certificate if requested. */ if (certificate) { - strdup_check(*certificate, sig_key_object->misc.key.certificate, r, error_cleanup); + strdup_check(command->certificate, sig_key_object->misc.key.certificate, r, error_cleanup); } /* If the pcrLog was not requested, the operation is done. */ @@ -438,7 +445,9 @@ Fapi_Quote_Finish( fallthrough; statecase(context->state, PCR_QUOTE_READ_EVENT_LIST); - r = ifapi_eventlog_get_finish(&context->eventlog, &context->io, + r = ifapi_eventlog_get_finish(&context->eventlog, + &command->fapi_quote_info, + &context->io, &command->pcrLog); return_try_again(r); goto_if_error(r, "Error getting event log", error_cleanup); @@ -451,9 +460,10 @@ Fapi_Quote_Finish( if (pcrLog) *pcrLog = command->pcrLog; + if (certificate) + *certificate = command->certificate; *signature = command->signature; *signatureSize = command->signatureSize; - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -466,6 +476,8 @@ Fapi_Quote_Finish( SAFE_FREE(command->keyPath); SAFE_FREE(command->pcrList); if (r) { + SAFE_FREE(command->certificate); + SAFE_FREE(command->quoteInfo); SAFE_FREE(command->pcrLog); SAFE_FREE(command->signature); } @@ -477,6 +489,7 @@ Fapi_Quote_Finish( if (command->handle != ESYS_TR_NONE) { Esys_FlushContext(context->esys, command->handle); } + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_SetAppData.c b/src/tss2-fapi/api/Fapi_SetAppData.c index 49ef82c..1ba5ae0 100644 --- a/src/tss2-fapi/api/Fapi_SetAppData.c +++ b/src/tss2-fapi/api/Fapi_SetAppData.c @@ -139,6 +139,13 @@ Fapi_SetAppData_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + /* App data is restricted to 10MB. */ if (appDataSize > FAPI_MAX_APP_DATA_SIZE) { LOG_ERROR("Only 10MB are allowd for app data."); @@ -264,10 +271,9 @@ Fapi_SetAppData_Finish( /* Finish writing of object */ r = ifapi_keystore_store_finish(&context->io); return_try_again(r); - return_if_error_reset_state(r, "write_finish failed"); + goto_if_error(r, "write_finish failed", error_cleanup); ifapi_cleanup_ifapi_object(object); - context->state = _FAPI_STATE_INIT; r = TSS2_RC_SUCCESS; break; @@ -281,6 +287,7 @@ Fapi_SetAppData_Finish( ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); SAFE_FREE(command->object_path); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_SetCertificate.c b/src/tss2-fapi/api/Fapi_SetCertificate.c index 94646e8..1f5a0fe 100644 --- a/src/tss2-fapi/api/Fapi_SetCertificate.c +++ b/src/tss2-fapi/api/Fapi_SetCertificate.c @@ -138,6 +138,13 @@ Fapi_SetCertificate_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + /* Helpful alias pointers */ IFAPI_Key_SetCertificate * command = &context->cmd.Key_SetCertificate; @@ -250,9 +257,8 @@ Fapi_SetCertificate_Finish( /* Finish writing the object to the key store */ r = ifapi_keystore_store_finish(&context->io); return_try_again(r); - return_if_error_reset_state(r, "write_finish failed"); + goto_if_error_reset_state(r, "write_finish failed", error_cleanup); - context->state = _FAPI_STATE_INIT; r = TSS2_RC_SUCCESS; break; @@ -269,6 +275,7 @@ Fapi_SetCertificate_Finish( ifapi_cleanup_ifapi_object(&context->loadKey.auth_object); ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_SetDescription.c b/src/tss2-fapi/api/Fapi_SetDescription.c index bbef27e..bee083e 100644 --- a/src/tss2-fapi/api/Fapi_SetDescription.c +++ b/src/tss2-fapi/api/Fapi_SetDescription.c @@ -127,6 +127,13 @@ Fapi_SetDescription_Async( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + /* Check for invalid parameters */ if (description && strlen(description) + 1 > 1024) { return_error(TSS2_FAPI_RC_BAD_VALUE, @@ -225,7 +232,6 @@ Fapi_SetDescription_Finish( return_try_again(r); return_if_error_reset_state(r, "write_finish failed"); - context->state = _FAPI_STATE_INIT; r = TSS2_RC_SUCCESS; break; @@ -239,6 +245,7 @@ Fapi_SetDescription_Finish( ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); SAFE_FREE(command->object_path); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_Sign.c b/src/tss2-fapi/api/Fapi_Sign.c index 724f22f..52b3c9c 100644 --- a/src/tss2-fapi/api/Fapi_Sign.c +++ b/src/tss2-fapi/api/Fapi_Sign.c @@ -187,6 +187,9 @@ Fapi_Sign_Async( check_not_null(keyPath); check_not_null(digest); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Check for invalid parameters */ if (padding) { if (strcasecmp("RSA_SSA", padding) != 0 && @@ -335,6 +338,7 @@ Fapi_Sign_Finish( SAFE_FREE(command->padding); ifapi_session_clean(context); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_Unseal.c b/src/tss2-fapi/api/Fapi_Unseal.c index 00ef353..4e8c0d3 100644 --- a/src/tss2-fapi/api/Fapi_Unseal.c +++ b/src/tss2-fapi/api/Fapi_Unseal.c @@ -76,6 +76,9 @@ Fapi_Unseal( check_not_null(context); check_not_null(path); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Check whether TCTI and ESYS are initialized */ return_if_null(context->esys, "Command can't be executed in none TPM mode.", TSS2_FAPI_RC_NO_TPM); @@ -244,7 +247,8 @@ Fapi_Unseal_Finish( /* Perform the unseal operation with the TPM. */ r = Esys_Unseal_Async(context->esys, command->object->public.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE); + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE); goto_if_error(r, "Error esys Unseal ", error_cleanup); fallthrough; @@ -289,7 +293,6 @@ Fapi_Unseal_Finish( } SAFE_FREE(command->unseal_data); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -305,6 +308,7 @@ Fapi_Unseal_Finish( ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); ifapi_session_clean(context); SAFE_FREE(command->keyPath); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_VerifyQuote.c b/src/tss2-fapi/api/Fapi_VerifyQuote.c index 03a6745..50474c6 100644 --- a/src/tss2-fapi/api/Fapi_VerifyQuote.c +++ b/src/tss2-fapi/api/Fapi_VerifyQuote.c @@ -175,6 +175,13 @@ Fapi_VerifyQuote_Async( check_not_null(quoteInfo); check_not_null(signature); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + + if (context->state != _FAPI_STATE_INIT) { + return_error(TSS2_FAPI_RC_BAD_SEQUENCE, "Invalid State"); + } + /* Check for invalid parameters */ if (qualifyingData == NULL && qualifyingDataSize != 0) { LOG_ERROR("qualifyingData is NULL but qualifyingDataSize is not 0"); @@ -262,7 +269,6 @@ Fapi_VerifyQuote_Finish( TSS2_RC r; IFAPI_OBJECT key_object; TPM2B_ATTEST attest2b; - TPM2B_DIGEST pcr_digest; /* Check for NULL parameters */ check_not_null(context); @@ -283,6 +289,11 @@ Fapi_VerifyQuote_Finish( &command->fapi_quote_info); goto_if_error(r, "Get quote info.", error_cleanup); + if (command->fapi_quote_info.attest.magic != TPM2_GENERATED_VALUE) { + goto_error(r, TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED, + "Attest without TPM2 generated value", error_cleanup); + } + /* Verify the signature over the attest2b structure. */ r = ifapi_verify_signature_quote(&key_object, command->signature, @@ -319,11 +330,10 @@ Fapi_VerifyQuote_Finish( /* Recalculate and verify the PCR digests. */ r = ifapi_calculate_pcr_digest(command->event_list, - &command->fapi_quote_info, &pcr_digest); + &command->fapi_quote_info); goto_if_error(r, "Verify event list.", error_cleanup); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -342,6 +352,7 @@ Fapi_VerifyQuote_Finish( SAFE_FREE(command->signature); SAFE_FREE(command->quoteInfo); SAFE_FREE(command->logData); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/api/Fapi_VerifySignature.c b/src/tss2-fapi/api/Fapi_VerifySignature.c index 157c7ec..dbc54b2 100644 --- a/src/tss2-fapi/api/Fapi_VerifySignature.c +++ b/src/tss2-fapi/api/Fapi_VerifySignature.c @@ -164,6 +164,9 @@ Fapi_VerifySignature_Async( check_not_null(digest); check_not_null(signature); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_Key_VerifySignature * command = &context->cmd.Key_VerifySignature; diff --git a/src/tss2-fapi/api/Fapi_WriteAuthorizeNV.c b/src/tss2-fapi/api/Fapi_WriteAuthorizeNV.c index 0cf1c88..8e346e8 100644 --- a/src/tss2-fapi/api/Fapi_WriteAuthorizeNV.c +++ b/src/tss2-fapi/api/Fapi_WriteAuthorizeNV.c @@ -156,6 +156,9 @@ Fapi_WriteAuthorizeNv_Async( check_not_null(nvPath); check_not_null(policyPath); + /* Cleanup command context. */ + memset(&context->cmd, 0, sizeof(IFAPI_CMD_STATE)); + /* Helpful alias pointers */ IFAPI_api_WriteAuthorizeNv * command = &context->cmd.WriteAuthorizeNV; IFAPI_NV_Cmds * nvCmd = &context->nv_cmd; @@ -333,7 +336,6 @@ Fapi_WriteAuthorizeNv_Finish( /* Cleanup the session used for authorizing access to the NV index. */ r = ifapi_cleanup_session(context); try_again_or_error_goto(r, "Cleanup", error_cleanup); - context->state = _FAPI_STATE_INIT; break; statecasedefault(context->state); @@ -349,6 +351,7 @@ Fapi_WriteAuthorizeNv_Finish( ifapi_cleanup_ifapi_object(context->loadKey.key_object); ifapi_cleanup_ifapi_object(&context->createPrimary.pkey_object); ifapi_cleanup_ifapi_object(object); + context->state = _FAPI_STATE_INIT; LOG_TRACE("finished"); return r; } diff --git a/src/tss2-fapi/efi_event.h b/src/tss2-fapi/efi_event.h index ddbeb4c..7c6b918 100644 --- a/src/tss2-fapi/efi_event.h +++ b/src/tss2-fapi/efi_event.h @@ -125,4 +125,19 @@ typedef struct { BYTE DevicePath[]; } PACKED UEFI_IMAGE_LOAD_EVENT; +/* + * EV_NO_ACTION_STRUCT is the structure of an EV_NO_ACTION event. + * Described in TCG PCClient PFP section 9.4.5. + * The Signature identifies which arm of the union applies. + */ +typedef struct { + BYTE Signature[16]; + union { + BYTE StartupLocality; + } Cases; +} PACKED EV_NO_ACTION_STRUCT; + +static const BYTE STARTUP_LOCALITY_SIGNATURE[16] = {0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x4C, + 0x6F, 0x63, 0x61, 0x6C, 0x69, 0x74, 0x79, 0}; + #endif diff --git a/src/tss2-fapi/fapi_certificates.h b/src/tss2-fapi/fapi_certificates.h index e8544b0..a59e46a 100644 --- a/src/tss2-fapi/fapi_certificates.h +++ b/src/tss2-fapi/fapi_certificates.h @@ -433,6 +433,22 @@ static char * root_cert_list[] = { "iC8Ee4cSHPmIXzEWC8e7VYavRxswHwYDVR0jBBgwFoAUiC8Ee4cSHPmIXzEWC8e7\n" "VYavRxswCgYIKoZIzj0EAwIDSAAwRQIhANrKhBfLXyHCznBRtWRBmTbfYJR9mCl1\n" "2N/xZkcohRZIAiBDufnmhZWCbX4pibbzAOgcxjsc5+qmpAovxW9ipWJEsA==\n" + "-----END CERTIFICATE-----\n", + + /* Nuvoton TPM Root CA 1210 */ + "-----BEGIN CERTIFICATE-----\n" + "MIICHTCCAaOgAwIBAgIBATAKBggqhkjOPQQDAzBVMR0wGwYDVQQDExROdXZvdG9u\n" + "VFBNUm9vdENBMTIxMDEnMCUGA1UEChMeTnV2b3RvbiBUZWNobm9sb2d5IENvcnBv\n" + "cmF0aW9uMQswCQYDVQQGEwJUVzAgFw0yMTA4MDIwMjUyMTVaGA8yMDUxMDcyNzAy\n" + "NTIxNVowVTEdMBsGA1UEAxMUTnV2b3RvblRQTVJvb3RDQTEyMTAxJzAlBgNVBAoT\n" + "Hk51dm90b24gVGVjaG5vbG9neSBDb3Jwb3JhdGlvbjELMAkGA1UEBhMCVFcwdjAQ\n" + "BgcqhkjOPQIBBgUrgQQAIgNiAARvsPpMWmh0EW5n+tBoGvcLWeRUiTCZIwyAFimh\n" + "wFrQ8SgvxX5A7QaUGQuyel/6Lio8GEzA15tDJPKn34fcWXvM2r2wPFQbE/a5N9Pl\n" + "R//ygpvgM1nTocas6xLd4BRIhcajRTBDMA4GA1UdDwEB/wQEAwICBDASBgNVHRMB\n" + "Af8ECDAGAQH/AgEEMB0GA1UdDgQWBBThUbCrBr/3WwdOW2qoNOLaL7qDgzAKBggq\n" + "hkjOPQQDAwNoADBlAjBKFPxjYwwwhFZ+w0wl0XrwRiPVzRkT2/HW3X7C8lC00sj7\n" + "z4fZilzZetOJPuTY0DACMQD3yABKMvC/Lu6/QclxX/2Tqk9Le3J8LyW5vIUFPesY\n" + "azaJJ7CuWqE9XgXOlfZR0vU=\n" "-----END CERTIFICATE-----\n", /* Nuvoton TPM Root CA 2010 */ @@ -511,7 +527,73 @@ static char * root_cert_list[] = { "I/TiKtO+N0pEl3KVSqKDrtdSVy4wHwYDVR0jBBgwFoAUI/TiKtO+N0pEl3KVSqKD\n" "rtdSVy4wCgYIKoZIzj0EAwIDSAAwRQIgXgXs2eVt2U4sCoRf1GLoUTf2ZzYTSsyg\n" "6I5w6hPTLigCIQDLLFlXK1xw1a1D1/idVhdd3a8gkE0FnTJO890WwiQbpg==\n" - "-----END CERTIFICATE-----" + "-----END CERTIFICATE-----", + + /* Nuvoton TPM Root CA 2112 */ + "-----BEGIN CERTIFICATE-----\n" + "MIICBjCCAa2gAwIBAgIJAOmPfeHxqsTXMAoGCCqGSM49BAMCMFUxUzAfBgNVBAMT\n" + "GE51dm90b24gVFBNIFJvb3QgQ0EgMjExMjAlBgNVBAoTHk51dm90b24gVGVjaG5v\n" + "bG9neSBDb3Jwb3JhdGlvbjAJBgNVBAYTAlRXMB4XDTIxMDMyMzA3NTgwNloXDTQx\n" + "MDMxOTA3NTgwNlowVTFTMB8GA1UEAxMYTnV2b3RvbiBUUE0gUm9vdCBDQSAyMTEy\n" + "MCUGA1UEChMeTnV2b3RvbiBUZWNobm9sb2d5IENvcnBvcmF0aW9uMAkGA1UEBhMC\n" + "VFcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASWuAVsyaGySEs+Z2NfR+0ZVq8d\n" + "rwXGuvaplMoiQFLr0Qphw/OaTrIcuBJ3Qdf3n1GH4Qi2/JyV9Vzg9s+OqOgio2Yw\n" + "ZDAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU\n" + "5Khmb49MbZw5MqlIhHeApoEMQhMwHwYDVR0jBBgwFoAU5Khmb49MbZw5MqlIhHeA\n" + "poEMQhMwCgYIKoZIzj0EAwIDRwAwRAIgAeBBSSNr4BvEDi0v5vJVOCV9W9Hy+nGB\n" + "TR4/YoYg3t8CIHC7KC8PS56v9xhPQQjJmN+DxH51RQ2s8ONrb1D8z/2m\n" + "-----END CERTIFICATE-----\n", + + /* AMD root certificate ECC */ + "-----BEGIN CERTIFICATE-----\n" + "MIIDAjCCAqigAwIBAgIQI0UiAdQcWrBkAyvSPxWP7zAKBggqhkjOPQQDAjB2MRQw\n" + "EgYDVQQLEwtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxEjAQBgNVBAcTCVN1bm55\n" + "dmFsZTELMAkGA1UECBMCQ0ExHzAdBgNVBAoTFkFkdmFuY2VkIE1pY3JvIERldmlj\n" + "ZXMxDzANBgNVBAMTBkFNRFRQTTAeFw0xNjAxMDEwNTAwMDBaFw00MTAxMDEwNTAw\n" + "MDBaMHYxFDASBgNVBAsTC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzESMBAGA1UE\n" + "BxMJU3Vubnl2YWxlMQswCQYDVQQIEwJDQTEfMB0GA1UEChMWQWR2YW5jZWQgTWlj\n" + "cm8gRGV2aWNlczEPMA0GA1UEAxMGQU1EVFBNMFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" + "AQcDQgAEKLNGw0F3uq7kcoZazSAm46NUyiIJC5DgNAPo1CfrPsn3UtRni1DxC1xa\n" + "sMtvIo3jAVHZlVsmAT1g0r5XiNb5mqOCARYwggESMA4GA1UdDwEB/wQEAwIBBjAj\n" + "BgkrBgEEAYI3FSsEFgQU8hrQ+OijBunLzTh+hnJjF9vBvrkwHQYDVR0OBBYEFPIa\n" + "0Pjoowbpy804foZyYxfbwb65MA8GA1UdEwEB/wQFMAMBAf8wOAYIKwYBBQUHAQEE\n" + "LDAqMCgGCCsGAQUFBzABhhxodHRwOi8vZnRwbS5hbWQuY29tL3BraS9vY3NwMCwG\n" + "A1UdHwQlMCMwIaAfoB2GG2h0dHA6Ly9mdHBtLmFtZC5jb20vcGtpL2NybDBDBgNV\n" + "HSAEPDA6MDgGCisGAQQBnHhlFQowKjAoBggrBgEFBQcCARYcaHR0cHM6Ly9mdHBt\n" + "LmFtZC5jb20vcGtpL2NwczAKBggqhkjOPQQDAgNIADBFAiEAgaCRgPGIA9/8xEVy\n" + "tJ1YK0ERBDGHxPT0igzycASqDhACIDWbPtOXQG3Z4W09OjRtWwLwdCEkelKfPazb\n" + "yhIHIT4m\n" + "-----END CERTIFICATE-----\n", + + /* AMD root certificate RSA */ + "-----BEGIN CERTIFICATE-----\n" + "MIIEiDCCA3CgAwIBAgIQJk05ojzrXVtJ1hAETuvRITANBgkqhkiG9w0BAQsFADB2\n" + "MRQwEgYDVQQLEwtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxEjAQBgNVBAcTCVN1\n" + "bm55dmFsZTELMAkGA1UECBMCQ0ExHzAdBgNVBAoTFkFkdmFuY2VkIE1pY3JvIERl\n" + "dmljZXMxDzANBgNVBAMTBkFNRFRQTTAeFw0xNDEwMjMxNDM0MzJaFw0zOTEwMjMx\n" + "NDM0MzJaMHYxFDASBgNVBAsTC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzESMBAG\n" + "A1UEBxMJU3Vubnl2YWxlMQswCQYDVQQIEwJDQTEfMB0GA1UEChMWQWR2YW5jZWQg\n" + "TWljcm8gRGV2aWNlczEPMA0GA1UEAxMGQU1EVFBNMIIBIjANBgkqhkiG9w0BAQEF\n" + "AAOCAQ8AMIIBCgKCAQEAssnOAYu5nRflQk0bVtsTFcLSAMx9odZ4Ey3n6/MA6FD7\n" + "DECIE70RGZgaRIID0eb+dyX3znMrp1TS+lD+GJSw7yDJrKeU4it8cMLqFrqGm4SE\n" + "x/X5GBa11sTmL4i60pJ5nDo2T69OiJ+iqYzgBfYJLqHQaeSRN6bBYyn3w1H4JNzP\n" + "DNvqKHvkPfYewHjUAFJAI1dShYO8REnNCB8eeolj375nymfAAZzgA8v7zmFX/1tV\n" + "LCy7Mm6n7zndT452TB1mek9LC5LkwlnyABwaN2Q8LV4NWpIAzTgr55xbU5VvgcIp\n" + "w+/qcbYHmqL6ZzCSeE1gRKQXlsybK+W4phCtQfMgHQIDAQABo4IBEDCCAQwwDgYD\n" + "VR0PAQH/BAQDAgEGMCMGCSsGAQQBgjcVKwQWBBRXjFRfeWlRQhIhpKV4rNtfaC+J\n" + "yDAdBgNVHQ4EFgQUV4xUX3lpUUISIaSleKzbX2gvicgwDwYDVR0TAQH/BAUwAwEB\n" + "/zA4BggrBgEFBQcBAQQsMCowKAYIKwYBBQUHMAGGHGh0dHA6Ly9mdHBtLmFtZC5j\n" + "b20vcGtpL29jc3AwLAYDVR0fBCUwIzAhoB+gHYYbaHR0cDovL2Z0cG0uYW1kLmNv\n" + "bS9wa2kvY3JsMD0GA1UdIAQ2MDQwMgYEVR0gADAqMCgGCCsGAQUFBwIBFhxodHRw\n" + "czovL2Z0cG0uYW1kLmNvbS9wa2kvY3BzMA0GCSqGSIb3DQEBCwUAA4IBAQCWB9yA\n" + "oYYIt5HRY/OqJ5LUacP6rNmsMfPUDTcahXB3iQmY8HpUoGB23lhxbq+kz3vIiGAc\n" + "UdKHlpB/epXyhABGTcJrNPMfx9akLqhI7WnMCPBbHDDDzKjjMB3Vm65PFbyuqbLu\n" + "jN/sN6kNtc4hL5r5Pr6Mze5H9WXBo2F2Oy+7+9jWMkxNrmUhoUUrF/6YsajTGPeq\n" + "7r+i6q84W2nJdd+BoQQv4sk5GeuN2j2u4k1a8DkRPsVPc2I9QTtbzekchTK1GCXW\n" + "ki3DKGkZUEuaoaa60Kgw55Q5rt1eK7HKEG5npmR8aEod7BDLWy4CMTNAWR5iabCW\n" + "/KX28JbJL6Phau9j\n" + "-----END CERTIFICATE-----\n" + }; #endif /* FAPI_CERTIFICATES_H */ diff --git a/src/tss2-fapi/fapi_crypto.c b/src/tss2-fapi/fapi_crypto.c index 3f11b3d..43b1bbb 100644 --- a/src/tss2-fapi/fapi_crypto.c +++ b/src/tss2-fapi/fapi_crypto.c @@ -66,10 +66,16 @@ ifapi_crypto_context_free(IFAPI_CRYPTO_CONTEXT *ctx) if (!ctx) return; - EVP_MD_CTX_destroy(ctx->osslContext); + if (ctx->osslContext) { + EVP_MD_CTX_destroy(ctx->osslContext); + } #if OPENSSL_VERSION_NUMBER >= 0x30000000L - EVP_MD_free(ctx->osslHashAlgorithm); - OSSL_LIB_CTX_free(ctx->libctx); + if (ctx->osslHashAlgorithm) { + EVP_MD_free(ctx->osslHashAlgorithm); + } + if (ctx->libctx) { + OSSL_LIB_CTX_free(ctx->libctx); + } #endif SAFE_FREE(ctx); } @@ -544,7 +550,7 @@ ossl_ecc_pub_from_tpm(const TPM2B_PUBLIC *tpmPublicKey, EVP_PKEY **evpPublicKey) case TPM2_ECC_NIST_P521: curveId = NID_secp521r1; break; -#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#ifdef NID_sm2 case TPM2_ECC_SM2_P256: curveId = NID_sm2; break; @@ -786,7 +792,7 @@ ifapi_hmac_sig_to_tpm( tpmSignature->sigAlg = TPM2_ALG_HMAC; tpmSignature->signature.hmac.hashAlg = hashAlgorithm; - memcpy(&tpmSignature->signature.hmac.digest.sha1, signature, signatureSize); + memcpy(&tpmSignature->signature.hmac.digest.sha512, signature, signatureSize); return TSS2_RC_SUCCESS; } @@ -1195,7 +1201,7 @@ get_ecc_tpm2b_public_from_evp( case NID_secp521r1: tpmCurveId = TPM2_ECC_NIST_P521; break; -#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#ifdef NID_sm2 case NID_sm2: tpmCurveId = TPM2_ECC_SM2_P256; break; @@ -1659,11 +1665,11 @@ ifapi_crypto_hash_start(IFAPI_CRYPTO_CONTEXT_BLOB **context, } *context = (IFAPI_CRYPTO_CONTEXT_BLOB *) mycontext; - return TSS2_RC_SUCCESS; cleanup: ifapi_crypto_context_free(mycontext); + *context = NULL; return r; } @@ -1715,6 +1721,8 @@ TSS2_RC ifapi_crypto_hash_finish(IFAPI_CRYPTO_CONTEXT_BLOB **context, uint8_t *digest, size_t *digestSize) { + TSS2_RC r = TSS2_RC_SUCCESS; + /* Check for NULL parameters */ return_if_null(context, "context is NULL", TSS2_FAPI_RC_BAD_REFERENCE); return_if_null(digest, "digest is NULL", TSS2_FAPI_RC_BAD_REFERENCE); @@ -1727,12 +1735,12 @@ ifapi_crypto_hash_finish(IFAPI_CRYPTO_CONTEXT_BLOB **context, IFAPI_CRYPTO_CONTEXT *mycontext = *context; if (1 != EVP_DigestFinal_ex(mycontext->osslContext, digest, &computedDigestSize)) { - return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "OSSL error."); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "OSSL error.", cleanup); } if (computedDigestSize != mycontext->hashSize) { - return_error(TSS2_FAPI_RC_GENERAL_FAILURE, - "Invalid size computed by EVP_DigestFinal_ex"); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Invalid size computed by EVP_DigestFinal_ex", cleanup); } LOGBLOB_DEBUG(digest, mycontext->hashSize, "finish hash"); @@ -1741,11 +1749,13 @@ ifapi_crypto_hash_finish(IFAPI_CRYPTO_CONTEXT_BLOB **context, *digestSize = mycontext->hashSize; } + cleanup: + /* Finalize the hash context */ ifapi_crypto_context_free(mycontext); *context = NULL; - return TSS2_RC_SUCCESS; + return r; } /** @@ -1762,9 +1772,8 @@ ifapi_crypto_hash_abort(IFAPI_CRYPTO_CONTEXT_BLOB **context) LOG_DEBUG("Null-Pointer passed"); return; } - IFAPI_CRYPTO_CONTEXT *mycontext = (IFAPI_CRYPTO_CONTEXT *) * context; - ifapi_crypto_context_free(mycontext); + ifapi_crypto_context_free(*context); *context = NULL; } @@ -2081,7 +2090,7 @@ ifapi_base64encode(uint8_t *buffer, size_t buffer_size, char** b64_data) { cleanup); } - BIO_flush(bio); + (void) BIO_flush(bio); BIO_get_mem_ptr(bio, &b64_mem); goto_if_null2(b64_mem, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, cleanup); @@ -2100,3 +2109,290 @@ ifapi_base64encode(uint8_t *buffer, size_t buffer_size, char** b64_data) { return r; } + +/** Openssl rsa encryption with OAEP padding. + * + * @param[in] pem_key The public RSA key. + * @param[in] rsa_decrypt_scheme The padding scheme. + * @param[in] plainText The data to be encrypted. + * @param[in] plainTextSize The size of the data to be encrypted. + * @param[out] cipherText The encrypted data. + * @param[out] cipherTextSize The size of the encrypted data. + * + * @retval TSS2_RC_SUCCESS on success + * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an error occurs in the crypto library + * @retval TSS2_FAPI_RC_MEMORY if memory could not be allocated + */ +TSS2_RC +ifapi_rsa_encrypt(const char *pem_key, + const TPMT_RSA_DECRYPT *rsa_decrypt_scheme, + const uint8_t *plainText, + size_t plainTextSize, + uint8_t **cipherText, + size_t *cipherTextSize) { + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *publicKey = NULL; + BIO *bufio = NULL; + TSS2_RC r; + const EVP_MD *evp_md; + + /* Convert the pem key to an OpenSSL object */ + bufio = BIO_new_mem_buf((void *)pem_key, strlen(pem_key)); + goto_if_null(bufio, "Out of memory.", TSS2_FAPI_RC_MEMORY, cleanup); + + publicKey = PEM_read_bio_PUBKEY(bufio, NULL, NULL, NULL); + goto_if_null(publicKey, "PEM format could not be decoded.", + TSS2_FAPI_RC_MEMORY, cleanup); + + if (EVP_PKEY_type(EVP_PKEY_id(publicKey)) == EVP_PKEY_RSA) { + if (rsa_decrypt_scheme->scheme == TPM2_ALG_OAEP) { + switch (rsa_decrypt_scheme->details.oaep.hashAlg) { + case TPM2_ALG_SHA1: + evp_md = EVP_sha1(); + break; + case TPM2_ALG_SHA256: + evp_md = EVP_sha256(); + break; + case TPM2_ALG_SHA384: + evp_md = EVP_sha384(); + break; + case TPM2_ALG_SHA512: + evp_md = EVP_sha512(); + break; +#if HAVE_EVP_SM3 && !defined(OPENSSL_NO_SM3) + case TPM2_ALG_SM3_256: + evp_md = EVP_sm3(); + break; +#endif + default: + goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Invalid hash alg.", + cleanup); + } + } else { + LOG_WARNING("OEAP (sha256) will be used for encryption padding."); + evp_md = EVP_sha256(); + } + + ctx = EVP_PKEY_CTX_new(publicKey, NULL); + goto_if_null(ctx, "EVP_PKEY_CTX_new.", TSS2_FAPI_RC_GENERAL_FAILURE, + cleanup); + if (EVP_PKEY_encrypt_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(ctx, evp_md) <= 0 || + EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, evp_md) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EVP init encrypt.", + cleanup); + } + + /* Determine buffer length */ + if (EVP_PKEY_encrypt(ctx, NULL, cipherTextSize, plainText, plainTextSize) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EVP encrypt determine size.", + cleanup); + } + + *cipherText = OPENSSL_malloc(*cipherTextSize); + if (EVP_PKEY_encrypt(ctx, *cipherText, cipherTextSize, plainText, plainTextSize) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EVP encrypt.", + cleanup); + } + r = TSS2_RC_SUCCESS; + } else { + goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "No RSA public key.", + cleanup); + } + + cleanup: + if (bufio) + BIO_free(bufio); + if (publicKey) + EVP_PKEY_free(publicKey); + if (ctx) + OSSL_FREE(ctx, EVP_PKEY_CTX); + return r; +} + +static bool +load_private_RSA_from_key(EVP_PKEY *key, + TPM2B_SENSITIVE *priv) { + + bool result = false; +#if OPENSSL_VERSION_NUMBER < 0x30000000L + const BIGNUM *p = NULL; /* the private key exponent */ + + RSA *k = EVP_PKEY_get0_RSA(key); + if (!k) { + LOG_ERROR("Could not retrieve RSA key"); + goto out; + } + RSA_get0_factors(k, &p, NULL); +#else + BIGNUM *p = NULL; /* the private key exponent */ + + int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_FACTOR1, &p); + if (!rc) { + LOG_ERROR("Could not read private key"); + goto out; + } +#endif + + TPMT_SENSITIVE *sa = &priv->sensitiveArea; + + sa->sensitiveType = TPM2_ALG_RSA; + + TPM2B_PRIVATE_KEY_RSA *pkr = &sa->sensitive.rsa; + + unsigned priv_bytes = BN_num_bytes(p); + if (priv_bytes > sizeof(pkr->buffer)) { + LOG_ERROR("Expected prime \"d\" to be less than or equal to %zu," + " got: %u", sizeof(pkr->buffer), priv_bytes); + goto out; + } + + pkr->size = priv_bytes; + + int success = BN_bn2bin(p, pkr->buffer); + if (!success) { + ERR_print_errors_fp(stderr); + LOG_ERROR("Could not copy private exponent \"d\""); + goto out; + } + result = true; +out: +#if OPENSSL_VERSION_NUMBER < 0x30000000L + /* k,p point to internal structrues and must not be freed after use */ +#else + BN_free(p); +#endif + return result; +} + +static TSS2_RC +load_RSA_key(EVP_PKEY *key, + TPM2B_PUBLIC *pub, + TPM2B_SENSITIVE *priv) { + TSS2_RC rc = TSS2_RC_SUCCESS; + + bool loaded_priv = load_private_RSA_from_key(key, priv); + if (!loaded_priv) { + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + + rc = get_rsa_tpm2b_public_from_evp(key, pub); + EVP_PKEY_free(key); + return rc; +} + +static bool +load_private_ECC_from_key(EVP_PKEY *key, + TPM2B_SENSITIVE *priv) { + bool result = false; + /* + * private data + */ + priv->sensitiveArea.sensitiveType = TPM2_ALG_ECC; + + TPM2B_ECC_PARAMETER *p = &priv->sensitiveArea.sensitive.ecc; + +#if OPENSSL_VERSION_NUMBER < 0x30000000L + EC_KEY *k = EVP_PKEY_get0_EC_KEY(key); + if (!k) { + LOG_ERROR("Could not retrieve ECC key"); + goto out; + } + + const EC_GROUP *group = EC_KEY_get0_group(k); + const BIGNUM *b = EC_KEY_get0_private_key(k); + unsigned priv_bytes = (EC_GROUP_get_degree(group) + 7) / 8; +#else + BIGNUM *b = NULL; /* the private key exponent */ + + int rc = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_PRIV_KEY, &b); + if (!rc) { + LOG_ERROR("Could not read ECC private key"); + goto out; + } + unsigned priv_bytes = (EVP_PKEY_bits(key) + 7) / 8; +#endif + + if (priv_bytes > sizeof(p->buffer)) { + LOG_ERROR("Expected ECC private portion to be less than or equal to %zu," + " got: %u", sizeof(p->buffer), priv_bytes); + goto out; + } + + p->size = BN_bn2binpad(b, p->buffer, priv_bytes); + if (p->size != priv_bytes) { + goto out; + } + result = true; +out: +#if OPENSSL_VERSION_NUMBER < 0x30000000L + /* k,b point to internal structrues and must not be freed after use */ +#else + BN_free(b); +#endif + return result; +} + +static TSS2_RC +load_ECC_key(EVP_PKEY *key, + TPM2B_PUBLIC *pub, + TPM2B_SENSITIVE *priv) { + TSS2_RC rc = TSS2_RC_SUCCESS; + + if (!load_private_ECC_from_key(key, priv)) { + rc = TSS2_FAPI_RC_GENERAL_FAILURE; + goto out; + } + rc = get_ecc_tpm2b_public_from_evp(key, pub); + if (rc) { + goto out; + } +out: + EVP_PKEY_free(key); + return rc; +} + +TSS2_RC +ifapi_openssl_load_private(const char *pem_key, + const char *passin, + const char *object_auth, + TPM2B_PUBLIC *template, + TPM2B_PUBLIC *pub, + TPM2B_SENSITIVE *priv) { + *pub = *template; + BIO *bio = NULL; + EVP_PKEY *key = NULL; + TSS2_RC rc = TSS2_RC_SUCCESS; + (void)object_auth; + + /* Create a key from PEM string. */ + bio = BIO_new_mem_buf(pem_key, -1); + + if (!bio) { + LOG_ERROR("Error creating BIO."); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + + key = PEM_read_bio_PrivateKey(bio,NULL,NULL, (void *) passin); + + if (!key) { + LOG_ERROR("Creation of key from PEM string failed."); + BIO_free_all(bio); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + + switch (template->publicArea.type) { + case TPM2_ALG_RSA: + rc = load_RSA_key(key, pub, priv); + break; + case TPM2_ALG_ECC: + rc = load_ECC_key(key, pub, priv); + break; + default: + LOG_ERROR("Cannot handle algorithm, got: 0x%x", template->publicArea.type); + rc = TSS2_FAPI_RC_GENERAL_FAILURE; + } + BIO_free_all(bio); + return rc; +} diff --git a/src/tss2-fapi/fapi_crypto.h b/src/tss2-fapi/fapi_crypto.h index 3335ec3..4360b9c 100644 --- a/src/tss2-fapi/fapi_crypto.h +++ b/src/tss2-fapi/fapi_crypto.h @@ -123,4 +123,22 @@ ifapi_base64encode( size_t buffer_size, char** b64_data); +TSS2_RC +ifapi_rsa_encrypt( + const char *pem_key, + const TPMT_RSA_DECRYPT *rsa_decrypt_scheme, + const uint8_t *plainText, + size_t plainTextSize, + uint8_t **cipherText, + size_t *cipherTextSize); + +TSS2_RC +ifapi_openssl_load_private( + const char *pem_key, + const char *passin, + const char *object_auth, + TPM2B_PUBLIC *template, + TPM2B_PUBLIC *pub, + TPM2B_SENSITIVE *priv); + #endif /* FAPI_CRYPTO_H */ diff --git a/src/tss2-fapi/fapi_int.h b/src/tss2-fapi/fapi_int.h index 98d398d..8435268 100644 --- a/src/tss2-fapi/fapi_int.h +++ b/src/tss2-fapi/fapi_int.h @@ -55,9 +55,10 @@ typedef UINT32 TSS2_KEY_TYPE; #define MAX_PLATFORM_CERT_HANDLE 0x01C0FFFF typedef UINT8 IFAPI_SESSION_TYPE; -#define IFAPI_SESSION_GENEK 0x01 -#define IFAPI_SESSION1 0x02 -#define IFAPI_SESSION2 0x04 +#define IFAPI_SESSION_GEN_SRK 0x01 +#define IFAPI_SESSION1 0x02 +#define IFAPI_SESSION2 0x04 +#define IFAPI_SESSION_USE_SRK 0x08 #define IFAPI_POLICY_PATH "policy" #define IFAPI_NV_PATH "nv" @@ -68,7 +69,9 @@ typedef UINT8 IFAPI_SESSION_TYPE; #define IFAPI_PUB_KEY_DIR "ext" #define IFAPI_POLICY_DIR "policy" #define IFAPI_PEM_PUBLIC_STRING "-----BEGIN PUBLIC KEY-----" -#define IFAPI_PEM_PRIVATE_KEY "-----PRIVATE KEY-----" +#define IFAPI_PEM_PRIVATE_KEY "-----BEGIN PRIVATE KEY-----" +#define IFAPI_PEM_RSA_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----" +#define IFAPI_PEM_ECC_PRIVATE_KEY "-----BEGIN EC PRIVATE KEY-----" #define IFAPI_JSON_TAG_POLICY "policy" #define IFAPI_JSON_TAG_OBJECT_TYPE "objectType" #define IFAPI_JSON_TAG_DUPLICATE "public_parent" @@ -126,6 +129,11 @@ typedef struct { goto label; \ } +#define ENC_SESSION_IF_POLICY(auth_session) \ + (auth_session == ESYS_TR_PASSWORD || auth_session == ESYS_TR_NONE || \ + auth_session == context->session2 || \ + !context->session2) ? ESYS_TR_NONE : context->session2 + /** The states for the FAPI's object authorization state*/ enum IFAPI_GET_CERT_STATE { GET_CERT_INIT = 0, @@ -185,13 +193,6 @@ typedef struct { TPMS_NV_PUBLIC public; /**< Template for public data */ } IFAPI_NV_TEMPLATE; -/** Type for representing a external public key - */ -typedef struct { - TPMT_SIG_SCHEME sig_scheme; /**< Signature scheme used for quote. */ - TPMS_ATTEST attest; /**< Attestation data from Quote */ -} FAPI_QUOTE_INFO; - /** The states for the FAPI's NV read state */ enum _FAPI_STATE_NV_READ { @@ -239,6 +240,7 @@ typedef struct { TPM2B_AUTH auth; /**< The Password */ IFAPI_NV nv_obj; /**< The NV Object */ ESYS_TR auth_index; /**< The ESAPI handle of the authorization object */ + ESYS_TR auth_session; /**< The autorization session for a nv object */ uint64_t bitmap; /**< The bitmask for the SetBits command */ IFAPI_NV_TEMPLATE public_templ; /**< The template for nv creation, adjusted appropriate by the passed flags */ @@ -291,7 +293,8 @@ typedef struct { uint32_t const *hashAlgs; uint32_t *hashAlgs2; size_t numHashAlgs; - char const *quoteInfo; + char const *quoteInfo; + char *certificate; TPM2B_ATTEST *tpm_quoted; TPMT_SIGNATURE *tpm_signature; uint8_t *signature; @@ -711,6 +714,9 @@ typedef struct { TPM2B_PRIVATE *private; char *jso_string; const IFAPI_PROFILE *profile; + IFAPI_KEY_TEMPLATE public_templ; /**< The template for the keys public data */ + const char *ossl_priv; /**< Private OSSL PEM key to be import. */ + TPM2B_SENSITIVE sensitive; /**< The sensitive part of an OSSL key. */ } IFAPI_ImportKey; @@ -1025,6 +1031,7 @@ enum _FAPI_STATE { DATA_ENCRYPT_WAIT_FOR_PROFILE, DATA_ENCRYPT_WAIT_FOR_SESSION, DATA_ENCRYPT_WAIT_FOR_KEY, + DATA_ENCRYPT_WAIT_FOR_EXT_KEY, DATA_ENCRYPT_WAIT_FOR_FLUSH, DATA_ENCRYPT_WAIT_FOR_RSA_ENCRYPTION, DATA_ENCRYPT_CLEAN, @@ -1206,5 +1213,6 @@ struct FAPI_CONTEXT { #define VENDOR_IFX 0x49465800 #define VENDOR_INTC 0x494E5443 #define VEDNOR_IBM 0x49424D20 +#define VENDOR_AMD 0x414D4400 #endif /* FAPI_INT_H */ diff --git a/src/tss2-fapi/fapi_util.c b/src/tss2-fapi/fapi_util.c index aa918a3..d2dc9ff 100644 --- a/src/tss2-fapi/fapi_util.c +++ b/src/tss2-fapi/fapi_util.c @@ -63,9 +63,9 @@ ifapi_flush_object(FAPI_CONTEXT *context, ESYS_TR handle) if (base_rc(r) == TSS2_BASE_RC_TRY_AGAIN) return TSS2_FAPI_RC_TRY_AGAIN; + context->flush_object_state = FLUSH_INIT; return_if_error(r, "FlushContext"); - context->flush_object_state = FLUSH_INIT; return TSS2_RC_SUCCESS; statecasedefault(context->flush_object_state); @@ -320,14 +320,13 @@ init_explicit_key_path( * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed. */ static TSS2_RC -pop_object_from_list(FAPI_CONTEXT *context, NODE_OBJECT_T **object_list) +pop_object_from_list(NODE_OBJECT_T **object_list) { return_if_null(*object_list, "Pop from list.", TSS2_FAPI_RC_BAD_REFERENCE); NODE_OBJECT_T *head = *object_list; NODE_OBJECT_T *next = head->next; *object_list = next; - ifapi_free_object(context, (void *)&head->object); free(head); return TSS2_RC_SUCCESS; } @@ -441,6 +440,10 @@ ifapi_set_auth( return_if_error(r, "policyAuthCallback"); if (auth != NULL) { authValue.size = strlen(auth); + if (authValue.size > sizeof(TPMU_HA)) { + return_error2(TSS2_FAPI_RC_BAD_VALUE, "Size of auth value %u > %lu", + authValue.size, sizeof(TPMU_HA)); + } memcpy(&authValue.buffer[0], auth, authValue.size); } @@ -740,7 +743,8 @@ ifapi_init_primary_finish(FAPI_CONTEXT *context, TSS2_KEY_TYPE ktype, IFAPI_OBJE r = Esys_CreatePrimary_Async(context->esys, hierarchy->public.handle, (auth_session == ESYS_TR_NONE) ? ESYS_TR_PASSWORD : auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &context->cmd.Provision.inSensitive, &context->cmd.Provision.public_templ.public, &context->cmd.Provision.outsideInfo, @@ -943,9 +947,12 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) /* Check whether a persistent key was loaded. In this case the handle has already been set. */ if (pkey_object->public.handle != ESYS_TR_NONE) { - if (pkey->creationTicket.hierarchy == TPM2_RH_EK) { + if (pkey->creationTicket.hierarchy == TPM2_RH_ENDORSEMENT && + strcmp("/EK", + &pkey_object->rel_path[strlen(pkey_object->rel_path)-3]) == 0) { context->ek_persistent = true; - } else { + } else if (strcmp("/SRK", + &pkey_object->rel_path[strlen(pkey_object->rel_path)-4]) == 0) { context->srk_persistent = true; } /* It has to be checked whether the persistent handle exists. */ @@ -953,7 +960,7 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) return TSS2_FAPI_RC_TRY_AGAIN; } else { - if (pkey->creationTicket.hierarchy == TPM2_RH_EK) { + if (pkey->creationTicket.hierarchy == TPM2_RH_ENDORSEMENT) { context->ek_persistent = false; } else { context->srk_persistent = false; @@ -963,8 +970,7 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) statecase(context->primary_state, PRIMARY_READ_HIERARCHY); /* The hierarchy object used for auth_session will be loaded from key store. */ - if (pkey->creationTicket.hierarchy == TPM2_RH_EK || - (pkey->ek_profile && pkey->creationTicket.hierarchy == TPM2_RH_ENDORSEMENT)) { + if (pkey->creationTicket.hierarchy == TPM2_RH_ENDORSEMENT) { r = ifapi_keystore_load_async(&context->keystore, &context->io, "/HE"); return_if_error2(r, "Could not open hierarchy /HE"); } else if (pkey->creationTicket.hierarchy == TPM2_RH_NULL) { @@ -984,10 +990,7 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) r = ifapi_initialize_object(context->esys, hierarchy); goto_if_error_reset_state(r, "Initialize hierarchy object", error_cleanup); - if (pkey->creationTicket.hierarchy == TPM2_RH_EK) { - hierarchy->public.handle = ESYS_TR_RH_ENDORSEMENT; - } else if (pkey->creationTicket.hierarchy == TPM2_RH_ENDORSEMENT && - pkey->ek_profile) { + if (pkey->creationTicket.hierarchy == TPM2_RH_ENDORSEMENT) { hierarchy->public.handle = ESYS_TR_RH_ENDORSEMENT; } else if (pkey->creationTicket.hierarchy == TPM2_RH_NULL) { hierarchy->public.handle = ESYS_TR_RH_NULL; @@ -1046,7 +1049,9 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) } r = Esys_CreatePrimary_Async(context->esys, hierarchy->public.handle, - auth_session, ESYS_TR_NONE, ESYS_TR_NONE, + auth_session, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &context->createPrimary.inSensitive, &public, &context->createPrimary.outsideInfo, @@ -1069,6 +1074,14 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) } *handle = pkey_object->public.handle; context->primary_state = PRIMARY_INIT; + + /* Check whether the public key corresponds to key in key store. */ + if (!ifapi_cmp_public_key(outPublic, &pkey_object->misc.key.public)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Public key for %s was not created correctly.", + error_cleanup, pkey_object->rel_path); + } + break; statecase(context->primary_state, PRIMARY_VERIFY_PERSISTENT); @@ -1096,9 +1109,8 @@ ifapi_load_primary_finish(FAPI_CONTEXT *context, ESYS_TR *handle) } goto_error(r, TSS2_FAPI_RC_KEY_NOT_FOUND , "The persistent handle 0x%x does not exist. " - "The TPM state and the keystore state do not match." -, error_cleanup, pkey_object->misc.key.persistent_handle); - fallthrough; + "The TPM state and the keystore state do not match.", + error_cleanup, pkey_object->misc.key.persistent_handle); statecasedefault(context->primary_state); } @@ -1147,7 +1159,6 @@ ifapi_session_init(FAPI_CONTEXT *context) context->session1 = ESYS_TR_NONE; context->session2 = ESYS_TR_NONE; - context->policy.session = ESYS_TR_NONE; context->srk_handle = ESYS_TR_NONE; return TSS2_RC_SUCCESS; } @@ -1176,7 +1187,6 @@ ifapi_non_tpm_mode_init(FAPI_CONTEXT *context) context->session1 = ESYS_TR_NONE; context->session2 = ESYS_TR_NONE; - context->policy.session = ESYS_TR_NONE; context->srk_handle = ESYS_TR_NONE; return TSS2_RC_SUCCESS; } @@ -1191,10 +1201,15 @@ ifapi_non_tpm_mode_init(FAPI_CONTEXT *context) void ifapi_session_clean(FAPI_CONTEXT *context) { - if (context->policy_session && context->policy_session != ESYS_TR_NONE) { - Esys_FlushContext(context->esys, context->policy_session); - } - if (context->session1 != ESYS_TR_NONE) { + TPM2_HANDLE tpm_policy_handle; + TPMI_YES_NO moreData; + TPMS_CAPABILITY_DATA *capabilityData = NULL; + bool handle_found = false; + + if (context->session1 != ESYS_TR_NONE && context->session1 != ESYS_TR_PASSWORD) { + if (context->session1 == context->session2) { + context->session2 = ESYS_TR_NONE; + } if (Esys_FlushContext(context->esys, context->session1) != TSS2_RC_SUCCESS) { LOG_ERROR("Cleanup session failed."); } @@ -1203,8 +1218,41 @@ ifapi_session_clean(FAPI_CONTEXT *context) if (context->session2 != ESYS_TR_NONE) { if (Esys_FlushContext(context->esys, context->session2) != TSS2_RC_SUCCESS) { LOG_ERROR("Cleanup session failed."); - context->session2 = ESYS_TR_NONE; } + context->session2 = ESYS_TR_NONE; + } + + if (context->policy_session && + context->policy_session != ESYS_TR_NONE) { + if (Esys_TR_GetTpmHandle(context->esys, context->policy_session, &tpm_policy_handle)) { + LOG_ERROR("Cleanup policy_session could not get TPM handle."); + } else { + /* Check whether policy session still exists. */ + if (Esys_GetCapability(context->esys, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + TPM2_CAP_HANDLES, TPM2_LOADED_SESSION_FIRST , TPM2_MAX_CAP_HANDLES, &moreData, + &capabilityData)) { + LOG_ERROR("Cleanup policy_session could not check TPM handle."); + } else { + /* Loop is used because usage of tpm_policy_handle instead of TPM2_LOADED_SESSION_FIRST + for get capability did not work. If the handle is not found and moreData is set + the flush will also be executed. */ + for (uint32_t i = 0; i < capabilityData->data.handles.count; i++) { + if (capabilityData->data.handles.handle[i] == tpm_policy_handle) { + handle_found = true; + } + } + if (handle_found || moreData) { + SAFE_FREE(capabilityData); + if (Esys_FlushContext(context->esys, context->policy_session) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup policy_session failed."); + } + } else { + SAFE_FREE(capabilityData); + } + } + } + context->policy_session = ESYS_TR_NONE; } if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) { if (Esys_FlushContext(context->esys, context->srk_handle) != TSS2_RC_SUCCESS) { @@ -1234,46 +1282,48 @@ ifapi_cleanup_session(FAPI_CONTEXT *context) TSS2_RC r; /* Policy sessions were closed after successful execution. */ - context->policy_session = ESYS_TR_NONE; switch (context->cleanup_state) { statecase(context->cleanup_state, CLEANUP_INIT); if (context->session1 != ESYS_TR_NONE) { + if (context->session1 == context->session2) { + context->session2 = ESYS_TR_NONE; + } r = Esys_FlushContext_Async(context->esys, context->session1); - try_again_or_error(r, "Flush session."); + try_again_or_error_goto(r, "Flush session.", error); } fallthrough; statecase(context->cleanup_state, CLEANUP_SESSION1); if (context->session1 != ESYS_TR_NONE) { r = Esys_FlushContext_Finish(context->esys); - try_again_or_error(r, "Flush session."); + try_again_or_error_goto(r, "Flush session.", error); } context->session1 = ESYS_TR_NONE; if (context->session2 != ESYS_TR_NONE) { r = Esys_FlushContext_Async(context->esys, context->session2); - try_again_or_error(r, "Flush session."); + try_again_or_error_goto(r, "Flush session.", error); } fallthrough; statecase(context->cleanup_state, CLEANUP_SESSION2); if (context->session2 != ESYS_TR_NONE) { r = Esys_FlushContext_Finish(context->esys); - try_again_or_error(r, "Flush session."); + try_again_or_error_goto(r, "Flush session.", error); } context->session2 = ESYS_TR_NONE; if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) { r = Esys_FlushContext_Async(context->esys, context->srk_handle); - try_again_or_error(r, "Flush SRK."); + try_again_or_error_goto(r, "Flush SRK.", error); } fallthrough; statecase(context->cleanup_state, CLEANUP_SRK); if (!context->srk_persistent && context->srk_handle != ESYS_TR_NONE) { r = Esys_FlushContext_Finish(context->esys); - try_again_or_error(r, "Flush SRK."); + try_again_or_error_goto(r, "Flush SRK.", error); context->srk_handle = ESYS_TR_NONE; context->srk_persistent = false; @@ -1283,6 +1333,9 @@ ifapi_cleanup_session(FAPI_CONTEXT *context) statecasedefault(context->state); } + error: + context->cleanup_state = CLEANUP_INIT; + return r; } /** Cleanup primary keys in error cases (non asynchronous). @@ -1321,7 +1374,7 @@ ifapi_primary_clean(FAPI_CONTEXT *context) * @param[in] context The FAPI_CONTEXT storing the used handles. * @param[in] session_flags The flags to adjust used session and encryption * key. With IFAPI_SESSION1 and IFAPI_SESSION2 the session creation - * for sesion1 and session2 can be activated, IFAPI_SESSION_GENEK + * for sesion1 and session2 can be activated, IFAPI_SESSION_GEN_SRK * triggers the creation of the primary for session secret encryption. * @param[in] attribute_flags1 The attributes used for session1. * @param[in] attribute_flags2 The attributes used for session2. @@ -1355,7 +1408,10 @@ ifapi_get_sessions_async(FAPI_CONTEXT *context, context->session2_attribute_flags = attribute_flags2; char *file = NULL; - if (!(session_flags & IFAPI_SESSION_GENEK)) { + if (session_flags & IFAPI_SESSION_USE_SRK) { + context->session_state = SESSION_CREATE_SESSION; + return TSS2_RC_SUCCESS; + } else if (!(session_flags & IFAPI_SESSION_GEN_SRK)) { context->srk_handle = ESYS_TR_NONE; context->session_state = SESSION_CREATE_SESSION; return TSS2_RC_SUCCESS; @@ -1985,7 +2041,8 @@ ifapi_load_key_finish(FAPI_CONTEXT *context, bool flush_parent) r = Esys_Load_Async(context->esys, context->loadKey.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &private, &key->public); goto_if_error(r, "Load async", error_cleanup); fallthrough; @@ -1996,6 +2053,7 @@ ifapi_load_key_finish(FAPI_CONTEXT *context, bool flush_parent) goto_if_error_reset_state(r, "Load", error_cleanup); /* The current parent is flushed if not prohibited by flush parent */ + context->session2 = ESYS_TR_NONE; if (flush_parent && context->loadKey.auth_object.objectType == IFAPI_KEY_OBJ && ! context->loadKey.auth_object.misc.key.persistent_handle) { r = Esys_FlushContext(context->esys, context->loadKey.auth_object.public.handle); @@ -2011,14 +2069,9 @@ ifapi_load_key_finish(FAPI_CONTEXT *context, bool flush_parent) IFAPI_OBJECT *top_obj = context->loadKey.key_list->object; ifapi_cleanup_ifapi_object(top_obj); SAFE_FREE(context->loadKey.key_list->object); - r = pop_object_from_list(context, &context->loadKey.key_list); + r = pop_object_from_list(&context->loadKey.key_list); goto_if_error_reset_state(r, "Pop key failed.", error_cleanup); - if (context->loadKey.key_list) { - /* Object can be cleaned if it's not the last */ - ifapi_free_object(context, &top_obj); - } - context->loadKey.state = LOAD_KEY_LOAD_KEY; return TSS2_FAPI_RC_TRY_AGAIN; @@ -2078,27 +2131,6 @@ get_name_alg(FAPI_CONTEXT *context, IFAPI_OBJECT *object) } } -/** Check whether policy session has to be flushed. - * - * Policy sessions with cleared continue session flag are not flushed in error - * cases. Therefore the return code will be checked and if a policy session was - * used the session will be flushed if the command was not executed successfully. - * - * @param[in,out] context for storing all state information. - * @param[in] session the session to be checked whether flush is needed. - * @param[in] r The return code of the command using the session. - */ -void -ifapi_flush_policy_session(FAPI_CONTEXT *context, ESYS_TR session, TSS2_RC r) -{ - if (session != context->session1) { - /* A policy session was used instead auf the default session. */ - if (r != TSS2_RC_SUCCESS) { - Esys_FlushContext(context->esys, session); - } - } -} - /** State machine to authorize a key, a NV object of a hierarchy. * * @param[in,out] context for storing all state information. @@ -2134,9 +2166,7 @@ ifapi_authorize_object(FAPI_CONTEXT *context, IFAPI_OBJECT *object, ESYS_TR *ses switch (object->authorization_state) { statecase(object->authorization_state, AUTH_INIT) LOG_TRACE("**STATE** AUTH_INIT"); - if (!policy_digest_size(object)) { - /* No policy used authorization callbacks have to be called if necessary. */ if (object_with_auth(object)) { /* Check whether hierarchy was already authorized. */ if (object->objectType != IFAPI_HIERARCHY_OBJ || @@ -2150,14 +2180,18 @@ ifapi_authorize_object(FAPI_CONTEXT *context, IFAPI_OBJECT *object, ESYS_TR *ses return_if_error(r, "Set auth value"); } } + } + if (!policy_digest_size(object)) { /* No policy session needed current fapi session can be used */ if (context->session1 && context->session1 != ESYS_TR_NONE) *session = context->session1; else /* Use password session if session1 had not been created */ *session = ESYS_TR_PASSWORD; + context->session2 = ESYS_TR_NONE; break; } + /* Save current object to be authorized in context. */ context->current_auth_object = object; r = ifapi_policyutil_execute_prepare(context, get_name_alg(context, object), @@ -2167,6 +2201,11 @@ ifapi_authorize_object(FAPI_CONTEXT *context, IFAPI_OBJECT *object, ESYS_TR *ses /* Next state will switch from prev context to next context. */ context->policy.util_current_policy = context->policy.util_current_policy->prev; object->authorization_state = AUTH_EXEC_POLICY; + + /* Use session for parameter encryption */ + if (context->session1 != ESYS_TR_PASSWORD) { + context->session2 = context->session1; + } fallthrough; statecase(object->authorization_state, AUTH_EXEC_POLICY) @@ -2177,6 +2216,7 @@ ifapi_authorize_object(FAPI_CONTEXT *context, IFAPI_OBJECT *object, ESYS_TR *ses return_if_error(r, "Execute policy."); + context->policy_session = *session; r = Esys_TRSess_GetAuthRequired(context->esys, *session, &auth_required); return_if_error(r, "GetAuthRequired"); @@ -2204,6 +2244,7 @@ ifapi_authorize_object(FAPI_CONTEXT *context, IFAPI_OBJECT *object, ESYS_TR *ses error: /* No policy call was executed session can be flushed */ Esys_FlushContext(context->esys, *session); + *session = ESYS_TR_NONE; return r; } @@ -2291,13 +2332,13 @@ ifapi_nv_write( /* Prepare reading of the key from keystore. */ r = ifapi_keystore_load_async(&context->keystore, &context->io, context->nv_cmd.nvPath); - return_if_error2(r, "Could not open: %s", context->nv_cmd.nvPath); + goto_if_error2(r, "Could not open: %s", error_cleanup, context->nv_cmd.nvPath); fallthrough; statecase(context->nv_cmd.nv_write_state, NV2_WRITE_READ); r = ifapi_keystore_load_finish(&context->keystore, &context->io, object); return_try_again(r); - return_if_error(r, "read_finish failed"); + goto_if_error(r, "read_finish failed", error_cleanup); if (object->objectType != IFAPI_NV_OBJ) goto_error(r, TSS2_FAPI_RC_BAD_PATH, "%s is no NV object.", error_cleanup, @@ -2327,7 +2368,7 @@ ifapi_nv_write( context->nv_cmd.auth_index = auth_index; /* Get A session for authorizing the NV write operation. */ - r = ifapi_get_sessions_async(context, IFAPI_SESSION_GENEK | IFAPI_SESSION1, + r = ifapi_get_sessions_async(context, IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_DECRYPT, 0); goto_if_error(r, "Create sessions", error_cleanup); @@ -2345,12 +2386,14 @@ ifapi_nv_write( r = ifapi_authorize_object(context, auth_object, &auth_session); FAPI_SYNC(r, "Authorize NV object.", error_cleanup); + context->nv_cmd.auth_session = auth_session; + /* Prepare the writing to NV ram. */ r = Esys_NV_Write_Async(context->esys, context->nv_cmd.auth_index, nv_index, auth_session, - context->session2, + ENC_SESSION_IF_POLICY(auth_session), ESYS_TR_NONE, aux_data, context->nv_cmd.data_idx); @@ -2375,7 +2418,7 @@ ifapi_nv_write( IFAPI_OBJECT *auth_object = &context->nv_cmd.auth_object; char *description; r = ifapi_get_description(auth_object, &description); - return_if_error(r, "Get description"); + goto_if_error(r, "Get description", error_cleanup); r = ifapi_set_auth(context, auth_object, description); SAFE_FREE(description); goto_if_error_reset_state(r, " Fapi_NvWrite_Finish", error_cleanup); @@ -2384,10 +2427,8 @@ ifapi_nv_write( r = Esys_NV_Write_Async(context->esys, context->nv_cmd.auth_index, nv_index, - (!context->policy.session - || context->policy.session == ESYS_TR_NONE) ? context->session1 : - context->policy.session, - context->session2, + context->nv_cmd.auth_session, + ENC_SESSION_IF_POLICY(context->nv_cmd.auth_session), ESYS_TR_NONE, aux_data, context->nv_cmd.data_idx); @@ -2421,7 +2462,7 @@ ifapi_nv_write( context->nv_cmd.auth_index, nv_index, auth_session, - context->session2, + ENC_SESSION_IF_POLICY(auth_session), ESYS_TR_NONE, aux_data, context->nv_cmd.data_idx); @@ -2458,16 +2499,16 @@ ifapi_nv_write( LOG_DEBUG("success"); r = TSS2_RC_SUCCESS; - - context->nv_cmd.nv_write_state = NV2_WRITE_INIT; break; statecasedefault(context->nv_cmd.nv_write_state); } error_cleanup: + context->session2 = ESYS_TR_NONE; SAFE_FREE(nv_file_name); SAFE_FREE(context->nv_cmd.write_data); + context->nv_cmd.nv_write_state = NV2_WRITE_INIT; return r; } @@ -2550,11 +2591,12 @@ ifapi_nv_read( aux_size = *numBytes; /* Prepare the reading from NV ram. */ + r = Esys_NV_Read_Async(context->esys, context->nv_cmd.auth_index, nv_index, session, - ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(session), ESYS_TR_NONE, aux_size, 0); @@ -2616,7 +2658,7 @@ ifapi_nv_read( context->nv_cmd.auth_index, nv_index, session, - ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(session), ESYS_TR_NONE, aux_size, context->nv_cmd.data_idx); @@ -2626,7 +2668,6 @@ ifapi_nv_read( return TSS2_FAPI_RC_TRY_AGAIN; } else { *size = context->nv_cmd.data_idx; - context->nv_cmd.nv_read_state = NV_READ_INIT; LOG_DEBUG("success"); r = TSS2_RC_SUCCESS; break; @@ -2650,7 +2691,6 @@ ifapi_nv_read( if (capabilityData->data.handles.count == 0 || capabilityData->data.handles.handle[0] != context->nv_cmd.tpm_handle) { - context->nv_cmd.nv_read_state = NV_READ_INIT; *size = 0; break; } @@ -2687,7 +2727,9 @@ ifapi_nv_read( } error_cleanup: + context->session2 = ESYS_TR_NONE; SAFE_FREE(capabilityData); + context->nv_cmd.nv_read_state = NV_READ_INIT; return r; } @@ -2834,8 +2876,9 @@ ifapi_load_key( /* Prepare the session creation. */ r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, - TPMA_SESSION_DECRYPT, 0); + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, + TPMA_SESSION_DECRYPT | TPMA_SESSION_ENCRYPT, + 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; @@ -2859,7 +2902,6 @@ ifapi_load_key( return_try_again(r); goto_if_error_reset_state(r, " Load key.", error_cleanup); - context->loadKey.prepare_state = PREPARE_LOAD_KEY_INIT; break; statecase(context->loadKey.prepare_state, PREPARE_LOAD_KEY_INIT_KEY); @@ -2875,6 +2917,7 @@ ifapi_load_key( } error_cleanup: + context->loadKey.prepare_state = PREPARE_LOAD_KEY_INIT; return r; } @@ -2947,9 +2990,8 @@ ifapi_key_sign( context->Key_Sign.handle = sig_key_object->public.handle; r = ifapi_authorize_object(context, sig_key_object, &session); - FAPI_SYNC(r, "Authorize signature key.", cleanup); - - context->policy.session = session; + return_try_again(r); + goto_if_error(r, "Authorize signing key", cleanup); r = ifapi_get_sig_scheme(context, sig_key_object, padding, digest, &sig_scheme); goto_if_error(r, "Get signature scheme", cleanup); @@ -2958,7 +3000,8 @@ ifapi_key_sign( r = Esys_Sign_Async(context->esys, context->Key_Sign.handle, session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(session), + ESYS_TR_NONE, digest, &sig_scheme, &hash_validation); @@ -2970,7 +3013,7 @@ ifapi_key_sign( r = Esys_Sign_Finish(context->esys, &context->Key_Sign.signature); return_try_again(r); - ifapi_flush_policy_session(context, context->policy.session, r); + context->session2 = ESYS_TR_NONE; goto_if_error(r, "Error: Sign", cleanup); /* Prepare the flushing of the signing key. */ @@ -3006,7 +3049,6 @@ ifapi_key_sign( strdup_check(*certificate, "", r, cleanup); } } - context->Key_Sign.state = SIGN_INIT; LOG_TRACE("success"); r = TSS2_RC_SUCCESS; break; @@ -3018,6 +3060,8 @@ ifapi_key_sign( if (context->Key_Sign.handle != ESYS_TR_NONE) Esys_FlushContext(context->esys, context->Key_Sign.handle); ifapi_cleanup_ifapi_object(context->Key_Sign.key_object); + context->Key_Sign.state = SIGN_INIT; + return r; } @@ -3492,7 +3536,7 @@ ifapi_key_create( context->policy.hash_size); } r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_ENCRYPT | TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); fallthrough; @@ -3537,7 +3581,8 @@ ifapi_key_create( r = Esys_Create_Async(context->esys, context->loadKey.auth_object.public.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &context->cmd.Key_Create.inSensitive, &context->cmd.Key_Create.public_templ.public, &context->cmd.Key_Create.outsideInfo, @@ -3550,6 +3595,8 @@ ifapi_key_create( &creationHash, &creationTicket); try_again_or_error_goto(r, "Key create finish", error_cleanup); + context->session2 = ESYS_TR_NONE; + /* Prepare object for serialization */ object->system = context->cmd.Key_Create.public_templ.system; object->objectType = IFAPI_KEY_OBJ; @@ -3599,7 +3646,8 @@ ifapi_key_create( r = Esys_Load_Async(context->esys, context->loadKey.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &private, &object->misc.key.public); goto_if_error(r, "Load key.", error_cleanup); @@ -3613,6 +3661,7 @@ ifapi_key_create( return_try_again(r); goto_if_error_reset_state(r, "Load", error_cleanup); } + context->session2 = ESYS_TR_NONE; /* Prepare Flushing of key used for authorization */ if (!context->loadKey.auth_object.misc.key.persistent_handle) { r = Esys_FlushContext_Async(context->esys, context->loadKey.auth_object.public.handle); @@ -3655,7 +3704,8 @@ ifapi_key_create( /* Prepare making the loaded key permanent. */ r = Esys_EvictControl_Async(context->esys, hierarchy->public.handle, context->loadKey.handle, - auth_session, ESYS_TR_NONE, + auth_session, + ESYS_TR_NONE, ESYS_TR_NONE, object->misc.key.persistent_handle); goto_if_error(r, "Error Esys EvictControl", error_cleanup); @@ -3680,6 +3730,8 @@ ifapi_key_create( r = ifapi_flush_object(context, context->loadKey.handle); return_try_again(r); goto_if_error(r, "Flush key", error_cleanup); + + context->loadKey.handle = ESYS_TR_NONE; } fallthrough; @@ -3874,7 +3926,8 @@ ifapi_change_auth_hierarchy( (auth_session && auth_session != ESYS_TR_NONE) ? auth_session : ESYS_TR_PASSWORD, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, newAuthValue); return_if_error(r, "HierarchyChangeAuth"); fallthrough; @@ -3918,6 +3971,7 @@ ifapi_change_auth_hierarchy( statecasedefault(context->hierarchy_state); } error: + context->hierarchy_state = HIERARCHY_CHANGE_AUTH_INIT; return r; } @@ -4024,7 +4078,8 @@ ifapi_change_policy_hierarchy( (auth_session && auth_session != ESYS_TR_NONE) ? auth_session : ESYS_TR_PASSWORD, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &context->cmd.Provision.policy_digest, context->cmd.Provision.policy_digest.size ? context->profiles.default_profile.nameAlg : @@ -4109,32 +4164,6 @@ ifapi_free_objects(FAPI_CONTEXT *context) } } -/** Free ifapi a object stored in the context. - * - * @param[in,out] context The FAPI_CONTEXT. - * @param[in,out] object The object which should be removed from the - * the linked list stored in context. - */ -void -ifapi_free_object(FAPI_CONTEXT *context, IFAPI_OBJECT **object) -{ - NODE_OBJECT_T *node; - NODE_OBJECT_T **update_ptr; - - for (node = context->object_list, - update_ptr = &context->object_list; - node != NULL; - update_ptr = &node->next, node = node->next) { - if (node->object == object) { - *update_ptr = node->next; - SAFE_FREE(node->object); - SAFE_FREE(node); - *object = NULL; - return; - } - } -} - #define ADD_CAPABILITY_INFO(capability, field, subfield, max_count, property_count) \ if (context->cmd.GetInfo.fetched_data->data.capability.count > max_count - property_count) { \ context->cmd.GetInfo.fetched_data->data.capability.count = max_count - property_count; \ @@ -4757,7 +4786,7 @@ ifapi_create_primary( } r = ifapi_get_sessions_async(context, - IFAPI_SESSION_GENEK | IFAPI_SESSION1, + IFAPI_SESSION_GEN_SRK | IFAPI_SESSION1, TPMA_SESSION_ENCRYPT | TPMA_SESSION_DECRYPT, 0); goto_if_error_reset_state(r, "Create sessions", error_cleanup); @@ -4794,7 +4823,8 @@ ifapi_create_primary( r = Esys_CreatePrimary_Async(context->esys, hierarchy->public.handle, auth_session, - ESYS_TR_NONE, ESYS_TR_NONE, + ENC_SESSION_IF_POLICY(auth_session), + ESYS_TR_NONE, &context->cmd.Key_Create.inSensitive, &context->cmd.Key_Create.public_templ.public, &context->cmd.Key_Create.outsideInfo, @@ -4811,6 +4841,7 @@ ifapi_create_primary( try_again_or_error_goto(r, "Create primary.", error_cleanup); /* Prepare object for serialization */ + context->session2 = ESYS_TR_NONE; object->system = context->cmd.Key_Create.public_templ.system; object->objectType = IFAPI_KEY_OBJ; object->misc.key.public = *outPublic; @@ -4845,13 +4876,15 @@ ifapi_create_primary( statecase(context->cmd.Key_Create.state, KEY_CREATE_PRIMARY_WAIT_FOR_AUTHORIZE2); if (template->persistent_handle) { + object->misc.key.persistent_handle = template->persistent_handle; r = ifapi_authorize_object(context, hierarchy, &auth_session); FAPI_SYNC(r, "Authorize hierarchy.", error_cleanup); /* Prepare making the created primary permanent. */ r = Esys_EvictControl_Async(context->esys, hierarchy->public.handle, context->cmd.Key_Create.handle, - auth_session, ESYS_TR_NONE, + auth_session, + ESYS_TR_NONE, ESYS_TR_NONE, object->misc.key.persistent_handle); goto_if_error(r, "Error Esys EvictControl", error_cleanup); @@ -4874,6 +4907,8 @@ ifapi_create_primary( return_try_again(r); goto_if_error(r, "Flush key", error_cleanup); + context->cmd.Key_Create.handle = ESYS_TR_NONE; + fallthrough; statecase(context->cmd.Key_Create.state, KEY_CREATE_PRIMARY_WRITE_PREPARE); diff --git a/src/tss2-fapi/fapi_util.h b/src/tss2-fapi/fapi_util.h index f9974be..8718251 100644 --- a/src/tss2-fapi/fapi_util.h +++ b/src/tss2-fapi/fapi_util.h @@ -125,12 +125,6 @@ ifapi_nv_read( uint8_t **data, size_t *size); -void -ifapi_flush_policy_session( - FAPI_CONTEXT *context, - ESYS_TR session, - TSS2_RC r); - TSS2_RC ifapi_nv_write( FAPI_CONTEXT *context, diff --git a/src/tss2-fapi/ifapi_config.c b/src/tss2-fapi/ifapi_config.c index 35e585f..dafd4e1 100644 --- a/src/tss2-fapi/ifapi_config.c +++ b/src/tss2-fapi/ifapi_config.c @@ -115,8 +115,11 @@ ifapi_json_IFAPI_CONFIG_deserialize(json_object *jso, IFAPI_CONFIG *out) } if (ifapi_get_sub_object(jso, "intel_cert_service", &jso2)) { - r = ifapi_json_char_deserialize(jso2, &out->intel_cert_service); + r = ifapi_json_char_deserialize(jso2, &out->web_cert_service); return_if_error(r, "Bad value for field \"intel_cert_service\"."); + } else if (ifapi_get_sub_object(jso, "web_cert_service", &jso2)) { + r = ifapi_json_char_deserialize(jso2, &out->web_cert_service); + return_if_error(r, "Bad value for field \"web_cert_service\"."); } if (!ifapi_get_sub_object(jso, "firmware_log_file", &jso2)) { @@ -305,7 +308,7 @@ ifapi_config_initialize_finish(IFAPI_IO *io, IFAPI_CONFIG *config) SAFE_FREE(config->tcti); SAFE_FREE(config->log_dir); SAFE_FREE(config->ek_cert_file); - SAFE_FREE(config->intel_cert_service); + SAFE_FREE(config->web_cert_service); SAFE_FREE(configFileContent); if (jso != NULL) { json_object_put(jso); diff --git a/src/tss2-fapi/ifapi_config.h b/src/tss2-fapi/ifapi_config.h index cadfe00..dca00a4 100644 --- a/src/tss2-fapi/ifapi_config.h +++ b/src/tss2-fapi/ifapi_config.h @@ -38,8 +38,8 @@ typedef struct { char *ek_cert_file; /* Switch whether certificate validation will done */ TPMI_YES_NO ek_cert_less; - /** Certificate service for Intel TPMs */ - char *intel_cert_service; + /** Certificate service for Intel/AMD TPMs */ + char *web_cert_service; /* File with firmware measurements. */ char *firmware_log_file; /* File with ima measurements. */ diff --git a/src/tss2-fapi/ifapi_curl.c b/src/tss2-fapi/ifapi_curl.c index 01f6e13..976f36d 100644 --- a/src/tss2-fapi/ifapi_curl.c +++ b/src/tss2-fapi/ifapi_curl.c @@ -107,8 +107,10 @@ get_crl_from_cert(X509 *cert, X509_CRL **crl) unsigned const char* tmp_ptr1 = crl_buffer; unsigned const char** tmp_ptr2 = &tmp_ptr1; - if (!d2i_X509_CRL(crl, tmp_ptr2, crl_buffer_size)) { - goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Can't convert crl.", cleanup); + if (crl_buffer_size > 0) { + if (!d2i_X509_CRL(crl, tmp_ptr2, crl_buffer_size)) { + goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Can't convert crl.", cleanup); + } } cleanup: @@ -118,6 +120,19 @@ get_crl_from_cert(X509 *cert, X509_CRL **crl) return r; } +static bool +is_self_signed(X509 *cert) { + X509_NAME *issuer = X509_get_issuer_name(cert); + X509_NAME *subject = X509_get_subject_name(cert); + + /* Compare the issuer and subject names */ + if (X509_NAME_cmp(issuer, subject) == 0) { + return true; + } else { + return false; + } +} + /** * Verify EK certificate read from TPM. * @@ -256,25 +271,28 @@ ifapi_curl_verify_ek_cert( } /* Verify intermediate certificate */ - ctx = X509_STORE_CTX_new(); - goto_if_null2(ctx, "Failed to create X509 store context.", - r, TSS2_FAPI_RC_GENERAL_FAILURE, cleanup); - if (1 != X509_STORE_CTX_init(ctx, store, intermed_cert, NULL)) { - goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, - "Failed to initialize X509 context.", cleanup); - } - if (1 != X509_verify_cert(ctx)) { - LOG_ERROR("%s", X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx))); - goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, - "Failed to verify intermediate certificate", cleanup); - } - if (1 != X509_STORE_add_cert(store, intermed_cert)) { - goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, - "Failed to add intermediate certificate", cleanup); - } + if (!is_self_signed(intermed_cert)) { + ctx = X509_STORE_CTX_new(); + goto_if_null2(ctx, "Failed to create X509 store context.", + r, TSS2_FAPI_RC_GENERAL_FAILURE, cleanup); + + if (1 != X509_STORE_CTX_init(ctx, store, intermed_cert, NULL)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Failed to initialize X509 context.", cleanup); + } + if (1 != X509_verify_cert(ctx)) { + LOG_ERROR("%s", X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx))); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Failed to verify intermediate certificate", cleanup); + } + if (1 != X509_STORE_add_cert(store, intermed_cert)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Failed to add intermediate certificate", cleanup); + } - X509_STORE_CTX_cleanup(ctx); - X509_STORE_CTX_free(ctx); + X509_STORE_CTX_cleanup(ctx); + X509_STORE_CTX_free(ctx); + } ctx = NULL; ctx = X509_STORE_CTX_new(); goto_if_null2(ctx, "Failed to create X509 store context.", diff --git a/src/tss2-fapi/ifapi_eventlog.c b/src/tss2-fapi/ifapi_eventlog.c index 8e542ee..51aae0f 100644 --- a/src/tss2-fapi/ifapi_eventlog.c +++ b/src/tss2-fapi/ifapi_eventlog.c @@ -123,7 +123,9 @@ ifapi_eventlog_get_async( r = ifapi_json_IFAPI_EVENT_serialize(&cel_event, &jso); goto_if_error(r, "Error serialize event", error); - json_object_array_add(eventlog->log, jso); + if (json_object_array_add(eventlog->log, jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } } @@ -155,7 +157,9 @@ ifapi_eventlog_get_async( r = ifapi_json_IFAPI_EVENT_serialize(&cel_event, &jso); goto_if_error(r, "Error serialize event", error); - json_object_array_add(eventlog->log, jso); + if (json_object_array_add(eventlog->log, jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } } if (eventlog->ima_log_file) { @@ -200,10 +204,11 @@ ifapi_eventlog_get_async( TSS2_RC ifapi_eventlog_get_finish( IFAPI_EVENTLOG *eventlog, + FAPI_QUOTE_INFO *fapi_quote_info, IFAPI_IO *io, char **log) { - /* eventlog parameter currently not used */ + /* eventlog parameteifapi_eventlog_get_finishr currently not used */ check_not_null(eventlog); check_not_null(io); check_not_null(log); @@ -230,7 +235,13 @@ ifapi_eventlog_get_finish( goto_if_error(r, "Error serialize policy", error); ifapi_cleanup_event(&event); - } + } + if (fapi_quote_info) { + r = ifapi_calculate_pcr_digest(eventlog->log, + fapi_quote_info); + + goto_if_error(r, "Verify event list.", error); + } *log = strdup(json_object_to_json_string_ext(eventlog->log, JSON_C_TO_STRING_PRETTY)); check_oom(*log); @@ -279,7 +290,9 @@ ifapi_eventlog_get_finish( json_type jso_type = json_object_get_type(logpart); if (jso_type != json_type_array) { /* libjson-c does not deliver an array if array has only one element */ - json_object_array_add(eventlog->log, logpart); + if (json_object_array_add(eventlog->log, logpart)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } else { /* Iterate through the array of logpart and add each item to the eventlog */ /* The return type of json_object_array_length() was changed, thus the case */ @@ -287,7 +300,9 @@ ifapi_eventlog_get_finish( jso_event = json_object_array_get_idx(logpart, i); /* Increment the refcount of event so it does not get freed on put(logpart) below */ json_object_get(jso_event); - json_object_array_add(eventlog->log, jso_event); + if (json_object_array_add(eventlog->log, jso_event)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } json_object_put(logpart); } @@ -358,7 +373,9 @@ ifapi_eventlog_append_check( json_type jso_type = json_object_get_type(eventlog->log); if (jso_type != json_type_array) { json_object *json_array = json_object_new_array(); - json_object_array_add(json_array, eventlog->log); + if (json_object_array_add(json_array, eventlog->log)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } eventlog->log = json_array; } } else { @@ -437,7 +454,9 @@ ifapi_eventlog_append_finish( goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "Error serializing event data", error_cleanup); } - json_object_array_add(eventlog->log, event); + if (json_object_array_add(eventlog->log, event)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } logstr2 = json_object_to_json_string_ext(eventlog->log, JSON_C_TO_STRING_PRETTY); /* Construct the filename for the eventlog file */ diff --git a/src/tss2-fapi/ifapi_eventlog.h b/src/tss2-fapi/ifapi_eventlog.h index 0ef50ab..e70893a 100644 --- a/src/tss2-fapi/ifapi_eventlog.h +++ b/src/tss2-fapi/ifapi_eventlog.h @@ -84,6 +84,13 @@ typedef struct IFAPI_EVENT { verified. */ } IFAPI_EVENT; +/** Type for representing the quote info and signature scheme for quote. + */ +typedef struct { + TPMT_SIG_SCHEME sig_scheme; /**< Signature scheme used for quote. */ + TPMS_ATTEST attest; /**< Attestation data from Quote */ +} FAPI_QUOTE_INFO; + enum IFAPI_EVENTLOG_STATE { IFAPI_EVENTLOG_STATE_INIT = 0, IFAPI_EVENTLOG_STATE_READING, @@ -120,6 +127,7 @@ ifapi_eventlog_get_async( TSS2_RC ifapi_eventlog_get_finish( IFAPI_EVENTLOG *eventlog, + FAPI_QUOTE_INFO *fapi_quote_info, IFAPI_IO *io, char **log); diff --git a/src/tss2-fapi/ifapi_eventlog_system.c b/src/tss2-fapi/ifapi_eventlog_system.c index e2ef6d7..81d2b07 100644 --- a/src/tss2-fapi/ifapi_eventlog_system.c +++ b/src/tss2-fapi/ifapi_eventlog_system.c @@ -99,7 +99,6 @@ bool digest2_accumulator_callback(TCG_DIGEST2 const *digest, size_t size, bool foreach_digest2( tpm2_eventlog_context *ctx, UINT32 event_type, - unsigned pcr_index, TCG_DIGEST2 const *digest, size_t count, size_t size) { @@ -110,7 +109,6 @@ bool foreach_digest2( } bool ret = true; - TSS2_RC r; size_t i, j; for (i = 0; i < count; i++) { @@ -126,36 +124,6 @@ bool foreach_digest2( return false; } - uint8_t *pcr = NULL; - if (pcr_index > TPM2_MAX_PCRS) { - LOG_ERROR("PCR%d > max %d", pcr_index, TPM2_MAX_PCRS); - return false; - } else if (alg == TPM2_ALG_SHA1) { - pcr = ctx->sha1_pcrs[pcr_index]; - ctx->sha1_used |= (1 << pcr_index); - } else if (alg == TPM2_ALG_SHA256) { - pcr = ctx->sha256_pcrs[pcr_index]; - ctx->sha256_used |= (1 << pcr_index); - } else if (alg == TPM2_ALG_SHA384) { - pcr = ctx->sha384_pcrs[pcr_index]; - ctx->sha384_used |= (1 << pcr_index); - } else if (alg == TPM2_ALG_SHA512) { - pcr = ctx->sha512_pcrs[pcr_index]; - ctx->sha512_used |= (1 << pcr_index); - } else if (alg == TPM2_ALG_SM3_256) { - pcr = ctx->sm3_256_pcrs[pcr_index]; - ctx->sm3_256_used |= (1 << pcr_index); - } else { - LOG_WARNING("PCR%d algorithm %d unsupported", pcr_index, alg); - } - if (pcr) { - r = ifapi_extend_pcr(alg, pcr, digest->Digest, alg_size); - if (r) { - LOG_ERROR("PCR%d extend failed", pcr_index); - return false; - } - } - if (event_type == EV_NO_ACTION) { /* Digest for EV_NO_ACTION must consist of 0 bytes. */ for (j = 0; j < alg_size; j++) { @@ -236,6 +204,21 @@ bool parse_event2body(TCG_EVENT2 const *event, UINT32 type) { /* what about the device path? */ } break; + /* TCG PC Client Platform Firmware Profile Specification Level 00 Version 1.05 Revision 23 section 10.4.1 */ + case EV_EFI_HCRTM_EVENT: + { + const char hcrtm_data[] = "HCRTM"; + size_t len = strlen(hcrtm_data); + BYTE *data = (BYTE *)event->Event; + if (event->EventSize != len || + strncmp((const char *)data, hcrtm_data, len)) { + LOG_ERROR("HCRTM Event Data MUST be the string: \"%s\"", hcrtm_data); + return false; + } + } + break; + + } return true; @@ -259,7 +242,7 @@ bool parse_event2(TCG_EVENT_HEADER2 const *eventhdr, size_t buf_size, .data = digests_size, .digest2_cb = digest2_accumulator_callback, }; - ret = foreach_digest2(&ctx, eventhdr->EventType, eventhdr->PCRIndex, + ret = foreach_digest2(&ctx, eventhdr->EventType, eventhdr->Digests, eventhdr->DigestCount, buf_size - sizeof(*eventhdr)); if (ret != true) { @@ -283,12 +266,9 @@ bool parse_event2(TCG_EVENT_HEADER2 const *eventhdr, size_t buf_size, return true; } -bool parse_sha1_log_event(tpm2_eventlog_context *ctx, TCG_EVENT const *event, size_t size, +bool parse_sha1_log_event(TCG_EVENT const *event, size_t size, size_t *event_size) { - uint8_t *pcr = NULL; - TSS2_RC r; - /* enough size for the 1.2 event structure */ if (size < sizeof(*event)) { LOG_ERROR("insufficient size for SpecID event header"); @@ -300,16 +280,6 @@ bool parse_sha1_log_event(tpm2_eventlog_context *ctx, TCG_EVENT const *event, si } *event_size = sizeof(*event); - pcr = ctx->sha1_pcrs[ event->pcrIndex]; - if (pcr) { - r = ifapi_extend_pcr(TPM2_ALG_SHA1, pcr, &event->digest[0], 20); - if (r) { - LOG_ERROR("PCR%d extend failed", event->pcrIndex); - return false; - } - ctx->sha1_used |= (1 << event->pcrIndex); - } - /* buffer size must be sufficient to hold event and event data */ if (size < sizeof(*event) + (sizeof(event->event[0]) * event->eventDataSize)) { @@ -339,7 +309,7 @@ bool foreach_sha1_log_event(tpm2_eventlog_context *ctx, TCG_EVENT const *eventhd eventhdr = (TCG_EVENT*)((uintptr_t)eventhdr + event_size), size -= event_size) { - ret = parse_sha1_log_event(ctx, eventhdr, size, &event_size); + ret = parse_sha1_log_event(eventhdr, size, &event_size); if (!ret) { return ret; } @@ -408,7 +378,7 @@ bool foreach_event2(tpm2_eventlog_context *ctx, TCG_EVENT_HEADER2 const *eventhd } /* digest callback foreach digest */ - ret = foreach_digest2(ctx, eventhdr->EventType, eventhdr->PCRIndex, + ret = foreach_digest2(ctx, eventhdr->EventType, eventhdr->Digests, eventhdr->DigestCount, digests_size); if (ret != true) { return false; @@ -566,6 +536,7 @@ ifapi_json_TCG_EVENT_TYPE_deserialize_txt(json_object *jso, const char *token = json_object_get_string(jso); check_oom(token); + LOG_TRACE("TCG Event: %s", token); if (get_number(token, &i64)) { *out = (IFAPI_EVENT_TYPE) i64; @@ -605,6 +576,7 @@ TSS2_RC ifapi_json_TCG_EVENT_TYPE_deserialize(json_object *jso, IFAPI_EVENT_TYPE *out) { LOG_TRACE("call"); + return ifapi_json_TCG_EVENT_TYPE_deserialize_txt(jso, out); } @@ -632,7 +604,7 @@ check_out_string(const IFAPI_FIRMWARE_EVENT *in, const char *string) { * * @param[in] jso the json object to be deserialized. * @param[out] out the deserialzed binary object. - * @param[out] verify swithc whether the digest can be verified. + * @param[out] verify switch whether the digest can be verified. * @retval TSS2_RC_SUCCESS if the function call was a success. * @retval TSS2_FAPI_RC_BAD_VALUE if the json object can't be deserialized. * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed. @@ -660,6 +632,8 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize( r = ifapi_json_TCG_EVENT_TYPE_deserialize (jso2, &event_type); return_if_error(r,"BAD VALUE"); + out->event_type = event_type; + if (!ifapi_get_sub_object(jso, "event_data", &jso2)) { LOG_ERROR("Bad value"); return TSS2_FAPI_RC_BAD_VALUE; @@ -682,6 +656,7 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize( used as digest. */ SAFE_FREE(out->data.buffer); out->data.buffer = calloc(1, 4); + check_oom(out->data.buffer); out->data.size = 4; /* hash of 0x00000001 will be used as digest. */ out->data.buffer[3] = 1; @@ -714,7 +689,10 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize( event_type == EV_IPL_PARTITION_DATA || event_type == EV_NONHOST_CODE || event_type == EV_NONHOST_CONFIG || - event_type == EV_EFI_RUNTIME_SERVICES_DRIVER) { + event_type == EV_EFI_RUNTIME_SERVICES_DRIVER || + /* Verification not possible. (TODO check) */ + event_type == EV_EFI_HCRTM_EVENT || + event_type == EV_EFI_VARIABLE_BOOT) { *verify = false; } else if ( /* Verification is possible. (TODO check) */ @@ -725,12 +703,10 @@ ifapi_json_IFAPI_FIRMWARE_EVENT_deserialize( event_type == EV_EFI_VARIABLE_AUTHORITY || /* Verification is possible. */ event_type == EV_S_CRTM_VERSION || - event_type == EV_EFI_HCRTM_EVENT || event_type == EV_SEPARATOR || event_type == EV_EFI_VARIABLE_DRIVER_CONFIG || event_type == EV_EFI_GPT_EVENT || event_type == EV_PLATFORM_CONFIG_FLAGS || - event_type == EV_EFI_VARIABLE_BOOT || event_type == EV_EFI_ACTION) { *verify = true; } else { diff --git a/src/tss2-fapi/ifapi_eventlog_system.h b/src/tss2-fapi/ifapi_eventlog_system.h index da42657..c10e2e3 100644 --- a/src/tss2-fapi/ifapi_eventlog_system.h +++ b/src/tss2-fapi/ifapi_eventlog_system.h @@ -34,16 +34,6 @@ typedef struct { EVENT2_CALLBACK event2hdr_cb; DIGEST2_CALLBACK digest2_cb; EVENT2DATA_CALLBACK event2_cb; - uint32_t sha1_used; - uint32_t sha256_used; - uint32_t sha384_used; - uint32_t sha512_used; - uint32_t sm3_256_used; - uint8_t sha1_pcrs[TPM2_MAX_PCRS][TPM2_SHA1_DIGEST_SIZE]; - uint8_t sha256_pcrs[TPM2_MAX_PCRS][TPM2_SHA256_DIGEST_SIZE]; - uint8_t sha384_pcrs[TPM2_MAX_PCRS][TPM2_SHA384_DIGEST_SIZE]; - uint8_t sha512_pcrs[TPM2_MAX_PCRS][TPM2_SHA512_DIGEST_SIZE]; - uint8_t sm3_256_pcrs[TPM2_MAX_PCRS][TPM2_SM3_256_DIGEST_SIZE]; } tpm2_eventlog_context; /** Firmware event information stored in log @@ -58,7 +48,7 @@ bool digest2_accumulator_callback(TCG_DIGEST2 const *digest, size_t size, void *data); bool parse_event2body(TCG_EVENT2 const *event, UINT32 type); -bool foreach_digest2(tpm2_eventlog_context *ctx, UINT32 event_type, unsigned pcr_index, +bool foreach_digest2(tpm2_eventlog_context *ctx, UINT32 event_type, TCG_DIGEST2 const *event_hdr, size_t count, size_t size); bool parse_event2(TCG_EVENT_HEADER2 const *eventhdr, size_t buf_size, size_t *event_size, size_t *digests_size); diff --git a/src/tss2-fapi/ifapi_get_intl_cert.c b/src/tss2-fapi/ifapi_get_web_cert.c similarity index 52% rename from src/tss2-fapi/ifapi_get_intl_cert.c rename to src/tss2-fapi/ifapi_get_web_cert.c index f8e135e..d06e8d8 100644 --- a/src/tss2-fapi/ifapi_get_intl_cert.c +++ b/src/tss2-fapi/ifapi_get_web_cert.c @@ -24,6 +24,9 @@ #include "util/log.h" #include "util/aux_util.h" +#define AMD_EK_URI_LEN 16 /*<< AMD EK takes first 16 hex chars of hash */ +#define NULL_TERM_LEN 1 // '\0' + typedef struct tpm_getekcertificate_ctx tpm_getekcertificate_ctx; struct tpm_getekcertificate_ctx { char *ec_cert_path; @@ -46,8 +49,7 @@ static tpm_getekcertificate_ctx ctx = { * @retval unsigned_char* The hash value. * @retval NULL If the computation of the hash fails. */ -static unsigned char *hash_ek_public(TPM2B_PUBLIC *ek_public) { - +static unsigned char *hash_ek_public(TPM2B_PUBLIC *ek_public, UINT32 vendor) { unsigned char *hash = (unsigned char *)malloc(SHA256_DIGEST_LENGTH); if (!hash) { LOG_ERROR("OOM"); @@ -66,53 +68,124 @@ static unsigned char *hash_ek_public(TPM2B_PUBLIC *ek_public) { goto err; } - switch (ek_public->publicArea.type) { - case TPM2_ALG_RSA: - /* Add public key to the hash. */ - is_success = EVP_DigestUpdate(sha256ctx, - ek_public->publicArea.unique.rsa.buffer, - ek_public->publicArea.unique.rsa.size); - if (!is_success) { - LOG_ERROR("EVP_DigestUpdate failed"); - goto err; + if (vendor == VENDOR_AMD) { + switch (ek_public->publicArea.type) { + case TPM2_ALG_RSA: { + /* + * hash = sha256(00 00 22 22 || (uint32_t) exp || modulus) + */ + BYTE buf[4] = { 0x00, 0x00, 0x22, 0x22 }; // Prefix + is_success = EVP_DigestUpdate(sha256ctx, buf, sizeof(buf)); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + + UINT32 exp = ek_public->publicArea.parameters.rsaDetail.exponent; + if (exp == 0) { + exp = 0x00010001; // 0 indicates default + } else { + LOG_WARNING("non-default exponent used"); + } + buf[3] = (BYTE)exp; + buf[2] = (BYTE)(exp>>=8); + buf[1] = (BYTE)(exp>>=8); + buf[0] = (BYTE)(exp>>8); + is_success = EVP_DigestUpdate(sha256ctx, buf, sizeof(buf)); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + + is_success = EVP_DigestUpdate(sha256ctx, + ek_public->publicArea.unique.rsa.buffer, + ek_public->publicArea.unique.rsa.size); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + break; } - - /* Add exponent to the hash. */ - if (ek_public->publicArea.parameters.rsaDetail.exponent != 0) { - LOG_ERROR("non-default exponents unsupported"); - goto err; + case TPM2_ALG_ECC: { + /* + * hash = sha256(00 00 44 44 || (UINT32) exp || modulus) + */ + BYTE buf[4] = { 0x00, 0x00, 0x44, 0x44 }; // Prefix + is_success = EVP_DigestUpdate(sha256ctx, buf, sizeof(buf)); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + is_success = EVP_DigestUpdate(sha256ctx, + ek_public->publicArea.unique.ecc.x.buffer, + ek_public->publicArea.unique.ecc.x.size); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + + is_success = EVP_DigestUpdate(sha256ctx, + ek_public->publicArea.unique.ecc.y.buffer, + ek_public->publicArea.unique.ecc.y.size); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + break; } - /* Exponent 65537 will be added. */ - BYTE buf[3] = { 0x1, 0x00, 0x01 }; - is_success = EVP_DigestUpdate(sha256ctx, buf, sizeof(buf)); - if (!is_success) { - LOG_ERROR("EVP_DigestUpdate failed"); + default: + LOG_ERROR("unsupported EK algorithm"); goto err; } - break; - - case TPM2_ALG_ECC: - is_success = EVP_DigestUpdate(sha256ctx, - ek_public->publicArea.unique.ecc.x.buffer, - ek_public->publicArea.unique.ecc.x.size); - if (!is_success) { - LOG_ERROR("EVP_DigestUpdate failed"); - goto err; - } - - /* Add public key to the hash. */ - is_success = EVP_DigestUpdate(sha256ctx, - ek_public->publicArea.unique.ecc.y.buffer, - ek_public->publicArea.unique.ecc.y.size); - if (!is_success) { - LOG_ERROR("EVP_DigestUpdate failed"); + } else { + switch (ek_public->publicArea.type) { + case TPM2_ALG_RSA: + /* Add public key to the hash. */ + is_success = EVP_DigestUpdate(sha256ctx, + ek_public->publicArea.unique.rsa.buffer, + ek_public->publicArea.unique.rsa.size); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + + /* Add exponent to the hash. */ + if (ek_public->publicArea.parameters.rsaDetail.exponent != 0) { + LOG_ERROR("non-default exponents unsupported"); + goto err; + } + /* Exponent 65537 will be added. */ + BYTE buf[3] = { 0x1, 0x00, 0x01 }; + is_success = EVP_DigestUpdate(sha256ctx, buf, sizeof(buf)); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + break; + + case TPM2_ALG_ECC: + is_success = EVP_DigestUpdate(sha256ctx, + ek_public->publicArea.unique.ecc.x.buffer, + ek_public->publicArea.unique.ecc.x.size); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + + /* Add public key to the hash. */ + is_success = EVP_DigestUpdate(sha256ctx, + ek_public->publicArea.unique.ecc.y.buffer, + ek_public->publicArea.unique.ecc.y.size); + if (!is_success) { + LOG_ERROR("EVP_DigestUpdate failed"); + goto err; + } + break; + + default: + LOG_ERROR("unsupported EK algorithm"); goto err; } - break; - - default: - LOG_ERROR("unsupported EK algorithm"); - goto err; } is_success = EVP_DigestFinal_ex(sha256ctx, hash, NULL); @@ -203,8 +276,8 @@ base64_encode(const unsigned char* buffer) static char * base64_decode(unsigned char* buffer, size_t len, size_t *new_len) { - size_t i, r; - int unescape_len = 0; + size_t i; + int unescape_len = 0, r = 0; char *binary_data = NULL, *unescaped_string = NULL; LOG_INFO("Decoding the base64 encoded cert into binary form"); @@ -263,13 +336,32 @@ base64_decode(unsigned char* buffer, size_t len, size_t *new_len) free(binary_data); binary_data = NULL; } - *new_len = r; + *new_len = (size_t)r; free (unescaped_string); BIO_free_all(bio); return binary_data; } +/** Encode the hash to the path required by the vendor + * + * @param[in] hash The sha256 hash of the public ek. + * @retval The encoded path. + */ +static char *encode_ek_public(unsigned char *hash, UINT32 vendor) { + if (vendor == VENDOR_INTC) { + return base64_encode(hash); + } else { + char *hash_str = malloc(AMD_EK_URI_LEN * 2 + NULL_TERM_LEN); + for (size_t i = 0; i < AMD_EK_URI_LEN; i++) + { + sprintf((char*)(hash_str + (i*2)), "%02x", hash[i]); + } + hash_str[AMD_EK_URI_LEN * 2] = '\0'; + return hash_str; + } +} + /** Get endorsement certificate from the WEB. * * The base64 encoded public endorsement key will be added to the INTEL @@ -280,11 +372,11 @@ base64_decode(unsigned char* buffer, size_t len, size_t *new_len) * @param[out] buffer The json encoded certificate. * @param[out] cert_size The size of the certificate. */ -int retrieve_endorsement_certificate(char *b64h, unsigned char ** buffer, +int retrieve_endorsement_certificate(char *path, unsigned char ** buffer, size_t *cert_size) { int ret = -1; - size_t len = 1 + strlen(b64h) + strlen(ctx.ek_server_addr); + size_t len = 1 + strlen(path) + strlen(ctx.ek_server_addr); char *weblink = (char *) malloc(len); if (!weblink) { @@ -292,7 +384,7 @@ int retrieve_endorsement_certificate(char *b64h, unsigned char ** buffer, return ret; } - snprintf(weblink, len, "%s%s", ctx.ek_server_addr, b64h); + snprintf(weblink, len, "%s%s", ctx.ek_server_addr, path); CURLcode rc = ifapi_get_curl_buffer((unsigned char *)weblink, buffer, cert_size); @@ -319,64 +411,81 @@ int retrieve_endorsement_certificate(char *b64h, unsigned char ** buffer, * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. */ TSS2_RC -ifapi_get_intl_ek_certificate(FAPI_CONTEXT *context, TPM2B_PUBLIC *ek_public, +ifapi_get_web_ek_certificate(FAPI_CONTEXT *context, TPM2B_PUBLIC *ek_public, + UINT32 vendor, unsigned char ** cert_buffer, size_t *cert_size) { int rc = 1; - unsigned char *hash = hash_ek_public(ek_public); char *cert_ptr = NULL; char *cert_start = NULL, *cert_bin = NULL; - char *b64 = base64_encode(hash); + char *path = NULL; + unsigned char *hash = hash_ek_public(ek_public, vendor); + struct json_object *jso_cert, *jso = NULL; + + if (hash == NULL) { + goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, + "Compute EK hash failed.", out); + } + + path = encode_ek_public(hash, vendor); *cert_buffer = NULL; - if (!b64) { - LOG_ERROR("base64_encode returned null"); + if (!path) { + LOG_ERROR("encode ek hash returned null"); goto out; } - if (context->config.intel_cert_service) - ctx.ek_server_addr = context->config.intel_cert_service; - else - ctx.ek_server_addr = "https://ekop.intel.com/ekcertservice/"; + if (context->config.web_cert_service) { + ctx.ek_server_addr = context->config.web_cert_service; + } else { + if (vendor == VENDOR_AMD) { + ctx.ek_server_addr = "https://ftpm.amd.com/pki/aia/"; + } else { + ctx.ek_server_addr = "https://ekop.intel.com/ekcertservice/"; + } + } - LOG_INFO("%s", b64); + LOG_INFO("%s", path); /* Download the JSON encoded certificate. */ - rc = retrieve_endorsement_certificate(b64, cert_buffer, cert_size); - free(b64); + rc = retrieve_endorsement_certificate(path, cert_buffer, cert_size); + free(path); goto_if_error(rc, "Retrieve endorsement certificate", out); cert_ptr = (char *)*cert_buffer; LOGBLOB_DEBUG((uint8_t *)cert_ptr, *cert_size, "%s", "Certificate"); - /* Parse certificate data out of the json structure */ - struct json_object *jso_cert, *jso = ifapi_parse_json(cert_ptr); - if (jso == NULL) - goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, - "Failed to parse EK cert data", out_free_json); - - if (!json_object_object_get_ex(jso, "certificate", &jso_cert)) - goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, - "Could not find cert object", out_free_json); + if (vendor == VENDOR_INTC ) { + /* Parse certificate data out of the json structure */ + jso = ifapi_parse_json(cert_ptr); + if (jso == NULL) + goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, + "Failed to parse EK cert data", out_free_json); + + if (!json_object_object_get_ex(jso, "certificate", &jso_cert)) + goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, + "Could not find cert object", out_free_json); + + if (!json_object_is_type(jso_cert, json_type_string)) + goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, + "Invalid EK cert data", out_free_json); + + cert_start = strdup(json_object_get_string(jso_cert)); + if (!cert_start) { + SAFE_FREE(cert_ptr); + goto_error(rc, TSS2_FAPI_RC_MEMORY, + "Failed to duplicate cert", out_free_json); + } - if (!json_object_is_type(jso_cert, json_type_string)) - goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, - "Invalid EK cert data", out_free_json); + *cert_size = strlen(cert_start); - cert_start = strdup(json_object_get_string(jso_cert)); - if (!cert_start) { + /* Base64 decode buffer into binary PEM format */ + cert_bin = base64_decode((unsigned char *)cert_start, + *cert_size, cert_size); SAFE_FREE(cert_ptr); - goto_error(rc, TSS2_FAPI_RC_MEMORY, - "Failed to duplicate cert", out_free_json); + SAFE_FREE(cert_start); + } else { + cert_bin = cert_ptr; } - - *cert_size = strlen(cert_start); - - /* Base64 decode buffer into binary PEM format */ - cert_bin = base64_decode((unsigned char *)cert_start, - *cert_size, cert_size); - SAFE_FREE(cert_ptr); - SAFE_FREE(cert_start); - - if (cert_bin == NULL) { + if (cert_bin == NULL) { goto_error(rc, TSS2_FAPI_RC_GENERAL_FAILURE, "Invalid EK cert data", out_free_json); } @@ -384,7 +493,8 @@ ifapi_get_intl_ek_certificate(FAPI_CONTEXT *context, TPM2B_PUBLIC *ek_public, *cert_buffer = (unsigned char *)cert_bin; out_free_json: - json_object_put(jso); + if (jso) + json_object_put(jso); out: free(hash); diff --git a/src/tss2-fapi/ifapi_get_intl_cert.h b/src/tss2-fapi/ifapi_get_web_cert.h similarity index 91% rename from src/tss2-fapi/ifapi_get_intl_cert.h rename to src/tss2-fapi/ifapi_get_web_cert.h index 10ee8e5..5a6fc4d 100644 --- a/src/tss2-fapi/ifapi_get_intl_cert.h +++ b/src/tss2-fapi/ifapi_get_web_cert.h @@ -7,9 +7,10 @@ #define IFAPI_GET_INTL_CERT_H TSS2_RC -ifapi_get_intl_ek_certificate( +ifapi_get_web_ek_certificate( FAPI_CONTEXT *context, TPM2B_PUBLIC *ek_public, + UINT32 vendor, unsigned char ** buffer, size_t *cert_size); diff --git a/src/tss2-fapi/ifapi_helpers.c b/src/tss2-fapi/ifapi_helpers.c index af7e48b..bd6e2da 100644 --- a/src/tss2-fapi/ifapi_helpers.c +++ b/src/tss2-fapi/ifapi_helpers.c @@ -1345,7 +1345,7 @@ copy_policy_element(const TPMT_POLICYELEMENT *from_policy, TPMT_POLICYELEMENT *t case POLICYPCR: to_policy->element.PolicyPCR.pcrs = calloc(1, sizeof(TPML_PCRVALUES) + - from_policy->element.PolicyPCR.pcrs->count + sizeof(TPMS_PCRVALUE)); + from_policy->element.PolicyPCR.pcrs->count * sizeof(TPMS_PCRVALUE)); goto_if_null2(to_policy->element.PolicyPCR.pcrs, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, error); to_policy->element.PolicyPCR.pcrs->count @@ -1730,6 +1730,8 @@ ifapi_tpm_to_fapi_signature( * * @param[in] sig_key_object The key object which was used for the quote. * @param[in] tpm_quoted: The attest produced by the quote. + * @param[out] fapi_quote_info Info The representation of the + * attest together with the signing schemed. * @param[out] quoteInfo The character string with the JSON representation of the * attest together with the signing schemed. * @@ -1745,13 +1747,13 @@ TSS2_RC ifapi_compute_quote_info( IFAPI_OBJECT *sig_key_object, TPM2B_ATTEST *tpm_quoted, + FAPI_QUOTE_INFO *fapi_quote_info, char **quoteInfo) { json_object *jso = NULL; TSS2_RC r; size_t offset = 0; TPMS_ATTEST attest_struct; - FAPI_QUOTE_INFO fapi_quote_info; /* The TPM2B_ATTEST contains the marshaled TPMS_ATTEST structure. */ r = Tss2_MU_TPMS_ATTEST_Unmarshal((const uint8_t *) @@ -1759,10 +1761,10 @@ ifapi_compute_quote_info( tpm_quoted->size, &offset, &attest_struct); return_if_error(r, "Unmarshal TPMS_ATTEST."); - fapi_quote_info.attest = attest_struct; + fapi_quote_info->attest = attest_struct; /* The signate scheme will be taken from the key used for qoting. */ - fapi_quote_info.sig_scheme = sig_key_object->misc.key.signing_scheme; - r = ifapi_json_FAPI_QUOTE_INFO_serialize(&fapi_quote_info, &jso); + fapi_quote_info->sig_scheme = sig_key_object->misc.key.signing_scheme; + r = ifapi_json_FAPI_QUOTE_INFO_serialize(fapi_quote_info, &jso); return_if_error(r, "Conversion to TPM2B_ATTEST to JSON."); /* The intermediate structure of type FAPI_QOTE_INFO will be serialized. */ @@ -2016,7 +2018,7 @@ ifapi_extend_vpcr( TSS2_RC r; size_t i, j; size_t event_size, size; - IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext; + IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL; bool zero_digest = false; LOGBLOB_TRACE(&vpcr->buffer[0], vpcr->size, "Old vpcr value"); @@ -2049,7 +2051,20 @@ ifapi_extend_vpcr( } } if (event->digests.count > 0 && i == event->digests.count && !zero_digest) { - LOG_ERROR("No digest for bank %"PRIu16" found in event", bank); + LOG_ERROR("No digest for bank %"PRIu16" found in event." + "\n\nThe bank for each pcr register can be set in the FAPI profile. If, for example," + "\nno digest for the default bank sha256 (11) exists in the eventlog of a" + "\ncertain PCR register the PCR selection has to be adapted. E.g.:" + "\n\n\"pcr_selection\": [" + "\n { \"hash\": \"TPM2_ALG_SHA1\"," + "\n \"pcrSelect\": [ 0, 10 ]," + "\n }," + "\n { \"hash\": \"TPM2_ALG_SHA256\"," + "\n \"pcrSelect\": [ 1, 2, ,3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15," + "16, 17, 18, 19, 20, 21, 22, 23 ]" + "\n }" + "\n]," + , bank); return TSS2_FAPI_RC_BAD_VALUE; } LOGBLOB_TRACE(&vpcr->buffer[0], vpcr->size, "New vpcr value"); @@ -2101,21 +2116,18 @@ ifapi_extend_pcr( return r; } - -/** Check whether a event list corresponds to a certain quote information. +/** Compute pcr values from event list and verify quote digest. * * The event list is used to compute the PCR values corresponding - * to this event list. The PCR digest for these PCRs is computed and compared - * with the attest passed with quote_info. - * + * to this event list. If a quote digest is passed success will + * be returned if the computed pcr digest matches the quote digest. * @param[in] jso_event_list The event list in JSON representation. - * @param[in] quote_info The information structure with the attest. - * @param[out] pcr_digest The computed pcr_digest for the PCRs uses by FAPI. + * @param[in] pcr_selection The definition of the used pcrs. + * @param[out] pcrs The computed pcr list + * @param[out] n_pcrs The number of used pcrs * * @retval TSS2_RC_SUCCESS: If the PCR digest from the event list matches * the PCR digest passed with the quote_info. - * @retval TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED: If the digest computed - * from event list does not match the attest * @retval TSS2_FAPI_RC_BAD_VALUE: If inappropriate values are detected in the * input data. * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. @@ -2123,54 +2135,28 @@ ifapi_extend_pcr( * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. */ TSS2_RC -ifapi_calculate_pcr_digest( +ifapi_calculate_pcrs( json_object *jso_event_list, - const FAPI_QUOTE_INFO *quote_info, - TPM2B_DIGEST *pcr_digest) + const TPML_PCR_SELECTION *pcr_selection, + TPMI_ALG_HASH pcr_digest_hash_alg, + const TPM2B_DIGEST *quote_digest, + IFAPI_PCR_REG *pcrs) { - TSS2_RC r; + TSS2_RC r = TSS2_RC_SUCCESS; IFAPI_CRYPTO_CONTEXT_BLOB *cryptoContext = NULL; - - struct { - TPMI_ALG_HASH bank; - TPM2_HANDLE pcr; - TPM2B_DIGEST value; - } pcrs[TPM2_MAX_PCRS]; - size_t i, pcr, i_evt, hash_size, n_pcrs = 0, n_events = 0; - + size_t i, pcr, i_evt, hash_size, n_events = 0; + size_t n_pcrs = 0; + TPM2B_DIGEST pcr_digest; json_object *jso; IFAPI_EVENT event; - - const TPML_PCR_SELECTION *pcr_selection; - TPMI_ALG_HASH pcr_digest_hash_alg; - - /* Get some data from the quote info for easier access */ - pcr_selection = "e_info->attest.attested.quote.pcrSelect; - pcr_digest->size = quote_info->attest.attested.quote.pcrDigest.size; - - switch (quote_info->sig_scheme.scheme) { - case TPM2_ALG_RSAPSS: - pcr_digest_hash_alg = quote_info->sig_scheme.details.rsapss.hashAlg; - break; - case TPM2_ALG_RSASSA: - pcr_digest_hash_alg = quote_info->sig_scheme.details.rsassa.hashAlg; - break; - case TPM2_ALG_ECDSA: - pcr_digest_hash_alg = quote_info->sig_scheme.details.ecdsa.hashAlg; - break; - case TPM2_ALG_SM2: - pcr_digest_hash_alg = quote_info->sig_scheme.details.sm2.hashAlg; - break; - default: - LOG_ERROR("Unknown sig scheme"); - return TSS2_FAPI_RC_BAD_VALUE; - } + bool found_hcrtm = false; + UINT8 locality = 0; /* Initialize used pcrs */ for (i = 0; i < pcr_selection->count; i++) { for (pcr = 0; pcr < TPM2_MAX_PCRS; pcr++) { uint8_t byte_idx = pcr / 8; - uint8_t flag = 1 << (pcr % 8); + uint8_t flag = ((uint8_t)1) << (pcr % 8); if (flag & pcr_selection->pcrSelections[i].pcrSelect[byte_idx]) { hash_size = ifapi_hash_get_digest_size(pcr_selection->pcrSelections[i].hash); pcrs[n_pcrs].pcr = pcr; @@ -2191,43 +2177,147 @@ ifapi_calculate_pcr_digest( goto_if_error(r, "Error serialize policy", error_cleanup); LOG_TRACE("Deserialized Event for PCR %u", event.pcr); + if (event.content_type == IFAPI_PC_CLIENT && + event.content.firmware_event.event_type == EV_EFI_HCRTM_EVENT && event.pcr == 0) { + found_hcrtm = true; + } + + /* Handle StartupLocality in replay for PCR0 */ + if (event.content_type == IFAPI_PC_CLIENT && + !found_hcrtm && + event.content.firmware_event.event_type == EV_NO_ACTION && event.pcr == 0) { + if (event.content.firmware_event.data.size < sizeof(EV_NO_ACTION_STRUCT)) { + goto_error(r, TSS2_FAPI_RC_BAD_VALUE, "EventSize is too small.", error_cleanup); + } + EV_NO_ACTION_STRUCT *locality_event = (EV_NO_ACTION_STRUCT*)&event.content.firmware_event.data.buffer[0]; + if (memcmp(locality_event->Signature, STARTUP_LOCALITY_SIGNATURE, + sizeof(STARTUP_LOCALITY_SIGNATURE)) == 0) { + locality = locality_event->Cases.StartupLocality; + } + } + for (i = 0; i < n_pcrs; i++) { if (pcrs[i].pcr == event.pcr) { + if (event.content_type == IFAPI_PC_CLIENT && event.pcr == 0) { + if (event.content.firmware_event.event_type == EV_EFI_HCRTM_EVENT) { + /* Trusted Platform Module Library Part 1 section 34.3 */ + pcrs[i].value.buffer[pcrs[i].value.size - 1] = 0x04; + } else if (event.content.firmware_event.event_type == EV_NO_ACTION && + locality > 0) { + pcrs[i].value.buffer[pcrs[i].value.size - 1] = locality; + } + } LOG_DEBUG("Extend PCR %uz", pcrs[i].pcr); r = ifapi_extend_vpcr(&pcrs[i].value, pcrs[i].bank, &event); goto_if_error2(r, "Extending vpcr %"PRIu32, error_cleanup, pcrs[i].pcr); } } ifapi_cleanup_event(&event); - } - } - /* Compute digest for the used pcrs */ - r = ifapi_crypto_hash_start(&cryptoContext, pcr_digest_hash_alg); - return_if_error(r, "crypto hash start"); + /* Compute digest for the used pcrs */ + if (quote_digest) { + r = ifapi_crypto_hash_start(&cryptoContext, pcr_digest_hash_alg); + return_if_error(r, "crypto hash start"); - for (i = 0; i < n_pcrs; i++) { - HASH_UPDATE_BUFFER(cryptoContext, &pcrs[i].value.buffer, pcrs[i].value.size, - r, error_cleanup); - } - r = ifapi_crypto_hash_finish(&cryptoContext, - (uint8_t *) &pcr_digest->buffer[0], - &hash_size); - return_if_error(r, "crypto hash finish"); - pcr_digest->size = hash_size; - - /* Compare the digest from the event list with the digest from the attest */ - if (memcmp(&pcr_digest->buffer[0], "e_info->attest.attested.quote.pcrDigest.buffer[0], - pcr_digest->size) != 0) { - goto_error(r, TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED, - "The digest computed from event list does not match the attest.", - error_cleanup); + for (i = 0; i < n_pcrs; i++) { + HASH_UPDATE_BUFFER(cryptoContext, &pcrs[i].value.buffer, pcrs[i].value.size, + r, error_cleanup); + } + r = ifapi_crypto_hash_finish(&cryptoContext, + (uint8_t *) &pcr_digest.buffer[0], + &hash_size); + return_if_error(r, "crypto hash finish"); + pcr_digest.size = hash_size; + + /* Compare the digest from the event list with the digest from the attest */ + if (memcmp(&pcr_digest.buffer[0], "e_digest->buffer[0], + pcr_digest.size) == 0) { + if (i_evt < (n_events - 1)) { + /* delete the events added after the quote */ + if (json_object_array_del_idx(jso_event_list, i_evt + 1, + n_events - i_evt - 1)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Can't delete remaining eventsize", error_cleanup); + } + } + break; + } else { + ifapi_crypto_hash_abort(&cryptoContext); + } + } + } + if (n_events > 0 && i_evt == n_events && quote_digest) { + /* Quote digest was not found. */ + r = TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED; + } } error_cleanup: if (cryptoContext) ifapi_crypto_hash_abort(&cryptoContext); - ifapi_cleanup_event(&event); + if (n_events > 0) { + ifapi_cleanup_event(&event); + } + return r; +} + +/** Check whether a event list corresponds to a certain quote information. + * + * The event list is used to compute the PCR values corresponding + * to this event list. The PCR digest for these PCRs is computed and compared + * with the attest passed with quote_info. + * + * @param[in] jso_event_list The event list in JSON representation. + * @param[in] quote_info The information structure with the attest. + * @param[out] pcr_digest The computed pcr_digest for the PCRs uses by FAPI. + * + * @retval TSS2_RC_SUCCESS: If the PCR digest from the event list matches + * the PCR digest passed with the quote_info. + * @retval TSS2_FAPI_RC_SIGNATURE_VERIFICATION_FAILED: If the digest computed + * from event list does not match the attest + * @retval TSS2_FAPI_RC_BAD_VALUE: If inappropriate values are detected in the + * input data. + * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred. + * @retval TSS2_FAPI_RC_BAD_REFERENCE a invalid null pointer is passed. + * @retval TSS2_FAPI_RC_MEMORY if not enough memory can be allocated. + */ +TSS2_RC +ifapi_calculate_pcr_digest( + json_object *jso_event_list, + const FAPI_QUOTE_INFO *quote_info) +{ + TSS2_RC r; + IFAPI_PCR_REG pcrs[TPM2_MAX_PCRS]; + + const TPML_PCR_SELECTION *pcr_selection; + TPMI_ALG_HASH pcr_digest_hash_alg; + + /* Get some data from the quote info for easier access */ + pcr_selection = "e_info->attest.attested.quote.pcrSelect; + + switch (quote_info->sig_scheme.scheme) { + case TPM2_ALG_RSAPSS: + pcr_digest_hash_alg = quote_info->sig_scheme.details.rsapss.hashAlg; + break; + case TPM2_ALG_RSASSA: + pcr_digest_hash_alg = quote_info->sig_scheme.details.rsassa.hashAlg; + break; + case TPM2_ALG_ECDSA: + pcr_digest_hash_alg = quote_info->sig_scheme.details.ecdsa.hashAlg; + break; + case TPM2_ALG_SM2: + pcr_digest_hash_alg = quote_info->sig_scheme.details.sm2.hashAlg; + break; + default: + LOG_ERROR("Unknown sig scheme"); + return TSS2_FAPI_RC_BAD_VALUE; + } + + r = ifapi_calculate_pcrs(jso_event_list, pcr_selection, pcr_digest_hash_alg, + "e_info->attest.attested.quote.pcrDigest, + &pcrs[0]); + return_if_error(r, "Compute PCRs"); + return r; } @@ -2303,10 +2393,10 @@ ifapi_filter_pcr_selection_by_index( UINT8 selection[] = { 0, 0, 0, 0 }; for (i = 0; i < pcr_count; i++) { - selection[0] |= (1 << pcr_index[i]) % 256; - selection[1] |= (1 << (pcr_index[i] - 8)) % 256; - selection[2] |= (1 << (pcr_index[i] - 16)) % 256; - selection[3] |= (1 << (pcr_index[i] - 24)) % 256; + selection[0] |= (((UINT32)1) << pcr_index[i]) % 256; + selection[1] |= (((UINT32)1) << (pcr_index[i] - 8)) % 256; + selection[2] |= (((UINT32)1) << (pcr_index[i] - 16)) % 256; + selection[3] |= (((UINT32)1) << (pcr_index[i] - 24)) % 256; }; /* Remove unselected PCRs */ @@ -2404,7 +2494,7 @@ ifapi_compute_policy_digest( if (pcrIndex + 1 > max_pcr) max_pcr = pcrIndex + 1; pcr_selection->pcrSelections[j].pcrSelect[pcrIndex / 8] |= - 1 << pcrIndex % 8; + ((BYTE)1) << pcrIndex % 8; if ((pcrIndex / 8) + 1 > pcr_selection->pcrSelections[j].sizeofSelect) pcr_selection->pcrSelections[j].sizeofSelect = (pcrIndex / 8) + 1; } @@ -2427,7 +2517,7 @@ ifapi_compute_policy_digest( hashAlg); } for (pcr = 0; pcr < max_pcr; pcr++) { - if ((selection.pcrSelect[pcr / 8]) & (1 << (pcr % 8))) { + if ((selection.pcrSelect[pcr / 8]) & (((BYTE)1) << (pcr % 8))) { /* pcr selected */ for (j = 0; j < pcrs->count; j++) { if (pcrs->pcrs[j].pcr == pcr) { @@ -2558,7 +2648,7 @@ TSS2_RC ifapi_pcr_selection_to_pcrvalues( for (i = 0; i < pcr_selection->count; i++) { for (pcr = 0; pcr < TPM2_MAX_PCRS; pcr++) { uint8_t byte_idx = pcr / 8; - uint8_t flag = 1 << (pcr % 8); + uint8_t flag = ((uint8_t)1) << (pcr % 8); /* Check whether PCR is used. */ if (flag & pcr_selection->pcrSelections[i].pcrSelect[byte_idx]) n_pcrs += 1; @@ -2574,7 +2664,7 @@ TSS2_RC ifapi_pcr_selection_to_pcrvalues( for (i = 0; i < pcr_selection->count; i++) { for (pcr = 0; pcr < TPM2_MAX_PCRS; pcr++) { uint8_t byte_idx = pcr / 8; - uint8_t flag = 1 << (pcr % 8); + uint8_t flag = ((uint8_t)1) << (pcr % 8); /* Check whether PCR is used. */ if (flag & pcr_selection->pcrSelections[i].pcrSelect[byte_idx]) { pcr_values->pcrs[i_pcr].pcr = pcr; diff --git a/src/tss2-fapi/ifapi_helpers.h b/src/tss2-fapi/ifapi_helpers.h index e1229ff..ef44829 100644 --- a/src/tss2-fapi/ifapi_helpers.h +++ b/src/tss2-fapi/ifapi_helpers.h @@ -17,6 +17,15 @@ #include "tss2_fapi.h" #include "fapi_int.h" +/** Type for representing a external public key + */ +typedef struct { + TPMI_ALG_HASH bank; + TPM2_HANDLE pcr; + TPM2B_DIGEST value; +} IFAPI_PCR_REG; + + TSS2_RC ifapi_create_dirs(const char *supdir, const char *path); @@ -130,6 +139,7 @@ TSS2_RC ifapi_compute_quote_info( IFAPI_OBJECT *sig_key_object, TPM2B_ATTEST *tpm_quoted, + FAPI_QUOTE_INFO *fapi_quote_info, char **quoteInfo); TSS2_RC @@ -164,10 +174,17 @@ ifapi_filter_pcr_selection_by_index( const TPM2_HANDLE *pcr_index, size_t pcr_count); +TSS2_RC +ifapi_calculate_pcrs( + json_object *jso_event_list, + const TPML_PCR_SELECTION *pcr_selection, + TPMI_ALG_HASH pcr_digest_hash_alg, + const TPM2B_DIGEST *quote_digest, + IFAPI_PCR_REG *pcrs); + TSS2_RC ifapi_calculate_pcr_digest( json_object *jso_event_list, - const FAPI_QUOTE_INFO *quote_info, - TPM2B_DIGEST *pcr_digest); + const FAPI_QUOTE_INFO *quote_info); TSS2_RC ifapi_compute_policy_digest( diff --git a/src/tss2-fapi/ifapi_ima_eventlog.c b/src/tss2-fapi/ifapi_ima_eventlog.c index 59df96b..8dd63ab 100644 --- a/src/tss2-fapi/ifapi_ima_eventlog.c +++ b/src/tss2-fapi/ifapi_ima_eventlog.c @@ -41,12 +41,48 @@ /* Define from kernel crypt.h */ #define CRYPTO_MAX_ALG_NAME 128 +static uint32_t endian_swap_32(uint32_t data) { + uint32_t converted; + uint8_t *bytes = (uint8_t *)&data; + uint8_t *tmp = (uint8_t *)&converted; + size_t i; + for(i=0; i < sizeof(uint32_t); i ++) { + tmp[i] = bytes[sizeof(uint32_t) - i - 1]; + } + return converted; +} + +static bool big_endian_arch(void) { + + uint32_t test_word; + uint8_t *test_byte; + + test_word = 0xFF000000; + test_byte = (uint8_t *) (&test_word); + return test_byte[0] == 0xFF; +} + +static bool little_endian_pcr(uint32_t pcr) { + + uint8_t *test_pcr; + + test_pcr = (uint8_t *) (&pcr); + return test_pcr[0]; +} + +static bool need_to_convert_to_big_endian(IFAPI_IMA_TEMPLATE *template) +{ + return big_endian_arch() && little_endian_pcr(template->header.pcr); +} + static TSS2_RC get_json_content(json_object *jso, json_object **jso_sub) { if (!ifapi_get_sub_object(jso, CONTENT, jso_sub)) { *jso_sub = json_object_new_object(); return_if_null(*jso_sub, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(jso, CONTENT, *jso_sub); + if (json_object_object_add(jso, CONTENT, *jso_sub)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -71,7 +107,9 @@ add_uint8_ary_to_json(UINT8 *buffer, UINT32 size, json_object *jso, const char * SAFE_FREE(hex_string) return_if_null(jso_byte_string, "Out of memory", TSS2_FAPI_RC_MEMORY); - json_object_object_add(jso, jso_tag, jso_byte_string); + if (json_object_object_add(jso, jso_tag, jso_byte_string)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -86,7 +124,9 @@ add_string_to_json(const char *string, json_object *jso, const char *jso_tag) jso_string = json_object_new_string(string); return_if_null(jso_string, "Out of memory", TSS2_FAPI_RC_MEMORY); - json_object_object_add(jso, jso_tag, jso_string); + if (json_object_object_add(jso, jso_tag, jso_string)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -100,7 +140,9 @@ add_number_to_json(UINT32 number, json_object *jso, const char *jso_tag) jso_number = json_object_new_int64(number); return_if_null(jso_number, "Out of memory", TSS2_FAPI_RC_MEMORY); - json_object_object_add(jso, jso_tag, jso_number); + if (json_object_object_add(jso, jso_tag, jso_number)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -138,20 +180,29 @@ set_ff_digest(json_object *jso) { return_if_null(jso_digest, "Out of memory.", TSS2_FAPI_RC_MEMORY); r = add_uint8_ary_to_json(digest_ff,TPM2_SHA1_DIGEST_SIZE, jso_digest, "digest"); - return_if_error(r, "Add digest to json"); + goto_if_error2(r, "Add digest to json", error); jso_digest_type = NULL; jso_digest_type = json_object_new_string ("sha1"); goto_if_null(jso_digest_type, "Out of memory.", TSS2_FAPI_RC_MEMORY, error); - json_object_object_add(jso_digest, "hashAlg", jso_digest_type); + if (json_object_object_add(jso_digest, "hashAlg", jso_digest_type)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object.", + error); + } jso_ary = json_object_new_array(); goto_if_null(jso_ary, "Out of memory.", TSS2_FAPI_RC_MEMORY, error); - json_object_array_add(jso_ary, jso_digest); + if (json_object_array_add(jso_ary, jso_digest)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object.", + error); + } json_object_object_del(jso, "digests"); - json_object_object_add(jso, "digests", jso_ary); + if (json_object_object_add(jso, "digests", jso_ary)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object.", + error); + } return TSS2_RC_SUCCESS; error: @@ -188,10 +239,13 @@ sha_digest_json_cb(UINT8 *digest, UINT8 * buffer, size_t *offset, json_object *j /** Get UINT32 size value from buffer and increase offset. */ UINT32 -get_size_from_buffer(UINT8 *buffer, size_t *offset) { +get_size_from_buffer(UINT8 *buffer, size_t *offset, IFAPI_IMA_TEMPLATE *template) { UINT32 size; memcpy(&size, &buffer[*offset], sizeof(UINT32)); *offset += sizeof(UINT32); + if (template->convert_to_big_endian) { + size = endian_swap_32(size); + } return size; } @@ -207,7 +261,7 @@ digest_with_hash_name_cb(UINT8 *digest, UINT8 *buffer, size_t *offset, json_obje int digest_size; UINT32 digest_buffer_size; - digest_buffer_size = get_size_from_buffer(buffer, offset); + digest_buffer_size = get_size_from_buffer(buffer, offset, template); alg_name_size = strlen((char *)&buffer[*offset]) - 1; /**< strip : */ if (alg_name_size > CRYPTO_MAX_ALG_NAME) { return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid hash name."); @@ -220,9 +274,12 @@ digest_with_hash_name_cb(UINT8 *digest, UINT8 *buffer, size_t *offset, json_obje *offset += alg_name_size + 2; /**< skip : and '\0' */ digest_size = EVP_MD_size(md); if (alg_name_size + 2 + digest_size != digest_buffer_size) { - return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid IMA binary format."); + digest_buffer_size = endian_swap_32(digest_buffer_size); + /* Try with endian swap */ + if (alg_name_size + 2 + digest_size != digest_buffer_size) { + return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid IMA binary format."); + } } - LOGBLOB_TRACE(&buffer[*offset], digest_size, "IMA data_hash"); if (jso && zero_digest(digest, template->hash_size) && @@ -244,7 +301,7 @@ signature_cb(UINT8 *digest, UINT8 *buffer, size_t *offset, json_object *jso, UINT32 digest_size; UNUSED(template); - digest_size = get_size_from_buffer(buffer, offset); + digest_size = get_size_from_buffer(buffer, offset, template); LOGBLOB_TRACE(&buffer[*offset], digest_size, "IMA Signature:"); *offset += digest_size; return TSS2_RC_SUCCESS; @@ -259,13 +316,17 @@ static TSS2_RC eventname_ng_json_cb(UINT8 *digest, UINT8 *buffer, size_t *offset UNUSED(digest); UNUSED(jso); - /* Get size from buffer without 0 Terminator. */ - size_from_buffer = get_size_from_buffer(buffer, offset) - 1; + /* Get size from buffer with 0 Terminator. */ + size_from_buffer = get_size_from_buffer(buffer, offset, template); size = strlen((const char *)&buffer[*offset]); - if (size != size_from_buffer) { - return_error2(TSS2_FAPI_RC_BAD_VALUE, - "Invalid digest size, string length: %zu size from buffer: %" - PRIu32, size, size_from_buffer); + if (size != size_from_buffer - 1) { + size_from_buffer = endian_swap_32(size_from_buffer); + /* Try with endian swap */ + if (size != size_from_buffer - 1) { + return_error2(TSS2_FAPI_RC_BAD_VALUE, + "Invalid digest size, string length: %zu size from buffer: %" + PRIu32, size, size_from_buffer); + } } LOG_TRACE("IMA name: %s", (const char *)&buffer[*offset]); template->name = (char *)&buffer[*offset]; @@ -353,13 +414,19 @@ event_header_json_cb( jso_digest_type = json_object_new_string (hash_name); return_if_null(jso_digest_type, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(jso_digest, "hashAlg", jso_digest_type); + if (json_object_object_add(jso_digest, "hashAlg", jso_digest_type)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_ary = json_object_new_array(); return_if_null(jso_ary, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_array_add(jso_ary, jso_digest); - json_object_object_add(*jso, "digests", jso_ary); + if (json_object_array_add(jso_ary, jso_digest)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(*jso, "digests", jso_ary)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } r = add_uint8_ary_to_json(digest, digest_size, jso_digest, "digest"); return_if_error(r, "Add digest to json"); @@ -373,7 +440,9 @@ event_header_json_cb( r = add_string_to_json(ima_type, jso_content, "template_name"); return_if_error(r, "Add number to json object."); - json_object_array_add(jso_list, *jso); + if (json_object_array_add(jso_list, *jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -500,7 +569,7 @@ convert_ima_event_buffer( r = get_json_content(jso, &jso_content); goto_if_error(r, "Get sub event", error); - r = add_uint8_ary_to_json(template->event_buffer, template->event_size, jso_content, "template_value"); + r = add_uint8_ary_to_json(template->event_buffer, template->event_size, jso_content, "template_data"); goto_if_error(r, "Create data to be hashed", error); } @@ -543,6 +612,9 @@ read_event_buffer(IFAPI_IMA_TEMPLATE *template, FILE *fp) if (rsize != 1) { return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid ima data"); } + if (template->convert_to_big_endian) { + template->event_size = endian_swap_32(template->event_size); + } size = template->event_size; } @@ -560,6 +632,9 @@ read_event_buffer(IFAPI_IMA_TEMPLATE *template, FILE *fp) if (rsize != 1) { return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid ima data"); } + if (template->convert_to_big_endian) { + field_len = endian_swap_32(field_len); + } if (field_len > template->event_size - TPM2_SHA1_DIGEST_SIZE) { return_error(TSS2_FAPI_RC_BAD_VALUE, "Invalid ima data"); } @@ -581,32 +656,47 @@ size_t read_ima_header(IFAPI_IMA_TEMPLATE *template, FILE *fp, TSS2_RC *rc) *rc = TSS2_RC_SUCCESS; - size = fread(&template->header, header_size, 1, fp); + size = fread(&template->header, 1, header_size, fp); if (size == 0) { return size; } + + if (size != header_size) { + *rc = TSS2_FAPI_RC_BAD_VALUE; + LOG_ERROR("Invalid ima data"); + return 0; + } + + template->convert_to_big_endian = need_to_convert_to_big_endian(template); + if (memcmp(&template->header.digest[pos_ima_type], "ima", 3) == 0) { /* Start of IMA type string found. */ memcpy(&template->ima_type_size, &template->header.digest[pos_ima_type - sizeof(UINT32)], sizeof(UINT32)); + if (template->convert_to_big_endian) { + template->ima_type_size = endian_swap_32(template->ima_type_size); + } memcpy(&template->ima_type[0], "ima", 3); /* Get the description of the IMA event. */ + if (template->ima_type_size < 3 || + template->ima_type_size >= TCG_EVENT_NAME_LEN_MAX) { + LOG_ERROR("Invalid ima data"); + *rc = TSS2_FAPI_RC_BAD_VALUE; + return 0; + } size = template->ima_type_size - 3; if (size > 0) { - if (size > TCG_EVENT_NAME_LEN_MAX) { - LOG_ERROR("Invalid ima data"); - *rc = TSS2_FAPI_RC_BAD_VALUE; - return 0; - } rsize = fread(&template->ima_type[3], size, 1, fp); if (rsize != 1) { LOG_ERROR("Invalid ima data"); *rc = TSS2_FAPI_RC_BAD_VALUE; return 0; } + template->ima_type[template->ima_type_size] = '\0'; + } else { + template->ima_type[3] = '\0'; } - template->ima_type[template->ima_type_size] = '\0'; template->hash_alg = TPM2_ALG_SHA1; template->hash_size = TPM2_SHA1_DIGEST_SIZE; return header_size; @@ -633,10 +723,11 @@ ifapi_read_ima_event_log( json_object **jso_list) { TSS2_RC r; FILE *fp = NULL; - IFAPI_IMA_TEMPLATE template; + IFAPI_IMA_TEMPLATE template = { 0 }; size_t recnum = 0, i; json_object *jso_current_event = NULL;; bool add_event; + uint32_t pcr = 0; return_if_null(jso_list, "Bad reference.", TSS2_FAPI_RC_BAD_VALUE); template.event_buffer = NULL; @@ -662,7 +753,11 @@ ifapi_read_ima_event_log( /* Check whether IMA PCR is member of pcrList. */ for (i = 0; i < pcrListSize; i++) { - if (pcrList[i] == template.header.pcr) + pcr = template.header.pcr; + if (template.convert_to_big_endian) { + pcr= endian_swap_32(pcr); + } + if (pcrList[i] == pcr) break; } if (i == pcrListSize) { @@ -671,7 +766,7 @@ ifapi_read_ima_event_log( } if (add_event) { - r = event_callbacks.add_header_cb(recnum, template.header.pcr, + r = event_callbacks.add_header_cb(recnum, pcr, template.ima_type, template.header.digest, template.hash_size, *jso_list, &jso_current_event); @@ -706,6 +801,7 @@ ifapi_read_ima_event_log( static char *field_IFAPI_IMA_EVENT_tab[] = { "template_value", + "template_data", "template_name" }; @@ -784,18 +880,20 @@ ifapi_json_IFAPI_IMA_EVENT_deserialize(json_object *jso, IFAPI_IMA_EVENT *out) SIZE_OF_ARY(field_IFAPI_IMA_EVENT_tab)); if (!ifapi_get_sub_object(jso, "template_name", &jso2)) { - LOG_ERROR("Field \"template_value\" not found."); + LOG_ERROR("Field \"template_name\" not found."); return TSS2_FAPI_RC_BAD_VALUE; } r = ifapi_json_IFAPI_IMA_EVENT_TYPE_deserialize(jso2, &out->template_name); return_if_error(r, "Bad value for field \"template_name\"."); - if (!ifapi_get_sub_object(jso, "template_value", &jso2)) { - LOG_ERROR("Field \"template_value\" not found."); - return TSS2_FAPI_RC_BAD_VALUE; + if (!ifapi_get_sub_object(jso, "template_data", &jso2)) { + if (!ifapi_get_sub_object(jso, "template_value", &jso2)) { + LOG_ERROR("Field \"template_data\" not found."); + return TSS2_FAPI_RC_BAD_VALUE; + } } r = ifapi_json_UINT8_ARY_deserialize(jso2, &out->template_value); - return_if_error(r, "Bad value for field \"template_valuse\"."); + return_if_error(r, "Bad value for field \"template_data \"."); LOG_TRACE("true"); return TSS2_RC_SUCCESS; diff --git a/src/tss2-fapi/ifapi_ima_eventlog.h b/src/tss2-fapi/ifapi_ima_eventlog.h index 6b6c222..4a4c63d 100644 --- a/src/tss2-fapi/ifapi_ima_eventlog.h +++ b/src/tss2-fapi/ifapi_ima_eventlog.h @@ -25,6 +25,11 @@ typedef UINT32 IFAPI_IMA_EVENT_TYPE; /* Structure to store event header and data of IMA template */ typedef struct { + /* Switch whether conversion from little endian to big endian + is needed if on a big endian machine with the option + --ima_canonical_fmt ima is forced to produce a little endian log. */ + bool convert_to_big_endian; + /* header is the First part of the template which will be read beforte the rest of the event will be read and parsed. */ struct { diff --git a/src/tss2-fapi/ifapi_json_deserialize.c b/src/tss2-fapi/ifapi_json_deserialize.c index aa9b275..29defbc 100644 --- a/src/tss2-fapi/ifapi_json_deserialize.c +++ b/src/tss2-fapi/ifapi_json_deserialize.c @@ -952,6 +952,7 @@ get_event_hash( LOG_TRACE("false"); return TSS2_FAPI_RC_BAD_VALUE; }; + error_cleanup: return r; } @@ -1032,6 +1033,7 @@ check_event_digest( return TSS2_RC_SUCCESS; error_cleanup: + ifapi_crypto_hash_abort(&cryptoContext); return r; } @@ -1078,6 +1080,7 @@ ifapi_json_IFAPI_EVENT_deserialize( } else { out->recnum = 0; } + LOG_TRACE("Event num %"PRIu32, out->recnum); if (!ifapi_get_sub_object(jso, "pcr", &jso2)) { LOG_ERROR("Field \"pcr\" not found."); diff --git a/src/tss2-fapi/ifapi_json_eventlog_serialize.c b/src/tss2-fapi/ifapi_json_eventlog_serialize.c index dfa6601..c875568 100644 --- a/src/tss2-fapi/ifapi_json_eventlog_serialize.c +++ b/src/tss2-fapi/ifapi_json_eventlog_serialize.c @@ -56,7 +56,9 @@ add_string_to_json(const char *string, json_object *jso, const char *jso_tag) jso_string = json_object_new_string(string); return_if_null(jso_string, "Out of memory", TSS2_FAPI_RC_MEMORY); - json_object_object_add(jso, jso_tag, jso_string); + if (json_object_object_add(jso, jso_tag, jso_string)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -194,14 +196,18 @@ TSS2_RC ifapi_json_TCG_DIGEST2_serialize(const TCG_DIGEST2 *in, json_object **js r = ifapi_json_TPM2_ALG_ID_serialize(in->AlgorithmId, &jso2); return_if_jso_error(r, "Serialize hash algorithm", jso2); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; size = ifapi_hash_get_digest_size(in->AlgorithmId); r = ifapi_json_BYTE_ARY_serialize(&in->Digest[0], size, &jso2); return_if_jso_error(r, "Serialize UINT8", jso2); - json_object_object_add(*jso, "digest", jso2); + if (json_object_object_add(*jso, "digest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -237,7 +243,9 @@ bool ifapi_json_TCG_DIGEST2_cb(const TCG_DIGEST2 *in, size_t size, void *data) return false; } - json_object_array_add(jso_digests, jso_digest); + if (json_object_array_add(jso_digests, jso_digest)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return true; } @@ -422,7 +430,9 @@ TSS2_RC ifapi_json_TCG_EVENT2_serialize(const TCG_EVENT2 *in, UINT32 event_type, r = ifapi_json_BYTE_ARY_serialize(&in->Event[0], in->EventSize, &jso2); return_if_jso_error(r, "Serialize UINT8", jso2); - json_object_object_add(*jso, "event_data", jso2); + if (json_object_object_add(*jso, "event_data", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -487,7 +497,9 @@ TSS2_RC ifapi_json_TCG_EVENT_HEADER2_serialize( } jso_sub = json_object_new_object(); return_if_null(jso_sub, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, CONTENT, jso_sub); + if (json_object_object_add(*jso, CONTENT, jso_sub)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } r = add_string_to_json("pcclient_std", *jso, CONTENT_TYPE); return_if_error(r, "Add event type"); @@ -495,20 +507,28 @@ TSS2_RC ifapi_json_TCG_EVENT_HEADER2_serialize( r = ifapi_json_UINT32_serialize(in->PCRIndex, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "pcr", jso2); + if (json_object_object_add(*jso, "pcr", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; jso2 = json_object_new_int64(recnum); return_if_null(jso2, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "recnum", jso2); + if (json_object_object_add(*jso, "recnum", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = json_object_new_string(eventtype_to_string(in->EventType)); - json_object_object_add(jso_sub, "event_type", jso2); + if (json_object_object_add(jso_sub, "event_type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_ary = json_object_new_array(); return_if_null(jso_ary, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "digests", jso_ary); + if (json_object_object_add(*jso, "digests", jso_ary)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -542,7 +562,9 @@ bool ifapi_json_TCG_EVENT_HEADER2_cb( cb_data->recnum_tab[in->PCRIndex]++; - json_object_array_add(jso_event_list, jso); + if (json_object_array_add(jso_event_list, jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return true; } @@ -591,19 +613,27 @@ TSS2_RC ifapi_json_TCG_EVENT_serialize(const TCG_EVENT *in, size_t recnum, json_ r = ifapi_json_UINT32_serialize(in->pcrIndex, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "pcr", jso2); + if (json_object_object_add(*jso, "pcr", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = json_object_new_int64(recnum); return_if_null(jso2, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "recnum", jso2); + if (json_object_object_add(*jso, "recnum", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = json_object_new_string(eventtype_to_string(in->eventType)); return_if_null(jso2, "Out of memory.", TSS2_FAPI_RC_MEMORY); jso_sub = json_object_new_object(); return_if_null(jso_sub, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, CONTENT, jso_sub); + if (json_object_object_add(*jso, CONTENT, jso_sub)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } - json_object_object_add(jso_sub, "event_type", jso2); + if (json_object_object_add(jso_sub, "event_type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_digest = json_object_new_object(); return_if_null(*jso, "Out of memory.", TSS2_FAPI_RC_MEMORY); @@ -612,25 +642,35 @@ TSS2_RC ifapi_json_TCG_EVENT_serialize(const TCG_EVENT *in, size_t recnum, json_ r = ifapi_json_TPM2_ALG_ID_serialize(TPM2_ALG_SHA1, &jso2); return_if_error(r, "Serialize hash algorithm"); - json_object_object_add(jso_digest, "hashAlg", jso2); + if (json_object_object_add(jso_digest, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_BYTE_ARY_serialize(&in->digest[0], 20, &jso2); return_if_error(r, "Serialize BYTE"); - json_object_object_add(jso_digest, "digest", jso2); + if (json_object_object_add(jso_digest, "digest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_ary = json_object_new_array(); return_if_null(jso_ary, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_array_add(jso_ary, jso_digest); + if (json_object_array_add(jso_ary, jso_digest)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } - json_object_object_add(*jso, "digests", jso_ary); + if (json_object_object_add(*jso, "digests", jso_ary)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_BYTE_ARY_serialize(&in->event[0], in->eventDataSize, &jso2); return_if_error(r, "Serialize BYTE"); - json_object_object_add(jso_sub, "event_data", jso2); + if (json_object_object_add(jso_sub, "event_data", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -660,7 +700,9 @@ bool ifapi_json_TCG_EVENT_cb(const TCG_EVENT *in, size_t size, void *data) cb_data->recnum_tab[in->pcrIndex]++; - json_object_array_add(jso_event_list, jso); + if (json_object_array_add(jso_event_list, jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return true; } @@ -690,12 +732,16 @@ TSS2_RC ifapi_json_TCG_SPECID_ALG_serialize( r = ifapi_json_TPM2_ALG_ID_serialize(in->algorithmId, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "algorithmId", jso2); + if (json_object_object_add(*jso, "algorithmId", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT16_serialize(in->digestSize, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "digestSize", jso2); + if (json_object_object_add(*jso, "digestSize", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -726,7 +772,9 @@ TSS2_RC ifapi_json_TCG_VENDOR_INFO_serialize(const TCG_VENDOR_INFO *in, json_obj r = ifapi_json_BYTE_ARY_serialize(&in->vendorInfo[0], in->vendorInfoSize, &jso2); return_if_error(r, "Serialize BYTE"); - json_object_object_add(*jso, "vendorInfo", jso2); + if (json_object_object_add(*jso, "vendorInfo", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -819,7 +867,9 @@ bool ifapi_json_TCG_SPECID_EVENT_cb( return false; } - json_object_array_add(jso_event_list, jso); + if (json_object_array_add(jso_event_list, jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return true; } @@ -902,6 +952,7 @@ file_to_buffer(const char *filename, size_t *size, uint8_t **eventlog) *size = 0; *eventlog = calloc(1, alloc_size); if (!*eventlog) { + fclose(fp); return_error2(TSS2_FAPI_RC_IO_ERROR, "Could not read %s", filename); } read_size = fread(*eventlog, 1, alloc_size, fp); @@ -910,19 +961,19 @@ file_to_buffer(const char *filename, size_t *size, uint8_t **eventlog) while (file_size == alloc_buf_size) { n_alloc += 1; - uint8_t* tmp_buff = calloc(1, alloc_size * n_alloc); + uint8_t* tmp_buff = realloc(*eventlog, file_size + alloc_size); if (!tmp_buff) { + fclose(fp); free(*eventlog); return_error2(TSS2_FAPI_RC_IO_ERROR, "Could not read %s", filename); } alloc_buf_size = alloc_size * n_alloc; - memcpy(&tmp_buff[0], eventlog[0], file_size); - free(*eventlog); *eventlog = tmp_buff; - read_size = fread(eventlog[file_size], 1, alloc_size, fp); + read_size = fread(*eventlog + file_size, 1, alloc_size, fp); file_size += read_size; } *size = file_size; + fclose(fp); return TSS2_RC_SUCCESS; } diff --git a/src/tss2-fapi/ifapi_json_serialize.c b/src/tss2-fapi/ifapi_json_serialize.c index f16f6cc..5cd28e5 100644 --- a/src/tss2-fapi/ifapi_json_serialize.c +++ b/src/tss2-fapi/ifapi_json_serialize.c @@ -105,41 +105,55 @@ ifapi_json_IFAPI_KEY_serialize(const IFAPI_KEY *in, json_object **jso) r = ifapi_json_TPMI_YES_NO_serialize(in->with_auth, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "with_auth", jso2); + if (json_object_object_add(*jso, "with_auth", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->persistent_handle, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "persistent_handle", jso2); + if (json_object_object_add(*jso, "persistent_handle", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_PUBLIC_serialize(&in->public, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC"); - json_object_object_add(*jso, "public", jso2); + if (json_object_object_add(*jso, "public", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT8_ARY_serialize(&in->serialization, &jso2); return_if_error(r, "Serialize UINT8_ARY"); - json_object_object_add(*jso, "serialization", jso2); + if (json_object_object_add(*jso, "serialization", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->private.buffer != NULL) { jso2 = NULL; r = ifapi_json_UINT8_ARY_serialize(&in->private, &jso2); return_if_error(r, "Serialize UINT8_ARY"); - json_object_object_add(*jso, "private", jso2); + if (json_object_object_add(*jso, "private", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->appData.buffer != NULL) { jso2 = NULL; r = ifapi_json_UINT8_ARY_serialize(&in->appData, &jso2); return_if_error(r, "Serialize UINT8_ARY"); - json_object_object_add(*jso, "appData", jso2); + if (json_object_object_add(*jso, "appData", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_char_serialize(in->policyInstance, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "policyInstance", jso2); + if (json_object_object_add(*jso, "policyInstance", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } /* Creation Data is not available for imported keys */ if (in->creationData.size) { @@ -147,7 +161,9 @@ ifapi_json_IFAPI_KEY_serialize(const IFAPI_KEY *in, json_object **jso) r = ifapi_json_TPM2B_CREATION_DATA_serialize(&in->creationData, &jso2); return_if_error(r, "Serialize TPM2B_CREATION_DATA"); - json_object_object_add(*jso, "creationData", jso2); + if (json_object_object_add(*jso, "creationData", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Creation Hash is not available for imported keys */ if (in->creationHash.size) { @@ -155,7 +171,9 @@ ifapi_json_IFAPI_KEY_serialize(const IFAPI_KEY *in, json_object **jso) r = ifapi_json_TPM2B_DIGEST_serialize(&in->creationHash, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "creationHash", jso2); + if (json_object_object_add(*jso, "creationHash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Creation Ticket is not available for imported keys */ if (in->creationTicket.tag) { @@ -163,18 +181,24 @@ ifapi_json_IFAPI_KEY_serialize(const IFAPI_KEY *in, json_object **jso) r = ifapi_json_TPMT_TK_CREATION_serialize(&in->creationTicket, &jso2); return_if_error(r, "Serialize TPMT_TK_CREATION"); - json_object_object_add(*jso, "creationTicket", jso2); + if (json_object_object_add(*jso, "creationTicket", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_char_serialize(in->description, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "description", jso2); + if (json_object_object_add(*jso, "description", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->certificate, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "certificate", jso2); + if (json_object_object_add(*jso, "certificate", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->public.publicArea.type != TPM2_ALG_KEYEDHASH) { /* Keyed hash objects to not need a signing scheme. */ @@ -182,38 +206,50 @@ ifapi_json_IFAPI_KEY_serialize(const IFAPI_KEY *in, json_object **jso) r = ifapi_json_TPMT_SIG_SCHEME_serialize(&in->signing_scheme, &jso2); return_if_error(r, "Serialize TPMT_SIG_SCHEME"); - json_object_object_add(*jso, "signing_scheme", jso2); + if (json_object_object_add(*jso, "signing_scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->name, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "name", jso2); + if (json_object_object_add(*jso, "name", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (in->reset_count) { r = ifapi_json_UINT32_serialize(in->reset_count, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "reset_count", jso2); + if (json_object_object_add(*jso, "reset_count", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPMI_YES_NO_serialize(in->delete_prohibited, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "delete_prohibited", jso2); + if (json_object_object_add(*jso, "delete_prohibited", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_YES_NO_serialize(in->ek_profile, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "ek_profile", jso2); + if (json_object_object_add(*jso, "ek_profile", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->nonce.size) { jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->nonce, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "nonce", jso2); + if (json_object_object_add(*jso, "nonce", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } @@ -245,13 +281,17 @@ ifapi_json_IFAPI_EXT_PUB_KEY_serialize(const IFAPI_EXT_PUB_KEY *in, r = ifapi_json_char_serialize(in->pem_ext_public, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "pem_ext_public", jso2); + if (json_object_object_add(*jso, "pem_ext_public", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (in->certificate) { r = ifapi_json_char_serialize(in->certificate, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "certificate", jso2); + if (json_object_object_add(*jso, "certificate", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->public.publicArea.type) { /* Public area was initialized */ @@ -259,7 +299,9 @@ ifapi_json_IFAPI_EXT_PUB_KEY_serialize(const IFAPI_EXT_PUB_KEY *in, r = ifapi_json_TPM2B_PUBLIC_serialize(&in->public, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC"); - json_object_object_add(*jso, "public", jso2); + if (json_object_object_add(*jso, "public", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -287,51 +329,69 @@ ifapi_json_IFAPI_NV_serialize(const IFAPI_NV *in, json_object **jso) r = ifapi_json_TPMI_YES_NO_serialize(in->with_auth, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "with_auth", jso2); + if (json_object_object_add(*jso, "with_auth", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } /* Add tag to classify json NV objects without deserialization */ jso2 = json_object_new_boolean(true); - json_object_object_add(*jso, "nv_object", jso2); + if (json_object_object_add(*jso, "nv_object", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_NV_PUBLIC_serialize(&in->public, &jso2); return_if_error(r, "Serialize TPM2B_NV_PUBLIC"); - json_object_object_add(*jso, "public", jso2); + if (json_object_object_add(*jso, "public", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT8_ARY_serialize(&in->serialization, &jso2); return_if_error(r, "Serialize UINT8_ARY"); - json_object_object_add(*jso, "serialization", jso2); + if (json_object_object_add(*jso, "serialization", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->hierarchy, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "hierarchy", jso2); + if (json_object_object_add(*jso, "hierarchy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->policyInstance, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "policyInstance", jso2); + if (json_object_object_add(*jso, "policyInstance", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->description, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "description", jso2); + if (json_object_object_add(*jso, "description", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->appData.buffer != NULL) { jso2 = NULL; r = ifapi_json_UINT8_ARY_serialize(&in->appData, &jso2); return_if_error(r, "Serialize UINT8_ARY"); - json_object_object_add(*jso, "appData", jso2); + if (json_object_object_add(*jso, "appData", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; if (in->event_log) { r = ifapi_json_char_serialize(in->event_log, &jso2); return_if_error(r, "Serialize event log"); - json_object_object_add(*jso, "event_log", jso2); + if (json_object_object_add(*jso, "event_log", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -359,25 +419,33 @@ ifapi_json_IFAPI_HIERARCHY_serialize(const IFAPI_HIERARCHY *in, json_object **js r = ifapi_json_TPMI_YES_NO_serialize(in->with_auth, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "with_auth", jso2); + if (json_object_object_add(*jso, "with_auth", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->authPolicy, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "authPolicy", jso2); + if (json_object_object_add(*jso, "authPolicy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->description, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "description", jso2); + if (json_object_object_add(*jso, "description", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->esysHandle, &jso2); return_if_error(r, "Serialize esys handle"); - json_object_object_add(*jso, "esysHandle", jso2); + if (json_object_object_add(*jso, "esysHandle", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -406,12 +474,16 @@ ifapi_json_FAPI_QUOTE_INFO_serialize(const FAPI_QUOTE_INFO *in, r = ifapi_json_TPMT_SIG_SCHEME_serialize(&in->sig_scheme, &jso2); return_if_error(r, "Serialize TPMT_SIG_SCHEME"); - json_object_object_add(*jso, "sig_scheme", jso2); + if (json_object_object_add(*jso, "sig_scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMS_ATTEST_serialize(&in->attest, &jso2); return_if_error(r, "Serialize TPMS_ATTEST"); - json_object_object_add(*jso, "attest", jso2); + if (json_object_object_add(*jso, "attest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -440,36 +512,48 @@ ifapi_json_IFAPI_DUPLICATE_serialize(const IFAPI_DUPLICATE *in, r = ifapi_json_TPM2B_PRIVATE_serialize(&in->duplicate, &jso2); return_if_error(r, "Serialize TPM2B_PRIVATE"); - json_object_object_add(*jso, "duplicate", jso2); + if (json_object_object_add(*jso, "duplicate", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_ENCRYPTED_SECRET_serialize(&in->encrypted_seed, &jso2); return_if_error(r, "Serialize TPM2B_ENCRYPTED_SECRET"); - json_object_object_add(*jso, "encrypted_seed", jso2); + if (json_object_object_add(*jso, "encrypted_seed", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (in->certificate) { r = ifapi_json_char_serialize(in->certificate, &jso2); return_if_error(r, "Serialize certificate"); - json_object_object_add(*jso, "certificate", jso2); + if (json_object_object_add(*jso, "certificate", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPM2B_PUBLIC_serialize(&in->public, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC"); - json_object_object_add(*jso, "public", jso2); + if (json_object_object_add(*jso, "public", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_PUBLIC_serialize(&in->public_parent, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC"); - json_object_object_add(*jso, "public_parent", jso2); + if (json_object_object_add(*jso, "public_parent", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->policy) { jso2 = NULL; r = ifapi_json_TPMS_POLICY_serialize(in->policy, &jso2); return_if_error(r, "Serialize policy"); - json_object_object_add(*jso, "policy", jso2); + if (json_object_object_add(*jso, "policy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; @@ -520,12 +604,16 @@ ifapi_json_IFAPI_OBJECT_serialize(const IFAPI_OBJECT *in, r = ifapi_json_IFAPI_OBJECT_TYPE_CONSTANT_serialize(in->objectType, &jso2); return_if_error(r, "Serialize IFAPI_OBJECT"); - json_object_object_add(*jso, "objectType", jso2); + if (json_object_object_add(*jso, "objectType", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_YES_NO_serialize(in->system, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "system", jso2); + if (json_object_object_add(*jso, "system", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } switch (in->objectType) { case IFAPI_HIERARCHY_OBJ: @@ -565,7 +653,9 @@ ifapi_json_IFAPI_OBJECT_serialize(const IFAPI_OBJECT *in, r = ifapi_json_TPMS_POLICY_serialize(in->policy, &jso2); return_if_error(r, "Serialize policy"); - json_object_object_add(*jso, "policy", jso2); + if (json_object_object_add(*jso, "policy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->policy) { @@ -573,7 +663,9 @@ ifapi_json_IFAPI_OBJECT_serialize(const IFAPI_OBJECT *in, r = ifapi_json_TPMS_POLICY_serialize(in->policy, &jso2); return_if_error(r, "Serialize policy"); - json_object_object_add(*jso, "policy", jso2); + if (json_object_object_add(*jso, "policy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -601,13 +693,17 @@ ifapi_json_IFAPI_CAP_INFO_serialize(const IFAPI_CAP_INFO *in, json_object **jso) r = ifapi_json_char_serialize(in->description, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "description", jso2); + if (json_object_object_add(*jso, "description", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMS_CAPABILITY_DATA_serialize(in->capability, &jso2); return_if_error(r, "Serialize TPMS_CAPABILITY_DATA"); - json_object_object_add(*jso, "info", jso2); + if (json_object_object_add(*jso, "info", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -637,12 +733,16 @@ ifapi_json_IFAPI_INFO_serialize(const IFAPI_INFO *in, json_object **jso) r = ifapi_json_char_serialize(in->fapi_version, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "version", jso2); + if (json_object_object_add(*jso, "version", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_IFAPI_CONFIG_serialize(&in->fapi_config, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "fapi_config", jso2); + if (json_object_object_add(*jso, "fapi_config", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_cap_list = json_object_new_array(); for (i = 0; i < IFAPI_MAX_CAP_INFO; i++) { @@ -650,10 +750,14 @@ ifapi_json_IFAPI_INFO_serialize(const IFAPI_INFO *in, json_object **jso) r = ifapi_json_IFAPI_CAP_INFO_serialize(&in->cap[i], &jso2); return_if_error(r, "Serialize TPMS_CAPABILITY_DATA"); - json_object_array_add(jso_cap_list, jso2); + if (json_object_array_add(jso_cap_list, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } - json_object_object_add(*jso, "capabilities", jso_cap_list); + if (json_object_object_add(*jso, "capabilities", jso_cap_list)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -736,7 +840,9 @@ ifapi_json_IFAPI_TSS_EVENT_serialize(const IFAPI_TSS_EVENT *in, r = ifapi_json_TPM2B_EVENT_serialize(&in->data, &jso2); return_if_error(r, "Serialize TPM2B_EVENT"); - json_object_object_add(*jso, "data", jso2); + if (json_object_object_add(*jso, "data", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->event) { /* The in->event field is somewhat special. Its an arbitrary json @@ -746,7 +852,9 @@ ifapi_json_IFAPI_TSS_EVENT_serialize(const IFAPI_TSS_EVENT *in, jso2 = ifapi_parse_json(in->event); return_if_null(jso2, "Event is not valid JSON.", TSS2_FAPI_RC_BAD_VALUE); - json_object_object_add(*jso, "event", jso2); + if (json_object_object_add(*jso, "event", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -775,7 +883,9 @@ ifapi_json_IFAPI_IMA_EVENT_serialize(const IFAPI_IMA_EVENT *in, r = ifapi_json_UINT8_ARY_serialize(&in->template_value, &jso2); return_if_error(r, "Serialize UINT8_ARY"); - json_object_object_add(*jso, "template_value", jso2); + if (json_object_object_add(*jso, "template_data", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -855,11 +965,21 @@ ifapi_json_IFAPI_EVENT_serialize(const IFAPI_EVENT *in, json_object **jso) } } - json_object_object_add(*jso, "recnum", recnum); - json_object_object_add(*jso, "pcr", pcr); - json_object_object_add(*jso, "digests", digests); - json_object_object_add(*jso, CONTENT_TYPE, type); - json_object_object_add(*jso, CONTENT, content); + if (json_object_object_add(*jso, "recnum", recnum)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(*jso, "pcr", pcr)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(*jso, "digests", digests)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(*jso, CONTENT_TYPE, type)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(*jso, CONTENT, content)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; @@ -901,76 +1021,100 @@ ifapi_json_IFAPI_CONFIG_serialize(const IFAPI_CONFIG *in, json_object **jso) r = ifapi_json_char_serialize(in->profile_dir, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "profile_dir", jso2); + if (json_object_object_add(*jso, "profile_dir", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->user_dir, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "user_dir", jso2); + if (json_object_object_add(*jso, "user_dir", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->keystore_dir, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "system_dir", jso2); + if (json_object_object_add(*jso, "system_dir", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->log_dir, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "log_dir", jso2); + if (json_object_object_add(*jso, "log_dir", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->profile_name, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "profile_name", jso2); + if (json_object_object_add(*jso, "profile_name", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->tcti, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "tcti", jso2); + if (json_object_object_add(*jso, "tcti", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPML_PCR_SELECTION_serialize(&in->system_pcrs, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "system_pcrs", jso2); + if (json_object_object_add(*jso, "system_pcrs", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->ek_cert_file, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "ek_cert_file", jso2); + if (json_object_object_add(*jso, "ek_cert_file", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_YES_NO_serialize(in->ek_cert_less, &jso2); return_if_error(r, "Serialize yes no"); - json_object_object_add(*jso, "ek_cert_less", jso2); + if (json_object_object_add(*jso, "ek_cert_less", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->ek_fingerprint.hashAlg) { jso2 = NULL; ifapi_json_TPMT_HA_serialize(&in->ek_fingerprint, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "ek_fingerprint", jso2); + if (json_object_object_add(*jso, "ek_fingerprint", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; - r = ifapi_json_char_serialize(in->intel_cert_service, &jso2); + r = ifapi_json_char_serialize(in->web_cert_service, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "intel_cert_service", jso2); + if (json_object_object_add(*jso, "web_cert_service", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->firmware_log_file) { jso2 = NULL; r = ifapi_json_char_serialize(in->firmware_log_file, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "firmware_log_file", jso2); + if (json_object_object_add(*jso, "firmware_log_file", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->ima_log_file) { @@ -978,7 +1122,9 @@ ifapi_json_IFAPI_CONFIG_serialize(const IFAPI_CONFIG *in, json_object **jso) r = ifapi_json_char_serialize(in->ima_log_file, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "ima_log_file", jso2); + if (json_object_object_add(*jso, "ima_log_file", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; @@ -1006,12 +1152,16 @@ ifapi_json_TPMS_CEL_VERSION_serialize( r = ifapi_json_UINT16_serialize(in->major, &jso2); return_if_error(r, "Serialize major version"); - json_object_object_add(*jso, "major", jso2); + if (json_object_object_add(*jso, "major", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT16_serialize(in->minor, &jso2); return_if_error(r, "Serialize minor version"); - json_object_object_add(*jso, "minor", jso2); + if (json_object_object_add(*jso, "minor", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1040,7 +1190,9 @@ ifapi_json_TPMU_CELMGT_serialize(const TPMU_CELMGT *in, UINT32 selector, json_ob jso2 = NULL; if (ifapi_json_UINT64_serialize(in->cel_timestamp, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "cel_timestamp", jso2); + if (json_object_object_add(*jso, "cel_timestamp", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } break; default: LOG_ERROR("\nSelector %"PRIx32 " did not match", selector); @@ -1098,13 +1250,17 @@ ifapi_json_TPMS_EVENT_CELMGT_serialize(const TPMS_EVENT_CELMGT *in, json_object r = ifapi_json_TPMI_CELMGTTYPE_serialize(in->type, &jso2); return_if_jso_error(r, "Serialize TPMI_CELMGTTYPE", jso2); - json_object_object_add(*jso, "type", jso2); + if (json_object_object_add(*jso, "type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMU_CELMGT_serialize(&in->data, in->type, &jso2); return_if_jso_error(r,"Serialize TPMU_CELMGT", jso2); if (jso2) { - json_object_object_add(*jso, "data", jso2); + if (json_object_object_add(*jso, "data", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } diff --git a/src/tss2-fapi/ifapi_keystore.c b/src/tss2-fapi/ifapi_keystore.c index 8e51e17..8d47b1e 100644 --- a/src/tss2-fapi/ifapi_keystore.c +++ b/src/tss2-fapi/ifapi_keystore.c @@ -6,10 +6,10 @@ #ifdef HAVE_CONFIG_H #include -#include -#include #endif +#include +#include #include "ifapi_io.h" #include "ifapi_helpers.h" #include "ifapi_keystore.h" @@ -1772,6 +1772,14 @@ ifapi_check_provisioned( *ok = false; + /* No profile in path, test can be skipped. */ + if (ifapi_path_type_p(rel_path, IFAPI_NV_PATH) || + ifapi_path_type_p(rel_path, IFAPI_POLICY_PATH) || + ifapi_path_type_p(rel_path, IFAPI_EXT_PATH)) { + *ok = true; + return TSS2_RC_SUCCESS; + } + /* First expand path in user directory */ r = expand_path(keystore, rel_path, &directory); goto_if_error(r, "Expand path", cleanup); diff --git a/src/tss2-fapi/ifapi_policy_calculate.c b/src/tss2-fapi/ifapi_policy_calculate.c index fcf214c..92fc812 100644 --- a/src/tss2-fapi/ifapi_policy_calculate.c +++ b/src/tss2-fapi/ifapi_policy_calculate.c @@ -127,7 +127,7 @@ ifapi_compute_policy_pcr( r = ifapi_crypto_hash_finish(&cryptoContext, (uint8_t *) & current_digest-> digests[digest_idx].digest, &hash_size); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", cleanup); cleanup: if (cryptoContext) @@ -187,7 +187,7 @@ calculate_policy_key_param( r = ifapi_crypto_hash_finish(&cryptoContext, (uint8_t *) digest, &hash_size); LOGBLOB_DEBUG((uint8_t *) digest, hash_size, "Digest Finish"); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", cleanup); /* Use policyRef for second hash computation */ if (policyRef) { @@ -199,7 +199,7 @@ calculate_policy_key_param( policyRef->size, r, cleanup); r = ifapi_crypto_hash_finish(&cryptoContext, (uint8_t *) digest, &hash_size); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", cleanup); } cleanup: @@ -372,7 +372,7 @@ ifapi_calculate_policy_duplicate( r = ifapi_crypto_hash_finish(&cryptoContext, (uint8_t *) & current_digest-> digests[digest_idx].digest, &hash_size); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", cleanup); LOGBLOB_DEBUG((uint8_t *) & current_digest->digests[digest_idx].digest, hash_size, "Policy Duplicate digest"); @@ -871,7 +871,7 @@ ifapi_calculate_policy_name_hash( r = ifapi_calculate_policy_digest_hash(&policy->nameHash, current_digest, current_hash_alg, TPM2_CC_PolicyNameHash); - return_if_error(r, "Calculate digest hash for policy"); + goto_if_error(r, "Calculate digest hash for policy", cleanup); cleanup: if (cryptoContext) @@ -1099,7 +1099,7 @@ ifapi_calculate_policy_nv( r = ifapi_crypto_hash_finish(&cryptoContext, (uint8_t *) ¤t_digest->digests[digest_idx].digest, &hash_size); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", cleanup); cleanup: if (cryptoContext) @@ -1276,7 +1276,7 @@ ifapi_calculate_policy_template( r = ifapi_crypto_hash_finish(&cryptoContext, (uint8_t *) & current_digest-> digests[digest_idx].digest, &hash_size); - return_if_error(r, "crypto hash finish"); + goto_if_error(r, "crypto hash finish", cleanup); LOGBLOB_DEBUG((uint8_t *) & current_digest->digests[digest_idx].digest, hash_size, "Policy Duplicate digest"); diff --git a/src/tss2-fapi/ifapi_policy_callbacks.c b/src/tss2-fapi/ifapi_policy_callbacks.c index 22b915b..8bc6e7f 100644 --- a/src/tss2-fapi/ifapi_policy_callbacks.c +++ b/src/tss2-fapi/ifapi_policy_callbacks.c @@ -361,7 +361,7 @@ TSS2_RC ifapi_read_pcr( for (i = 0; i < profile_selection->count; i++) { for (pcr = 0; pcr < TPM2_MAX_PCRS; pcr++) { uint8_t byte_idx = pcr / 8; - uint8_t flag = 1 << (pcr % 8); + uint8_t flag = ((uint8_t)1) << (pcr % 8); /* Check whether PCR is used. */ if ((flag & profile_selection->pcrSelections[i].pcrSelect[byte_idx]) && (flag & pcr_selection->selections.pcr_select.pcrSelect[byte_idx])) { diff --git a/src/tss2-fapi/ifapi_policy_callbacks.h b/src/tss2-fapi/ifapi_policy_callbacks.h index 357b4e9..3c43077 100644 --- a/src/tss2-fapi/ifapi_policy_callbacks.h +++ b/src/tss2-fapi/ifapi_policy_callbacks.h @@ -32,6 +32,7 @@ typedef struct { ESYS_TR auth_index; /**< Index of authorization object */ ESYS_TR flush_handle; /**< Handle which has to be flushed after policy execution */ IFAPI_OBJECT auth_object; /**< FAPI auth object needed for authorization */ + ESYS_TR *enc_session; /**< FAPI session used for encryption if policy is used */ IFAPI_LoadKey load_ctx_sav; IFAPI_LoadKey load_ctx; IFAPI_CreatePrimary create_primary_ctx_sav; diff --git a/src/tss2-fapi/ifapi_policy_execute.c b/src/tss2-fapi/ifapi_policy_execute.c index 278c82d..b821d15 100644 --- a/src/tss2-fapi/ifapi_policy_execute.c +++ b/src/tss2-fapi/ifapi_policy_execute.c @@ -574,8 +574,10 @@ execute_policy_signed( SAFE_FREE(current_policy->buffer); SAFE_FREE(current_policy->pem_key); /* In error cases object might not have been flushed. */ - if (current_policy->object_handle != ESYS_TR_NONE) + if (current_policy->object_handle != ESYS_TR_NONE) { Esys_FlushContext(esys_ctx, current_policy->object_handle); + current_policy->object_handle = ESYS_TR_NONE; + } return r; } @@ -745,9 +747,10 @@ execute_policy_authorize( } cleanup: /* In error cases object might not have been flushed. */ - if (current_policy->object_handle != ESYS_TR_NONE) + if (current_policy->object_handle != ESYS_TR_NONE) { Esys_FlushContext(esys_ctx, current_policy->object_handle); - + current_policy->object_handle = ESYS_TR_NONE; + } return r; } @@ -955,6 +958,7 @@ execute_policy_secret( statecase(current_policy->state, POLICY_FLUSH_KEY); r = Esys_FlushContext_Finish(esys_ctx); try_again_or_error(r, "Flush key finish."); + current_policy->auth_handle = ESYS_TR_NONE; current_policy->state = POLICY_EXECUTE_INIT; break; @@ -964,8 +968,9 @@ execute_policy_secret( return r; cleanup: - if (current_policy->flush_handle) { + if (current_policy->flush_handle && current_policy->auth_handle != ESYS_TR_NONE) { Esys_FlushContext(esys_ctx, current_policy->auth_handle); + current_policy->auth_handle = ESYS_TR_NONE; } SAFE_FREE(current_policy->nonceTPM); return r; @@ -1301,6 +1306,12 @@ execute_policy_cp_hash( r = Esys_PolicyCpHash_Finish(esys_ctx); try_again_or_error(r, "Execute PolicyCpHash_Finish."); + /* Disable encryption to enable check of cp hash defined in + policy cp. */ + if (current_policy->enc_session) { + *current_policy->enc_session = ESYS_TR_NONE; + } + current_policy->state = POLICY_EXECUTE_INIT; return r; @@ -1899,9 +1910,9 @@ ifapi_policyeval_execute( return_try_again(r); if (r != TSS2_RC_SUCCESS) { - if (do_flush) { + if (do_flush && current_policy->session && + current_policy->session != ESYS_TR_NONE) { Esys_FlushContext(esys_ctx, current_policy->session); - current_policy->session = ESYS_TR_NONE; } ifapi_free_node_list(current_policy->policy_elements); diff --git a/src/tss2-fapi/ifapi_policy_execute.h b/src/tss2-fapi/ifapi_policy_execute.h index 0deef8b..dd960be 100644 --- a/src/tss2-fapi/ifapi_policy_execute.h +++ b/src/tss2-fapi/ifapi_policy_execute.h @@ -74,6 +74,8 @@ struct IFAPI_POLICY_EXEC_CTX { ESYS_TR session; /**< The current policy session */ TPMS_POLICY *policy; ESYS_TR policySessionSav; /**< Backup policy session */ + ESYS_TR *enc_session; /**< ession used for encryption if policy is used */ + ESYS_TR object_handle; ESYS_TR nv_index; ESYS_TR auth_handle; diff --git a/src/tss2-fapi/ifapi_policy_json_deserialize.c b/src/tss2-fapi/ifapi_policy_json_deserialize.c index 9d7ec83..5e5c76e 100644 --- a/src/tss2-fapi/ifapi_policy_json_deserialize.c +++ b/src/tss2-fapi/ifapi_policy_json_deserialize.c @@ -451,7 +451,7 @@ ifapi_json_TPMS_POLICYNV_deserialize(json_object *jso, TPMS_POLICYNV *out) } if (!ifapi_get_sub_object(jso, "nvPublic", &jso2)) { - memset(&out->nvPublic, 0, sizeof(TPM2B_NV_PUBLIC)); + memset(&out->nvPublic, 0, sizeof(TPMS_NV_PUBLIC)); } else { TPM2B_NV_PUBLIC tmp = { 0 }; r = ifapi_json_TPM2B_NV_PUBLIC_deserialize(jso2, &tmp); diff --git a/src/tss2-fapi/ifapi_policy_json_serialize.c b/src/tss2-fapi/ifapi_policy_json_serialize.c index 0500267..a103576 100644 --- a/src/tss2-fapi/ifapi_policy_json_serialize.c +++ b/src/tss2-fapi/ifapi_policy_json_serialize.c @@ -135,14 +135,18 @@ ifapi_json_TPMS_POLICYSIGNED_serialize(const TPMS_POLICYSIGNED *in, r = ifapi_json_TPM2B_DIGEST_serialize(&in->cpHashA, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "cpHashA", jso2); + if (json_object_object_add(*jso, "cpHashA", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->policyRef.size != 0) { jso2 = NULL; r = ifapi_json_TPM2B_NONCE_serialize(&in->policyRef, &jso2); return_if_error(r, "Serialize TPM2B_NONCE"); - json_object_object_add(*jso, "policyRef", jso2); + if (json_object_object_add(*jso, "policyRef", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->keyPath && strlen(in->keyPath) > 0) { jso2 = NULL; @@ -150,7 +154,9 @@ ifapi_json_TPMS_POLICYSIGNED_serialize(const TPMS_POLICYSIGNED *in, r = ifapi_json_char_serialize(in->keyPath, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "keyPath", jso2); + if (json_object_object_add(*jso, "keyPath", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->keyPublic.type != 0) { jso2 = NULL; @@ -158,7 +164,9 @@ ifapi_json_TPMS_POLICYSIGNED_serialize(const TPMS_POLICYSIGNED *in, r = ifapi_json_TPMT_PUBLIC_serialize(&in->keyPublic, &jso2); return_if_error(r, "Serialize TPMT_PUBLIC"); - json_object_object_add(*jso, "keyPublic", jso2); + if (json_object_object_add(*jso, "keyPublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if ((in->keyPEM) && strcmp(in->keyPEM, "") != 0) { jso2 = NULL; @@ -166,28 +174,36 @@ ifapi_json_TPMS_POLICYSIGNED_serialize(const TPMS_POLICYSIGNED *in, r = ifapi_json_char_serialize(in->keyPEM, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "keyPEM", jso2); + if (json_object_object_add(*jso, "keyPEM", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if ((in->publicKeyHint) && strcmp(in->publicKeyHint, "") != 0) { jso2 = NULL; r = ifapi_json_char_serialize(in->publicKeyHint, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "publicKeyHint", jso2); + if (json_object_object_add(*jso, "publicKeyHint", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->publicKey.size) { jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->publicKey, &jso2); return_if_error(r, "Serialize key name"); - json_object_object_add(*jso, "publicKey", jso2); + if (json_object_object_add(*jso, "publicKey", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->keyPEMhashAlg != 0) { jso2 = NULL; r = ifapi_json_TPMI_ALG_HASH_serialize(in->keyPEMhashAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "keyPEMhashAlg", jso2); + if (json_object_object_add(*jso, "keyPEMhashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Check whether only one conditional is used. */ if (cond_cnt != 1) { @@ -198,7 +214,9 @@ ifapi_json_TPMS_POLICYSIGNED_serialize(const TPMS_POLICYSIGNED *in, r = ifapi_json_TPMT_RSA_SCHEME_serialize(&in->rsaScheme, &jso2); return_if_error(r, "Serialize RSA scheme"); - json_object_object_add(*jso, "rsaScheme", jso2); + if (json_object_object_add(*jso, "rsaScheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -228,31 +246,41 @@ ifapi_json_TPMS_POLICYSECRET_serialize(const TPMS_POLICYSECRET *in, r = ifapi_json_TPM2B_NONCE_serialize(&in->nonceTPM, &jso2); return_if_error(r, "Serialize TPM2B_NONCE"); - json_object_object_add(*jso, "nonceTPM", jso2); + if (json_object_object_add(*jso, "nonceTPM", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->cpHashA, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "cpHashA", jso2); + if (json_object_object_add(*jso, "cpHashA", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->policyRef.size != 0) { jso2 = NULL; r = ifapi_json_TPM2B_NONCE_serialize(&in->policyRef, &jso2); return_if_error(r, "Serialize TPM2B_NONCE"); - json_object_object_add(*jso, "policyRef", jso2); + if (json_object_object_add(*jso, "policyRef", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_INT32_serialize(in->expiration, &jso2); return_if_error(r, "Serialize INT32"); - json_object_object_add(*jso, "expiration", jso2); + if (json_object_object_add(*jso, "expiration", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if ((in->objectPath) && strcmp(in->objectPath, "") != 0) { jso2 = NULL; cond_cnt++; r = ifapi_json_char_serialize(in->objectPath, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "objectPath", jso2); + if (json_object_object_add(*jso, "objectPath", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->objectName.size != 0) { jso2 = NULL; @@ -260,7 +288,9 @@ ifapi_json_TPMS_POLICYSECRET_serialize(const TPMS_POLICYSECRET *in, r = ifapi_json_TPM2B_NAME_serialize(&in->objectName, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "objectName", jso2); + if (json_object_object_add(*jso, "objectName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (cond_cnt != 1) { return_error(TSS2_FAPI_RC_BAD_VALUE, @@ -293,7 +323,9 @@ ifapi_json_TPMS_POLICYLOCALITY_serialize(const TPMS_POLICYLOCALITY *in, r = ifapi_json_TPMA_LOCALITY_serialize(in->locality, &jso2); return_if_error(r, "Serialize TPMA_LOCALITY"); - json_object_object_add(*jso, "locality", jso2); + if (json_object_object_add(*jso, "locality", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -323,7 +355,9 @@ ifapi_json_TPMS_POLICYNV_serialize(const TPMS_POLICYNV *in, json_object **jso) r = ifapi_json_char_serialize(in->nvPath, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "nvPath", jso2); + if (json_object_object_add(*jso, "nvPath", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->nvIndex != 0) { jso2 = NULL; @@ -331,7 +365,9 @@ ifapi_json_TPMS_POLICYNV_serialize(const TPMS_POLICYNV *in, json_object **jso) r = ifapi_json_TPMI_RH_NV_INDEX_serialize(in->nvIndex, &jso2); return_if_error(r, "Serialize TPMI_RH_NV_INDEX"); - json_object_object_add(*jso, "nvIndex", jso2); + if (json_object_object_add(*jso, "nvIndex", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->nvPublic.nvIndex) { @@ -341,27 +377,35 @@ ifapi_json_TPMS_POLICYNV_serialize(const TPMS_POLICYNV *in, json_object **jso) r = ifapi_json_TPM2B_NV_PUBLIC_serialize(&tmp, &jso2); return_if_error(r, "Serialize TPM2B_NV_PUBLIC"); - json_object_object_add(*jso, "nvPublic", jso2); + if (json_object_object_add(*jso, "nvPublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPM2B_OPERAND_serialize(&in->operandB, &jso2); return_if_error(r, "Serialize TPM2B_OPERAND"); - json_object_object_add(*jso, "operandB", jso2); + if (json_object_object_add(*jso, "operandB", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->offset != 0) { jso2 = NULL; r = ifapi_json_UINT16_serialize(in->offset, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "offset", jso2); + if (json_object_object_add(*jso, "offset", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->operation != 0) { jso2 = NULL; r = ifapi_json_TPM2_EO_serialize(in->operation, &jso2); return_if_error(r, "Serialize TPM2_EO"); - json_object_object_add(*jso, "operation", jso2); + if (json_object_object_add(*jso, "operation", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Check whether only one conditional is used. */ if (cond_cnt != 1) { @@ -396,19 +440,25 @@ ifapi_json_TPMS_POLICYCOUNTERTIMER_serialize(const TPMS_POLICYCOUNTERTIMER *in, r = ifapi_json_TPM2B_OPERAND_serialize(&in->operandB, &jso2); return_if_error(r, "Serialize TPM2B_OPERAND"); - json_object_object_add(*jso, "operandB", jso2); + if (json_object_object_add(*jso, "operandB", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->offset != 0) { jso2 = NULL; r = ifapi_json_UINT16_serialize(in->offset, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "offset", jso2); + if (json_object_object_add(*jso, "offset", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPM2_EO_serialize(in->operation, &jso2); return_if_error(r, "Serialize TPM2_EO"); - json_object_object_add(*jso, "operation", jso2); + if (json_object_object_add(*jso, "operation", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -436,7 +486,9 @@ ifapi_json_TPMS_POLICYCOMMANDCODE_serialize(const TPMS_POLICYCOMMANDCODE *in, r = ifapi_json_TPM2_CC_serialize(in->code, &jso2); return_if_error(r, "Serialize TPM2_CC"); - json_object_object_add(*jso, "code", jso2); + if (json_object_object_add(*jso, "code", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -484,7 +536,9 @@ ifapi_json_TPMS_POLICYCPHASH_serialize(const TPMS_POLICYCPHASH *in, r = ifapi_json_TPM2B_DIGEST_serialize(&in->cpHash, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "cpHash", jso2); + if (json_object_object_add(*jso, "cpHash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -519,7 +573,9 @@ ifapi_json_TPMS_POLICYNAMEHASH_serialize(const TPMS_POLICYNAMEHASH *in, r = ifapi_json_TPM2B_DIGEST_serialize(&in->nameHash, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "nameHash", jso2); + if (json_object_object_add(*jso, "nameHash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } /* No need to serialize namePaths or objectNames from which would be needed to compute nameHash. */ @@ -537,18 +593,26 @@ ifapi_json_TPMS_POLICYNAMEHASH_serialize(const TPMS_POLICYNAMEHASH *in, r = ifapi_json_char_serialize(in->namePaths[i], &jso2); return_if_error(r, "Serialize char"); - json_object_array_add(jso_ary, jso2); + if (json_object_array_add(jso_ary, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + } + if (json_object_object_add(*jso, "namePaths", jso_ary)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); } - json_object_object_add(*jso, "namePaths", jso_ary); } else { /* TPM object names are used */ for (i = 0; i < in->count; i++) { jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->objectNames[i], &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_array_add(jso_ary, jso2); + if (json_object_array_add(jso_ary, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + } + if (json_object_object_add(*jso, "objectNames", jso_ary)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); } - json_object_object_add(*jso, "objectNames", jso_ary); } /* Check whether only one condition field found in policy. */ if (cond_cnt != 1) { @@ -584,7 +648,9 @@ ifapi_json_TPMS_POLICYDUPLICATIONSELECT_serialize(const r = ifapi_json_TPM2B_NAME_serialize(&in->objectName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "objectName", jso2); + if (json_object_object_add(*jso, "objectName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->newParentName.size) { cond_cnt++; @@ -592,13 +658,17 @@ ifapi_json_TPMS_POLICYDUPLICATIONSELECT_serialize(const r = ifapi_json_TPM2B_NAME_serialize(&in->newParentName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "newParentName", jso2); + if (json_object_object_add(*jso, "newParentName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPMI_YES_NO_serialize(in->includeObject, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "includeObject", jso2); + if (json_object_object_add(*jso, "includeObject", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->newParentPath) { jso2 = NULL; @@ -606,7 +676,9 @@ ifapi_json_TPMS_POLICYDUPLICATIONSELECT_serialize(const r = ifapi_json_char_serialize(in->newParentPath, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "newParentPath", jso2); + if (json_object_object_add(*jso, "newParentPath", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->newParentPublic.type) { @@ -615,7 +687,9 @@ ifapi_json_TPMS_POLICYDUPLICATIONSELECT_serialize(const r = ifapi_json_TPMT_PUBLIC_serialize(&in->newParentPublic, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC"); - json_object_object_add(*jso, "newParentPublic", jso2); + if (json_object_object_add(*jso, "newParentPublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Check whether only one condition field found in policy. */ @@ -652,19 +726,25 @@ ifapi_json_TPMS_POLICYAUTHORIZE_serialize(const TPMS_POLICYAUTHORIZE *in, r = ifapi_json_TPM2B_DIGEST_serialize(&in->approvedPolicy, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "approvedPolicy", jso2); + if (json_object_object_add(*jso, "approvedPolicy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->policyRef.size != 0) { jso2 = NULL; r = ifapi_json_TPM2B_NONCE_serialize(&in->policyRef, &jso2); return_if_error(r, "Serialize TPM2B_NONCE"); - json_object_object_add(*jso, "policyRef", jso2); + if (json_object_object_add(*jso, "policyRef", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->keyName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "keyName", jso2); + if (json_object_object_add(*jso, "keyName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (in->keyPath) { @@ -672,7 +752,9 @@ ifapi_json_TPMS_POLICYAUTHORIZE_serialize(const TPMS_POLICYAUTHORIZE *in, r = ifapi_json_char_serialize(in->keyPath, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "keyPath", jso2); + if (json_object_object_add(*jso, "keyPath", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->keyPublic.type != 0) { jso2 = NULL; @@ -680,28 +762,43 @@ ifapi_json_TPMS_POLICYAUTHORIZE_serialize(const TPMS_POLICYAUTHORIZE *in, r = ifapi_json_TPMT_PUBLIC_serialize(&in->keyPublic, &jso2); return_if_error(r, "Serialize TPMT_PUBLIC"); - json_object_object_add(*jso, "keyPublic", jso2); + if (json_object_object_add(*jso, "keyPublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if ((in->keyPEM) && strcmp(in->keyPEM, "") != 0) { jso2 = NULL; r = ifapi_json_char_serialize(in->keyPEM, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "keyPEM", jso2); + if (json_object_object_add(*jso, "keyPEM", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->keyPEMhashAlg != 0) { jso2 = NULL; r = ifapi_json_TPMI_ALG_HASH_serialize(in->keyPEMhashAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "keyPEMhashAlg", jso2); + if (json_object_object_add(*jso, "keyPEMhashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPMT_RSA_SCHEME_serialize(&in->rsaScheme, &jso2); return_if_error(r, "Serialize RSA scheme"); - json_object_object_add(*jso, "rsaScheme", jso2); + if (json_object_object_add(*jso, "rsaScheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + + /* Check whether only one condition field found in policy. */ + if (cond_cnt > 1) { + return_error(TSS2_FAPI_RC_BAD_VALUE, + "Exactly one conditional is allowed for policy " + "duplication select."); + } return TSS2_RC_SUCCESS; } @@ -770,7 +867,9 @@ ifapi_json_TPMS_POLICYNVWRITTEN_serialize(const TPMS_POLICYNVWRITTEN *in, r = ifapi_json_TPMI_YES_NO_serialize(in->writtenSet, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "writtenSet", jso2); + if (json_object_object_add(*jso, "writtenSet", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -801,7 +900,9 @@ ifapi_json_TPMS_POLICYTEMPLATE_serialize(const TPMS_POLICYTEMPLATE *in, r = ifapi_json_TPM2B_DIGEST_serialize(&in->templateHash, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "templateHash", jso2); + if (json_object_object_add(*jso, "templateHash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->templatePublic.publicArea.type) { jso2 = NULL; @@ -809,7 +910,9 @@ ifapi_json_TPMS_POLICYTEMPLATE_serialize(const TPMS_POLICYTEMPLATE *in, r = ifapi_json_TPMT_PUBLIC_serialize(&in->templatePublic.publicArea, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC"); - json_object_object_add(*jso, "templatePublic", jso2); + if (json_object_object_add(*jso, "templatePublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Check whether only one condition field found in policy. */ @@ -847,7 +950,9 @@ ifapi_json_TPMS_POLICYAUTHORIZENV_serialize(const TPMS_POLICYAUTHORIZENV *in, r = ifapi_json_char_serialize(in->nvPath, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "nvPath", jso2); + if (json_object_object_add(*jso, "nvPath", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; if (in->nvPublic.nvIndex > 0) { @@ -856,7 +961,9 @@ ifapi_json_TPMS_POLICYAUTHORIZENV_serialize(const TPMS_POLICYAUTHORIZENV *in, r = ifapi_json_TPMS_NV_PUBLIC_serialize(&in->nvPublic, &jso2); return_if_error(r, "Serialize TPM2B_NV_PUBLIC"); - json_object_object_add(*jso, "nvPublic", jso2); + if (json_object_object_add(*jso, "nvPublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (cond_cnt != 1) { return_error(TSS2_FAPI_RC_BAD_VALUE, @@ -889,7 +996,9 @@ ifapi_json_TPMS_POLICYACTION_serialize(const TPMS_POLICYACTION *in, r = ifapi_json_char_serialize(in->action, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "action", jso2); + if (json_object_object_add(*jso, "action", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -916,17 +1025,23 @@ ifapi_json_TPMS_PCRVALUE_serialize(const TPMS_PCRVALUE *in, json_object **jso) r = ifapi_json_UINT32_serialize(in->pcr, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "pcr", jso2); + if (json_object_object_add(*jso, "pcr", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2_ALG_ID_serialize(in->hashAlg, &jso2); return_if_error(r, "Serialize TPM2_ALG_ID"); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMU_HA_serialize(&in->digest, in->hashAlg, &jso2); return_if_error(r, "Serialize TPMU_HA"); - json_object_object_add(*jso, "digest", jso2); + if (json_object_object_add(*jso, "digest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -955,7 +1070,9 @@ ifapi_json_TPML_PCRVALUES_serialize(const TPML_PCRVALUES *in, json_object **jso) r = ifapi_json_TPMS_PCRVALUE_serialize(&in->pcrs[i], &jso2); return_if_error(r, "Serialize TPMS_PCRVALUE"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -986,7 +1103,9 @@ ifapi_json_TPMS_POLICYPCR_serialize(const TPMS_POLICYPCR *in, json_object **jso) r = ifapi_json_TPML_PCRVALUES_serialize(in->pcrs, &jso2); return_if_error(r, "Serialize TPML_PCRVALUES"); - json_object_object_add(*jso, "pcrs", jso2); + if (json_object_object_add(*jso, "pcrs", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->currentPCRandBanks.count) { @@ -995,7 +1114,9 @@ ifapi_json_TPMS_POLICYPCR_serialize(const TPMS_POLICYPCR *in, json_object **jso) r = ifapi_json_TPML_PCR_SELECTION_serialize(&in->currentPCRandBanks, &jso2); return_if_error(r, "Serialize TPML_PCR_SELECTION"); - json_object_object_add(*jso, "currentPCRandBanks", jso2); + if (json_object_object_add(*jso, "currentPCRandBanks", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->currentPCRs.sizeofSelect) { @@ -1004,7 +1125,9 @@ ifapi_json_TPMS_POLICYPCR_serialize(const TPMS_POLICYPCR *in, json_object **jso) r = ifapi_json_TPMS_PCR_SELECT_serialize(&in->currentPCRs, &jso2); return_if_error(r, "Serialize TPMS_PCR_SELECT"); - json_object_object_add(*jso, "currentPCRs", jso2); + if (json_object_object_add(*jso, "currentPCRs", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } /* Check whether only one conditional is used. */ if (cond_cnt != 1) { @@ -1039,52 +1162,68 @@ ifapi_json_TPMS_POLICYAUTHORIZATION_serialize( r = ifapi_json_char_serialize(in->type, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "type", jso2); + if (json_object_object_add(*jso, "type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_NONCE_serialize(&in->policyRef, &jso2); return_if_error(r, "Serialize TPM2B_NONCE"); - json_object_object_add(*jso, "policyRef", jso2); + if (json_object_object_add(*jso, "policyRef", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (strcmp(in->type, "tpm") == 0) { jso2 = NULL; r = ifapi_json_TPMT_PUBLIC_serialize(&in->key, &jso2); return_if_error(r, "Serialize TPMT_PUBLIC"); - json_object_object_add(*jso, "key", jso2); + if (json_object_object_add(*jso, "key", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; jso2 = NULL; r = ifapi_json_TPMT_SIGNATURE_serialize(&in->signature, &jso2); return_if_error(r, "Serialize TPMT_SIGNATURE"); - json_object_object_add(*jso, "signature", jso2); + if (json_object_object_add(*jso, "signature", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } else if (strcmp(in->type, "pem") == 0) { jso2 = NULL; r = ifapi_json_char_serialize(in->keyPEM, &jso2); return_if_error(r, "Serialize TPMT_PUBLIC"); - json_object_object_add(*jso, "key", jso2); + if (json_object_object_add(*jso, "key", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; jso2 = NULL; r = ifapi_json_UINT8_ARY_serialize(&in->pemSignature, &jso2); return_if_error(r, "Serialize Signature"); - json_object_object_add(*jso, "signature", jso2); + if (json_object_object_add(*jso, "signature", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMT_RSA_SCHEME_serialize(&in->rsaScheme, &jso2); return_if_error(r, "Serialize RSA scheme"); - json_object_object_add(*jso, "rsaScheme", jso2); + if (json_object_object_add(*jso, "rsaScheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_ALG_HASH_serialize(in->hashAlg, &jso2); return_if_error(r, "Serialize hash alg."); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } else { return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Invalid key type."); } @@ -1121,7 +1260,9 @@ ifapi_json_TPML_POLICYAUTHORIZATIONS_serialize(const TPML_POLICYAUTHORIZATIONS &jso2); return_if_error(r, "Serialize TPMS_POLICYAUTHORIZATION"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1150,23 +1291,31 @@ ifapi_json_TPMS_POLICYBRANCH_serialize(const TPMS_POLICYBRANCH *in, r = ifapi_json_char_serialize(in->name, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "name", jso2); + if (json_object_object_add(*jso, "name", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_char_serialize(in->description, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "description", jso2); + if (json_object_object_add(*jso, "description", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPML_POLICYELEMENTS_serialize(in->policy, &jso2); return_if_error(r, "Serialize TPML_POLICYELEMENTS"); - json_object_object_add(*jso, "policy", jso2); + if (json_object_object_add(*jso, "policy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->policyDigests.count > 0) { jso2 = NULL; r = ifapi_json_TPML_DIGEST_VALUES_serialize(&in->policyDigests, &jso2); return_if_error(r, "Serialize TPML_DIGEST_VALUES"); - json_object_object_add(*jso, "policyDigests", jso2); + if (json_object_object_add(*jso, "policyDigests", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1199,7 +1348,9 @@ ifapi_json_TPML_POLICYBRANCHES_serialize(const TPML_POLICYBRANCHES *in, r = ifapi_json_TPMS_POLICYBRANCH_serialize(&in->authorizations[i], &jso2); return_if_error(r, "Serialize TPMS_POLICYBRANCH"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1227,7 +1378,9 @@ ifapi_json_TPMS_POLICYOR_serialize(const TPMS_POLICYOR *in, json_object **jso) r = ifapi_json_TPML_POLICYBRANCHES_serialize(in->branches, &jso2); return_if_error(r, "Serialize TPML_POLICYBRANCHES"); - json_object_object_add(*jso, "branches", jso2); + if (json_object_object_add(*jso, "branches", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1323,14 +1476,18 @@ ifapi_json_TPMT_POLICYELEMENT_serialize(const TPMT_POLICYELEMENT *in, r = ifapi_json_TPMI_POLICYTYPE_serialize(in->type, &jso2); return_if_error(r, "Serialize TPMI_POLICYTYPE"); - json_object_object_add(*jso, "type", jso2); + if (json_object_object_add(*jso, "type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->policyDigests.count > 0) { jso2 = NULL; r = ifapi_json_TPML_DIGEST_VALUES_serialize(&in->policyDigests, &jso2); return_if_error(r, "Serialize TPML_DIGEST_VALUES"); - json_object_object_add(*jso, "policyDigests", jso2); + if (json_object_object_add(*jso, "policyDigests", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } r = ifapi_json_TPMU_POLICYELEMENT_serialize(&in->element, in->type, jso); return_if_error(r, "Serialize TPMU_POLICYELEMENT"); @@ -1366,7 +1523,9 @@ ifapi_json_TPML_POLICYELEMENTS_serialize(const TPML_POLICYELEMENTS *in, r = ifapi_json_TPMT_POLICYELEMENT_serialize(&in->elements[i], &jso2); return_if_error(r, "Serialize TPMT_POLICYELEMENT"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1395,24 +1554,32 @@ ifapi_json_TPMS_POLICY_serialize(const TPMS_POLICY *in, r = ifapi_json_char_serialize(in->description, &jso2); return_if_error(r, "Serialize char"); - json_object_object_add(*jso, "description", jso2); + if (json_object_object_add(*jso, "description", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPML_DIGEST_VALUES_serialize(&in->policyDigests, &jso2); return_if_error(r, "Serialize TPML_DIGEST_VALUES"); - json_object_object_add(*jso, "policyDigests", jso2); + if (json_object_object_add(*jso, "policyDigests", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->policyAuthorizations) { jso2 = NULL; r = ifapi_json_TPML_POLICYAUTHORIZATIONS_serialize(in->policyAuthorizations, &jso2); return_if_error(r, "Serialize TPML_POLICYAUTHORIZATIONS"); - json_object_object_add(*jso, "policyAuthorizations", jso2); + if (json_object_object_add(*jso, "policyAuthorizations", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso2 = NULL; r = ifapi_json_TPML_POLICYELEMENTS_serialize(in->policy, &jso2); return_if_error(r, "Serialize TPML_POLICYELEMENTS"); - json_object_object_add(*jso, "policy", jso2); + if (json_object_object_add(*jso, "policy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } diff --git a/src/tss2-fapi/ifapi_policyutil_execute.c b/src/tss2-fapi/ifapi_policyutil_execute.c index 7b89ab3..b0925f0 100644 --- a/src/tss2-fapi/ifapi_policyutil_execute.c +++ b/src/tss2-fapi/ifapi_policyutil_execute.c @@ -53,6 +53,9 @@ new_policy( return_error(TSS2_FAPI_RC_MEMORY, "Out of memory"); } (*current_policy)->pol_exec_ctx = pol_exec_ctx; + /* Save address of encryption session to disable encryption if + policy cp hash is executed. */ + pol_exec_ctx->enc_session = &context->session2; pol_exec_ctx->callbacks.cbauth = ifapi_policyeval_cbauth; pol_exec_ctx->callbacks.cbauth_userdata = context; pol_exec_ctx->callbacks.cbload = ifapi_policyeval_cbload_key; @@ -119,8 +122,14 @@ create_session( case WAIT_FOR_CREATE_SESSION: r = Esys_StartAuthSession_Finish(context->esys, session); - if (r != TSS2_RC_SUCCESS) + if (r == TSS2_FAPI_RC_TRY_AGAIN) { return r; + } + if (r != TSS2_RC_SUCCESS) { + context->policy.create_session_state = CREATE_SESSION_INIT; + return r; + } + context->policy.create_session_state = CREATE_SESSION_INIT; break; @@ -280,8 +289,6 @@ ifapi_policyutil_execute(FAPI_CONTEXT *context, ESYS_TR *session) goto_if_error(r, "Create policy session", error); pol_util_ctx->pol_exec_ctx->session = pol_util_ctx->policy_session; - /* Save policy session for cleanup in error case. */ - context->policy_session = pol_util_ctx->policy_session; } else { pol_util_ctx->pol_exec_ctx->session = *session; } @@ -295,6 +302,18 @@ ifapi_policyutil_execute(FAPI_CONTEXT *context, ESYS_TR *session) context->policy.util_current_policy = pol_util_ctx->prev; return TSS2_FAPI_RC_TRY_AGAIN; } + + if (r) { + /* Cleanup stack */ + IFAPI_POLICYUTIL_STACK *utl_ctx = pol_util_ctx->prev; + while (utl_ctx) { + if (utl_ctx->pol_exec_ctx->session == pol_util_ctx->pol_exec_ctx->session) { + utl_ctx->pol_exec_ctx->session = ESYS_TR_NONE; + } + utl_ctx = utl_ctx->prev; + } + pol_util_ctx->pol_exec_ctx->session = ESYS_TR_NONE; + } goto_if_error(r, "Execute policy.", error); break; @@ -302,6 +321,7 @@ ifapi_policyutil_execute(FAPI_CONTEXT *context, ESYS_TR *session) statecasedefault(pol_util_ctx->state); } *session = pol_util_ctx->policy_session; + pol_util_ctx->state = POLICY_UTIL_INIT; pol_util_ctx = pol_util_ctx->prev; @@ -314,6 +334,7 @@ ifapi_policyutil_execute(FAPI_CONTEXT *context, ESYS_TR *session) return r; error: + pol_util_ctx->state = POLICY_UTIL_INIT; pol_util_ctx = pol_util_ctx->prev; if (context->policy.util_current_policy) clear_current_policy(context); diff --git a/src/tss2-fapi/ifapi_profiles.c b/src/tss2-fapi/ifapi_profiles.c index cdf639c..1551337 100644 --- a/src/tss2-fapi/ifapi_profiles.c +++ b/src/tss2-fapi/ifapi_profiles.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "tss2_common.h" @@ -256,12 +257,12 @@ ifapi_profiles_get( } /* Search for path delimiter */ - split = index(name, IFAPI_FILE_DELIM_CHAR); + split = strchr(name, IFAPI_FILE_DELIM_CHAR); /* If the path beging with delimiters, skip over those */ if (name == split) { name += 1; - split = index(name, IFAPI_FILE_DELIM_CHAR); + split = strchr(name, IFAPI_FILE_DELIM_CHAR); } if (split == NULL) len = strlen(name); diff --git a/src/tss2-fapi/tpm_json_deserialize.c b/src/tss2-fapi/tpm_json_deserialize.c index 97833c2..1b27a83 100644 --- a/src/tss2-fapi/tpm_json_deserialize.c +++ b/src/tss2-fapi/tpm_json_deserialize.c @@ -34,9 +34,11 @@ json_object* ifapi_parse_json(const char *jstring) { json_object *jso = NULL; enum json_tokener_error jerr; +#if MAXLOGLEVEL > 0 int line = 1; int line_offset = 0; int char_pos; +#endif struct json_tokener* tok = json_tokener_new(); if (!tok) { LOG_ERROR("Could not allocate json tokener"); @@ -45,6 +47,7 @@ ifapi_parse_json(const char *jstring) { jso = json_tokener_parse_ex(tok, jstring, -1); jerr = json_tokener_get_error(tok); if (jerr != json_tokener_success) { +#if MAXLOGLEVEL > 0 for (char_pos = 0; char_pos <= tok->char_offset; char_pos++) { if (jstring[char_pos] == '\n') { line++; @@ -55,6 +58,7 @@ ifapi_parse_json(const char *jstring) { } LOG_ERROR("Invalid JSON at line %i column %i: %s.", line, line_offset, json_tokener_error_desc(jerr)); +#endif json_tokener_free(tok); return NULL; } @@ -316,7 +320,7 @@ ifapi_json_pcr_selection_deserialize( r = get_number_from_json(json_object_array_get_idx(jso, i), &n); return_if_error(r, "Bad PCR value"); n_byte = n / 8; - pcrSelect[n_byte] |= (BYTE)(1 << (n % 8)); + pcrSelect[n_byte] |= ((BYTE)1) << (n % 8); if (n_byte > *sizeofSelect) *sizeofSelect = n_byte; } @@ -694,6 +698,7 @@ ifapi_json_TPM2_GENERATED_deserialize(json_object *jso, TPM2_GENERATED *out) const char *s = json_object_get_string(jso); const char *str = strip_prefix(s, "TPM_", "TPM2_", "GENERATED_", NULL); LOG_TRACE("called for %s parsing %s", s, str); + TSS2_RC r; if (str) { for (size_t i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) { @@ -703,8 +708,14 @@ ifapi_json_TPM2_GENERATED_deserialize(json_object *jso, TPM2_GENERATED *out) } } } - - return ifapi_json_UINT32_deserialize(jso, out); + r = ifapi_json_UINT32_deserialize(jso, out); + return_if_error(r, "Could not deserialize UINT32"); + if (*out != TPM2_GENERATED_VALUE) { + return_error2(TSS2_FAPI_RC_BAD_VALUE, + "Value %x not equal TPM self generated value %x", + *out, TPM2_GENERATED_VALUE); + } + return TSS2_RC_SUCCESS; } /** Deserialize a TPM2_ALG_ID json object. @@ -3578,7 +3589,7 @@ ifapi_json_TPMI_RSA_KEY_BITS_deserialize(json_object *jso, TPMI_RSA_KEY_BITS *out) { SUBTYPE_FILTER(TPMI_RSA_KEY_BITS, UINT16, - 1024, 2048); + 1024, 2048, 3072, 4096); } /** Deserialize a TPM2B_ECC_PARAMETER json object. diff --git a/src/tss2-fapi/tpm_json_serialize.c b/src/tss2-fapi/tpm_json_serialize.c index a7905c9..8e1e4e4 100644 --- a/src/tss2-fapi/tpm_json_serialize.c +++ b/src/tss2-fapi/tpm_json_serialize.c @@ -68,10 +68,12 @@ ifapi_json_pcr_select_serialize( json_object *jso2; for (i1 = 0; i1 < TPM2_PCR_LAST - TPM2_PCR_FIRST; i1++) { i2 = i1 + TPM2_PCR_FIRST; - if (pcrSelect[i2 / 8] & (BYTE)(1 << (i2 % 8))) { + if (pcrSelect[i2 / 8] & (((BYTE)1) << (i2 % 8))) { jso2 = json_object_new_int(i2); return_if_null(jso2, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } } return TSS2_RC_SUCCESS; @@ -119,12 +121,16 @@ ifapi_json_TPMS_PCR_SELECTION_serialize(const TPMS_PCR_SELECTION *in, r = ifapi_json_TPMI_ALG_HASH_serialize(in->hash, &jso2); return_if_error(r, "Serialize pcr selection"); - json_object_object_add(*jso, "hash", jso2); + if (json_object_object_add(*jso, "hash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_pcr_select_serialize(in->sizeofSelect, &in->pcrSelect[0], &jso2); return_if_error(r, "Serialize pcr selection"); - json_object_object_add(*jso, "pcrSelect", jso2); + if (json_object_object_add(*jso, "pcrSelect", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -147,12 +153,16 @@ ifapi_json_TPMS_TAGGED_PCR_SELECT_serialize(const TPMS_TAGGED_PCR_SELECT *in, r = ifapi_json_TPM2_PT_PCR_serialize(in->tag, &jso2); return_if_error(r, "Serialize pcr selection"); - json_object_object_add(*jso, "tag", jso2); + if (json_object_object_add(*jso, "tag", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_pcr_select_serialize(in->sizeofSelect, &in->pcrSelect[0], &jso2); return_if_error(r, "Serialize pcr selection"); - json_object_object_add(*jso, "pcrSelect", jso2); + if (json_object_object_add(*jso, "pcrSelect", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -174,12 +184,16 @@ ifapi_json_TPMS_TAGGED_POLICY_serialize(const TPMS_TAGGED_POLICY *in, json_objec r = ifapi_json_TPM2_HANDLE_serialize(in->handle, &jso2); return_if_error(r, "Serialize tagged policy"); - json_object_object_add(*jso, "handle", jso2); + if (json_object_object_add(*jso, "handle", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMT_HA_serialize(&in->policyHash, &jso2); return_if_error(r, "Serialize tagged policy"); - json_object_object_add(*jso, "policyHash", jso2); + if (json_object_object_add(*jso, "policyHash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -201,17 +215,23 @@ ifapi_json_TPMS_ACT_DATA_serialize(const TPMS_ACT_DATA *in, json_object **jso) r = ifapi_json_TPM2_HANDLE_serialize(in->handle, &jso2); return_if_error(r, "Serialize act data"); - json_object_object_add(*jso, "handle", jso2); + if (json_object_object_add(*jso, "handle", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->timeout, &jso2); return_if_error(r, "Serialize act data"); - json_object_object_add(*jso, "timeout", jso2); + if (json_object_object_add(*jso, "timeout", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMA_ACT_serialize(in->attributes, &jso2); return_if_error(r, "Serialize act data"); - json_object_object_add(*jso, "attributes", jso2); + if (json_object_object_add(*jso, "attributes", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -307,8 +327,12 @@ ifapi_json_UINT64_serialize(UINT64 in, json_object **jso) if (!*jso) json_object_put(jso2); return_if_null(*jso, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_array_add(*jso, jso1); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso1)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -877,7 +901,9 @@ ifapi_json_TPMA_ALGORITHM_serialize(const TPMA_ALGORITHM in, json_object **jso) jso_bit = json_object_new_int(0); return_if_null(jso_bit, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, tab[i].name, jso_bit); + if (json_object_object_add(*jso, tab[i].name, jso_bit)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -922,7 +948,9 @@ ifapi_json_TPMA_OBJECT_serialize(const TPMA_OBJECT in, json_object **jso) jso_bit = json_object_new_int(0); return_if_null(jso_bit, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, tab[i].name, jso_bit); + if (json_object_object_add(*jso, tab[i].name, jso_bit)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -963,13 +991,17 @@ ifapi_json_TPMA_LOCALITY_serialize(const TPMA_LOCALITY in, json_object **jso) jso_bit = json_object_new_int(0); return_if_null(jso_bit, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, tab[i].name, jso_bit); + if (json_object_object_add(*jso, tab[i].name, jso_bit)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso_bit_idx = json_object_new_int64((TPMA_LOCALITY_EXTENDED_MASK & input) >> 5); return_if_null(jso_bit_idx, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "Extended", jso_bit_idx); + if (json_object_object_add(*jso, "Extended", jso_bit_idx)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1009,22 +1041,30 @@ ifapi_json_TPMA_CC_serialize(const TPMA_CC in, json_object **jso) jso_bit = json_object_new_int(0); return_if_null(jso_bit, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, tab[i].name, jso_bit); + if (json_object_object_add(*jso, tab[i].name, jso_bit)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } jso_bit_idx = json_object_new_int64((TPMA_CC_COMMANDINDEX_MASK & input) >> 0); return_if_null(jso_bit_idx, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "commandIndex", jso_bit_idx); + if (json_object_object_add(*jso, "commandIndex", jso_bit_idx)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_bit_idx = json_object_new_int64((TPMA_CC_CHANDLES_MASK & input) >> 25); return_if_null(jso_bit_idx, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "cHandles", jso_bit_idx); + if (json_object_object_add(*jso, "cHandles", jso_bit_idx)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso_bit_idx = json_object_new_int64((TPMA_CC_RES_MASK & input) >> 30); return_if_null(jso_bit_idx, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, "Res", jso_bit_idx); + if (json_object_object_add(*jso, "Res", jso_bit_idx)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1062,7 +1102,9 @@ ifapi_json_TPMA_ACT_serialize(const TPMA_ACT in, json_object **jso) jso_bit = json_object_new_int(0); return_if_null(jso_bit, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, tab[i].name, jso_bit); + if (json_object_object_add(*jso, tab[i].name, jso_bit)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1315,13 +1357,17 @@ ifapi_json_TPMT_HA_serialize(const TPMT_HA *in, json_object **jso) r = ifapi_json_TPMI_ALG_HASH_serialize(in->hashAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->hashAlg != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_HA_serialize(&in->digest, in->hashAlg, &jso2); return_if_error(r, "Serialize TPMU_HA"); - json_object_object_add(*jso, "digest", jso2); + if (json_object_object_add(*jso, "digest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1532,17 +1578,23 @@ ifapi_json_TPMT_TK_CREATION_serialize(const TPMT_TK_CREATION *in, json_object ** r = ifapi_json_TPM2_ST_serialize(in->tag, &jso2); return_if_error(r, "Serialize TPM2_ST"); - json_object_object_add(*jso, "tag", jso2); + if (json_object_object_add(*jso, "tag", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_RH_HIERARCHY_serialize(in->hierarchy, &jso2); return_if_error(r, "Serialize TPMI_RH_HIERARCHY"); - json_object_object_add(*jso, "hierarchy", jso2); + if (json_object_object_add(*jso, "hierarchy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->digest, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "digest", jso2); + if (json_object_object_add(*jso, "digest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1561,6 +1613,14 @@ ifapi_json_TPMS_ALG_PROPERTY_serialize(const TPMS_ALG_PROPERTY *in, json_object return_if_null(in, "Bad reference.", TSS2_FAPI_RC_BAD_REFERENCE); TSS2_RC r; + + if ((in->alg == TPM2_ALG_SHA3_256 || + in->alg == TPM2_ALG_SHA3_384 || + in->alg == TPM2_ALG_SHA3_512)) { + LOG_WARNING("SHA3 hash algs are not supported by TSS"); + return TSS2_RC_SUCCESS; + } + json_object *jso2; if (*jso == NULL) *jso = json_object_new_object (); @@ -1568,12 +1628,16 @@ ifapi_json_TPMS_ALG_PROPERTY_serialize(const TPMS_ALG_PROPERTY *in, json_object r = ifapi_json_TPM2_ALG_ID_serialize(in->alg, &jso2); return_if_error(r, "Serialize TPM2_ALG_ID"); - json_object_object_add(*jso, "alg", jso2); + if (json_object_object_add(*jso, "alg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMA_ALGORITHM_serialize(in->algProperties, &jso2); return_if_error(r, "Serialize TPMA_ALGORITHM"); - json_object_object_add(*jso, "algProperties", jso2); + if (json_object_object_add(*jso, "algProperties", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1599,12 +1663,16 @@ ifapi_json_TPMS_TAGGED_PROPERTY_serialize(const TPMS_TAGGED_PROPERTY *in, json_o r = ifapi_json_TPM2_PT_serialize(in->property, &jso2); return_if_error(r, "Serialize TPM2_PT"); - json_object_object_add(*jso, "property", jso2); + if (json_object_object_add(*jso, "property", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->value, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "value", jso2); + if (json_object_object_add(*jso, "value", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -1636,7 +1704,9 @@ ifapi_json_TPML_CC_serialize(const TPML_CC *in, json_object **jso) r = ifapi_json_TPM2_CC_serialize (in->commandCodes[i], &jso2); return_if_error(r, "Serialize TPM2_CC"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1669,7 +1739,9 @@ ifapi_json_TPML_CCA_serialize(const TPML_CCA *in, json_object **jso) r = ifapi_json_TPMA_CC_serialize (in->commandAttributes[i], &jso2); return_if_error(r, "Serialize TPMA_CC"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1702,7 +1774,9 @@ ifapi_json_TPML_HANDLE_serialize(const TPML_HANDLE *in, json_object **jso) r = ifapi_json_TPM2_HANDLE_serialize (in->handle[i], &jso2); return_if_error(r, "Serialize TPM2_HANDLE"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1735,7 +1809,9 @@ ifapi_json_TPML_DIGEST_VALUES_serialize(const TPML_DIGEST_VALUES *in, json_objec r = ifapi_json_TPMT_HA_serialize (&in->digests[i], &jso2); return_if_error(r, "Serialize TPMT_HA"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1768,7 +1844,9 @@ ifapi_json_TPML_PCR_SELECTION_serialize(const TPML_PCR_SELECTION *in, json_objec r = ifapi_json_TPMS_PCR_SELECTION_serialize (&in->pcrSelections[i], &jso2); return_if_error(r, "Serialize TPMS_PCR_SELECTION"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1801,7 +1879,9 @@ ifapi_json_TPML_ALG_PROPERTY_serialize(const TPML_ALG_PROPERTY *in, json_object r = ifapi_json_TPMS_ALG_PROPERTY_serialize (&in->algProperties[i], &jso2); return_if_error(r, "Serialize TPMS_ALG_PROPERTY"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1834,7 +1914,9 @@ ifapi_json_TPML_TAGGED_TPM_PROPERTY_serialize(const TPML_TAGGED_TPM_PROPERTY *in r = ifapi_json_TPMS_TAGGED_PROPERTY_serialize (&in->tpmProperty[i], &jso2); return_if_error(r, "Serialize TPMS_TAGGED_PROPERTY"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1867,7 +1949,9 @@ ifapi_json_TPML_TAGGED_PCR_PROPERTY_serialize(const TPML_TAGGED_PCR_PROPERTY *in r = ifapi_json_TPMS_TAGGED_PCR_SELECT_serialize (&in->pcrProperty[i], &jso2); return_if_error(r, "Serialize TPMS_TAGGED_PCR_SELECT"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1900,7 +1984,9 @@ ifapi_json_TPML_ECC_CURVE_serialize(const TPML_ECC_CURVE *in, json_object **jso) r = ifapi_json_TPM2_ECC_CURVE_serialize (in->eccCurves[i], &jso2); return_if_error(r, "Serialize TPM2_ECC_CURVE"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1933,7 +2019,9 @@ ifapi_json_TPML_TAGGED_POLICY_serialize(const TPML_TAGGED_POLICY *in, json_objec r = ifapi_json_TPMS_TAGGED_POLICY_serialize (&in->policies[i], &jso2); return_if_error(r, "Serialize TPMS_TAGGED_POLICY"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -1966,7 +2054,9 @@ ifapi_json_TPML_ACT_DATA_serialize(const TPML_ACT_DATA *in, json_object **jso) r = ifapi_json_TPMS_ACT_DATA_serialize(&in->actData[i], &jso2); return_if_error(r, "Serialize TPMS_ACT_DATA"); - json_object_array_add(*jso, jso2); + if (json_object_array_add(*jso, jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -2037,12 +2127,16 @@ ifapi_json_TPMS_CAPABILITY_DATA_serialize(const TPMS_CAPABILITY_DATA *in, json_o r = ifapi_json_TPM2_CAP_serialize(in->capability, &jso2); return_if_error(r, "Serialize TPM2_CAP"); - json_object_object_add(*jso, "capability", jso2); + if (json_object_object_add(*jso, "capability", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMU_CAPABILITIES_serialize(&in->data, in->capability, &jso2); return_if_error(r,"Serialize TPMU_CAPABILITIES"); - json_object_object_add(*jso, "data", jso2); + if (json_object_object_add(*jso, "data", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2068,22 +2162,30 @@ ifapi_json_TPMS_CLOCK_INFO_serialize(const TPMS_CLOCK_INFO *in, json_object **js r = ifapi_json_UINT64_serialize(in->clock, &jso2); return_if_error(r, "Serialize UINT64"); - json_object_object_add(*jso, "clock", jso2); + if (json_object_object_add(*jso, "clock", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->resetCount, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "resetCount", jso2); + if (json_object_object_add(*jso, "resetCount", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->restartCount, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "restartCount", jso2); + if (json_object_object_add(*jso, "restartCount", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_YES_NO_serialize(in->safe, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "safe", jso2); + if (json_object_object_add(*jso, "safe", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2109,12 +2211,16 @@ ifapi_json_TPMS_TIME_INFO_serialize(const TPMS_TIME_INFO *in, json_object **jso) r = ifapi_json_UINT64_serialize(in->time, &jso2); return_if_error(r, "Serialize UINT64"); - json_object_object_add(*jso, "time", jso2); + if (json_object_object_add(*jso, "time", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMS_CLOCK_INFO_serialize(&in->clockInfo, &jso2); return_if_error(r, "Serialize TPMS_CLOCK_INFO"); - json_object_object_add(*jso, "clockInfo", jso2); + if (json_object_object_add(*jso, "clockInfo", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2140,12 +2246,16 @@ ifapi_json_TPMS_TIME_ATTEST_INFO_serialize(const TPMS_TIME_ATTEST_INFO *in, json r = ifapi_json_TPMS_TIME_INFO_serialize(&in->time, &jso2); return_if_error(r, "Serialize TPMS_TIME_INFO"); - json_object_object_add(*jso, "time", jso2); + if (json_object_object_add(*jso, "time", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT64_serialize(in->firmwareVersion, &jso2); return_if_error(r, "Serialize UINT64"); - json_object_object_add(*jso, "firmwareVersion", jso2); + if (json_object_object_add(*jso, "firmwareVersion", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2171,12 +2281,16 @@ ifapi_json_TPMS_CERTIFY_INFO_serialize(const TPMS_CERTIFY_INFO *in, json_object r = ifapi_json_TPM2B_NAME_serialize(&in->name, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "name", jso2); + if (json_object_object_add(*jso, "name", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->qualifiedName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "qualifiedName", jso2); + if (json_object_object_add(*jso, "qualifiedName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2202,12 +2316,16 @@ ifapi_json_TPMS_QUOTE_INFO_serialize(const TPMS_QUOTE_INFO *in, json_object **js r = ifapi_json_TPML_PCR_SELECTION_serialize(&in->pcrSelect, &jso2); return_if_error(r, "Serialize TPML_PCR_SELECTION"); - json_object_object_add(*jso, "pcrSelect", jso2); + if (json_object_object_add(*jso, "pcrSelect", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->pcrDigest, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "pcrDigest", jso2); + if (json_object_object_add(*jso, "pcrDigest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2233,22 +2351,30 @@ ifapi_json_TPMS_COMMAND_AUDIT_INFO_serialize(const TPMS_COMMAND_AUDIT_INFO *in, r = ifapi_json_UINT64_serialize(in->auditCounter, &jso2); return_if_error(r, "Serialize UINT64"); - json_object_object_add(*jso, "auditCounter", jso2); + if (json_object_object_add(*jso, "auditCounter", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2_ALG_ID_serialize(in->digestAlg, &jso2); return_if_error(r, "Serialize TPM2_ALG_ID"); - json_object_object_add(*jso, "digestAlg", jso2); + if (json_object_object_add(*jso, "digestAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->auditDigest, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "auditDigest", jso2); + if (json_object_object_add(*jso, "auditDigest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->commandDigest, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "commandDigest", jso2); + if (json_object_object_add(*jso, "commandDigest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2274,12 +2400,16 @@ ifapi_json_TPMS_SESSION_AUDIT_INFO_serialize(const TPMS_SESSION_AUDIT_INFO *in, r = ifapi_json_TPMI_YES_NO_serialize(in->exclusiveSession, &jso2); return_if_error(r, "Serialize TPMI_YES_NO"); - json_object_object_add(*jso, "exclusiveSession", jso2); + if (json_object_object_add(*jso, "exclusiveSession", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->sessionDigest, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "sessionDigest", jso2); + if (json_object_object_add(*jso, "sessionDigest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2305,12 +2435,16 @@ ifapi_json_TPMS_CREATION_INFO_serialize(const TPMS_CREATION_INFO *in, json_objec r = ifapi_json_TPM2B_NAME_serialize(&in->objectName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "objectName", jso2); + if (json_object_object_add(*jso, "objectName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->creationHash, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "creationHash", jso2); + if (json_object_object_add(*jso, "creationHash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2336,17 +2470,23 @@ ifapi_json_TPMS_NV_CERTIFY_INFO_serialize(const TPMS_NV_CERTIFY_INFO *in, json_o r = ifapi_json_TPM2B_NAME_serialize(&in->indexName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "indexName", jso2); + if (json_object_object_add(*jso, "indexName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT16_serialize(in->offset, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "offset", jso2); + if (json_object_object_add(*jso, "offset", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_MAX_NV_BUFFER_serialize(&in->nvContents, &jso2); return_if_error(r, "Serialize TPM2B_MAX_NV_BUFFER"); - json_object_object_add(*jso, "nvContents", jso2); + if (json_object_object_add(*jso, "nvContents", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2425,37 +2565,51 @@ ifapi_json_TPMS_ATTEST_serialize(const TPMS_ATTEST *in, json_object **jso) r = ifapi_json_TPM2_GENERATED_serialize(in->magic, &jso2); return_if_error(r, "Serialize TPM2_GENERATED"); - json_object_object_add(*jso, "magic", jso2); + if (json_object_object_add(*jso, "magic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_ST_ATTEST_serialize(in->type, &jso2); return_if_error(r, "Serialize TPMI_ST_ATTEST"); - json_object_object_add(*jso, "type", jso2); + if (json_object_object_add(*jso, "type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->qualifiedSigner, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "qualifiedSigner", jso2); + if (json_object_object_add(*jso, "qualifiedSigner", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DATA_serialize(&in->extraData, &jso2); return_if_error(r, "Serialize TPM2B_DATA"); - json_object_object_add(*jso, "extraData", jso2); + if (json_object_object_add(*jso, "extraData", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMS_CLOCK_INFO_serialize(&in->clockInfo, &jso2); return_if_error(r, "Serialize TPMS_CLOCK_INFO"); - json_object_object_add(*jso, "clockInfo", jso2); + if (json_object_object_add(*jso, "clockInfo", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT64_serialize(in->firmwareVersion, &jso2); return_if_error(r, "Serialize UINT64"); - json_object_object_add(*jso, "firmwareVersion", jso2); + if (json_object_object_add(*jso, "firmwareVersion", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMU_ATTEST_serialize(&in->attested, in->type, &jso2); return_if_error(r,"Serialize TPMU_ATTEST"); - json_object_object_add(*jso, "attested", jso2); + if (json_object_object_add(*jso, "attested", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2586,20 +2740,26 @@ ifapi_json_TPMT_SYM_DEF_OBJECT_serialize(const TPMT_SYM_DEF_OBJECT *in, json_obj r = ifapi_json_TPMI_ALG_SYM_OBJECT_serialize(in->algorithm, &jso2); return_if_error(r, "Serialize TPMI_ALG_SYM_OBJECT"); - json_object_object_add(*jso, "algorithm", jso2); + if (json_object_object_add(*jso, "algorithm", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->algorithm != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_SYM_KEY_BITS_serialize(&in->keyBits, in->algorithm, &jso2); return_if_error(r,"Serialize TPMU_SYM_KEY_BITS"); - json_object_object_add(*jso, "keyBits", jso2); + if (json_object_object_add(*jso, "keyBits", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } if (in->algorithm != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_SYM_MODE_serialize(&in->mode, in->algorithm, &jso2); return_if_error(r,"Serialize TPMU_SYM_MODE"); - json_object_object_add(*jso, "mode", jso2); + if (json_object_object_add(*jso, "mode", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -2626,7 +2786,9 @@ ifapi_json_TPMS_SYMCIPHER_PARMS_serialize(const TPMS_SYMCIPHER_PARMS *in, json_o r = ifapi_json_TPMT_SYM_DEF_OBJECT_serialize(&in->sym, &jso2); return_if_error(r, "Serialize TPMT_SYM_DEF_OBJECT"); - json_object_object_add(*jso, "sym", jso2); + if (json_object_object_add(*jso, "sym", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2652,7 +2814,9 @@ ifapi_json_TPMS_SCHEME_HASH_serialize(const TPMS_SCHEME_HASH *in, json_object ** r = ifapi_json_TPMI_ALG_HASH_serialize(in->hashAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2678,12 +2842,16 @@ ifapi_json_TPMS_SCHEME_ECDAA_serialize(const TPMS_SCHEME_ECDAA *in, json_object r = ifapi_json_TPMI_ALG_HASH_serialize(in->hashAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT16_serialize(in->count, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "count", jso2); + if (json_object_object_add(*jso, "count", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2739,12 +2907,16 @@ ifapi_json_TPMS_SCHEME_XOR_serialize(const TPMS_SCHEME_XOR *in, json_object **js r = ifapi_json_TPMI_ALG_HASH_serialize(in->hashAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "hashAlg", jso2); + if (json_object_object_add(*jso, "hashAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_ALG_KDF_serialize(in->kdf, &jso2); return_if_error(r, "Serialize TPMI_ALG_KDF"); - json_object_object_add(*jso, "kdf", jso2); + if (json_object_object_add(*jso, "kdf", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -2796,13 +2968,17 @@ ifapi_json_TPMT_KEYEDHASH_SCHEME_serialize(const TPMT_KEYEDHASH_SCHEME *in, json r = ifapi_json_TPMI_ALG_KEYEDHASH_SCHEME_serialize(in->scheme, &jso2); return_if_error(r, "Serialize TPMI_ALG_KEYEDHASH_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->scheme != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_SCHEME_KEYEDHASH_serialize(&in->details, in->scheme, &jso2); return_if_error(r,"Serialize TPMU_SCHEME_KEYEDHASH"); - json_object_object_add(*jso, "details", jso2); + if (json_object_object_add(*jso, "details", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -2955,13 +3131,17 @@ ifapi_json_TPMT_SIG_SCHEME_serialize(const TPMT_SIG_SCHEME *in, json_object **js r = ifapi_json_TPMI_ALG_SIG_SCHEME_serialize(in->scheme, &jso2); return_if_error(r, "Serialize TPMI_ALG_SIG_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->scheme != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_SIG_SCHEME_serialize(&in->details, in->scheme, &jso2); return_if_error(r,"Serialize TPMU_SIG_SCHEME"); - json_object_object_add(*jso, "details", jso2); + if (json_object_object_add(*jso, "details", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -3105,13 +3285,17 @@ ifapi_json_TPMT_KDF_SCHEME_serialize(const TPMT_KDF_SCHEME *in, json_object **js r = ifapi_json_TPMI_ALG_KDF_serialize(in->scheme, &jso2); return_if_error(r, "Serialize TPMI_ALG_KDF"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->scheme != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_KDF_SCHEME_serialize(&in->details, in->scheme, &jso2); return_if_error(r,"Serialize TPMU_KDF_SCHEME"); - json_object_object_add(*jso, "details", jso2); + if (json_object_object_add(*jso, "details", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -3211,13 +3395,17 @@ ifapi_json_TPMT_RSA_SCHEME_serialize(const TPMT_RSA_SCHEME *in, json_object **js r = ifapi_json_TPMI_ALG_RSA_SCHEME_serialize(in->scheme, &jso2); return_if_error(r, "Serialize TPMI_ALG_RSA_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->scheme != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_ASYM_SCHEME_serialize(&in->details, in->scheme, &jso2); return_if_error(r,"Serialize TPMU_ASYM_SCHEME"); - json_object_object_add(*jso, "details", jso2); + if (json_object_object_add(*jso, "details", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -3264,7 +3452,7 @@ ifapi_json_TPM2B_PUBLIC_KEY_RSA_serialize(const TPM2B_PUBLIC_KEY_RSA *in, json_o TSS2_RC ifapi_json_TPMI_RSA_KEY_BITS_serialize(const TPMI_RSA_KEY_BITS in, json_object **jso) { - CHECK_IN_LIST(TPMI_RSA_KEY_BITS, in, 1024, 2048); + CHECK_IN_LIST(TPMI_RSA_KEY_BITS, in, 1024, 2048, 3072, 4096); return ifapi_json_UINT16_serialize(in, jso); } @@ -3320,12 +3508,16 @@ ifapi_json_TPMS_ECC_POINT_serialize(const TPMS_ECC_POINT *in, json_object **jso) r = ifapi_json_TPM2B_ECC_PARAMETER_serialize(&in->x, &jso2); return_if_error(r, "Serialize TPM2B_ECC_PARAMETER"); - json_object_object_add(*jso, "x", jso2); + if (json_object_object_add(*jso, "x", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_ECC_PARAMETER_serialize(&in->y, &jso2); return_if_error(r, "Serialize TPM2B_ECC_PARAMETER"); - json_object_object_add(*jso, "y", jso2); + if (json_object_object_add(*jso, "y", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3382,13 +3574,17 @@ ifapi_json_TPMT_ECC_SCHEME_serialize(const TPMT_ECC_SCHEME *in, json_object **js r = ifapi_json_TPMI_ALG_ECC_SCHEME_serialize(in->scheme, &jso2); return_if_error(r, "Serialize TPMI_ALG_ECC_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->scheme != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_ASYM_SCHEME_serialize(&in->details, in->scheme, &jso2); return_if_error(r,"Serialize TPMU_ASYM_SCHEME"); - json_object_object_add(*jso, "details", jso2); + if (json_object_object_add(*jso, "details", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -3415,12 +3611,16 @@ ifapi_json_TPMS_SIGNATURE_RSA_serialize(const TPMS_SIGNATURE_RSA *in, json_objec r = ifapi_json_TPMI_ALG_HASH_serialize(in->hash, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "hash", jso2); + if (json_object_object_add(*jso, "hash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_PUBLIC_KEY_RSA_serialize(&in->sig, &jso2); return_if_error(r, "Serialize TPM2B_PUBLIC_KEY_RSA"); - json_object_object_add(*jso, "sig", jso2); + if (json_object_object_add(*jso, "sig", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3476,17 +3676,23 @@ ifapi_json_TPMS_SIGNATURE_ECC_serialize(const TPMS_SIGNATURE_ECC *in, json_objec r = ifapi_json_TPMI_ALG_HASH_serialize(in->hash, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "hash", jso2); + if (json_object_object_add(*jso, "hash", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_ECC_PARAMETER_serialize(&in->signatureR, &jso2); return_if_error(r, "Serialize TPM2B_ECC_PARAMETER"); - json_object_object_add(*jso, "signatureR", jso2); + if (json_object_object_add(*jso, "signatureR", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_ECC_PARAMETER_serialize(&in->signatureS, &jso2); return_if_error(r, "Serialize TPM2B_ECC_PARAMETER"); - json_object_object_add(*jso, "signatureS", jso2); + if (json_object_object_add(*jso, "signatureS", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3608,13 +3814,17 @@ ifapi_json_TPMT_SIGNATURE_serialize(const TPMT_SIGNATURE *in, json_object **jso) r = ifapi_json_TPMI_ALG_SIG_SCHEME_serialize(in->sigAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_SIG_SCHEME"); - json_object_object_add(*jso, "sigAlg", jso2); + if (json_object_object_add(*jso, "sigAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } if (in->sigAlg != TPM2_ALG_NULL) { json_object *jso2 = NULL; r = ifapi_json_TPMU_SIGNATURE_serialize(&in->signature, in->sigAlg, &jso2); return_if_error(r,"Serialize TPMU_SIGNATURE"); - json_object_object_add(*jso, "signature", jso2); + if (json_object_object_add(*jso, "signature", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } return TSS2_RC_SUCCESS; } @@ -3717,7 +3927,9 @@ ifapi_json_TPMS_KEYEDHASH_PARMS_serialize(const TPMS_KEYEDHASH_PARMS *in, json_o r = ifapi_json_TPMT_KEYEDHASH_SCHEME_serialize(&in->scheme, &jso2); return_if_error(r, "Serialize TPMT_KEYEDHASH_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3743,22 +3955,30 @@ ifapi_json_TPMS_RSA_PARMS_serialize(const TPMS_RSA_PARMS *in, json_object **jso) r = ifapi_json_TPMT_SYM_DEF_OBJECT_serialize(&in->symmetric, &jso2); return_if_error(r, "Serialize TPMT_SYM_DEF_OBJECT"); - json_object_object_add(*jso, "symmetric", jso2); + if (json_object_object_add(*jso, "symmetric", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMT_RSA_SCHEME_serialize(&in->scheme, &jso2); return_if_error(r, "Serialize TPMT_RSA_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_RSA_KEY_BITS_serialize(in->keyBits, &jso2); return_if_error(r, "Serialize TPMI_RSA_KEY_BITS"); - json_object_object_add(*jso, "keyBits", jso2); + if (json_object_object_add(*jso, "keyBits", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT32_serialize(in->exponent, &jso2); return_if_error(r, "Serialize UINT32"); - json_object_object_add(*jso, "exponent", jso2); + if (json_object_object_add(*jso, "exponent", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3784,22 +4004,30 @@ ifapi_json_TPMS_ECC_PARMS_serialize(const TPMS_ECC_PARMS *in, json_object **jso) r = ifapi_json_TPMT_SYM_DEF_OBJECT_serialize(&in->symmetric, &jso2); return_if_error(r, "Serialize TPMT_SYM_DEF_OBJECT"); - json_object_object_add(*jso, "symmetric", jso2); + if (json_object_object_add(*jso, "symmetric", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMT_ECC_SCHEME_serialize(&in->scheme, &jso2); return_if_error(r, "Serialize TPMT_ECC_SCHEME"); - json_object_object_add(*jso, "scheme", jso2); + if (json_object_object_add(*jso, "scheme", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_ECC_CURVE_serialize(in->curveID, &jso2); return_if_error(r, "Serialize TPMI_ECC_CURVE"); - json_object_object_add(*jso, "curveID", jso2); + if (json_object_object_add(*jso, "curveID", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMT_KDF_SCHEME_serialize(&in->kdf, &jso2); return_if_error(r, "Serialize TPMT_KDF_SCHEME"); - json_object_object_add(*jso, "kdf", jso2); + if (json_object_object_add(*jso, "kdf", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3855,32 +4083,44 @@ ifapi_json_TPMT_PUBLIC_serialize(const TPMT_PUBLIC *in, json_object **jso) r = ifapi_json_TPMI_ALG_PUBLIC_serialize(in->type, &jso2); return_if_error(r, "Serialize TPMI_ALG_PUBLIC"); - json_object_object_add(*jso, "type", jso2); + if (json_object_object_add(*jso, "type", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_ALG_HASH_serialize(in->nameAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "nameAlg", jso2); + if (json_object_object_add(*jso, "nameAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMA_OBJECT_serialize(in->objectAttributes, &jso2); return_if_error(r, "Serialize TPMA_OBJECT"); - json_object_object_add(*jso, "objectAttributes", jso2); + if (json_object_object_add(*jso, "objectAttributes", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->authPolicy, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "authPolicy", jso2); + if (json_object_object_add(*jso, "authPolicy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMU_PUBLIC_PARMS_serialize(&in->parameters, in->type, &jso2); return_if_error(r,"Serialize TPMU_PUBLIC_PARMS"); - json_object_object_add(*jso, "parameters", jso2); + if (json_object_object_add(*jso, "parameters", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMU_PUBLIC_ID_serialize(&in->unique, in->type, &jso2); return_if_error(r,"Serialize TPMU_PUBLIC_ID"); - json_object_object_add(*jso, "unique", jso2); + if (json_object_object_add(*jso, "unique", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -3906,13 +4146,17 @@ ifapi_json_TPM2B_PUBLIC_serialize(const TPM2B_PUBLIC *in, json_object **jso) if (ifapi_json_UINT16_serialize(in->size, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "size", jso2); + if (json_object_object_add(*jso, "size", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (ifapi_json_TPMT_PUBLIC_serialize(&in->publicArea, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "publicArea", jso2); + if (json_object_object_add(*jso, "publicArea", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -4030,14 +4274,18 @@ ifapi_json_TPMA_NV_serialize(const TPMA_NV in, json_object **jso) jso_bit = json_object_new_int(0); return_if_null(jso_bit, "Out of memory.", TSS2_FAPI_RC_MEMORY); - json_object_object_add(*jso, tab[i].name, jso_bit); + if (json_object_object_add(*jso, tab[i].name, jso_bit)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } TPM2_NT input2 = (TPMA_NV_TPM2_NT_MASK & input)>>4; json_object *jso2 = NULL; TSS2_RC r = ifapi_json_TPM2_NT_serialize(input2, &jso2); return_if_error(r, "Bad value"); - json_object_object_add(*jso, "TPM2_NT", jso2); + if (json_object_object_add(*jso, "TPM2_NT", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -4064,27 +4312,37 @@ ifapi_json_TPMS_NV_PUBLIC_serialize(const TPMS_NV_PUBLIC *in, json_object **jso) r = ifapi_json_TPMI_RH_NV_INDEX_serialize(in->nvIndex, &jso2); return_if_error(r, "Serialize TPMI_RH_NV_INDEX"); - json_object_object_add(*jso, "nvIndex", jso2); + if (json_object_object_add(*jso, "nvIndex", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMI_ALG_HASH_serialize(in->nameAlg, &jso2); return_if_error(r, "Serialize TPMI_ALG_HASH"); - json_object_object_add(*jso, "nameAlg", jso2); + if (json_object_object_add(*jso, "nameAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMA_NV_serialize(in->attributes, &jso2); return_if_error(r, "Serialize TPMA_NV"); - json_object_object_add(*jso, "attributes", jso2); + if (json_object_object_add(*jso, "attributes", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->authPolicy, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "authPolicy", jso2); + if (json_object_object_add(*jso, "authPolicy", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_UINT16_serialize(in->dataSize, &jso2); return_if_error(r, "Serialize UINT16"); - json_object_object_add(*jso, "dataSize", jso2); + if (json_object_object_add(*jso, "dataSize", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -4110,13 +4368,17 @@ ifapi_json_TPM2B_NV_PUBLIC_serialize(const TPM2B_NV_PUBLIC *in, json_object **js if (ifapi_json_UINT16_serialize(in->size, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "size", jso2); + if (json_object_object_add(*jso, "size", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (ifapi_json_TPMS_NV_PUBLIC_serialize(&in->nvPublic, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "nvPublic", jso2); + if (json_object_object_add(*jso, "nvPublic", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -4143,37 +4405,51 @@ ifapi_json_TPMS_CREATION_DATA_serialize(const TPMS_CREATION_DATA *in, json_objec r = ifapi_json_TPML_PCR_SELECTION_serialize(&in->pcrSelect, &jso2); return_if_error(r, "Serialize TPML_PCR_SELECTION"); - json_object_object_add(*jso, "pcrSelect", jso2); + if (json_object_object_add(*jso, "pcrSelect", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DIGEST_serialize(&in->pcrDigest, &jso2); return_if_error(r, "Serialize TPM2B_DIGEST"); - json_object_object_add(*jso, "pcrDigest", jso2); + if (json_object_object_add(*jso, "pcrDigest", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPMA_LOCALITY_serialize(in->locality, &jso2); return_if_error(r, "Serialize TPMA_LOCALITY"); - json_object_object_add(*jso, "locality", jso2); + if (json_object_object_add(*jso, "locality", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2_ALG_ID_serialize(in->parentNameAlg, &jso2); return_if_error(r, "Serialize TPM2_ALG_ID"); - json_object_object_add(*jso, "parentNameAlg", jso2); + if (json_object_object_add(*jso, "parentNameAlg", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->parentName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "parentName", jso2); + if (json_object_object_add(*jso, "parentName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_NAME_serialize(&in->parentQualifiedName, &jso2); return_if_error(r, "Serialize TPM2B_NAME"); - json_object_object_add(*jso, "parentQualifiedName", jso2); + if (json_object_object_add(*jso, "parentQualifiedName", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; r = ifapi_json_TPM2B_DATA_serialize(&in->outsideInfo, &jso2); return_if_error(r, "Serialize TPM2B_DATA"); - json_object_object_add(*jso, "outsideInfo", jso2); + if (json_object_object_add(*jso, "outsideInfo", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } @@ -4199,13 +4475,17 @@ ifapi_json_TPM2B_CREATION_DATA_serialize(const TPM2B_CREATION_DATA *in, json_obj if (ifapi_json_UINT16_serialize(in->size, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "size", jso2); + if (json_object_object_add(*jso, "size", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } jso2 = NULL; if (ifapi_json_TPMS_CREATION_DATA_serialize(&in->creationData, &jso2)) return TSS2_FAPI_RC_BAD_VALUE; - json_object_object_add(*jso, "creationData", jso2); + if (json_object_object_add(*jso, "creationData", jso2)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } return TSS2_RC_SUCCESS; } diff --git a/src/tss2-mu/tpm2b-types.c b/src/tss2-mu/tpm2b-types.c index f9ae24c..e02c679 100644 --- a/src/tss2-mu/tpm2b-types.c +++ b/src/tss2-mu/tpm2b-types.c @@ -248,11 +248,7 @@ TSS2_RC Tss2_MU_##type##_Unmarshal(uint8_t const buffer[], size_t buffer_size, \ sizeof(size)); \ return TSS2_MU_RC_INSUFFICIENT_BUFFER; \ } \ - if (dest && dest->size != 0) { \ - LOG_WARNING("Size not zero"); \ - return TSS2_SYS_RC_BAD_VALUE; \ - } \ -\ + \ rc = Tss2_MU_UINT16_Unmarshal(buffer, buffer_size, &local_offset, &size); \ if (rc) \ return rc; \ diff --git a/src/tss2-mu/tpml-types.c b/src/tss2-mu/tpml-types.c index 60f85a8..1df9bbb 100644 --- a/src/tss2-mu/tpml-types.c +++ b/src/tss2-mu/tpml-types.c @@ -175,8 +175,10 @@ TPML_MARSHAL(TPML_PCR_SELECTION, Tss2_MU_TPMS_PCR_SELECTION_Marshal, pcrSelectio TPML_UNMARSHAL(TPML_PCR_SELECTION, Tss2_MU_TPMS_PCR_SELECTION_Unmarshal, pcrSelections) TPML_MARSHAL(TPML_DIGEST_VALUES, Tss2_MU_TPMT_HA_Marshal, digests, ADDR) TPML_UNMARSHAL(TPML_DIGEST_VALUES, Tss2_MU_TPMT_HA_Unmarshal, digests) +#ifndef DISABLE_VENDOR TPML_MARSHAL(TPML_INTEL_PTT_PROPERTY, Tss2_MU_UINT32_Marshal, property, VAL) TPML_UNMARSHAL(TPML_INTEL_PTT_PROPERTY, Tss2_MU_UINT32_Unmarshal, property) +#endif TPML_MARSHAL(TPML_AC_CAPABILITIES, Tss2_MU_TPMS_AC_OUTPUT_Marshal, acCapabilities, ADDR) TPML_UNMARSHAL(TPML_AC_CAPABILITIES, Tss2_MU_TPMS_AC_OUTPUT_Unmarshal, acCapabilities) TPML_MARSHAL(TPML_TAGGED_POLICY, Tss2_MU_TPMS_TAGGED_POLICY_Marshal, policies, ADDR) diff --git a/src/tss2-mu/tpms-types.c b/src/tss2-mu/tpms-types.c index 3ad7252..56aca0c 100644 --- a/src/tss2-mu/tpms-types.c +++ b/src/tss2-mu/tpms-types.c @@ -22,6 +22,27 @@ #define VAL #define TAB_SIZE(tab) (sizeof(tab) / sizeof(tab[0])) +static TSS2_RC +TPM2_GENERATED_Unmarshal( + uint8_t const buffer[], + size_t buffer_size, + size_t *offset, + TPM2_GENERATED *magic) +{ + TPM2_GENERATED mymagic = 0; + TSS2_RC rc = Tss2_MU_UINT32_Unmarshal(buffer, buffer_size, offset, &mymagic); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + if (mymagic != TPM2_GENERATED_VALUE) { + LOG_ERROR("Bad magic in tpms_attest"); + return TSS2_SYS_RC_BAD_VALUE; + } + if (magic != NULL) + *magic = mymagic; + return TSS2_RC_SUCCESS; +} + #define TPMS_PCR_MARSHAL(type, firstFieldMarshal) \ TSS2_RC \ Tss2_MU_##type##_Marshal(const type *src, uint8_t buffer[], \ @@ -1219,7 +1240,7 @@ TPMS_MARSHAL_7_U(TPMS_ATTEST, attested, ADDR, Tss2_MU_TPMU_ATTEST_Marshal) TPMS_UNMARSHAL_7_U(TPMS_ATTEST, - magic, Tss2_MU_UINT32_Unmarshal, + magic, TPM2_GENERATED_Unmarshal, type, Tss2_MU_TPM2_ST_Unmarshal, qualifiedSigner, Tss2_MU_TPM2B_NAME_Unmarshal, extraData, Tss2_MU_TPM2B_DATA_Unmarshal, diff --git a/src/tss2-mu/tpmu-types.c b/src/tss2-mu/tpmu-types.c index a615a9b..428349b 100644 --- a/src/tss2-mu/tpmu-types.c +++ b/src/tss2-mu/tpmu-types.c @@ -285,7 +285,7 @@ TSS2_RC Tss2_MU_##type##_Marshal(type const *src, uint32_t selector, uint8_t buf return TSS2_MU_RC_BAD_REFERENCE; \ } \ \ - LOG_DEBUG("Marshalling " #type ", selector %x", selector); \ + LOG_DEBUG("Marshalling " #type ", selector 0x%"PRIx32, selector); \ switch (selector) { \ case sel: \ ret = fn(op src->m, buffer, buffer_size, offset); \ @@ -328,7 +328,7 @@ TSS2_RC Tss2_MU_##type##_Marshal(type const *src, uint32_t selector, uint8_t buf ret = TSS2_RC_SUCCESS; \ break; \ default: \ - LOG_DEBUG("wrong selector %x return error", selector); \ + LOG_ERROR("wrong selector 0x%"PRIx32" return error", selector); \ break; \ } \ return ret; \ @@ -382,7 +382,7 @@ TSS2_RC Tss2_MU_##type##_Unmarshal(uint8_t const buffer[], size_t buffer_size, \ { \ TSS2_RC ret = TSS2_MU_RC_BAD_VALUE; \ \ - LOG_DEBUG("Unmarshalling " #type ", selector %x", selector); \ + LOG_DEBUG("Unmarshalling " #type ", selector 0x%"PRIx32, selector); \ switch (selector) { \ case sel: \ ret = fn(buffer, buffer_size, offset, dest ? &dest->m : NULL); \ @@ -425,7 +425,7 @@ TSS2_RC Tss2_MU_##type##_Unmarshal(uint8_t const buffer[], size_t buffer_size, \ ret = TSS2_RC_SUCCESS; \ break; \ default: \ - LOG_DEBUG("wrong selector %x return error", selector); \ + LOG_ERROR("wrong selector 0x%"PRIx32" return error", selector); \ break; \ } \ return ret; \ diff --git a/src/tss2-mu/tss2-mu.vcxproj b/src/tss2-mu/tss2-mu.vcxproj index ebf56a9..043d17f 100644 --- a/src/tss2-mu/tss2-mu.vcxproj +++ b/src/tss2-mu/tss2-mu.vcxproj @@ -37,28 +37,28 @@ Clang libtss2_mu 14.0 - 10.0.17134.0 + 10 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL diff --git a/src/tss2-policy/tss2_policy.c b/src/tss2-policy/tss2_policy.c index 5cf3f39..e8c6b25 100644 --- a/src/tss2-policy/tss2_policy.c +++ b/src/tss2-policy/tss2_policy.c @@ -250,7 +250,7 @@ Tss2_PolicyExecute( through all execution stages / states of this invocation. */ } while (is_try_again(r)); - LOG_TRACE("finished, returning: 0x%x", r); + LOG_TRACE("finished, returning: 0x%"PRIx32, r); return r; } diff --git a/src/tss2-rc/tss2-rc.vcxproj b/src/tss2-rc/tss2-rc.vcxproj index 15f9115..11d7e28 100644 --- a/src/tss2-rc/tss2-rc.vcxproj +++ b/src/tss2-rc/tss2-rc.vcxproj @@ -31,28 +31,28 @@ Clang libtss2_rc 14.0 - 10.0.17134.0 + 10 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -75,4 +75,4 @@ - + \ No newline at end of file diff --git a/src/tss2-rc/tss2_rc.c b/src/tss2-rc/tss2_rc.c index 0f58e80..a3d5a60 100644 --- a/src/tss2-rc/tss2_rc.c +++ b/src/tss2-rc/tss2_rc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "tss2_rc.h" #include "tss2_sys.h" @@ -116,7 +117,7 @@ tss2_rc_layer_number_get(TSS2_RC rc) static inline UINT8 tpm2_rc_fmt1_N_get(TPM2_RC rc) { - return ((rc & (0xF << 8)) >> 8); + return ((rc & (((TPM2_RC)0xF) << 8)) >> 8); } /** @@ -150,7 +151,7 @@ tpm2_rc_fmt1_N_is_handle(TPM2_RC rc) static inline UINT8 tpm2_rc_fmt1_P_get(TPM2_RC rc) { - return ((rc & (1 << 6)) >> 6); + return ((rc & (((TPM2_RC)1) << 6)) >> 6); } static inline UINT8 @@ -168,19 +169,19 @@ tpm2_rc_fmt0_error_get(TPM2_RC rc) static inline UINT8 tpm2_rc_tpm_fmt0_V_get(TPM2_RC rc) { - return ((rc & (1 << 8)) >> 8); + return ((rc & (((TPM2_RC)1) << 8)) >> 8); } static inline UINT8 tpm2_rc_fmt0_T_get(TPM2_RC rc) { - return ((rc & (1 << 10)) >> 8); + return ((rc & (((TPM2_RC)1) << 10)) >> 8); } static inline UINT8 tpm2_rc_fmt0_S_get(TSS2_RC rc) { - return ((rc & (1 << 11)) >> 8); + return ((rc & (((TPM2_RC)1) << 11)) >> 8); } /** @@ -289,6 +290,10 @@ tss2_fmt1_err_strs_get(TSS2_RC error) "curve not supported", /* 0x27 - TPM2_RC_ECC_POINT */ "point is not on the required curve", + /* 0x28 - TPM2_RC_FW_LIMITED */ + "the command requires the firmware secret but the firmware secret is unavailable", + /* 0x29 - TPM2_RC_SVN_LIMITED */ + "the command requires the firmware SVN secret but the firmware SVN secret is unavailable" }; if (error < ARRAY_LEN(fmt1_err_strs)) { @@ -641,7 +646,7 @@ tpm2_err_handler_fmt1(TPM2_RC rc) if (m) { catbuf(buf, "%s", m); } else { - catbuf(buf, "unknown error num: 0x%X", errnum); + catbuf(buf, "unknown error num: 0x%"PRIX8, errnum); } return buf; @@ -663,7 +668,7 @@ tpm2_err_handler_fmt0(TSS2_RC rc) if (tpm2_rc_tpm_fmt0_V_get(rc)) { /* TCG specific error code */ if (tpm2_rc_fmt0_T_get(rc)) { - catbuf(buf, "Vendor specific error: 0x%X", errnum); + catbuf(buf, "Vendor specific error: 0x%"PRIX8, errnum); return buf; } @@ -691,7 +696,7 @@ tpm2_err_handler_fmt0(TSS2_RC rc) static inline UINT8 tss2_rc_layer_format_get(TSS2_RC rc) { - return ((rc & (1 << 7)) >> 7); + return ((rc & (((TPM2_RC)1) << 7)) >> 7); } /** @@ -884,7 +889,7 @@ unknown_layer_handler(TSS2_RC rc) static __thread char buf[32]; clearbuf(buf); - catbuf(buf, "0x%X", rc); + catbuf(buf, "0x%"PRIX32, rc); return buf; } @@ -992,14 +997,14 @@ Tss2_RC_Decode(TSS2_RC rc) if (e) { catbuf(buf, "%s", e); } else { - catbuf(buf, "0x%X", err_bits); + catbuf(buf, "0x%"PRIX16, err_bits); } } else { /* * we don't want to drop any bits if we don't know what to do with it - * so drop the layer byte since we we already have that. + * so just send the whole thing. */ - const char *e = unknown_layer_handler(rc >> 8); + const char *e = unknown_layer_handler(rc); assert(e); catbuf(buf, "%s", e); } @@ -1076,7 +1081,7 @@ Tss2_RC_DecodeInfoError(TSS2_RC_INFO *info) if (m) { catbuf(buf, "%s", m); } else { - catbuf(buf, "0x%X", info->error); + catbuf(buf, "0x%"PRIX32, info->error); } return buf; diff --git a/src/tss2-sys/api/Tss2_Sys_Execute.c b/src/tss2-sys/api/Tss2_Sys_Execute.c index 8935940..ae5a77f 100644 --- a/src/tss2-sys/api/Tss2_Sys_Execute.c +++ b/src/tss2-sys/api/Tss2_Sys_Execute.c @@ -75,7 +75,7 @@ TSS2_RC Tss2_Sys_ExecuteFinish(TSS2_SYS_CONTEXT *sysContext, int32_t timeout) } if (response_size > ctx->maxCmdSize) { ctx->previousStage = CMD_STAGE_PREPARE; - LOG_ERROR("Response size to big: %zu > %u", response_size, ctx->maxCmdSize); + LOG_ERROR("Response size to big: %zu > %"PRIu32, response_size, ctx->maxCmdSize); return TSS2_SYS_RC_INSUFFICIENT_CONTEXT; } diff --git a/src/tss2-sys/api/Tss2_Sys_GetCapability.c b/src/tss2-sys/api/Tss2_Sys_GetCapability.c index a0b5c1a..0329c49 100644 --- a/src/tss2-sys/api/Tss2_Sys_GetCapability.c +++ b/src/tss2-sys/api/Tss2_Sys_GetCapability.c @@ -108,7 +108,7 @@ TSS2_RC Tss2_Sys_GetCapability_Complete( */ ctx->nextData = next_data_vendor; size_t left = ctx->rsp_header.responseSize - ctx->nextData; - if (left > sizeof(capabilityData->data.vendor)) + if (left > sizeof(capabilityData->data.vendor.buffer)) return TSS2_MU_RC_BAD_SIZE; /* seems callers can use NULL */ diff --git a/src/tss2-sys/tss2-sys.vcxproj b/src/tss2-sys/tss2-sys.vcxproj index d9c0557..68fc57a 100644 --- a/src/tss2-sys/tss2-sys.vcxproj +++ b/src/tss2-sys/tss2-sys.vcxproj @@ -173,28 +173,28 @@ Clang tss2_sys 14.0 - 10.0.17134.0 + 10 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -218,4 +218,4 @@ - + \ No newline at end of file diff --git a/src/tss2-tcti/mpsse/mpsse.c b/src/tss2-tcti/mpsse/mpsse.c new file mode 100644 index 0000000..017e1bc --- /dev/null +++ b/src/tss2-tcti/mpsse/mpsse.c @@ -0,0 +1,1278 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +/* + * This file was copied from https://github.com/devttys0/libmpsse.git (sha1: a2eafa2) + * and modified accordingly. + * + * Copyright (c) 2015, Craig Heffner + * All rights reserved. + * SPDX short identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +#include "mpsse.h" +#include "support.h" +#include "config.h" + +/* List of known FT2232-based devices */ +struct vid_pid supported_devices[] = { + { 0x0403, 0x6014, "FT232H Future Technology Devices International, Ltd" }, + { 0x0403, 0x6010, "FT2232 Future Technology Devices International, Ltd" }, + { 0x0403, 0x6011, "FT4232 Future Technology Devices International, Ltd" }, + + /* These devices are based on FT2232 chips, but have not been tested. */ + { 0x0403, 0x8878, "Bus Blaster v2 (channel A)" }, + { 0x0403, 0x8879, "Bus Blaster v2 (channel B)" }, + { 0x0403, 0xBDC8, "Turtelizer JTAG/RS232 Adapter A" }, + { 0x0403, 0xCFF8, "Amontec JTAGkey" }, + { 0x0403, 0x8A98, "TIAO Multi Protocol Adapter"}, + { 0x15BA, 0x0003, "Olimex Ltd. OpenOCD JTAG" }, + { 0x15BA, 0x0004, "Olimex Ltd. OpenOCD JTAG TINY" }, + + { 0, 0, NULL } +}; + +/* + * Opens and initializes the first FTDI device found. + * + * @mode - Mode to open the device in. One of enum modes. + * @freq - Clock frequency to use for the specified mode. + * @endianess - Specifies how data is clocked in/out (MSB, LSB). + * + * Returns a pointer to an MPSSE context structure. + * On success, mpsse->open will be set to 1. + * On failure, mpsse->open will be set to 0. + */ +struct mpsse_context *MPSSE (enum modes mode, int freq, int endianess) +{ + int i = 0; + struct mpsse_context *mpsse = NULL; + + for (i=0; supported_devices[i].vid != 0; i++) + { + if ((mpsse = Open (supported_devices[i].vid, supported_devices[i].pid, mode, freq, endianess, IFACE_A, NULL, NULL)) != NULL) + { + if (mpsse->open) + { + mpsse->description = supported_devices[i].description; + break; + } + /* If there is another device still left to try, free the context pointer and try again */ + else if (supported_devices[i+1].vid != 0) + { + Close (mpsse); + mpsse = NULL; + } + } + } + + return mpsse; +} + +/* + * Open device by VID/PID + * + * @vid - Device vendor ID. + * @pid - Device product ID. + * @mode - MPSSE mode, one of enum modes. + * @freq - Clock frequency to use for the specified mode. + * @endianess - Specifies how data is clocked in/out (MSB, LSB). + * @interface - FTDI interface to use (IFACE_A - IFACE_D). + * @description - Device product description (set to NULL if not needed). + * @serial - Device serial number (set to NULL if not needed). + * + * Returns a pointer to an MPSSE context structure. + * On success, mpsse->open will be set to 1. + * On failure, mpsse->open will be set to 0. + */ +struct mpsse_context *Open (int vid, int pid, enum modes mode, int freq, int endianess, int interface, const char *description, const char *serial) +{ + return OpenIndex (vid, pid, mode, freq, endianess, interface, description, serial, 0); +} + +/* + * Open device by VID/PID/index + * + * @vid - Device vendor ID. + * @pid - Device product ID. + * @mode - MPSSE mode, one of enum modes. + * @freq - Clock frequency to use for the specified mode. + * @endianess - Specifies how data is clocked in/out (MSB, LSB). + * @interface - FTDI interface to use (IFACE_A - IFACE_D). + * @description - Device product description (set to NULL if not needed). + * @serial - Device serial number (set to NULL if not needed). + * @index - Device index (set to 0 if not needed). + * + * Returns a pointer to an MPSSE context structure. + * On success, mpsse->open will be set to 1. + * On failure, mpsse->open will be set to 0. + */ +struct mpsse_context *OpenIndex (int vid, int pid, enum modes mode, int freq, int endianess, int interface, const char *description, const char *serial, int index) +{ + int status = 0; + struct mpsse_context *mpsse = NULL; + + mpsse = malloc (sizeof(struct mpsse_context)); + if (mpsse) + { + memset (mpsse, 0, sizeof (struct mpsse_context)); + + /* Legacy; flushing is no longer needed, so disable it by default. */ + FlushAfterRead (mpsse, 0); + + /* ftdilib initialization */ + if (ftdi_init (&mpsse->ftdi) == 0) + { + /* Set the FTDI interface */ + ftdi_set_interface (&mpsse->ftdi, interface); + + /* Open the specified device */ + if (ftdi_usb_open_desc_index (&mpsse->ftdi, vid, pid, description, serial, index) == 0) + { + mpsse->mode = mode; + mpsse->vid = vid; + mpsse->pid = pid; + mpsse->status = STOPPED; + mpsse->endianess = endianess; + + /* Set the appropriate transfer size for the requested protocol */ + if (mpsse->mode == I2C) + { + mpsse->xsize = I2C_TRANSFER_SIZE; + } + else + { + mpsse->xsize = SPI_RW_SIZE; + } + + status |= ftdi_usb_reset (&mpsse->ftdi); + status |= ftdi_set_latency_timer (&mpsse->ftdi, LATENCY_MS); + status |= ftdi_write_data_set_chunksize (&mpsse->ftdi, CHUNK_SIZE); + status |= ftdi_read_data_set_chunksize (&mpsse->ftdi, CHUNK_SIZE); + status |= ftdi_set_bitmode (&mpsse->ftdi, 0, BITMODE_RESET); + + if (status == 0) + { + /* Set the read and write timeout periods */ + set_timeouts (mpsse, USB_TIMEOUT); + + if (mpsse->mode != BITBANG) + { + ftdi_set_bitmode (&mpsse->ftdi, 0, BITMODE_MPSSE); + + if (SetClock (mpsse, freq) == MPSSE_OK) + { + if (SetMode (mpsse, endianess) == MPSSE_OK) + { + int32_t ms = SETUP_DELAY/1000; + struct timeval tv = {ms/1000, (ms%1000)*1000}; + + mpsse->open = 1; + + /* Give the chip a few mS to initialize */ + select (0, NULL, NULL, NULL, &tv); + + /* + * Not all FTDI chips support all the commands that SetMode may have sent. + * This clears out any errors from unsupported commands that might have been sent during set up. + */ + ftdi_usb_purge_buffers (&mpsse->ftdi); + } + } + } + else + { + /* Skip the setup functions if we're just operating in BITBANG mode */ + if (ftdi_set_bitmode (&mpsse->ftdi, 0xFF, BITMODE_BITBANG) == 0) + { + mpsse->open = 1; + } + } + } + } + } + } + + return mpsse; +} + +/* + * Closes the device, deinitializes libftdi, and frees the MPSSE context pointer. + * + * @mpsse - MPSSE context pointer. + * + * Returns void. + */ +void Close (struct mpsse_context *mpsse) +{ + if (mpsse) + { + if (mpsse->open) + { + ftdi_set_bitmode (&mpsse->ftdi, 0, BITMODE_RESET); + ftdi_usb_close (&mpsse->ftdi); + ftdi_deinit (&mpsse->ftdi); + } + + free (mpsse); + mpsse = NULL; + } + + return; +} + +/* Enables bit-wise data transfers. + * Must be called after MPSSE() / Open() / OpenIndex(). + * + * Returns void. + */ +void EnableBitmode (struct mpsse_context *mpsse, int tf) +{ + if (is_valid_context (mpsse)) + { + if (tf) + { + mpsse->tx |= MPSSE_BITMODE; + mpsse->rx |= MPSSE_BITMODE; + mpsse->txrx |= MPSSE_BITMODE; + } + else + { + mpsse->tx &= ~MPSSE_BITMODE; + mpsse->rx &= ~MPSSE_BITMODE; + mpsse->txrx &= ~MPSSE_BITMODE; + } + } +} + +/* + * Sets the appropriate transmit and receive commands based on the requested mode and byte order. + * + * @mpsse - MPSSE context pointer. + * @endianess - MPSSE_MSB or MPSSE_LSB. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int SetMode (struct mpsse_context *mpsse, int endianess) +{ + int retval = MPSSE_OK, i = 0, setup_commands_size = 0; + unsigned char buf[CMD_SIZE] = { 0 }; + unsigned char setup_commands[CMD_SIZE*MAX_SETUP_COMMANDS] = { 0 }; + + /* Do not call is_valid_context() here, as the FTDI chip may not be completely configured when SetMode is called */ + if (mpsse) + { + /* Read and write commands need to include endianess */ + mpsse->tx = MPSSE_DO_WRITE | endianess; + mpsse->rx = MPSSE_DO_READ | endianess; + mpsse->txrx = MPSSE_DO_WRITE | MPSSE_DO_READ | endianess; + + /* Clock, data out, chip select pins are outputs; all others are inputs. */ + mpsse->tris = DEFAULT_TRIS; + + /* Clock and chip select pins idle high; all others are low */ + mpsse->pidle = mpsse->pstart = mpsse->pstop = DEFAULT_PORT; + + /* During reads and writes the chip select pin is brought low */ + mpsse->pstart &= ~TMS; + + /* Disable FTDI internal loopback */ + SetLoopback (mpsse, 0); + + /* Send ACKs by default */ + SetAck (mpsse, ACK); + + /* Ensure adaptive clock is disabled */ + setup_commands[setup_commands_size++] = DISABLE_ADAPTIVE_CLOCK; + + switch (mpsse->mode) + { + case SPI0: + /* SPI mode 0 clock idles low */ + mpsse->pidle &= ~SK; + mpsse->pstart &= ~SK; + mpsse->pstop &= ~SK; + /* SPI mode 0 propogates data on the falling edge and read data on the rising edge of the clock */ + mpsse->tx |= MPSSE_WRITE_NEG; + mpsse->rx &= ~MPSSE_READ_NEG; + mpsse->txrx |= MPSSE_WRITE_NEG; + mpsse->txrx &= ~MPSSE_READ_NEG; + break; + case SPI3: + /* SPI mode 3 clock idles high */ + mpsse->pidle |= SK; + mpsse->pstart |= SK; + /* Keep the clock low while the CS pin is brought high to ensure we don't accidentally clock out an extra bit */ + mpsse->pstop &= ~SK; + /* SPI mode 3 propogates data on the falling edge and read data on the rising edge of the clock */ + mpsse->tx |= MPSSE_WRITE_NEG; + mpsse->rx &= ~MPSSE_READ_NEG; + mpsse->txrx |= MPSSE_WRITE_NEG; + mpsse->txrx &= ~MPSSE_READ_NEG; + break; + case SPI1: + /* SPI mode 1 clock idles low */ + mpsse->pidle &= ~SK; + /* Since this mode idles low, the start condition should ensure that the clock is low */ + mpsse->pstart &= ~SK; + /* Even though we idle low in this mode, we need to keep the clock line high when we set the CS pin high to prevent + * an unintended clock cycle from being sent by the FT2232. This way, the clock goes high, but does not go low until + * after the CS pin goes high. + */ + mpsse->pstop |= SK; + /* Data read on falling clock edge */ + mpsse->rx |= MPSSE_READ_NEG; + mpsse->tx &= ~MPSSE_WRITE_NEG; + mpsse->txrx |= MPSSE_READ_NEG; + mpsse->txrx &= ~MPSSE_WRITE_NEG; + break; + case SPI2: + /* SPI 2 clock idles high */ + mpsse->pidle |= SK; + mpsse->pstart |= SK; + mpsse->pstop |= SK; + /* Data read on falling clock edge */ + mpsse->rx |= MPSSE_READ_NEG; + mpsse->tx &= ~MPSSE_WRITE_NEG; + mpsse->txrx |= MPSSE_READ_NEG; + mpsse->txrx &= ~MPSSE_WRITE_NEG; + break; + case I2C: + /* I2C propogates data on the falling clock edge and reads data on the falling (or rising) clock edge */ + mpsse->tx |= MPSSE_WRITE_NEG; + mpsse->rx &= ~MPSSE_READ_NEG; + /* In I2C, both the clock and the data lines idle high */ + mpsse->pidle |= DO | DI; + /* I2C start bit == data line goes from high to low while clock line is high */ + mpsse->pstart &= ~DO & ~DI; + /* I2C stop bit == data line goes from low to high while clock line is high - set data line low here, so the transition to the idle state triggers the stop condition. */ + mpsse->pstop &= ~DO & ~DI; + /* Enable three phase clock to ensure that I2C data is available on both the rising and falling clock edges */ + setup_commands[setup_commands_size++] = ENABLE_3_PHASE_CLOCK; + break; + case GPIO: + break; + default: + retval = MPSSE_FAIL; + } + + /* Send any setup commands to the chip */ + if (retval == MPSSE_OK) + { + retval = raw_write (mpsse, setup_commands, setup_commands_size); + } + + if (retval == MPSSE_OK) + { + /* Set the idle pin states */ + set_bits_low (mpsse, mpsse->pidle); + + /* All GPIO pins are outputs, set low */ + mpsse->trish = 0xFF; + mpsse->gpioh = 0x00; + + buf[i++] = SET_BITS_HIGH; + buf[i++] = mpsse->gpioh; + buf[i++] = mpsse->trish; + + retval = raw_write (mpsse, buf, i); + } + } + else + { + retval = MPSSE_FAIL; + } + + return retval; +} + +/* + * Sets the appropriate divisor for the desired clock frequency. + * + * @mpsse - MPSSE context pointer. + * @freq - Desired clock frequency in hertz. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int SetClock (struct mpsse_context *mpsse, uint32_t freq) +{ + int retval = MPSSE_FAIL; + uint32_t system_clock = 0; + uint16_t divisor = 0; + unsigned char buf[CMD_SIZE] = { 0 }; + + /* Do not call is_valid_context() here, as the FTDI chip may not be completely configured when SetClock is called */ + if (mpsse) + { + if (freq > SIX_MHZ) + { + buf[0] = TCK_X5; + system_clock = SIXTY_MHZ; + } + else + { + buf[0] = TCK_D5; + system_clock = TWELVE_MHZ; + } + + if (raw_write (mpsse, buf, 1) == MPSSE_OK) + { + if (freq <= 0) + { + divisor = 0xFFFF; + } + else + { + divisor = freq2div (system_clock, freq); + } + + buf[0] = TCK_DIVISOR; + buf[1] = (divisor & 0xFF); + buf[2] = ((divisor >> 8) & 0xFF); + + if (raw_write (mpsse, buf, 3) == MPSSE_OK) + { + mpsse->clock = div2freq (system_clock, divisor); + retval = MPSSE_OK; + } + } + } + + return retval; +} + +/* + * Retrieves the last error string from libftdi. + * + * @mpsse - MPSSE context pointer. + * + * Returns a pointer to the last error string. + */ +const char *ErrorString (struct mpsse_context *mpsse) +{ + if (mpsse != NULL) + { + return ftdi_get_error_string (&mpsse->ftdi); + } + + return NULL_CONTEXT_ERROR_MSG; +} + +/* + * Gets the currently configured clock rate. + * + * @mpsse - MPSSE context pointer. + * + * Returns the existing clock rate in hertz. + */ +int GetClock (struct mpsse_context *mpsse) +{ + int clock = 0; + + if (is_valid_context (mpsse)) + { + clock = mpsse->clock; + } + + return clock; +} + +/* + * Returns the vendor ID of the FTDI chip. + * + * @mpsse - MPSSE context pointer. + * + * Returns the integer value of the vendor ID. + */ +int GetVid (struct mpsse_context *mpsse) +{ + int vid = 0; + + if (is_valid_context (mpsse)) + { + vid = mpsse->vid; + } + + return vid; +} + +/* + * Returns the product ID of the FTDI chip. + * + * @mpsse - MPSSE context pointer. + * + * Returns the integer value of the product ID. + */ +int GetPid (struct mpsse_context *mpsse) +{ + int pid = 0; + + if (is_valid_context (mpsse)) + { + pid = mpsse->pid; + } + + return pid; +} + +/* + * Returns the description of the FTDI chip, if any. + * + * @mpsse - MPSSE context pointer. + * + * Returns the description of the FTDI chip. + */ +const char *GetDescription (struct mpsse_context *mpsse) +{ + char *description = NULL; + + if (is_valid_context (mpsse)) + { + description = mpsse->description; + } + + return description; +} + +/* + * Enable / disable internal loopback. + * + * @mpsse - MPSSE context pointer. + * @enable - Zero to disable loopback, 1 to enable loopback. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int SetLoopback (struct mpsse_context *mpsse, int enable) +{ + unsigned char buf[1] = { 0 }; + int retval = MPSSE_FAIL; + + if (is_valid_context (mpsse)) + { + if (enable) + { + buf[0] = LOOPBACK_START; + } + else + { + buf[0] = LOOPBACK_END; + } + + retval = raw_write (mpsse, buf, 1); + } + + return retval; +} + +/* + * Sets the idle state of the chip select pin. CS idles high by default. + * + * @mpsse - MPSSE context pointer. + * @idle - Set to 1 to idle high, 0 to idle low. + * + * Returns void. + */ +void SetCSIdle (struct mpsse_context *mpsse, int idle) +{ + if (is_valid_context (mpsse)) + { + if (idle > 0) + { + /* Chip select idles high, active low */ + mpsse->pidle |= TMS; + mpsse->pstop |= TMS; + mpsse->pstart &= ~TMS; + } + else + { + /* Chip select idles low, active high */ + mpsse->pidle &= ~TMS; + mpsse->pstop &= ~TMS; + mpsse->pstart |= TMS; + } + } + + return; +} + +/* + * Enables or disables flushing of the FTDI chip's RX buffers after each read operation. + * Flushing is disable by default. + * + * @mpsse - MPSSE context pointer. + * @tf - Set to 1 to enable flushing, or 0 to disable flushing. + * + * Returns void. + */ +void FlushAfterRead (struct mpsse_context *mpsse, int tf) +{ + mpsse->flush_after_read = tf; + return; +} + +/* + * Send data start condition. + * + * @mpsse - MPSSE context pointer. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int Start (struct mpsse_context *mpsse) +{ + int status = MPSSE_OK; + + if (is_valid_context (mpsse)) + { + + if (mpsse->mode == I2C && mpsse->status == STARTED) + { + /* Set the default pin states while the clock is low since this is an I2C repeated start condition */ + status |= set_bits_low (mpsse, (mpsse->pidle & ~SK)); + + /* Make sure the pins are in their default idle state */ + status |= set_bits_low (mpsse, mpsse->pidle); + } + + /* Set the start condition */ + status |= set_bits_low (mpsse, mpsse->pstart); + + /* + * Hackish work around to properly support SPI mode 3. + * SPI3 clock idles high, but needs to be set low before sending out + * data to prevent unintenteded clock glitches from the FT2232. + */ + if (mpsse->mode == SPI3) + { + status |= set_bits_low (mpsse, (mpsse->pstart & ~SK)); + } + /* + * Hackish work around to properly support SPI mode 1. + * SPI1 clock idles low, but needs to be set high before sending out + * data to preven unintended clock glitches from the FT2232. + */ + else if (mpsse->mode == SPI1) + { + status |= set_bits_low (mpsse, (mpsse->pstart | SK)); + } + + mpsse->status = STARTED; + } + else + { + status = MPSSE_FAIL; + mpsse->status = STOPPED; + } + + return status; +} + +/* + * Performs a bit-wise write of up to 8 bits at a time. + * + * @mpsse - MPSSE context pointer. + * @bits - A byte containing the desired bits to write. + * @size - The number of bits from the 'bits' byte to write. + * + * Returns MPSSE_OK on success, MPSSE_FAIL on failure. + */ +int WriteBits (struct mpsse_context *mpsse, char bits, int size) +{ + char data[8] = { 0 }; + int i = 0, retval = MPSSE_OK; + + if (size > (int)sizeof(data)) + { + size = sizeof(data); + } + + /* Convert each bit in bits to an array of bytes */ + for (i=0; iendianess == LSB) + { + data[i] = '\xFF'; + } + else + { + data[size-i-1] = '\xFF'; + } + } + } + + /* Enable bit mode before writing, then disable it afterwards. */ + EnableBitmode (mpsse, 1); + retval = Write (mpsse, data, size); + EnableBitmode (mpsse, 0); + + return retval; +} + +/* + * Send data out via the selected serial protocol. + * + * @mpsse - MPSSE context pointer. + * @data - Buffer of data to send. + * @size - Size of data. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int Write (struct mpsse_context *mpsse, char *data, int size) +{ + unsigned char *buf = NULL; + int retval = MPSSE_FAIL, buf_size = 0, txsize = 0, n = 0; + + if (is_valid_context (mpsse)) + { + if (mpsse->mode) + { + while(n < size) + { + txsize = size - n; + if (txsize > mpsse->xsize) + { + txsize = mpsse->xsize; + } + + /* + * For I2C we need to send each byte individually so that we can + * read back each individual ACK bit, so set the transmit size to 1. + */ + if (mpsse->mode == I2C) + { + txsize = 1; + } + + buf = build_block_buffer (mpsse, mpsse->tx, (unsigned char *) (data + n), txsize, &buf_size); + if (buf) + { + retval = raw_write (mpsse, buf, buf_size); + n += txsize; + free(buf); + + if (retval == MPSSE_FAIL) + { + break; + } + + /* Read in the ACK bit and store it in mpsse->rack */ + if (mpsse->mode == I2C) + { + raw_read (mpsse, (unsigned char *) &mpsse->rack, 1); + } + } + else + { + break; + } + } + } + + if (retval == MPSSE_OK && n == size) + { + retval = MPSSE_OK; + } + } + + return retval; +} + +/* Performs a read. For internal use only; see Read() and ReadBits(). */ +char *InternalRead (struct mpsse_context *mpsse, int size) +{ + unsigned char *data = NULL, *buf = NULL; + unsigned char sbuf[SPI_RW_SIZE] = { 0 }; + int n = 0, rxsize = 0, data_size = 0, retval = 0; + + if (is_valid_context (mpsse)) + { + if (mpsse->mode) + { + buf = malloc (size); + if (buf) + { + memset (buf, 0, size); + + while(n < size) + { + rxsize = size - n; + if (rxsize > mpsse->xsize) + { + rxsize = mpsse->xsize; + } + + data = build_block_buffer (mpsse, mpsse->rx, sbuf, rxsize, &data_size); + if (data) + { + retval = raw_write (mpsse, data, data_size); + free (data); + + if (retval == MPSSE_OK) + { + n += raw_read (mpsse, buf+n, rxsize); + } + else + { + break; + } + } + else + { + break; + } + } + } + } + } + + return (char *) buf; +} + +/* + * Reads data over the selected serial protocol. + * + * @mpsse - MPSSE context pointer. + * @size - Number of bytes to read. + * + * Returns a pointer to the read data on success. + * Returns NULL on failure. + */ +#ifdef SWIGPYTHON +swig_string_data Read (struct mpsse_context *mpsse, int size) +#else +char *Read (struct mpsse_context *mpsse, int size) +#endif +{ + char *buf = NULL; + + buf = InternalRead (mpsse, size); + +#ifdef SWIGPYTHON + swig_string_data sdata = { 0 }; + sdata.size = size; + sdata.data = buf; + return sdata; +#else + return buf; +#endif +} + +/* + * Performs a bit-wise read of up to 8 bits. + * + * @mpsse - MPSSE context pointer. + * @size - Number of bits to read. + * + * Returns an 8-bit byte containing the read bits. + */ +char ReadBits (struct mpsse_context *mpsse, int size) +{ + char bits = 0; + char *rdata = NULL; + + if (size > 8) + { + size = 8; + } + + EnableBitmode (mpsse, 1); + rdata = InternalRead (mpsse, size); + EnableBitmode (mpsse, 0); + + if (rdata) + { + /* The last byte in rdata will have all the read bits set or unset as needed. */ + bits = rdata[size-1]; + + if (mpsse->endianess == MSB) + { + /* + * In MSB mode, bits are sifted in from the left. If less than 8 bits were + * read, we need to shift them left accordingly. + */ + bits = bits << (8-size); + } + else if (mpsse->endianess == LSB) + { + /* + * In LSB mode, bits are shifted in from the right. If less than 8 bits were + * read, we need to shift them right accordingly. + */ + bits = bits >> (8-size); + } + + free (rdata); + } + + return bits; +} + +/* + * Reads and writes data over the selected serial protocol (SPI only). + * + * @mpsse - MPSSE context pointer. + * @data - Buffer containing bytes to write. + * @size - Number of bytes to transfer. + * + * Returns a pointer to the read data on success. + * Returns NULL on failure. + */ +#ifdef SWIGPYTHON +swig_string_data Transfer (struct mpsse_context *mpsse, char *data, int size) +#else +char *Transfer (struct mpsse_context *mpsse, char *data, int size) +#endif +{ + unsigned char *txdata = NULL, *buf = NULL; + int n = 0, data_size = 0, rxsize = 0, retval = 0; + + if (is_valid_context (mpsse)) + { + /* Make sure we're configured for one of the SPI modes */ + if (mpsse->mode >= SPI0 && mpsse->mode <= SPI3) + { + buf = malloc (size); + if (buf) + { + memset (buf, 0, size); + + while(n < size) + { + /* When sending and recieving, FTDI chips don't seem to like large data blocks. Limit the size of each block to SPI_TRANSFER_SIZE */ + rxsize = size - n; + if (rxsize > SPI_TRANSFER_SIZE) + { + rxsize = SPI_TRANSFER_SIZE; + } + + txdata = build_block_buffer (mpsse, mpsse->txrx, (unsigned char *) (data + n), rxsize, &data_size); + if (txdata) + { + retval = raw_write (mpsse, txdata, data_size); + free (txdata); + + if (retval == MPSSE_OK) + { + n += raw_read (mpsse, (buf + n), rxsize); + } + else + { + break; + } + } + else + { + break; + } + } + } + } + } + +#ifdef SWIGPYTHON + swig_string_data sdata = { 0 }; + sdata.size = n; + sdata.data = (char *) buf; + return sdata; +#else + return (char *) buf; +#endif +} + +/* + * Returns the last received ACK bit. + * + * @mpsse - MPSSE context pointer. + * + * Returns either an ACK (0) or a NACK (1). + */ +int GetAck (struct mpsse_context *mpsse) +{ + int ack = 0; + + if (is_valid_context (mpsse)) + { + ack = (mpsse->rack & 0x01); + } + + return ack; +} + +/* + * Sets the transmitted ACK bit. + * + * @mpsse - MPSSE context pointer. + * @ack - 0 to send ACKs, 1 to send NACKs. + * + * Returns void. + */ +void SetAck (struct mpsse_context *mpsse, int ack) +{ + if (is_valid_context (mpsse)) + { + if (ack == NACK) + { + mpsse->tack = 0xFF; + } + else + { + mpsse->tack = 0x00; + } + } + + return; +} + +/* + * Causes libmpsse to send ACKs after each read byte in I2C mode. + * + * @mpsse - MPSSE context pointer. + * + * Returns void. + */ +void SendAcks (struct mpsse_context *mpsse) +{ + return SetAck (mpsse, ACK); +} + +/* + * Causes libmpsse to send NACKs after each read byte in I2C mode. + * + * @mpsse - MPSSE context pointer. + * + * Returns void. + */ +void SendNacks (struct mpsse_context *mpsse) +{ + return SetAck (mpsse, NACK); +} + +/* + * Send data stop condition. + * + * @mpsse - MPSSE context pointer. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int Stop (struct mpsse_context *mpsse) +{ + int retval = MPSSE_OK; + + if (is_valid_context (mpsse)) + { + /* In I2C mode, we need to ensure that the data line goes low while the clock line is low to avoid sending an inadvertent start condition */ + if (mpsse->mode == I2C) + { + retval |= set_bits_low (mpsse, (mpsse->pidle & ~DO & ~SK)); + } + + /* Send the stop condition */ + retval |= set_bits_low (mpsse, mpsse->pstop); + + if (retval == MPSSE_OK) + { + /* Restore the pins to their idle states */ + retval |= set_bits_low (mpsse, mpsse->pidle); + } + + mpsse->status = STOPPED; + } + else + { + retval = MPSSE_FAIL; + mpsse->status = STOPPED; + } + + return retval; +} + +/* + * Sets the specified pin high. + * + * @mpsse - MPSSE context pointer. + * @pin - Pin number to set high. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int PinHigh (struct mpsse_context *mpsse, int pin) +{ + int retval = MPSSE_FAIL; + + if (is_valid_context (mpsse)) + { + retval = gpio_write (mpsse, pin, HIGH); + } + + return retval; +} + +/* + * Sets the specified pin low. + * + * @mpsse - MPSSE context pointer. + * @pin - Pin number to set low. + * + * Returns MPSSE_OK on success. + * Returns MPSSE_FAIL on failure. + */ +int PinLow (struct mpsse_context *mpsse, int pin) +{ + int retval = MPSSE_FAIL; + + if (is_valid_context (mpsse)) + { + retval = gpio_write (mpsse, pin, LOW); + } + + return retval; +} + +/* + * Sets the input/output direction of all pins. For use in BITBANG mode only. + * + * @mpsse - MPSSE context pointer. + * @direction - Byte indicating input/output direction of each bit. 1 is out. + * + * Returns MPSSE_OK if direction could be set, MPSSE_FAIL otherwise. + */ +int SetDirection (struct mpsse_context *mpsse, uint8_t direction) +{ + int retval = MPSSE_FAIL; + + if (is_valid_context (mpsse)) + { + if (mpsse->mode == BITBANG) + { + if (ftdi_set_bitmode (&mpsse->ftdi, direction, BITMODE_BITBANG) == 0) + { + retval = MPSSE_OK; + } + } + } + + return retval; +} + +/* + * Sets the input/output value of all pins. For use in BITBANG mode only. + * + * @mpsse - MPSSE context pointer. + * @data - Byte indicating bit hi/low value of each bit. + * + * Returns MPSSE_OK if direction could be set, MPSSE_FAIL otherwise. + */ +int WritePins (struct mpsse_context *mpsse, uint8_t data) +{ + int retval = MPSSE_FAIL; + + if (is_valid_context (mpsse)) + { + if (mpsse->mode == BITBANG) + { + if (ftdi_write_data (&mpsse->ftdi, &data, 1) == 0) + { + retval = MPSSE_OK; + } + } + } + + return retval; +} + +/* + * Reads the state of the chip's pins. For use in BITBANG mode only. + * + * @mpsse - MPSSE context pointer. + * + * Returns a byte with the corresponding pin's bits set to 1 or 0. + */ +int ReadPins (struct mpsse_context *mpsse) +{ + uint8_t val = 0; + + if (is_valid_context (mpsse)) + { + ftdi_read_pins ((struct ftdi_context *)&mpsse->ftdi, (unsigned char *)&val); + } + + return (int) val; +} + +/* + * Checks if a specific pin is high or low. For use in BITBANG mode only. + * + * @mpsse - MPSSE context pointer. + * @pin - The pin number. + * @state - The state of the pins, as returned by ReadPins. + * If set to -1, ReadPins will automatically be called. + * + * Returns a 1 if the pin is high, 0 if the pin is low. + */ +int PinState (struct mpsse_context *mpsse, int pin, int state) +{ + if (state == -1) + { + state = ReadPins (mpsse); + } + + /* If not in bitbang mode, the specified pin should be one of GPIOLx. Convert these defines into an absolute pin number. */ + if (mpsse->mode != BITBANG) + { + pin += NUM_GPIOL_PINS; + } + + return ((state & (1 << pin)) >> pin); +} + +/* + * Places all I/O pins into a tristate mode. + * + * @mpsse - MPSSE context pointer. + * + * Returns MPSSE_OK on success, MPSSE_FAIL on failure. + */ +int Tristate (struct mpsse_context *mpsse) +{ + unsigned char cmd[CMD_SIZE] = { 0 }; + + /* Tristate the all I/O pins (FT232H only) */ + cmd[0] = TRISTATE_IO; + cmd[1] = 0xFF; + cmd[2] = 0xFF; + + return raw_write (mpsse, cmd, sizeof (cmd)); +} diff --git a/src/tss2-tcti/mpsse/mpsse.h b/src/tss2-tcti/mpsse/mpsse.h new file mode 100644 index 0000000..69469dd --- /dev/null +++ b/src/tss2-tcti/mpsse/mpsse.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +/* + * This file was copied from https://github.com/devttys0/libmpsse.git (sha1: a2eafa2) + * and modified accordingly. + * + * Copyright (c) 2015, Craig Heffner + * All rights reserved. + * SPDX short identifier: BSD-2-Clause + */ +#ifndef _LIBMPSSE_H_ +#define _LIBMPSSE_H_ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if LIBFTDI_VERSION == 1 +#include +#else +#include +#endif + +#define MPSSE_OK 0 +#define MPSSE_FAIL -1 + +#define MSB 0x00 +#define LSB 0x08 + +#define CHUNK_SIZE 65535 +#define SPI_RW_SIZE (63 * 1024) +#define SPI_TRANSFER_SIZE 512 +#define I2C_TRANSFER_SIZE 64 + +#define LATENCY_MS 2 +#define TIMEOUT_DIVISOR 1000000 +#define USB_TIMEOUT 120000 +#define SETUP_DELAY 25000 + +#define BITMODE_RESET 0 +#define BITMODE_MPSSE 2 + +#define CMD_SIZE 3 +#define MAX_SETUP_COMMANDS 10 +#define SS_TX_COUNT 3 + +#define LOW 0 +#define HIGH 1 +#define NUM_GPIOL_PINS 4 +#define NUM_GPIO_PINS 12 + +#define NULL_CONTEXT_ERROR_MSG "NULL MPSSE context pointer!" + +/* FTDI interfaces */ +enum interface +{ + IFACE_ANY = INTERFACE_ANY, + IFACE_A = INTERFACE_A, + IFACE_B = INTERFACE_B, + IFACE_C = INTERFACE_C, + IFACE_D = INTERFACE_D +}; + +/* Common clock rates */ +enum clock_rates +{ + ONE_HUNDRED_KHZ = 100000, + FOUR_HUNDRED_KHZ = 400000, + ONE_MHZ = 1000000, + TWO_MHZ = 2000000, + FIVE_MHZ = 5000000, + SIX_MHZ = 6000000, + TEN_MHZ = 10000000, + TWELVE_MHZ = 12000000, + FIFTEEN_MHZ = 15000000, + THIRTY_MHZ = 30000000, + SIXTY_MHZ = 60000000 +}; + +/* Supported MPSSE modes */ +enum modes +{ + SPI0 = 1, + SPI1 = 2, + SPI2 = 3, + SPI3 = 4, + I2C = 5, + GPIO = 6, + BITBANG = 7, +}; + +enum pins +{ + SK = 1, + DO = 2, + DI = 4, + TMS = 8 , + GPIO0 = 16, + GPIO1 = 32, + GPIO2 = 64, + GPIO3 = 128 +}; + +enum gpio_pins +{ + GPIOL0 = 0, + GPIOL1 = 1, + GPIOL2 = 2, + GPIOL3 = 3, + GPIOH0 = 4, + GPIOH1 = 5, + GPIOH2 = 6, + GPIOH3 = 7, + GPIOH4 = 8, + GPIOH5 = 9, + GPIOH6 = 10, + GPIOH7 = 11 +}; + +enum i2c_ack +{ + ACK = 0, + NACK = 1 +}; + +#define DEFAULT_TRIS (SK | DO | TMS | GPIO0 | GPIO1 | GPIO2 | GPIO3) /* SK/DO/CS and GPIOs are outputs, DI is an input */ +#define DEFAULT_PORT (SK | TMS) /* SK and CS are high, all others low */ + +enum mpsse_commands +{ + INVALID_COMMAND = 0xAB, + ENABLE_ADAPTIVE_CLOCK = 0x96, + DISABLE_ADAPTIVE_CLOCK = 0x97, + ENABLE_3_PHASE_CLOCK = 0x8C, + DISABLE_3_PHASE_CLOCK = 0x8D, + TCK_X5 = 0x8A, + TCK_D5 = 0x8B, + CLOCK_N_CYCLES = 0x8E, + CLOCK_N8_CYCLES = 0x8F, + PULSE_CLOCK_IO_HIGH = 0x94, + PULSE_CLOCK_IO_LOW = 0x95, + CLOCK_N8_CYCLES_IO_HIGH = 0x9C, + CLOCK_N8_CYCLES_IO_LOW = 0x9D, + TRISTATE_IO = 0x9E, +}; + +enum low_bits_status +{ + STARTED, + STOPPED +}; + +struct vid_pid +{ + int vid; + int pid; + char *description; +}; + +struct mpsse_context +{ + char *description; + struct ftdi_context ftdi; + enum modes mode; + enum low_bits_status status; + int flush_after_read; + int vid; + int pid; + int clock; + int xsize; + int open; + int endianess; + uint8_t tris; + uint8_t pstart; + uint8_t pstop; + uint8_t pidle; + uint8_t gpioh; + uint8_t trish; + uint8_t bitbang; + uint8_t tx; + uint8_t rx; + uint8_t txrx; + uint8_t tack; + uint8_t rack; +}; + +struct mpsse_context *MPSSE (enum modes mode, int freq, int endianess); +struct mpsse_context *Open (int vid, int pid, enum modes mode, int freq, int endianess, int interface, const char *description, const char *serial); +struct mpsse_context *OpenIndex (int vid, int pid, enum modes mode, int freq, int endianess, int interface, const char *description, const char *serial, int index); +void Close (struct mpsse_context *mpsse); +const char *ErrorString (struct mpsse_context *mpsse); +int SetMode (struct mpsse_context *mpsse, int endianess); +void EnableBitmode (struct mpsse_context *mpsse, int tf); +int SetClock (struct mpsse_context *mpsse, uint32_t freq); +int GetClock (struct mpsse_context *mpsse); +int GetVid (struct mpsse_context *mpsse); +int GetPid (struct mpsse_context *mpsse); +const char *GetDescription (struct mpsse_context *mpsse); +int SetLoopback (struct mpsse_context *mpsse, int enable); +void SetCSIdle (struct mpsse_context *mpsse, int idle); +int Start (struct mpsse_context *mpsse); +int Write (struct mpsse_context *mpsse, char *data, int size); +int Stop (struct mpsse_context *mpsse); +int GetAck (struct mpsse_context *mpsse); +void SetAck (struct mpsse_context *mpsse, int ack); +void SendAcks (struct mpsse_context *mpsse); +void SendNacks (struct mpsse_context *mpsse); +void FlushAfterRead (struct mpsse_context *mpsse, int tf); +int PinHigh (struct mpsse_context *mpsse, int pin); +int PinLow (struct mpsse_context *mpsse, int pin); +int SetDirection (struct mpsse_context *mpsse, uint8_t direction); +int WriteBits (struct mpsse_context *mpsse, char bits, int size); +char ReadBits (struct mpsse_context *mpsse, int size); +int WritePins (struct mpsse_context *mpsse, uint8_t data); +int ReadPins (struct mpsse_context *mpsse); +int PinState (struct mpsse_context *mpsse, int pin, int state); +int Tristate (struct mpsse_context *mpsse); + +#ifdef SWIGPYTHON +typedef struct swig_string_data +{ + int size; + char *data; +} swig_string_data; + +swig_string_data Read (struct mpsse_context *mpsse, int size); +swig_string_data Transfer (struct mpsse_context *mpsse, char *data, int size); +#else +char *Read (struct mpsse_context *mpsse, int size); +char *Transfer (struct mpsse_context *mpsse, char *data, int size); + +int FastWrite (struct mpsse_context *mpsse, char *data, int size); +int FastRead (struct mpsse_context *mpsse, char *data, int size); +int FastTransfer (struct mpsse_context *mpsse, char *wdata, char *rdata, int size); +#endif + +#endif diff --git a/src/tss2-tcti/mpsse/support.c b/src/tss2-tcti/mpsse/support.c new file mode 100644 index 0000000..3781412 --- /dev/null +++ b/src/tss2-tcti/mpsse/support.c @@ -0,0 +1,326 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +/* + * This file was copied from https://github.com/devttys0/libmpsse.git (sha1: a2eafa2) + * and modified accordingly. + * + * Copyright (c) 2015, Craig Heffner + * All rights reserved. + * SPDX short identifier: BSD-2-Clause + */ + +#include +#include + +#include "mpsse.h" +#include "support.h" + +/* Write data to the FTDI chip */ +int raw_write (struct mpsse_context *mpsse, unsigned char *buf, int size) +{ + int retval = MPSSE_FAIL; + + if (mpsse->mode) + { + if (ftdi_write_data (&mpsse->ftdi, buf, size) == size) + { + retval = MPSSE_OK; + } + } + + return retval; +} + +/* Read data from the FTDI chip */ +int raw_read (struct mpsse_context *mpsse, unsigned char *buf, int size) +{ + int n = 0, r = 0; + + if (mpsse->mode) + { + while (n < size) + { + r = ftdi_read_data (&mpsse->ftdi, buf, size); + if (r < 0) break; + n += r; + } + + if (mpsse->flush_after_read) + { + /* + * Make sure the buffers are cleared after a read or subsequent reads may fail. + * + * Is this needed anymore? It slows down repetitive read operations by ~8%. + */ + ftdi_usb_purge_rx_buffer (&mpsse->ftdi); + } + } + + return n; +} + +/* Sets the read and write timeout periods for bulk usb data transfers. */ +void set_timeouts (struct mpsse_context *mpsse, int timeout) +{ + if (mpsse->mode) + { + mpsse->ftdi.usb_read_timeout = timeout; + mpsse->ftdi.usb_write_timeout = timeout; + } + + return; +} + +/* Convert a frequency to a clock divisor */ +uint16_t freq2div (uint32_t system_clock, uint32_t freq) +{ + return (((system_clock / freq) / 2) - 1); +} + +/* Convert a clock divisor to a frequency */ +uint32_t div2freq (uint32_t system_clock, uint16_t div) +{ + return (system_clock / ((1 + (uint32_t)div) * 2)); +} + +/* Builds a buffer of commands + data blocks */ +unsigned char *build_block_buffer (struct mpsse_context *mpsse, uint8_t cmd, unsigned char *data, int size, int *buf_size) +{ + unsigned char *buf = NULL; + int i = 0, j = 0, k = 0, dsize = 0, num_blocks = 0, total_size = 0, xfer_size = 0; + uint16_t rsize = 0; + + *buf_size = 0; + + /* Data block size is 1 in I2C, or when in bitmode */ + if (mpsse->mode == I2C || (cmd & MPSSE_BITMODE)) + { + xfer_size = 1; + } + else + { + xfer_size = mpsse->xsize; + } + + num_blocks = (size / xfer_size); + if (size % xfer_size) + { + num_blocks++; + } + + /* The total size of the data will be the data size + the write command */ + total_size = size + (CMD_SIZE * num_blocks); + + /* In I2C we have to add 3 additional commands per data block */ + if (mpsse->mode == I2C) + { + total_size += (CMD_SIZE * 3 * num_blocks); + } + + buf = malloc (total_size); + if (buf) + { + memset (buf, 0, total_size); + + for(j=0; j xfer_size) + { + dsize = xfer_size; + } + + /* The reported size of this block is block size - 1 */ + rsize = dsize - 1; + + /* For I2C we need to ensure that the clock pin is set low prior to clocking out data */ + if (mpsse->mode == I2C) + { + buf[i++] = SET_BITS_LOW; + buf[i++] = mpsse->pstart & ~SK; + + /* On receive, we need to ensure that the data out line is set as an input to avoid contention on the bus */ + if (cmd == mpsse->rx) + { + buf[i++] = mpsse->tris & ~DO; + } + else + { + buf[i++] = mpsse->tris; + } + } + + /* Copy in the command for this block */ + buf[i++] = cmd; + buf[i++] = (rsize & 0xFF); + if (!(cmd & MPSSE_BITMODE)) + { + buf[i++] = ((rsize >> 8) & 0xFF); + } + + /* On a write, copy the data to transmit after the command */ + if (cmd == mpsse->tx || cmd == mpsse->txrx) + { + memcpy (buf+i, data+k, dsize); + + /* i == offset into buf */ + i += dsize; + /* k == offset into data */ + k += dsize; + } + + /* In I2C mode we need to clock one ACK bit after each byte */ + if (mpsse->mode == I2C) + { + /* If we are receiving data, then we need to clock out an ACK for each byte */ + if (cmd == mpsse->rx) + { + buf[i++] = SET_BITS_LOW; + buf[i++] = mpsse->pstart & ~SK; + buf[i++] = mpsse->tris; + + buf[i++] = mpsse->tx | MPSSE_BITMODE; + buf[i++] = 0; + buf[i++] = mpsse->tack; + } + /* If we are sending data, then we need to clock in an ACK for each byte */ + else if (cmd == mpsse->tx) + { + /* Need to make data out an input to avoid contention on the bus when the slave sends an ACK */ + buf[i++] = SET_BITS_LOW; + buf[i++] = mpsse->pstart & ~SK; + buf[i++] = mpsse->tris & ~DO; + + buf[i++] = mpsse->rx | MPSSE_BITMODE; + buf[i++] = 0; + buf[i++] = SEND_IMMEDIATE; + } + } + } + + *buf_size = i; + } + + return buf; +} + +/* Set the low bit pins high/low */ +int set_bits_low (struct mpsse_context *mpsse, int port) +{ + char buf[CMD_SIZE] = { 0 }; + + buf[0] = SET_BITS_LOW; + buf[1] = port; + buf[2] = mpsse->tris; + + return raw_write (mpsse, (unsigned char *) &buf, sizeof (buf)); +} + +/* Set the high bit pins high/low */ +int set_bits_high (struct mpsse_context *mpsse, int port) +{ + char buf[CMD_SIZE] = { 0 }; + + buf[0] = SET_BITS_HIGH; + buf[1] = port; + buf[2] = mpsse->trish; + + return raw_write (mpsse, (unsigned char *)&buf, sizeof (buf)); +} + +/* Set the GPIO pins high/low */ +int gpio_write (struct mpsse_context *mpsse, int pin, int direction) +{ + int retval = MPSSE_FAIL; + + if (mpsse->mode == BITBANG) + { + if (direction == HIGH) + { + mpsse->bitbang |= (((uint8_t)1) << pin); + } + else + { + mpsse->bitbang &= ~(((uint8_t)1) << pin); + } + + if (set_bits_high (mpsse, mpsse->bitbang) == MPSSE_OK) + { + retval = raw_write (mpsse, (unsigned char *)&mpsse->bitbang, 1); + } + } + else + { + /* The first four pins can't be changed unless we are in a stopped status */ + if (pin < NUM_GPIOL_PINS && mpsse->status == STOPPED) + { + /* Convert pin number (0-3) to the corresponding pin bit */ + pin = (GPIO0 << pin); + + if (direction == HIGH) + { + mpsse->pstart |= pin; + mpsse->pidle |= pin; + mpsse->pstop |= pin; + } + else + { + mpsse->pstart &= ~pin; + mpsse->pidle &= ~pin; + mpsse->pstop &= ~pin; + } + + retval = set_bits_low (mpsse, mpsse->pstart); + } + else if (pin >= NUM_GPIOL_PINS && pin < NUM_GPIO_PINS) + { + /* Convert pin number (4 - 11) to the corresponding pin bit */ + pin -= NUM_GPIOL_PINS; + + if (direction == HIGH) + { + mpsse->gpioh |= (((uint8_t)1) << pin); + } + else + { + mpsse->gpioh &= ~(((uint8_t)1) << pin); + } + retval = set_bits_high (mpsse, mpsse->gpioh); + } + } + + return retval; +} + +/* Checks if a given MPSSE context is valid. */ +int is_valid_context (struct mpsse_context *mpsse) +{ + int retval = 0; + + if (mpsse != NULL && mpsse->open) + { + retval = 1; + } + + return retval; +} diff --git a/src/tss2-tcti/mpsse/support.h b/src/tss2-tcti/mpsse/support.h new file mode 100644 index 0000000..1197951 --- /dev/null +++ b/src/tss2-tcti/mpsse/support.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +/* + * This file was copied from https://github.com/devttys0/libmpsse.git (sha1: a2eafa2) + * and modified accordingly. + * + * Copyright (c) 2015, Craig Heffner + * All rights reserved. + * SPDX short identifier: BSD-2-Clause + */ +#ifndef _SUPPORT_H_ +#define _SUPPORT_H_ + +#include "mpsse.h" + +int raw_write (struct mpsse_context *mpsse, unsigned char *buf, int size); +int raw_read (struct mpsse_context *mpsse, unsigned char *buf, int size); +void set_timeouts (struct mpsse_context *mpsse, int timeout); +uint16_t freq2div (uint32_t system_clock, uint32_t freq); +uint32_t div2freq (uint32_t system_clock, uint16_t div); +unsigned char *build_block_buffer (struct mpsse_context *mpsse, uint8_t cmd, unsigned char *data, int size, int *buf_size); +int set_bits_high (struct mpsse_context *mpsse, int port); +int set_bits_low (struct mpsse_context *mpsse, int port); +int gpio_write (struct mpsse_context *mpsse, int pin, int direction); +int is_valid_context (struct mpsse_context *mpsse); + +#endif diff --git a/src/tss2-tcti/tcti-cmd.c b/src/tss2-tcti/tcti-cmd.c index a3f26ed..47920f0 100644 --- a/src/tss2-tcti/tcti-cmd.c +++ b/src/tss2-tcti/tcti-cmd.c @@ -621,7 +621,7 @@ TSS2_RC Tss2_Tcti_Cmd_Init (TSS2_TCTI_CONTEXT *tctiContext, size_t *size, } /* public info structure */ -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_cmd_info = { .version = TCTI_VERSION, .name = TCTI_CMD_NAME, .description = TCTI_CMD_DESCRIPTION, @@ -632,5 +632,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_cmd_info; } diff --git a/src/tss2-tcti/tcti-cmd.h b/src/tss2-tcti/tcti-cmd.h index cd7bdf5..923e66c 100644 --- a/src/tss2-tcti/tcti-cmd.h +++ b/src/tss2-tcti/tcti-cmd.h @@ -10,7 +10,7 @@ #include #include "tcti-common.h" -#include "util/io.h" +#include "util-io/io.h" #define TCTI_CMD_NAME "tcti-cmd" #define TCTI_CMD_DESCRIPTION "TCTI module for using a process to send and receive data." diff --git a/src/tss2-tcti/tcti-device.c b/src/tss2-tcti/tcti-device.c index 87e365e..ebd27b2 100644 --- a/src/tss2-tcti/tcti-device.c +++ b/src/tss2-tcti/tcti-device.c @@ -52,7 +52,7 @@ #include "tss2_mu.h" #include "tcti-common.h" #include "tcti-device.h" -#include "util/io.h" +#include "util-io/io.h" #include "util/aux_util.h" #define LOGMODULE tcti #include "util/log.h" @@ -63,6 +63,7 @@ static char *default_conf[] = { #else "/dev/tpmrm0", "/dev/tpm0", + "/dev/tcm0", #endif /* __VX_WORKS__ */ }; @@ -198,6 +199,9 @@ tcti_device_receive ( tcti_dev->fd, errno, strerror (errno)); return TSS2_TCTI_RC_IO_ERROR; } + } else { + LOG_ERROR ("Header could not be received"); + return TSS2_TCTI_RC_GENERAL_FAILURE; } LOG_DEBUG("Partial read - received header"); rc = Tss2_MU_UINT32_Unmarshal(header, TPM_HEADER_SIZE, @@ -526,7 +530,7 @@ Tss2_Tcti_Device_Init ( return TSS2_RC_SUCCESS; } -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_device_info = { .version = TCTI_VERSION, .name = "tcti-device", .description = "TCTI module for communication with Linux kernel interface.", @@ -538,5 +542,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_device_info; } diff --git a/src/tss2-tcti/tcti-i2c-ftdi.c b/src/tss2-tcti/tcti-i2c-ftdi.c new file mode 100644 index 0000000..c8e7db2 --- /dev/null +++ b/src/tss2-tcti/tcti-i2c-ftdi.c @@ -0,0 +1,295 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tss2_tcti.h" +#include "tcti-i2c-ftdi.h" +#include "tss2_tcti_i2c_ftdi.h" +#include "tcti-i2c-helper.h" +#include "tss2_mu.h" +#define LOGMODULE tcti +#include "util/log.h" + +TSS2_RC +platform_sleep_us (void *user_data, int32_t microseconds) +{ + (void) user_data; + struct timeval tv = {microseconds/1000000, microseconds%1000000}; + select (0, NULL, NULL, NULL, &tv); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_sleep_ms (void *user_data, int32_t milliseconds) +{ + return platform_sleep_us (user_data, milliseconds*1000); +} + +TSS2_RC +platform_start_timeout (void *user_data, int32_t milliseconds) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + memset (&platform_data->timeout, 0, sizeof (struct timeval)); + + if (gettimeofday (&platform_data->timeout, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + platform_data->timeout.tv_sec += (milliseconds/1000); + platform_data->timeout.tv_usec += (milliseconds%1000)*1000; + if (platform_data->timeout.tv_usec > 999999) { + platform_data->timeout.tv_sec++; + platform_data->timeout.tv_usec -= 1000000; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_timeout_expired (void *user_data, bool *is_timeout_expired) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + struct timeval now; + if (gettimeofday (&now, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + if (now.tv_sec > platform_data->timeout.tv_sec) { + *is_timeout_expired = true; + } else if ((now.tv_sec == platform_data->timeout.tv_sec) + && (now.tv_usec > platform_data->timeout.tv_usec)) { + *is_timeout_expired = true; + } else { + *is_timeout_expired = false; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_i2c_write (void *user_data, uint8_t reg_addr, const void *data, size_t cnt) +{ + TSS2_RC rc = TSS2_TCTI_RC_IO_ERROR; + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct mpsse_context *mpsse = platform_data->mpsse; + uint8_t addr[2] = {I2C_DEV_ADDR_DEFAULT << 1, 0x0}; + + if (Start (mpsse) != MPSSE_OK) + { + return rc; + } + + addr[1] = reg_addr; + if (Write (mpsse, (char *)addr, sizeof (addr)) != MPSSE_OK) + { + goto error; + } + + if (GetAck (mpsse) != ACK) + { + goto error; + } + + if (Write (mpsse, (char *)data, cnt) != MPSSE_OK) + { + goto error; + } + + rc = TSS2_RC_SUCCESS; + +error: + if (Stop (mpsse) != MPSSE_OK) + { + return TSS2_TCTI_RC_IO_ERROR; + } + + return rc; +} + +TSS2_RC +platform_i2c_read (void *user_data, uint8_t reg_addr, void *data, size_t cnt) +{ + TSS2_RC rc = TSS2_TCTI_RC_IO_ERROR; + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct mpsse_context *mpsse = platform_data->mpsse; + uint8_t addr[2] = {I2C_DEV_ADDR_DEFAULT << 1, 0x0}; + char *data_in = NULL; + + if (Start (mpsse) != MPSSE_OK) + { + return rc; + } + + /* Send the register address */ + addr[1] = reg_addr; + if (Write (mpsse, (char *)addr, sizeof (addr)) != MPSSE_OK) + { + goto error; + } + + if (GetAck (mpsse) != ACK) + { + goto error; + } + + /* Repeat the STOP (S) START (P) sequence */ + if ((Stop (mpsse) != MPSSE_OK) || (Start (mpsse) != MPSSE_OK)) + { + return rc; + } + + /* Send the read command */ + addr[0] |= 0x01; + if (Write (mpsse, (char *)addr, 1) != MPSSE_OK) + { + goto error; + } + + if (GetAck (mpsse) != ACK) + { + goto error; + } + + /* Read in (cnt - 1) bytes with ACK */ + SendAcks (mpsse); + if ((data_in = Read (mpsse, cnt - 1)) == NULL) + { + goto error; + } + + memcpy (data, (unsigned char *)data_in, cnt - 1); + free (data_in); + data_in = NULL; + + /* Read in the last byte with NACK */ + SendNacks (mpsse); + if ((data_in = Read (mpsse, 1)) == NULL) + { + goto error; + } + + ((unsigned char *)data)[cnt - 1] = *((unsigned char *)data_in); + free (data_in); + + rc = TSS2_RC_SUCCESS; + +error: + if (Stop (mpsse) != MPSSE_OK) + { + return TSS2_TCTI_RC_IO_ERROR; + } + + return rc; +} + +void +platform_finalize (void *user_data) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct mpsse_context *mpsse = platform_data->mpsse; + + if (mpsse != NULL) { + Close (mpsse); + } + + free (platform_data); +} + +TSS2_RC +create_tcti_i2c_ftdi_platform (TSS2_TCTI_I2C_HELPER_PLATFORM *platform) +{ + PLATFORM_USERDATA *platform_data = malloc (sizeof (PLATFORM_USERDATA)); + struct mpsse_context **mpsse = &platform_data->mpsse; + + if (platform_data == NULL) { + return TSS2_BASE_RC_MEMORY; + } + + memset (platform_data, 0, sizeof (PLATFORM_USERDATA)); + + if ((*mpsse = MPSSE (I2C, ONE_HUNDRED_KHZ, MSB)) == NULL ) + { + goto error; + } + + platform->user_data = platform_data; + platform->sleep_us = platform_sleep_us; + platform->sleep_ms = platform_sleep_ms; + platform->start_timeout = platform_start_timeout; + platform->timeout_expired = platform_timeout_expired; + platform->i2c_write = platform_i2c_write; + platform->i2c_read = platform_i2c_read; + platform->finalize = platform_finalize; + + return TSS2_RC_SUCCESS; + +error: + platform_finalize ((void *) platform_data); + return TSS2_BASE_RC_IO_ERROR; +} + +TSS2_RC +Tss2_Tcti_I2c_Ftdi_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, const char* config) +{ + (void) config; + TSS2_RC ret = 0; + TSS2_TCTI_I2C_HELPER_PLATFORM tcti_platform = {0}; + + if (tcti_context == NULL) { + return Tss2_Tcti_I2c_Helper_Init (NULL, size, NULL); + } + + if ((ret = create_tcti_i2c_ftdi_platform (&tcti_platform))) { + return ret; + } + + return Tss2_Tcti_I2c_Helper_Init (tcti_context, size, &tcti_platform); +} + +const TSS2_TCTI_INFO tss2_tcti_i2c_ftdi_info = { + .version = TCTI_VERSION, + .name = "tcti-i2c-ftdi", + .description = "TCTI for communicating with TPM through the USB-FTDI-I2C converter.", + .config_help = "Takes no configuration.", + .init = Tss2_Tcti_I2c_Ftdi_Init +}; + +const TSS2_TCTI_INFO * +Tss2_Tcti_Info (void) +{ + return &tss2_tcti_i2c_ftdi_info; +} diff --git a/src/tss2-tcti/tcti-i2c-ftdi.h b/src/tss2-tcti/tcti-i2c-ftdi.h new file mode 100644 index 0000000..a5b450c --- /dev/null +++ b/src/tss2-tcti/tcti-i2c-ftdi.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifndef TCTI_I2C_FTDI_H +#define TCTI_I2C_FTDI_H + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include "tcti-common.h" +#include "tss2_tcti_i2c_helper.h" +#include "mpsse/mpsse.h" + +/* The default 7-bit I2C device address defined by TCG */ +#define I2C_DEV_ADDR_DEFAULT 0x2E + +typedef struct { + struct timeval timeout; + struct mpsse_context *mpsse; +} PLATFORM_USERDATA; + +#endif /* TCTI_I2C_FTDI_H */ diff --git a/src/tss2-tcti/tcti-i2c-helper.c b/src/tss2-tcti/tcti-i2c-helper.c new file mode 100644 index 0000000..60e161b --- /dev/null +++ b/src/tss2-tcti/tcti-i2c-helper.c @@ -0,0 +1,868 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_i2c_helper.h" +#include "tss2_mu.h" +#include "tcti-common.h" +#include "tcti-i2c-helper.h" +#include "util/tss2_endian.h" +#define LOGMODULE tcti +#include "util/log.h" + +#define TIMEOUT_B 2000 /* The default timeout value as specified in the TCG spec. */ + +/* + * CRC-CCITT KERMIT with following parameters: + * + * Length : 16 bit + * Poly : 0x1021 + * Init : 0x0000 + * RefIn : False + * RefOut : False + * XorOut : 0x0000 + * Output for ASCII "123456789" : 0x2189 + */ +static const uint16_t crc16_kermit_lookup[256]= { + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +static uint16_t crc_ccitt (const uint8_t *buffer, int size) { + int i; + uint16_t result = 0; + + for (i = 0; i < size; i++) { + uint8_t j = buffer[i] ^ result; + result = crc16_kermit_lookup[j] ^ (result >> 8); + } + + return result; +} + +/* + * This function wraps the "up-cast" of the opaque TCTI context type to the + * type for the device TCTI context. The only safe-guard we have to ensure + * this operation is possible is the magic number for the device TCTI context. + * If passed a NULL context, or the magic number check fails, this function + * will return NULL. + */ +TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper_context_cast (TSS2_TCTI_CONTEXT *tcti_ctx) +{ + if (tcti_ctx != NULL && TSS2_TCTI_MAGIC (tcti_ctx) == TCTI_I2C_HELPER_MAGIC) { + return (TSS2_TCTI_I2C_HELPER_CONTEXT*)tcti_ctx; + } + return NULL; +} + +/* + * This function down-casts the device TCTI context to the common context + * defined in the tcti-common module. + */ +TSS2_TCTI_COMMON_CONTEXT* tcti_i2c_helper_down_cast (TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper) +{ + if (tcti_i2c_helper == NULL) { + return NULL; + } + return &tcti_i2c_helper->common; +} + +static inline TSS2_RC i2c_tpm_helper_delay_us (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, int microseconds) +{ + /* Sleep a specified amount of microseconds */ + if (ctx->platform.sleep_us == NULL) { + return ctx->platform.sleep_ms (ctx->platform.user_data, (microseconds < 1000) ? 1 : (microseconds / 1000)); + } else { + return ctx->platform.sleep_us (ctx->platform.user_data, microseconds); + } +} + +static inline TSS2_RC i2c_tpm_helper_delay_ms (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, int milliseconds) +{ + /* Sleep a specified amount of milliseconds */ + if (ctx->platform.sleep_ms == NULL) { + return ctx->platform.sleep_us (ctx->platform.user_data, milliseconds * 1000); + } else { + return ctx->platform.sleep_ms (ctx->platform.user_data, milliseconds); + } +} + +static inline TSS2_RC i2c_tpm_helper_start_timeout (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, int milliseconds) +{ + /* Start a timeout timer with the specified amount of milliseconds */ + return ctx->platform.start_timeout (ctx->platform.user_data, milliseconds); +} + +static inline TSS2_RC i2c_tpm_helper_timeout_expired(TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, bool *result) +{ + /* Check if the last started tiemout expired */ + return ctx->platform.timeout_expired (ctx->platform.user_data, result); +} + +static inline TSS2_RC i2c_tpm_helper_i2c_write (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, const void *data, size_t cnt) +{ + TSS2_RC rc; + int i = TCTI_I2C_HELPER_RETRY; + + do { + /* Perform I2C write with cnt bytes */ + rc = ctx->platform.i2c_write (ctx->platform.user_data, reg_addr, data, cnt); + if (rc == TSS2_RC_SUCCESS) { + if (ctx->guard_time_write) { + i2c_tpm_helper_delay_us (ctx, ctx->guard_time); + } + break; + } + + i2c_tpm_helper_delay_us (ctx, TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US); + } while (--i); + + return rc; +} + +static inline TSS2_RC i2c_tpm_helper_i2c_read (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, void *data, size_t cnt) +{ + TSS2_RC rc; + int i = TCTI_I2C_HELPER_RETRY; + + do { + /* Perform I2C read with cnt bytes */ + rc = ctx->platform.i2c_read (ctx->platform.user_data, reg_addr, data, cnt); + if (rc == TSS2_RC_SUCCESS) { + if (ctx->guard_time_read) { + i2c_tpm_helper_delay_us (ctx, ctx->guard_time); + } + break; + } + + i2c_tpm_helper_delay_us (ctx, TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US); + } while (--i); + + return rc; +} + +static inline void i2c_tpm_helper_platform_finalize (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + /* Free user_data and resources inside */ + if (ctx->platform.finalize) + ctx->platform.finalize (ctx->platform.user_data); +} + +static TSS2_RC check_platform_conf(TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf) +{ + + bool required_set = (platform_conf->sleep_ms || platform_conf->sleep_us) \ + && platform_conf->i2c_write \ + && platform_conf->i2c_read && platform_conf->start_timeout \ + && platform_conf->timeout_expired; + if (!required_set) { + LOG_ERROR("Expected sleep_us/sleep_ms, i2c_write, i2c_read, start_timeout and timeout_expired to be set."); + return TSS2_TCTI_RC_BAD_VALUE; + } + + return TSS2_RC_SUCCESS; +} + +static void i2c_tpm_helper_log_register_access (enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access, uint8_t reg_addr, const void *buffer, size_t cnt, char* err) +{ +#if MAXLOGLEVEL == LOGL_NONE + (void) access; + (void) reg_addr; + (void) buffer; + (void) cnt; + (void) err; +#else + /* Print register access debug information */ + char* access_str = (access == TCTI_I2C_HELPER_REGISTER_READ) ? "READ" : "WRITE"; + + if (err != NULL) { + LOG_ERROR ("%s register %#02x (%zu bytes) %s", access_str, reg_addr, cnt, err); + } else { +#if MAXLOGLEVEL < LOGL_TRACE + (void) buffer; +#else + LOGBLOB_TRACE (buffer, cnt, "%s register %#02x (%zu bytes)", access_str, reg_addr, cnt); +#endif + } +#endif +} + +static TSS2_RC i2c_tpm_sanity_check_read (uint8_t reg, uint8_t *buffer, size_t cnt) +{ + uint32_t zero_mask; + uint32_t value; + + switch (cnt) { + case sizeof (uint8_t): + value = buffer[0]; + break; + case sizeof (uint16_t): + value = LE_TO_HOST_16 (*((uint16_t *)buffer)); + break; + case sizeof (uint32_t): + value = LE_TO_HOST_32 (*((uint32_t *)buffer)); + break; + default: + return TSS2_RC_SUCCESS; + } + + switch (reg) { + case TCTI_I2C_HELPER_TPM_ACCESS_REG: + zero_mask = TCTI_I2C_HELPER_TPM_ACCESS_ZERO; + break; + case TCTI_I2C_HELPER_TPM_STS_REG: + zero_mask = TCTI_I2C_HELPER_TPM_STS_ZERO; + break; + case TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG: + zero_mask = TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_ZERO; + break; + default: + return TSS2_RC_SUCCESS; + } + + if (value & zero_mask) { + LOG_ERROR ("TPM I2C read of register 0x%02x failed sanity check", reg); + return TSS2_TCTI_RC_IO_ERROR; + } + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC i2c_tpm_helper_read_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, void *buffer, size_t cnt) +{ + TSS2_RC rc; + enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access = TCTI_I2C_HELPER_REGISTER_READ; + + /* Read register */ + rc = i2c_tpm_helper_i2c_read (ctx, reg_addr, buffer, cnt); + if (rc != TSS2_RC_SUCCESS) { + i2c_tpm_helper_log_register_access (access, reg_addr, NULL, cnt, "failed in transfer"); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Sanity check, check that the 0 bits of the TPM_STS register are indeed 0s*/ + rc = i2c_tpm_sanity_check_read (reg_addr, buffer, cnt); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + + /* Print debug information and return success */ + i2c_tpm_helper_log_register_access (access, reg_addr, buffer, cnt, NULL); + return TSS2_RC_SUCCESS; +} + +static TSS2_RC i2c_tpm_helper_write_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t reg_addr, const void *buffer, size_t cnt) +{ + TSS2_RC rc; + enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE access = TCTI_I2C_HELPER_REGISTER_WRITE; + + /* Write register */ + rc = i2c_tpm_helper_i2c_write (ctx, reg_addr, buffer, cnt); + if (rc != TSS2_RC_SUCCESS) { + i2c_tpm_helper_log_register_access (access, reg_addr, buffer, cnt, "failed in transfer"); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Print debug information and return success */ + i2c_tpm_helper_log_register_access (access, reg_addr, buffer, cnt, NULL); + return TSS2_RC_SUCCESS; +} + +static uint8_t i2c_tpm_helper_read_access_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + uint8_t access = 0; + i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_ACCESS_REG, &access, sizeof(access)); + return access; +} + +static void i2c_tpm_helper_write_access_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t access_bit) +{ + /* Writes to access register can set only 1 bit at a time */ + if (access_bit & (access_bit - 1)) { + LOG_ERROR ("Writes to access register can set only 1 bit at a time."); + } else { + i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_ACCESS_REG, &access_bit, sizeof(access_bit)); + } +} + +static uint32_t i2c_tpm_helper_read_sts_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + uint32_t status = 0; + i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_STS_REG, &status, sizeof(status)); + return LE_TO_HOST_32 (status); +} + +static void i2c_tpm_helper_write_sts_reg (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint32_t status) +{ + status = HOST_TO_LE_32 (status); + i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_STS_REG, &status, sizeof (status)); +} + +static uint32_t i2c_tpm_helper_get_burst_count (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + uint32_t status = i2c_tpm_helper_read_sts_reg (ctx); + return (status & TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_MASK) >> TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_SHIFT; +} + +static inline size_t i2c_tpm_helper_size_t_min (size_t a, size_t b) { + if (a < b) { + return a; + } + return b; +} + +static inline uint32_t i2c_tpm_helper_read_be32 (const void *src) +{ + const uint8_t *s = src; + return (((uint32_t)s[0]) << 24) | (((uint32_t)s[1]) << 16) | (((uint32_t)s[2]) << 8) | (((uint32_t)s[3]) << 0); +} + +static TSS2_RC i2c_tpm_helper_claim_locality (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + uint8_t access; + access = i2c_tpm_helper_read_access_reg (ctx); + + /* Check if locality 0 is active */ + if (access & TCTI_I2C_HELPER_TPM_ACCESS_ACTIVE_LOCALITY) { + LOG_DEBUG ("Locality 0 is already active, status: %#x", access); + return TSS2_RC_SUCCESS; + } + + /* Request locality 0 */ + i2c_tpm_helper_write_access_reg (ctx, TCTI_I2C_HELPER_TPM_ACCESS_REQUEST_USE); + access = i2c_tpm_helper_read_access_reg (ctx); + if (access & (TCTI_I2C_HELPER_TPM_ACCESS_VALID | TCTI_I2C_HELPER_TPM_ACCESS_ACTIVE_LOCALITY)) { + LOG_DEBUG ("Claimed locality 0"); + return TSS2_RC_SUCCESS; + } + + LOG_ERROR ("Failed to claim locality 0, status: %#x", access); + return TSS2_TCTI_RC_IO_ERROR; +} + +static TSS2_RC i2c_tpm_helper_init_guard_time (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + TSS2_RC rc; + uint32_t i2c_caps; + + ctx->guard_time_read = true; + ctx->guard_time_write = true; + ctx->guard_time = TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US; + + rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG, &i2c_caps, sizeof (i2c_caps)); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to read TPM_I2C_INTERFACE_CAPABILITY register"); + return rc; + } + + i2c_caps = LE_TO_HOST_32 (i2c_caps); + + ctx->guard_time_read = (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_RR_MASK) || + (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_RW_MASK); + ctx->guard_time_write = (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_WR_MASK) || + (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_WW_MASK); + ctx->guard_time = (i2c_caps & TCTI_I2C_HELPER_TPM_GUARD_TIME_MASK) >> + TCTI_I2C_HELPER_TPM_GUARD_TIME_SHIFT; + + return TSS2_RC_SUCCESS; +} + +static TSS2_RC i2c_tpm_helper_enable_crc (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx) +{ + TSS2_RC rc; + uint8_t crc_enable; + + rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG, &crc_enable, sizeof (crc_enable)); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + + if (crc_enable == 1) { + return TSS2_RC_SUCCESS; + } + + crc_enable = 1; + return i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG, &crc_enable, sizeof (crc_enable)); +} + +static TSS2_RC i2c_tpm_helper_wait_for_status (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint32_t status_mask, uint32_t status_expected, int32_t timeout) +{ + TSS2_RC rc; + uint32_t status; + bool blocking = (timeout == TSS2_TCTI_TIMEOUT_BLOCK); + if (!blocking) { + rc = i2c_tpm_helper_start_timeout (ctx, timeout); + return_if_error(rc, "i2c_tpm_helper_start_timeout"); + } + + /* Wait for the expected status with or without timeout */ + bool is_timeout_expired = false; + do { + status = i2c_tpm_helper_read_sts_reg (ctx); + /* Return success on expected status */ + if ((status & status_mask) == status_expected) { + return TSS2_RC_SUCCESS; + } + /* Delay next poll by 8ms to avoid spamming the TPM */ + rc = i2c_tpm_helper_delay_ms (ctx, 8); + return_if_error (rc, "i2c_tpm_helper_delay_ms"); + + rc = i2c_tpm_helper_timeout_expired (ctx, &is_timeout_expired); + return_if_error (rc, "i2c_tpm_helper_timeout_expired"); + } while (blocking || !is_timeout_expired); + + /* Timed out */ + return TSS2_TCTI_RC_TRY_AGAIN; +} + +static TSS2_RC i2c_tpm_helper_verify_crc (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, const uint8_t* buffer, size_t size) +{ + (void) buffer; + (void) size; + TSS2_RC rc; + uint16_t crc_tpm = 0; + uint16_t crc_host = 0; + + rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_CSUM_REG, &crc_tpm, sizeof (crc_tpm)); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + + crc_tpm = LE_TO_HOST_16 (crc_tpm); + /* Reflect crc result, regardless of host endianness */ + crc_tpm = ((crc_tpm >> 8) & 0xFFu) | ((crc_tpm << 8) & 0xFF00u); + crc_host = crc_ccitt (buffer, size); + + if (crc_tpm == crc_host) { + return TSS2_RC_SUCCESS; + } + + return TSS2_TCTI_RC_IO_ERROR; +} + +static void i2c_tpm_helper_fifo_transfer (TSS2_TCTI_I2C_HELPER_CONTEXT* ctx, uint8_t* transfer_buffer, size_t transfer_size, enum TCTI_I2C_HELPER_FIFO_TRANSFER_DIRECTION direction) +{ + size_t transaction_size; + size_t burst_count; + size_t handled_so_far = 0; + + do { + do { + /* Can be zero when TPM is busy */ + burst_count = i2c_tpm_helper_get_burst_count (ctx); + } while (!burst_count); + + transaction_size = transfer_size - handled_so_far; + transaction_size = i2c_tpm_helper_size_t_min (transaction_size, burst_count); + + if (direction == TCTI_I2C_HELPER_FIFO_RECEIVE){ + i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, (void*)(transfer_buffer + handled_so_far), transaction_size); + } else { + i2c_tpm_helper_write_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, (const void*)(transfer_buffer + handled_so_far), transaction_size); + } + + handled_so_far += transaction_size; + + } while (handled_so_far != transfer_size); +} + +TSS2_RC tcti_i2c_helper_transmit (TSS2_TCTI_CONTEXT *tcti_ctx, size_t size, const uint8_t *cmd_buf) +{ + TSS2_RC rc; + TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_ctx); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + tpm_header_t header; + + if (tcti_i2c_helper == NULL) { + return TSS2_TCTI_RC_BAD_CONTEXT; + } + TSS2_TCTI_I2C_HELPER_CONTEXT* ctx = tcti_i2c_helper; + + rc = tcti_common_transmit_checks (tcti_common, cmd_buf, TCTI_I2C_HELPER_MAGIC); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + rc = header_unmarshal (cmd_buf, &header); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + if (header.size != size) { + LOG_ERROR("Buffer size parameter: %zu, and TPM2 command header size " + "field: %" PRIu32 " disagree.", size, header.size); + return TSS2_TCTI_RC_BAD_VALUE; + } + + LOGBLOB_DEBUG (cmd_buf, size, "Sending command with TPM_CC %#"PRIx32" and size %" PRIu32, + header.code, header.size); + + /* Tell TPM to expect command */ + i2c_tpm_helper_write_sts_reg(ctx, TCTI_I2C_HELPER_TPM_STS_COMMAND_READY); + + /* Wait until ready bit is set by TPM device */ + uint32_t expected_status_bits = TCTI_I2C_HELPER_TPM_STS_COMMAND_READY; + rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed waiting for TPM to become ready"); + return rc; + } + + /* Send command */ + i2c_tpm_helper_fifo_transfer (ctx, (void*)cmd_buf, size, TCTI_I2C_HELPER_FIFO_TRANSMIT); + + /* Verify CRC */ + rc = i2c_tpm_helper_verify_crc (ctx, cmd_buf, size); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("CRC mismatch for command"); + return rc; + } + + /* Tell TPM to start processing the command */ + i2c_tpm_helper_write_sts_reg (ctx, TCTI_I2C_HELPER_TPM_STS_GO); + + tcti_common->state = TCTI_STATE_RECEIVE; + return TSS2_RC_SUCCESS; +} + +TSS2_RC tcti_i2c_helper_receive (TSS2_TCTI_CONTEXT* tcti_context, size_t *response_size, unsigned char *response_buffer, int32_t timeout) +{ + TSS2_RC rc; + TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); + TSS2_TCTI_COMMON_CONTEXT* tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + + if (tcti_i2c_helper == NULL) { + return TSS2_TCTI_RC_BAD_CONTEXT; + } + + rc = tcti_common_receive_checks (tcti_common, response_size, TCTI_I2C_HELPER_MAGIC); + if (rc != TSS2_RC_SUCCESS) { + return rc; + } + + /* Use ctx as a shorthand for tcti_i2c_helper */ + TSS2_TCTI_I2C_HELPER_CONTEXT* ctx = tcti_i2c_helper; + + /* Expected status bits for valid status and data availabe */ + uint32_t expected_status_bits = TCTI_I2C_HELPER_TPM_STS_VALID | TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL; + + /* Check if we already have received the header */ + if (tcti_common->header.size == 0) { + /* Wait for response to be ready */ + rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, timeout); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed waiting for status"); + /* Return rc from wait_for_status(). May be TRY_AGAIN after timeout. */ + return rc; + } + + /* Read only response header into context header buffer */ + rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, ctx->header, TCTI_I2C_HELPER_RESP_HEADER_SIZE); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed reading response header"); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Find out the total payload size, skipping the two byte tag and update tcti_common */ + tcti_common->header.size = i2c_tpm_helper_read_be32 (ctx->header + 2); + LOG_TRACE ("Read response size from response header: %" PRIu32 " bytes", tcti_common->header.size); + } + + /* Check if response size is requested */ + if (response_buffer == NULL) { + *response_size = tcti_common->header.size; + LOG_TRACE ("Caller requested response size. Returning size of %zu bytes", *response_size); + return TSS2_RC_SUCCESS; + } + + /* Check if response fits in buffer and update response size */ + if (tcti_common->header.size > *response_size) { + LOG_ERROR ("TPM response too long (%" PRIu32 " bytes)", tcti_common->header.size); + return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; + } + *response_size = tcti_common->header.size; + + /* Receive the TPM response */ + LOG_TRACE ("Reading response of size %" PRIu32, tcti_common->header.size); + + /* Copy already received header into response buffer */ + memcpy (response_buffer, ctx->header, TCTI_I2C_HELPER_RESP_HEADER_SIZE); + + /* Read all but the last byte in the FIFO */ + size_t bytes_to_go = tcti_common->header.size - 1 - TCTI_I2C_HELPER_RESP_HEADER_SIZE; + i2c_tpm_helper_fifo_transfer (ctx, response_buffer + TCTI_I2C_HELPER_RESP_HEADER_SIZE, bytes_to_go, TCTI_I2C_HELPER_FIFO_RECEIVE); + + /* Verify that there is still data to read */ + uint32_t status = i2c_tpm_helper_read_sts_reg (ctx); + if ((status & expected_status_bits) != expected_status_bits) { + LOG_ERROR ("Unexpected intermediate status %#"PRIx32,status); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Read the last byte */ + rc = i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG, response_buffer + tcti_common->header.size - 1, 1); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Verify that there is no more data available */ + status = i2c_tpm_helper_read_sts_reg (ctx); + if ((status & expected_status_bits) != TCTI_I2C_HELPER_TPM_STS_VALID) { + LOG_ERROR ("Unexpected final status %#"PRIx32, status); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Verify CRC */ + rc = i2c_tpm_helper_verify_crc (ctx, response_buffer, *response_size); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("CRC mismatch for response"); + return rc; + } + + LOGBLOB_DEBUG (response_buffer, tcti_common->header.size, "Response buffer received:"); + + /* Set the TPM back to idle state */ + i2c_tpm_helper_write_sts_reg(ctx, TCTI_I2C_HELPER_TPM_STS_COMMAND_READY); + + tcti_common->header.size = 0; + tcti_common->state = TCTI_STATE_TRANSMIT; + + return TSS2_RC_SUCCESS; +} + +void tcti_i2c_helper_finalize (TSS2_TCTI_CONTEXT* tcti_context) +{ + TSS2_TCTI_I2C_HELPER_CONTEXT *tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); + TSS2_TCTI_COMMON_CONTEXT *tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + + if (tcti_i2c_helper == NULL) { + return; + } + tcti_common->state = TCTI_STATE_FINAL; + + /* Free platform struct user data and resources inside */ + i2c_tpm_helper_platform_finalize (tcti_i2c_helper); +} + +TSS2_RC tcti_i2c_helper_cancel (TSS2_TCTI_CONTEXT* tcti_context) +{ + (void)(tcti_context); + return TSS2_TCTI_RC_NOT_IMPLEMENTED; +} + +TSS2_RC tcti_i2c_helper_get_poll_handles (TSS2_TCTI_CONTEXT* tcti_context, TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles) +{ + (void)(tcti_context); + (void)(handles); + (void)(num_handles); + return TSS2_TCTI_RC_NOT_IMPLEMENTED; +} + +TSS2_RC tcti_i2c_helper_set_locality (TSS2_TCTI_CONTEXT* tcti_context, uint8_t locality) +{ + (void)(tcti_context); + (void)(locality); + return TSS2_TCTI_RC_NOT_IMPLEMENTED; +} + +TSS2_RC Tss2_Tcti_I2c_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, TSS2_TCTI_I2C_HELPER_PLATFORM *platform_conf) +{ + TSS2_RC rc; + TSS2_TCTI_I2C_HELPER_CONTEXT* tcti_i2c_helper; + TSS2_TCTI_COMMON_CONTEXT* tcti_common; + + if (!size) { + return TSS2_TCTI_RC_BAD_VALUE; + } + + /* Check if context size is requested */ + if (tcti_context == NULL) { + *size = sizeof (TSS2_TCTI_I2C_HELPER_CONTEXT); + return TSS2_RC_SUCCESS; + } + + if (!platform_conf) { + return TSS2_TCTI_RC_BAD_VALUE; + } + + if (*size < sizeof (TSS2_TCTI_I2C_HELPER_CONTEXT)) { + return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; + } + + /* Init TCTI context */ + TSS2_TCTI_MAGIC (tcti_context) = TCTI_I2C_HELPER_MAGIC; + TSS2_TCTI_VERSION (tcti_context) = TCTI_VERSION; + TSS2_TCTI_TRANSMIT (tcti_context) = tcti_i2c_helper_transmit; + TSS2_TCTI_RECEIVE (tcti_context) = tcti_i2c_helper_receive; + TSS2_TCTI_FINALIZE (tcti_context) = tcti_i2c_helper_finalize; + TSS2_TCTI_CANCEL (tcti_context) = tcti_i2c_helper_cancel; + TSS2_TCTI_GET_POLL_HANDLES (tcti_context) = tcti_i2c_helper_get_poll_handles; + TSS2_TCTI_SET_LOCALITY (tcti_context) = tcti_i2c_helper_set_locality; + TSS2_TCTI_MAKE_STICKY (tcti_context) = tcti_make_sticky_not_implemented; + + /* Init I2C TCTI context */ + tcti_i2c_helper = tcti_i2c_helper_context_cast (tcti_context); + tcti_common = tcti_i2c_helper_down_cast (tcti_i2c_helper); + tcti_common->state = TCTI_STATE_TRANSMIT; + memset (&tcti_common->header, 0, sizeof (tcti_common->header)); + tcti_common->locality = 0; + + rc = check_platform_conf (platform_conf); + return_if_error (rc, "platform_conf invalid"); + + /* Copy platform struct into context */ + tcti_i2c_helper->platform = *platform_conf; + + /* Probe TPM */ + TSS2_TCTI_I2C_HELPER_CONTEXT* ctx = tcti_i2c_helper; + LOG_DEBUG ("Probing TPM..."); + uint32_t did_vid = 0; + for (int retries = 100; retries > 0; retries--) { + /* In case of failed read div_vid is set to zero */ + i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_DID_VID_REG, &did_vid, sizeof(did_vid)); + if (did_vid != 0) { + did_vid = LE_TO_HOST_32 (did_vid); + break; + } + /* TPM might be resetting, let's retry in a bit */ + rc = i2c_tpm_helper_delay_ms (ctx, 10); + return_if_error (rc, "i2c_tpm_helper_delay_ms"); + } + if (did_vid == 0) { + LOG_ERROR ("Probing TPM failed"); + return TSS2_TCTI_RC_IO_ERROR; + } + LOG_DEBUG ("Probing TPM successful"); + + /* Init guard time */ + LOG_DEBUG ("Initializing guard time"); + rc = i2c_tpm_helper_init_guard_time (ctx); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Claim locality */ + LOG_DEBUG ("Claiming TPM locality"); + rc = i2c_tpm_helper_claim_locality (ctx); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Enable Data Checksum */ + LOG_DEBUG ("Enable Data Checksum"); + rc = i2c_tpm_helper_enable_crc (ctx); + if (rc != TSS2_RC_SUCCESS) { + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Wait up to TIMEOUT_B for TPM to become ready */ + LOG_DEBUG ("Waiting for TPM to become ready..."); + uint32_t expected_status_bits = TCTI_I2C_HELPER_TPM_STS_COMMAND_READY; + rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + if (rc == TSS2_TCTI_RC_TRY_AGAIN) { + /* + * TPM did not auto transition into ready state, + * write 1 to commandReady to start the transition. + */ + i2c_tpm_helper_write_sts_reg (ctx, TCTI_I2C_HELPER_TPM_STS_COMMAND_READY); + rc = i2c_tpm_helper_wait_for_status (ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + } + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed waiting for TPM to become ready"); + return rc; + } + + LOG_DEBUG ("TPM is ready"); + + /* Get rid */ + uint8_t rid = 0; + i2c_tpm_helper_read_reg (ctx, TCTI_I2C_HELPER_TPM_RID_REG, &rid, sizeof(rid)); + +#if MAXLOGLEVEL >= LOGL_INFO + /* Print device details */ + uint16_t vendor_id, device_id, revision; + vendor_id = did_vid & 0xffff; + device_id = did_vid >> 16; + revision = rid; + LOG_INFO ("Connected to TPM with vid:did:rid of %4.4x:%4.4x:%2.2x", vendor_id, device_id, revision); +#endif + + return TSS2_RC_SUCCESS; +} + +static const TSS2_TCTI_INFO tss2_tcti_i2c_helper_info = { + .version = TCTI_VERSION, + .name = "tcti-i2c-helper", + .description = "Platform independent TCTI for communication with TPMs over I2C.", + .config_help = "TSS2_TCTI_I2C_HELPER_PLATFORM struct containing platform methods. See tss2_tcti_i2c_helper.h for more information.", + + /* + * The Tss2_Tcti_I2c_Helper_Init method has a different signature than required by .init due too + * our custom platform_conf parameter, so we can't expose it here and it has to be used directly. + */ + .init = NULL, +}; + +const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) +{ + return &tss2_tcti_i2c_helper_info; +} diff --git a/src/tss2-tcti/tcti-i2c-helper.h b/src/tss2-tcti/tcti-i2c-helper.h new file mode 100644 index 0000000..b6b05e1 --- /dev/null +++ b/src/tss2-tcti/tcti-i2c-helper.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifndef TCTI_I2C_HELPER_H +#define TCTI_I2C_HELPER_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "tcti-common.h" + +#define TCTI_I2C_HELPER_MAGIC 0x392452ED67A5D511ULL + +#define TCTI_I2C_HELPER_RESP_HEADER_SIZE 6 + +typedef struct { + TSS2_TCTI_COMMON_CONTEXT common; + TSS2_TCTI_I2C_HELPER_PLATFORM platform; + bool guard_time_read; + bool guard_time_write; + int guard_time; + char header[TCTI_I2C_HELPER_RESP_HEADER_SIZE]; +} TSS2_TCTI_I2C_HELPER_CONTEXT; + +#define TCTI_I2C_HELPER_RETRY 50 +#define TCTI_I2C_HELPER_DEFAULT_GUARD_TIME_US 250 + +#define TCTI_I2C_HELPER_TPM_ACCESS_REG 0x04 +#define TCTI_I2C_HELPER_TPM_STS_REG 0x18 +#define TCTI_I2C_HELPER_TPM_DATA_FIFO_REG 0x24 +#define TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG 0x30 +#define TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG 0x40 +#define TCTI_I2C_HELPER_TPM_DATA_CSUM_REG 0x44 +#define TCTI_I2C_HELPER_TPM_DID_VID_REG 0x48 +#define TCTI_I2C_HELPER_TPM_RID_REG 0x4C + +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_SR_MASK 0x40000000 +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_RR_MASK 0x00100000 +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_RW_MASK 0x00080000 +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_WR_MASK 0x00040000 +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_WW_MASK 0x00020000 +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_MASK 0x0001FE00 +#define TCTI_I2C_HELPER_TPM_BURST_COUNT_STATIC_MASK 0x20000000 +#define TCTI_I2C_HELPER_TPM_GUARD_TIME_SHIFT 9 + +#define TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_ZERO 0x80000000 +#define TCTI_I2C_HELPER_TPM_STS_ZERO 0x23 +#define TCTI_I2C_HELPER_TPM_ACCESS_ZERO 0x48 + +enum TCTI_I2C_HELPER_TPM_ACCESS { + TCTI_I2C_HELPER_TPM_ACCESS_VALID = (1 << 7), + TCTI_I2C_HELPER_TPM_ACCESS_ACTIVE_LOCALITY = (1 << 5), + TCTI_I2C_HELPER_TPM_ACCESS_REQUEST_USE = (1 << 1) +}; + +enum TCTI_I2C_HELPER_TPM_STATUS { + TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_SHIFT = 8, + TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_MASK = (0xFFFF << TCTI_I2C_HELPER_TPM_STS_BURST_COUNT_SHIFT), + TCTI_I2C_HELPER_TPM_STS_VALID = (1 << 7), + TCTI_I2C_HELPER_TPM_STS_COMMAND_READY = (1 << 6), + TCTI_I2C_HELPER_TPM_STS_GO = (1 << 5), + TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL = (1 << 4), + TCTI_I2C_HELPER_TPM_STS_DATA_EXPECT = (1 << 3) +}; + +enum TCTI_I2C_HELPER_FIFO_TRANSFER_DIRECTION { + TCTI_I2C_HELPER_FIFO_TRANSMIT = 0, + TCTI_I2C_HELPER_FIFO_RECEIVE = 1 +}; + +enum TCTI_I2C_HELPER_REGISTER_ACCESS_TYPE { + TCTI_I2C_HELPER_REGISTER_WRITE = 0, + TCTI_I2C_HELPER_REGISTER_READ = 1 +}; + +#endif /* TCTI_I2C_HELPER_H */ diff --git a/src/tss2-tcti/tcti-libtpms.c b/src/tss2-tcti/tcti-libtpms.c index 922a440..328d3e8 100644 --- a/src/tss2-tcti/tcti-libtpms.c +++ b/src/tss2-tcti/tcti-libtpms.c @@ -354,6 +354,20 @@ tcti_libtpms_down_cast(TSS2_TCTI_LIBTPMS_CONTEXT *tcti_libtpms) return &tcti_libtpms->common; } +TSS2_RC +Tss2_Tcti_Libtpms_Reset(TSS2_TCTI_CONTEXT *tcti_ctx) +{ + TSS2_RC rc; + int ret; + TSS2_TCTI_LIBTPMS_CONTEXT *tcti_libtpms = tcti_libtpms_context_cast(tcti_ctx); + + LIBTPMS_API_CALL(fail, tcti_libtpms, TPM_IO_TpmEstablished_Reset); + rc = TSS2_RC_SUCCESS; + +fail: + return rc; +} + /* * Transmits and gets the response. The response buffer was allocated by * libtpms, is referenced by the libtpms TCTI context and needs to be freed once @@ -370,6 +384,8 @@ tcti_libtpms_transmit( tpm_header_t header; TSS2_RC rc; TPM_RESULT ret; + uint32_t resp_size; + uint32_t respbufsize; rc = tcti_common_transmit_checks(tcti_common, cmd_buf, TCTI_LIBTPMS_MAGIC); if (rc != TSS2_RC_SUCCESS) { @@ -386,11 +402,16 @@ tcti_libtpms_transmit( } LOGBLOB_DEBUG(cmd_buf, size, "Sending command with TPM_CC 0x%" PRIx32, header.size); + resp_size = (uint32_t) tcti_libtpms->response_len; + respbufsize = (uint32_t) tcti_libtpms->response_buffer_len; LIBTPMS_API_CALL(fail, tcti_libtpms, TPMLIB_Process, &tcti_libtpms->response_buffer, - (uint32_t *) &tcti_libtpms->response_len, - (uint32_t *) &tcti_libtpms->response_buffer_len, + (uint32_t *) &resp_size, + (uint32_t *) &respbufsize, (uint8_t *) cmd_buf, size); + tcti_libtpms->response_len = resp_size; + tcti_libtpms->response_buffer_len = respbufsize; + rc = tcti_libtpms_store_state(tcti_libtpms); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR("Failed to store state file"); @@ -617,6 +638,12 @@ tcti_libtpms_dl(TSS2_TCTI_LIBTPMS_CONTEXT *tcti_libtpms) goto cleanup_dl; } + tcti_libtpms->TPM_IO_TpmEstablished_Reset = dlsym(tcti_libtpms->libtpms, "TPM_IO_TpmEstablished_Reset"); + if (tcti_libtpms->TPM_IO_TpmEstablished_Reset == NULL) { + LOG_ERROR("Could not resolve libtpms symbol TPM_IO_TpmEstablished_Reset(): %s", dlerror()); + goto cleanup_dl; + } + return TPM2_RC_SUCCESS; cleanup_dl: @@ -783,12 +810,19 @@ Tss2_Tcti_Libtpms_Init( if (conf == NULL || strlen(conf) == 0) { tcti_libtpms->state_path = NULL; } else { +#ifdef __FreeBSD__ + // mremap() on FreeBSD is a stub returning -1/ENOMEM + // this could be fixed with a munmap()/mmap() workaround + LOG_ERROR("Libtpms state files are not supported on FreeBSD. Try an empty conf string."); + return TSS2_TCTI_RC_BAD_VALUE; +#else tcti_libtpms->state_path = strdup(conf); if (tcti_libtpms->state_path == NULL) { LOG_ERROR("Out of memory."); rc = TSS2_TCTI_RC_MEMORY; goto cleanup_dl; } +#endif } rc = tcti_libtpms_map_state_file(tcti_libtpms); @@ -802,8 +836,8 @@ Tss2_Tcti_Libtpms_Init( struct libtpms_callbacks callbacks = { .sizeOfStruct = sizeof(struct libtpms_callbacks), .tpm_nvram_init = tcti_libtpms_cb_nvram_init, - .tpm_nvram_loaddata = tcti_libtpms_cb_nvram_loaddata, - .tpm_nvram_storedata = tcti_libtpms_cb_nvram_storedata, + .tpm_nvram_loaddata = NULL, + .tpm_nvram_storedata = NULL, .tpm_nvram_deletename = tcti_libtpms_cb_nvram_deletename, .tpm_io_init = tcti_libtpms_cb_io_init, .tpm_io_getlocality = tcti_libtpms_cb_io_getlocality, @@ -840,7 +874,7 @@ Tss2_Tcti_Libtpms_Init( } /* public info structure */ -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_libtpms_info = { .version = TCTI_VERSION, .name = "tcti-libtpms", .description = "TCTI module for communication with the libtpms library.", @@ -851,5 +885,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO * Tss2_Tcti_Info(void) { - return &tss2_tcti_info; + return &tss2_tcti_libtpms_info; } diff --git a/src/tss2-tcti/tcti-libtpms.h b/src/tss2-tcti/tcti-libtpms.h index c811548..63f09dc 100644 --- a/src/tss2-tcti/tcti-libtpms.h +++ b/src/tss2-tcti/tcti-libtpms.h @@ -10,14 +10,15 @@ #include #include +#include #include #include #include +#include #include #include "tcti-common.h" -#include "util/io.h" #include "util/aux_util.h" #define TCTI_LIBTPMS_MAGIC 0x49E299A554504D32ULL @@ -34,6 +35,7 @@ typedef struct { TPM_RESULT (*TPMLIB_Process)(unsigned char **, uint32_t *, uint32_t *, unsigned char *, uint32_t); TPM_RESULT (*TPMLIB_SetState)(enum TPMLIB_StateType, const unsigned char *, uint32_t); void (*TPMLIB_Terminate)(void); + TPM_RESULT (*TPM_IO_TpmEstablished_Reset)(void); uint8_t *response_buffer; size_t response_buffer_len; size_t response_len; diff --git a/src/tss2-tcti/tcti-mssim.c b/src/tss2-tcti/tcti-mssim.c index 6c9680f..a0afa9f 100644 --- a/src/tss2-tcti/tcti-mssim.c +++ b/src/tss2-tcti/tcti-mssim.c @@ -284,7 +284,12 @@ tcti_mssim_get_poll_handles ( *num_handles = 1; if (handles != NULL) { #ifdef _WIN32 - *handles = tcti_mssim->tpm_sock; + HANDLE hEvent = WSACreateEvent(); + if (WSAEventSelect(tcti_mssim->tpm_sock, hEvent, FD_READ | FD_WRITE)) { + WSACloseEvent(hEvent); + return TSS2_TCTI_RC_BAD_VALUE; + } + *handles = hEvent; #else handles->fd = tcti_mssim->tpm_sock; handles->events = POLLIN | POLLOUT; @@ -659,7 +664,7 @@ Tss2_Tcti_Mssim_Init ( } /* public info structure */ -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_mssim_info = { .version = TCTI_VERSION, .name = "tcti-socket", .description = "TCTI module for communication with the Microsoft TPM2 Simulator.", @@ -670,5 +675,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_mssim_info; } diff --git a/src/tss2-tcti/tcti-mssim.h b/src/tss2-tcti/tcti-mssim.h index c1001d7..e2aacc3 100644 --- a/src/tss2-tcti/tcti-mssim.h +++ b/src/tss2-tcti/tcti-mssim.h @@ -10,7 +10,7 @@ #include #include "tcti-common.h" -#include "util/io.h" +#include "util-io/io.h" /* * longest possible conf string: diff --git a/src/tss2-tcti/tcti-pcap-builder.c b/src/tss2-tcti/tcti-pcap-builder.c index 6aa2dec..f6b6af7 100644 --- a/src/tss2-tcti/tcti-pcap-builder.c +++ b/src/tss2-tcti/tcti-pcap-builder.c @@ -20,7 +20,7 @@ #include "tss2_common.h" #include "tcti-pcap-builder.h" -#include "util/io.h" +#include "util-io/io.h" #define LOGMODULE tcti #include "util/log.h" diff --git a/src/tss2-tcti/tcti-pcap.c b/src/tss2-tcti/tcti-pcap.c index fbb0cd7..b0008a3 100644 --- a/src/tss2-tcti/tcti-pcap.c +++ b/src/tss2-tcti/tcti-pcap.c @@ -287,7 +287,7 @@ Tss2_Tcti_Pcap_Init ( } /* public info structure */ -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_pcap_info = { .version = TCTI_VERSION, .name = "tcti-pcap", .description = "TCTI module for logging TPM commands in pcapng format.", @@ -298,5 +298,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_pcap_info; } diff --git a/src/tss2-tcti/tcti-spi-ftdi.c b/src/tss2-tcti/tcti-spi-ftdi.c new file mode 100644 index 0000000..1a14196 --- /dev/null +++ b/src/tss2-tcti/tcti-spi-ftdi.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tss2_tcti.h" +#include "tcti-spi-ftdi.h" +#include "tss2_tcti_spi_ftdi.h" +#include "tcti-spi-helper.h" +#include "tss2_mu.h" +#define LOGMODULE tcti +#include "util/log.h" + +TSS2_RC +platform_sleep_ms (void *user_data, int32_t milliseconds) +{ + (void) user_data; + struct timeval tv = {milliseconds/1000, (milliseconds%1000)*1000}; + select (0, NULL, NULL, NULL, &tv); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_start_timeout (void *user_data, int32_t milliseconds) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + memset (&platform_data->timeout, 0, sizeof (struct timeval)); + + if (gettimeofday (&platform_data->timeout, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + platform_data->timeout.tv_sec += (milliseconds/1000); + platform_data->timeout.tv_usec += (milliseconds%1000)*1000; + if (platform_data->timeout.tv_usec > 999999) { + platform_data->timeout.tv_sec++; + platform_data->timeout.tv_usec -= 1000000; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_timeout_expired (void *user_data, bool *is_timeout_expired) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + struct timeval now; + if (gettimeofday (&now, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + if (now.tv_sec > platform_data->timeout.tv_sec) { + *is_timeout_expired = true; + } else if ((now.tv_sec == platform_data->timeout.tv_sec) + && (now.tv_usec > platform_data->timeout.tv_usec)) { + *is_timeout_expired = true; + } else { + *is_timeout_expired = false; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_spi_transfer (void *user_data, const void *data_out, void *data_in, size_t cnt) +{ + int length = cnt; + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct mpsse_context *mpsse = platform_data->mpsse; + char *data = NULL; + + if (Start (mpsse) != MPSSE_OK) { + return TSS2_TCTI_RC_IO_ERROR; + } + + if ((data = Transfer (mpsse, (char *)data_out, length)) == NULL) { + Stop (mpsse); + return TSS2_TCTI_RC_IO_ERROR; + } + + if (data_in != NULL) { + memcpy (data_in, (unsigned char *)data, length); + } + + free (data); + + if (Stop (mpsse) != MPSSE_OK) { + return TSS2_TCTI_RC_IO_ERROR; + } + + return TSS2_RC_SUCCESS; +} + +void +platform_finalize (void *user_data) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct mpsse_context *mpsse = platform_data->mpsse; + + if (mpsse != NULL) { + Close (mpsse); + } + + free (platform_data); +} + +TSS2_RC +create_tcti_spi_ftdi_platform (TSS2_TCTI_SPI_HELPER_PLATFORM *platform) +{ + PLATFORM_USERDATA *platform_data = malloc (sizeof (PLATFORM_USERDATA)); + struct mpsse_context **mpsse = &platform_data->mpsse; + + if (platform_data == NULL) { + return TSS2_BASE_RC_MEMORY; + } + + memset (platform_data, 0, sizeof (PLATFORM_USERDATA)); + + if ((*mpsse = MPSSE (SPI0, FIFTEEN_MHZ, MSB)) == NULL ) + { + goto error; + } + + platform->user_data = platform_data; + platform->sleep_ms = platform_sleep_ms; + platform->start_timeout = platform_start_timeout; + platform->timeout_expired = platform_timeout_expired; + platform->spi_acquire = NULL; + platform->spi_release = NULL; + platform->spi_transfer = platform_spi_transfer; + platform->finalize = platform_finalize; + + return TSS2_RC_SUCCESS; + +error: + platform_finalize ((void *) platform_data); + return TSS2_BASE_RC_IO_ERROR; +} + +TSS2_RC +Tss2_Tcti_Spi_Ftdi_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, const char* config) +{ + (void) config; + TSS2_RC ret = 0; + TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = {0}; + + if (tcti_context == NULL) { + return Tss2_Tcti_Spi_Helper_Init (NULL, size, NULL); + } + + if ((ret = create_tcti_spi_ftdi_platform (&tcti_platform))) { + return ret; + } + + return Tss2_Tcti_Spi_Helper_Init (tcti_context, size, &tcti_platform); +} + +const TSS2_TCTI_INFO tss2_tcti_spi_ftdi_info = { + .version = TCTI_VERSION, + .name = "tcti-spi-ftdi", + .description = "TCTI for communicating with TPM through the USB-FTDI-SPI converter.", + .config_help = "Takes no configuration.", + .init = Tss2_Tcti_Spi_Ftdi_Init +}; + +const TSS2_TCTI_INFO * +Tss2_Tcti_Info (void) +{ + return &tss2_tcti_spi_ftdi_info; +} diff --git a/src/tss2-tcti/tcti-spi-ftdi.h b/src/tss2-tcti/tcti-spi-ftdi.h new file mode 100644 index 0000000..2000cbb --- /dev/null +++ b/src/tss2-tcti/tcti-spi-ftdi.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifndef TCTI_SPI_FTDI_H +#define TCTI_SPI_FTDI_H + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include "tcti-common.h" +#include "tss2_tcti_spi_helper.h" +#include "mpsse/mpsse.h" + +typedef struct { + struct timeval timeout; + struct mpsse_context *mpsse; +} PLATFORM_USERDATA; + +#endif /* TCTI_SPI_FTDI_H */ diff --git a/src/tss2-tcti/tcti-spi-helper.c b/src/tss2-tcti/tcti-spi-helper.c index 969bc36..a714960 100644 --- a/src/tss2-tcti/tcti-spi-helper.c +++ b/src/tss2-tcti/tcti-spi-helper.c @@ -2,6 +2,10 @@ /* * Copyright 2020 Fraunhofer SIT. All rights reserved. */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -18,10 +22,12 @@ #include "tss2_mu.h" #include "tcti-common.h" #include "tcti-spi-helper.h" -#include "util/io.h" +#include "util/tss2_endian.h" #define LOGMODULE tcti #include "util/log.h" +#define TIMEOUT_B 2000 // The default timeout value as specified in the TCG spec + static inline TSS2_RC spi_tpm_helper_delay_ms(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, int milliseconds) { // Sleep a specified amount of milliseconds @@ -155,12 +161,12 @@ static void spi_tpm_helper_log_register_access(enum TCTI_SPI_HELPER_REGISTER_ACC char* access_str = (access == TCTI_SPI_HELPER_REGISTER_READ) ? "READ" : "WRITE"; if (err != NULL) { - LOG_ERROR("%s register %#02x (%zu bytes) %s", access_str, reg_number, cnt, err); + LOG_ERROR("%s register %#02"PRIx32" (%zu bytes) %s", access_str, reg_number, cnt, err); } else { #if MAXLOGLEVEL < LOGL_TRACE (void) buffer; #else - LOGBLOB_TRACE(buffer, cnt, "%s register %#02x (%zu bytes)", access_str, reg_number, cnt); + LOGBLOB_TRACE(buffer, cnt, "%s register %#02"PRIx32" (%zu bytes)", access_str, reg_number, cnt); #endif } #endif @@ -312,7 +318,7 @@ static uint32_t spi_tpm_helper_read_sts_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx) { uint32_t status = 0; spi_tpm_helper_read_reg(ctx, TCTI_SPI_HELPER_TPM_STS_REG, &status, sizeof(status)); - return status; + return LE_TO_HOST_32(status); } static void spi_tpm_helper_write_sts_reg(TSS2_TCTI_SPI_HELPER_CONTEXT* ctx, uint32_t status) @@ -545,7 +551,7 @@ TSS2_RC tcti_spi_helper_receive (TSS2_TCTI_CONTEXT* tcti_context, size_t *respon // Verify that there is still data to read uint32_t status = spi_tpm_helper_read_sts_reg(ctx); if ((status & expected_status_bits) != expected_status_bits) { - LOG_ERROR("Unexpected intermediate status %#x",status); + LOG_ERROR("Unexpected intermediate status %#"PRIx32,status); return TSS2_TCTI_RC_IO_ERROR; } @@ -558,7 +564,7 @@ TSS2_RC tcti_spi_helper_receive (TSS2_TCTI_CONTEXT* tcti_context, size_t *respon // Verify that there is no more data available status = spi_tpm_helper_read_sts_reg(ctx); if ((status & expected_status_bits) != TCTI_SPI_HELPER_TPM_STS_VALID) { - LOG_ERROR("Unexpected final status %#x", status); + LOG_ERROR("Unexpected final status %#"PRIx32, status); return TSS2_TCTI_RC_IO_ERROR; } @@ -613,12 +619,20 @@ TSS2_RC tcti_spi_helper_transmit (TSS2_TCTI_CONTEXT *tcti_ctx, size_t size, cons return TSS2_TCTI_RC_BAD_VALUE; } - LOGBLOB_DEBUG (cmd_buf, size, "Sending command with TPM_CC %#x and size %" PRIu32, + LOGBLOB_DEBUG (cmd_buf, size, "Sending command with TPM_CC %#"PRIx32" and size %" PRIu32, header.code, header.size); // Tell TPM to expect command spi_tpm_helper_write_sts_reg(ctx, TCTI_SPI_HELPER_TPM_STS_COMMAND_READY); + // Wait until ready bit is set by TPM device + uint32_t expected_status_bits = TCTI_SPI_HELPER_TPM_STS_COMMAND_READY; + rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed waiting for TPM to become ready"); + return rc; + } + // Send command spi_tpm_helper_fifo_transfer(ctx, (void*)cmd_buf, size, TCTI_SPI_HELPER_FIFO_TRANSMIT); @@ -666,14 +680,13 @@ TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size return TSS2_RC_SUCCESS; } - if (*size < sizeof (TSS2_TCTI_SPI_HELPER_CONTEXT)) { - return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; - } - if (!platform_conf) { return TSS2_TCTI_RC_BAD_VALUE; } + if (*size < sizeof (TSS2_TCTI_SPI_HELPER_CONTEXT)) { + return TSS2_TCTI_RC_INSUFFICIENT_BUFFER; + } // Init TCTI context TSS2_TCTI_MAGIC (tcti_context) = TCTI_SPI_HELPER_MAGIC; @@ -724,14 +737,23 @@ TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size return TSS2_TCTI_RC_IO_ERROR; } - // Wait up to 200ms for TPM to become ready + // Wait up to TIMEOUT_B for TPM to become ready LOG_DEBUG("Waiting for TPM to become ready..."); uint32_t expected_status_bits = TCTI_SPI_HELPER_TPM_STS_COMMAND_READY; - rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, 200); + rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + if (rc == TSS2_TCTI_RC_TRY_AGAIN) { + /* + * TPM did not auto transition into ready state, + * write 1 to commandReady to start the transition. + */ + spi_tpm_helper_write_sts_reg(ctx, TCTI_SPI_HELPER_TPM_STS_COMMAND_READY); + rc = spi_tpm_helper_wait_for_status(ctx, expected_status_bits, expected_status_bits, TIMEOUT_B); + } if (rc != TSS2_RC_SUCCESS) { LOG_ERROR("Failed waiting for TPM to become ready"); return rc; } + LOG_DEBUG("TPM is ready"); // Get rid @@ -750,7 +772,7 @@ TSS2_RC Tss2_Tcti_Spi_Helper_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size return TSS2_RC_SUCCESS; } -static const TSS2_TCTI_INFO tss2_tcti_info = { +static const TSS2_TCTI_INFO tss2_tcti_spi_helper_info = { .version = TCTI_VERSION, .name = "tcti-spi-helper", .description = "Platform independent TCTI for communication with TPMs over SPI.", @@ -765,5 +787,5 @@ static const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_spi_helper_info; } diff --git a/src/tss2-tcti/tcti-spi-ltt2go.c b/src/tss2-tcti/tcti-spi-ltt2go.c new file mode 100644 index 0000000..5834d4b --- /dev/null +++ b/src/tss2-tcti/tcti-spi-ltt2go.c @@ -0,0 +1,331 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2020 Peter Huewe + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tss2_tcti.h" +#include "tcti-spi-ltt2go.h" +#include "tss2_tcti_spi_ltt2go.h" +#include "tcti-spi-helper.h" +#include "tss2_mu.h" +#define LOGMODULE tcti +#include "util/log.h" + +#define VID_PI3G 0x365Du +#define PID_LTT2GO 0x1337u +#define TIMEOUT 1000 +#define CTRL_SET 0xC0u +#define CTRL_GET 0x40u +#define CY_CMD_SPI 0xCAu +#define CY_CMD_GPIO_SET 0xDBu +#define CY_SPI_WRITEREAD 0x03u +#define EP_OUT 0x01u +#define EP_IN 0x82u + +#define SPI_MAX_TRANSFER (4 + 64) + +TSS2_RC +platform_spi_transfer (void *user_data, const void *data_out, void *data_in, size_t cnt) +{ + int act_len = 0; + int retry = 0; + int ret = 0; + size_t transfered = 0; + size_t length = cnt; + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + uint8_t *spi_dma_buffer = platform_data->spi_dma_buffer; + libusb_device_handle *dev_handle = platform_data->dev_handle; + + memset (spi_dma_buffer, 0, SPI_MAX_TRANSFER); + + /* Maximum transfer size is 64 bytes */ + if (cnt > SPI_MAX_TRANSFER) { + return TSS2_TCTI_RC_BAD_VALUE; + } + + /* At least one of the buffers has to be set */ + if (data_out == NULL && data_in == NULL) { + return TSS2_TCTI_RC_BAD_VALUE; + } + + /* Clear receive buffer */ + if (data_in != NULL && data_in != data_out) { + memset (data_in, 0, cnt); + } + + if (data_out != NULL){ + memcpy (spi_dma_buffer, data_out, length); + } + + ret = libusb_control_transfer (dev_handle, CTRL_SET, CY_CMD_SPI, CY_SPI_WRITEREAD, length, NULL, 0, TIMEOUT); + if (ret) { + LOG_ERROR ("libusb_control_transfer failed with error: %s.", libusb_strerror(ret)); + ret = TSS2_TCTI_RC_IO_ERROR; + goto out; + } + + while (transfered != cnt){ + ret = libusb_bulk_transfer (dev_handle, EP_OUT, spi_dma_buffer+transfered, length, &act_len, TIMEOUT); + if (ret) { + LOG_ERROR ("libusb_bulk_transfer write failed with error: %s.", libusb_strerror(ret)); + ret = TSS2_TCTI_RC_IO_ERROR; + goto out; + } + transfered += act_len; + length -= act_len; + } + + transfered = 0; + length = cnt; + while(transfered != cnt){ + ret = libusb_bulk_transfer (dev_handle, EP_IN, spi_dma_buffer+transfered, length, &act_len, TIMEOUT); + if (ret) { + if (retry++ > 5) { + LOG_ERROR ("libusb_bulk_transfer read failed with error: %s.", libusb_strerror(ret)); + ret = TSS2_TCTI_RC_IO_ERROR; + goto out; + } + continue; + } + transfered += act_len; + length -= act_len; + } + + if (data_in != NULL) { + memcpy(data_in, spi_dma_buffer, cnt); + } + +out: + memset (spi_dma_buffer, 0, SPI_MAX_TRANSFER); + return ret; +} + +TSS2_RC +platform_sleep_ms (void *user_data, int32_t milliseconds) +{ + (void) user_data; + struct timeval tv = {milliseconds/1000, (milliseconds%1000)*1000}; + select (0, NULL, NULL, NULL, &tv); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_start_timeout (void *user_data, int32_t milliseconds) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + memset (&platform_data->timeout, 0, sizeof (struct timeval)); + + if (gettimeofday (&platform_data->timeout, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + platform_data->timeout.tv_sec += (milliseconds/1000); + platform_data->timeout.tv_usec += (milliseconds%1000)*1000; + if (platform_data->timeout.tv_usec > 999999) { + platform_data->timeout.tv_sec++; + platform_data->timeout.tv_usec -= 1000000; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_timeout_expired (void *user_data, bool *is_timeout_expired) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + struct timeval now; + if (gettimeofday (&now, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + if (now.tv_sec > platform_data->timeout.tv_sec) { + *is_timeout_expired = true; + } else if ((now.tv_sec == platform_data->timeout.tv_sec) + && (now.tv_usec > platform_data->timeout.tv_usec)) { + *is_timeout_expired = true; + } else { + *is_timeout_expired = false; + } + + return TSS2_RC_SUCCESS; +} + +void +platform_finalize(void *user_data) +{ + int ret = 0; + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + if (platform_data->spi_dma_buffer) + libusb_dev_mem_free (platform_data->dev_handle, platform_data->spi_dma_buffer, SPI_MAX_TRANSFER); + + if (platform_data->dev_handle) { + /* Release the interface we claimed */ + ret = libusb_release_interface (platform_data->dev_handle, 0); + if (ret) { + LOG_WARNING ("libusb_release_interface failed: %s.", libusb_strerror (ret)); + } + + /* Close the device we opened */ + libusb_close (platform_data->dev_handle); + } + + if (platform_data->ctx) { + /* Needs to be called after closing all open devices + and before your application terminates */ + libusb_exit (platform_data->ctx); + } + + free(platform_data); +} + +TSS2_RC +create_tcti_spi_ltt2go_platform (TSS2_TCTI_SPI_HELPER_PLATFORM *platform) +{ + int ret = 0; + int nb_ifaces = 0; + libusb_device *dev = NULL; + struct libusb_config_descriptor *conf_desc = NULL; + + /* Create required platform user data */ + PLATFORM_USERDATA *platform_data = calloc (1, sizeof (PLATFORM_USERDATA)); + + if (platform_data == NULL) { + return TSS2_BASE_RC_MEMORY; + } + + ret = libusb_init (&platform_data->ctx); + if (ret) { + LOG_ERROR ("libusb init failed: %s.", libusb_strerror (ret)); + goto out; + } + + platform_data->dev_handle = libusb_open_device_with_vid_pid (platform_data->ctx, VID_PI3G, PID_LTT2GO); + if (!platform_data->dev_handle) { + LOG_ERROR ("LetsTrust-TPM2Go not found."); + goto out; + } + + dev = libusb_get_device (platform_data->dev_handle); + if (dev == NULL) { + LOG_ERROR ("libusb_get_device failed."); + goto out; + } + + ret = libusb_get_config_descriptor (dev, 0, &conf_desc); + if (ret) { + LOG_ERROR ("libusb_get_config_descriptor failed: %s.", libusb_strerror (ret)); + goto out; + } + + nb_ifaces = conf_desc->bNumInterfaces; + libusb_free_config_descriptor(conf_desc); + if (!nb_ifaces) { + LOG_ERROR ("libusb no interface found."); + goto out; + } + + ret = libusb_set_auto_detach_kernel_driver (platform_data->dev_handle, 1); + if (ret) { + LOG_ERROR ("libusb_set_auto_detach_kernel_driver failed: %s.", libusb_strerror (ret)); + goto out; + } + + ret = libusb_claim_interface (platform_data->dev_handle, 0); + if (ret) { + LOG_ERROR ("libusb_claim_interface failed: %s.", libusb_strerror (ret)); + goto out; + } + + platform_data->spi_dma_buffer = libusb_dev_mem_alloc (platform_data->dev_handle, SPI_MAX_TRANSFER); + if (!platform_data->spi_dma_buffer){ + LOG_ERROR ("libusb_dev_mem_alloc failed."); + goto out; + } + + /* Create TCTI SPI platform struct with custom platform methods */ + platform->user_data = platform_data; + platform->sleep_ms = platform_sleep_ms; + platform->start_timeout = platform_start_timeout; + platform->timeout_expired = platform_timeout_expired; + platform->spi_acquire = NULL; + platform->spi_release = NULL; + platform->spi_transfer = platform_spi_transfer; + platform->finalize = platform_finalize; + + return TSS2_RC_SUCCESS; + +out: + if (platform_data->spi_dma_buffer) + libusb_dev_mem_free (platform_data->dev_handle, platform_data->spi_dma_buffer, SPI_MAX_TRANSFER); + + if (platform_data->dev_handle) { + /* Release the interface we claimed */ + ret = libusb_release_interface(platform_data->dev_handle, 0); + if (ret) { + LOG_WARNING ("libusb_release_interface failed: %s.", libusb_strerror (ret)); + } + + /* Close the device we opened */ + libusb_close (platform_data->dev_handle); + } + + if (platform_data->ctx) { + /* Needs to be called after closing all open devices + and before your application terminates */ + libusb_exit (platform_data->ctx); + } + + free(platform_data); + + return TSS2_BASE_RC_IO_ERROR; +} + +TSS2_RC +Tss2_Tcti_Spi_Ltt2go_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, const char* config) +{ + (void) config; + TSS2_RC ret = 0; + TSS2_TCTI_SPI_HELPER_PLATFORM tcti_platform = {0}; + + /* Check if context size is requested */ + if (tcti_context == NULL) { + return Tss2_Tcti_Spi_Helper_Init (NULL, size, NULL); + } + + if ((ret = create_tcti_spi_ltt2go_platform (&tcti_platform))) { + return ret; + } + + /* Initialize TCTI context */ + return Tss2_Tcti_Spi_Helper_Init (tcti_context, size, &tcti_platform); +} + +const TSS2_TCTI_INFO tss2_tcti_ltt2go_info = { + .version = TCTI_VERSION, + .name = "tcti-spi-ltt2go", + .description = "TCTI for communicating with LetsTrust-TPM2Go.", + .config_help = "Takes no configuration.", + .init = Tss2_Tcti_Spi_Ltt2go_Init +}; + +const TSS2_TCTI_INFO * +Tss2_Tcti_Info (void) +{ + return &tss2_tcti_ltt2go_info; +} diff --git a/src/tss2-tcti/tcti-spi-ltt2go.h b/src/tss2-tcti/tcti-spi-ltt2go.h new file mode 100644 index 0000000..759e6f1 --- /dev/null +++ b/src/tss2-tcti/tcti-spi-ltt2go.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2020 Peter Huewe + */ +#ifndef TCTI_SPI_LTT2GO_H +#define TCTI_SPI_LTT2GO_H + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +#include "tcti-common.h" +#include "tss2_tcti_spi_helper.h" + +typedef struct { + struct timeval timeout; + libusb_device_handle *dev_handle; + libusb_context *ctx; + uint8_t *spi_dma_buffer; +} PLATFORM_USERDATA; + +#endif /* TCTI_SPI_LTT2GO_H */ diff --git a/src/tss2-tcti/tcti-spidev.c b/src/tss2-tcti/tcti-spidev.c new file mode 100644 index 0000000..00a70c2 --- /dev/null +++ b/src/tss2-tcti/tcti-spidev.c @@ -0,0 +1,214 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2020 Peter Huewe + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_spidev.h" +#include "tss2_tcti_spi_helper.h" +#include "tcti-common.h" +#include "tss2_mu.h" +#define LOGMODULE tcti +#include "util/log.h" + +typedef struct { + struct timeval timeout; + int fd; +} PLATFORM_USERDATA; + +TSS2_RC +platform_spi_acquire (void *user_data) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct spi_ioc_transfer tr = { + .delay_usecs = 0, + .speed_hz = 5000000, + .bits_per_word = 8, + .cs_change = 1, + .len = 0, + }; + + int ret = ioctl(platform_data->fd, SPI_IOC_MESSAGE(1), &tr); + if (ret < 0) { + LOG_ERROR("SPI acquire failed: %s", strerror(errno)); + return TSS2_TCTI_RC_IO_ERROR; + } + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_spi_release (void *user_data) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + struct spi_ioc_transfer tr = { + .delay_usecs = 0, + .speed_hz = 5000000, + .bits_per_word = 8, + .cs_change = 0, + .len = 0, + }; + + int ret = ioctl(platform_data->fd, SPI_IOC_MESSAGE(1), &tr); + if (ret < 0) { + LOG_ERROR("SPI release failed: %s", strerror(errno)); + return TSS2_TCTI_RC_IO_ERROR; + } + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_spi_transfer (void *user_data, const void *data_out, void *data_in, size_t cnt) +{ + LOGBLOB_DEBUG(data_out, cnt, "Transferring data over ioctl:"); + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + struct spi_ioc_transfer tr = { + .delay_usecs = 0, + .speed_hz = 5000000, + .bits_per_word = 8, + .cs_change = 1, + }; + + tr.len = cnt; + tr.tx_buf = (unsigned long) data_out; + tr.rx_buf = (unsigned long) data_in; + int ret = ioctl(platform_data->fd, SPI_IOC_MESSAGE(1), &tr); + if (ret < 0) { + LOG_ERROR("SPI acquire failed: %s", strerror(errno)); + return TSS2_TCTI_RC_IO_ERROR; + } + LOGBLOB_DEBUG(data_in, cnt, "Received data over ioctl:"); + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_sleep_ms (void *user_data, int32_t milliseconds) +{ + (void) user_data; + struct timeval tv = {milliseconds/1000, (milliseconds%1000)*1000}; + select (0, NULL, NULL, NULL, &tv); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_start_timeout (void *user_data, int32_t milliseconds) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + memset (&platform_data->timeout, 0, sizeof (struct timeval)); + + if (gettimeofday (&platform_data->timeout, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + platform_data->timeout.tv_sec += (milliseconds/1000); + platform_data->timeout.tv_usec += (milliseconds%1000)*1000; + if (platform_data->timeout.tv_usec > 999999) { + platform_data->timeout.tv_sec++; + platform_data->timeout.tv_usec -= 1000000; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_timeout_expired (void *user_data, bool *is_timeout_expired) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + + struct timeval now; + if (gettimeofday (&now, NULL)) { + LOG_ERROR ("getimeofday failed with errno: %d.", errno); + return TSS2_TCTI_RC_GENERAL_FAILURE; + } + + if (now.tv_sec > platform_data->timeout.tv_sec) { + *is_timeout_expired = true; + } else if ((now.tv_sec == platform_data->timeout.tv_sec) + && (now.tv_usec > platform_data->timeout.tv_usec)) { + *is_timeout_expired = true; + } else { + *is_timeout_expired = false; + } + + return TSS2_RC_SUCCESS; +} + +void +platform_finalize(void *user_data) +{ + PLATFORM_USERDATA *platform_data = (PLATFORM_USERDATA *) user_data; + close(platform_data->fd); + free(platform_data); +} + +TSS2_RC +Tss2_Tcti_Spidev_Init (TSS2_TCTI_CONTEXT* tcti_context, size_t* size, const char* config) +{ + TSS2_TCTI_SPI_HELPER_PLATFORM platform = {0}; + + if (!config || config[0] == '\0') + config = "/dev/spidev0.1"; + + /* Check if context size is requested */ + if (tcti_context == NULL) { + return Tss2_Tcti_Spi_Helper_Init (NULL, size, NULL); + } + + /* Create required platform user data */ + PLATFORM_USERDATA *platform_data = calloc (1, sizeof (PLATFORM_USERDATA)); + if (platform_data == NULL) { + return TSS2_BASE_RC_MEMORY; + } + + platform_data->fd = open(config, O_RDWR); + if (!platform_data->fd) { + LOG_ERROR("%s cannot be opened: %s", config, strerror(errno)); + free(platform_data); + return TSS2_TCTI_RC_IO_ERROR; + } + + /* Create TCTI SPI platform struct with custom platform methods */ + platform.user_data = platform_data; + platform.sleep_ms = platform_sleep_ms; + platform.start_timeout = platform_start_timeout; + platform.timeout_expired = platform_timeout_expired; + platform.spi_acquire = platform_spi_acquire; + platform.spi_release = platform_spi_release; + platform.spi_transfer = platform_spi_transfer; + platform.finalize = platform_finalize; + + /* Initialize TCTI context */ + return Tss2_Tcti_Spi_Helper_Init (tcti_context, size, &platform); +} + +const TSS2_TCTI_INFO tss2_tcti_spidev_info = { + .version = TCTI_VERSION, + .name = "tcti-spidev", + .description = "TCTI for communicating with a TPM via spidev.", + .config_help = "Path to spidev (Default: /dev/spidev0.1).", + .init = Tss2_Tcti_Spidev_Init +}; + +const TSS2_TCTI_INFO * +Tss2_Tcti_Info (void) +{ + return &tss2_tcti_spidev_info; +} diff --git a/src/tss2-tcti/tcti-swtpm.c b/src/tss2-tcti/tcti-swtpm.c index e6f6fce..783ed55 100644 --- a/src/tss2-tcti/tcti-swtpm.c +++ b/src/tss2-tcti/tcti-swtpm.c @@ -132,8 +132,12 @@ TSS2_RC tcti_control_command ( uint8_t req_buf[SWTPM_CTRL_REQ_MAX_LEN] = { 0 }; size_t req_buf_len = 0; uint8_t resp_buf[SWTPM_CTRL_RESP_MAX_LEN] = { 0 }; - size_t resp_buf_len = sizeof(uint32_t); +#ifdef _WIN32 + int resp_buf_len = sizeof(uint32_t); +#else + ssize_t resp_buf_len = sizeof(uint32_t); +#endif if (tcti_swtpm->swtpm_conf.path) rc = socket_connect_unix (tcti_swtpm->swtpm_conf.path, 1, @@ -187,7 +191,7 @@ TSS2_RC tcti_control_command ( } #else resp_buf_len = read(tcti_swtpm->ctrl_sock, resp_buf, sizeof(resp_buf)); - if (resp_buf_len < (ssize_t) sizeof(uint32_t)) { + if (resp_buf_len == -1 || resp_buf_len < (ssize_t) sizeof(uint32_t)) { LOG_ERROR ("Failed to get response to control command, errno %d: %s", errno, strerror (errno)); rc = TSS2_TCTI_RC_IO_ERROR; @@ -633,7 +637,7 @@ Tss2_Tcti_Swtpm_Init ( } /* public info structure */ -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_swtpm_info = { .version = TCTI_VERSION, .name = "tcti-swtpm", .description = "TCTI module for communication with the swtpm.", @@ -644,5 +648,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_swtpm_info; } diff --git a/src/tss2-tcti/tcti-swtpm.h b/src/tss2-tcti/tcti-swtpm.h index 320b8c1..eef88c8 100644 --- a/src/tss2-tcti/tcti-swtpm.h +++ b/src/tss2-tcti/tcti-swtpm.h @@ -10,7 +10,7 @@ #include #include "tcti-common.h" -#include "util/io.h" +#include "util-io/io.h" /* * longest possible conf string: diff --git a/src/tss2-tcti/tcti-tbs.c b/src/tss2-tcti/tcti-tbs.c index 3d9292e..c42b998 100644 --- a/src/tss2-tcti/tcti-tbs.c +++ b/src/tss2-tcti/tcti-tbs.c @@ -315,7 +315,7 @@ Tss2_Tcti_Tbs_Init ( return TSS2_RC_SUCCESS; } -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_tbs_info = { .version = TCTI_VERSION, .name = "tcti-tbs", .description = "TCTI module for communication with Windows TPM Base Services", @@ -326,5 +326,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_tbs_info; } diff --git a/src/tss2-tcti/tctildr-dl.c b/src/tss2-tcti/tctildr-dl.c index 622637d..d26219d 100644 --- a/src/tss2-tcti/tctildr-dl.c +++ b/src/tss2-tcti/tctildr-dl.c @@ -47,6 +47,11 @@ struct { .conf = "/dev/tpm0", .description = "Access libtss2-tcti-device.so.0 with /dev/tpm0", }, + { + .file = "libtss2-tcti-device.so.0", + .conf = "/dev/tcm0", + .description = "Access libtss2-tcti-device.so.0 with /dev/tcm0", + }, { .file = "libtss2-tcti-swtpm.so.0", .description = "Access to libtss2-tcti-swtpm.so", @@ -78,65 +83,40 @@ TSS2_RC handle_from_name(const char *file, void **handle) { - char *file_xfrm = NULL; size_t size; - size_t len; + char file_xfrm[PATH_MAX]; + const char *formats[] = { + /* */ + "%s", + /* libtss2-tcti-.so.0 */ + FMT_TCTI_PREFIX "%s" FMT_LIB_SUFFIX_0, + /* libtss2-tcti-.so */ + FMT_TCTI_PREFIX "%s" FMT_LIB_SUFFIX, + /* libtss2-.so.0 */ + FMT_TSS_PREFIX "%s" FMT_LIB_SUFFIX_0, + /* libtss2-.so */ + FMT_TSS_PREFIX "%s" FMT_LIB_SUFFIX, + }; if (handle == NULL) { return TSS2_TCTI_RC_BAD_REFERENCE; } - *handle = dlopen(file, RTLD_NOW); - if (*handle != NULL) { - return TSS2_RC_SUCCESS; - } else { - LOG_DEBUG("Could not load TCTI file: \"%s\": %s", file, dlerror()); - } - len = snprintf(NULL, 0, TCTI_NAME_TEMPLATE_0, file); - if (len >= PATH_MAX) { - LOG_ERROR("TCTI name truncated in transform."); - return TSS2_TCTI_RC_BAD_VALUE; - } - file_xfrm = calloc(len + 1, sizeof(char)); - if (file_xfrm == NULL) { - return TSS2_TCTI_RC_MEMORY; - } - /* 'name' alone didn't work, try libtss2-tcti-.so.0 */ - size = snprintf(file_xfrm, - len + 1, - TCTI_NAME_TEMPLATE_0, - file); - if (size >= (len + 1)) { - LOG_ERROR("TCTI name truncated in transform."); - SAFE_FREE(file_xfrm); - return TSS2_TCTI_RC_BAD_VALUE; - } - *handle = dlopen(file_xfrm, RTLD_NOW); - if (*handle != NULL) { - SAFE_FREE(file_xfrm); - return TSS2_RC_SUCCESS; - } else { - LOG_DEBUG("Could not load TCTI file \"%s\": %s", file, dlerror()); - } - /* libtss2-tcti-.so.0 didn't work, try libtss2-tcti-.so */ - size = snprintf(file_xfrm, - len + 1, - TCTI_NAME_TEMPLATE, - file); - if (size >= (len + 1)) { - LOG_ERROR("TCTI name truncated in transform."); - SAFE_FREE(file_xfrm); - return TSS2_TCTI_RC_BAD_VALUE; - } - *handle = dlopen(file_xfrm, RTLD_NOW); - if (*handle == NULL) { - LOG_DEBUG("Failed to load TCTI for name \"%s\": %s", file, dlerror()); - SAFE_FREE(file_xfrm); - return TSS2_TCTI_RC_NOT_SUPPORTED; + for (size_t i = 0; i < ARRAY_SIZE(formats); i++) { + size = snprintf(file_xfrm, sizeof(file_xfrm), formats[i], file); + if (size >= sizeof(file_xfrm)) { + LOG_ERROR("TCTI name truncated in transform."); + return TSS2_TCTI_RC_BAD_VALUE; + } + *handle = dlopen(file_xfrm, RTLD_NOW); + if (*handle != NULL) { + return TSS2_RC_SUCCESS; + } else { + LOG_DEBUG("Could not load TCTI file \"%s\": %s", file, dlerror()); + } } - SAFE_FREE(file_xfrm); - return TSS2_RC_SUCCESS; + return TSS2_TCTI_RC_NOT_SUPPORTED; } TSS2_RC tcti_from_file(const char *file, @@ -202,7 +182,14 @@ get_info_default(const TSS2_TCTI_INFO **info, return TSS2_TCTI_RC_IO_ERROR; #else size_t i; + if (ARRAY_SIZE(tctis) == 0) { + LOG_ERROR("No default TCTIs configured during compilation"); + return TSS2_TCTI_RC_IO_ERROR; + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" for (i = 0; i < ARRAY_SIZE(tctis); i++) { +#pragma GCC diagnostic pop name = tctis[i].file; LOG_DEBUG("name: %s", name); if (name == NULL) { @@ -256,7 +243,14 @@ tctildr_get_default(TSS2_TCTI_CONTEXT ** tcticontext, void **dlhandle) TSS2_RC r; size_t i; + if (ARRAY_SIZE(tctis) == 0) { + LOG_ERROR("No default TCTIs configured during compilation"); + return TSS2_TCTI_RC_IO_ERROR; + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" for (i = 0; i < ARRAY_SIZE(tctis); i++) { +#pragma GCC diagnostic pop LOG_DEBUG("Attempting to connect using standard TCTI: %s", tctis[i].description); r = tcti_from_file(tctis[i].file, tctis[i].conf, tcticontext, diff --git a/src/tss2-tcti/tctildr-nodl.c b/src/tss2-tcti/tctildr-nodl.c index 7489b54..fd2f350 100644 --- a/src/tss2-tcti/tctildr-nodl.c +++ b/src/tss2-tcti/tctildr-nodl.c @@ -100,6 +100,16 @@ struct { .conf = "/dev/tpm0", .description = "Access to /dev/tpm0", }, + { + .names = { + "libtss2-tcti-device.so.0", + "libtss2-tcti-device.so", + "device", + }, + .init = Tss2_Tcti_Device_Init, + .conf = "/dev/tcm0", + .description = "Access to /dev/tcm0", + }, #endif /* TCTI_DEVICE */ #endif /* _WIN32 */ #ifdef TCTI_SWTPM @@ -137,7 +147,14 @@ tctildr_get_default(TSS2_TCTI_CONTEXT ** tcticontext, void **dlhandle) } *tcticontext = NULL; + if (ARRAY_SIZE(tctis) == 0) { + LOG_ERROR("No default TCTIs configured during compilation"); + return TSS2_TCTI_RC_IO_ERROR; + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" for (size_t i = 0; i < ARRAY_SIZE(tctis); i++) { +#pragma GCC diagnostic pop LOG_DEBUG("Attempting to connect using standard TCTI: %s", tctis[i].description); rc = tcti_from_init (tctis[i].init, @@ -168,7 +185,14 @@ tctildr_get_tcti (const char *name, return tctildr_get_default (tcti, data); } + if (ARRAY_SIZE(tctis) == 0) { + LOG_ERROR("No default TCTIs configured during compilation"); + return TSS2_TCTI_RC_IO_ERROR; + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" for (size_t i = 0; i < ARRAY_SIZE(tctis); ++i) { +#pragma GCC diagnostic pop for (size_t j = 0; j < NAME_ARRAY_SIZE; ++j) { if (strcmp (name, tctis[i].names[j])) continue; diff --git a/src/tss2-tcti/tctildr.c b/src/tss2-tcti/tctildr.c index 96b11c7..4f380ce 100644 --- a/src/tss2-tcti/tctildr.c +++ b/src/tss2-tcti/tctildr.c @@ -39,6 +39,9 @@ static char *strndup(const char* s, size_t n) #endif #else #include +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif #endif #include #include @@ -186,6 +189,56 @@ tctildr_conf_parse (const char *name_conf, return TSS2_RC_SUCCESS; } +/* + * calls tctildr_conf_parse. + * allocates memory for name and conf if necessary. + * does not return empty strings, but NULL instead. + */ +TSS2_RC +tctildr_conf_parse_alloc (const char *name_conf, + char **name, + char **conf) +{ + size_t combined_length; + TSS2_RC rc; + + if (name_conf == NULL) { + *name = NULL; + *conf = NULL; + return TSS2_RC_SUCCESS; + } + + /* Parse name_conf into name and conf */ + combined_length = strlen (name_conf); + if (combined_length > PATH_MAX - 1) { + LOG_ERROR ("combined conf length must be between 0 and PATH_MAX"); + return TSS2_TCTI_RC_BAD_VALUE; + } + *name = calloc(combined_length + 1, sizeof(char)); + *conf = calloc(combined_length + 1, sizeof(char)); + if (*name == NULL || *conf == NULL) { + SAFE_FREE(*name); + SAFE_FREE(*conf); + return TSS2_TCTI_RC_MEMORY; + } + rc = tctildr_conf_parse (name_conf, *name, *conf); + if (rc != TSS2_RC_SUCCESS) { + SAFE_FREE(*name); + SAFE_FREE(*conf); + return rc; + } + + /* Set name and conf to NULL if they are empty strings */ + if (!strcmp(*name, "")) { + SAFE_FREE(*name); + } + if (!strcmp(*conf, "")) { + SAFE_FREE(*conf); + } + + return TSS2_RC_SUCCESS; +} + TSS2_TCTILDR_CONTEXT* tctildr_context_cast (TSS2_TCTI_CONTEXT *ctx) { @@ -404,6 +457,45 @@ Tss2_TctiLdr_FreeInfo (TSS2_TCTI_INFO **info) free (info_tmp); *info = NULL; } + +TSS2_RC +tctildr_init_context_data (TSS2_TCTI_CONTEXT *tctiContext, + const char *name, + const char *conf) +{ + TSS2_TCTILDR_CONTEXT *ldr_ctx = NULL; + TSS2_TCTI_CONTEXT *child_ctx = NULL; + void *dl_handle = NULL; + TSS2_RC rc; + + if (tctiContext == NULL) { + return TSS2_TCTI_RC_BAD_VALUE; + } + + rc = tctildr_get_tcti(name, conf, &child_ctx, &dl_handle); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR ("Failed to instantiate TCTI"); + return rc; + } + TSS2_TCTI_MAGIC (tctiContext) = TCTILDR_MAGIC; + TSS2_TCTI_VERSION (tctiContext) = TCTI_VERSION; + TSS2_TCTI_TRANSMIT (tctiContext) = tctildr_transmit; + TSS2_TCTI_RECEIVE (tctiContext) = tctildr_receive; + TSS2_TCTI_FINALIZE (tctiContext) = tctildr_finalize; + TSS2_TCTI_CANCEL (tctiContext) = tctildr_cancel; + TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = tctildr_get_poll_handles; + TSS2_TCTI_SET_LOCALITY (tctiContext) = tctildr_set_locality; + TSS2_TCTI_MAKE_STICKY (tctiContext) = tctildr_make_sticky; + ldr_ctx = tctildr_context_cast(tctiContext); + if (ldr_ctx == NULL) { + return TSS2_TCTI_RC_BAD_VALUE; + } + ldr_ctx->library_handle = dl_handle; + ldr_ctx->tcti = child_ctx; + + return TSS2_RC_SUCCESS; +} + TSS2_RC Tss2_TctiLdr_Initialize_Ex (const char *name, const char *conf, @@ -425,29 +517,15 @@ Tss2_TctiLdr_Initialize_Ex (const char *name, if (conf != NULL && strcmp (conf, "")) { local_conf = conf; } - rc = tctildr_get_tcti (local_name, local_conf, tctiContext, &dl_handle); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR ("Failed to instantiate TCTI"); - goto err; - } ldr_ctx = calloc (1, sizeof (TSS2_TCTILDR_CONTEXT)); if (ldr_ctx == NULL) { rc = TSS2_TCTI_RC_MEMORY; goto err; } - TSS2_TCTI_MAGIC (ldr_ctx) = TCTILDR_MAGIC; - TSS2_TCTI_VERSION (ldr_ctx) = TCTI_VERSION; - TSS2_TCTI_TRANSMIT (ldr_ctx) = tctildr_transmit; - TSS2_TCTI_RECEIVE (ldr_ctx) = tctildr_receive; - TSS2_TCTI_FINALIZE (ldr_ctx) = tctildr_finalize; - TSS2_TCTI_CANCEL (ldr_ctx) = tctildr_cancel; - TSS2_TCTI_GET_POLL_HANDLES (ldr_ctx) = tctildr_get_poll_handles; - TSS2_TCTI_SET_LOCALITY (ldr_ctx) = tctildr_set_locality; - TSS2_TCTI_MAKE_STICKY (ldr_ctx) = tctildr_make_sticky; - ldr_ctx->library_handle = dl_handle; - ldr_ctx->tcti = *tctiContext; - *tctiContext = (TSS2_TCTI_CONTEXT*)ldr_ctx; - return rc; + + *tctiContext = (TSS2_TCTI_CONTEXT *) ldr_ctx; + return tctildr_init_context_data(*tctiContext, local_name, local_conf); + err: if (*tctiContext != NULL) { Tss2_Tcti_Finalize (*tctiContext); @@ -465,29 +543,76 @@ Tss2_TctiLdr_Initialize (const char *nameConf, char *name = NULL; char *conf = NULL; TSS2_RC rc; - size_t combined_length; - if (nameConf == NULL) { - return Tss2_TctiLdr_Initialize_Ex (NULL, NULL, tctiContext); + rc = tctildr_conf_parse_alloc (nameConf, &name, &conf); + if (rc != TSS2_RC_SUCCESS) { + return rc; } + rc = Tss2_TctiLdr_Initialize_Ex (name, conf, tctiContext); - combined_length = strlen (nameConf); - if (combined_length > PATH_MAX - 1) { - LOG_ERROR ("combined conf length must be between 0 and PATH_MAX"); + SAFE_FREE(name); + SAFE_FREE(conf); + return rc; +} + +TSS2_RC Tss2_Tcti_TctiLdr_Init (TSS2_TCTI_CONTEXT *tctiContext, size_t *size, + const char *nameConf) +{ + TSS2_RC rc; + char *name = NULL; + char *conf = NULL; + + LOG_TRACE("tctiContext: 0x%" PRIxPTR ", size: 0x%" PRIxPTR ", conf: %s", + (uintptr_t)tctiContext, (uintptr_t)size, nameConf); + + if (tctiContext == NULL && size == NULL) { return TSS2_TCTI_RC_BAD_VALUE; + } else if (tctiContext == NULL) { + *size = sizeof (TSS2_TCTILDR_CONTEXT); + return TSS2_RC_SUCCESS; } - name = calloc(combined_length + 1, sizeof(char)); - conf = calloc(combined_length + 1, sizeof(char)); - if (name == NULL || conf == NULL) { - rc = TSS2_TCTI_RC_MEMORY; - goto out; + + rc = tctildr_conf_parse_alloc (nameConf, &name, &conf); + if (rc != TSS2_RC_SUCCESS) { + goto free_name_conf; } - rc = tctildr_conf_parse (nameConf, name, conf); - if (rc != TSS2_RC_SUCCESS) - goto out; - rc = Tss2_TctiLdr_Initialize_Ex (name, conf, tctiContext); -out: + + rc = tctildr_init_context_data(tctiContext, name, conf); + +free_name_conf: SAFE_FREE(name); SAFE_FREE(conf); return rc; } + +__attribute__((weak)) +const TSS2_TCTI_INFO tss2_tctildr_info = { + .version = TCTI_VERSION, + .name = "tctildr", + .description = "TCTI module for dynamically loading other TCTI modules", + .config_help = "TCTI to load and its configuration. Either" + " * , e.g. device (child_conf will be NULL) OR\n" + " * :, e.g., device:/dev/tpmrm0 OR\n" + " * NULL, tctildr will attempt to load a child tcti in the following order:\n" + " * libtss2-tcti-default.so\n" + " * libtss2-tcti-tabrmd.so\n" + " * libtss2-tcti-device.so.0:/dev/tpmrm0\n" + " * libtss2-tcti-device.so.0:/dev/tpm0\n" + " * libtss2-tcti-device.so.0:/dev/tcm0\n" + " * libtss2-tcti-swtpm.so\n" + " * libtss2-tcti-mssim.so\n" + "Where child_name: if not empty, tctildr will try to dynamically load the child tcti library in the following order:\n" + " * \n" + " * libtss2-tcti-.so.0\n" + " * libtss2-tcti-.so\n" + " * libtss2-.so.0\n" + " * libtss2-.so\n", + .init = Tss2_Tcti_TctiLdr_Init, +}; + +__attribute__((weak)) +const TSS2_TCTI_INFO* +Tss2_Tcti_Info (void) +{ + return &tss2_tctildr_info; +} diff --git a/src/tss2-tcti/tctildr.h b/src/tss2-tcti/tctildr.h index 0579cd3..02cd394 100644 --- a/src/tss2-tcti/tctildr.h +++ b/src/tss2-tcti/tctildr.h @@ -9,13 +9,14 @@ #include "tss2_tpm2_types.h" #include "tss2_tcti.h" -#define TCTI_SUFFIX ".so" -#define TCTI_SUFFIX_0 TCTI_SUFFIX".0" -#define LIB_PREFIX "lib" -#define TCTI_PREFIX LIB_PREFIX"tss2-tcti" -#define TCTI_NAME_TEMPLATE TCTI_PREFIX"-%s"TCTI_SUFFIX -#define TCTI_NAME_TEMPLATE_0 TCTI_PREFIX"-%s"TCTI_SUFFIX_0 -#define DEFAULT_TCTI_LIBRARY_NAME TCTI_PREFIX"-default"TCTI_SUFFIX +#define FMT_LIB_PREFIX "lib" +#define FMT_TSS_PREFIX FMT_LIB_PREFIX"tss2-" +#define FMT_TCTI_PREFIX FMT_TSS_PREFIX"tcti-" + +#define FMT_LIB_SUFFIX_0 FMT_LIB_SUFFIX".0" +#define FMT_LIB_SUFFIX ".so" + +#define DEFAULT_TCTI_LIBRARY_NAME FMT_TCTI_PREFIX"-default"TCTI_SUFFIX #define TCTILDR_MAGIC 0xbc44a31ca74b4aafULL @@ -27,6 +28,11 @@ typedef struct { TSS2_TCTI_CONTEXT *tcti; } TSS2_TCTILDR_CONTEXT; +TSS2_RC +Tss2_Tcti_TctiLdr_Init (TSS2_TCTI_CONTEXT *tctiContext, + size_t *size, + const char *conf); + TSS2_RC tcti_from_init(TSS2_TCTI_INIT_FUNC init, const char* conf, diff --git a/src/tss2-tcti/tss2-tcti-mssim.vcxproj b/src/tss2-tcti/tss2-tcti-mssim.vcxproj index d9df3fb..3566da0 100644 --- a/src/tss2-tcti/tss2-tcti-mssim.vcxproj +++ b/src/tss2-tcti/tss2-tcti-mssim.vcxproj @@ -22,28 +22,28 @@ 15.0 {89B6B774-2886-48CF-B1D0-534AC449E0FD} Win32Proj - 10.0.17134.0 + 10 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -120,14 +120,14 @@ - + - + @@ -136,4 +136,4 @@ - + \ No newline at end of file diff --git a/src/tss2-tcti/tss2-tcti-swtpm.vcxproj b/src/tss2-tcti/tss2-tcti-swtpm.vcxproj index fa9e9ee..54f81a5 100644 --- a/src/tss2-tcti/tss2-tcti-swtpm.vcxproj +++ b/src/tss2-tcti/tss2-tcti-swtpm.vcxproj @@ -28,22 +28,22 @@ DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -137,14 +137,14 @@ - + - + diff --git a/src/tss2-tcti/tss2-tcti-tbs.vcxproj b/src/tss2-tcti/tss2-tcti-tbs.vcxproj index 0ad9e74..8d63913 100644 --- a/src/tss2-tcti/tss2-tcti-tbs.vcxproj +++ b/src/tss2-tcti/tss2-tcti-tbs.vcxproj @@ -22,28 +22,28 @@ 15.0 {6BA6146F-8B38-49A2-A156-769E0F2CC302} Win32Proj - 10.0.17134.0 + 10 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -133,4 +133,4 @@ - + \ No newline at end of file diff --git a/src/tss2-tcti/tss2-tctildr.vcxproj b/src/tss2-tcti/tss2-tctildr.vcxproj index 28d0af2..fe50113 100644 --- a/src/tss2-tcti/tss2-tctildr.vcxproj +++ b/src/tss2-tcti/tss2-tctildr.vcxproj @@ -22,28 +22,28 @@ 15.0 {40EC0A14-E90F-450F-B250-2071B05ED099} Win32Proj - 10.0.17134.0 + 10 DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL DynamicLibrary true - v141_clang_c2 + ClangCL DynamicLibrary false - v141_clang_c2 + ClangCL @@ -134,4 +134,4 @@ - + \ No newline at end of file diff --git a/src/util/io.c b/src/util-io/io.c similarity index 100% rename from src/util/io.c rename to src/util-io/io.c diff --git a/src/util/io.h b/src/util-io/io.h similarity index 100% rename from src/util/io.h rename to src/util-io/io.h diff --git a/src/util/aux_util.h b/src/util/aux_util.h index fbe1a61..a30e405 100644 --- a/src/util/aux_util.h +++ b/src/util/aux_util.h @@ -10,6 +10,7 @@ #ifdef HAVE_CONFIG_H #include #endif +#include #include "tss2_tpm2_types.h" #ifdef __cplusplus extern "C" { @@ -19,7 +20,7 @@ extern "C" { #define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) -#define TPM2_ERROR_FORMAT "%s%s (0x%08x)" +#define TPM2_ERROR_FORMAT "%s%s (0x%08"PRIx32")" #define TPM2_ERROR_TEXT(r) "Error", "Code", r #define SIZE_OF_ARY(ary) (sizeof(ary) / sizeof(ary[0])) diff --git a/src/util/tss2_endian.h b/src/util/tss2_endian.h index 0406fea..ff42768 100644 --- a/src/util/tss2_endian.h +++ b/src/util/tss2_endian.h @@ -22,46 +22,61 @@ #define BE_TO_HOST_32(value) be32toh(value) #define BE_TO_HOST_64(value) be64toh(value) -#else /* linux || unix */ - -#if defined(WORDS_BIGENDIAN) +#define HOST_TO_LE_16(value) htole16(value) +#define HOST_TO_LE_32(value) htole32(value) +#define HOST_TO_LE_64(value) htole64(value) +#define LE_TO_HOST_16(value) le16toh(value) +#define LE_TO_HOST_32(value) le32toh(value) +#define LE_TO_HOST_64(value) le64toh(value) -#define HOST_TO_BE_16(value) (value) -#define HOST_TO_BE_32(value) (value) -#define HOST_TO_BE_64(value) (value) -#define BE_TO_HOST_16(value) (value) -#define BE_TO_HOST_32(value) (value) -#define BE_TO_HOST_64(value) (value) +#else /* linux || unix */ -#else #include static inline uint16_t endian_conv_16(uint16_t value) { - return ((value & (0xff)) << 8) | \ - ((value & (0xff << 8)) >> 8); + return ((value & (((uint16_t)0xffU))) << 8) | \ + ((value & (((uint16_t)0xffU) << 8)) >> 8); } static inline uint32_t endian_conv_32(uint32_t value) { - return ((value & (0xff)) << 24) | \ - ((value & (0xff << 8)) << 8) | \ - ((value & (0xff << 16)) >> 8) | \ - ((value & (0xff << 24)) >> 24); + return ((value & (((uint32_t)0xffU))) << 24) | \ + ((value & (((uint32_t)0xffU) << 8)) << 8) | \ + ((value & (((uint32_t)0xffU) << 16)) >> 8) | \ + ((value & (((uint32_t)0xffU) << 24)) >> 24); } static inline uint64_t endian_conv_64(uint64_t value) { - return ((value & (0xffULL)) << 56) | \ - ((value & (0xffULL << 8)) << 40) | \ - ((value & (0xffULL << 16)) << 24) | \ - ((value & (0xffULL << 24)) << 8) | \ - ((value & (0xffULL << 32)) >> 8) | \ - ((value & (0xffULL << 40)) >> 24) | \ - ((value & (0xffULL << 48)) >> 40) | \ - ((value & (0xffULL << 56)) >> 56); + return ((value & (((uint64_t)0xffU))) << 56) | \ + ((value & (((uint64_t)0xffU) << 8)) << 40) | \ + ((value & (((uint64_t)0xffU) << 16)) << 24) | \ + ((value & (((uint64_t)0xffU) << 24)) << 8) | \ + ((value & (((uint64_t)0xffU) << 32)) >> 8) | \ + ((value & (((uint64_t)0xffU) << 40)) >> 24) | \ + ((value & (((uint64_t)0xffU) << 48)) >> 40) | \ + ((value & (((uint64_t)0xffU) << 56)) >> 56); } +#if defined(WORDS_BIGENDIAN) + +#define HOST_TO_BE_16(value) (value) +#define HOST_TO_BE_32(value) (value) +#define HOST_TO_BE_64(value) (value) +#define BE_TO_HOST_16(value) (value) +#define BE_TO_HOST_32(value) (value) +#define BE_TO_HOST_64(value) (value) + +#define HOST_TO_LE_16(value) endian_conv_16(value) +#define HOST_TO_LE_32(value) endian_conv_32(value) +#define HOST_TO_LE_64(value) endian_conv_64(value) +#define LE_TO_HOST_16(value) endian_conv_16(value) +#define LE_TO_HOST_32(value) endian_conv_32(value) +#define LE_TO_HOST_64(value) endian_conv_64(value) + +#else /* WORDS_BIGENDIAN */ + #define HOST_TO_BE_16(value) endian_conv_16(value) #define HOST_TO_BE_32(value) endian_conv_32(value) #define HOST_TO_BE_64(value) endian_conv_64(value) @@ -69,6 +84,13 @@ static inline uint64_t endian_conv_64(uint64_t value) #define BE_TO_HOST_32(value) endian_conv_32(value) #define BE_TO_HOST_64(value) endian_conv_64(value) -#endif /* WORDS_BIGENDIAN */ +#define HOST_TO_LE_16(value) (value) +#define HOST_TO_LE_32(value) (value) +#define HOST_TO_LE_64(value) (value) +#define LE_TO_HOST_16(value) (value) +#define LE_TO_HOST_32(value) (value) +#define LE_TO_HOST_64(value) (value) + +#endif /* WORDS_BIGENDIAN else */ #endif /* linux || unix */ #endif /* TSS2_ENDIAN_H */ diff --git a/test/data/fapi/P_ECC.json b/test/data/fapi/P_ECC.json index 6efe409..dbf43ca 100644 --- a/test/data/fapi/P_ECC.json +++ b/test/data/fapi/P_ECC.json @@ -33,7 +33,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/test/data/fapi/P_ECC_error.json b/test/data/fapi/P_ECC_error.json index c85c2a2..e2053ba 100644 --- a/test/data/fapi/P_ECC_error.json +++ b/test/data/fapi/P_ECC_error.json @@ -33,7 +33,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/test/data/fapi/P_ECC_sh_eh_policy.json b/test/data/fapi/P_ECC_sh_eh_policy.json index 143da6a..5b20214 100644 --- a/test/data/fapi/P_ECC_sh_eh_policy.json +++ b/test/data/fapi/P_ECC_sh_eh_policy.json @@ -31,7 +31,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] }, diff --git a/test/data/fapi/P_ECC_system.json b/test/data/fapi/P_ECC_system.json index 65bac2b..996de1d 100644 --- a/test/data/fapi/P_ECC_system.json +++ b/test/data/fapi/P_ECC_system.json @@ -33,7 +33,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/test/data/fapi/P_RSA.json b/test/data/fapi/P_RSA.json index 6df8911..8678782 100644 --- a/test/data/fapi/P_RSA.json +++ b/test/data/fapi/P_RSA.json @@ -46,7 +46,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/test/data/fapi/P_RSA2.json b/test/data/fapi/P_RSA2.json index 84c9d1a..ad20415 100644 --- a/test/data/fapi/P_RSA2.json +++ b/test/data/fapi/P_RSA2.json @@ -46,7 +46,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] } diff --git a/test/data/fapi/P_RSA3072.json b/test/data/fapi/P_RSA3072.json new file mode 100644 index 0000000..50486c4 --- /dev/null +++ b/test/data/fapi/P_RSA3072.json @@ -0,0 +1,107 @@ +{ + "type": "TPM2_ALG_RSA", + "nameAlg":"TPM2_ALG_SHA384", + "srk_template": "system,restricted,decrypt,0x81000001", + "srk_description": "Storage root key SRK", + "srk_persistent": 1, + "ek_template": "system,restricted,decrypt,user", + "ek_description": "Endorsement key EK", + "rsa_signing_scheme": { + "scheme":"TPM2_ALG_RSAPSS", + "details":{ + "hashAlg":"TPM2_ALG_SHA384" + } + }, + "rsa_decrypt_scheme": { + "scheme":"TPM2_ALG_OAEP", + "details":{ + "hashAlg":"TPM2_ALG_SHA384" + } + }, + "sym_mode":"TPM2_ALG_CFB", + "sym_parameters": { + "algorithm":"TPM2_ALG_AES", + "keyBits":"256", + "mode":"TPM2_ALG_CFB" + }, + "sym_block_size": 16, + "pcr_selection": [ + { "hash": "TPM2_ALG_SHA1", + "pcrSelect": [ ] + }, + { "hash": "TPM2_ALG_SHA256", + "pcrSelect": [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ] + } + ], + "exponent": 0, + "keyBits": 3072, + "session_symmetric":{ + "algorithm":"TPM2_ALG_AES", + "keyBits":"256", + "mode":"TPM2_ALG_CFB" + }, + "ek_policy": { + "description": "Endorsement hierarchy used for policy secret.", + "policy":[ + { + "type": "PolicyOR", + "branches": [ + { + "name": "A", + "description": "", + "policy": [ + { + "type":"POLICYSECRET", + "objectName": "4000000b" + } + ] + }, + { + "name": "B", + "description": "", + "policy": [ + { + "type":"AUTHORIZENV", + "nvPublic": { + "size": 60, + "nvPublic": { + "nvIndex": 29392642, + "nameAlg":"SHA384", + "attributes":{ + "PPWRITE":0, + "OWNERWRITE":0, + "AUTHWRITE":0, + "POLICYWRITE":1, + "POLICY_DELETE":0, + "WRITELOCKED":0, + "WRITEALL":1, + "WRITEDEFINE":0, + "WRITE_STCLEAR":0, + "GLOBALLOCK":0, + "PPREAD":1, + "OWNERREAD":1, + "AUTHREAD":1, + "POLICYREAD":1, + "NO_DA":1, + "ORDERLY":0, + "CLEAR_STCLEAR":0, + "READLOCKED":0, + "WRITTEN":1, + "PLATFORMCREATE":0, + "READ_STCLEAR":0, + "TPM2_NT":"ORDINARY" + }, + "authPolicy":"8bbf2266537c171cb56e403c4dc1d4b64f432611dc386e6f532050c3278c930e143e8bb1133824ccb431053871c6db53", + "dataSize":50 + } + } + + } + ] + } + ] + } + ] + } + +} diff --git a/test/data/fapi/P_RSA_sh_policy.json b/test/data/fapi/P_RSA_sh_policy.json index 32a5e1a..7401edb 100644 --- a/test/data/fapi/P_RSA_sh_policy.json +++ b/test/data/fapi/P_RSA_sh_policy.json @@ -46,7 +46,7 @@ "policy":[ { "type":"POLICYSECRET", - "objectName": "4000000b", + "objectName": "4000000b" } ] }, diff --git a/test/data/fapi/eventlog/binary_measurements_hcrtm.b64 b/test/data/fapi/eventlog/binary_measurements_hcrtm.b64 new file mode 100644 index 0000000..706310f --- /dev/null +++ b/test/data/fapi/eventlog/binary_measurements_hcrtm.b64 @@ -0,0 +1,1118 @@ +AAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACkAAABTcGVjIElEIEV2ZW50MDMA +AAAAAAACAAIDAAAABAAUAAsAIAASACAAAAAAAAAQAACAAwAAAAQAHyn8eESXsoWL +189pjgqUnINqByALAEz/mXtpDq2jkh3mVbN29BQULQHRmT5sbKtQj1adhBBZEgBb +qD2SvjrAROB7fZTUzJyAabwIg7R+uhFzUAGFzWTGbgUAAABIQ1JUTQAAAAAIAAAA +AwAAAAQABGWsau2OMf/L2N27Cp0b7GhQpd8LAJeu0Hme0isqz42yNTE6VRpNKjxd +9Z7z+Coomz+mdkeAEgD/1wTvjSTbDyNSnSMgrQz/hzbUAhYLEkjDQcPaXCxA+SwA +AABEAGgAeQBhAG4AYQAyAC4AMAA1AC4ANAAzAC4AMgA5AC4AMAAwADAAMwAAAAAA +AAAIAACAAwAAAAQA6GYEgWuhb8ZU1eGgc78tmIGyuU4LAEDoUegRUvbBTIcubFDH +brZzWszF3DgeEac7FeFNNn7tEgA3JeLUDZaOifmn90Yg4OtoB3yZjDIa+IBBWc6W +7dH0vBAAAAAAAOAxAAAAAAAAHAAAAAAAAAAAAAgAAIADAAAABAD/jJ44DJIO+n5c +VL/k0UFHqhlA4gsAu87md94pQOc20G+gNorNlKNz5yCre1tVVUSt+JYfeEASAOK8 +LRU9w7RQj6H42Ihy1oj51o4RAOf9oUj7h6vv7JLmEAAAAAAAmP8AAAAAAABOAAAA +AAAHAAAAAQAAgAMAAAAEAFfNTcGUQkdaqCdDSE87HKqI4UK4CwARWqgn28z7RNIW +rZ7P2la96mILhgqUvtW3onu6HE0C2BIAw+hiCXBLITPV93+6X/o+BO9jNymx6mCG +3GWElW20e201AAAAYd/ki8qT0hGqDQDgmAMrjAoAAAAAAAAAAQAAAAAAAABTAGUA +YwB1AHIAZQBCAG8AbwB0AAAHAAAAAQAAgAMAAAAEAJsThzBuu3/455XnvndWNma7 +9FFuCwDep7gKtTo9qqJNXMRsZOH6n/0Dc5+QqtvYwIZ8SltIkBIAIFcCJYrq7K9o +Uz6QwsbLF83BvDT1yZ4FZLtX9e06DickAAAAYd/ki8qT0hGqDQDgmAMrjAIAAAAA +AAAAAAAAAAAAAABQAEsABwAAAAEAAIADAAAABACa+obFB0GbhXDGIWfLlIbZ/ICX +WAsA5nDhIfzr1HO4vEG7gBMB/B2a+jOQTwb3FJt08SxHpo8SAJf4Qs+L4+8Mmx5f +ttSrSvJrKUPlzjSYg6/fYH6BcH96JgAAAGHf5IvKk9IRqg0A4JgDK4wDAAAAAAAA +AAAAAAAAAAAASwBFAEsABwAAAAEAAIADAAAABABb+PqgeNQP+9AzF8kzmLASKaDh +4AsAuviaPMrOUnUMXwEoNR4EIqQVl6Gt/VCCKqNjudEk6nwSAPeCR5M3WGAqDiuj +jNx++0tV1KF/muwh32r1bWxzibsFJAAAAMuyGdc6PZZFo7za0A5nZW8CAAAAAAAA +AAAAAAAAAAAAZABiAAcAAAABAACAAwAAAAQArDR1MERmdkcIXnsRkQoBERKXA/YL +AMt4LqYi2FgqpxeAISxQAStxHCbuYuMwFT9Gsz6fBsNbEgANY12Kiw7u2VmJWJ80 +FAkN7lfjrBntgDSFAA61IFxCxXIAAADLshnXOj2WRaO82tAOZ2VvAwAAAAAAAABM +AAAAAAAAAGQAYgB4ACYWxMFMUJJArKlB+TaTQyhMAAAAAAAAADAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAABAAA +AAMAAAAEAJBpynjnRQooUXNDGz5SxcJSmeRzCwDfP2GYBKkv20BXGS3EPddI6neK +3FK8SYzoBSTAFLgRGRIAr8yHD6IMUHmVSZeUNx6MJeOnMQ+nIgDBCTeZc64jaEUE +AAAAAAAAAAEAAAAJAACAAwAAAAQAibw5TbjmpxAMk5d2gWviZJNrcKkLAG0/MaDP +Ba8/uKWwgfidAFqy4iivKsf/ifUGqsWqydjvEgA+oNXRQ8hJIdGzk65EID/OFdBF +itkgPlDH3kaZYfBBiiAAAAABAAAAAAAAAEQV/fKUlyxKmS7lu88g45QAUOduAAAA +AAEAAAACAACAAwAAAAQAoz9bX9axyt30pK3uEHo8yR0tFNILAGsec6AJS3uBLTue +Is/7T4I5MZhHUixPoQN1O2lQAg+TEgCMXDpy4+hMcETzbA8x0KpjEkbvbUl4mmCf +L9Rgy5+/vjYAAABh3+SLypPSEaoNAOCYAyuMCQAAAAAAAAAEAAAAAAAAAEIAbwBv +AHQATwByAGQAZQByAAAAAQABAAAAAgAAgAMAAAAEAISbPfuGZWkfp42//EA9jXzb +kaWPCwCl7qB6z1o95ydhWWMVQySMm3/tVNGRlAlAzv8m8jww7RIAMHrnfjK4REYN +WzcvQtKf90RM4xL9lue/PdIFwf91bNgKAQAAYd/ki8qT0hGqDQDgmAMrjAgAAAAA +AAAA2gAAAAAAAABCAG8AbwB0ADAAMAAwADAAAQAAAFAAUwBBAFQAQQAwACAAUABv +AHIAdAA3ACAALQAgAEUARgBJACAASABhAHIAZAAgAEQAcgBpAHYAZQAgACgAVwBN +AEMANgBOADAASwBBAEgANQBSAFIALQBIAEcAUwBUACAASABVAFMANwAyADIAVAAy +AFQAQQBMAEEANgAwADQAKQAAAAIBDADQQQMKAAAAAAEBBgABCAEBBgACAAMSCgAH +AAAAAAAEASoAAQAAAAAIAAAAAAAAAAAQAAAAAABifeGGOoCdT57l9d+7O7xWAgJ/ +/wQAUkMBAAAAAgAAgAMAAAAEAK1w96gJ3YF88VMzVEeZQY/mblyRCwCWBB7I2oyK +6nvV0gUff45LKkGknHjVXBfnZ9X6x/uWShIAXEQGStGm/6+a146j8keuWor2Ufq9 +zBmv3Xrsnr/bxcmSAAAAYd/ki8qT0hGqDQDgmAMrjAgAAAAAAAAAYgAAAAAAAABC +AG8AbwB0ADAAMAAwADEAAQAAADAARQBGAEkAIABJAG4AdABlAHIAbgBhAGwAIABT +AGgAZQBsAGwAAAABAxgACwAAAIAAAFUAAAAAfwCFVgAAAAAEBhQAg6UEfD6eHE+t +ZeBSaNC00X//BABSQ4mBoEQEAAAABwAAgAMAAAAEAM0P20UxpuxBvidTugQmN9bl +9/JWCwA9Z3K0+E7UdZXXKixMX/0V9btyx1B/4m8qruLGnVYzuhIADEWlw8ME1z8a +nXPU/gMZDPGGHom6W5WHUqulHG+1/FooAAAAQ2FsbGluZyBFRkkgQXBwbGljYXRp +b24gZnJvbSBCb290IE9wdGlvbgAAAAAEAAAAAwAAAAQAkGnKeOdFCihRc0MbPlLF +wlKZ5HMLAN8/YZgEqS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZEgCvzIcPogxQ +eZVJl5Q3Howl46cxD6ciAMEJN5lzriNoRQQAAAAAAAAAAQAAAAQAAAADAAAABACQ +acp450UKKFFzQxs+UsXCUpnkcwsA3z9hmASpL9tAVxktxD3XSOp3itxSvEmM6AUk +wBS4ERkSAK/Mhw+iDFB5lUmXlDcejCXjpzEPpyIAwQk3mXOuI2hFBAAAAAAAAAAC +AAAABAAAAAMAAAAEAJBpynjnRQooUXNDGz5SxcJSmeRzCwDfP2GYBKkv20BXGS3E +PddI6neK3FK8SYzoBSTAFLgRGRIAr8yHD6IMUHmVSZeUNx6MJeOnMQ+nIgDBCTeZ +c64jaEUEAAAAAAAAAAMAAAAEAAAAAwAAAAQAkGnKeOdFCihRc0MbPlLFwlKZ5HML +AN8/YZgEqS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZEgCvzIcPogxQeZVJl5Q3 +Howl46cxD6ciAMEJN5lzriNoRQQAAAAAAAAABAAAAAQAAAADAAAABACQacp450UK +KFFzQxs+UsXCUpnkcwsA3z9hmASpL9tAVxktxD3XSOp3itxSvEmM6AUkwBS4ERkS +AK/Mhw+iDFB5lUmXlDcejCXjpzEPpyIAwQk3mXOuI2hFBAAAAAAAAAAFAAAABAAA +AAMAAAAEAJBpynjnRQooUXNDGz5SxcJSmeRzCwDfP2GYBKkv20BXGS3EPddI6neK +3FK8SYzoBSTAFLgRGRIAr8yHD6IMUHmVSZeUNx6MJeOnMQ+nIgDBCTeZc64jaEUE +AAAAAAAAAAYAAAAEAAAAAwAAAAQAkGnKeOdFCihRc0MbPlLFwlKZ5HMLAN8/YZgE +qS/bQFcZLcQ910jqd4rcUrxJjOgFJMAUuBEZEgCvzIcPogxQeZVJl5Q3Howl46cx +D6ciAMEJN5lzriNoRQQAAAAAAAAABQAAAAYAAIADAAAABACz8WP/eW8/rw7v4PWs +mFhMmIHJHQsAhQgDGd8yTtXGmoT89b8LljT++4IW2w8pSe13Uee6RNISAPmJ/HNJ +Lox7wOePKnJkAwBvyUmaYl0EE6m4bj53sN60ZAMAAEVGSSBQQVJUAAABAFwAAABL +G/dJAAAAAAEAAAAAAAAAr4jg6AAAAAAiAAAAAAAAAI6I4OgAAAAA+tOm7qDeFEST +poeFSXoHYgIAAAAAAAAAgAAAAIAAAADjlRFDBgAAAAAAAAAocyrBH/jSEbpLAKDJ +Psk7Yn3hhjqAnU+e5fXfuzu8VgAIAAAAAAAA/wcQAAAAAAAAAAAAAAAAAEUARgBJ +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAK89xg+DhHJHjnk9adhHfeQ8+a1ZyQdhQrCDDyGs +nDrqAAgQAAAAAAD/BzAAAAAAAAAAAAAAAAAAYgBvAG8AdAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAArz3GD4OEckeOeT1p2Ed95G6I4DcWFKpFmBMNbAcKpvYACDAAAAAAAP8HsAwA +AAAAAAAAAAAAAABTAFkAUwBSAE8ATwBUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACvPcYPg4RyR455PWnY +R33kHaafXb/4aUuHSZ6CFpcsnQAIsAwAAAAA/wcwGQAAAAAAAAAAAAAAAGIAYQBj +AGsAdQBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAK89xg+DhHJHjnk9adhHfeRk23vasVFTRbxF5pnK +d9+xAAgwGQAAAAD/P4nmAAAAAAAAAAAAAAAAZABhAHQAYQAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAbf1XBqukxEOE5QkzyEtPT0EZA0OxfOFAuDQmGDaIRdkAQInmAAAAAP+H4OgA +AAAAAAAAAAAAAABzAHcAYQBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAwAAgAMAAAAE +AFj98uw2SVjehVzhHhCj3Zxgv/BYCwAlJZ7JtV6qQtjuMM4bqPtZp81lL9kYc7GE +zCa1O6Pj5RIAB7nLBan42zpTmeFOQgXQ59ElgexWhf9AhFAQ7T5H1JqgAAAAGFCc +XQAAAAAAMAIAAAAAAAAAAAAAAAAAgAAAAAAAAAACAQwA0EEDCgAAAAABAQYAAQgB +AQYAAgADEgoABwAAAAAABAEqAAEAAAAACAAAAAAAAAAAEAAAAAAAYn3hhjqAnU+e +5fXfuzu8VgICBAQwAFwARQBGAEkAXABCAE8ATwBUAFwAQgBPAE8AVABYADYANAAu +AEUARgBJAAAAf/8EAAkAAAANAAAAAwAAAAQAihFT0xYNO9BaMjsx3aPQ2YHuHYkL +ADb92QwSzP/2aAe8NLu6UrrqAOZuLYQeCITd+f0+Av/LEgC2Fpovi+yYGxCW0prK +ohkwgm50jOpyGcc7ZYx1qiiCxSsAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1Yi94ODZf +NjQtZWZpL25vcm1hbC5tb2QACQAAAA0AAAADAAAABADrURRyX+EuADKYY9l0isgP +kSZGugsAq2GMWv6qM9qk81EMF1G5uUs9tmwp/raRP3J3NRaIxHkSADtMTqFqK6dM +5ZqCGwXvFtPiVq3h0FYC+UlvQwimhDXpKwAAAChoZDAsZ3B0MSkvYm9vdC9ncnVi +L3g4Nl82NC1lZmkvZXh0Y21kLm1vZAAJAAAADQAAAAMAAAAEAIRV7YpT0Zeqm9j6 +juzCGf1PBQ4tCwApDgQpJ7QE3ZMNpe0oJ94Me9q428Rv/vEOKFgCzCFVnhIAHSU8 +gtArVpCS4N/jdjxOKmrsVBaAnwPgJS4MPIOnBtQrAAAAKGhkMCxncHQxKS9ib290 +L2dydWIveDg2XzY0LWVmaS9jcnlwdG8ubW9kAAkAAAANAAAAAwAAAAQAhHLPvivc +wNKv0S82nS0iP0sR/n4LAHbd7MyXm1TvkHCVq7Sb0X8gW6IOCp4g83hSDGMaPNcm +EgCDlccYHDHU8yyJOVfdCAZ/fF1couzjrZj3OgsBKHX5IikAAAAoaGQwLGdwdDEp +L2Jvb3QvZ3J1Yi94ODZfNjQtZWZpL2Jvb3QubW9kAAkAAAANAAAAAwAAAAQA3HEe +D2yXzckQ6noWeV3S4cGWD5MLANkD5ZZmovSN3bG4C4Kfa4qxsNTF3kipHKcPd5+C +SqSaEgACW3H92N8TrH81L3DKwHyfXBBAhKMn1pdcRvuglfK3uyoAAAAoaGQwLGdw +dDEpL2Jvb3QvZ3J1Yi94ODZfNjQtZWZpL2J1ZmlvLm1vZAAJAAAADQAAAAMAAAAE +ALuwrhcErOZ6XXvKPkjNK6pFdLIHCwDLwLi3VzvETQeocy6TTqJoEDRbaPPpZVAs +1k2SaxqJHBIA0FB5PFG1AaERWHYhX+RzUlOhmYIwoWMOptQat9V835UsAAAAKGhk +MCxncHQxKS9ib290L2dydWIveDg2XzY0LWVmaS9nZXR0ZXh0Lm1vZAAJAAAADQAA +AAMAAAAEAM6MxNIAwwkolDUTrF+5xwcaF0FMCwBErhs+GwY2ATZVqea6xdMd4N6B +F5EbcZR9unf6Qe7IhhIAgbMv7vo/KlNdYMSDgjd2pUwkHz48LtlIicwGPSLlbskt +AAAAKGhkMCxncHQxKS9ib290L2dydWIveDg2XzY0LWVmaS90ZXJtaW5hbC5tb2QA +CQAAAA0AAAADAAAABAAJFlyl200kh2Jfy7ZedLmK/6L3TgsArZ9CsrMS9B0Mf0ob +z4YMXTXlI2PBuAVTMnfWksMaoLUSAGQwchYvEq/JSaoKh4D9VsOiu5Di60QtS5eh +nNqZy3THKQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvZ3ppby5t +b2QACQAAAA0AAAADAAAABABVzEm/bHrFcpt1JZUxKtNyDJ5OpwsAKxqTAI3nhlCN +umSjo+JcXgAadQELSTjY3mE2efxc9wASAAaYT4oFeLTzM6YF/ThO29QZPlunrvgV +KcGXIyeJFJsjLQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvZ2Ny +eV9jcmMubW9kAAkAAAANAAAAAwAAAAQAf36FkJ+zfRUPV4IsCtO2NueFOv8LAFE3 +JXzc7BQLzn4Mg8EADfP37PGN4RveRrjTL0m6ZXeREgBtCZdkct52Ic+JH9dwbjzH +JFWEIYPheKN2EA+8W7hzzCwAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1Yi94ODZfNjQt +ZWZpL2NvbW1hbmQubHN0AAkAAAANAAAAAwAAAAQA8JFlXHrHMU6w3yGTFBXeR2KN +Yh8LADL8f13owKXcCx5+tgnKMad+s0dVOeHZekVD3KG5smxXEgB7wzykn90I3FHJ +nwdma3DuKB3oQ1gAvKMtg875pZY3picAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1Yi94 +ODZfNjQtZWZpL2ZzLmxzdAAJAAAADQAAAAMAAAAEAP8A0oEUOYzxoFIylJTWOs7r +j/KaCwAbdm84qUkn/pt7wegJ8DY+d44UxgHoAPrqJxouddP8QxIAH4xoVH7kzcLm +/HYsZ/6UZf/yslHR00xNCBKx/jue644rAAAAKGhkMCxncHQxKS9ib290L2dydWIv +eDg2XzY0LWVmaS9jcnlwdG8ubHN0AAkAAAANAAAAAwAAAAQAZrcmxtZLwQnTlIqV +KPUC6pSTjvQLAEb4iMUvNrr5ti1gvI0GQmoxSq1aD/hqQ2KpHCUSod+cEgDany7c +2H89Xd8FzR+PjfMhcSWdp5B7bjUsuYCOLoBMhy0AAAAoaGQwLGdwdDEpL2Jvb3Qv +Z3J1Yi94ODZfNjQtZWZpL3Rlcm1pbmFsLmxzdAAJAAAADQAAAAMAAAAEAC0vDCLi +yRh8yohtaKx2jbMrUlygCwD19HF1sbxPcGrZTOkoi7AxFu7rwPhLwNCmTaKelmuG +DRIAxYa5eBVy7TBHkGQDVuyVyQ80mJANKLaBZMYpG/vLq1ceAAAAKGhkMCxncHQx +KS9ib290L2dydWIvZ3J1Yi5jZmcACAAAAA0AAAADAAAABACtqxiREAsKfrRj0QGz +A4bDYLdc/wsA9d9pRjdL/XmiFiKvlD1+dqQ/UpnXBDP0WKuDVxw0S4YSADM7Stgf +EhtZalSnnAMQyoQ1XkZA15I20+l+YtQGUOdpHwAAAGdydWJfY21kOiBzZXQgaXNf +cHJlbG9hZD1mYWxzZQAIAAAADQAAAAMAAAAEAD5c1+oP3C4rL5VtQfkJDuNzL7gz +CwB+KzSTuqP55MaoNigtHma1hVaSFp3uRNRv4g0R28FzgRIAwLTjSnvaBVOvNHfL +1EDDIRY1B/9+zjJZALs8a/VPdm0uAAAAZ3J1Yl9jbWQ6IFsgLXMgKGhkMCxncHQx +KS9ib290L2dydWIvZ3J1YmVudiBdAAkAAAANAAAAAwAAAAQAWfg4e8ElXH2mxyDi +jWKONnJTAG8LAIJP99JllpUsIuyJwNigpMLm7Z+0Vur3KVueRSnbKsVOEgCrtc4I +RDfQBZkOWU7d9Scv8TTM8ZWHHwnkOTQ9KEKqlykAAAAoaGQwLGdwdDEpL2Jvb3Qv +Z3J1Yi94ODZfNjQtZWZpL3Rlc3QubW9kAAkAAAANAAAAAwAAAAQAsn6+VYWPMZeb +ZFpCRLVebvrbTa4LAC5CNMhR3fJRsP/JNe4duWt779Ty34aaVhLigt4Ewj/AEgCi +vVVZREbLFbiqPMCM8LcYuzSBonWuhDfA3DQqixeoIR0AAAAoaGQwLGdwdDEpL2Jv +b3QvZ3J1Yi9ncnViZW52AAgAAAANAAAAAwAAAAQAPE6bEZjswWCv9gIsD5a1si+r +FGkLAA46F+DEjkLXn00Vduf3h8kRI5UQWGUFwyYUO5smi91lEgA/pL5s/kciL06t +aEYuXiyUXE5bTTzsuMd4GhC7yU4fqCAAAABncnViX2NtZDogc2V0IGhhdmVfZ3J1 +YmVudj10cnVlAAgAAAANAAAAAwAAAAQART3ubOgr2A6om9gIVySul4T/DxsLAPi5 +n3eYOZDogEhkyt6R82G1tmAMwoMv6674eKyLRNJ+EgAe1QS803FDdLH1lB/JPtgG +WwZVEcL231bcPkbHYz3TiBMAAABncnViX2NtZDogbG9hZF9lbnYACQAAAA0AAAAD +AAAABACg4o3wyYqQTPm1stESlkF+SwHH4wsAgqAtB4b/rQMCCuu6Yanytfueeibm +2uOPxzYMV4clKz4SABWbLr8ziV5Zwk2wQ5/dM0RDVhUcUlbQJJ0jvWUZdYglLAAA +AChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvbG9hZGVudi5tb2QACQAA +AA0AAAADAAAABAD4zqYYHucVHf9oJwb6nTa85ny/zgsA7kFxqLsQ5IUADu+HU3/H +208K8z8Kq/AAObg9SokCgP8SAOTgE+vGHFhFIGOHlOyRvSIEsGFLkQvD2YH6buHN +qi0cKQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvZGlzay5tb2QA +CQAAAA0AAAADAAAABACyfr5VhY8xl5tkWkJEtV5u+ttNrgsALkI0yFHd8lGw/8k1 +7h25a3vv1PLfhppWEuKC3gTCP8ASAKK9VVlERssVuKo8wIzwtxi7NIGida6EN8Dc +NCqLF6ghHQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL2dydWJlbnYACAAAAA0AAAAD +AAAABAC06ZtA0t3c32joqkOeGN1eusv/yQsA0rkpg+Zq/5mYL+WvVeD5J33A+IeZ +NOF7ABR+H0FWF54SAL+dqBXVCKKonwxBGEpWat3D7IjIPuEJjnSDLg4sQdUhEwAA +AGdydWJfY21kOiBbICA9IDIgXQAIAAAADQAAAAMAAAAEAAW6RSvwC3+IBSizXQLp +B3+JwIU4CwCCpKFOQ6T3YRiuYyhdCvBa8TnyYPrleywgc3ocHfM4KxIA+G23hSZd +akog8u5+vU01f+CkMillEvsIrotKCuM5NloTAAAAZ3J1Yl9jbWQ6IFsgID0gMSBd +AAgAAAANAAAAAwAAAAQAcQy/I3yavQccqRxBBDJIAL7HsPsLAM6BJLwbD7wMtc1H +M4ygx9X1RG15k25EOiAdlrGSp71lEgDK2xBbkVNsfgW4E+0nfEw0jD1FN6PAQdUp +tbA/FqQuQw8AAABncnViX2NtZDogWyAgXQAIAAAADQAAAAMAAAAEAGz7qTy2scB7 +oWvaYz+hh/fWM2l3CwBztL6/cui2aJmzqqm6WiUy3ExRBHch/EdVdUZwIEfbwBIA +pllm9O+kfTjq9cVDciqzMic0ov8bhSCKu/l+3Ciqo+JOAAAAZ3J1Yl9jbWQ6IHNl +dCBkZWZhdWx0PUt5bGluIFYxMCBTUDEg55qE6auY57qn6YCJ6aG5Pkt5bGluIFYx +MCBTUDEsIDUuNC4xOC1jc3YACAAAAA0AAAADAAAABAD1sGflnBY/Z7Gbg2++6eik +h6Gc3QsARWg2H7dYGzGkLWRatTQwL7n3Qq2qN7f94VIhXWniWfsSAEmtoKcNc70p +b/eMg4fJhPQ8A60wk8UkGXb3bmQZ/XlcFgAAAGdydWJfY21kOiBbIHh5ID0geHkg +XQAIAAAADQAAAAMAAAAEAL1SCeUMCWUP/PXC0SqL6Cd+Q4AjCwAJ8X1N+0uX8WJG +YywhsawhJclcFIiZ7uUGn7sbNDZVExIA+yKUBkKzQpYIpI+Z643YoP9S17DVmnaN +Y76oHCjeBH4jAAAAZ3J1Yl9jbWQ6IG1lbnVlbnRyeV9pZF9vcHRpb249LS1pZAAI +AAAADQAAAAMAAAAEAGJIWZuuDXjMvaGF7S/OAYLtQeKXCwBK8Ls3DJ47eYICfQLg +TJNeMtUrUoAHR2v8UNNtG4aBXhIAC+SqF8vcwfxXAh8R1bzDAmeJIHMiCsL8gjmB +nbRYKP4lAAAAZ3J1Yl9jbWQ6IGV4cG9ydCBtZW51ZW50cnlfaWRfb3B0aW9uAAgA +AAANAAAAAwAAAAQAcQy/I3yavQccqRxBBDJIAL7HsPsLAM6BJLwbD7wMtc1HM4yg +x9X1RG15k25EOiAdlrGSp71lEgDK2xBbkVNsfgW4E+0nfEw0jD1FN6PAQdUptbA/ +FqQuQw8AAABncnViX2NtZDogWyAgXQAIAAAADQAAAAMAAAAEAPWwZ+WcFj9nsZuD +b77p6KSHoZzdCwBFaDYft1gbMaQtZFq1NDAvufdCrao3t/3hUiFdaeJZ+xIASa2g +pw1zvSlv94yDh8mE9DwDrTCTxSQZdvduZBn9eVwWAAAAZ3J1Yl9jbWQ6IFsgeHkg +PSB4eSBdAAgAAAANAAAAAwAAAAQAdpbn7Ai6LCSBc4uMNuF4Oojui5cLALc7+Dqj +5fAFDvl+6IDQ/THk9ixBgH5KUQRLoqs5tzO6EgAtRf+ip9uUDXihxLlZMq042LX+ +dtFuEzOhKMXm9QEzhBcAAABncnViX2NtZDogZm9udD11bmljb2RlAAgAAAANAAAA +AwAAAAQA/iavRzwMoDJnbdOKq5CZiI/VxKQLAPv5heqaan49vfNLXu7GoU1p3pRg +qQydiEuabTj8rIR9EgDxR0xCX7ujUiWRIR+3fz9kqvBsjm8rzYjnXQQxq2s99RsA +AABncnViX2NtZDogbG9hZGZvbnQgdW5pY29kZQAJAAAADQAAAAMAAAAEAORMl3W1 +KGCMw0w8Bndj8ABBRVFDCwC+5tRr6XUGzbjAdbVYyxxC+JNxGUbPy/cnoaGvvJCY +nRIAf1fXy8kMzr5eF36HS/g/FjoJ6exI2GS1s6v8egEBUUspAAAAKGhkMCxncHQx +KS9ib290L2dydWIveDg2XzY0LWVmaS9mb250Lm1vZAAJAAAADQAAAAMAAAAEAKuU +HrUonPjhEzFDUxuLZ+Fc113iCwAbIcNzzZs3VNkF7XxJY+Ti6u+zV1QGHptAI8O/ +6J0p4BIAo1a8qqoH1m0E4PvTF8/+OmIjLwOZEXfgNnLilfMbkxEqAAAAKGhkMCxn +cHQxKS9ib290L2dydWIveDg2XzY0LWVmaS92aWRlby5tb2QACQAAAA0AAAADAAAA +BACXcQvk0t5HImMLRMB7wUDYLVDMbQsAZosxVynDmtXwoLWfhwtgd3bt60JUgbcK +HeAbChnBLi0SAMzIlyEtz0nf0JqcXl1Cy6itSZQ4hCiRlNjuO4NBJam3JwAAACho +ZDAsZ3B0MSkvYm9vdC9ncnViL2ZvbnRzL3VuaWNvZGUucGYyAAgAAAANAAAAAwAA +AAQAq0WVYbyeWYJDLAmw5q9VvpZJ//cLAA5n4/jUbbQUSGYNLQco+k9g3yMe6cO1 +VLMdoLW3NgBrEgCoMSc1X9Oe6VMUxgn70Y8hKFb0Wp7LZyD6iA2JR6v0nhsAAABn +cnViX2NtZDogc2V0IGdmeG1vZGU9YXV0bwAIAAAADQAAAAMAAAAEAI/lnmbW7BmE +IEd/JPeR6SnxU+FECwB2JqvYvnRCwuV1Nko+lcs6O1M8WK+7pALSvavf+F0pxxIA +B5ELepGxQoM6gCvMrKe3JYNfwAbSKUdBOu4FWZ81cxYVAAAAZ3J1Yl9jbWQ6IGxv +YWRfdmlkZW8ACAAAAA0AAAADAAAABAD1sGflnBY/Z7Gbg2++6eikh6Gc3QsARWg2 +H7dYGzGkLWRatTQwL7n3Qq2qN7f94VIhXWniWfsSAEmtoKcNc70pb/eMg4fJhPQ8 +A60wk8UkGXb3bmQZ/XlcFgAAAGdydWJfY21kOiBbIHh5ID0geHkgXQAIAAAADQAA +AAMAAAAEAFnO00OwYLffVPp7olHvh3lAYB7kCwDXE1P1No6ywSgFkJKBKJeb2W6o +2x6MgUk/eHg4O3arOxIA8K4p/w0Yph5Ix3O/CPWVoD379Upw7zfM1MfsuA7zZacb +AAAAZ3J1Yl9jbWQ6IGluc21vZCBhbGxfdmlkZW8ACQAAAA0AAAADAAAABADAflkD +G2Nk8/oNdLiaKFXEEt874gsAFBUUArI4Jj7ZA2NsQJaa7OvNhZrrIOPMr2avvcQA +JbwSAMQOjYjFt9tvx4Jzkesz65THPvZ7sbvzkNlfpt682ls5LgAAAChoZDAsZ3B0 +MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvYWxsX3ZpZGVvLm1vZAAJAAAADQAAAAMA +AAAEABd2YAnGXRouySwi0KjNzBqORU0hCwAEyx67yPq4VPj0/O35XXJ5cMegNu+T +6kmy/BeOi+zJYhIA2zxLpc5Xm/vevy10vH9+qZ9t8lDpT+ysQWNObbR3yNUsAAAA +KGhkMCxncHQxKS9ib290L2dydWIveDg2XzY0LWVmaS9lZmlfZ29wLm1vZAAJAAAA +DQAAAAMAAAAEAHwfz2wZ9FM6c3dtJn5kOOK5ewURCwDC+xoa3ahDLgSHwiOLf4jV +Qz8vQs3RhaQfc59fckGuwBIAHcR/8ygH9SSn6Go/LmNFO8WCekwkrgvR6cfk+Lgf +qsYtAAAAKGhkMCxncHQxKS9ib290L2dydWIveDg2XzY0LWVmaS92aWRlb19mYi5t +b2QACQAAAA0AAAADAAAABAC1OIpqldWD+PAQRyeo9HtptOxnAgsALCcG3tEKCPPF +leWfGSzLeYYeNirtEZ2iKiVTr5qZbBkSANItLrlOfXhe7wpX97ZCzMom5eH4fqPP +WjCRKXI8Q6ZDLAAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvZWZp +X3VnYS5tb2QACQAAAA0AAAADAAAABADtxHMQBzWKYzmDwFkaxHIs6VSa0wsAF646 +MQj+MhdM6LoZO3hcHf2u8rnEYHIHE0jACQctDZASACy/XZ1zjjpV4nomhAe+hJBC +RWeOzxd7M0GUhRAUbEcNMAAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1l +ZmkvdmlkZW9fYm9jaHMubW9kAAkAAAANAAAAAwAAAAQALJyeOpPKpAopoS1z1b08 +AgdVpToLALMfiyw+Se2QAJkUBkOFr1X3aR9Vrr9vrTlNr+T3eR7UEgDe8y1othR0 +iYpmmkWu7twnwxECizdF+/M5p0bdSYaX1jEAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1 +Yi94ODZfNjQtZWZpL3ZpZGVvX2NpcnJ1cy5tb2QACAAAAA0AAAADAAAABADDf+TO +SpaqzDt+yTOgMD3fHPLOzAsAglhZKbzB9TG4PtsHegmFVljyCYzdkMhty1BscaMX +G04SABnwjQ4+RDkus8p7Fq/YOYKs4nNfTjuj0/QZ65ipG/BDGQAAAGdydWJfY21k +OiBpbnNtb2QgZ2Z4dGVybQAJAAAADQAAAAMAAAAEAE2dMjV8bRuARr9F/eFyvJwm +S6W8CwDDUBbgALp6icj+CGmMNTLWafSVxE47Saw6lNDDKp+fwxIAQGqo5FfHtjsA +8mL6ffgAZZVkY5xrk2kQrDuNsuCE9jMsAAAAKGhkMCxncHQxKS9ib290L2dydWIv +eDg2XzY0LWVmaS9nZnh0ZXJtLm1vZAAIAAAADQAAAAMAAAAEAL1wlfc0orwDVbOB +QSWLY+OuI0N3CwD+8rnXFuI5sLjCR4+2wI/sR7qXOPeaNyoe/z62jPxWoRIAyDnt +n9qJJ7k2PAXO6n9igHZPEDPdGoBlyEOB6Y21+DM1AAAAZ3J1Yl9jbWQ6IHNldCBs +b2NhbGVfZGlyPShoZDAsZ3B0MSkvYm9vdC9ncnViL2xvY2FsZQAIAAAADQAAAAMA +AAAEADDzB333M68fyHmjwLpRrSNiWBHSCwCsqdzuP9FM+6Vd5CxtNNE0C/n4J+I4 +1GpMFyB28PkwZBIAgWjo7Z+B0CmRRKTJAoR9Vw6mvrayZuK32DQ4c8oxX+cZAAAA +Z3J1Yl9jbWQ6IHNldCBsYW5nPXpoX0NOAAkAAAANAAAAAwAAAAQAQNEeBaLnpRGG +OvX00qG/aQSel1ILAKiVb9u6UuebuWJYH2SAZMpUWLbUh7KbajkWDnDFcLL0EgCl +V4fmARi2Xqmvqi26sPPMotMhERE3cjeaqMLQAXT21iUAAAAoaGQwLGdwdDEpL2Jv +b3QvZ3J1Yi9sb2NhbGUvemhfQ04ubW8ACAAAAA0AAAADAAAABADU0VTqdjzwvsyj +mOMtwOiE5tU1XAsArHL19iPUcqMfcBUrKtyzEOC4wXKX/yUpCJujojcUqy8SAJbJ +ei5yjbqEt0Q09Y2irOeUf/3nZn0ybuOCEAV6ya1jGQAAAGdydWJfY21kOiBpbnNt +b2QgZ2V0dGV4dAAIAAAADQAAAAMAAAAEADgcUmeAI0Nif2Npc26OEv03yIWjCwA/ +PcigRA5DayaJTvvEBS90viLAmOwEQUWgWHBdndAsGxIAaI8pTPW1TqkcDJk7TUzq +gqwrsUVy+nJ7msalihU5yd0iAAAAZ3J1Yl9jbWQ6IHRlcm1pbmFsX291dHB1dCBn +Znh0ZXJtAAgAAAANAAAAAwAAAAQABbpFK/ALf4gFKLNdAukHf4nAhTgLAIKkoU5D +pPdhGK5jKF0K8FrxOfJg+uV7LCBzehwd8zgrEgD4bbeFJl1qSiDy7n69TTV/4KQy +KWUS+wiui0oK4zk2WhMAAABncnViX2NtZDogWyAgPSAxIF0ACAAAAA0AAAADAAAA +BAD1sGflnBY/Z7Gbg2++6eikh6Gc3QsARWg2H7dYGzGkLWRatTQwL7n3Qq2qN7f9 +4VIhXWniWfsSAEmtoKcNc70pb/eMg4fJhPQ8A60wk8UkGXb3bmQZ/XlcFgAAAGdy +dWJfY21kOiBbIHh5ID0geHkgXQAIAAAADQAAAAMAAAAEAMUSCSsEgSNMqkFu98GW +q06SuOACCwAcVoOYzy5KnfWIdbvXnf/gWOxFvgt0US+pGaL+fbSmCRIAAEnjfMNq +w7GVLZXvqmAc1V0/3DxeZfRFwNAwKQvPqXAhAAAAZ3J1Yl9jbWQ6IHNldCB0aW1l +b3V0X3N0eWxlPW1lbnUACAAAAA0AAAADAAAABABzLHE6b0w6OI7htGYkt8P+NNWd +UAsAcaWzshrDhi9A+rt0WpZJw6HTQkm5cGUkyQskgMKYvrASADU5Id83sx1BJRi5 +WsPCC6j7oIduN7FhSlCMJCCdhFOAGAAAAGdydWJfY21kOiBzZXQgdGltZW91dD01 +AAgAAAANAAAAAwAAAAQARWnhtm2WlAlOKcPDv//iEpCIOjwLAB3HS05I/fNap/W7 +l69ZWmpNprBif+jU82RgDtR5MB+HEgDL2ydmoGmhWtmPSTUjXYr1iO7cNTL1yE7g +l/ytw8CgYSoAAABncnViX2NtZDogc2V0IG1lbnVfY29sb3Jfbm9ybWFsPWN5YW4v +Ymx1ZQAIAAAADQAAAAMAAAAEAEssGYSzPXGYGB/adFJlODOy+CacCwCo3vwn11Ga +RzLCg7QH5zb9k2brsKyI1xYdbZGMwNNNTBIA17cRx8QmdqEEGsTcnkyeabFyY9P5 +rlkfLr9wWSZsUlMuAAAAZ3J1Yl9jbWQ6IHNldCBtZW51X2NvbG9yX2hpZ2hsaWdo +dD13aGl0ZS9ibHVlAAgAAAANAAAAAwAAAAQApOHG9QV5tHyWQRHR6iFw5vkjyUEL +AGLNdtMco9ENdC5Gxv8XEEbOGd2Q82GoJ/7GVx5ZwkeUEgCQj2JiFB82Zdf73hlV +4Fe2+ZM3za17+s9vdYU9rx2PpBoAAABncnViX2NtZDogaW5zbW9kIHBhcnRfZ3B0 +AAgAAAANAAAAAwAAAAQArz8Hq6yeXFa4LwmrmDKJBaq79u8LALg4pNKGDIEFgQX7 +sZB6H7f2C2VZGwmbOwANmzHY0vsgEgCIG7misbEg9fcfHP3ZYd08L2Vr8OAvcDJy +sP/wLkovMhYAAABncnViX2NtZDogaW5zbW9kIGV4dDIACQAAAA0AAAADAAAABADb +rrsY0z1zLWm8n67wneXdWYT6awsA8j2ng1Yjwg/zvbJGPmBuYkk9WsNLW0Jj2P6C +ZQpuvF8SAM7NB3o0UVU/5ZLpBJUWuw2bg6GAyluIket4heb9/FBbKQAAAChoZDAs +Z3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvZXh0Mi5tb2QACAAAAA0AAAADAAAA +BADfamdAgKAhvedC8g3+pLJozZgVUgsAbeEtJhuxX/bI6VzhWw0hlkicSxOELr5Y +IRuo8/JNkB8SAKYuuWmHW99wAl0NK4Hx2gafDG1voliyc0wvjc8a9i7dHAAAAGdy +dWJfY21kOiBzZXQgcm9vdD1oZDAsZ3B0MwAIAAAADQAAAAMAAAAEAPWwZ+WcFj9n +sZuDb77p6KSHoZzdCwBFaDYft1gbMaQtZFq1NDAvufdCrao3t/3hUiFdaeJZ+xIA +Sa2gpw1zvSlv94yDh8mE9DwDrTCTxSQZdvduZBn9eVwWAAAAZ3J1Yl9jbWQ6IFsg +eHkgPSB4eSBdAAgAAAANAAAAAwAAAAQATMP7kmm/EUVBv7QSd/T33+LJSQgLABuL +vvzDeIcozoQ/m3FzNpJWMi0ikYeNTjy+p12RnZxgEgCIPVwwnDX2fvVP6WWVYRfR +mdlZfMvhA94+ZWRVZGLdeZwAAABncnViX2NtZDogc2VhcmNoIC0tbm8tZmxvcHB5 +IC0tZnMtdXVpZCAtLXNldD1yb290IC0taGludC1iaW9zPWhkMCxncHQzIC0taGlu +dC1lZmk9aGQwLGdwdDMgLS1oaW50LWJhcmVtZXRhbD1haGNpMCxncHQzIDY2ODlj +ZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYQAJAAAADQAAAAMAAAAEAKiR +G5udjT9Sbol5iSD5zsajp7GuCwDGJte2i1luFtEk6PRs+5ZAy1a39f1G1UenN2+6 +PjYXUhIAdr31+T+53Xq3B+T3lidzoE19eqx3IjKx7+8x7r5SLB8rAAAAKGhkMCxn +cHQxKS9ib290L2dydWIveDg2XzY0LWVmaS9zZWFyY2gubW9kAAkAAAANAAAAAwAA +AAQAGQnBVCcHd2wHH7dO401jsgXHXzELAFjY88ApoovEDVFFZsrYH+OBOg57ruyq +pEkJQwDn0XP1EgB2PovmyxcmMIaY4CN1ZL3x0Db7VgXzKGACUr/YBvLWqDMAAAAo +aGQwLGdwdDEpL2Jvb3QvZ3J1Yi94ODZfNjQtZWZpL3NlYXJjaF9mc191dWlkLm1v +ZAAJAAAADQAAAAMAAAAEADZa7PWHq+vcWH6fkpRzZGrFckv1CwBoT2+Sc9y3hIwO +u718cZzYSowZ1OBvc5IJVUGpjMeyMhIALRgq32ePDD+Aa6bTE93cxCozz731YVZ8 +kq7muQnz9MMzAAAAKGhkMCxncHQxKS9ib290L2dydWIveDg2XzY0LWVmaS9zZWFy +Y2hfZnNfZmlsZS5tb2QACQAAAA0AAAADAAAABABcdSIFtA5Ea6Zpwi3TE0wF5J9I ++wsARXH6UTiGl+GLFj7QnvlszlWjJsHnqm2qDcaTuvMaorQSAFlYN8hTGAFB3q3r +3adRCJEiLxL10ZEG8ELM+xazSQ+BMQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4 +Nl82NC1lZmkvc2VhcmNoX2xhYmVsLm1vZAAIAAAADQAAAAMAAAAEADlomZC6TdSO +K00X0hP2gzhJuDk/CwDVNY5GJbEF7TQksXcmhJZYkYcvSCP6CjfWj6ubanyfjBIA +xOXvTNXyuIYPZFhSKeDqtAhCVMoMjWlhsXjBhFFoVdkZAAAAZ3J1Yl9jbWQ6IGlu +c21vZCBnZnhtZW51AAkAAAANAAAAAwAAAAQAI8mh/qMXg1BcdOk2du+hRrmazCwL +ADiSuWemz1TpMSuXFvj8Ff/0Qlz4YNmAgli238KsyGo4EgCqiZ6FgULdwKuHos5N +UZBN994491kJrptMqVzMt1kCcCwAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1Yi94ODZf +NjQtZWZpL2dmeG1lbnUubW9kAAkAAAANAAAAAwAAAAQAp7P8PkOY+IIVMxrdt0Ug +j8T+xJcLAFYvo+JetRkJFMgZtIvQKqxEqrW/kRgoh2cMw8RyVcnMEgBb/rIlbgrY +o8tbY1sDw7NBqwG6Q1kcSnbtU2zcL3+mASsAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1 +Yi94ODZfNjQtZWZpL2JpdG1hcC5tb2QACQAAAA0AAAADAAAABABFcTnAoIUyM9en +QaB8orW2ao0aQQsA4bMgth022D9TRrLE6zNvgljfOqCYuRlc9asx+oy6UXQSAJZR +WVxzTwtOusha6dXtnANUGSpS4/Ma2ix56VD/kgS+MQAAAChoZDAsZ3B0MSkvYm9v +dC9ncnViL3g4Nl82NC1lZmkvdmlkZW9fY29sb3JzLm1vZAAJAAAADQAAAAMAAAAE +ADpJVozKuVlyGMwnsoCdOgyiNEx7CwDiyVJezM8rmLu+V8nMI51oBo6fcNOaVtM/ +ktE5B9BeWxIA64wkU4p/Rd/soCHAIV07HHYpe86g/FRbe/bn65fprqcxAAAAKGhk +MCxncHQxKS9ib290L2dydWIveDg2XzY0LWVmaS9iaXRtYXBfc2NhbGUubW9kAAkA +AAANAAAAAwAAAAQAY3GrDBD73J+LagQXhdca+bH99rMLAATHxyK/ETQ/6/CXbIh7 +ycO948u0FBXPCplpHyiAoGFWEgDy6bStfIXnTHIhj8cC4MDG1UbqHT+UhBchtvt3 +ySZzgCkAAAAoaGQwLGdwdDEpL2Jvb3QvZ3J1Yi94ODZfNjQtZWZpL3RyaWcubW9k +AAgAAAANAAAAAwAAAAQAIN07Bwx4u5LCWgTWl0oChNmV2SQLAGX9g9S0CWDM7Hi5 +DejYE37RAUOtT5CpujvdlbFcCea4EgAZ8MAmluPnC16vm8Q30SG2jdeIb+Vzrd1/ +9rQfK3YIeE0AAABncnViX2NtZDogbG9hZGZvbnQgKGhkMCxncHQzKS91c3Ivc2hh +cmUvZ3J1Yi90aGVtZXMvVUtVSS91bmlmb250LWJvbGQtMTYucGYyAAkAAAANAAAA +AwAAAAQAPEKvzgyWH/Gd8TIjpUbA3Nod6/ILAMgt9Lz95OaZsK9wBY6kKpdF7cUV +LNS6lV/jcwDx8HmoEgBSfO5bQwBG+XE07bxcxyDodvvvQgUoIgFhV2jISd6D5DoA +AAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3VuaWZvbnQt +Ym9sZC0xNi5wZjIACAAAAA0AAAADAAAABAAX1UJxEJ5TrFxwyH7bqJMdssgQpQsA +lBvz9OqzEKsZdreX8EDhBnM5uvmrc7TnKrJEzEgBsr0SAMXNnLqlAntEeKk7g/Yt +sbqgD4Bd6zQ0ulBdOHinOBhmUAAAAGdydWJfY21kOiBsb2FkZm9udCAoaGQwLGdw +dDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3VuaWZvbnQtcmVndWxhci0x +Ni5wZjIACQAAAA0AAAADAAAABADvmZCGE+94vnFr8TQ6J8FYUpbSywsALHZpXG27 +NzahOktltyCqvpWV3OOc9Xla6710umOQGQcSAG/aV6h31O+uJ8qFbLYKKo6w77W4 +KDfpoTW6g543oif7PQAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVz +L1VLVUkvdW5pZm9udC1yZWd1bGFyLTE2LnBmMgAIAAAADQAAAAMAAAAEABddTnMv +mEcDglOytB40SDYkK7F/CwB8+gcXR2lEIexO0zd8Rn2z00/XbDKcOfcK6Faz2drG +AhIATIE2FjESpuTXmQZpuo8qByN0jZGSKu4zgLZ/ihjJAukVAAAAZ3J1Yl9jbWQ6 +IGluc21vZCBwbmcACQAAAA0AAAADAAAABACWSiIGJAfnjARL+fTja8CIc72+YwsA +px7aP7ftAEMi6WFul0j6Ecxz4sGLuWLCCzTZZUGZQVQSAAo+ZTcApbKirdlYRGXK +s5Vv7KzBLBuqf9xCll/a3soMKAAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82 +NC1lZmkvcG5nLm1vZAAIAAAADQAAAAMAAAAEAE37RvubxJV+lYwQquZGIcQZHJ69 +CwAKeDYjNTPZorGpMOlNrqeac46s2TJuqvwB6XALyTjDqxIA6iOYS2TWCfy3/I+0 +fh5nyjhL327GIjpWPf0AdeEox+REAAAAZ3J1Yl9jbWQ6IHNldCB0aGVtZT0oaGQw +LGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3RoZW1lLnR4dAAIAAAA +DQAAAAMAAAAEAIDx46p9OIcEY5l1bhrwGI22/9bvCwAZFYHaxl0cOKY9Bsh8tRiu +BGaO0GqtPgCjPqjSQYAbdhIADqBmx76d4Hine/hrvVNJ7tau16wbLU8CnFuISOhv +saUXAAAAZ3J1Yl9jbWQ6IGV4cG9ydCB0aGVtZQAIAAAADQAAAAMAAAAEAEIyh6QL +kUu1FJfbMvkIZpfR+54SCwDwtLPCMQOCjqL6BQRKLPzl78nRXpn/ucYdc0nBMDdB +rxIAnuWEidCYiUvHs/xxtpWcUfTGduK2UmnxkCRvhm3udIwUAAAAZ3J1Yl9jbWQ6 +IFsgICE9IDEgXQAIAAAADQAAAAMAAAAEACkszpDSjhc2qOkU6FQNm/DjyzaRCwBd +iE5S0OGR2IIbd8eoU6iaLQWER0PI6YGHtHTYAPHH5hIAsTNxYT9ZyrwWUDTUhztO +G1h667IQXhD6MgMOTlqZrjI3AAAAZ3J1Yl9jbWQ6IFsgLWUgKGhkMCxncHQxKS9i +b290L2dydWIvZ2Z4YmxhY2tsaXN0LnR4dCBdAAgAAAANAAAAAwAAAAQAaJd6J9k8 +Xig298VNYk3Uj+7A9n0LAPJJ52Gn43UQ+Kz1kULBF0RMOqG8WnGa5+q2DTtxCRgK +EgA5kv6lJ3EeL9Osr0YNb87mA7h16YwtXVNNsoJmf+r3SCIAAABncnViX2NtZDog +c2V0IGxpbnV4X2dmeF9tb2RlPWtlZXAACAAAAA0AAAADAAAABACd7vD6RE5Z16CO +YV8lYogm5/7d+QsAIuBBJR61TusycCRXWao+i9O3emR9uYi2gbHq/GlgqkUSAMkt +oqQHT+zQtWZQvzbsk8qzjf/UqSQWFbV3qUuq3SpcIAAAAGdydWJfY21kOiBleHBv +cnQgbGludXhfZ2Z4X21vZGUACAAAAA0AAAADAAAABACWg/0LSN2DCf8oL2z9gwfw +DHQ0NAsA+hTAvhWWzwv+y4rfv0x31m/vOP/ebC1fXoHdpGs8Jn0SAB5mf3Q2yXBE +3acMjNb16Vxkbw5tP1JaI4OZQ4bBsvvLkQMAAGdydWJfY21kOiBtZW51ZW50cnkg +S3lsaW4gVjEwIFNQMSA1LjQuMTgtMzUtZ2VuZXJpYyAtLWNsYXNzIGt5bGluIC0t +Y2xhc3MgZ251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mgb3MgLS1pZCBnbnVs +aW51eC1zaW1wbGUtNjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNh +IHsKCXJlY29yZGZhaWwKCWxvYWRfdmlkZW8KCWdmeG1vZGUgJGxpbnV4X2dmeF9t +b2RlCglpbnNtb2QgZ3ppbwoJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07 +IHRoZW4gaW5zbW9kIHh6aW87IGluc21vZCBsem9waW87IGZpCglpbnNtb2QgcGFy +dF9ncHQKCWluc21vZCBleHQyCglzZXQgcm9vdD0naGQwLGdwdDInCglpZiBbIHgk +ZmVhdHVyZV9wbGF0Zm9ybV9zZWFyY2hfaGludCA9IHh5IF07IHRoZW4KCSAgc2Vh +cmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IC0taGludC1iaW9z +PWhkMCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIgLS1oaW50LWJhcmVtZXRhbD1h +aGNpMCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcK +CWVsc2UKCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290 +IGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJZmkKCWxpbnV4 +CS92bWxpbnV6LTUuNC4xOC0zNS1nZW5lcmljIHJvb3Q9VVVJRD02Njg5Y2ZiZS03 +YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2Egcm8gIHF1aWV0IHNwbGFzaCBkZWZh +dWx0X2h1Z2VwYWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBtZW1f +ZW5jcnlwdD1vZmYgIHJlc3VtZT1VVUlEPTZhM2ExNmVmLWMwMTEtNDkxNi1iMDc4 +LWNlNjk5YjIxN2Y4MCBhdWRpdD0wIHNlY3VyaXR5PWt5c2VjCglpbml0cmQJL2lu +aXRyZC5pbWctNS40LjE4LTM1LWdlbmVyaWMKfQAIAAAADQAAAAMAAAAEAPe2AaP4 +DdXGgOwGRMGZOcZX9mneCwCAeQLw59WxvQu1Q+6Mh67lN/vtVwjR0ixOgFMHIKXV +oRIAoHHUWizsY3KnZ6utFDTrSeby+3KLZEf63Aj9isbcjGu4CAAAZ3J1Yl9jbWQ6 +IHN1Ym1lbnUgS3lsaW4gVjEwIFNQMSAo57O757uf5aSH5Lu96L+Y5Y6f5qih5byP +KSAtLWlkIGdudWxpbnV4LWFkdmFuY2VkLTY2ODljZmJlLTdjM2EtNDM4Yi04NmZk +LTJkMTAzOWQ1ZDljYSB7CgltZW51ZW50cnkgJ0t5bGluIFYxMCBTUDEsIHdpdGgg +NS40LjE4LTM1LWdlbmVyaWMgKGJhY2t1cCBtb2RlKScgLS1jbGFzcyBreWxpbiAt +LWNsYXNzIGdudS1saW51eCAtLWNsYXNzIGdudSAtLWNsYXNzIG9zICRtZW51ZW50 +cnlfaWRfb3B0aW9uICdnbnVsaW51eC01LjQuMTgtMzUtZ2VuZXJpYy1iYWNrdXAt +NjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhJyB7CgkJcmVjb3Jk +ZmFpbAoJCWxvYWRfdmlkZW8KCQlnZnhtb2RlICRsaW51eF9nZnhfbW9kZQoJCWlu +c21vZCBnemlvCgkJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07IHRoZW4g +aW5zbW9kIHh6aW87IGluc21vZCBsem9waW87IGZpCgkJaW5zbW9kIHBhcnRfZ3B0 +CgkJaW5zbW9kIGV4dDIKCQlzZXQgcm9vdD0naGQwLGdwdDInCgkJaWYgWyB4JGZl +YXR1cmVfcGxhdGZvcm1fc2VhcmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJICBzZWFy +Y2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgLS1oaW50LWJpb3M9 +aGQwLGdwdDIgLS1oaW50LWVmaT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1ldGFsPWFo +Y2kwLGdwdDIgIGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJ +CWVsc2UKCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9v +dCBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQlmaQoJCWVj +aG8JJ+i9veWFpSBMaW51eCA1LjQuMTgtMzUtZ2VuZXJpYyAuLi4nCgkgICAgICBs +aW51eCAgIC92bWxpbnV6LTUuNC4xOC0zNS1nZW5lcmljIHJvb3Q9VVVJRD02Njg5 +Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2EgcncgIHF1aWV0IHNwbGFz +aCBkZWZhdWx0X2h1Z2VwYWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9 +MSBtZW1fZW5jcnlwdD1vZmYgIHJlc3VtZT1VVUlEPTZhM2ExNmVmLWMwMTEtNDkx +Ni1iMDc4LWNlNjk5YjIxN2Y4MCBhdWRpdD0wIHNlY3VyaXR5PWt5c2VjIHNlbGlu +dXg9MCBiYWNrdXAKCSAgICAgIGluaXRyZCAgL2luaXRyZC5pbWctNS40LjE4LTM1 +LWdlbmVyaWMKCX0KCW1lbnVlbnRyeSAnS3lsaW4gVjEwIFNQMSwgd2l0aCA1LjQu +MTgtMzUtZ2VuZXJpYyAocmVzdG9yZSBtb2RlKScgLS1jbGFzcyBreWxpbiAtLWNs +YXNzIGdudS1saW51eCAtLWNsYXNzIGdudSAtLWNsYXNzIG9zICRtZW51ZW50cnlf +aWRfb3B0aW9uICdnbnVsaW51eC01LjQuMTgtMzUtZ2VuZXJpYy1yZXN0b3JlLTY2 +ODljZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYScgewoJCXJlY29yZGZh +aWwKCQlsb2FkX3ZpZGVvCgkJZ2Z4bW9kZSAkbGludXhfZ2Z4X21vZGUKCQlpbnNt +b2QgZ3ppbwoJCWlmIFsgeCRncnViX3BsYXRmb3JtID0geHhlbiBdOyB0aGVuIGlu +c21vZCB4emlvOyBpbnNtb2QgbHpvcGlvOyBmaQoJCWluc21vZCBwYXJ0X2dwdAoJ +CWluc21vZCBleHQyCgkJc2V0IHJvb3Q9J2hkMCxncHQyJwoJCWlmIFsgeCRmZWF0 +dXJlX3BsYXRmb3JtX3NlYXJjaF9oaW50ID0geHkgXTsgdGhlbgoJCSAgc2VhcmNo +IC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IC0taGludC1iaW9zPWhk +MCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIgLS1oaW50LWJhcmVtZXRhbD1haGNp +MCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQll +bHNlCgkJICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3Qg +ZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZmkKCQllY2hv +CSfovb3lhaUgTGludXggNS40LjE4LTM1LWdlbmVyaWMgLi4uJwoJICAgICAgbGlu +dXggICAvdm1saW51ei01LjQuMTgtMzUtZ2VuZXJpYyByb290PVVVSUQ9NjY4OWNm +YmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHJ3ICBxdWlldCBzcGxhc2gg +ZGVmYXVsdF9odWdlcGFnZXN6PTFHIGh1Z2VwYWdlc3o9MUcgaHVnZXBhZ2VzPTEg +bWVtX2VuY3J5cHQ9b2ZmICByZXN1bWU9VVVJRD02YTNhMTZlZi1jMDExLTQ5MTYt +YjA3OC1jZTY5OWIyMTdmODAgYXVkaXQ9MCBzZWN1cml0eT1reXNlYyBzZWxpbnV4 +PTAgcmVzdG9yZQoJICAgICAgaW5pdHJkICAvaW5pdHJkLmltZy01LjQuMTgtMzUt +Z2VuZXJpYwoJfQogIH0ACAAAAA0AAAADAAAABAAXYdVqJCChMFeqWTm/nsb3uuDa +8wsAYjFBHsIpkC1hYPlAwOMUcd+Cke4dV5r6TT/cPCOadpUSAK5htSKR5zDJTkbB +MdUwVqoiU/9PrQeQjUbJgQBbvL8/aiYAAGdydWJfY21kOiBzdWJtZW51IEt5bGlu +IFYxMCBTUDEg55qE6auY57qn6YCJ6aG5IC0taWQgZ251bGludXgtYWR2YW5jZWQt +NjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHsKCW1lbnVlbnRy +eSAnS3lsaW4gVjEwIFNQMSwgNS40LjE4LTM1LWdlbmVyaWMnIC0tY2xhc3Mga3ls +aW4gLS1jbGFzcyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAkbWVu +dWVudHJ5X2lkX29wdGlvbiAnZ251bGludXgtNS40LjE4LTM1LWdlbmVyaWMtYWR2 +YW5jZWQtNjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhJyB7CgkJ +cmVjb3JkZmFpbAoJCWxvYWRfdmlkZW8KCQlnZnhtb2RlICRsaW51eF9nZnhfbW9k +ZQoJCWluc21vZCBnemlvCgkJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07 +IHRoZW4gaW5zbW9kIHh6aW87IGluc21vZCBsem9waW87IGZpCgkJaW5zbW9kIHBh +cnRfZ3B0CgkJaW5zbW9kIGV4dDIKCQlzZXQgcm9vdD0naGQwLGdwdDInCgkJaWYg +WyB4JGZlYXR1cmVfcGxhdGZvcm1fc2VhcmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJ +ICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgLS1oaW50 +LWJpb3M9aGQwLGdwdDIgLS1oaW50LWVmaT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1l +dGFsPWFoY2kwLGdwdDIgIGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVm +M2UwNwoJCWVsc2UKCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1z +ZXQ9cm9vdCBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQlm +aQoJCWVjaG8JJ+i9veWFpSBMaW51eCA1LjQuMTgtMzUtZ2VuZXJpYyAuLi4nCgkJ +bGludXgJL3ZtbGludXotNS40LjE4LTM1LWdlbmVyaWMgcm9vdD1VVUlEPTY2ODlj +ZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYSBybyAgcXVpZXQgc3BsYXNo +IGRlZmF1bHRfaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXN6PTFHIGh1Z2VwYWdlcz0x +IG1lbV9lbmNyeXB0PW9mZiAgcmVzdW1lPVVVSUQ9NmEzYTE2ZWYtYzAxMS00OTE2 +LWIwNzgtY2U2OTliMjE3ZjgwIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMKCQllY2hv +CSfovb3lhaXliJ3lp4vljJblhoXlrZjnm5guLi4nCgkJaW5pdHJkCS9pbml0cmQu +aW1nLTUuNC4xOC0zNS1nZW5lcmljCgl9CgltZW51ZW50cnkgJ0t5bGluIFYxMCBT +UDEsIDUuNC4xOC0zNS1nZW5lcmljIChyZWNvdmVyeSBtb2RlKScgLS1jbGFzcyBr +eWxpbiAtLWNsYXNzIGdudS1saW51eCAtLWNsYXNzIGdudSAtLWNsYXNzIG9zICRt +ZW51ZW50cnlfaWRfb3B0aW9uICdnbnVsaW51eC01LjQuMTgtMzUtZ2VuZXJpYy1y +ZWNvdmVyeS02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2EnIHsK +CQlyZWNvcmRmYWlsCgkJbG9hZF92aWRlbwoJCWluc21vZCBnemlvCgkJaWYgWyB4 +JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07IHRoZW4gaW5zbW9kIHh6aW87IGluc21v +ZCBsem9waW87IGZpCgkJaW5zbW9kIHBhcnRfZ3B0CgkJaW5zbW9kIGV4dDIKCQlz +ZXQgcm9vdD0naGQwLGdwdDInCgkJaWYgWyB4JGZlYXR1cmVfcGxhdGZvcm1fc2Vh +cmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJICBzZWFyY2ggLS1uby1mbG9wcHkgLS1m +cy11dWlkIC0tc2V0PXJvb3QgLS1oaW50LWJpb3M9aGQwLGdwdDIgLS1oaW50LWVm +aT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1ldGFsPWFoY2kwLGdwdDIgIGZjNTFiNTM5 +LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJCWVsc2UKCQkgIHNlYXJjaCAt +LW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCBmYzUxYjUzOS1lOGFiLTQw +M2MtODAyZC02NjcyZTRlZjNlMDcKCQlmaQoJCWVjaG8JJ+i9veWFpSBMaW51eCA1 +LjQuMTgtMzUtZ2VuZXJpYyAuLi4nCgkJbGludXgJL3ZtbGludXotNS40LjE4LTM1 +LWdlbmVyaWMgcm9vdD1VVUlEPTY2ODljZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAz +OWQ1ZDljYSBybyBzaW5nbGUgbm9tb2Rlc2V0IGRpc191Y29kZV9sZHIgIGF1ZGl0 +PTAgc2VjdXJpdHk9a3lzZWMKCQllY2hvCSfovb3lhaXliJ3lp4vljJblhoXlrZjn +m5guLi4nCgkJaW5pdHJkCS9pbml0cmQuaW1nLTUuNC4xOC0zNS1nZW5lcmljCgl9 +CgltZW51ZW50cnkgJ0t5bGluIFYxMCBTUDEsIDUuNC4xOC10a21fb3JpJyAtLWNs +YXNzIGt5bGluIC0tY2xhc3MgZ251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mg +b3MgJG1lbnVlbnRyeV9pZF9vcHRpb24gJ2dudWxpbnV4LTUuNC4xOC10a21fb3Jp +LWFkdmFuY2VkLTY2ODljZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYScg +ewoJCXJlY29yZGZhaWwKCQlsb2FkX3ZpZGVvCgkJZ2Z4bW9kZSAkbGludXhfZ2Z4 +X21vZGUKCQlpbnNtb2QgZ3ppbwoJCWlmIFsgeCRncnViX3BsYXRmb3JtID0geHhl +biBdOyB0aGVuIGluc21vZCB4emlvOyBpbnNtb2QgbHpvcGlvOyBmaQoJCWluc21v +ZCBwYXJ0X2dwdAoJCWluc21vZCBleHQyCgkJc2V0IHJvb3Q9J2hkMCxncHQyJwoJ +CWlmIFsgeCRmZWF0dXJlX3BsYXRmb3JtX3NlYXJjaF9oaW50ID0geHkgXTsgdGhl +bgoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IC0t +aGludC1iaW9zPWhkMCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIgLS1oaW50LWJh +cmVtZXRhbD1haGNpMCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02Njcy +ZTRlZjNlMDcKCQllbHNlCgkJICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11dWlk +IC0tc2V0PXJvb3QgZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3 +CgkJZmkKCQllY2hvCSfovb3lhaUgTGludXggNS40LjE4LXRrbV9vcmkgLi4uJwoJ +CWxpbnV4CS92bWxpbnV6LTUuNC4xOC10a21fb3JpIHJvb3Q9VVVJRD02Njg5Y2Zi +ZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2Egcm8gIHF1aWV0IHNwbGFzaCBk +ZWZhdWx0X2h1Z2VwYWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBt +ZW1fZW5jcnlwdD1vZmYgIHJlc3VtZT1VVUlEPTZhM2ExNmVmLWMwMTEtNDkxNi1i +MDc4LWNlNjk5YjIxN2Y4MCBhdWRpdD0wIHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn +6L295YWl5Yid5aeL5YyW5YaF5a2Y55uYLi4uJwoJCWluaXRyZAkvaW5pdHJkLmlt +Zy01LjQuMTgtdGttX29yaQoJfQoJbWVudWVudHJ5ICdLeWxpbiBWMTAgU1AxLCA1 +LjQuMTgtdGttX29yaSAocmVjb3ZlcnkgbW9kZSknIC0tY2xhc3Mga3lsaW4gLS1j +bGFzcyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAkbWVudWVudHJ5 +X2lkX29wdGlvbiAnZ251bGludXgtNS40LjE4LXRrbV9vcmktcmVjb3ZlcnktNjY4 +OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhJyB7CgkJcmVjb3JkZmFp +bAoJCWxvYWRfdmlkZW8KCQlpbnNtb2QgZ3ppbwoJCWlmIFsgeCRncnViX3BsYXRm +b3JtID0geHhlbiBdOyB0aGVuIGluc21vZCB4emlvOyBpbnNtb2QgbHpvcGlvOyBm +aQoJCWluc21vZCBwYXJ0X2dwdAoJCWluc21vZCBleHQyCgkJc2V0IHJvb3Q9J2hk +MCxncHQyJwoJCWlmIFsgeCRmZWF0dXJlX3BsYXRmb3JtX3NlYXJjaF9oaW50ID0g +eHkgXTsgdGhlbgoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNl +dD1yb290IC0taGludC1iaW9zPWhkMCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIg +LS1oaW50LWJhcmVtZXRhbD1haGNpMCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2Mt +ODAyZC02NjcyZTRlZjNlMDcKCQllbHNlCgkJICBzZWFyY2ggLS1uby1mbG9wcHkg +LS1mcy11dWlkIC0tc2V0PXJvb3QgZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3 +MmU0ZWYzZTA3CgkJZmkKCQllY2hvCSfovb3lhaUgTGludXggNS40LjE4LXRrbV9v +cmkgLi4uJwoJCWxpbnV4CS92bWxpbnV6LTUuNC4xOC10a21fb3JpIHJvb3Q9VVVJ +RD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2Egcm8gc2luZ2xl +IG5vbW9kZXNldCBkaXNfdWNvZGVfbGRyICBhdWRpdD0wIHNlY3VyaXR5PWt5c2Vj +CgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uYLi4uJwoJCWluaXRyZAkv +aW5pdHJkLmltZy01LjQuMTgtdGttX29yaQoJfQoJbWVudWVudHJ5ICdLeWxpbiBW +MTAgU1AxLCA1LjQuMTgtdGttX29yaS5vbGQnIC0tY2xhc3Mga3lsaW4gLS1jbGFz +cyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAkbWVudWVudHJ5X2lk +X29wdGlvbiAnZ251bGludXgtNS40LjE4LXRrbV9vcmkub2xkLWFkdmFuY2VkLTY2 +ODljZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYScgewoJCXJlY29yZGZh +aWwKCQlsb2FkX3ZpZGVvCgkJZ2Z4bW9kZSAkbGludXhfZ2Z4X21vZGUKCQlpbnNt +b2QgZ3ppbwoJCWlmIFsgeCRncnViX3BsYXRmb3JtID0geHhlbiBdOyB0aGVuIGlu +c21vZCB4emlvOyBpbnNtb2QgbHpvcGlvOyBmaQoJCWluc21vZCBwYXJ0X2dwdAoJ +CWluc21vZCBleHQyCgkJc2V0IHJvb3Q9J2hkMCxncHQyJwoJCWlmIFsgeCRmZWF0 +dXJlX3BsYXRmb3JtX3NlYXJjaF9oaW50ID0geHkgXTsgdGhlbgoJCSAgc2VhcmNo +IC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IC0taGludC1iaW9zPWhk +MCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIgLS1oaW50LWJhcmVtZXRhbD1haGNp +MCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQll +bHNlCgkJICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3Qg +ZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZmkKCQllY2hv +CSfovb3lhaUgTGludXggNS40LjE4LXRrbV9vcmkub2xkIC4uLicKCQlsaW51eAkv +dm1saW51ei01LjQuMTgtdGttX29yaS5vbGQgcm9vdD1VVUlEPTY2ODljZmJlLTdj +M2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYSBybyAgcXVpZXQgc3BsYXNoIGRlZmF1 +bHRfaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXN6PTFHIGh1Z2VwYWdlcz0xIG1lbV9l +bmNyeXB0PW9mZiAgcmVzdW1lPVVVSUQ9NmEzYTE2ZWYtYzAxMS00OTE2LWIwNzgt +Y2U2OTliMjE3ZjgwIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMKCQllY2hvCSfovb3l +haXliJ3lp4vljJblhoXlrZjnm5guLi4nCgkJaW5pdHJkCS9pbml0cmQuaW1nLTUu +NC4xOC10a21fb3JpCgl9CgltZW51ZW50cnkgJ0t5bGluIFYxMCBTUDEsIDUuNC4x +OC10a21fb3JpLm9sZCAocmVjb3ZlcnkgbW9kZSknIC0tY2xhc3Mga3lsaW4gLS1j +bGFzcyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAkbWVudWVudHJ5 +X2lkX29wdGlvbiAnZ251bGludXgtNS40LjE4LXRrbV9vcmkub2xkLXJlY292ZXJ5 +LTY2ODljZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYScgewoJCXJlY29y +ZGZhaWwKCQlsb2FkX3ZpZGVvCgkJaW5zbW9kIGd6aW8KCQlpZiBbIHgkZ3J1Yl9w +bGF0Zm9ybSA9IHh4ZW4gXTsgdGhlbiBpbnNtb2QgeHppbzsgaW5zbW9kIGx6b3Bp +bzsgZmkKCQlpbnNtb2QgcGFydF9ncHQKCQlpbnNtb2QgZXh0MgoJCXNldCByb290 +PSdoZDAsZ3B0MicKCQlpZiBbIHgkZmVhdHVyZV9wbGF0Zm9ybV9zZWFyY2hfaGlu +dCA9IHh5IF07IHRoZW4KCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQg +LS1zZXQ9cm9vdCAtLWhpbnQtYmlvcz1oZDAsZ3B0MiAtLWhpbnQtZWZpPWhkMCxn +cHQyIC0taGludC1iYXJlbWV0YWw9YWhjaTAsZ3B0MiAgZmM1MWI1MzktZThhYi00 +MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZWxzZQoJCSAgc2VhcmNoIC0tbm8tZmxv +cHB5IC0tZnMtdXVpZCAtLXNldD1yb290IGZjNTFiNTM5LWU4YWItNDAzYy04MDJk +LTY2NzJlNGVmM2UwNwoJCWZpCgkJZWNobwkn6L295YWlIExpbnV4IDUuNC4xOC10 +a21fb3JpLm9sZCAuLi4nCgkJbGludXgJL3ZtbGludXotNS40LjE4LXRrbV9vcmku +b2xkIHJvb3Q9VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5 +Y2Egcm8gc2luZ2xlIG5vbW9kZXNldCBkaXNfdWNvZGVfbGRyICBhdWRpdD0wIHNl +Y3VyaXR5PWt5c2VjCgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uYLi4u +JwoJCWluaXRyZAkvaW5pdHJkLmltZy01LjQuMTgtdGttX29yaQoJfQoJbWVudWVu +dHJ5ICdLeWxpbiBWMTAgU1AxLCA1LjQuMTgtdGttJyAtLWNsYXNzIGt5bGluIC0t +Y2xhc3MgZ251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mgb3MgJG1lbnVlbnRy +eV9pZF9vcHRpb24gJ2dudWxpbnV4LTUuNC4xOC10a20tYWR2YW5jZWQtNjY4OWNm +YmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhJyB7CgkJcmVjb3JkZmFpbAoJ +CWxvYWRfdmlkZW8KCQlnZnhtb2RlICRsaW51eF9nZnhfbW9kZQoJCWluc21vZCBn +emlvCgkJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07IHRoZW4gaW5zbW9k +IHh6aW87IGluc21vZCBsem9waW87IGZpCgkJaW5zbW9kIHBhcnRfZ3B0CgkJaW5z +bW9kIGV4dDIKCQlzZXQgcm9vdD0naGQwLGdwdDInCgkJaWYgWyB4JGZlYXR1cmVf +cGxhdGZvcm1fc2VhcmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJICBzZWFyY2ggLS1u +by1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgLS1oaW50LWJpb3M9aGQwLGdw +dDIgLS1oaW50LWVmaT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1ldGFsPWFoY2kwLGdw +dDIgIGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJCWVsc2UK +CQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCBmYzUx +YjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQlmaQoJCWVjaG8JJ+i9 +veWFpSBMaW51eCA1LjQuMTgtdGttIC4uLicKCQlsaW51eAkvdm1saW51ei01LjQu +MTgtdGttIHJvb3Q9VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlk +NWQ5Y2Egcm8gIHF1aWV0IHNwbGFzaCBkZWZhdWx0X2h1Z2VwYWdlc3o9MUcgaHVn +ZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBtZW1fZW5jcnlwdD1vZmYgIHJlc3VtZT1V +VUlEPTZhM2ExNmVmLWMwMTEtNDkxNi1iMDc4LWNlNjk5YjIxN2Y4MCBhdWRpdD0w +IHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uY +Li4uJwoJCWluaXRyZAkvaW5pdHJkLmltZy01LjQuMTgtdGttCgl9CgltZW51ZW50 +cnkgJ0t5bGluIFYxMCBTUDEsIDUuNC4xOC10a20gKHJlY292ZXJ5IG1vZGUpJyAt +LWNsYXNzIGt5bGluIC0tY2xhc3MgZ251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xh +c3Mgb3MgJG1lbnVlbnRyeV9pZF9vcHRpb24gJ2dudWxpbnV4LTUuNC4xOC10a20t +cmVjb3ZlcnktNjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhJyB7 +CgkJcmVjb3JkZmFpbAoJCWxvYWRfdmlkZW8KCQlpbnNtb2QgZ3ppbwoJCWlmIFsg +eCRncnViX3BsYXRmb3JtID0geHhlbiBdOyB0aGVuIGluc21vZCB4emlvOyBpbnNt +b2QgbHpvcGlvOyBmaQoJCWluc21vZCBwYXJ0X2dwdAoJCWluc21vZCBleHQyCgkJ +c2V0IHJvb3Q9J2hkMCxncHQyJwoJCWlmIFsgeCRmZWF0dXJlX3BsYXRmb3JtX3Nl +YXJjaF9oaW50ID0geHkgXTsgdGhlbgoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0t +ZnMtdXVpZCAtLXNldD1yb290IC0taGludC1iaW9zPWhkMCxncHQyIC0taGludC1l +Zmk9aGQwLGdwdDIgLS1oaW50LWJhcmVtZXRhbD1haGNpMCxncHQyICBmYzUxYjUz +OS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQllbHNlCgkJICBzZWFyY2gg +LS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgZmM1MWI1MzktZThhYi00 +MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZmkKCQllY2hvCSfovb3lhaUgTGludXgg +NS40LjE4LXRrbSAuLi4nCgkJbGludXgJL3ZtbGludXotNS40LjE4LXRrbSByb290 +PVVVSUQ9NjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHJvIHNp +bmdsZSBub21vZGVzZXQgZGlzX3Vjb2RlX2xkciAgYXVkaXQ9MCBzZWN1cml0eT1r +eXNlYwoJCWVjaG8JJ+i9veWFpeWIneWni+WMluWGheWtmOebmC4uLicKCQlpbml0 +cmQJL2luaXRyZC5pbWctNS40LjE4LXRrbQoJfQoJbWVudWVudHJ5ICdLeWxpbiBW +MTAgU1AxLCA1LjQuMTgtY3N2JyAtLWNsYXNzIGt5bGluIC0tY2xhc3MgZ251LWxp +bnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mgb3MgJG1lbnVlbnRyeV9pZF9vcHRpb24g +J2dudWxpbnV4LTUuNC4xOC1jc3YtYWR2YW5jZWQtNjY4OWNmYmUtN2MzYS00Mzhi +LTg2ZmQtMmQxMDM5ZDVkOWNhJyB7CgkJcmVjb3JkZmFpbAoJCWxvYWRfdmlkZW8K +CQlnZnhtb2RlICRsaW51eF9nZnhfbW9kZQoJCWluc21vZCBnemlvCgkJaWYgWyB4 +JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07IHRoZW4gaW5zbW9kIHh6aW87IGluc21v +ZCBsem9waW87IGZpCgkJaW5zbW9kIHBhcnRfZ3B0CgkJaW5zbW9kIGV4dDIKCQlz +ZXQgcm9vdD0naGQwLGdwdDInCgkJaWYgWyB4JGZlYXR1cmVfcGxhdGZvcm1fc2Vh +cmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJICBzZWFyY2ggLS1uby1mbG9wcHkgLS1m +cy11dWlkIC0tc2V0PXJvb3QgLS1oaW50LWJpb3M9aGQwLGdwdDIgLS1oaW50LWVm +aT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1ldGFsPWFoY2kwLGdwdDIgIGZjNTFiNTM5 +LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJCWVsc2UKCQkgIHNlYXJjaCAt +LW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCBmYzUxYjUzOS1lOGFiLTQw +M2MtODAyZC02NjcyZTRlZjNlMDcKCQlmaQoJCWVjaG8JJ+i9veWFpSBMaW51eCA1 +LjQuMTgtY3N2IC4uLicKCQlsaW51eAkvdm1saW51ei01LjQuMTgtY3N2IHJvb3Q9 +VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2Egcm8gIHF1 +aWV0IHNwbGFzaCBkZWZhdWx0X2h1Z2VwYWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBo +dWdlcGFnZXM9MSBtZW1fZW5jcnlwdD1vZmYgIHJlc3VtZT1VVUlEPTZhM2ExNmVm +LWMwMTEtNDkxNi1iMDc4LWNlNjk5YjIxN2Y4MCBhdWRpdD0wIHNlY3VyaXR5PWt5 +c2VjCgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uYLi4uJwoJCWluaXRy +ZAkvaW5pdHJkLmltZy01LjQuMTgtY3N2Cgl9CgltZW51ZW50cnkgJ0t5bGluIFYx +MCBTUDEsIDUuNC4xOC1jc3YgKHJlY292ZXJ5IG1vZGUpJyAtLWNsYXNzIGt5bGlu +IC0tY2xhc3MgZ251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mgb3MgJG1lbnVl +bnRyeV9pZF9vcHRpb24gJ2dudWxpbnV4LTUuNC4xOC1jc3YtcmVjb3ZlcnktNjY4 +OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhJyB7CgkJcmVjb3JkZmFp +bAoJCWxvYWRfdmlkZW8KCQlpbnNtb2QgZ3ppbwoJCWlmIFsgeCRncnViX3BsYXRm +b3JtID0geHhlbiBdOyB0aGVuIGluc21vZCB4emlvOyBpbnNtb2QgbHpvcGlvOyBm +aQoJCWluc21vZCBwYXJ0X2dwdAoJCWluc21vZCBleHQyCgkJc2V0IHJvb3Q9J2hk +MCxncHQyJwoJCWlmIFsgeCRmZWF0dXJlX3BsYXRmb3JtX3NlYXJjaF9oaW50ID0g +eHkgXTsgdGhlbgoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNl +dD1yb290IC0taGludC1iaW9zPWhkMCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIg +LS1oaW50LWJhcmVtZXRhbD1haGNpMCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2Mt +ODAyZC02NjcyZTRlZjNlMDcKCQllbHNlCgkJICBzZWFyY2ggLS1uby1mbG9wcHkg +LS1mcy11dWlkIC0tc2V0PXJvb3QgZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3 +MmU0ZWYzZTA3CgkJZmkKCQllY2hvCSfovb3lhaUgTGludXggNS40LjE4LWNzdiAu +Li4nCgkJbGludXgJL3ZtbGludXotNS40LjE4LWNzdiByb290PVVVSUQ9NjY4OWNm +YmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHJvIHNpbmdsZSBub21vZGVz +ZXQgZGlzX3Vjb2RlX2xkciAgYXVkaXQ9MCBzZWN1cml0eT1reXNlYwoJCWVjaG8J +J+i9veWFpeWIneWni+WMluWGheWtmOebmC4uLicKCQlpbml0cmQJL2luaXRyZC5p +bWctNS40LjE4LWNzdgoJfQp9AAgAAAANAAAAAwAAAAQAxRIJKwSBI0yqQW73wZar +TpK44AILABxWg5jPLkqd9Yh1u9ed/+BY7EW+C3RRL6kZov59tKYJEgAASeN8w2rD +sZUtle+qYBzVXT/cPF5l9EXA0DApC8+pcCEAAABncnViX2NtZDogc2V0IHRpbWVv +dXRfc3R5bGU9bWVudQAIAAAADQAAAAMAAAAEAFp1wFVx8R3SRlYx+4xeFcsZYTtV +CwBAQUoUMSCSvaLx0GBVzrn12K82qDIVWpvw0F0ZyJWknRIAqNTd+mZDZlCOIsaS +447vHpb/qieToRlN6WXimBIrl6kUAAAAZ3J1Yl9jbWQ6IFsgNSA9IDAgXQAIAAAA +DQAAAAMAAAAEACc/XIDBLpNcHTfCz+PhYbxC152OCwAeo3QwlQyDcCHrzAL5jBIB +jDHlk+NmQpQ24TU1hMfschIAI7V+jbR093yVQWJWPM/4a4+fb0F2VN3lNAyZUyyj +hmgxAAAAZ3J1Yl9jbWQ6IFsgLWYgKGhkMCxncHQxKS9ib290L2dydWIvY3VzdG9t +LmNmZyBdAAgAAAANAAAAAwAAAAQAozJt8xlCAVdeUcO5ocjV0Xrv8tALANVHjZBX +WAUxv2/zc4OwG7eOEnnCCiNyGqOmetDRyjXbEgAgKK5stp0dg7GLTGQH2BYLqC2r +Im7gyqT60hLorBqpx0wAAABncnViX2NtZDogWyAteiAoaGQwLGdwdDEpL2Jvb3Qv +Z3J1YiAtYSAtZiAoaGQwLGdwdDEpL2Jvb3QvZ3J1Yi9jdXN0b20uY2ZnIF0ACQAA +AA0AAAADAAAABACrF0D1G+oxCLf4sfKkXrnUl+4OfQsA01LVDQHiCPZsuNORBAl1 +hiRmJORHIU5Mtme39xI8cjwSAMUtHhSNQDot11uFrOkP4ULZwoFeVL4qeyK5ZzYS +PQ/7MAAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvdGhl +bWUudHh0AAkAAAANAAAAAwAAAAQAZ6F3K6EKxT5Nqf5BUMV6deb4j8MLANLAVA8G +x+GlUrDTZvFC7nsZC4BlprE3OPXZOLgWw+R9EgC0+1UdnOAohrL1865rfS/SUnCP +x5a29XAs0yLWe8H9+jUAAAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1l +cy9VS1VJL2JhY2tncm91bmQucG5nAAkAAAANAAAAAwAAAAQAJAprDxRkWG1AmMEN +PqhwHQ4cFVYLAIdeY+6jLFu/e6BbxCho5RLw1nLyRNrTk54XDi9TvN+5EgDdJU74 +WPH1pSFGzrJ6LnqGApMiKmy5ilrBcNi/fnjHfToAAAAoaGQwLGdwdDMpL3Vzci9z +aGFyZS9ncnViL3RoZW1lcy9VS1VJL3Rlcm1pbmFsX2JveF9udy5wbmcACQAAAA0A +AAADAAAABADlAlzEHdQdSXhSP4JiOMTPwjeN6gsAZp1N1g0WEI67biZIoWrDq/yF +agxVdY8GYEyKbbX6klcSANcIaVKm5wut95P3BguQh5QemPIFenAkbtfhl4PP8oum +OgAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvdGVybWlu +YWxfYm94X25lLnBuZwAJAAAADQAAAAMAAAAEAF19Ya81IlTFMgwsV+PxbjXk+Nfk +CwCnPawKUAmGn+fpHJhlg8Jmu+yL9emOabJ+vTjdfSQ74BIAc3PG3FHX8to8YL/e +6z9QKKikFCKlLW0kGiViEAqHvRA6AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1 +Yi90aGVtZXMvVUtVSS90ZXJtaW5hbF9ib3hfc2UucG5nAAkAAAANAAAAAwAAAAQA +18mEjGZNcICR4WhHWEAhpcJI5VMLAD4gCPZBzlDTIgCtlz7xHSliFHrMeNv1wb6E +7RmgkkLoEgCJFWMAuq2yvQMqW6UcAYHaGCqz5ZVsX/l8klP4jNq//DoAAAAoaGQw +LGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3Rlcm1pbmFsX2JveF9z +dy5wbmcACQAAAA0AAAADAAAABAA+kfKMFCgxMCPIwwdc+Xux4TTA4wsAp+EVkvz3 +7JAqQTiW+A5Z4U1tmORE8BeM+H7GN7CqBboSAHDjY6GHPvKNt1FxIoflB7VRqNOq +TON7db8dIC60fqK1OQAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVz +L1VLVUkvdGVybWluYWxfYm94X24ucG5nAAkAAAANAAAAAwAAAAQA0qXoEL1Ppj/a +r8Hxu++K02lHLbQLADDaV3i9+w1VD+O5kWVrJr3sWzELPY+Ev/jjyDAF5oyBEgAf +Khp4txaLctQzF0NOcMGkK4r3n9khSV+i2R2PMcREJzkAAAAoaGQwLGdwdDMpL3Vz +ci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3Rlcm1pbmFsX2JveF9lLnBuZwAJAAAA +DQAAAAMAAAAEAHFlMZHUKag0sRjyjnVEeN+OM9rOCwCpHoYI4lvWXm34BW/Ra6av +8ZiiQDsvjFQOnOWhh4x2txIAIvNnQAZDsnYiCzwMEsRvBO/8uDcOWuoN1EAhXMVP +a5U5AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVtZXMvVUtVSS90ZXJt +aW5hbF9ib3hfcy5wbmcACQAAAA0AAAADAAAABADfEYW81VVxIs7H4IdfMq4wOKZ3 +ygsA/eLUPi8jUxsKHj12ziEZBR2EqbhOxtToA0Ou8mi44ugSANxQJNtcVuT/J+p6 +YkEzxTJkGcwv6sEDjDIkMdOwxRqKOQAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dy +dWIvdGhlbWVzL1VLVUkvdGVybWluYWxfYm94X3cucG5nAAkAAAANAAAAAwAAAAQA +8sorIwIOiWLgNPjlG7sGdRIoulQLAJgmVD/ZRF/7p0QDDvFqH/nvX6zbRHWIBhj3 +7/mFHab/EgAyUjjvtCr0GULEQ8EbezIPo2c6Y0nCtpuwvU+So3jC9TkAAAAoaGQw +LGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3Rlcm1pbmFsX2JveF9j +LnBuZwAJAAAADQAAAAMAAAAEAEpkWfr76/9hJfR8Lrtbsg//1yEfCwAx2Fee6huf +XAYJ3u3q4ldxqAGjnaZD5/0DUNIPpGrodRIAkhNS25HS6IzSLjIQxd9CdWqJr3/+ +ILTBkoidZZxbuuYvAAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVtZXMv +VUtVSS9sb2dvLnBuZwAJAAAADQAAAAMAAAAEAIEqkegJuyQg/X6jZTNtVzxl3lP+ +CwDUqUXzZt4aMAoThaMPxXfH75LxEzS+50hQ9q2cWJT1aRIArxq96+tVeq2YZb38 +TqztGljbgOpG+CbhiyMjcRLq9vY6AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1 +Yi90aGVtZXMvVUtVSS9wcm9ncmVzc19iYXJfbncucG5nAAkAAAANAAAAAwAAAAQA +sYFfeeg7S/rrf4HfIX2YJt5CpjcLAET7eaHFr6KRqoQ8mUranw5BVsdFGzTAqwMt +xyPYKhMNEgAjyb9NlrNLrhAZb53I6XGHgj7pllfUniYOa7yW9ofi1ToAAAAoaGQw +LGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3Byb2dyZXNzX2Jhcl9u +ZS5wbmcACQAAAA0AAAADAAAABAAKOHDV5q/7KZNq/fFEXDlknmr9fgsA+4vC20Kv +QZO5MxGeSxetJq9HFBubZ9kd4NWtR240F3ESAHQp22k+t9fhHEJzJSL8sZJJUvhZ +GlwxQMR2hEtgRoa+OgAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVz +L1VLVUkvcHJvZ3Jlc3NfYmFyX3NlLnBuZwAJAAAADQAAAAMAAAAEAFjjYohj3M6f +EiwNcBLNkiXULfGSCwAx9vSP2lnP2mePWMauJcNbgn4+J21cZ1W3592VhAbTUhIA +i/wHWY26QvZwVhWyeNgovh2PY9rAXWJNmCURvNKCsj86AAAAKGhkMCxncHQzKS91 +c3Ivc2hhcmUvZ3J1Yi90aGVtZXMvVUtVSS9wcm9ncmVzc19iYXJfc3cucG5nAAkA +AAANAAAAAwAAAAQAb/DomhSvITPqoipOTxjlr9fTxTALAAoGj84gj3egrZpTGMnS ++kgVUXAHP52qmOyBN9cBKjY9EgA8ecItHf6o+R6XzxQ0drnntyExNGfubT5dJbLt +BItkhjkAAAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3By +b2dyZXNzX2Jhcl9uLnBuZwAJAAAADQAAAAMAAAAEAAzeTq2tA9tAf4kOQZavPquP +5diECwBfUrFJRtKWKQCfDi4SEBO9ihDGIrwM/nI/V7aUS3WdJRIAouylHMB7CjCQ +6TSUv9YQTUafUwp2lAtxq5CLRuB+2fg5AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUv +Z3J1Yi90aGVtZXMvVUtVSS9wcm9ncmVzc19iYXJfZS5wbmcACQAAAA0AAAADAAAA +BAD/LR3sjPEhyfJnlNDXJpeLaAaJlAsAh+TKiDJgRqIXeLgWD9nzxYleeD2PVjF1 +K2rtmHAPWcASADSU79BdMa0NMUz2mlZb0rWXaQ5k4AQw4L19migU+mltOQAAACho +ZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvcHJvZ3Jlc3NfYmFy +X3MucG5nAAkAAAANAAAAAwAAAAQA+AGm/ANjXZMINdB2jtG4eSvUuiULAM4KR+t2 +cro3Ez5hxGv2wbyAxsef9tGMlRtaL5p6t/wYEgBOU8ObCxPturt9B1NSynFh51K5 +1I+3K/+Udrmvyb0yfTkAAAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1l +cy9VS1VJL3Byb2dyZXNzX2Jhcl93LnBuZwAJAAAADQAAAAMAAAAEALsIhCkUY8/e +0NykIexK2zI+5ByiCwAJvuGV8XqaANcY/NsDZW+QjI3XpE5hczNrFQdY6fL1exIA +3RoNVx5xUobPIkKprSmmRMo3HuzIvqmZXV3yPmUfkW85AAAAKGhkMCxncHQzKS91 +c3Ivc2hhcmUvZ3J1Yi90aGVtZXMvVUtVSS9wcm9ncmVzc19iYXJfYy5wbmcACQAA +AA0AAAADAAAABADPqG74hAgs4iTtigf9Bt9te8hrpwsAumYWPqEqdPRzJlYP41Bw +0YPqHbl17BiFvnhEB/Va2cASALPHgKIblYqQinVMi4KzTHeRSKDMMF3rFSPsCK/x +LQKAPwAAAChoZDAsZ3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvcHJv +Z3Jlc3NfaGlnaGxpZ2h0X2UucG5nAAkAAAANAAAAAwAAAAQAz6hu+IQILOIk7YoH +/QbfbXvIa6cLALpmFj6hKnT0cyZWD+NQcNGD6h25dewYhb54RAf1WtnAEgCzx4Ci +G5WKkIp1TIuCs0x3kUigzDBd6xUj7Aiv8S0CgD8AAAAoaGQwLGdwdDMpL3Vzci9z +aGFyZS9ncnViL3RoZW1lcy9VS1VJL3Byb2dyZXNzX2hpZ2hsaWdodF93LnBuZwAJ +AAAADQAAAAMAAAAEAPiwTs7R8O0Ti62woYWtk7a+hnpYCwDorwvieRBFzktFTRDc +L3GLTnEQtOtwqcq6hSBpN0xCHhIAV0hRbwTiNHcZycsI9Z8ld5NodHbX/NyoeE93 +Pup6GX8/AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVtZXMvVUtVSS9w +cm9ncmVzc19oaWdobGlnaHRfYy5wbmcACQAAAA0AAAADAAAABACng8EoFl5rEVQI +iXLcmGRol5+z8wsAEVsiMTUzd7ogJNd5eu6HzzKiGzj6WpY3Cm2hYF1BL3kSADeJ +8hHhYS7ZVvXOkmsztS76n/LO8A5mfKmFwAxrDYK1NgAAAChoZDAsZ3B0MykvdXNy +L3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvbWVudV9ia2dfbncucG5nAAkAAAANAAAA +AwAAAAQAXjr8UlKweOI/F7W9VEflbYfh5h8LAMv0LxMbTTRAVc787ylb0ou/+grW +giK8B3mom2Kr+/m0EgAASuxBsaDxmjS12RtJyzo9wLMGqn6gyLLHpV5dGsDH9DYA +AAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL21lbnVfYmtn +X25lLnBuZwAJAAAADQAAAAMAAAAEAKVPWyOwpcOSr1keSLLE3SGbAfxrCwAbjXUi +5mhOgkn+k3k5izXEyFIzdGBk+V6xUlAT0mOkpRIALBWqNFAbnGCEAy3YS/N+m52z +85CYaAfChF14x/4OPT82AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVt +ZXMvVUtVSS9tZW51X2JrZ19zZS5wbmcACQAAAA0AAAADAAAABABvV0HJugAIX2sy +YaV875R8dA2qnAsALbcExEiWuqLC9U1EXwuIM/2KIjBRFeX7nj5Wm/HAE0gSAFYm +tYHQzUG7hqqMH9Vgahp5brS60GjHlOACpiVD1HRaNgAAAChoZDAsZ3B0MykvdXNy +L3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvbWVudV9ia2dfc3cucG5nAAkAAAANAAAA +AwAAAAQArSbjNnhXXyjFcRKv/XetFSyp8EYLANXIrifU+Tlk9RjrTcM1b/Gz0py8 +LugsTc8NxZGph5e0EgAk/++Kmu4VOnBoPckAehUWyR0EbTxijywhq4t2WivsuTUA +AAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL21lbnVfYmtn +X24ucG5nAAkAAAANAAAAAwAAAAQA9NZDgt4cSFAf08KYtoPJGBiz+e8LAB1qcWe7 +S6SEnPEr75lZcW02rr4ZGhXUVa5XeD3z2w5QEgB0HJcHT9H2QMwpP4ffkNoFtEtS +mUr+uiD09QMdlgjyszUAAAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1l +cy9VS1VJL21lbnVfYmtnX2UucG5nAAkAAAANAAAAAwAAAAQAVnZCQFKJdX63Bkg8 +CvQbHNpmFdALANfIeraAC4IwjvbjoLws/QHJcyblYpGt8MxGzuzg4029EgALNuu4 +wMpTgVPERqcQco+yU3uVoeigHYx9oeQP7IWcfjUAAAAoaGQwLGdwdDMpL3Vzci9z +aGFyZS9ncnViL3RoZW1lcy9VS1VJL21lbnVfYmtnX3MucG5nAAkAAAANAAAAAwAA +AAQAk6Lk5PBTURgPWm031yoF/rXq6r0LAFTcpvPIRw7ME0xNTFENpFUEzxQ3Bqtu +60i7adXkHAUzEgAMu5ZTRqLJ2421r3hwJjiNhBzOotMx/LLoyblA0oqkiTUAAAAo +aGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL21lbnVfYmtnX3cu +cG5nAAkAAAANAAAAAwAAAAQAW/7Xnckd1WVvKntElhY1tekNJdgLALzP61RaIsr3 +bY+UoNI0brIhCoTt0y7O8H36CCf1L/WnEgBIgBU0enSB7GrS5oJuA2KcpfuilQ/q +xB0O+tX1QChL9jUAAAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9V +S1VJL21lbnVfYmtnX2MucG5nAAkAAAANAAAAAwAAAAQAo6/dJVV7ABt4Frqf0q54 +AHEiEScLAFP4eu1AtEVkd4ff09Y0Wo0Qy/grwhnA1WVCTqjTVvUiEgBXkHiVBKrO +yxkxKdQhbvaRKVQIc/zVfTYpURIWaAitdTQAAAAoaGQwLGdwdDMpL3Vzci9zaGFy +ZS9ncnViL3RoZW1lcy9VS1VJL3NlbGVjdF9udy5wbmcACQAAAA0AAAADAAAABACj +r90lVXsAG3gWup/SrngAcSIRJwsAU/h67UC0RWR3h9/T1jRajRDL+CvCGcDVZUJO +qNNW9SISAFeQeJUEqs7LGTEp1CFu9pEpVAhz/NV9NilREhZoCK11NAAAAChoZDAs +Z3B0MykvdXNyL3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvc2VsZWN0X25lLnBuZwAJ +AAAADQAAAAMAAAAEAKOv3SVVewAbeBa6n9KueABxIhEnCwBT+HrtQLRFZHeH39PW +NFqNEMv4K8IZwNVlQk6o01b1IhIAV5B4lQSqzssZMSnUIW72kSlUCHP81X02KVES +FmgIrXU0AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVtZXMvVUtVSS9z +ZWxlY3Rfc2UucG5nAAkAAAANAAAAAwAAAAQAo6/dJVV7ABt4Frqf0q54AHEiEScL +AFP4eu1AtEVkd4ff09Y0Wo0Qy/grwhnA1WVCTqjTVvUiEgBXkHiVBKrOyxkxKdQh +bvaRKVQIc/zVfTYpURIWaAitdTQAAAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnVi +L3RoZW1lcy9VS1VJL3NlbGVjdF9zdy5wbmcACQAAAA0AAAADAAAABAAk11o8Lfvh +WNy0yyFUlqU9dEmj3AsAKdiettNwcyjL1KLtRFg4JeCrUD5eOUAoR15224UelDMS +AMx8LKkaL5bePaX3YGWs0N+dvPd90eCpt9wvRZfPiCYRMwAAAChoZDAsZ3B0Mykv +dXNyL3NoYXJlL2dydWIvdGhlbWVzL1VLVUkvc2VsZWN0X24ucG5nAAkAAAANAAAA +AwAAAAQAHDs3645tuaAPTaiRYQ/gFDDG2SkLAEpFqDJL023+95rTbLX51nZlLAbH +1S+nGxeoP/H565LLEgAWfzOOI8uED2RCgGfNi7TPCITPtpoTO2edgnpY+kK9xjMA +AAAoaGQwLGdwdDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3NlbGVjdF9l +LnBuZwAJAAAADQAAAAMAAAAEACTXWjwt++FY3LTLIVSWpT10SaPcCwAp2J6203Bz +KMvUou1EWDgl4KtQPl45QChHXnbbhR6UMxIAzHwsqRovlt49pfdgZazQ3528933R +4Km33C9Fl8+IJhEzAAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVtZXMv +VUtVSS9zZWxlY3Rfcy5wbmcACQAAAA0AAAADAAAABAAcOzfrjm25oA9NqJFhD+AU +MMbZKQsASkWoMkvTbf73mtNstfnWdmUsBsfVL6cbF6g/8fnrkssSABZ/M44jy4QP +ZEKAZ82LtM8IhM+2mhM7Z52Celj6Qr3GMwAAAChoZDAsZ3B0MykvdXNyL3NoYXJl +L2dydWIvdGhlbWVzL1VLVUkvc2VsZWN0X3cucG5nAAkAAAANAAAAAwAAAAQAFsGU +++Ecl6Yhbv5HYekWfJEtIjgLAAq4BNCUFiwAGwA1fyOfEZK37JmvOByoiksQRnUE +SiyYEgAbYc44BgCTFoK4ucSDvX0Y/EcxUOjXEfG1FyNYXj0rJDMAAAAoaGQwLGdw +dDMpL3Vzci9zaGFyZS9ncnViL3RoZW1lcy9VS1VJL3NlbGVjdF9jLnBuZwAJAAAA +DQAAAAMAAAAEANLVvuGzNJB9fNxRl/uI/UkYvi1HCwAbaCPoaiSaVHEhSyLwPx58 +P10ZMk6X98LSBZpUsh9/YBIAGY7i54k9X8ZzzYYtPxninALKV+krZQh8QHiSopkg +hKU2AAAAKGhkMCxncHQzKS91c3Ivc2hhcmUvZ3J1Yi90aGVtZXMvVUtVSS9pY29u +cy9reWxpbi5wbmcACAAAAA0AAAADAAAABAD0ByQn3k5SWYRbVxNeSLGPF7Em7QsA +ai5RlanzQxE/yXApSAQsegVBma918IDTwlSDv4WmKQQSAIRAg7dQf0PXbCiorIuf +TOsHLYqPEXNlU6W4xkhbVnwrMgAAAGdydWJfY21kOiBzZXRwYXJhbXMgS3lsaW4g +VjEwIFNQMSDnmoTpq5jnuqfpgInpobkACAAAAA0AAAADAAAABAD7Cbzj0G1A8U6p +JHlePNz9pw9aIgsAgEBR0hokuL7iavbQD3txxSjqcLLbpOXkc0mvOq1iNtUSALo1 +Khy8vAWYbpgb7K2HZ+bP/fwsFBdOm6zmcU3YHp6FBwQAAGdydWJfY21kOiBtZW51 +ZW50cnkgS3lsaW4gVjEwIFNQMSwgNS40LjE4LTM1LWdlbmVyaWMgLS1jbGFzcyBr +eWxpbiAtLWNsYXNzIGdudS1saW51eCAtLWNsYXNzIGdudSAtLWNsYXNzIG9zIC0t +aWQgZ251bGludXgtNS40LjE4LTM1LWdlbmVyaWMtYWR2YW5jZWQtNjY4OWNmYmUt +N2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHsKCQlyZWNvcmRmYWlsCgkJbG9h +ZF92aWRlbwoJCWdmeG1vZGUgJGxpbnV4X2dmeF9tb2RlCgkJaW5zbW9kIGd6aW8K +CQlpZiBbIHgkZ3J1Yl9wbGF0Zm9ybSA9IHh4ZW4gXTsgdGhlbiBpbnNtb2QgeHpp +bzsgaW5zbW9kIGx6b3BpbzsgZmkKCQlpbnNtb2QgcGFydF9ncHQKCQlpbnNtb2Qg +ZXh0MgoJCXNldCByb290PSdoZDAsZ3B0MicKCQlpZiBbIHgkZmVhdHVyZV9wbGF0 +Zm9ybV9zZWFyY2hfaGludCA9IHh5IF07IHRoZW4KCQkgIHNlYXJjaCAtLW5vLWZs +b3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCAtLWhpbnQtYmlvcz1oZDAsZ3B0MiAt +LWhpbnQtZWZpPWhkMCxncHQyIC0taGludC1iYXJlbWV0YWw9YWhjaTAsZ3B0MiAg +ZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZWxzZQoJCSAg +c2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IGZjNTFiNTM5 +LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJCWZpCgkJZWNobwkn6L295YWl +IExpbnV4IDUuNC4xOC0zNS1nZW5lcmljIC4uLicKCQlsaW51eAkvdm1saW51ei01 +LjQuMTgtMzUtZ2VuZXJpYyByb290PVVVSUQ9NjY4OWNmYmUtN2MzYS00MzhiLTg2 +ZmQtMmQxMDM5ZDVkOWNhIHJvICBxdWlldCBzcGxhc2ggZGVmYXVsdF9odWdlcGFn +ZXN6PTFHIGh1Z2VwYWdlc3o9MUcgaHVnZXBhZ2VzPTEgbWVtX2VuY3J5cHQ9b2Zm +ICByZXN1bWU9VVVJRD02YTNhMTZlZi1jMDExLTQ5MTYtYjA3OC1jZTY5OWIyMTdm +ODAgYXVkaXQ9MCBzZWN1cml0eT1reXNlYwoJCWVjaG8JJ+i9veWFpeWIneWni+WM +luWGheWtmOebmC4uLicKCQlpbml0cmQJL2luaXRyZC5pbWctNS40LjE4LTM1LWdl +bmVyaWMKCX0ACAAAAA0AAAADAAAABAAxpAm0ncBC0y1AK4EKP1IxF3bmYgsA6jwz +vThRwgw5OMyyYQHRMMr04WyYB+nqU6SCwHeR7jwSAKSWLplDmjnjbLkeHBZDPdKL +jT55bu7dshwafMTnH1JznQMAAGdydWJfY21kOiBtZW51ZW50cnkgS3lsaW4gVjEw +IFNQMSwgNS40LjE4LTM1LWdlbmVyaWMgKHJlY292ZXJ5IG1vZGUpIC0tY2xhc3Mg +a3lsaW4gLS1jbGFzcyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAt +LWlkIGdudWxpbnV4LTUuNC4xOC0zNS1nZW5lcmljLXJlY292ZXJ5LTY2ODljZmJl +LTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYSB7CgkJcmVjb3JkZmFpbAoJCWxv +YWRfdmlkZW8KCQlpbnNtb2QgZ3ppbwoJCWlmIFsgeCRncnViX3BsYXRmb3JtID0g +eHhlbiBdOyB0aGVuIGluc21vZCB4emlvOyBpbnNtb2QgbHpvcGlvOyBmaQoJCWlu +c21vZCBwYXJ0X2dwdAoJCWluc21vZCBleHQyCgkJc2V0IHJvb3Q9J2hkMCxncHQy +JwoJCWlmIFsgeCRmZWF0dXJlX3BsYXRmb3JtX3NlYXJjaF9oaW50ID0geHkgXTsg +dGhlbgoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290 +IC0taGludC1iaW9zPWhkMCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIgLS1oaW50 +LWJhcmVtZXRhbD1haGNpMCxncHQyICBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02 +NjcyZTRlZjNlMDcKCQllbHNlCgkJICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11 +dWlkIC0tc2V0PXJvb3QgZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYz +ZTA3CgkJZmkKCQllY2hvCSfovb3lhaUgTGludXggNS40LjE4LTM1LWdlbmVyaWMg +Li4uJwoJCWxpbnV4CS92bWxpbnV6LTUuNC4xOC0zNS1nZW5lcmljIHJvb3Q9VVVJ +RD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2Egcm8gc2luZ2xl +IG5vbW9kZXNldCBkaXNfdWNvZGVfbGRyICBhdWRpdD0wIHNlY3VyaXR5PWt5c2Vj +CgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uYLi4uJwoJCWluaXRyZAkv +aW5pdHJkLmltZy01LjQuMTgtMzUtZ2VuZXJpYwoJfQAIAAAADQAAAAMAAAAEAH9J +ZWZaKjulL4BR3mlvxlJv1rs9CwBotDUP6cTjfaCn9ybe4peiZgWcWok5y78F7uMT ++spSXxIAY+hvEiz8eV4JygYEqQVu9FbvmZoCpyD6VnHCeKK88q34AwAAZ3J1Yl9j +bWQ6IG1lbnVlbnRyeSBLeWxpbiBWMTAgU1AxLCA1LjQuMTgtdGttX29yaSAtLWNs +YXNzIGt5bGluIC0tY2xhc3MgZ251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mg +b3MgLS1pZCBnbnVsaW51eC01LjQuMTgtdGttX29yaS1hZHZhbmNlZC02Njg5Y2Zi +ZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2EgewoJCXJlY29yZGZhaWwKCQls +b2FkX3ZpZGVvCgkJZ2Z4bW9kZSAkbGludXhfZ2Z4X21vZGUKCQlpbnNtb2QgZ3pp +bwoJCWlmIFsgeCRncnViX3BsYXRmb3JtID0geHhlbiBdOyB0aGVuIGluc21vZCB4 +emlvOyBpbnNtb2QgbHpvcGlvOyBmaQoJCWluc21vZCBwYXJ0X2dwdAoJCWluc21v +ZCBleHQyCgkJc2V0IHJvb3Q9J2hkMCxncHQyJwoJCWlmIFsgeCRmZWF0dXJlX3Bs +YXRmb3JtX3NlYXJjaF9oaW50ID0geHkgXTsgdGhlbgoJCSAgc2VhcmNoIC0tbm8t +ZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IC0taGludC1iaW9zPWhkMCxncHQy +IC0taGludC1lZmk9aGQwLGdwdDIgLS1oaW50LWJhcmVtZXRhbD1haGNpMCxncHQy +ICBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQllbHNlCgkJ +ICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgZmM1MWI1 +MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZmkKCQllY2hvCSfovb3l +haUgTGludXggNS40LjE4LXRrbV9vcmkgLi4uJwoJCWxpbnV4CS92bWxpbnV6LTUu +NC4xOC10a21fb3JpIHJvb3Q9VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0y +ZDEwMzlkNWQ5Y2Egcm8gIHF1aWV0IHNwbGFzaCBkZWZhdWx0X2h1Z2VwYWdlc3o9 +MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBtZW1fZW5jcnlwdD1vZmYgIHJl +c3VtZT1VVUlEPTZhM2ExNmVmLWMwMTEtNDkxNi1iMDc4LWNlNjk5YjIxN2Y4MCBh +dWRpdD0wIHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF +5a2Y55uYLi4uJwoJCWluaXRyZAkvaW5pdHJkLmltZy01LjQuMTgtdGttX29yaQoJ +fQAIAAAADQAAAAMAAAAEAKStKW4Fgo1U+lxZSl9RUb8ldeE4CwATutrn2rzmRRTl +k3cKkOeHT5exxAN0cc11GGWkDolGZhIA0pnNfuf3j2fmcbCAOwij4Fa1NrxgZbvQ +NDl3l8dySg2OAwAAZ3J1Yl9jbWQ6IG1lbnVlbnRyeSBLeWxpbiBWMTAgU1AxLCA1 +LjQuMTgtdGttX29yaSAocmVjb3ZlcnkgbW9kZSkgLS1jbGFzcyBreWxpbiAtLWNs +YXNzIGdudS1saW51eCAtLWNsYXNzIGdudSAtLWNsYXNzIG9zIC0taWQgZ251bGlu +dXgtNS40LjE4LXRrbV9vcmktcmVjb3ZlcnktNjY4OWNmYmUtN2MzYS00MzhiLTg2 +ZmQtMmQxMDM5ZDVkOWNhIHsKCQlyZWNvcmRmYWlsCgkJbG9hZF92aWRlbwoJCWlu +c21vZCBnemlvCgkJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07IHRoZW4g +aW5zbW9kIHh6aW87IGluc21vZCBsem9waW87IGZpCgkJaW5zbW9kIHBhcnRfZ3B0 +CgkJaW5zbW9kIGV4dDIKCQlzZXQgcm9vdD0naGQwLGdwdDInCgkJaWYgWyB4JGZl +YXR1cmVfcGxhdGZvcm1fc2VhcmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJICBzZWFy +Y2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgLS1oaW50LWJpb3M9 +aGQwLGdwdDIgLS1oaW50LWVmaT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1ldGFsPWFo +Y2kwLGdwdDIgIGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJ +CWVsc2UKCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9v +dCBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQlmaQoJCWVj +aG8JJ+i9veWFpSBMaW51eCA1LjQuMTgtdGttX29yaSAuLi4nCgkJbGludXgJL3Zt +bGludXotNS40LjE4LXRrbV9vcmkgcm9vdD1VVUlEPTY2ODljZmJlLTdjM2EtNDM4 +Yi04NmZkLTJkMTAzOWQ1ZDljYSBybyBzaW5nbGUgbm9tb2Rlc2V0IGRpc191Y29k +ZV9sZHIgIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMKCQllY2hvCSfovb3lhaXliJ3l +p4vljJblhoXlrZjnm5guLi4nCgkJaW5pdHJkCS9pbml0cmQuaW1nLTUuNC4xOC10 +a21fb3JpCgl9AAgAAAANAAAAAwAAAAQAv9g+HaNzzxKOkA189TgJSre0Fi0LAPDY +X32D5QWc4O3oXpRnxkMn5LavQmAp+BUJk/jLVxlyEgCJwEuCcK05hZ6w1nYW+Ujv +Kg+WRPWpI8DFesicvmKKjggEAABncnViX2NtZDogbWVudWVudHJ5IEt5bGluIFYx +MCBTUDEsIDUuNC4xOC10a21fb3JpLm9sZCAtLWNsYXNzIGt5bGluIC0tY2xhc3Mg +Z251LWxpbnV4IC0tY2xhc3MgZ251IC0tY2xhc3Mgb3MgLS1pZCBnbnVsaW51eC01 +LjQuMTgtdGttX29yaS5vbGQtYWR2YW5jZWQtNjY4OWNmYmUtN2MzYS00MzhiLTg2 +ZmQtMmQxMDM5ZDVkOWNhIHsKCQlyZWNvcmRmYWlsCgkJbG9hZF92aWRlbwoJCWdm +eG1vZGUgJGxpbnV4X2dmeF9tb2RlCgkJaW5zbW9kIGd6aW8KCQlpZiBbIHgkZ3J1 +Yl9wbGF0Zm9ybSA9IHh4ZW4gXTsgdGhlbiBpbnNtb2QgeHppbzsgaW5zbW9kIGx6 +b3BpbzsgZmkKCQlpbnNtb2QgcGFydF9ncHQKCQlpbnNtb2QgZXh0MgoJCXNldCBy +b290PSdoZDAsZ3B0MicKCQlpZiBbIHgkZmVhdHVyZV9wbGF0Zm9ybV9zZWFyY2hf +aGludCA9IHh5IF07IHRoZW4KCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1 +aWQgLS1zZXQ9cm9vdCAtLWhpbnQtYmlvcz1oZDAsZ3B0MiAtLWhpbnQtZWZpPWhk +MCxncHQyIC0taGludC1iYXJlbWV0YWw9YWhjaTAsZ3B0MiAgZmM1MWI1MzktZThh +Yi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3CgkJZWxzZQoJCSAgc2VhcmNoIC0tbm8t +ZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1yb290IGZjNTFiNTM5LWU4YWItNDAzYy04 +MDJkLTY2NzJlNGVmM2UwNwoJCWZpCgkJZWNobwkn6L295YWlIExpbnV4IDUuNC4x +OC10a21fb3JpLm9sZCAuLi4nCgkJbGludXgJL3ZtbGludXotNS40LjE4LXRrbV9v +cmkub2xkIHJvb3Q9VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlk +NWQ5Y2Egcm8gIHF1aWV0IHNwbGFzaCBkZWZhdWx0X2h1Z2VwYWdlc3o9MUcgaHVn +ZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBtZW1fZW5jcnlwdD1vZmYgIHJlc3VtZT1V +VUlEPTZhM2ExNmVmLWMwMTEtNDkxNi1iMDc4LWNlNjk5YjIxN2Y4MCBhdWRpdD0w +IHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uY +Li4uJwoJCWluaXRyZAkvaW5pdHJkLmltZy01LjQuMTgtdGttX29yaQoJfQAIAAAA +DQAAAAMAAAAEAJwVVMJ+wxBsMrVABTpaAsE8xzK8CwBWYjxp1xLIacuPtcKYFmi5 +ajbWpIb+8OHOJVbtBkI3DhIAazFyiJiSrFDqj/HYczA338EtLuLH4g72Tw/Xolqr ++JueAwAAZ3J1Yl9jbWQ6IG1lbnVlbnRyeSBLeWxpbiBWMTAgU1AxLCA1LjQuMTgt +dGttX29yaS5vbGQgKHJlY292ZXJ5IG1vZGUpIC0tY2xhc3Mga3lsaW4gLS1jbGFz +cyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAtLWlkIGdudWxpbnV4 +LTUuNC4xOC10a21fb3JpLm9sZC1yZWNvdmVyeS02Njg5Y2ZiZS03YzNhLTQzOGIt +ODZmZC0yZDEwMzlkNWQ5Y2EgewoJCXJlY29yZGZhaWwKCQlsb2FkX3ZpZGVvCgkJ +aW5zbW9kIGd6aW8KCQlpZiBbIHgkZ3J1Yl9wbGF0Zm9ybSA9IHh4ZW4gXTsgdGhl +biBpbnNtb2QgeHppbzsgaW5zbW9kIGx6b3BpbzsgZmkKCQlpbnNtb2QgcGFydF9n +cHQKCQlpbnNtb2QgZXh0MgoJCXNldCByb290PSdoZDAsZ3B0MicKCQlpZiBbIHgk +ZmVhdHVyZV9wbGF0Zm9ybV9zZWFyY2hfaGludCA9IHh5IF07IHRoZW4KCQkgIHNl +YXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCAtLWhpbnQtYmlv +cz1oZDAsZ3B0MiAtLWhpbnQtZWZpPWhkMCxncHQyIC0taGludC1iYXJlbWV0YWw9 +YWhjaTAsZ3B0MiAgZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0ZWYzZTA3 +CgkJZWxzZQoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNldD1y +b290IGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJCWZpCgkJ +ZWNobwkn6L295YWlIExpbnV4IDUuNC4xOC10a21fb3JpLm9sZCAuLi4nCgkJbGlu +dXgJL3ZtbGludXotNS40LjE4LXRrbV9vcmkub2xkIHJvb3Q9VVVJRD02Njg5Y2Zi +ZS03YzNhLTQzOGItODZmZC0yZDEwMzlkNWQ5Y2Egcm8gc2luZ2xlIG5vbW9kZXNl +dCBkaXNfdWNvZGVfbGRyICBhdWRpdD0wIHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn +6L295YWl5Yid5aeL5YyW5YaF5a2Y55uYLi4uJwoJCWluaXRyZAkvaW5pdHJkLmlt +Zy01LjQuMTgtdGttX29yaQoJfQAIAAAADQAAAAMAAAAEAGbS/zAlDwyKn41Fxs3t +qGCD7e+XCwDmOgMyVwdnAYosPC43OI8UHo276GAPq7qGNgFa9RIEExIALR8mKDCl +MUXC5zmNAePzoVjxJxbcRGm3fyDMiWfIqwbkAwAAZ3J1Yl9jbWQ6IG1lbnVlbnRy +eSBLeWxpbiBWMTAgU1AxLCA1LjQuMTgtdGttIC0tY2xhc3Mga3lsaW4gLS1jbGFz +cyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAtLWlkIGdudWxpbnV4 +LTUuNC4xOC10a20tYWR2YW5jZWQtNjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQx +MDM5ZDVkOWNhIHsKCQlyZWNvcmRmYWlsCgkJbG9hZF92aWRlbwoJCWdmeG1vZGUg +JGxpbnV4X2dmeF9tb2RlCgkJaW5zbW9kIGd6aW8KCQlpZiBbIHgkZ3J1Yl9wbGF0 +Zm9ybSA9IHh4ZW4gXTsgdGhlbiBpbnNtb2QgeHppbzsgaW5zbW9kIGx6b3Bpbzsg +ZmkKCQlpbnNtb2QgcGFydF9ncHQKCQlpbnNtb2QgZXh0MgoJCXNldCByb290PSdo +ZDAsZ3B0MicKCQlpZiBbIHgkZmVhdHVyZV9wbGF0Zm9ybV9zZWFyY2hfaGludCA9 +IHh5IF07IHRoZW4KCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1z +ZXQ9cm9vdCAtLWhpbnQtYmlvcz1oZDAsZ3B0MiAtLWhpbnQtZWZpPWhkMCxncHQy +IC0taGludC1iYXJlbWV0YWw9YWhjaTAsZ3B0MiAgZmM1MWI1MzktZThhYi00MDNj +LTgwMmQtNjY3MmU0ZWYzZTA3CgkJZWxzZQoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5 +IC0tZnMtdXVpZCAtLXNldD1yb290IGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2 +NzJlNGVmM2UwNwoJCWZpCgkJZWNobwkn6L295YWlIExpbnV4IDUuNC4xOC10a20g +Li4uJwoJCWxpbnV4CS92bWxpbnV6LTUuNC4xOC10a20gcm9vdD1VVUlEPTY2ODlj +ZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYSBybyAgcXVpZXQgc3BsYXNo +IGRlZmF1bHRfaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXN6PTFHIGh1Z2VwYWdlcz0x +IG1lbV9lbmNyeXB0PW9mZiAgcmVzdW1lPVVVSUQ9NmEzYTE2ZWYtYzAxMS00OTE2 +LWIwNzgtY2U2OTliMjE3ZjgwIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMKCQllY2hv +CSfovb3lhaXliJ3lp4vljJblhoXlrZjnm5guLi4nCgkJaW5pdHJkCS9pbml0cmQu +aW1nLTUuNC4xOC10a20KCX0ACAAAAA0AAAADAAAABAA9qlGpeTrqANhc+uTBgIx6 +eE2wFgsAcdHD2CnzlCaJUVacu4Yv9x015mT5qjTF+bssNx5GjyUSAK+IoVcIvfJm +spy0xy02/6XSpIQcftr9TpKlU9bYKUaCegMAAGdydWJfY21kOiBtZW51ZW50cnkg +S3lsaW4gVjEwIFNQMSwgNS40LjE4LXRrbSAocmVjb3ZlcnkgbW9kZSkgLS1jbGFz +cyBreWxpbiAtLWNsYXNzIGdudS1saW51eCAtLWNsYXNzIGdudSAtLWNsYXNzIG9z +IC0taWQgZ251bGludXgtNS40LjE4LXRrbS1yZWNvdmVyeS02Njg5Y2ZiZS03YzNh +LTQzOGItODZmZC0yZDEwMzlkNWQ5Y2EgewoJCXJlY29yZGZhaWwKCQlsb2FkX3Zp +ZGVvCgkJaW5zbW9kIGd6aW8KCQlpZiBbIHgkZ3J1Yl9wbGF0Zm9ybSA9IHh4ZW4g +XTsgdGhlbiBpbnNtb2QgeHppbzsgaW5zbW9kIGx6b3BpbzsgZmkKCQlpbnNtb2Qg +cGFydF9ncHQKCQlpbnNtb2QgZXh0MgoJCXNldCByb290PSdoZDAsZ3B0MicKCQlp +ZiBbIHgkZmVhdHVyZV9wbGF0Zm9ybV9zZWFyY2hfaGludCA9IHh5IF07IHRoZW4K +CQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCAtLWhp +bnQtYmlvcz1oZDAsZ3B0MiAtLWhpbnQtZWZpPWhkMCxncHQyIC0taGludC1iYXJl +bWV0YWw9YWhjaTAsZ3B0MiAgZmM1MWI1MzktZThhYi00MDNjLTgwMmQtNjY3MmU0 +ZWYzZTA3CgkJZWxzZQoJCSAgc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAt +LXNldD1yb290IGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJ +CWZpCgkJZWNobwkn6L295YWlIExpbnV4IDUuNC4xOC10a20gLi4uJwoJCWxpbnV4 +CS92bWxpbnV6LTUuNC4xOC10a20gcm9vdD1VVUlEPTY2ODljZmJlLTdjM2EtNDM4 +Yi04NmZkLTJkMTAzOWQ1ZDljYSBybyBzaW5nbGUgbm9tb2Rlc2V0IGRpc191Y29k +ZV9sZHIgIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMKCQllY2hvCSfovb3lhaXliJ3l +p4vljJblhoXlrZjnm5guLi4nCgkJaW5pdHJkCS9pbml0cmQuaW1nLTUuNC4xOC10 +a20KCX0ACAAAAA0AAAADAAAABADcgM/1k4C/xovb6FwBkfqd6Zr/NQsA4a9JjIid +zWneHewak7usay2vVrIMMWVZcgxey2PrrDsSAKWmSDLJ7Dl9QbVWbrv4JX8Yv7A5 +57+5fq+A4fRDBqQ25AMAAGdydWJfY21kOiBtZW51ZW50cnkgS3lsaW4gVjEwIFNQ +MSwgNS40LjE4LWNzdiAtLWNsYXNzIGt5bGluIC0tY2xhc3MgZ251LWxpbnV4IC0t +Y2xhc3MgZ251IC0tY2xhc3Mgb3MgLS1pZCBnbnVsaW51eC01LjQuMTgtY3N2LWFk +dmFuY2VkLTY2ODljZmJlLTdjM2EtNDM4Yi04NmZkLTJkMTAzOWQ1ZDljYSB7CgkJ +cmVjb3JkZmFpbAoJCWxvYWRfdmlkZW8KCQlnZnhtb2RlICRsaW51eF9nZnhfbW9k +ZQoJCWluc21vZCBnemlvCgkJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07 +IHRoZW4gaW5zbW9kIHh6aW87IGluc21vZCBsem9waW87IGZpCgkJaW5zbW9kIHBh +cnRfZ3B0CgkJaW5zbW9kIGV4dDIKCQlzZXQgcm9vdD0naGQwLGdwdDInCgkJaWYg +WyB4JGZlYXR1cmVfcGxhdGZvcm1fc2VhcmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJ +ICBzZWFyY2ggLS1uby1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgLS1oaW50 +LWJpb3M9aGQwLGdwdDIgLS1oaW50LWVmaT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1l +dGFsPWFoY2kwLGdwdDIgIGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVm +M2UwNwoJCWVsc2UKCQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1z +ZXQ9cm9vdCBmYzUxYjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQlm +aQoJCWVjaG8JJ+i9veWFpSBMaW51eCA1LjQuMTgtY3N2IC4uLicKCQlsaW51eAkv +dm1saW51ei01LjQuMTgtY3N2IHJvb3Q9VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGIt +ODZmZC0yZDEwMzlkNWQ5Y2Egcm8gIHF1aWV0IHNwbGFzaCBkZWZhdWx0X2h1Z2Vw +YWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBtZW1fZW5jcnlwdD1v +ZmYgIHJlc3VtZT1VVUlEPTZhM2ExNmVmLWMwMTEtNDkxNi1iMDc4LWNlNjk5YjIx +N2Y4MCBhdWRpdD0wIHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn6L295YWl5Yid5aeL +5YyW5YaF5a2Y55uYLi4uJwoJCWluaXRyZAkvaW5pdHJkLmltZy01LjQuMTgtY3N2 +Cgl9AAgAAAANAAAAAwAAAAQAjWdefpSZqeezEPd634h2CdgowB8LAAyodg73+xWw +Ki2tBRb9Ttcn9XMPdWMZvEY2Ht7R6SSCEgBRQy4alaGkfRJKwgsaHaRtW4vJbMod +aoe6LyF6yEOjQHoDAABncnViX2NtZDogbWVudWVudHJ5IEt5bGluIFYxMCBTUDEs +IDUuNC4xOC1jc3YgKHJlY292ZXJ5IG1vZGUpIC0tY2xhc3Mga3lsaW4gLS1jbGFz +cyBnbnUtbGludXggLS1jbGFzcyBnbnUgLS1jbGFzcyBvcyAtLWlkIGdudWxpbnV4 +LTUuNC4xOC1jc3YtcmVjb3ZlcnktNjY4OWNmYmUtN2MzYS00MzhiLTg2ZmQtMmQx +MDM5ZDVkOWNhIHsKCQlyZWNvcmRmYWlsCgkJbG9hZF92aWRlbwoJCWluc21vZCBn +emlvCgkJaWYgWyB4JGdydWJfcGxhdGZvcm0gPSB4eGVuIF07IHRoZW4gaW5zbW9k +IHh6aW87IGluc21vZCBsem9waW87IGZpCgkJaW5zbW9kIHBhcnRfZ3B0CgkJaW5z +bW9kIGV4dDIKCQlzZXQgcm9vdD0naGQwLGdwdDInCgkJaWYgWyB4JGZlYXR1cmVf +cGxhdGZvcm1fc2VhcmNoX2hpbnQgPSB4eSBdOyB0aGVuCgkJICBzZWFyY2ggLS1u +by1mbG9wcHkgLS1mcy11dWlkIC0tc2V0PXJvb3QgLS1oaW50LWJpb3M9aGQwLGdw +dDIgLS1oaW50LWVmaT1oZDAsZ3B0MiAtLWhpbnQtYmFyZW1ldGFsPWFoY2kwLGdw +dDIgIGZjNTFiNTM5LWU4YWItNDAzYy04MDJkLTY2NzJlNGVmM2UwNwoJCWVsc2UK +CQkgIHNlYXJjaCAtLW5vLWZsb3BweSAtLWZzLXV1aWQgLS1zZXQ9cm9vdCBmYzUx +YjUzOS1lOGFiLTQwM2MtODAyZC02NjcyZTRlZjNlMDcKCQlmaQoJCWVjaG8JJ+i9 +veWFpSBMaW51eCA1LjQuMTgtY3N2IC4uLicKCQlsaW51eAkvdm1saW51ei01LjQu +MTgtY3N2IHJvb3Q9VVVJRD02Njg5Y2ZiZS03YzNhLTQzOGItODZmZC0yZDEwMzlk +NWQ5Y2Egcm8gc2luZ2xlIG5vbW9kZXNldCBkaXNfdWNvZGVfbGRyICBhdWRpdD0w +IHNlY3VyaXR5PWt5c2VjCgkJZWNobwkn6L295YWl5Yid5aeL5YyW5YaF5a2Y55uY +Li4uJwoJCWluaXRyZAkvaW5pdHJkLmltZy01LjQuMTgtY3N2Cgl9AAgAAAANAAAA +AwAAAAQA0Cq5PY/APR7cQ92SyQ1zDTAIx7ALAFUiPUUfl1dZ2wGVEXPLy9c3ZKpo +pyssiJxBqvetoVHmEgABRTW15itStuohXZmhnNH315+gUBs3p5KI+WIBjUKVhi4A +AABncnViX2NtZDogc2V0cGFyYW1zIEt5bGluIFYxMCBTUDEsIDUuNC4xOC1jc3YA +CAAAAA0AAAADAAAABACY0Gb4/9BGuss4sQYYjL5/6a2nKQsApX4Gfihu/E7qiWWd +QPE6OMwXkuQne+2CDe1nTJS/Lq0SAGSsqEVdFAzMXwRuLbNPKDdHOYrhS+ZBSMgw +RdMfdyLUFQAAAGdydWJfY21kOiByZWNvcmRmYWlsAAgAAAANAAAAAwAAAAQAusFw +hf71BDZipQzvGL82aETAdP8LAGS9qPZbFYXXhoJIopLESWYMyPdQdcENh65ZpNtA +HOEZEgCJB/N29pmas13OBtEhMWnXxfOc6MI2RCeMoUx1BFYZbhsAAABncnViX2Nt +ZDogc2V0IHJlY29yZGZhaWw9MQAIAAAADQAAAAMAAAAEAHqGAJ3B8jhn2JUbuVRx +YYveLRkYCwAkNq/jyxgUVKuAfWylJu0xMtwXWXh/ntPy8UjoaUjpeBIAXYS7iLk9 +Nz2OHkKjHxSqtSxus74O5o+hDK0MnNQ46tsSAAAAZ3J1Yl9jbWQ6IFsgLW4gIF0A +CAAAAA0AAAADAAAABACP5Z5m1uwZhCBHfyT3kekp8VPhRAsAdiar2L50QsLldTZK +PpXLOjtTPFivu6QC0r2r3/hdKccSAAeRC3qRsUKDOoArzKyntyWDX8AG0ilHQTru +BVmfNXMWFQAAAGdydWJfY21kOiBsb2FkX3ZpZGVvAAgAAAANAAAAAwAAAAQA9bBn +5ZwWP2exm4NvvunopIehnN0LAEVoNh+3WBsxpC1kWrU0MC+590Ktqje3/eFSIV1p +4ln7EgBJraCnDXO9KW/3jIOHyYT0PAOtMJPFJBl2925kGf15XBYAAABncnViX2Nt +ZDogWyB4eSA9IHh5IF0ACAAAAA0AAAADAAAABABZztNDsGC331T6e6JR74d5QGAe +5AsA1xNT9TaOssEoBZCSgSiXm9luqNsejIFJP3h4ODt2qzsSAPCuKf8NGKYeSMdz +vwj1laA9+/VKcO83zNTH7LgO82WnGwAAAGdydWJfY21kOiBpbnNtb2QgYWxsX3Zp +ZGVvAAgAAAANAAAAAwAAAAQAE60ajd9kfIFI8XObYIHXg4gWtZ8LAC+oBl2e4wk4 +TTX41TAYa3dtJuG7VjL4mkbVbpOxQCgrEgBQu039M/+QlP8IgDXDwzjZowStSzbx +CIK3zPps8EzElRcAAABncnViX2NtZDogZ2Z4bW9kZSBrZWVwAAgAAAANAAAAAwAA +AAQALhxnbd2bFvDXIM1cZthXMt57d7YLABWlAYsBd8+cScC5eRHfZ+fywZPTYT4/ +xMnrmKK10G/MEgCniW8dSPi+GohzRJhPnoZv1wOl2dzMr2eP/ZKm7SrP5x4AAABn +cnViX2NtZDogc2V0IGdmeHBheWxvYWQ9a2VlcAAIAAAADQAAAAMAAAAEALpQnKOC +EPBoPEd8ncQOTE9lPh37CwBsRnTUxlLuZ7mKYgbXVBzL8tXcChja4xrWboLHlMSX +hBIAJ6EDTah33TUI664SCsQwLjsbHTLzVY/76CSDN0EU85UWAAAAZ3J1Yl9jbWQ6 +IGluc21vZCBnemlvAAgAAAANAAAAAwAAAAQALehF3OilHI/duqBGhnYAkzJbdWkL +ABiGVGjy5L2fDMT/3aEzX0BdBt+Nb/GDs3P1DgjoH5JNEgA9QTafZvLt2MwVj7ce +xJ23AiBoEaMh2TSp4Azxr/B14BoAAABncnViX2NtZDogWyB4ZWZpID0geHhlbiBd +AAgAAAANAAAAAwAAAAQApOHG9QV5tHyWQRHR6iFw5vkjyUELAGLNdtMco9ENdC5G +xv8XEEbOGd2Q82GoJ/7GVx5ZwkeUEgCQj2JiFB82Zdf73hlV4Fe2+ZM3za17+s9v +dYU9rx2PpBoAAABncnViX2NtZDogaW5zbW9kIHBhcnRfZ3B0AAgAAAANAAAAAwAA +AAQArz8Hq6yeXFa4LwmrmDKJBaq79u8LALg4pNKGDIEFgQX7sZB6H7f2C2VZGwmb +OwANmzHY0vsgEgCIG7misbEg9fcfHP3ZYd08L2Vr8OAvcDJysP/wLkovMhYAAABn +cnViX2NtZDogaW5zbW9kIGV4dDIACAAAAA0AAAADAAAABACsNEEaPnhkwh+GVD3B +Z1X/TSQtegsAF7LDHq/HWkO/Ioee/PguSj0m4hLX1zNhyeB1XDevrPcSAMygGKoo +Lh5m1NBB78MOtt6W80xAPuGJCM2Jk61ydqtBHAAAAGdydWJfY21kOiBzZXQgcm9v +dD1oZDAsZ3B0MgAIAAAADQAAAAMAAAAEAPWwZ+WcFj9nsZuDb77p6KSHoZzdCwBF +aDYft1gbMaQtZFq1NDAvufdCrao3t/3hUiFdaeJZ+xIASa2gpw1zvSlv94yDh8mE +9DwDrTCTxSQZdvduZBn9eVwWAAAAZ3J1Yl9jbWQ6IFsgeHkgPSB4eSBdAAgAAAAN +AAAAAwAAAAQACLDoCKlOzMdChbcLGvQfBMFTuGcLALlL6DFp9VaxzQuEl1iTFSaD +t7ZE2VOM+iSS2xAnpHB1EgDgDEkmSJ/aKaaQEC4CCRWWgGvMfxuV0Ul+c8u/tqF6 +9JwAAABncnViX2NtZDogc2VhcmNoIC0tbm8tZmxvcHB5IC0tZnMtdXVpZCAtLXNl +dD1yb290IC0taGludC1iaW9zPWhkMCxncHQyIC0taGludC1lZmk9aGQwLGdwdDIg +LS1oaW50LWJhcmVtZXRhbD1haGNpMCxncHQyIGZjNTFiNTM5LWU4YWItNDAzYy04 +MDJkLTY2NzJlNGVmM2UwNwAIAAAADQAAAAMAAAAEAD3wdZ0Ci8YrCYrPYDt6+8+S +NPy1CwCZSykjPgzTzCU7mfrbvP4PqDVWO4Nx/1XbyFXaqnvgzxIAa85gxulLn7DV +XbCEY8sMP0qChGVmTbvS34NHg1a3+6grAAAAZ3J1Yl9jbWQ6IGVjaG8g6L295YWl +IExpbnV4IDUuNC4xOC1jc3YgLi4uAAkAAAANAAAAAwAAAAQA7/XfuTKUWWPYd8VU +YSRrboUKR4sLACbi7WsibJZGbd4k5vvviX4vbLsuRsDLfY47ZBCu2iy4EgCLqXH9 +u/Ju8cSqfjIHspKxQBNWyB24IkOVXoQgVMHg1ykAAAAoaGQwLGdwdDEpL2Jvb3Qv +Z3J1Yi94ODZfNjQtZWZpL2VjaG8ubW9kAAgAAAANAAAAAwAAAAQA3KkQMCNuaMCO +iqch+wchyyPu3sMLABZIVeZU+/vk1pabOnIjTu2OwuT+EgVjvOggoTFAc+Z+EgCd +I53xddnsHBbfQXq6dMLFxTT7dmB3RWhwQY9VmoC5LesAAABncnViX2NtZDogbGlu +dXggL3ZtbGludXotNS40LjE4LWNzdiByb290PVVVSUQ9NjY4OWNmYmUtN2MzYS00 +MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHJvIHF1aWV0IHNwbGFzaCBkZWZhdWx0X2h1 +Z2VwYWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBtZW1fZW5jcnlw +dD1vZmYgcmVzdW1lPVVVSUQ9NmEzYTE2ZWYtYzAxMS00OTE2LWIwNzgtY2U2OTli +MjE3ZjgwIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMACQAAAA0AAAADAAAABADpzyd8 +7v42M3ohmL7bKueEF948bAsA4qF0YNX45QhsnuRDemLfEhXtw+Lnp/n2BcCgMdpO +evESAJ+sGRic+FZJ32B43G6AU6U16i5wTc5Ht5f4w9InEOVtKgAAAChoZDAsZ3B0 +MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvbGludXgubW9kAAkAAAANAAAAAwAAAAQA +fCRA9WLik3+DurLfyuDhQ1cHWfQLAA8U8MFXVATCwYmIFXnTR8j1nra1bnGO1MLz +CsCfzgDeEgAl+rg5vzpwd2btr9z9PE5LvAQFU+q2wWfZa6QBzEQi/S4AAAAoaGQw +LGdwdDEpL2Jvb3QvZ3J1Yi94ODZfNjQtZWZpL3JlbG9jYXRvci5tb2QACQAAAA0A +AAADAAAABAAuakEHyPWViSFUKpUeb4IpbHXAwgsAyOggXMWzTvunI8BmD+iys12C +c14O2NPCMRWPVmBblzYSAFGwS3HxPTqEMiXB+vnYyEscWsnOLnqB4GwBOWPen6NM +KQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvbW1hcC5tb2QACQAA +AA0AAAADAAAABABgMMQbmD1iMIHuooycxWHeK2dbQwsApCHgjzVzBMUhx1+xtQqT +nbZc4eICf2+yCgyqM45qecQSADCFvMWLjDGRjrgWWRPdFpR+HvtMGUbYoAYIOcnQ +rZ8sLQAAAChoZDAsZ3B0MSkvYm9vdC9ncnViL3g4Nl82NC1lZmkvbGludXhlZmku +bW9kAAkAAAANAAAAAwAAAAQAV0xlAEJz4EyBRwZsIbp1jbPgt6QLAGYflDeDqoOD +C0kYAos3h2iS0gh4snKDz5yGZYW0CRNwEgA3a0J15FztbUN/WvEEGqYJJDGndxE8 +VXhqu6RwmK1wsxQAAAAvdm1saW51ei01LjQuMTgtY3N2AAgAAAANAAAAAwAAAAQA +JjrJrXUFWdCkLT8dlwtVomb/fzwLABHQaJBmPk9AfYu9yULICRkpN+vQE02hFwNq +EBg9QSdNEgAOIPa1D84Q0N99nm+/U2cP6zbIFri8roUi/VRbTGvYUOsAAABrZXJu +ZWxfY21kbGluZTogL3ZtbGludXotNS40LjE4LWNzdiByb290PVVVSUQ9NjY4OWNm +YmUtN2MzYS00MzhiLTg2ZmQtMmQxMDM5ZDVkOWNhIHJvIHF1aWV0IHNwbGFzaCBk +ZWZhdWx0X2h1Z2VwYWdlc3o9MUcgaHVnZXBhZ2Vzej0xRyBodWdlcGFnZXM9MSBt +ZW1fZW5jcnlwdD1vZmYgcmVzdW1lPVVVSUQ9NmEzYTE2ZWYtYzAxMS00OTE2LWIw +NzgtY2U2OTliMjE3ZjgwIGF1ZGl0PTAgc2VjdXJpdHk9a3lzZWMACAAAAA0AAAAD +AAAABAC/hvcdBkhxjl2+ZJiqBuxEKpskRgsAG9EMQ82y5nVDthS7D1yM1d3SCsxj +qfdna8gylS37OGASAG/0sItqAvaP8k/EcDOtqaHIWpKPkbsATWr+eKLQUiw2KwAA +AGdydWJfY21kOiBlY2hvIOi9veWFpeWIneWni+WMluWGheWtmOebmC4uLgAIAAAA +DQAAAAMAAAAEAGcaiXLr+P/uLenWBj5xr6Mwi+y/CwAXOFqmbLowFNuv8htW4pOT +bVTXL8C7T3hrj5TstRyEqRIAqlzkaS6bJfmugPhLMN09TMmUEendFgaZ467R6pep +TDUoAAAAZ3J1Yl9jbWQ6IGluaXRyZCAvaW5pdHJkLmltZy01LjQuMTgtY3N2AAkA +AAANAAAAAwAAAAQAFi6/EDL6ctnKcjgBa+eK7gvr2KoLAGWXykP7KaqH6jnc4Ndk +n7Fy2yWKu4vG2uJ8Huf2Fi5uEgCv4Nvq6VcJlE5XQ22aI/nNaqsrbR9Mqr/UC1Ax +72MrMxcAAAAvaW5pdHJkLmltZy01LjQuMTgtY3N2AAUAAAAHAACAAwAAAAQARDpr +e4K3r1ZPLjk82dWjiLf6SpgLANgEPWt7ha01jrO2rmqHOrfvI6JjUsXcT6pa7trP +XrQbEgB/UC+7//tNhL9tx0P79ZyLyJzPkN3K4iGWtSuaMkfdHx0AAABFeGl0IEJv +b3QgU2VydmljZXMgSW52b2NhdGlvbgUAAAAHAACAAwAAAAQAR1VF3cl417/QNvrM +fi6Yf0gYnw0LALVPdULL2HKoGp2d6oObK410fH69XqZhXED0L0Sm2+ugEgCUlJ4M +fh6D5GCcH1B3sFAPK2ONnKX8fS/9g2KDylEfoygAAABFeGl0IEJvb3QgU2Vydmlj +ZXMgUmV0dXJuZWQgd2l0aCBTdWNjZXNz diff --git a/test/data/fapi/policy/pol_signed_keyedhash_sha384.json b/test/data/fapi/policy/pol_signed_keyedhash_sha384.json new file mode 100644 index 0000000..586d170 --- /dev/null +++ b/test/data/fapi/policy/pol_signed_keyedhash_sha384.json @@ -0,0 +1,11 @@ +{ + "description":"Description pol_signed", + "policy":[ + { + "type": "POLICYSIGNED", + "publicKeyHint": "Test key hint", + "keyPath": "/SRK/sym_sign_key", + "keyPEMhashAlg": "SHA384" + } + ] +} diff --git a/test/fuzz/main-sys.c b/test/fuzz/main-sys.c index cc0e395..b3e5a53 100644 --- a/test/fuzz/main-sys.c +++ b/test/fuzz/main-sys.c @@ -16,54 +16,47 @@ #include "tss2_tcti.h" #include "util/log.h" #include "test.h" -#include "test-options.h" -#include "context-util.h" #include "tss2-sys/sysapi_util.h" #include "tcti/tcti-fuzzing.h" +#include "test-common.h" + int LLVMFuzzerTestOneInput ( const uint8_t *Data, size_t Size) { - int ret; - TSS2_SYS_CONTEXT *sys_context; - _TSS2_SYS_CONTEXT_BLOB *ctx = NULL; + TSS2_TEST_SYS_CONTEXT *test_sys_ctx; TSS2_TCTI_FUZZING_CONTEXT *tcti_fuzzing = NULL; + TSS2_RC rc; + int ret; - /* Use the fuzzing tcti */ - test_opts_t opts = { - .tcti_type = FUZZING_TCTI, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) { - LOG_ERROR("Checking test options"); - exit(1); /* fatal error */ + ret = test_sys_setup(&test_sys_ctx); + if (ret != 0) { + return ret; } - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) { - LOG_ERROR("SYS context not initialized"); - exit(1); /* fatal error */ + ret = test_sys_checks_pre(test_sys_ctx); + if (ret != 0) { + return ret; } - ctx = syscontext_cast (sys_context); - tcti_fuzzing = tcti_fuzzing_context_cast (ctx->tctiContext); + tcti_fuzzing = tcti_fuzzing_context_cast(test_sys_ctx->tcti_ctx); tcti_fuzzing->data = Data; tcti_fuzzing->size = Size; - ret = test_invoke (sys_context); - - sys_teardown_full (sys_context); + rc = test_invoke(test_sys_ctx->sys_ctx); + if (rc != 0 && ret != 77) { + LOG_ERROR("Test returned %08x", rc); + exit(1); + } - if (ret) { - LOG_ERROR("Test failed"); - exit(1); /* fatal error */ + ret = test_sys_checks_post(test_sys_ctx); + if (ret != 0) { + exit(1); } + test_sys_teardown(test_sys_ctx); + return 0; // Non-zero return values are reserved for future use. } diff --git a/test/fuzz/tcti-spi-helper-fuzz-test.c b/test/fuzz/tcti-spi-helper-fuzz-test.c index 2535bd8..c21aea0 100644 --- a/test/fuzz/tcti-spi-helper-fuzz-test.c +++ b/test/fuzz/tcti-spi-helper-fuzz-test.c @@ -6,6 +6,7 @@ #include #include +#include #define LOGMODULE test #include "tss2_sys.h" @@ -13,10 +14,6 @@ #include "tss2/tss2_tcti_spi_helper.h" #include "util/log.h" #include "test.h" -#include "test-options.h" -#include "context-util.h" -#include "tss2-sys/sysapi_util.h" -#include "tcti/tcti-fuzzing.h" typedef struct fuzz_user_data fuzz_user_data; struct fuzz_user_data { diff --git a/test/fuzz/tcti/tcti-fuzzing.c b/test/fuzz/tcti/tcti-fuzzing.c index a4cda84..78ed925 100644 --- a/test/fuzz/tcti/tcti-fuzzing.c +++ b/test/fuzz/tcti/tcti-fuzzing.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "tss2_mu.h" #include "tss2_tcti_fuzzing.h" @@ -264,7 +265,7 @@ Tss2_Tcti_Fuzzing_Init ( } /* public info structure */ -const TSS2_TCTI_INFO tss2_tcti_info = { +const TSS2_TCTI_INFO tss2_tcti_fuzzing_info = { .version = TCTI_VERSION, .name = "tcti-fuzzing", .description = "TCTI module for fuzzing the System API.", @@ -275,5 +276,5 @@ const TSS2_TCTI_INFO tss2_tcti_info = { const TSS2_TCTI_INFO* Tss2_Tcti_Info (void) { - return &tss2_tcti_info; + return &tss2_tcti_fuzzing_info; } diff --git a/test/fuzz/tcti/tcti-fuzzing.h b/test/fuzz/tcti/tcti-fuzzing.h index 09a396a..c4c0026 100644 --- a/test/fuzz/tcti/tcti-fuzzing.h +++ b/test/fuzz/tcti/tcti-fuzzing.h @@ -10,7 +10,6 @@ #include #include "tss2-tcti/tcti-common.h" -#include "util/io.h" #include "tss2-sys/sysapi_util.h" #define TCTI_FUZZING_MAGIC 0x66757a7a696e6700ULL diff --git a/test/helper/tpm_dumpstate.c b/test/helper/tpm_dumpstate.c deleted file mode 100644 index ad7e760..0000000 --- a/test/helper/tpm_dumpstate.c +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "tss2_sys.h" -#include "tss2_mu.h" - -#define LOGMODULE test -#include "util/log.h" -#include "test-options.h" -#include "context-util.h" - -#define TAB_SIZE(x) (sizeof(x)/sizeof(x[0])) - -/* NOTE: CAP_PCRS and CAP_HANDLES->HR_PCR do not change until a reboot is - triggered. This should be improved if an approach is found. */ -struct { - TPM2_CAP cap; - UINT32 prop; - UINT32 count; -} capabilities[] = { - { TPM2_CAP_PCRS, 0, 10 }, - { TPM2_CAP_HANDLES, TPM2_HR_PCR, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_HMAC_SESSION, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_POLICY_SESSION, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_TRANSIENT, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_PERSISTENT, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_NV_INDEX, TPM2_MAX_CAP_HANDLES }, -}; - -int -main (int argc, char *argv[]) -{ - TSS2_RC rc; - TSS2_SYS_CONTEXT *sys_context; - - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) - exit (1); - - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) - exit (1); - - for (size_t i = 0; i < TAB_SIZE(capabilities); i++) { - TPMS_CAPABILITY_DATA caps; - uint8_t buffer[sizeof(caps)]; - size_t off = 0; - - rc = Tss2_Sys_GetCapability(sys_context, NULL, capabilities[i].cap, - capabilities[i].prop, - capabilities[i].count, NULL, - &caps, NULL); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM GetCapabilities FAILED: 0x%"PRIx32, rc); - exit(1); - } - - rc = Tss2_MU_TPMS_CAPABILITY_DATA_Marshal(&caps, &buffer[off], - sizeof(buffer) - off - 1, - &off); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Marshaling FAILED: 0x%"PRIx32, rc); - exit(1); - } - - buffer[off++] = '\0'; - - printf("cap%zi: ", i); - for (size_t j = 0; j < off; j++) - printf("%02"PRIx8, buffer[j]); - printf("\n"); - } - - sys_teardown_full (sys_context); - - return 0; -} diff --git a/test/helper/tpm_getek.c b/test/helper/tpm_getek.c deleted file mode 100644 index c5c5493..0000000 --- a/test/helper/tpm_getek.c +++ /dev/null @@ -1,182 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#if OPENSSL_VERSION_NUMBER < 0x30000000 -#include -#else -#include -#include -#include -#endif - -#include "tss2_sys.h" -#include "tss2_mu.h" - -#define LOGMODULE test -#include "util/log.h" -#include "test-options.h" -#include "context-util.h" - -int -main (int argc, char *argv[]) -{ - TSS2_RC rc; - TSS2_SYS_CONTEXT *sys_context; - TSS2L_SYS_AUTH_COMMAND auth_cmd = { - .auths = {{ .sessionHandle = TPM2_RH_PW }}, - .count = 1 - }; - TPM2B_SENSITIVE_CREATE in_sensitive = { 0 }; - TPM2B_PUBLIC in_public = { - .publicArea = { - .type = TPM2_ALG_RSA, - .nameAlg = TPM2_ALG_SHA256, - .objectAttributes = ( - TPMA_OBJECT_FIXEDTPM | - TPMA_OBJECT_FIXEDPARENT | - TPMA_OBJECT_SENSITIVEDATAORIGIN | - TPMA_OBJECT_ADMINWITHPOLICY | - TPMA_OBJECT_RESTRICTED | - TPMA_OBJECT_DECRYPT - ), - .authPolicy = { - .size = 32, - .buffer = 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, - 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, - 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, - 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, - 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, - 0x69, 0xAA, - }, - .parameters.rsaDetail = { - .symmetric = { - .algorithm = TPM2_ALG_AES, - .keyBits.aes = 128, - .mode.aes = TPM2_ALG_CFB, - }, - .scheme = { - .scheme = TPM2_ALG_NULL, - }, - .keyBits = 2048, - .exponent = 0, - }, - .unique.rsa = { - .size = 256, - .buffer = {0}, - } - } - }; - TPML_PCR_SELECTION creation_pcr = { 0 }; - TPM2_HANDLE handle; - TPM2B_PUBLIC out_public = { 0 }; - TSS2L_SYS_AUTH_RESPONSE auth_rsp = { - .count = 0 - }; - - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) - exit (1); - - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) - exit (1); - - /* Generate the EK key */ - - rc = Tss2_Sys_CreatePrimary(sys_context, TPM2_RH_ENDORSEMENT, &auth_cmd, - &in_sensitive, &in_public, NULL, &creation_pcr, - &handle, &out_public, NULL, NULL, NULL, NULL, &auth_rsp); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM CreatePrimary FAILED: 0x%"PRIx32, rc); - exit(1); - } - - rc = Tss2_Sys_FlushContext(sys_context, handle); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM FlushContext FAILED: 0x%"PRIx32, rc); - exit(1); - } - - sys_teardown_full (sys_context); - - /* Convert the key from out_public to PEM */ - - EVP_PKEY *evp = NULL; - BIO *bio; - FILE *out = NULL; - - if (argc == 2) { - out = fopen(argv[1], "w"); - if (!out) { - LOG_ERROR("Can not open file %s", argv[1]); - exit(1); - } - bio = BIO_new_fp(out, BIO_NOCLOSE); - } - else - bio = BIO_new_fp(stdout, BIO_NOCLOSE); - - BIGNUM *n = BN_bin2bn(out_public.publicArea.unique.rsa.buffer, - out_public.publicArea.unique.rsa.size, NULL); - uint32_t exp; - if (out_public.publicArea.parameters.rsaDetail.exponent == 0) - exp = 65537; - else - exp = out_public.publicArea.parameters.rsaDetail.exponent; - -#if OPENSSL_VERSION_NUMBER < 0x30000000 - BIGNUM *e = BN_new(); - BN_set_word(e, exp); - - RSA *rsa = RSA_new(); - RSA_set0_key(rsa, n, e, NULL); - n = NULL; - e = NULL; - - evp = EVP_PKEY_new(); - EVP_PKEY_assign_RSA(evp, rsa); -#else /* OPENSSL_VERSION_NUMBER < 0x30000000 */ - OSSL_PARAM_BLD *build = OSSL_PARAM_BLD_new(); - OSSL_PARAM_BLD_push_BN(build, OSSL_PKEY_PARAM_RSA_N, n); - OSSL_PARAM_BLD_push_uint32(build, OSSL_PKEY_PARAM_RSA_E, exp); - OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(build); - - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL); - EVP_PKEY_fromdata_init(ctx); - EVP_PKEY_fromdata(ctx, &evp, EVP_PKEY_PUBLIC_KEY, params); -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000 */ - - if (!PEM_write_bio_PUBKEY(bio, evp)) { - LOG_ERROR("PEM_write failed"); - exit(1); - } - - EVP_PKEY_free(evp); -#if OPENSSL_VERSION_NUMBER < 0x30000000 - /* ownership was taken by the EVP_PKEY */ -#else - EVP_PKEY_CTX_free(ctx); - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(build); -#endif - BN_free(n); - BIO_free(bio); - fclose(out); - - return 0; -} diff --git a/test/helper/tpm_getek_ecc.c b/test/helper/tpm_getek_ecc.c deleted file mode 100644 index 5a0e252..0000000 --- a/test/helper/tpm_getek_ecc.c +++ /dev/null @@ -1,232 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#if OPENSSL_VERSION_NUMBER < 0x30000000 -#include -#else -#include -#include -#include -#endif -#include - -#include "tss2_sys.h" -#include "tss2_mu.h" - -#define LOGMODULE test -#include "util/log.h" -#include "test-options.h" -#include "context-util.h" - -void handleErrors(void) -{ - unsigned long errCode; - - printf("An error occurred\n"); - while((errCode = ERR_get_error())) - { - char *err = ERR_error_string(errCode, NULL); - printf("%s\n", err); - } - abort(); -} - -int -main (int argc, char *argv[]) -{ - TSS2_RC rc; - TSS2_SYS_CONTEXT *sys_context; - TSS2L_SYS_AUTH_COMMAND auth_cmd = { - .auths = {{ .sessionHandle = TPM2_RH_PW }}, - .count = 1 - }; - TPM2B_SENSITIVE_CREATE in_sensitive = { 0 }; - TPM2B_PUBLIC in_public = { - .publicArea = { - .type = TPM2_ALG_ECC, - .nameAlg = TPM2_ALG_SHA256, - .objectAttributes = ( - TPMA_OBJECT_FIXEDTPM | - TPMA_OBJECT_FIXEDPARENT | - TPMA_OBJECT_SENSITIVEDATAORIGIN | - TPMA_OBJECT_ADMINWITHPOLICY | - TPMA_OBJECT_RESTRICTED | - TPMA_OBJECT_DECRYPT - ), - .authPolicy = { - .size = 32, - .buffer = 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, - 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, - 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, - 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, - 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, - 0x69, 0xAA, - }, - .parameters.eccDetail = { - .symmetric = { - .algorithm = TPM2_ALG_AES, - .keyBits.aes = 128, - .mode.aes = TPM2_ALG_CFB, - }, - .scheme = { - .scheme = TPM2_ALG_NULL, - .details = { 0 } - }, - .curveID = TPM2_ECC_NIST_P256, - .kdf = {.scheme = TPM2_ALG_NULL, - .details = { 0 } - } - }, - .unique.ecc = { - .x = {.size = 32,.buffer = { 0 }}, - .y = {.size = 32,.buffer = { 0 }} - } - } - }; - TPML_PCR_SELECTION creation_pcr = { 0 }; - TPM2_HANDLE handle; - TPM2B_PUBLIC out_public = { 0 }; - TSS2L_SYS_AUTH_RESPONSE auth_rsp = { - .count = 0 - }; - - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) - exit (1); - - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) - exit (1); - - /* Generate the EK key */ - - rc = Tss2_Sys_CreatePrimary(sys_context, TPM2_RH_ENDORSEMENT, &auth_cmd, - &in_sensitive, &in_public, NULL, &creation_pcr, - &handle, &out_public, NULL, NULL, NULL, NULL, &auth_rsp); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM CreatePrimary FAILED: 0x%"PRIx32, rc); - exit(1); - } - - rc = Tss2_Sys_FlushContext(sys_context, handle); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM FlushContext FAILED: 0x%"PRIx32, rc); - exit(1); - } - - sys_teardown_full (sys_context); - - /* Convert the key from out_public to PEM */ - - EVP_PKEY *evp = NULL; - BIGNUM *x = NULL, *y = NULL; - BIO *bio; - FILE *out = NULL; - int nid; - - if (argc == 2) { - out = fopen(argv[1], "w"); - if (!out) { - LOG_ERROR("Can not open file %s", argv[1]); - exit(1); - } - bio = BIO_new_fp(out, BIO_NOCLOSE); - } - else - bio = BIO_new_fp(stdout, BIO_NOCLOSE); - - nid = EC_curve_nist2nid("P-256"); - EC_GROUP *ecgroup = EC_GROUP_new_by_curve_name(nid); - - /* Set the ECC parameters in the OpenSSL key */ - x = BN_bin2bn(out_public.publicArea.unique.ecc.x.buffer, - out_public.publicArea.unique.ecc.x.size, NULL); - - y = BN_bin2bn(out_public.publicArea.unique.ecc.y.buffer, - out_public.publicArea.unique.ecc.y.size, NULL); - - if (!x || !y) { - exit(1); - } - - EC_POINT *point = EC_POINT_new(ecgroup); -#if OPENSSL_VERSION_NUMBER < 0x10101000L - EC_POINT_set_affine_coordinates_GFp(ecgroup, point, x, y, NULL); -#else - EC_POINT_set_affine_coordinates(ecgroup, point, x, y, NULL); -#endif - -#if OPENSSL_VERSION_NUMBER < 0x30000000 - EC_KEY *ecc_key = EC_KEY_new(); - if (!EC_KEY_set_group(ecc_key, ecgroup)) - exit(1); - - if (!EC_KEY_set_public_key(ecc_key, point)) { - exit(1); - } - - evp = EVP_PKEY_new(); - if (!EVP_PKEY_assign_EC_KEY(evp, ecc_key)) { - handleErrors(); - LOG_ERROR("PEM_write failed"); - exit(1); - } -#else /* OPENSSL_VERSION_NUMBER < 0x30000000 */ - unsigned char *puboct = NULL; - size_t bsize; - - bsize = EC_POINT_point2buf(ecgroup, point, POINT_CONVERSION_UNCOMPRESSED, - &puboct, NULL); - - OSSL_PARAM_BLD *build = OSSL_PARAM_BLD_new(); - OSSL_PARAM_BLD_push_utf8_string(build, OSSL_PKEY_PARAM_GROUP_NAME, - (char *)OBJ_nid2sn(nid), 0); - OSSL_PARAM_BLD_push_octet_string(build, OSSL_PKEY_PARAM_PUB_KEY, - puboct, bsize); - OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(build); - - EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); - EVP_PKEY_fromdata_init(ctx); - EVP_PKEY_fromdata(ctx, &evp, EVP_PKEY_PUBLIC_KEY, params); -#endif /* OPENSSL_VERSION_NUMBER < 0x30000000 */ - - if (!PEM_write_bio_PUBKEY(bio, evp)) { - handleErrors(); - LOG_ERROR("PEM_write failed"); - exit(1); - } - - EVP_PKEY_free(evp); -#if OPENSSL_VERSION_NUMBER < 0x30000000 - /* ownership was taken by the EVP_PKEY */ -#else - EVP_PKEY_CTX_free(ctx); - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(build); - OPENSSL_free(puboct); -#endif - EC_POINT_free(point); - EC_GROUP_free(ecgroup); - BN_free(y); - BN_free(x); - BIO_free(bio); - fclose(out); - - return 0; -} diff --git a/test/helper/tpm_startup.c b/test/helper/tpm_startup.c deleted file mode 100644 index 126024d..0000000 --- a/test/helper/tpm_startup.c +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "tss2_sys.h" - -#define LOGMODULE test -#include "util/log.h" -#include "test-options.h" -#include "context-util.h" - -int -main (int argc, char *argv[]) -{ - TSS2_RC rc; - TSS2_SYS_CONTEXT *sys_context; - - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) - exit (1); - - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) - exit (1); - - rc = Tss2_Sys_Startup(sys_context, TPM2_SU_CLEAR); - if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { - LOG_ERROR("TPM Startup FAILED! Response Code : 0x%x", rc); - exit(1); - } - - sys_teardown_full (sys_context); - return 0; -} diff --git a/test/helper/tpm_transientempty.c b/test/helper/tpm_transientempty.c deleted file mode 100644 index fb7830f..0000000 --- a/test/helper/tpm_transientempty.c +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "tss2_sys.h" - -#define LOGMODULE test -#include "util/log.h" -#include "test-options.h" -#include "context-util.h" - -#define TAB_SIZE(x) (sizeof(x)/sizeof(x[0])) - -int -main (int argc, char *argv[]) -{ - TSS2_RC rc; - TSS2_SYS_CONTEXT *sys_context; - - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) - exit (1); - - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) - exit (1); - - TPMS_CAPABILITY_DATA caps; - - rc = Tss2_Sys_GetCapability(sys_context, NULL, TPM2_CAP_HANDLES, - TPM2_HR_TRANSIENT, - TAB_SIZE(caps.data.handles.handle), NULL, - &caps, NULL); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM GetCapabilities FAILED! Response Code : 0x%"PRIx32, rc); - exit(1); - } - - - sys_teardown_full (sys_context); - - if (caps.data.handles.count) { - LOG_ERROR("TPM contains transient entries"); - for (UINT32 i = 0; i < caps.data.handles.count; i++) - LOG_ERROR("Handle %"PRIx32, caps.data.handles.handle[i]); - return 1; - } - - return 0; -} diff --git a/test/helper/tpm_writeekcert.c b/test/helper/tpm_writeekcert.c deleted file mode 100644 index 1089884..0000000 --- a/test/helper/tpm_writeekcert.c +++ /dev/null @@ -1,128 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "tss2_sys.h" -#include "tss2_mu.h" - -#define LOGMODULE test -#include "util/log.h" -#include "test-options.h" -#include "context-util.h" - -#define TAB_SIZE(x) (sizeof(x)/sizeof(x[0])) - -/* NOTE: CAP_PCRS and CAP_HANDLES->HR_PCR do not change until a reboot is - triggered. This should be improved if an approach is found. */ -struct { - TPM2_CAP cap; - UINT32 prop; - UINT32 count; -} capabilities[] = { - { TPM2_CAP_PCRS, 0, 10 }, - { TPM2_CAP_HANDLES, TPM2_HR_PCR, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_HMAC_SESSION, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_POLICY_SESSION, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_TRANSIENT, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_PERSISTENT, TPM2_MAX_CAP_HANDLES }, - { TPM2_CAP_HANDLES, TPM2_HR_NV_INDEX, TPM2_MAX_CAP_HANDLES }, -}; - -int -main (int argc, char *argv[]) -{ - TSS2_RC rc; - TSS2_SYS_CONTEXT *sys_context; - TSS2L_SYS_AUTH_COMMAND auth_cmd = { - .auths = {{ .sessionHandle = TPM2_RH_PW }}, - .count = 1 - }; - TPMI_RH_NV_INDEX nvIndex; - - if (argv[1]) - nvIndex = strtol(argv[1], NULL, 16); - else - nvIndex = 0x01c00002; - - TPM2B_AUTH nv_auth = { 0 }; - TPM2B_NV_PUBLIC public_info = { - .nvPublic = { - .nameAlg = TPM2_ALG_SHA1, - .attributes = TPMA_NV_PPWRITE | TPMA_NV_AUTHREAD | TPMA_NV_OWNERREAD | - TPMA_NV_PLATFORMCREATE | TPMA_NV_NO_DA, - .dataSize = 0, - .nvIndex = nvIndex, - }, - }; - - TSS2L_SYS_AUTH_RESPONSE auth_rsp = { - .count = 0 - }; - TPM2B_MAX_NV_BUFFER buf1 = { 0 }; - TPM2B_MAX_NV_BUFFER buf2 = { 0 }; - - buf1.size += fread(&buf1.buffer[buf1.size], sizeof(buf1.buffer[0]), - sizeof(buf1.buffer) - buf1.size, stdin); - if (buf1.size >= sizeof(buf1.buffer)) { - LOG_ERROR("input to large"); - exit(1); - } - - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) - exit (1); - - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) - exit (1); - - /* First make sure that not EK certificate is currently loaded */ - LOG_WARNING("Cert input size is %"PRIu16, buf1.size); - public_info.nvPublic.dataSize = buf1.size; - - LOG_WARNING("Define NV cert with nv index: %x", public_info.nvPublic.nvIndex); - - rc = Tss2_Sys_NV_DefineSpace(sys_context, TPM2_RH_PLATFORM, &auth_cmd, - &nv_auth, &public_info, &auth_rsp); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM NV DefineSpace FAILED: 0x%"PRIx32, rc); - exit(1); - } - - /* Split the input buffer into 2 chunks */ - buf2.size = buf1.size; - buf1.size /= 2; - buf2.size -= buf1.size; - memcpy(&buf2.buffer[0], &buf1.buffer[buf1.size], buf2.size); - - rc = Tss2_Sys_NV_Write(sys_context, TPM2_RH_PLATFORM, nvIndex, &auth_cmd, - &buf1, 0, &auth_rsp); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM NV Write FAILED: 0x%"PRIx32, rc); - exit(1); - } - - rc = Tss2_Sys_NV_Write(sys_context, TPM2_RH_PLATFORM, nvIndex, &auth_cmd, - &buf2, buf1.size, &auth_rsp); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("TPM NV Write FAILED: 0x%"PRIx32, rc); - exit(1); - } - - sys_teardown_full (sys_context); - - return 0; -} diff --git a/test/integration/context-util.h b/test/integration/context-util.h deleted file mode 100644 index 48facbb..0000000 --- a/test/integration/context-util.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/*********************************************************************** - * Copyright (c) 2017-2018, Intel Corporation - * - * All rights reserved. - ***********************************************************************/ -#ifndef CONTEXT_UTIL_H -#define CONTEXT_UTIL_H - -#include "tss2_tcti.h" -#include "tss2_sys.h" - -#include "test-options.h" - -/** - * functions to setup TCTIs and SYS contexts using data from the common - * options - */ -TSS2_TCTI_CONTEXT *tcti_device_init(char const *device_name); -TSS2_TCTI_CONTEXT *tcti_socket_init(char const *address, uint16_t port); -TSS2_TCTI_CONTEXT *tcti_init_from_opts(test_opts_t * options); -TSS2_SYS_CONTEXT *sys_init_from_opts(test_opts_t * options); -TSS2_SYS_CONTEXT *sys_init_from_tcti_ctx(TSS2_TCTI_CONTEXT * tcti_ctx); -void tcti_teardown(TSS2_TCTI_CONTEXT * tcti_context); -void sys_teardown(TSS2_SYS_CONTEXT * sys_context); -void sys_teardown_full(TSS2_SYS_CONTEXT * sys_context); - -#endif /* CONTEXT_UTIL_H */ diff --git a/test/integration/esys-act-set-timeout.int.c b/test/integration/esys-act-set-timeout.int.c index f85a074..a104f75 100644 --- a/test/integration/esys-act-set-timeout.int.c +++ b/test/integration/esys-act-set-timeout.int.c @@ -75,7 +75,9 @@ test_esys_act_set_timeout(ESYS_CONTEXT * esys_context) } } /* If the TPM doesn't support it return skip */ - if (r == TPM2_RC_COMMAND_CODE) + if ((r == TPM2_RC_COMMAND_CODE) || + (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_RC_LAYER)) || + (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_TPM_RC_LAYER))) return EXIT_SKIP; else return EXIT_FAILURE; diff --git a/test/integration/esys-certifyX509.int.c b/test/integration/esys-certifyX509.int.c index 048ed41..f9d625b 100644 --- a/test/integration/esys-certifyX509.int.c +++ b/test/integration/esys-certifyX509.int.c @@ -223,7 +223,9 @@ test_esys_certifyx509(ESYS_CONTEXT * esys_context) Esys_Free(tbsDigest); /* If the TPM doesn't support it return skip */ - if (r == TPM2_RC_COMMAND_CODE) + if ((r == TPM2_RC_COMMAND_CODE) || + (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_RC_LAYER)) || + (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_TPM_RC_LAYER))) return EXIT_SKIP; else return EXIT_FAILURE; diff --git a/test/integration/esys-check-auth-with-trailing-zero.int.c b/test/integration/esys-check-auth-with-trailing-zero.int.c new file mode 100644 index 0000000..a9f52e5 --- /dev/null +++ b/test/integration/esys-check-auth-with-trailing-zero.int.c @@ -0,0 +1,678 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "tss2_esys.h" + +#include "esys_iutil.h" +#define LOGMODULE test +#include "util/log.h" +#include "util/aux_util.h" + +/** This test is intended to test trailing zeros in an auth value + * + * An primary key with an auth value with trailing zeros is created. + * A key with this primary is parent is created. + * Esys_TR_SetAuth which strips the zeros is calles. + * The key is created again. + * The creation of an session where an bind key with a trailing + * zero in the auth value is tested. + * A session where the owner hierarchy is used as bind key in + * combination with Esys_HierarchyChangeAuth is tested. + * An nv index with trailing zeros in the auth value with + * trailing zeros in combination with Esys_NV_ChangeAuth + * is tested. + * + * Tested ESYS commands: + * - Esys_Create() (M) + * - Esys_CreatePrimary() (M) + * - Esys_FlushContext() (M) + * - Esys_StartAuthSession() (M) + * - Esys_PolicyAuthValue() (M) + * - Esys_PolicyCommandcode() (M) + * - Esys_PolicyGetDigest() (M) + * - Esys_NV_DefineSpace() (M) + * - Esys_NV_Write() (M) + * - Esys_NV_Read() (M) + * - Esys_NV_UndefineSpace() (M) + * - Esys_NV_ChangeAuth() (M) + + * @param[in,out] esys_context The ESYS_CONTEXT. + * @retval EXIT_FAILURE + * @retval EXIT_SUCCESS + */ + +int +test_esys_trailing_zeros_in_auth(ESYS_CONTEXT * esys_context) +{ + TSS2_RC r; + ESYS_TR primaryHandle = ESYS_TR_NONE; + ESYS_TR session = ESYS_TR_NONE; + ESYS_TR enc_session = ESYS_TR_NONE; + ESYS_TR bind_key = ESYS_TR_NONE; + ESYS_TR key = ESYS_TR_NONE; + ESYS_TR key_sign = ESYS_TR_NONE; + ESYS_TR policySession = ESYS_TR_NONE; + ESYS_TR sessionTrial = ESYS_TR_NONE; + ESYS_TR nvHandle = ESYS_TR_NONE; + + TPM2B_PUBLIC *outPublic = NULL; + TPM2B_CREATION_DATA *creationData = NULL; + TPM2B_DIGEST *creationHash = NULL; + TPMT_TK_CREATION *creationTicket = NULL; + + TPM2B_PUBLIC *outPublicEcc = NULL; + TPM2B_CREATION_DATA *creationDataEcc = NULL; + TPM2B_DIGEST *creationHashEcc = NULL; + TPMT_TK_CREATION *creationTicketEcc = NULL; + + TPM2B_PUBLIC *outPublic2 = NULL; + TPM2B_PRIVATE *outPrivate2 = NULL; + TPM2B_CREATION_DATA *creationData2 = NULL; + TPM2B_DIGEST *creationHash2 = NULL; + TPMT_TK_CREATION *creationTicket2 = NULL; + + TPM2B_PUBLIC *outPublic3 = NULL; + TPM2B_PRIVATE *outPrivate3 = NULL; + + + TPM2B_AUTH authValuePrimary = { + .size = 6, + .buffer = {1, 2, 3, 4, 5, 0} + }; + + TPM2B_SENSITIVE_CREATE inSensitivePrimary = { + .size = 0, + .sensitive = { + .userAuth = { + .size = 0, + .buffer = {0 }, + }, + .data = { + .size = 0, + .buffer = {0}, + }, + }, + }; + + inSensitivePrimary.sensitive.userAuth = authValuePrimary; + + TPM2B_PUBLIC inPublicPrimary = { + .size = 0, + .publicArea = { + .type = TPM2_ALG_ECC, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT | + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN), + .authPolicy = { + .size = 0, + }, + .parameters.eccDetail = { + .symmetric ={ + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB}, + .scheme = { + .scheme = TPM2_ALG_NULL + }, + .curveID = TPM2_ECC_NIST_P256, + .kdf = { + .scheme = TPM2_ALG_NULL, + .details = {}} + }, + .unique.ecc = { + .x = {.size = 0,.buffer = {}}, + .y = {.size = 0,.buffer = {}}, + }, + }, + }; + + TPM2B_DATA outsideInfo = { + .size = 0, + .buffer = {}, + }; + + TPML_PCR_SELECTION creationPCR = { + .count = 0, + }; + + r = Esys_CreatePrimary(esys_context, ESYS_TR_RH_OWNER, ESYS_TR_PASSWORD, + ESYS_TR_NONE, ESYS_TR_NONE, &inSensitivePrimary, + &inPublicPrimary, + &outsideInfo, &creationPCR, &primaryHandle, + &outPublicEcc, &creationDataEcc, &creationHashEcc, + &creationTicketEcc); + goto_if_error(r, "Error esys create primary", error); + + TPMA_SESSION sessionAttributes; + sessionAttributes = (TPMA_SESSION_DECRYPT | + TPMA_SESSION_ENCRYPT | + TPMA_SESSION_CONTINUESESSION); + + r = Esys_TR_SetAuth(esys_context, primaryHandle, &authValuePrimary); + goto_if_error(r, "Error: TR_SetAuth", error); + + /* Test Session with bind key */ + + static const TPMT_SYM_DEF SESSION_TEMPLATE_SYM_AES_128_CFB = + { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }; + + TPM2B_PUBLIC template = + { + .size = sizeof(TPMT_PUBLIC), + .publicArea = { + .type = TPM2_ALG_KEYEDHASH, + .nameAlg = TPM2_ALG_SHA256, + .parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL, + .unique.keyedHash.size = TPM2_SHA256_DIGEST_SIZE, + }, + }; + TPM2B_SENSITIVE_CREATE sensitive = + { + .size = sizeof(TPMS_SENSITIVE_CREATE), + .sensitive.data.size = 1, + .sensitive.data.buffer[0] = 1, + .sensitive.userAuth.size = 4, + .sensitive.userAuth.buffer = { 1, 2, 3, 0 }, + }; + + r = Esys_Create(esys_context, primaryHandle, ESYS_TR_PASSWORD, ESYS_TR_NONE, + ESYS_TR_NONE, &sensitive, &template, NULL, &(TPML_PCR_SELECTION) {}, + &outPrivate3 , &outPublic3, NULL, NULL, NULL); + goto_if_error(r, "Error Esys_Create", error); + + r = Esys_Load(esys_context, primaryHandle, ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, + outPrivate3, outPublic3, &bind_key); + goto_if_error(r, "Error Esys_Load", error); + + TPM2B_AUTH bind_key_auth = + { + .size = 4, + .buffer = { 1, 2, 3, 0, }, + }; + + r = Esys_TR_SetAuth(esys_context, bind_key, &bind_key_auth); + goto_if_error(r, "Error Esys_TR_SetAuth", error); + + r = Esys_StartAuthSession(esys_context, primaryHandle, bind_key, ESYS_TR_NONE, + ESYS_TR_NONE, ESYS_TR_NONE, NULL, TPM2_SE_HMAC, + &SESSION_TEMPLATE_SYM_AES_128_CFB, + TPM2_ALG_SHA256, &enc_session); + goto_if_error(r, "Error Esys_StartAuthSession", error); + + r = Esys_TRSess_SetAttributes(esys_context, enc_session, sessionAttributes, 0xff); + goto_if_error(r, "Error Esys_TRSess_SetAttributes", error); + + r = Esys_StartAuthSession(esys_context, primaryHandle, ESYS_TR_NONE, + enc_session, ESYS_TR_NONE, + ESYS_TR_NONE, NULL, TPM2_SE_POLICY, + &SESSION_TEMPLATE_SYM_AES_128_CFB, + TPM2_ALG_SHA256, &session); + goto_if_error(r, "Error Esys_StartAuthSession", error); + + r = Esys_FlushContext(esys_context, enc_session); + goto_if_error(r, "Error Esys_FlushContext", error); + enc_session = ESYS_TR_NONE; + + r = Esys_FlushContext(esys_context, session); + goto_if_error(r, "Error Esys_FlushContext", error); + enc_session = ESYS_TR_NONE; + + r = Esys_FlushContext(esys_context, bind_key); + goto_if_error(r, "Error Esys_FlushContext", error); + bind_key = ESYS_TR_NONE; + + /* Test HierarchyChangeAuth */ + + TPM2B_AUTH authKey2 = { + .size = 6, + .buffer = { 6, 7, 8, 9, 10, 0 } + }; + + TPM2B_SENSITIVE_CREATE inSensitive2 = { + .size = 0, + .sensitive = { + .userAuth = { + .size = 0, + .buffer = {0} + }, + .data = { + .size = 0, + .buffer = {} + } + } + }; + + inSensitive2.sensitive.userAuth = authKey2; + + + TPM2B_AUTH newAuth = { + .size = 6, + .buffer = {6, 7, 8, 9, 10, 0 } + }; + + TPM2B_AUTH newAuth2 = { + .size = 6, + .buffer = {11, 12, 13, 14, 15, 0 } + }; + + TPM2B_PUBLIC template_parent = { + .size = 0, + .publicArea = { + .type = TPM2_ALG_RSA, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT | + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN), + + .authPolicy = { + .size = 0, + }, + .parameters.rsaDetail = { + .symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB + }, + .scheme = { + .scheme = + TPM2_ALG_NULL, + }, + .keyBits = 2048, + .exponent = 0 + }, + .unique.rsa = { + .size = 0, + .buffer = {} + , + } + } + }; + + Esys_Free(outPublic3); + outPublic3 = NULL; + Esys_Free(outPrivate3); + outPrivate3 = NULL; + + r = Esys_Create(esys_context, primaryHandle, ESYS_TR_PASSWORD, ESYS_TR_NONE, + ESYS_TR_NONE, &inSensitive2, &template_parent, NULL, &(TPML_PCR_SELECTION) {}, + &outPrivate3 , &outPublic3, NULL, NULL, NULL); + goto_if_error(r, "Error Esys_Create", error); + + r = Esys_HierarchyChangeAuth(esys_context, + ESYS_TR_RH_OWNER, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + &newAuth); + + r = Esys_StartAuthSession(esys_context, primaryHandle, ESYS_TR_RH_OWNER, ESYS_TR_NONE, + ESYS_TR_NONE, ESYS_TR_NONE, NULL, TPM2_SE_HMAC, + &SESSION_TEMPLATE_SYM_AES_128_CFB, + TPM2_ALG_SHA256, &session); + goto_if_error(r, "Error Esys_StartAuthSession", error); + + r = Esys_TRSess_SetAttributes(esys_context, session, sessionAttributes, 0xff); + goto_if_error(r, "Error Esys_TRSess_SetAttributes", error); + + r = Esys_Load(esys_context, primaryHandle, session, ESYS_TR_NONE, ESYS_TR_NONE, + outPrivate3, outPublic3, &key); + goto_if_error(r, "Error Esys_Load", error); + + r = Esys_HierarchyChangeAuth(esys_context, + ESYS_TR_RH_OWNER, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + &newAuth2); + goto_if_error(r, "Error: HierarchyChangeAuth", error); + + Esys_Free(outPublic3); + Esys_Free(outPrivate3); + + TPM2B_PUBLIC template_sign = { + .size = 0, + .publicArea = { + .type = TPM2_ALG_ECC, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT | + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN), + .authPolicy = { + .size = 0, + }, + .parameters.eccDetail = { + .symmetric ={ + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB}, + .scheme = { + .scheme = TPM2_ALG_NULL + }, + .curveID = TPM2_ECC_NIST_P256, + .kdf = { + .scheme = TPM2_ALG_NULL, + .details = {}} + }, + .unique.ecc = { + .x = {.size = 0,.buffer = {}}, + .y = {.size = 0,.buffer = {}}, + }, + }, + }; + + Esys_FlushContext(esys_context, primaryHandle); + primaryHandle = ESYS_TR_NONE; + + r = Esys_TR_SetAuth(esys_context, key, &authKey2); + goto_if_error(r, "Error Esys_", error); + + r = Esys_Create(esys_context, key, ESYS_TR_PASSWORD, session, + ESYS_TR_NONE, &inSensitive2, &template_sign, NULL, &(TPML_PCR_SELECTION) {}, + &outPrivate3 , &outPublic3, NULL, NULL, NULL); + goto_if_error(r, "Error Esys_Create", error); + + r = Esys_Load(esys_context, key, session, ESYS_TR_NONE, ESYS_TR_NONE, + outPrivate3, outPublic3, &key_sign); + goto_if_error(r, "Error Esys_Load", error); + + /* Reset auth value for storage hierarchy */ + r = Esys_HierarchyChangeAuth(esys_context, + ESYS_TR_RH_OWNER, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + NULL); + goto_if_error(r, "Error: HierarchyChangeAuth", error); + + /* Test NV_ChangeAuth */ + + TPM2B_NV_PUBLIC *nvPublic = NULL; + TPM2B_NAME *nvName = NULL; + TPM2B_MAX_NV_BUFFER *nv_test_data2 = NULL; + TPM2B_DIGEST *policyDigestTrial = NULL; + TPMT_SYM_DEF symmetricTrial = {.algorithm = TPM2_ALG_AES, + .keyBits = {.aes = 128}, + .mode = {.aes = TPM2_ALG_CFB} + }; + TPM2B_NONCE nonceCallerTrial = { + .size = 20, + .buffer = {11, 12, 13, 14, 15, 16, 17, 18, 19, 11, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30} + }; + + r = Esys_StartAuthSession(esys_context, ESYS_TR_NONE, ESYS_TR_NONE, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + &nonceCallerTrial, + TPM2_SE_TRIAL, &symmetricTrial, TPM2_ALG_SHA256, + &sessionTrial); + goto_if_error(r, "Error: During initialization of policy trial session", error); + + r = Esys_PolicyAuthValue(esys_context, + sessionTrial, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE + ); + goto_if_error(r, "Error: PolicyAuthValue", error); + + r = Esys_PolicyCommandCode(esys_context, + sessionTrial, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + TPM2_CC_NV_ChangeAuth + ); + goto_if_error(r, "Error: PolicyCommandCode", error); + + r = Esys_PolicyGetDigest(esys_context, + sessionTrial, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + &policyDigestTrial + ); + goto_if_error(r, "Error: PolicyGetDigest", error); + + r = Esys_FlushContext(esys_context, sessionTrial); + goto_if_error(r, "Flushing context", error); + sessionTrial = ESYS_TR_NONE; + + TPM2B_AUTH auth = {.size = 20, + .buffer={10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 0}}; + + TPM2B_AUTH new_auth = {.size = 20, + .buffer={30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 0}}; + + TPM2B_NV_PUBLIC publicInfo = { + .size = 0, + .nvPublic = { + .nvIndex =TPM2_NV_INDEX_FIRST, + .nameAlg = TPM2_ALG_SHA256, + .attributes = ( + TPMA_NV_OWNERWRITE | + TPMA_NV_AUTHWRITE | + TPMA_NV_WRITE_STCLEAR | + TPMA_NV_READ_STCLEAR | + TPMA_NV_AUTHREAD | + TPMA_NV_OWNERREAD + ), + .authPolicy = *policyDigestTrial, + .dataSize = 32, + } + }; + + Esys_Free(policyDigestTrial); + policyDigestTrial = NULL; + + r = Esys_NV_DefineSpace(esys_context, + ESYS_TR_RH_OWNER, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + &auth, + &publicInfo, + &nvHandle); + + goto_if_error(r, "Error esys define nv space", error); + + UINT16 offset = 0; + TPM2B_MAX_NV_BUFFER nv_test_data = + { .size = 20, + .buffer= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0}}; + + r = Esys_NV_Write(esys_context, + nvHandle, + nvHandle, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + &nv_test_data, + offset); + + goto_if_error(r, "Error esys nv write", error); + + r = Esys_NV_Read(esys_context, + nvHandle, + nvHandle, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + 20, + 0, + &nv_test_data2); + + goto_if_error(r, "Error esys nv read", error); + + Esys_Free(nvPublic); + Esys_Free(nvName); + Esys_Free(nv_test_data2); + nv_test_data2 = NULL; + + TPMT_SYM_DEF policySymmetric = + {.algorithm = TPM2_ALG_AES, + .keyBits = {.aes = 128}, + .mode = {.aes = TPM2_ALG_CFB} + }; + + TPM2B_NONCE policyNonceCaller = { + .size = 20, + .buffer = {11, 12, 13, 14, 15, 16, 17, 18, 19, 11, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30} + }; + + r = Esys_StartAuthSession(esys_context, ESYS_TR_NONE, ESYS_TR_NONE, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + &policyNonceCaller, + TPM2_SE_POLICY, &policySymmetric, TPM2_ALG_SHA256, + &policySession); + goto_if_error(r, "Error: During initialization of policy trial session", error); + + r = Esys_PolicyAuthValue(esys_context, + policySession, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE + ); + goto_if_error(r, "Error: PolicyAuthValue", error); + + r = Esys_PolicyCommandCode(esys_context, + policySession, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + TPM2_CC_NV_ChangeAuth + ); + goto_if_error(r, "Error: PolicyCommandCode", error); + + r = Esys_NV_ChangeAuth(esys_context, nvHandle, policySession, + ESYS_TR_NONE, ESYS_TR_NONE, &new_auth); + goto_if_error(r, "Error Esys_NV_ChangeAuth", error); + + r = Esys_NV_Read(esys_context, + nvHandle, + nvHandle, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + 20, + 0, + &nv_test_data2); + + goto_if_error(r, "Error esys nv read", error); + + Esys_Free(nv_test_data2); + nv_test_data2 = NULL; + + r = Esys_NV_UndefineSpace(esys_context, + ESYS_TR_RH_OWNER, + nvHandle, + session, + ESYS_TR_NONE, + ESYS_TR_NONE); + goto_if_error(r, "Error: NV_UndefineSpace", error); + + nvHandle = ESYS_TR_NONE; + + error: + + if (session != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, policySession) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup session failed."); + } + } + + if (session != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, session) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup session failed."); + } + } + + if (enc_session != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, enc_session) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup session failed."); + } + } + + if (primaryHandle != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, primaryHandle) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup primaryHandle failed."); + } + } + + if (bind_key != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, bind_key) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup primaryHandle failed."); + } + } + + if (key != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, key) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup key."); + } + } + + if (key_sign != ESYS_TR_NONE) { + if (Esys_FlushContext(esys_context, key_sign) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup key2 failed."); + } + } + + if (nvHandle != ESYS_TR_NONE) { + if (Esys_NV_UndefineSpace(esys_context, + ESYS_TR_RH_OWNER, + nvHandle, + session, + ESYS_TR_NONE, + ESYS_TR_NONE) != TSS2_RC_SUCCESS) { + LOG_ERROR("Cleanup nvHandle failed."); + } + } + + Esys_Free(outPublic); + Esys_Free(creationData); + Esys_Free(creationHash); + Esys_Free(creationTicket); + Esys_Free(outPublicEcc); + Esys_Free(creationDataEcc); + Esys_Free(creationHashEcc); + Esys_Free(creationTicketEcc); + Esys_Free(outPublic2); + Esys_Free(outPrivate2); + Esys_Free(outPublic3); + Esys_Free(outPrivate3); + Esys_Free(creationData2); + Esys_Free(creationHash2); + Esys_Free(creationTicket2); + + if (r) + return EXIT_FAILURE; + else + return EXIT_SUCCESS; +} + +int +test_invoke_esys(ESYS_CONTEXT * esys_context) { + return test_esys_trailing_zeros_in_auth(esys_context); +} diff --git a/test/integration/esys-crypto.int.c b/test/integration/esys-crypto.int.c index 1618e9c..7969f54 100644 --- a/test/integration/esys-crypto.int.c +++ b/test/integration/esys-crypto.int.c @@ -61,6 +61,8 @@ test_invoke_esys(ESYS_CONTEXT *esys_context) CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_decrypt); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_encrypt); + CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_decrypt); + CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_encrypt); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_ecdh_point); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_random2b); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, rsa_pk_encrypt); @@ -68,6 +70,8 @@ test_invoke_esys(ESYS_CONTEXT *esys_context) ESYS_CRYPTO_CALLBACKS callbacks = { .aes_decrypt = TEST_FN_PTR, .aes_encrypt = TEST_FN_PTR, + .sm4_decrypt = TEST_FN_PTR, + .sm4_encrypt = TEST_FN_PTR, .get_ecdh_point = TEST_FN_PTR, .get_random2b = TEST_FN_PTR, .rsa_pk_encrypt = TEST_FN_PTR, @@ -123,6 +127,8 @@ test_invoke_esys(ESYS_CONTEXT *esys_context) CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_decrypt); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, aes_encrypt); + CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_decrypt); + CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, sm4_encrypt); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_ecdh_point); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, get_random2b); CHECK_BACKEND_FN_NOT_TEST(esys_context->crypto_backend, rsa_pk_encrypt); diff --git a/test/integration/esys-pcr-auth-value.int.c b/test/integration/esys-pcr-auth-value.int.c index f666674..ba04098 100644 --- a/test/integration/esys-pcr-auth-value.int.c +++ b/test/integration/esys-pcr-auth-value.int.c @@ -39,7 +39,7 @@ test_esys_pcr_auth_value(ESYS_CONTEXT * esys_context) int failure_return = EXIT_FAILURE; /* - * PCR register 20 belongs to the policy group and the auth value group. + * PCR register 21 belongs to the policy group and the auth value group. * PCRs of these groups can be used for SetAuthValue and SetAuthPolicy. */ ESYS_TR pcrHandle_handle = 20; @@ -60,7 +60,8 @@ test_esys_pcr_auth_value(ESYS_CONTEXT * esys_context) ); - if ((r == TPM2_RC_COMMAND_CODE) || + if ((r == TPM2_RC_VALUE) || + (r == TPM2_RC_COMMAND_CODE) || (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_RC_LAYER)) || (r == (TPM2_RC_COMMAND_CODE | TSS2_RESMGR_TPM_RC_LAYER))) { LOG_WARNING("Command TPM2_PCR_SetAuthValue not supported by TPM."); diff --git a/test/integration/esys-pcr-basic.int.c b/test/integration/esys-pcr-basic.int.c index 0a5bc02..974a70b 100644 --- a/test/integration/esys-pcr-basic.int.c +++ b/test/integration/esys-pcr-basic.int.c @@ -142,6 +142,7 @@ test_esys_pcr_basic(ESYS_CONTEXT * esys_context) /* Platform authorization not possible test will be skipped */ LOG_WARNING("Platform authorization not possible."); failure_return = EXIT_SKIP; + goto error; } goto_if_error(r, "Error: PCR_Allocate", error); diff --git a/test/integration/esys-pp-commands.int.c b/test/integration/esys-pp-commands.int.c index 51fd365..4fdd0ee 100644 --- a/test/integration/esys-pp-commands.int.c +++ b/test/integration/esys-pp-commands.int.c @@ -58,8 +58,9 @@ test_esys_pp_commands(ESYS_CONTEXT * esys_context) } if (r == (TPM2_RC_WARN | TPM2_RC_PP)) { - LOG_INFO("Command TPM2_PP_Commands requires physical presence."); - return EXIT_SUCCESS; + LOG_WARNING("Command TPM2_PP_Commands requires physical presence."); + failure_return = EXIT_SKIP; + goto error; } if (number_rc(r) == TPM2_RC_BAD_AUTH) { diff --git a/test/integration/esys-tr-fromTpmPublic-key.int.c b/test/integration/esys-tr-fromTpmPublic-key.int.c index 429f20e..c6a14db 100644 --- a/test/integration/esys-tr-fromTpmPublic-key.int.c +++ b/test/integration/esys-tr-fromTpmPublic-key.int.c @@ -105,51 +105,80 @@ test_esys_tr_fromTpmPublic_key(ESYS_CONTEXT * ectx) .count = 0, }; - r = Esys_CreatePrimary(ectx, ESYS_TR_RH_OWNER, - ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, - &inSensitivePrimary, &inPublic, &outsideInfo, - &creationPCR, - &primaryHandle, NULL, NULL, NULL, NULL); - goto_if_error(r, "Create primary", error); - - r = Esys_ReadPublic(ectx, primaryHandle, - ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, - NULL, &name1, NULL); - goto_if_error(r, "Read Public", error); - - r = Esys_EvictControl(ectx, ESYS_TR_RH_OWNER, primaryHandle, - ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, - TPM2_PERSISTENT_FIRST, &keyHandle); - goto_if_error(r, "EvictControl make persistent", error_name1); - - r = Esys_FlushContext(ectx, primaryHandle); - goto_if_error(r, "Flushing primary", error_name1); - - r = Esys_TR_Close(ectx, &keyHandle); - goto_if_error(r, "TR close on nv object", error_name1); - - r = Esys_TR_FromTPMPublic(ectx, TPM2_PERSISTENT_FIRST, - ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, - &keyHandle); - goto_if_error(r, "TR from TPM public", error_name1); - - r = Esys_TR_GetName(ectx, keyHandle, &name2); - goto_if_error(r, "TR get name", error_name1); - - r = Esys_EvictControl(ectx, ESYS_TR_RH_OWNER, keyHandle, - ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, - TPM2_PERSISTENT_FIRST, &keyHandle); - goto_if_error(r, "EvictControl delete", error_name2); - - if (name1->size != name2->size || - memcmp(&name1->name[0], &name2->name[0], name1->size) != 0) - { - LOG_ERROR("Names mismatch between NV_GetPublic and TR_GetName"); - goto error_name2; - } + /* + * Do this twice to test that Esys_TR_FromTPMPublic doesn't error + * due to the handle not being closed by Esys_EvictControl + */ + for (int i = 0; i < 2; i++) { + /* + * Change public data to verify that handle is closed on + * Esys_EvictControl delete + */ + if (i == 1) { + inPublic.publicArea.unique.rsa.size = 2048 / 8; + inPublic.publicArea.unique.rsa.buffer[0] = 1; + } - free(name1); - free(name2); + r = Esys_CreatePrimary(ectx, ESYS_TR_RH_OWNER, + ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, + &inSensitivePrimary, &inPublic, &outsideInfo, + &creationPCR, + &primaryHandle, NULL, NULL, NULL, NULL); + goto_if_error(r, "Create primary", error); + + r = Esys_ReadPublic(ectx, primaryHandle, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + NULL, &name1, NULL); + goto_if_error(r, "Read Public", error); + + r = Esys_EvictControl(ectx, ESYS_TR_RH_OWNER, primaryHandle, + ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, + TPM2_PERSISTENT_FIRST, &keyHandle); + goto_if_error(r, "EvictControl make persistent", error_name1); + + LOG_ERROR("Key handle (1) 0x%x", keyHandle); + + r = Esys_FlushContext(ectx, primaryHandle); + goto_if_error(r, "Flushing primary", error_name1); + + r = Esys_TR_Close(ectx, &keyHandle); + goto_if_error(r, "TR close on object", error_name1); + + r = Esys_TR_FromTPMPublic(ectx, TPM2_PERSISTENT_FIRST, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + &keyHandle); + goto_if_error(r, "TR from TPM public", error_name1); + + r = Esys_TR_FromTPMPublic(ectx, TPM2_PERSISTENT_FIRST, + ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + &keyHandle); + goto_if_error(r, "TR from TPM public", error_name1); + + r = Esys_TR_Close(ectx, &keyHandle); + goto_if_error(r, "TR close on object", error_name1) + + LOG_ERROR("Key handle (2) 0x%x", keyHandle); + + r = Esys_TR_GetName(ectx, keyHandle, &name2); + goto_if_error(r, "TR get name", error_name1); + + r = Esys_EvictControl(ectx, ESYS_TR_RH_OWNER, keyHandle, + ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE, + TPM2_PERSISTENT_FIRST, &keyHandle); + goto_if_error(r, "EvictControl delete", error_name2); + + LOG_ERROR("Key handle (after delete) 0x%x", keyHandle); + + if (name1->size != name2->size || + memcmp(&name1->name[0], &name2->name[0], name1->size) != 0) + { + LOG_ERROR("Names mismatch between NV_GetPublic and TR_GetName"); + goto error_name2; + } + + free(name1); + free(name2); + } return EXIT_SUCCESS; diff --git a/test/integration/fapi-data-crypt.int.c b/test/integration/fapi-data-crypt.int.c index 51ccbb7..07437b6 100644 --- a/test/integration/fapi-data-crypt.int.c +++ b/test/integration/fapi-data-crypt.int.c @@ -96,9 +96,11 @@ signatureCallback( UNUSED(publicKey); UNUSED(publicKeyHint); uint8_t *aux_signature = NULL; + size_t profile_len = strlen(FAPI_PROFILE); - if (strcmp(objectPath, "P_RSA/HS/SRK/myRsaCryptKey") != 0) { - return_error(TSS2_FAPI_RC_BAD_VALUE, "Unexpected path"); + if (strcmp(objectPath + profile_len, "/HS/SRK/myRsaCryptKey") || + strncmp(objectPath, "P_RSA", 5)) + return_error(TSS2_FAPI_RC_BAD_VALUE, "Unexpected path") { } if (userData != userDataTest) { @@ -207,6 +209,7 @@ test_fapi_data_crypt(FAPI_CONTEXT *context) uint8_t *cipherText = NULL; size_t cipherTextSize; + char *export_data = NULL; r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); @@ -277,6 +280,42 @@ test_fapi_data_crypt(FAPI_CONTEXT *context) goto error; } + Fapi_Free(cipherText); + Fapi_Free(plainText2); + SAFE_FREE(global_signature); + + /* + * Run test with openssl encryption with the public RSA key. + */ + r = Fapi_ExportKey(context, "HS/SRK/myRsaCryptKey", NULL, &export_data); + goto_if_error(r, "Export.", error); + + r = Fapi_Import(context, "/ext/myRsaCryptKey", export_data); + goto_if_error(r, "Error Fapi_Import", error); + + r = Fapi_Encrypt(context, "/ext/myRsaCryptKey", &plainText[0], + SIZE, &cipherText, &cipherTextSize); + + goto_if_error(r, "Error Fapi_Encrypt", error); + + plainText2 = NULL; + plainText2_size = 0; + + r = Fapi_Decrypt(context, "HS/SRK/myRsaCryptKey", cipherText, cipherTextSize, + &plainText2, &plainText2_size); + + if (r == TSS2_FAPI_RC_NOT_IMPLEMENTED) { + goto skip; + } + goto_if_error(r, "Error Fapi_Encrypt", error); + + if (plainText2_size != SIZE || + memcmp(plainText, plainText2, plainText2_size) != 0) { + LOG_ERROR("Error: decrypted text not equal to origin"); + goto error; + } + + SAFE_FREE(export_data); Fapi_Free(cipherText); Fapi_Free(plainText2); Fapi_Free(json_policy); @@ -286,6 +325,7 @@ test_fapi_data_crypt(FAPI_CONTEXT *context) return EXIT_SUCCESS; error: + SAFE_FREE(export_data); Fapi_Delete(context, "/"); Fapi_Free(cipherText); Fapi_Free(json_policy); @@ -295,6 +335,7 @@ test_fapi_data_crypt(FAPI_CONTEXT *context) return EXIT_FAILURE; skip: + SAFE_FREE(export_data); Fapi_Delete(context, "/"); Fapi_Free(json_policy); Fapi_Delete(context, "/"); diff --git a/test/integration/fapi-get-esys-blobs.int.c b/test/integration/fapi-get-esys-blobs.int.c index b1eb4dd..ef7f12c 100644 --- a/test/integration/fapi-get-esys-blobs.int.c +++ b/test/integration/fapi-get-esys-blobs.int.c @@ -72,6 +72,7 @@ auth_callback( * @param[in,out] context The FAPI_CONTEXT. * @retval EXIT_FAILURE * @retval EXIT_SUCCESS + * @retval EXIT_SKIP */ int test_fapi_get_esys_blobs(FAPI_CONTEXT *context) @@ -90,6 +91,11 @@ test_fapi_get_esys_blobs(FAPI_CONTEXT *context) ESYS_TR esys_handle; uint8_t type; + if (strncmp(FAPI_PROFILE,"P_ECC", 5)) { + LOG_WARNING("Profile %s is no ECC profile.", FAPI_PROFILE); + return EXIT_SKIP; + } + /* We need to reset the passwords again, in order to not brick physical TPMs */ r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); @@ -178,7 +184,12 @@ test_fapi_get_esys_blobs(FAPI_CONTEXT *context) &inScheme, &hash_validation, &signature); - goto_if_error(r, "Error: Sign", error); + + if (r != TSS2_RC_SUCCESS) { + LOG_ERROR("%s " TPM2_ERROR_FORMAT, "Error: Sign", TPM2_ERROR_TEXT(r)); + Esys_FlushContext(context->esys, esys_handle); + goto error; + } SAFE_FREE(signature); diff --git a/test/integration/fapi-import-ossl-key.int.c b/test/integration/fapi-import-ossl-key.int.c new file mode 100644 index 0000000..e52f8f3 --- /dev/null +++ b/test/integration/fapi-import-ossl-key.int.c @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/******************************************************************************* + * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG + * All rights reserved. + *******************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "tss2_fapi.h" + +#include "test-fapi.h" +#define LOGMODULE test +#include "util/log.h" +#include "util/aux_util.h" + +#define SIZE 2000 + +/** Test the FAPI functions for key duplication. + * + * Tested FAPI commands: + * - Fapi_Provision() + * - Fapi_Import() + * - Fapi_Delete() + * + * @param[in,out] context The FAPI_CONTEXT. + * @retval EXIT_FAILURE + * @retval EXIT_SUCCESS + */ + +const char *priv_rsa_pem = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEAwBgOktII9d+oYJQLUhQYPk8Ad6dW54ak8XWLdMtNx7161kgQ\n" + "sohndq3WUZ10mR/lf/GVPYNHj5+vR28BQ3In0GZgYGNSiE+6drSq6h+VyaYzDRQG\n" + "b2CUKqNSMhl5FAqhCs6kM8GeXI6FZhnur3gNv4S+hcra9is9mwzucLnt1Maqu5/D\n" + "7HgXJrWmn5JTg8OlZMiYnqD91LD+nx9ZYWxCQzwUBDVaEXQtndvF5neTALOXro1B\n" + "awMMqjlMug0IFA46MOo2mvOWaRWm4JgVS50lj+cye7nobQbw6gkF/kb1VbiEvi/L\n" + "/vbnQCtDlvjx9a97QKuphp2sGtOM/K8c9yuXMwIDAQABAoIBADPYSlamCXUS4Ebw\n" + "rf2BHunyOJYSvAnQ9UOWDgV/uYZnRXgAC0GkPwhw8p8keAu76B0X/seTXwUMfCoz\n" + "c4vYi5Zbizd4lxXjLthK+rYlwC+kg7LL7NCyqEq5ub170onuNHjOPNMbNrqUXLyp\n" + "0xnYtR0znphNn7tBAGeQneoexGngnPnImUh4+wwJReUaDO6Kozu4ETd/1TWa1xLY\n" + "VzMWWLuU+adUmjY+AvEOHXva7P2c4B1d+FS16JHSxGN0i/cPyZBMx3DEAGP3JIN8\n" + "zpMmMlUmG3yuX3w0atWXkvA/lPYajIiRASdzBFri8dLt4euR/I88DUYAT0gelvl7\n" + "IoPnOUECgYEA5lqTe7NNnLJNFqWd96Xu2ga44711oIOuTBLgiuHjTnDwUicBRjMY\n" + "rzPx7Ya3kJds9SLatyswWAvlr3oBidRg/HH/IMejinySGLgbaJOB2srAXMuHD4/k\n" + "pMrHC7CSGglgvXkNFH+4FIny5n1CHcsRA8cHFfUGbW5FYRaNnuJyvgcCgYEA1XsE\n" + "09gbBy0jaTZHdn0Km82+7uTb+9zgtG8TeTskR7zLC3Daq2O896dhPYqVnrZ6MSj1\n" + "9cZGTEzhtT5LaipvDkXU27yvUhcDfZAYYBIAlQ40mpkDxzorHGPEdZ3opxzg1E8D\n" + "UHEs0kdsoVQS7FgugEHTZ2zOZc2VtenOL3of0nUCgYEApnQbEI8PbUSWWeARVwur\n" + "nhavcbnNDtE4mLYnVZRHCb6omeSfkheIJcpWbnojmTMiw7yM6UEnLOhj77os9Gjo\n" + "MGM7pXc9YOwFMiGPhLDaa7yI5kUX8pHa+Y2h6XuNB41xP1kCr6Ze4VCRmiY3KYo8\n" + "YEtofmBRZbACKFcAvSgLG+8CgYEAublk4cjI+t1SSV5nnbX7XMEKs1t35w6qj09z\n" + "aa0CS0b8ft+X3jPPWsXL23aN5J5sgAhas4/j6M2aL8waYCq6o3gtT15ASPKsnriV\n" + "/D6tMwBA0577ooAAsZo6ePkARyLgltSG1Z0gmXB6GYDDVcsB6aNbAEew6PCKptDa\n" + "CIP+22ECgYBWe2OzDxPVj04WDCcyaQIURFtjYjL+Z7FQD9iQX9ux4a+qBdNkEdEs\n" + "CRawbM1vO4VgjLzqg5QSl+OM8CAr7jiSAxqUCCe/25VrxZi+QqDMZ2a0wzz00dSZ\n" + "N1DbUyfqzTzv0jCTEPNbtSjDc/SMuLPWB1G9wvz6LRZxOgeGgaQQGQ==\n" + "-----END RSA PRIVATE KEY-----\n"; + +const char *priv_ecc_pem = + "-----BEGIN EC PRIVATE KEY-----\n" + "MHcCAQEEIJ+3y/OoXGdVUvht0DxYtOhI69dNqe0KqyWFmIleIjMqoAoGCCqGSM49\n" + "AwEHoUQDQgAEKGzvYBs1yaZO5t0unKAtXSl/theSgmdGpkFKc5BAzXp+AeNgmuu1\n" + "wpkzNe7Pl4hneV/W4ddBvJMI5ux2ftaCBQ==\n" + "-----END EC PRIVATE KEY-----\n"; + +const char *pub_rsa_pem = + "-----BEGIN PUBLIC KEY-----\n" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwBgOktII9d+oYJQLUhQY\n" + "Pk8Ad6dW54ak8XWLdMtNx7161kgQsohndq3WUZ10mR/lf/GVPYNHj5+vR28BQ3In\n" + "0GZgYGNSiE+6drSq6h+VyaYzDRQGb2CUKqNSMhl5FAqhCs6kM8GeXI6FZhnur3gN\n" + "v4S+hcra9is9mwzucLnt1Maqu5/D7HgXJrWmn5JTg8OlZMiYnqD91LD+nx9ZYWxC\n" + "QzwUBDVaEXQtndvF5neTALOXro1BawMMqjlMug0IFA46MOo2mvOWaRWm4JgVS50l\n" + "j+cye7nobQbw6gkF/kb1VbiEvi/L/vbnQCtDlvjx9a97QKuphp2sGtOM/K8c9yuX\n" + "MwIDAQAB\n" + "-----END PUBLIC KEY-----\n"; + +const char *pub_ecc_pem = + "-----BEGIN PUBLIC KEY-----\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKGzvYBs1yaZO5t0unKAtXSl/theS\n" + "gmdGpkFKc5BAzXp+AeNgmuu1wpkzNe7Pl4hneV/W4ddBvJMI5ux2ftaCBQ==\n" + "-----END PUBLIC KEY-----\n"; + +int +test_fapi_import_ossl(FAPI_CONTEXT *context) +{ + TSS2_RC r; + const char *priv_pem; + char *json_string_pubkey = NULL; + json_object *jso = NULL; + json_object *jso_public = NULL; + char *pubkey_pem = NULL; + const char *pubkey_test = NULL; + + + if (strncmp(FAPI_PROFILE, "P_RSA", 5) == 0) { + priv_pem = priv_rsa_pem; + pubkey_test = pub_rsa_pem; + } else { + priv_pem = priv_ecc_pem; + pubkey_test =pub_ecc_pem; + } + + r = Fapi_Provision(context, NULL, NULL, NULL); + goto_if_error(r, "Error Fapi_Provision", error); + + r = Fapi_Import(context, "/SRK/my_osslkey", priv_pem); + goto_if_error(r, "Error Fapi_Import", error); + + r = Fapi_ExportKey(context, "/SRK/my_osslkey", NULL, &json_string_pubkey); + goto_if_error(r, "Error Fapi_CreateKey", error); + ASSERT(json_string_pubkey != NULL); + ASSERT(strlen(json_string_pubkey) > ASSERT_SIZE); + + jso = json_tokener_parse(json_string_pubkey); + LOG_INFO("\nExported: %s\n", json_string_pubkey); + + if (!jso || !json_object_object_get_ex(jso, "pem_ext_public", &jso_public)) { + LOG_ERROR("No public key eyported."); + goto error; + } + pubkey_pem = strdup(json_object_get_string(jso_public)); + if (!pubkey_pem) { + LOG_ERROR("Out of memory."); + goto error; + } + + if (strcmp(pubkey_pem, pubkey_test) != 0) { + LOG_ERROR("Pub keys not equal."); + LOG_ERROR("%s", pubkey_test); + LOG_ERROR("%s", pubkey_pem); + goto error; + } + + r = Fapi_Delete(context, "/"); + goto_if_error(r, "Error Fapi_Delete", error2); + + SAFE_FREE(json_string_pubkey); + json_object_put(jso); + SAFE_FREE(pubkey_pem); + return EXIT_SUCCESS; + +error: + Fapi_Delete(context, "/"); + error2: + if (jso) + json_object_put(jso); + SAFE_FREE(pubkey_pem); + SAFE_FREE(json_string_pubkey); + return EXIT_FAILURE; +} + +int +test_invoke_fapi(FAPI_CONTEXT *fapi_context) +{ + return test_fapi_import_ossl(fapi_context); +} diff --git a/test/integration/fapi-key-create-policies-sign.int.c b/test/integration/fapi-key-create-policies-sign.int.c index 040d435..a8d5054 100644 --- a/test/integration/fapi-key-create-policies-sign.int.c +++ b/test/integration/fapi-key-create-policies-sign.int.c @@ -165,7 +165,7 @@ test_fapi_key_create_policies_sign(FAPI_CONTEXT *context) if (number_rc(r) == TPM2_RC_PP) { LOG_WARNING("Test requires physical presence."); goto skip; - } else if (r == TPM2_RC_COMMAND_CODE) { + } else if (base_rc(r) == TPM2_RC_COMMAND_CODE) { LOG_WARNING("Command not supported, probably PolicyPhysicalPresence"); goto skip; } diff --git a/test/integration/fapi-key-create-policy-authorize-nv-sign.int.c b/test/integration/fapi-key-create-policy-authorize-nv-sign.int.c index d31e119..47a1316 100644 --- a/test/integration/fapi-key-create-policy-authorize-nv-sign.int.c +++ b/test/integration/fapi-key-create-policy-authorize-nv-sign.int.c @@ -141,7 +141,7 @@ test_fapi_key_create_policy_authorize_nv(FAPI_CONTEXT *context) return EXIT_SKIP; } - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { if (snprintf(&extended_name[0], 1023, "%s_sha384", POLICY_AUTHORIZE_NV) < 0) { LOG_ERROR("snprint failed"); return EXIT_FAILURE; @@ -158,7 +158,7 @@ test_fapi_key_create_policy_authorize_nv(FAPI_CONTEXT *context) if (strcmp(FAPI_PROFILE, "P_ECC") == 0) { policy_nv_auth_size = 34; - } else if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + } else if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { policy_nv_auth_size = 50; } else { LOG_ERROR("No appropriate policy file exists!"); diff --git a/test/integration/fapi-key-create-policy-authorize-pem-sign.int.c b/test/integration/fapi-key-create-policy-authorize-pem-sign.int.c index 13d8f81..b17bf8e 100644 --- a/test/integration/fapi-key-create-policy-authorize-pem-sign.int.c +++ b/test/integration/fapi-key-create-policy-authorize-pem-sign.int.c @@ -53,8 +53,8 @@ test_fapi_key_create_policy_authorize_pem_sign(FAPI_CONTEXT *context) { TSS2_RC r; char *policy_pcr = "/policy/pol_pcr"; - char *policy_file_pcr; - char *policy_file_authorize; + char *policy_file_pcr = NULL; + char *policy_file_authorize = NULL; char *policy_name_authorize = "/policy/pol_authorize"; // uint8_t policyRef[] = { 1, 2, 3, 4, 5 }; FILE *stream = NULL; @@ -69,9 +69,12 @@ test_fapi_key_create_policy_authorize_pem_sign(FAPI_CONTEXT *context) if (strcmp(FAPI_PROFILE, "P_ECC") == 0) { policy_file_authorize = TOP_SOURCEDIR "/test/data/fapi/policy/pol_authorize_ecc_pem.json"; policy_file_pcr = TOP_SOURCEDIR "/test/data/fapi/policy/pol_pcr16_0_ecc_authorized.json"; - } else if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + } else if (strcmp(FAPI_PROFILE, "P_ECC384" ) == 0) { policy_file_authorize = TOP_SOURCEDIR "/test/data/fapi/policy/pol_authorize_ecc_pem_sha384.json"; policy_file_pcr = TOP_SOURCEDIR "/test/data/fapi/policy/pol_pcr16_0_ecc_authorized_sha384.json"; + } else { + LOG_ERROR("Profule can't be used for test: %s", FAPI_PROFILE); + return EXIT_SKIP; } #else policy_file_pcr = TOP_SOURCEDIR "/test/data/fapi/policy/pol_pcr16_0_rsa_authorized.json"; diff --git a/test/integration/fapi-key-create-policy-pcr-sign.int.c b/test/integration/fapi-key-create-policy-pcr-sign.int.c index bfbbd2a..74eae02 100644 --- a/test/integration/fapi-key-create-policy-pcr-sign.int.c +++ b/test/integration/fapi-key-create-policy-pcr-sign.int.c @@ -104,7 +104,7 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) " \"description\":\"Description pol_16_0\"," \ " \"policyDigests\":[" \ " {" \ - " \"hashAlg\":\"SHA384\"," \ + " \"hashAlg\":\"sha384\"," \ " \"digest\":\"c1923346b6d44a154b58b57b4327ee70c29ac536f9209d94880de6834f370587846a2834e3e88af61efd8679fcccedd5\"" \ " }" \ " ]," \ @@ -113,14 +113,14 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) " \"type\":\"POLICYPCR\"," \ " \"policyDigests\":[" \ " {" \ - " \"hashAlg\":\"SHA384\"," \ + " \"hashAlg\":\"sha384\"," \ " \"digest\":\"c1923346b6d44a154b58b57b4327ee70c29ac536f9209d94880de6834f370587846a2834e3e88af61efd8679fcccedd5\"" \ " }" \ " ]," \ " \"pcrs\":[" \ " {" \ " \"pcr\":16," \ - " \"hashAlg\":\"SHA256\"," \ + " \"hashAlg\":\"sha256\"," \ " \"digest\":\"0000000000000000000000000000000000000000000000000000000000000000\"" \ " }" \ " ]" \ @@ -178,15 +178,15 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) " \"description\":\"Description pol_16_0\"," \ " \"policyDigests\":[" \ " { " \ - " \"hashAlg\":\"SHA384\"," \ + " \"hashAlg\":\"sha384\"," \ " \"digest\":\"c1923346b6d44a154b58b57b4327ee70c29ac536f9209d94880de6834f370587846a2834e3e88af61efd8679fcccedd5\"" \ " }," \ " {" \ - " \"hashAlg\":\"SHA256\"," \ + " \"hashAlg\":\"sha256\"," \ " \"digest\":\"bff2d58e9813f97cefc14f72ad8133bc7092d652b7c877959254af140c841f36\"" \ " }," \ " {" \ - " \"hashAlg\":\"SHA1\"," \ + " \"hashAlg\":\"sha1\"," \ " \"digest\":\"eab0d71ae6088009cbd0b50729fde69eb453649c\"" \ " }" \ " ]," \ @@ -195,22 +195,22 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) " \"type\":\"POLICYPCR\"," \ " \"policyDigests\":[" \ " { " \ - " \"hashAlg\":\"SHA384\"," \ + " \"hashAlg\":\"sha384\"," \ " \"digest\":\"c1923346b6d44a154b58b57b4327ee70c29ac536f9209d94880de6834f370587846a2834e3e88af61efd8679fcccedd5\"" \ " }," \ " {" \ - " \"hashAlg\":\"SHA256\"," \ + " \"hashAlg\":\"sha256\"," \ " \"digest\":\"bff2d58e9813f97cefc14f72ad8133bc7092d652b7c877959254af140c841f36\"" \ " }," \ " {" \ - " \"hashAlg\":\"SHA1\"," \ + " \"hashAlg\":\"sha1\"," \ " \"digest\":\"eab0d71ae6088009cbd0b50729fde69eb453649c\"" \ " }" \ " ]," \ " \"pcrs\":[" \ " {" \ " \"pcr\":16," \ - " \"hashAlg\":\"SHA256\"," \ + " \"hashAlg\":\"sha256\"," \ " \"digest\":\"0000000000000000000000000000000000000000000000000000000000000000\"" \ " }" \ " ]" \ @@ -281,7 +281,7 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) ASSERT(policy != NULL); LOG_INFO("\nTEST_JSON\nPolicy_sha256:\n%s\nEND_JSON", policy); - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { CHECK_JSON(policy, policy_sha384_check, error); } else { CHECK_JSON(policy, policy_sha256_check, error); @@ -296,7 +296,7 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) goto_if_error(r, "Error Fapi_ExportPolicy", error); ASSERT(policy != NULL); LOG_INFO("\nTEST_JSON\nPolicy export1:\n%s\nEND_JSON", policy); - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { CHECK_JSON(policy, policy_sha384_export_check, error) } else { CHECK_JSON(policy, policy_sha256_export_check, error) @@ -427,7 +427,7 @@ test_fapi_key_create_policy_pcr_sign(FAPI_CONTEXT *context) goto_if_error(r, "Error Fapi_ExportPolicy", error); ASSERT(policy != NULL); - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0){ CHECK_JSON(policy, policy_sha384_check, error); } else { CHECK_JSON(policy, policy_sha256_check, error); diff --git a/test/integration/fapi-key-create-policy-signed-keyedhash.int.c b/test/integration/fapi-key-create-policy-signed-keyedhash.int.c index 273d79d..f9f4131 100644 --- a/test/integration/fapi-key-create-policy-signed-keyedhash.int.c +++ b/test/integration/fapi-key-create-policy-signed-keyedhash.int.c @@ -196,8 +196,8 @@ int test_fapi_key_create_policy_signed(FAPI_CONTEXT *context) { TSS2_RC r; - char *policy_name = "/policy/pol_signed_keyedhash"; - char *policy_file = TOP_SOURCEDIR "/test/data/fapi/policy/pol_signed_keyedhash.json"; + char *policy_name; + char *policy_file; FILE *stream = NULL; char *json_policy = NULL; long policy_size; @@ -206,6 +206,14 @@ test_fapi_key_create_policy_signed(FAPI_CONTEXT *context) char *publicKey = NULL; char *certificate = NULL; + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { + policy_name = "/policy/pol_signed_keyedhash_sha384"; + policy_file = TOP_SOURCEDIR "/test/data/fapi/policy/pol_signed_keyedhash_sha384.json"; + } else { + policy_name = "/policy/pol_signed_keyedhash"; + policy_file = TOP_SOURCEDIR "/test/data/fapi/policy/pol_signed_keyedhash.json"; + } + r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); diff --git a/test/integration/fapi-key-create-sign.int.c b/test/integration/fapi-key-create-sign.int.c index db5bac0..78c0976 100644 --- a/test/integration/fapi-key-create-sign.int.c +++ b/test/integration/fapi-key-create-sign.int.c @@ -184,8 +184,12 @@ test_fapi_key_create_sign(FAPI_CONTEXT *context) jso = json_object_new_object(); goto_if_null2(jso, "Out of memory", r, TSS2_FAPI_RC_MEMORY, error); - json_object_object_add(jso, "public", publicblobHex_jso); - json_object_object_add(jso, "private", privateblobHex_jso); + if (json_object_object_add(jso, "public", publicblobHex_jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(jso, "private", privateblobHex_jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } const char * jso_string = json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY); diff --git a/test/integration/fapi-key-create2-sign.int.c b/test/integration/fapi-key-create2-sign.int.c index 85960e5..4a12e85 100644 --- a/test/integration/fapi-key-create2-sign.int.c +++ b/test/integration/fapi-key-create2-sign.int.c @@ -322,8 +322,12 @@ test_fapi_key_create_sign(FAPI_CONTEXT *context) jso = json_object_new_object(); goto_if_null2(jso, "Out of memory", r, TSS2_FAPI_RC_MEMORY, error); - json_object_object_add(jso, "public", publicblobHex_jso); - json_object_object_add(jso, "private", privateblobHex_jso); + if (json_object_object_add(jso, "public", publicblobHex_jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } + if (json_object_object_add(jso, "private", privateblobHex_jso)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } const char * jso_string = json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY); diff --git a/test/integration/fapi-nv-authorizenv-cphash.int.c b/test/integration/fapi-nv-authorizenv-cphash.int.c index 8d8d67a..8ecb660 100644 --- a/test/integration/fapi-nv-authorizenv-cphash.int.c +++ b/test/integration/fapi-nv-authorizenv-cphash.int.c @@ -96,7 +96,7 @@ test_fapi_nv_authorizenv_cphash(FAPI_CONTEXT *context) r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { policy2_name = "/policy/pol_cphash_sha384"; policy2_file = TOP_SOURCEDIR "/test/data/fapi/policy/pol_cphash_sha384.json"; policy_nv_auth_size = 50; @@ -148,7 +148,6 @@ test_fapi_nv_authorizenv_cphash(FAPI_CONTEXT *context) r = Fapi_WriteAuthorizeNv(context, "/nv/Owner/myNV", policy2_name); goto_if_error(r, "Error Fapi_WriteAuthorizeNv", error); - LOG_ERROR("XXXX Write"); r = Fapi_NvWrite(context, "/nv/Owner/myNV2", &data[0], sizeof(data)); goto_if_error(r, "Error Fapi_NvWrite", error); diff --git a/test/integration/fapi-nv-extend.int.c b/test/integration/fapi-nv-extend.int.c index dfe8646..04488d2 100644 --- a/test/integration/fapi-nv-extend.int.c +++ b/test/integration/fapi-nv-extend.int.c @@ -91,7 +91,7 @@ test_fapi_nv_extend(FAPI_CONTEXT *context) LOG_INFO("\nTEST_JSON\nLog:\n%s\nEND_JSON", log); char *fields_log1[] = { "0", "digests", "0", "digest" }; - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { CHECK_JSON_FIELDS(log, fields_log1, "c8ffec7d7d70c61b16adaab88925a1759b94cf6b50669b04aef1a8427fabb131eafbf9a21e3b8bddd9c5d5e7", error); @@ -120,7 +120,7 @@ test_fapi_nv_extend(FAPI_CONTEXT *context) LOG_INFO("\nTEST_JSON\nLog:\n%s\nEND_JSON", log); char *fields_log2[] = { "1", "digests", "0", "digest" }; - if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { + if (strcmp(FAPI_PROFILE, "P_ECC384") == 0 || strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { CHECK_JSON_FIELDS(log, fields_log2, "c8ffec7d7d70c61b16adaab88925a1759b94cf6b50669b04aef1a8427fabb131eafbf9a21e3b8bddd9c5d5e7", error); diff --git a/test/integration/fapi-provisioning-cert-error.int.c b/test/integration/fapi-provisioning-cert-error.int.c new file mode 100644 index 0000000..43c2c6b --- /dev/null +++ b/test/integration/fapi-provisioning-cert-error.int.c @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/******************************************************************************* + * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG + * All rights reserved. + *******************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "tss2_fapi.h" +#include "tss2_esys.h" + +#include "test-fapi.h" +#include "fapi_util.h" +#include "fapi_int.h" +#include "tss2_esys.h" + +#include "esys_iutil.h" +#define LOGMODULE test +#include "util/log.h" +#include "util/aux_util.h" +#include "tss2_mu.h" +#include "fapi_int.h" + + +/** Test the FAPI cleanup in an error case. + * + * Tested FAPI commands: + * - Fapi_Provision() + * + * @param[in,out] context The FAPI_CONTEXT. + * @retval EXIT_FAILURE + * @retval EXIT_SUCCESS + */ +int +test_fapi_test_provisioning_cert_error(FAPI_CONTEXT *context) +{ + TSS2_RC r; + +#if !defined(SELF_SIGNED_CERTIFICATE) || defined(FAPI_TEST_EK_CERT_LESS) + return EXIT_SKIP; +#endif + + setenv("FAPI_TEST_ROOT_CERT", "self", 1); + setenv("FAPI_TEST_INT_CERT", "./ca/root-ca/root-ca.cert.pem", 1); + + r = Fapi_Provision(context, NULL, NULL, NULL); + + if (r == TSS2_FAPI_RC_GENERAL_FAILURE) + return EXIT_SUCCESS; + + LOG_ERROR("Test with self signed certificate did not fail."); + return EXIT_FAILURE; + +} + +int +test_invoke_fapi(FAPI_CONTEXT *fapi_context) +{ + return test_fapi_test_provisioning_cert_error(fapi_context); +} diff --git a/test/integration/fapi-provisioning-with-template.int.c b/test/integration/fapi-provisioning-with-template.int.c index 27f8e57..74184cd 100644 --- a/test/integration/fapi-provisioning-with-template.int.c +++ b/test/integration/fapi-provisioning-with-template.int.c @@ -4,6 +4,8 @@ #endif #include +#include +#include #include "tss2_esys.h" #include "tss2_fapi.h" @@ -31,9 +33,45 @@ * @retval EXIT_SKIP * */ +static bool +fapi_ek_certless() +{ + FILE *stream = NULL; + long config_size; + char *config = NULL; + char *fapi_config_file = getenv("TSS2_FAPICONF"); + + stream = fopen(fapi_config_file, "r"); + if (!stream) { + LOG_ERROR("File %s does not exist", fapi_config_file); + return NULL; + } + fseek(stream, 0L, SEEK_END); + config_size = ftell(stream); + fclose(stream); + config = malloc(config_size + 1); + stream = fopen(fapi_config_file, "r"); + ssize_t ret = read(fileno(stream), config, config_size); + if (ret != config_size) { + LOG_ERROR("IO error %s.", fapi_config_file); + return NULL; + } + config[config_size] = '\0'; + if (strstr(config, "\"ek_cert_less\": \"yes\"") == NULL) { + SAFE_FREE(config); + return false; + } else { + SAFE_FREE(config); + return true; + } +} + int test_fapi_provision_template(FAPI_CONTEXT *context) { +#ifndef SELF_GENERATED_CERTIFICATE + return EXIT_SKIP; +#endif size_t offset = 0; UINT16 offset_nv = 0; TSS2_TCTI_CONTEXT *tcti; @@ -148,6 +186,9 @@ test_fapi_provision_template(FAPI_CONTEXT *context) TPM2B_AUTH auth = { .size = 0, .buffer = {} }; TPM2B_MAX_NV_BUFFER nv_data; + if (fapi_ek_certless()) + return EXIT_SKIP; + if (strcmp(FAPI_PROFILE, "P_ECC") == 0) { nv_template_idx = ecc_nv_template_idx; nv_nonce_idx = ecc_nv_nonce_idx; @@ -166,7 +207,7 @@ test_fapi_provision_template(FAPI_CONTEXT *context) r = Esys_Initialize(&esys_ctx, tcti, NULL); goto_if_error(r, "Error Esys_Initialize", error); - /* + /* * Store template (marshaled TPMT_PUBLIC) in NV ram. */ r = Tss2_MU_TPMT_PUBLIC_Marshal(&in_public, &nv_data.buffer[0], diff --git a/test/integration/fapi-quote-destructive-eventlog.int.c b/test/integration/fapi-quote-destructive-eventlog.int.c index 2faa811..060e21c 100644 --- a/test/integration/fapi-quote-destructive-eventlog.int.c +++ b/test/integration/fapi-quote-destructive-eventlog.int.c @@ -24,8 +24,6 @@ #define EVENT_SIZE 10 - - typedef struct { uint32_t pcr; TPML_DIGEST_VALUES digest; @@ -1003,11 +1001,23 @@ test_fapi_quote_destructive(FAPI_CONTEXT *context) size_t i; json_object *jso_log = NULL; json_object *jso_log2 = NULL; + bool sha1_bank_exists; uint8_t data[EVENT_SIZE] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; size_t signatureSize = 0; uint32_t pcrList[13] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 14, 16 }; + #ifdef WORDS_BIGENDIAN + return EXIT_SKIP; + #endif + + r = pcr_bank_sha1_exists(context, &sha1_bank_exists); + goto_if_error(r, "Test sha1 bank", error); + + if (!sha1_bank_exists) { + return EXIT_SKIP; + } + r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); @@ -1081,7 +1091,9 @@ test_fapi_quote_destructive(FAPI_CONTEXT *context) jso_duplicate = json_object_get(jso_event); goto_if_null(jso_duplicate, "Out of memory.", TSS2_FAPI_RC_MEMORY, error); - json_object_array_add(jso_log2, jso_duplicate); + if (json_object_array_add(jso_log2, jso_duplicate)) { + return_error(TSS2_FAPI_RC_GENERAL_FAILURE, "Could not add json object."); + } } pcrEventLog2 = strdup(json_object_to_json_string_ext(jso_log2, JSON_C_TO_STRING_PRETTY)); diff --git a/test/integration/fapi-quote-destructive.int.c b/test/integration/fapi-quote-destructive.int.c index 7b1c109..07077b1 100644 --- a/test/integration/fapi-quote-destructive.int.c +++ b/test/integration/fapi-quote-destructive.int.c @@ -23,6 +23,17 @@ #define EVENT_SIZE 10 +static bool big_endian(void) { + + uint32_t test_word; + uint8_t *test_byte; + + test_word = 0xFF000000; + test_byte = (uint8_t *) (&test_word); + + return test_byte[0] == 0xFF; +} + /** Test the FAPI functions for quote commands. * * Tested FAPI commands: @@ -56,6 +67,10 @@ test_fapi_quote_destructive(FAPI_CONTEXT *context) size_t signatureSize = 0; uint32_t pcrList[2] = { 11, 16 }; + if (big_endian()) { + return EXIT_SKIP; + } + r = Fapi_Provision(context, NULL, NULL, NULL); goto_if_error(r, "Error Fapi_Provision", error); diff --git a/test/integration/fapi-second-provisioning.int.c b/test/integration/fapi-second-provisioning.int.c index 8651a26..fbc7d2b 100644 --- a/test/integration/fapi-second-provisioning.int.c +++ b/test/integration/fapi-second-provisioning.int.c @@ -63,6 +63,11 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) { TSS2_RC r; + if (strncmp(FAPI_PROFILE, "P_RSA", 5) == 0) { + LOG_WARNING("Default ECC profile needed for this test %s is used", FAPI_PROFILE); + return EXIT_SKIP; + } + /* We need to reset the passwords again, in order to not brick physical TPMs */ r = Fapi_Provision(context, PASSWORD, PASSWORD, NULL); goto_if_error(r, "Error Fapi_Provision", error); @@ -149,6 +154,8 @@ test_fapi_test_second_provisioning(FAPI_CONTEXT *context) rc = init_fapi("P_ECC", &context); } else if (strcmp(FAPI_PROFILE, "P_ECC384") == 0) { rc = init_fapi("P_ECC384", &context); + } else if (strcmp(FAPI_PROFILE, "P_RSA3072") == 0) { + rc = init_fapi("P_ECC384", &context); } else { LOG_ERROR("Profile %s not supported for this test!", FAPI_PROFILE); } diff --git a/test/integration/main-esys.c b/test/integration/main-esys.c index bfa2dd9..5bcc755 100644 --- a/test/integration/main-esys.c +++ b/test/integration/main-esys.c @@ -14,166 +14,18 @@ #include "tss2_esys.h" +#include "tss2_tctildr.h" #include "test-esys.h" -#include "test-options.h" -#include "context-util.h" #include "tss2-esys/esys_int.h" #define LOGMODULE test #include "util/log.h" -/** Define a proxy tcti that returns yielded on every second invocation - * thus the corresponding handling code in ESYS can be tested. - * The first invocation will be Tss2_Sys_StartUp. - */ - -TSS2_RC -(*transmit_hook) (const uint8_t *command_buffer, size_t command_size) = NULL; - -#define TCTI_PROXY_MAGIC 0x5250584f0a000000ULL /* 'PROXY\0\0\0' */ -#define TCTI_PROXY_VERSION 0x1 - -enum state { - forwarding, - intercepting -}; - -typedef struct { - uint64_t magic; - uint32_t version; - TSS2_TCTI_TRANSMIT_FCN transmit; - TSS2_TCTI_RECEIVE_FCN receive; - TSS2_RC (*finalize) (TSS2_TCTI_CONTEXT *tctiContext); - TSS2_RC (*cancel) (TSS2_TCTI_CONTEXT *tctiContext); - TSS2_RC (*getPollHandles) (TSS2_TCTI_CONTEXT *tctiContext, - TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles); - TSS2_RC (*setLocality) (TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality); - TSS2_TCTI_CONTEXT *tctiInner; - enum state state; -} TSS2_TCTI_CONTEXT_PROXY; - -static TSS2_TCTI_CONTEXT_PROXY* -tcti_proxy_cast (TSS2_TCTI_CONTEXT *ctx) -{ - TSS2_TCTI_CONTEXT_PROXY *ctxi = (TSS2_TCTI_CONTEXT_PROXY*)ctx; - if (ctxi == NULL || ctxi->magic != TCTI_PROXY_MAGIC) { - LOG_ERROR("Bad tcti passed."); - return NULL; - } - return ctxi; -} -static TSS2_RC -tcti_proxy_transmit( - TSS2_TCTI_CONTEXT *tctiContext, - size_t command_size, - const uint8_t *command_buffer - ) -{ - TSS2_RC rval; - TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); - if (tcti_proxy->state == intercepting) { - return TSS2_RC_SUCCESS; - } +#include "test-common.h" - if (transmit_hook != NULL) { - rval = transmit_hook(command_buffer, command_size); - if (rval != TSS2_RC_SUCCESS) { - LOG_ERROR("transmit hook requested error"); - return rval; - } - } - rval = Tss2_Tcti_Transmit(tcti_proxy->tctiInner, command_size, - command_buffer); - if (rval != TSS2_RC_SUCCESS) { - LOG_ERROR("Calling TCTI Transmit"); - return rval; - } - return rval; -} - -uint8_t yielded_response[] = { - 0x80, 0x01, /* TPM_ST_NO_SESSION */ - 0x00, 0x00, 0x00, 0x0A, /* Response Size 10 */ - 0x00, 0x00, 0x09, 0x08 /* TPM_RC_YIELDED */ -}; - -static TSS2_RC -tcti_proxy_receive( - TSS2_TCTI_CONTEXT *tctiContext, - size_t *response_size, - uint8_t *response_buffer, - int32_t timeout - ) -{ - TSS2_RC rval; - TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); - - if (tcti_proxy->state == intercepting) { - *response_size = sizeof(yielded_response); - - if (response_buffer != NULL) { - memcpy(response_buffer, &yielded_response[0], sizeof(yielded_response)); - tcti_proxy->state = forwarding; - } - return TSS2_RC_SUCCESS; - } - - rval = Tss2_Tcti_Receive(tcti_proxy->tctiInner, response_size, - response_buffer, timeout); - if (rval != TSS2_RC_SUCCESS) { - LOG_ERROR("Calling TCTI Transmit"); - return rval; - } - - /* First read with response buffer == NULL is to get the size of the - * response. The subsequent read needs to be forwarded also */ - if (response_buffer != NULL) - tcti_proxy->state = intercepting; - - return rval; -} - -static void -tcti_proxy_finalize( - TSS2_TCTI_CONTEXT *tctiContext) -{ - memset(tctiContext, 0, sizeof(TSS2_TCTI_CONTEXT_PROXY)); -} - -static TSS2_RC -tcti_proxy_initialize( - TSS2_TCTI_CONTEXT *tctiContext, - size_t *contextSize, - TSS2_TCTI_CONTEXT *tctiInner) -{ - TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = - (TSS2_TCTI_CONTEXT_PROXY*) tctiContext; - - if (tctiContext == NULL && contextSize == NULL) { - return TSS2_TCTI_RC_BAD_VALUE; - } else if (tctiContext == NULL) { - *contextSize = sizeof(*tcti_proxy); - return TSS2_RC_SUCCESS; - } - - /* Init TCTI context */ - memset(tcti_proxy, 0, sizeof(*tcti_proxy)); - TSS2_TCTI_MAGIC (tctiContext) = TCTI_PROXY_MAGIC; - TSS2_TCTI_VERSION (tctiContext) = TCTI_PROXY_VERSION; - TSS2_TCTI_TRANSMIT (tctiContext) = tcti_proxy_transmit; - TSS2_TCTI_RECEIVE (tctiContext) = tcti_proxy_receive; - TSS2_TCTI_FINALIZE (tctiContext) = tcti_proxy_finalize; - TSS2_TCTI_CANCEL (tctiContext) = NULL; - TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = NULL; - TSS2_TCTI_SET_LOCALITY (tctiContext) = NULL; - tcti_proxy->tctiInner = tctiInner; - tcti_proxy->state = forwarding; - - return TSS2_RC_SUCCESS; -} /** * This program is a template for integration tests (ones that use the TCTI @@ -184,69 +36,35 @@ tcti_proxy_initialize( int main(int argc, char *argv[]) { + TSS2_TEST_ESYS_CONTEXT *test_esys_ctx; TSS2_RC rc; - size_t tcti_size; - TSS2_TCTI_CONTEXT *tcti_context; - TSS2_TCTI_CONTEXT *tcti_inner; - ESYS_CONTEXT *esys_context; - TSS2_ABI_VERSION abiVersion = - { TSSWG_INTEROP, TSS_SAPI_FIRST_FAMILY, TSS_SAPI_FIRST_LEVEL, -TSS_SAPI_FIRST_VERSION }; - int ret; - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; - - get_test_opts_from_env(&opts); - if (sanity_check_test_opts(&opts) != 0) { - LOG_ERROR("TPM Startup FAILED! Error in sanity check"); - exit(1); - } - tcti_inner = tcti_init_from_opts(&opts); - if (tcti_inner == NULL) { - LOG_ERROR("TPM Startup FAILED! Error tcti init"); - exit(1); - } - rc = tcti_proxy_initialize(NULL, &tcti_size, tcti_inner); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("tcti initialization FAILED! Response Code : 0x%x", rc); - return 1; - } - tcti_context = calloc(1, tcti_size); - if (tcti_inner == NULL) { - LOG_ERROR("TPM Startup FAILED! Error tcti init"); - exit(1); - } - rc = tcti_proxy_initialize(tcti_context, &tcti_size, tcti_inner); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("tcti initialization FAILED! Response Code : 0x%x", rc); - return 1; + + (void) argc; + (void) argv; + + ret = test_esys_setup(&test_esys_ctx); + if (ret != 0) { + return ret; } - rc = Esys_Initialize(&esys_context, tcti_context, &abiVersion); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Esys_Initialize FAILED! Response Code : 0x%x", rc); - return 1; + + ret = test_esys_checks_pre(test_esys_ctx); + if (ret != 0) { + return ret; } - rc = Esys_Startup(esys_context, TPM2_SU_CLEAR); - if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { - LOG_ERROR("Esys_Startup FAILED! Response Code : 0x%x", rc); - return 1; + + rc = test_invoke_esys(test_esys_ctx->esys_ctx); + if (rc != 0 && rc != EXIT_SKIP) { + LOG_ERROR("Test returned %08x", rc); + return rc; } - rc = Esys_SetTimeout(esys_context, TSS2_TCTI_TIMEOUT_BLOCK); - if (rc != TSS2_RC_SUCCESS) { - LOG_ERROR("Esys_SetTimeout FAILED! Response Code : 0x%x", rc); - return 1; + ret = test_esys_checks_post(test_esys_ctx); + if (ret != 0) { + return ret; } - ret = test_invoke_esys(esys_context); + test_esys_teardown(test_esys_ctx); - Esys_Finalize(&esys_context); - tcti_teardown(tcti_inner); - tcti_teardown(tcti_context); - return ret; + return rc; } diff --git a/test/integration/main-fapi.c b/test/integration/main-fapi.c index d39a998..59b1913 100644 --- a/test/integration/main-fapi.c +++ b/test/integration/main-fapi.c @@ -14,28 +14,63 @@ #include #include #include -#include + +#include +#include +#include +#if OPENSSL_VERSION_NUMBER < 0x30000000L +#include +#else +#include +#include +#include +#endif +#include +#include #include "tss2_esys.h" #include "tss2_fapi.h" - #include "test-fapi.h" +#include "fapi_int.h" +#include "tss2_rc.h" #define LOGDEFAULT LOGLEVEL_INFO #define LOGMODULE test #include "util/log.h" #include "util/aux_util.h" +#include "test-common.h" + +#if OPENSSL_VERSION_NUMBER >= 0x10101000L +#define EC_POINT_set_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_set_affine_coordinates(group, tpm_pub_key, bn_x, bn_y, dmy) + +#define EC_POINT_get_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_get_affine_coordinates(group, tpm_pub_key, bn_x, bn_y, dmy) + +#else +#define EC_POINT_set_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_set_affine_coordinates_GFp(group, tpm_pub_key, bn_x, bn_y, dmy) + +#define EC_POINT_get_affine_coordinates_tss(group, tpm_pub_key, bn_x, bn_y, dmy) \ + EC_POINT_get_affine_coordinates_GFp(group, tpm_pub_key, bn_x, bn_y, dmy) +#endif /* OPENSSL_VERSION_NUMBER >= 0x10101000L */ + +#define SYS_CALL(rc,fu,...) \ + do { \ + rc = fu(__VA_ARGS__); \ + } while (rc == TPM2_RC_YIELDED); \ + if (rc != TPM2_RC_SUCCESS) { \ + LOG_ERROR("%s FAILED: 0x%"PRIx32, #fu, rc); \ + return rc; \ + } + char *fapi_profile = NULL; -char *tmpdir = NULL; +TSS2_TEST_FAPI_CONTEXT *fapi_test_ctx = NULL; -char *config = NULL; -char *config_bak = NULL; -char *config_path = NULL; -char *config_env = NULL; -char *remove_cmd = NULL; -char *system_dir = NULL; -FAPI_CONTEXT *global_fapi_context = NULL; +struct tpm_state { + TPMS_CAPABILITY_DATA capabilities[7]; +}; bool file_exists (char *path) { struct stat buffer; @@ -181,6 +216,49 @@ pcr_reset(FAPI_CONTEXT *context, UINT32 pcr) return r; } +TSS2_RC +pcr_bank_sha1_exists(FAPI_CONTEXT *context, bool *exists) +{ + TSS2_RC r; + TSS2_TCTI_CONTEXT *tcti; + ESYS_CONTEXT *esys; + TPML_PCR_SELECTION pcrSelectionIn = { + .count = 1, + .pcrSelections = { + { .hash = TPM2_ALG_SHA1, + .sizeofSelect = 3, + .pcrSelect = { 1, 0, 0} + }, + } + }; + UINT32 pcrUpdateCounter; + TPML_PCR_SELECTION *pcrSelectionOut = NULL; + TPML_DIGEST *pcrValues = NULL; + + r = Fapi_GetTcti(context, &tcti); + goto_if_error(r, "Error Fapi_GetTcti", error); + + r = Esys_Initialize(&esys, tcti, NULL); + goto_if_error(r, "Error Fapi_GetTcti", error); + + r = Esys_PCR_Read(esys, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, + &pcrSelectionIn, &pcrUpdateCounter, &pcrSelectionOut, &pcrValues); + goto_if_error(r, "Error: PCR_Read", error); + if (!pcrSelectionOut->pcrSelections[0].pcrSelect[0]) { + *exists = false; + } else { + *exists = true; + } + Esys_Finalize(&esys); + goto_if_error(r, "Error Eys_PCR_Reset", error); + +error: + SAFE_FREE(pcrSelectionOut); + SAFE_FREE(pcrValues); + return r; +} + + TSS2_RC pcr_extend(FAPI_CONTEXT *context, UINT32 pcr, TPML_DIGEST_VALUES *digest_values) { @@ -208,15 +286,15 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) { TSS2_RC rc; int ret, size; - SAFE_FREE(config); - SAFE_FREE(config_path); - SAFE_FREE(config_env); - SAFE_FREE(remove_cmd); - SAFE_FREE(system_dir); - + char *config = NULL; + char *config_path = NULL; + char *config_env = NULL; + char *config_bak = NULL; FILE *config_file; + char *tmpdir; fapi_profile = profile; + tmpdir = fapi_test_ctx->tmpdir; /* First we construct a fapi config file */ #if defined(FAPI_NONTPM) @@ -242,11 +320,11 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) #if defined(FAPI_TEST_EK_CERT_LESS) " \"ek_cert_less\": \"yes\",\n" #else - " \"ek_fingerprint\": %s,\n" + " \"ek_fingerprint\": { \"hashAlg\": \"sha256\", \"digest\": \"%s\" },\n" #endif "}\n", profile, tmpdir, tmpdir, tmpdir, - getenv("TPM20TEST_TCTI") + getenv(ENV_TCTI) #if !defined(FAPI_TEST_EK_CERT_LESS) , getenv("FAPI_TEST_FINGERPRINT") #endif @@ -263,11 +341,11 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) #if defined(FAPI_TEST_EK_CERT_LESS) " \"ek_cert_less\": \"yes\",\n" #else - " \"ek_cert_file\": \"%s\",\n" + " \"ek_cert_file\": \"file:%s\",\n" #endif "}\n", profile, tmpdir, tmpdir, tmpdir, - getenv("TPM20TEST_TCTI") + getenv(ENV_TCTI) #if !defined(FAPI_TEST_EK_CERT_LESS) , getenv("FAPI_TEST_CERTIFICATE") #endif @@ -284,11 +362,11 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) #if defined(FAPI_TEST_EK_CERT_LESS) " \"ek_cert_less\": \"yes\",\n" #else - " \"ek_fingerprint\": %s,\n" + " \"ek_fingerprint\": { \"hashAlg\": \"sha256\", \"digest\": \"%s\" },\n" #endif "}\n", profile, tmpdir, tmpdir, tmpdir, - getenv("TPM20TEST_TCTI") + getenv(ENV_TCTI) #if !defined(FAPI_TEST_EK_CERT_LESS) , getenv("FAPI_TEST_FINGERPRINT_ECC") #endif @@ -305,11 +383,11 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) #if defined(FAPI_TEST_EK_CERT_LESS) " \"ek_cert_less\": \"yes\",\n" #else - " \"ek_cert_file\": \"%s\",\n" + " \"ek_cert_file\": \"file:%s\",\n" #endif "}\n", profile, tmpdir, tmpdir, tmpdir, - getenv("TPM20TEST_TCTI") + getenv(ENV_TCTI) #if defined(FAPI_TEST_EK_CERT_LESS) #else , getenv("FAPI_TEST_CERTIFICATE_ECC") @@ -324,12 +402,12 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) " \"system_pcrs\" : [],\n" " \"log_dir\" : \"%s\",\n" " \"tcti\": \"%s\",\n" -#if defined(FAPI_TEST_EK_CERT_LESS) +#if defined(FAPI_TEST_EK_CERT_LESS) || defined(DLOPEN) " \"ek_cert_less\": \"yes\",\n" #endif "", profile, tmpdir, tmpdir, tmpdir, - getenv("TPM20TEST_TCTI")); + getenv(ENV_TCTI)); #endif /* FAPI_NONTPM */ if (size < 0) { @@ -389,22 +467,6 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) } SAFE_FREE(config_bak); - size = asprintf(&system_dir, "%s/system_dir/", tmpdir); - if (size < 0) { - LOG_ERROR("Out of memory"); - ret = EXIT_ERROR; - goto error; - } - - if (!file_exists(system_dir)) { - int rc_mkdir = mkdir(system_dir, 0777); - if (rc_mkdir != 0) { - LOG_ERROR("mkdir not possible: %i %s", rc_mkdir, system_dir); - ret = EXIT_ERROR; - goto error; - } - } - if (size < 0) { LOG_ERROR("Out of memory"); ret = EXIT_ERROR; @@ -450,26 +512,946 @@ int init_fapi(char *profile, FAPI_CONTEXT **fapi_context) * Call FAPI ***********/ + rc = Fapi_Initialize(fapi_context, NULL); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR("Esys_Initialize FAILED! Response Code : 0x%x", rc); ret = EXIT_FAILURE; goto error; } - global_fapi_context = *fapi_context; + + fapi_test_ctx->fapi_ctx = *fapi_context; + SAFE_FREE(config_env); + SAFE_FREE(config); + SAFE_FREE(config_path); return 0; error: Fapi_Finalize(fapi_context); - if (system_dir) free(system_dir); if (config) free(config); if (config_path) free(config_path); if (config_env) free(config_env); - if (remove_cmd) free(remove_cmd); return ret; } +TSS2_RC +rsa_pub_from_tpm(const TPM2B_PUBLIC *tpmPublicKey, EVP_PKEY **evpPublicKey) +{ +#if OPENSSL_VERSION_NUMBER < 0x30000000L + RSA *rsa = NULL; +#else + OSSL_PARAM_BLD *build = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; +#endif + + /* Check for NULL parameters */ + return_if_null(tpmPublicKey, "tpmPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + return_if_null(evpPublicKey, "evpPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + + TSS2_RC r = TSS2_RC_SUCCESS; + /* Initialize the RSA parameters */ + BIGNUM *e = NULL; + BIGNUM *n = BN_bin2bn(tpmPublicKey->publicArea.unique.rsa.buffer, + tpmPublicKey->publicArea.unique.rsa.size, NULL); + if (!n) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + + uint32_t exp; + if (tpmPublicKey->publicArea.parameters.rsaDetail.exponent == 0) + exp = 65537; + else + exp = tpmPublicKey->publicArea.parameters.rsaDetail.exponent; + +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if ((rsa = RSA_new()) == NULL) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + + if ((e = BN_new()) == NULL) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + if (1 != BN_set_word(e, exp)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Could not set exponent.", error_cleanup); + } + + if (!RSA_set0_key(rsa, n, e, NULL)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "Could not set public key.", error_cleanup); + } + n = NULL; /* ownership transferred */ + e = NULL; + + *evpPublicKey = EVP_PKEY_new(); + goto_if_null2(*evpPublicKey, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, error_cleanup); + + /* Assign the parameters to the key */ + if (!EVP_PKEY_assign_RSA(*evpPublicKey, rsa)) { + EVP_PKEY_free(*evpPublicKey); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Assign rsa key", + error_cleanup); + } + rsa = NULL; /* ownership transferred */ +error_cleanup: + OSSL_FREE(rsa, RSA); +#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + if ((build = OSSL_PARAM_BLD_new()) == NULL + || !OSSL_PARAM_BLD_push_BN(build, OSSL_PKEY_PARAM_RSA_N, n) + || !OSSL_PARAM_BLD_push_uint32(build, OSSL_PKEY_PARAM_RSA_E, exp) + || (params = OSSL_PARAM_BLD_to_param(build)) == NULL) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create rsa key parameters", + error_cleanup); + } + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL + || EVP_PKEY_fromdata_init(ctx) <= 0 + || EVP_PKEY_fromdata(ctx, evpPublicKey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create rsa key", + error_cleanup); + } +error_cleanup: + OSSL_FREE(ctx, EVP_PKEY_CTX); + OSSL_FREE(params, OSSL_PARAM); + OSSL_FREE(build, OSSL_PARAM_BLD); +#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */ + OSSL_FREE(e, BN); + OSSL_FREE(n, BN); + return r; +} + +TSS2_RC +ecc_pub_from_tpm(const TPM2B_PUBLIC *tpmPublicKey, EVP_PKEY **evpPublicKey) +{ + /* Check for NULL parameters */ + return_if_null(tpmPublicKey, "tpmPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + return_if_null(evpPublicKey, "evpPublicKey is NULL", TSS2_FAPI_RC_BAD_REFERENCE); + + TSS2_RC r = TSS2_RC_SUCCESS; + EC_GROUP *ecgroup = NULL; + int curveId; + BIGNUM *x = NULL, *y = NULL; + EC_POINT *ecPoint = NULL; +#if OPENSSL_VERSION_NUMBER < 0x30000000L + EC_KEY *ecKey = NULL; +#else + OSSL_PARAM_BLD *build = NULL; + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; + unsigned char *puboct = NULL; + size_t bsize; +#endif + + /* Find the curve of the ECC key */ + switch (tpmPublicKey->publicArea.parameters.eccDetail.curveID) { + case TPM2_ECC_NIST_P192: + curveId = NID_X9_62_prime192v1; + break; + case TPM2_ECC_NIST_P224: + curveId = NID_secp224r1; + break; + case TPM2_ECC_NIST_P256: + curveId = NID_X9_62_prime256v1; + break; + case TPM2_ECC_NIST_P384: + curveId = NID_secp384r1; + break; + case TPM2_ECC_NIST_P521: + curveId = NID_secp521r1; + break; +#ifdef NID_sm2 + case TPM2_ECC_SM2_P256: + curveId = NID_sm2; + break; +#endif + default: + return_error(TSS2_FAPI_RC_BAD_VALUE, + "ECC curve not implemented."); + } + + /* Initialize the OpenSSL ECC key with its group */ + ecgroup = EC_GROUP_new_by_curve_name(curveId); + goto_if_null(ecgroup, "new EC group.", TSS2_FAPI_RC_GENERAL_FAILURE, + error_cleanup); + + /* Set the ECC parameters in the OpenSSL key */ + x = BN_bin2bn(tpmPublicKey->publicArea.unique.ecc.x.buffer, + tpmPublicKey->publicArea.unique.ecc.x.size, NULL); + + y = BN_bin2bn(tpmPublicKey->publicArea.unique.ecc.y.buffer, + tpmPublicKey->publicArea.unique.ecc.y.size, NULL); + + if (!x || !y) { + goto_error(r, TSS2_FAPI_RC_MEMORY, "Out of memory", error_cleanup); + } + + if ((ecPoint = EC_POINT_new(ecgroup)) == NULL + || !EC_POINT_set_affine_coordinates_tss(ecgroup, ecPoint, x, y, NULL)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EC_POINT_set_affine_coordinates", + error_cleanup); + } + +#if OPENSSL_VERSION_NUMBER < 0x30000000 + ecKey = EC_KEY_new(); + return_if_null(ecKey, "Out of memory.", TSS2_FAPI_RC_MEMORY); + + if (!EC_KEY_set_group(ecKey, ecgroup)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "EC_KEY_set_group", + error_cleanup); + } + + if (!EC_KEY_set_public_key(ecKey, ecPoint)) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, + "EC_KEY_set_public_key", error_cleanup); + } + + *evpPublicKey = EVP_PKEY_new(); + goto_if_null2(*evpPublicKey, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, error_cleanup); + + if (!EVP_PKEY_assign_EC_KEY(*evpPublicKey, ecKey)) { + EVP_PKEY_free(*evpPublicKey); + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Assign ecc key", + error_cleanup); + } + ecKey = NULL; /* ownership transferred */ +error_cleanup: + OSSL_FREE(ecKey, EC_KEY); +#else + if ((build = OSSL_PARAM_BLD_new()) == NULL + || !OSSL_PARAM_BLD_push_utf8_string(build, OSSL_PKEY_PARAM_GROUP_NAME, + (char *)OBJ_nid2sn(curveId), 0) + || (bsize = EC_POINT_point2buf(ecgroup, ecPoint, + POINT_CONVERSION_COMPRESSED, + &puboct, NULL)) == 0 + || !OSSL_PARAM_BLD_push_octet_string(build, OSSL_PKEY_PARAM_PUB_KEY, + puboct, bsize) + || (params = OSSL_PARAM_BLD_to_param(build)) == NULL) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create ecc key parameters", + error_cleanup); + } + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL + || EVP_PKEY_fromdata_init(ctx) <= 0 + || EVP_PKEY_fromdata(ctx, evpPublicKey, EVP_PKEY_PUBLIC_KEY, params) <= 0) { + goto_error(r, TSS2_FAPI_RC_GENERAL_FAILURE, "Create ecc key", + error_cleanup); + } +error_cleanup: + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(build); + OPENSSL_free(puboct); +#endif + OSSL_FREE(ecPoint, EC_POINT); + OSSL_FREE(ecgroup, EC_GROUP); + OSSL_FREE(y, BN); + OSSL_FREE(x, BN); + return r; +} + +TPM2_RC +get_rsa_ek_public(TSS2_SYS_CONTEXT *sys_context, EVP_PKEY **evp_pub) +{ + TSS2_RC rc; + TSS2L_SYS_AUTH_COMMAND auth_cmd = { + .auths = {{ .sessionHandle = TPM2_RH_PW }}, + .count = 1 + }; + TPM2B_SENSITIVE_CREATE in_sensitive = { 0 }; + TPM2B_PUBLIC in_public = { + .publicArea = { + .type = TPM2_ALG_RSA, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = ( + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN | + TPMA_OBJECT_ADMINWITHPOLICY | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT + ), + .authPolicy = { + .size = 32, + .buffer = 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, + 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, + 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, + 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, + 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, + 0x69, 0xAA, + }, + .parameters.rsaDetail = { + .symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }, + .scheme = { + .scheme = TPM2_ALG_NULL, + }, + .keyBits = 2048, + .exponent = 0, + }, + .unique.rsa = { + .size = 256, + .buffer = {0}, + } + } + }; + TPML_PCR_SELECTION creation_pcr = { 0 }; + TPM2_HANDLE handle; + TPM2B_PUBLIC out_public = { 0 }; + TSS2L_SYS_AUTH_RESPONSE auth_rsp = { + .count = 0 + }; + + /* Generate the EK key */ + + SYS_CALL(rc, Tss2_Sys_CreatePrimary, + sys_context, TPM2_RH_ENDORSEMENT, &auth_cmd, + &in_sensitive, &in_public, NULL, &creation_pcr, + &handle, &out_public, NULL, NULL, NULL, NULL, &auth_rsp); + + SYS_CALL(rc, Tss2_Sys_FlushContext, sys_context, handle); + + rc = rsa_pub_from_tpm(&out_public, evp_pub); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERROR("Failed to create EVP key from RSA EK: 0x%"PRIx32, rc); + return rc; + } + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +get_ecc_ek_public(TSS2_SYS_CONTEXT *sys_context, EVP_PKEY **evp_pub) +{ + TSS2_RC rc; + TSS2L_SYS_AUTH_COMMAND auth_cmd = { + .auths = {{ .sessionHandle = TPM2_RH_PW }}, + .count = 1 + }; + TPM2B_SENSITIVE_CREATE in_sensitive = { 0 }; + TPM2B_PUBLIC in_public = { + .publicArea = { + .type = TPM2_ALG_ECC, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = ( + TPMA_OBJECT_FIXEDTPM | + TPMA_OBJECT_FIXEDPARENT | + TPMA_OBJECT_SENSITIVEDATAORIGIN | + TPMA_OBJECT_ADMINWITHPOLICY | + TPMA_OBJECT_RESTRICTED | + TPMA_OBJECT_DECRYPT + ), + .authPolicy = { + .size = 32, + .buffer = 0x83, 0x71, 0x97, 0x67, 0x44, 0x84, + 0xB3, 0xF8, 0x1A, 0x90, 0xCC, 0x8D, + 0x46, 0xA5, 0xD7, 0x24, 0xFD, 0x52, + 0xD7, 0x6E, 0x06, 0x52, 0x0B, 0x64, + 0xF2, 0xA1, 0xDA, 0x1B, 0x33, 0x14, + 0x69, 0xAA, + }, + .parameters.eccDetail = { + .symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }, + .scheme = { + .scheme = TPM2_ALG_NULL, + .details = { 0 } + }, + .curveID = TPM2_ECC_NIST_P256, + .kdf = {.scheme = TPM2_ALG_NULL, + .details = { 0 } + } + }, + .unique.ecc = { + .x = {.size = 32,.buffer = { 0 }}, + .y = {.size = 32,.buffer = { 0 }} + } + } + }; + TPML_PCR_SELECTION creation_pcr = { 0 }; + TPM2_HANDLE handle; + TPM2B_PUBLIC out_public = { 0 }; + TSS2L_SYS_AUTH_RESPONSE auth_rsp = { + .count = 0 + }; + SYS_CALL(rc, Tss2_Sys_CreatePrimary, + sys_context, TPM2_RH_ENDORSEMENT, &auth_cmd, + &in_sensitive, &in_public, NULL, &creation_pcr, + &handle, &out_public, NULL, NULL, NULL, NULL, &auth_rsp); + + + SYS_CALL(rc, Tss2_Sys_FlushContext, sys_context, handle); + + rc = ecc_pub_from_tpm(&out_public, evp_pub); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERROR("Failed to create EVP key from ECC EK: 0x%"PRIx32, rc); + return rc; + } + + return TSS2_RC_SUCCESS; + +} + +char pwd[6] = "123456"; + +int pass_cb(char *buf, int size, int rwflag, void *u) +{ + (void)rwflag; + memcpy(buf, &pwd[0], 6); + return 6; +} + +TSS2_RC +nv_write(TSS2_SYS_CONTEXT *sys_context, TPMI_RH_NV_INDEX nvIndex, X509 *cert) +{ + TSS2_RC rc; + TSS2L_SYS_AUTH_COMMAND auth_cmd = { + .auths = {{ .sessionHandle = TPM2_RH_PW }}, + .count = 1 + }; + + if (!nvIndex) { + nvIndex = 0x01c00002; + } + + TPM2B_AUTH nv_auth = { 0 }; + TPM2B_NV_PUBLIC public_info = { + .nvPublic = { + .nameAlg = TPM2_ALG_SHA1, + .attributes = TPMA_NV_PPWRITE | TPMA_NV_AUTHREAD | TPMA_NV_OWNERREAD | + TPMA_NV_PLATFORMCREATE | TPMA_NV_NO_DA, + .dataSize = 0, + .nvIndex = nvIndex, + }, + }; + + TSS2L_SYS_AUTH_RESPONSE auth_rsp = { + .count = 0 + }; + TPM2B_MAX_NV_BUFFER buf1 = { 0 }; + TPM2B_MAX_NV_BUFFER buf2 = { 0 }; + unsigned char *cert_buf = NULL; + int cert_size; + + cert_size = i2d_X509(cert, &cert_buf); + if (cert_size < 0) { + LOG_ERROR("Certificate buffer can't be created."); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + if (buf1.size >= sizeof(buf1.buffer)) { + LOG_ERROR("Certificate to large"); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + buf1.size = cert_size; + memcpy(&buf1.buffer[0], cert_buf, cert_size); + free(cert_buf); + + /* First make sure that not EK certificate is currently loaded */ + LOG_WARNING("Cert input size is %"PRIu16, buf1.size); + public_info.nvPublic.dataSize = buf1.size; + + LOG_WARNING("Define NV cert with nv index: %x", public_info.nvPublic.nvIndex); + + SYS_CALL(rc, Tss2_Sys_NV_DefineSpace, + sys_context, TPM2_RH_PLATFORM, &auth_cmd, + &nv_auth, &public_info, &auth_rsp); + + /* Split the input buffer into 2 chunks */ + buf2.size = buf1.size; + buf1.size /= 2; + buf2.size -= buf1.size; + memcpy(&buf2.buffer[0], &buf1.buffer[buf1.size], buf2.size); + + SYS_CALL(rc, Tss2_Sys_NV_Write, sys_context, TPM2_RH_PLATFORM, nvIndex, &auth_cmd, + &buf1, 0, &auth_rsp); + + SYS_CALL(rc, Tss2_Sys_NV_Write, sys_context, TPM2_RH_PLATFORM, nvIndex, &auth_cmd, + &buf2, buf1.size, &auth_rsp); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +load_intermed_cert_and_key(const char *ca_key_path, EVP_PKEY **ca_key, + const char *ca_cert_path, X509 **ca_crt) +{ + BIO *bio = NULL; + *ca_crt = NULL; + *ca_key = NULL; + + /* Load the intermediate certificate */ + bio = BIO_new(BIO_s_file()); + if (!bio || !BIO_read_filename(bio, ca_cert_path)) { + unsigned long err = ERR_get_error(); + char err_buffer[256]; + ERR_error_string_n(err, err_buffer, sizeof(err_buffer)); + LOG_ERROR("Failure in BIO_read_filename \"%s\" %s", ca_cert_path, err_buffer); + goto error_cleanup; + } + *ca_crt = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (!*ca_crt) { + LOG_ERROR("Could not read intermediate cert %s", ca_cert_path); + goto error_cleanup; + } + BIO_free_all(bio); + + /* Load the intermediate key. */ + bio = BIO_new(BIO_s_file()); + if (!bio || !BIO_read_filename(bio, ca_key_path)) { + unsigned long err = ERR_get_error(); + char err_buffer[256]; + ERR_error_string_n(err, err_buffer, sizeof(err_buffer)); + LOG_ERROR("Failure in BIO_read_filename \"%s\" %s", ca_key_path, err_buffer); + goto error_cleanup; + } + *ca_key = PEM_read_bio_PrivateKey(bio, NULL, pass_cb, NULL); + if (!*ca_key) { + LOG_ERROR("Could not read intermediate key %s", ca_key_path); + goto error_cleanup; + } + BIO_free_all(bio); + return TSS2_RC_SUCCESS; + + error_cleanup: + BIO_free_all(bio); + X509_free(*ca_crt); + EVP_PKEY_free(*ca_key); + return TSS2_FAPI_RC_GENERAL_FAILURE; +} + +TSS2_RC +get_dummy_csr(EVP_PKEY **dmy_key, X509_REQ **req) +{ + *dmy_key = NULL; + *req = NULL; + EVP_PKEY_CTX *ctx = NULL; + + *dmy_key = NULL; + *req = X509_REQ_new(); + if (!*req) { + LOG_ERROR("Failed to allocate Memory for request"); + goto error_cleanup; + } + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + if (!ctx) { + LOG_ERROR("Failed to allocate Memory for PKEY context"); + goto error_cleanup; + } + + /* Create dummy key */ + + if (EVP_PKEY_keygen_init(ctx) <= 0 || + EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) <= 0 || + EVP_PKEY_keygen(ctx, dmy_key) <= 0) { + LOG_ERROR("Failed to create key"); + goto error_cleanup; + } + + X509_REQ_set_pubkey(*req, *dmy_key); + + /* Self-sign the request to prove that we posses the key. */ + if (!X509_REQ_sign(*req, *dmy_key, EVP_sha256())) { + LOG_ERROR("Failed to sign request."); + goto error_cleanup; + } + EVP_PKEY_CTX_free(ctx); + return TSS2_RC_SUCCESS; + + error_cleanup: + if (dmy_key) + EVP_PKEY_free(*dmy_key); + if (req) + X509_REQ_free(*req); + if (ctx) + EVP_PKEY_CTX_free(ctx); + return TSS2_FAPI_RC_GENERAL_FAILURE; +} + +TSS2_RC +get_ek_certificate(EVP_PKEY *ca_key, X509 *ca_cert, + X509_REQ *req, + EVP_PKEY *ek, X509 **ek_cert) +{ + BIGNUM *bn = NULL; + unsigned char serial_ary[5] = { 0x01, 0x02, 0x03, 0x04, 0x05 }; + ASN1_INTEGER *serial_asn1 = NULL; + + *ek_cert = X509_new(); + if (!*ek_cert) { + LOG_ERROR("Failed to allocate Memory for PKEY context"); + goto error_cleanup; + } + if (X509_set_version(*ek_cert, 2) <= 0) goto error_cleanup; + bn = BN_new(); + if (!bn) { + LOG_ERROR("Failed to allocate BN"); + goto error_cleanup; + } + BN_bin2bn(&serial_ary[0], sizeof(serial_ary), bn); + serial_asn1 = ASN1_INTEGER_new(); + if (!serial_asn1) { + LOG_ERROR("Failed to allocate ASN1 serial."); + goto error_cleanup; + } + + BN_to_ASN1_INTEGER(bn, serial_asn1); + + if (X509_set_serialNumber(*ek_cert, serial_asn1) <= 0 || + X509_set_issuer_name(*ek_cert, X509_get_subject_name(ca_cert)) <= 0) { + LOG_ERROR("Failed to initialize EK cert."); + goto error_cleanup; + } + + X509_gmtime_adj(X509_get_notBefore(*ek_cert), 0); + X509_gmtime_adj(X509_get_notAfter(*ek_cert), (long)3*365*24*3600); + + ASN1_INTEGER_free(serial_asn1); + BN_free(bn); + + EVP_PKEY *req_pubkey = X509_REQ_get_pubkey(req); + if (X509_set_pubkey(*ek_cert, ek) <= 0) { + LOG_ERROR("Failed to set pubkey of EK cert."); + goto error_cleanup; + } + EVP_PKEY_free(req_pubkey); + + if (X509_sign(*ek_cert, ca_key, EVP_sha256()) == 0) { + LOG_ERROR("Failed to sign certificate."); + goto error_cleanup; + } + X509_REQ_free(req); + return TSS2_RC_SUCCESS; + + error_cleanup: + X509_REQ_free(req); + if (bn) + BN_free(bn); + if (serial_asn1) + ASN1_INTEGER_free(serial_asn1); + if (*ek_cert) + X509_free(*ek_cert); + return TSS2_FAPI_RC_GENERAL_FAILURE; +} + +TSS2_RC +get_pubkey_fingerprint(EVP_PKEY *key, char **fingerprint) +{ + TPM2_RC rc = TSS2_FAPI_RC_GENERAL_FAILURE; + size_t size_der_pub; + unsigned char *der_key = NULL; + BUF_MEM *bio_mem_data = NULL; +#if OPENSSL_VERSION_NUMBER < 0x30000000L + SHA256_CTX sha256_context; +#else + size_t size_hash; +#endif + unsigned char fingerprint_digest[TPM2_SHA256_DIGEST_SIZE]; + + BIO *bio_mem = BIO_new(BIO_s_mem()); + if (!bio_mem) { + LOG_ERROR("Failed to allocate BIO."); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + if (i2d_PUBKEY_bio(bio_mem, key) == 0) { + LOG_ERROR("Failed to get public key."); + return TSS2_FAPI_RC_GENERAL_FAILURE; + } + BIO_get_mem_ptr(bio_mem, &bio_mem_data); + der_key = (unsigned char *)bio_mem_data->data; + size_der_pub = bio_mem_data->length; + +#if OPENSSL_VERSION_NUMBER < 0x30000000L + if (SHA256_Init(&sha256_context) == 0 || + SHA256_Update(&sha256_context, der_key, size_der_pub) == 0 || + SHA256_Final(&fingerprint_digest[0], &sha256_context) == 0) { + LOG_ERROR("sha256 update failed."); + goto error_cleanup; + } +#else + if (EVP_Q_digest(NULL, "sha256", NULL, der_key, size_der_pub, + &fingerprint_digest[0], &size_hash) == 0) { + LOG_ERROR("sha256 update failed."); + goto error_cleanup; + } +#endif + *fingerprint = calloc(TPM2_SHA256_DIGEST_SIZE * 2 + 1, 1); + if (!(*fingerprint)) { + LOG_ERROR("Failed to allocate fingerprint."); + goto error_cleanup; + } + char *pf = &(*fingerprint)[0]; + for (size_t i = 0; i < TPM2_SHA256_DIGEST_SIZE; i++) { + pf += sprintf(pf, "%.2x", fingerprint_digest[i]); + } + rc = TSS2_RC_SUCCESS; + + error_cleanup: + if (bio_mem) + BIO_free_all(bio_mem); + return rc; + } + +TSS2_RC +get_ek_fingerprints(TSS2_SYS_CONTEXT *sys_ctx, + char **rsa_fingerprint, char **ecc_fingerprint) +{ + TSS2_RC rc; + EVP_PKEY *ecc_ek_key_pub = NULL; + EVP_PKEY *rsa_ek_key_pub = NULL; + + rc = get_ecc_ek_public(sys_ctx, &ecc_ek_key_pub); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get ECC EK: %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + rc = get_pubkey_fingerprint(ecc_ek_key_pub, ecc_fingerprint); + if (rc != TSS2_RC_SUCCESS) { + goto error_cleanup; + } + + rc = get_rsa_ek_public(sys_ctx, &rsa_ek_key_pub); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get RSA EK: %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + + rc = get_pubkey_fingerprint(rsa_ek_key_pub, rsa_fingerprint); + if (rc != TSS2_RC_SUCCESS) { + SAFE_FREE(*ecc_fingerprint); + goto error_cleanup; + } + + error_cleanup: + if (ecc_ek_key_pub) + EVP_PKEY_free(ecc_ek_key_pub); + if (rsa_ek_key_pub) + EVP_PKEY_free(rsa_ek_key_pub); + return rc; +} + +TSS2_RC +prepare_certificate(TSS2_SYS_CONTEXT *sys_ctx, X509 *ek_cert, + TPM2_NV_INDEX nv_index, char* env_var) { + TSS2_RC rc; + +#if defined(FAPI_TEST_CERTIFICATE) || defined(FAPI_TEST_CERTIFICATE_ECC) + char *pem_filename; + FILE *output_file; + // (void)nv_idex; + (void)sys_ctx; + + pem_filename = getenv(env_var); + if (!pem_filename) { + LOG_ERROR("Environment variable FAPI_TEST_CERTIFICATE_ECC not set."); + rc = TSS2_FAPI_RC_GENERAL_FAILURE; + goto error_cleanup; + } + output_file = fopen(pem_filename, "w"); + if (!output_file) { + LOG_ERROR("Error opening output file: %s", pem_filename); + rc = TSS2_FAPI_RC_GENERAL_FAILURE; + goto error_cleanup; + } + if (PEM_write_X509(output_file, ek_cert) != 1) { + perror("Error writing X.509 certificate to file"); + fclose(output_file); + rc = TSS2_FAPI_RC_GENERAL_FAILURE; + goto error_cleanup; + } + fclose(output_file); +#else + // (void)env_var; + + rc = nv_write(sys_ctx, nv_index, ek_cert); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to write ECC EK cert."); + goto error_cleanup; + } +#endif + rc = TSS2_RC_SUCCESS; + + error_cleanup: + return rc; +} + +TSS2_RC +init_ek_certificates(TSS2_SYS_CONTEXT *sys_ctx) +{ + TSS2_RC rc; + X509_REQ *req = NULL; + EVP_PKEY *dmy_key = NULL; + X509 *ecc_ek_cert = NULL; + EVP_PKEY *ecc_ek_key_pub = NULL; + X509 *rsa_ek_cert = NULL; + EVP_PKEY *rsa_ek_key_pub = NULL; + X509 *intermed_cert = NULL; + EVP_PKEY *intermed_key = NULL; + + rc = get_ecc_ek_public(sys_ctx, &ecc_ek_key_pub); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get ECC EK: %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + + rc = get_rsa_ek_public(sys_ctx, &rsa_ek_key_pub); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get RSA EK: %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + +#ifdef SELF_SIGNED_CERTIFICATE + /* The self signed root cert will be used as intermediate certificate. */ + rc = load_intermed_cert_and_key("./ca/root-ca/private/root-ca.key.pem", + &intermed_key, + "./ca/root-ca/root-ca.cert.pem", + &intermed_cert); +#else + rc = load_intermed_cert_and_key("./ca/intermed-ca/private/intermed-ca.key.pem", + &intermed_key, + "./ca/intermed-ca/intermed-ca.cert.pem", + &intermed_cert); +#endif + + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to load intermediate key and cert %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + + rc = get_dummy_csr(&dmy_key, &req); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get req: %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + + rc = get_ek_certificate(intermed_key, intermed_cert, req, + ecc_ek_key_pub, &ecc_ek_cert); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get ECC EK cert."); + goto error_cleanup; + } + + rc = prepare_certificate(sys_ctx, ecc_ek_cert, 0x1c0000a, + "FAPI_TEST_CERTIFICATE_ECC"); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to prepare ECC EK cert."); + goto error_cleanup; + } + + EVP_PKEY_free(dmy_key); + dmy_key = NULL; + X509_REQ_free(req); + req = NULL; + + rc = get_dummy_csr(&dmy_key, &req); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get req: %s\n", Tss2_RC_Decode(rc)); + goto error_cleanup; + } + + rc = get_ek_certificate(intermed_key, intermed_cert, req, + rsa_ek_key_pub, &rsa_ek_cert); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get RSA EK cert."); + goto error_cleanup; + } + + rc = prepare_certificate(sys_ctx, rsa_ek_cert, 0x1c00002, + "FAPI_TEST_CERTIFICATE"); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to prepare RSA EK cert."); + goto error_cleanup; + } + + rc = TSS2_RC_SUCCESS; + + error_cleanup: + if (req) + X509_REQ_free(req); + if (rsa_ek_cert) + X509_free(rsa_ek_cert); + if (ecc_ek_cert) + X509_free(ecc_ek_cert); + if (dmy_key) + EVP_PKEY_free(dmy_key); + if (ecc_ek_key_pub) + EVP_PKEY_free(ecc_ek_key_pub); + if (rsa_ek_key_pub) + EVP_PKEY_free(rsa_ek_key_pub); + if (intermed_cert) + X509_free(intermed_cert); + if (intermed_key) + EVP_PKEY_free(intermed_key); + + return rc; +} + +int +test_fapi_setup(TSS2_TEST_FAPI_CONTEXT **test_ctx) +{ + char template[] = "/tmp/fapi_tmpdir.XXXXXX"; + char *tmpdir = NULL; + size_t size; + int ret; + + size = sizeof(TSS2_TEST_FAPI_CONTEXT); + *test_ctx = calloc(size, 1); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for the test context", size); + goto error; + } + + tmpdir = strdup(template); + if (!tmpdir) { + LOG_ERROR("Failed to allocate name of temp dir."); + goto error; + } + (*test_ctx)->tmpdir = mkdtemp(tmpdir); + if (!(*test_ctx)->tmpdir) { + LOG_ERROR("No temp dir created"); + goto error; + } + fapi_test_ctx = *test_ctx; + + ret = init_fapi(FAPI_PROFILE, &(*test_ctx)->fapi_ctx); + if (ret != 0) { + LOG_ERROR("init fapi failed."); + goto error; + } + (*test_ctx)->test_esys_ctx.esys_ctx = (*test_ctx)->fapi_ctx->esys; + (*test_ctx)->test_esys_ctx.tpm_state = malloc(sizeof(tpm_state)); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for tpm_state.", size); + goto error; + } + + return ret; + + error: + SAFE_FREE(tmpdir); + SAFE_FREE(*test_ctx); + return EXIT_ERROR; +} + +void +test_fapi_teardown(TSS2_TEST_FAPI_CONTEXT *test_ctx) +{ + if (test_ctx) { + if (test_ctx->fapi_ctx) { + Fapi_Finalize(&test_ctx->fapi_ctx); + } + SAFE_FREE(test_ctx->tmpdir); + SAFE_FREE(test_ctx->test_esys_ctx.tpm_state); + SAFE_FREE(test_ctx); + } +} /** * This program is a template for integration tests (ones that use the TCTI, @@ -485,41 +1467,95 @@ main(int argc, char *argv[]) char *config_path = NULL; char *config_env = NULL; char *remove_cmd = NULL; - char *system_dir = NULL; + TSS2_TEST_FAPI_CONTEXT *test_ctx = NULL; - char template[] = "/tmp/fapi_tmpdir.XXXXXX"; + TSS2_TEST_ESYS_CONTEXT *test_esys_ctx; - tmpdir = mkdtemp(template); + ret = test_esys_setup(&test_esys_ctx); + if (ret != 0) { + return ret; + } +#if !defined(FAPI_NONTPM) && !defined(DLOPEN) && defined(SELF_GENERATED_CERTIFICATE) && \ + !defined(FAPI_TEST_FINGERPRINT) && !defined(FAPI_TEST_FINGERPRINT_ECC) + TSS2_SYS_CONTEXT *sys_ctx; + TSS2_RC rc; - if (!tmpdir) { - LOG_ERROR("No temp dir created"); + rc = Esys_GetSysContext(test_esys_ctx->esys_ctx, &sys_ctx); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get SysContext: %s\n", Tss2_RC_Decode(rc)); + ret = 1; + goto error; + } + rc = init_ek_certificates(sys_ctx); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to initialize EK certificates: %s\n", + Tss2_RC_Decode(rc)); + ret = 1; + goto error; + } +#else + char *ecc_fingerprint = NULL; + char *rsa_fingerprint = NULL; + TSS2_SYS_CONTEXT *sys_ctx; + TSS2_RC rc; + + rc = Esys_GetSysContext(test_esys_ctx->esys_ctx, &sys_ctx); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to get SysContext: %s\n", Tss2_RC_Decode(rc)); return EXIT_ERROR; } - ret = init_fapi(FAPI_PROFILE, &global_fapi_context); - if (ret) + + rc = get_ek_fingerprints(sys_ctx, &rsa_fingerprint, &ecc_fingerprint); + if (rc != TSS2_RC_SUCCESS) { + return EXIT_ERROR; + } + setenv("FAPI_TEST_FINGERPRINT", rsa_fingerprint, 1); + setenv("FAPI_TEST_FINGERPRINT_ECC", ecc_fingerprint, 1); + free(rsa_fingerprint); + free(ecc_fingerprint); +#endif + + test_esys_teardown(test_esys_ctx); + + ret = test_fapi_setup(&test_ctx); + if (ret != 0) { goto error; + } - ret = test_invoke_fapi(global_fapi_context); +#if !defined(FAPI_NONTPM) && !defined(DLOPEN) + ret = test_fapi_checks_pre(test_ctx); + if (ret != 0) { + goto error; + } +#endif + ret = test_invoke_fapi(test_ctx->fapi_ctx); LOG_INFO("Test returned %i", ret); if (ret) goto error; - size = asprintf(&remove_cmd, "rm -r -f %s", tmpdir); +#if !defined(FAPI_NONTPM) && !defined(DLOPEN) + test_ctx->test_esys_ctx.esys_ctx = test_ctx->fapi_ctx->esys; + ret = test_fapi_checks_post(test_ctx); + if (ret != 0) { + goto error; + } + +#endif + + size = asprintf(&remove_cmd, "rm -r -f %s", test_ctx->tmpdir); if (size < 0) { LOG_ERROR("Out of memory"); ret = EXIT_ERROR; goto error; } if (system(remove_cmd) != 0) { - LOG_ERROR("Directory %s can't be deleted.", tmpdir); + LOG_ERROR("Directory %s can't be deleted.", test_ctx->tmpdir); ret = EXIT_ERROR; goto error; } error: - Fapi_Finalize(&global_fapi_context); - - if (system_dir) free(system_dir); + test_fapi_teardown(test_ctx); if (config) free(config); if (config_path) free(config_path); if (config_env) free(config_env); diff --git a/test/integration/main-sys.c b/test/integration/main-sys.c index 351247c..613cd98 100644 --- a/test/integration/main-sys.c +++ b/test/integration/main-sys.c @@ -12,15 +12,16 @@ #include #define LOGMODULE test +#include "tss2_tctildr.h" #include "tss2_sys.h" #include "util/log.h" #include "test.h" -#include "test-options.h" -#include "context-util.h" + +#include "test-common.h" /** * This program is a template for integration tests (ones that use the TCTI - * and the SYS contexts / API directly). It does nothing more than parsing + * and the SYS ctxs / API directly). It does nothing more than parsing * command line options that allow the caller (likely a script) to specify * which TCTI to use for the test. */ @@ -28,38 +29,35 @@ int main (int argc, char *argv[]) { - TSS2_SYS_CONTEXT *sys_context; + TSS2_TEST_SYS_CONTEXT *test_sys_ctx; + TSS2_RC rc; int ret; - test_opts_t opts = { - .tcti_type = TCTI_DEFAULT, - .device_file = DEVICE_PATH_DEFAULT, - .socket_address = HOSTNAME_DEFAULT, - .socket_port = PORT_DEFAULT, - }; UNUSED(argc); UNUSED(argv); - get_test_opts_from_env (&opts); - if (sanity_check_test_opts (&opts) != 0) { - LOG_ERROR("Checking test options"); - return 99; /* fatal error */ + ret = test_sys_setup(&test_sys_ctx); + if (ret != 0) { + return ret; } - sys_context = sys_init_from_opts (&opts); - if (sys_context == NULL) { - LOG_ERROR("SYS context not initialized"); - return 99; /* fatal error */ + + ret = test_sys_checks_pre(test_sys_ctx); + if (ret != 0) { + return ret; } - ret = Tss2_Sys_Startup(sys_context, TPM2_SU_CLEAR); - if (ret != TSS2_RC_SUCCESS && ret != TPM2_RC_INITIALIZE) { - LOG_ERROR("TPM Startup FAILED! Response Code : 0x%x", ret); - exit(1); + rc = test_invoke(test_sys_ctx->sys_ctx); + if (rc != 0 && ret != 77) { + LOG_ERROR("Test returned %08x", rc); + return rc; } - ret = test_invoke (sys_context); + ret = test_sys_checks_post(test_sys_ctx); + if (ret != 0) { + return ret; + } - sys_teardown_full (sys_context); + test_sys_teardown(test_sys_ctx); - return ret; + return rc; } diff --git a/test/integration/session-util.h b/test/integration/session-util.h index 3de4250..e89460e 100644 --- a/test/integration/session-util.h +++ b/test/integration/session-util.h @@ -57,7 +57,7 @@ tpm_calc_phash( UINT32 tpm_handle_to_name( - TSS2_TCTI_CONTEXT *tcti_context, + TSS2_SYS_CONTEXT *sysContext, TPM2_HANDLE handle, TPM2B_NAME *name); @@ -89,7 +89,7 @@ TSS2_RC create_auth_session( TPM2_SE sessionType, TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH algId, - TSS2_TCTI_CONTEXT *tctiContext); + TSS2_SYS_CONTEXT *sysContext); TSS2_RC compute_command_hmac( diff --git a/test/integration/sys-abi-version.int.c b/test/integration/sys-abi-version.int.c index 676bc87..b188c78 100644 --- a/test/integration/sys-abi-version.int.c +++ b/test/integration/sys-abi-version.int.c @@ -15,13 +15,9 @@ #include #define LOGMODULE test #include "util/log.h" +#include "test-common.h" #include "test.h" -#define TSSWG_INTEROP 1 -#define TSS_SYS_FIRST_FAMILY 2 -#define TSS_SYS_FIRST_LEVEL 1 -#define TSS_SYS_FIRST_VERSION 108 - /** */ int @@ -30,7 +26,7 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) TSS2_RC rc; UINT32 contextSize; TSS2_TCTI_CONTEXT *tcti_context = NULL; - TSS2_ABI_VERSION tstAbiVersion = { TSSWG_INTEROP, TSS_SYS_FIRST_FAMILY, TSS_SYS_FIRST_LEVEL, TSS_SYS_FIRST_VERSION }; + TSS2_ABI_VERSION tstAbiVersion = TEST_ABI_VERSION; LOG_INFO( "ABI NEGOTIATION TESTS" ); diff --git a/test/integration/sys-context-util.c b/test/integration/sys-context-util.c deleted file mode 100644 index 896e45f..0000000 --- a/test/integration/sys-context-util.c +++ /dev/null @@ -1,296 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/*********************************************************************** - * Copyright (c) 2017-2018, Intel Corporation - * - * All rights reserved. - ***********************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include - -#include "tss2_tcti_device.h" -#include "tss2_tcti_mssim.h" -#include "tss2_tcti_swtpm.h" -#ifdef TCTI_FUZZING -#include "tss2_tcti_fuzzing.h" -#endif /* TCTI_FUZZING */ - -#include "context-util.h" -#include "tss2-tcti/tcti-mssim.h" -#include "tss2-tcti/tcti-swtpm.h" - -#ifdef TCTI_DEVICE -/* - * Initialize a TSS2_TCTI_CONTEXT for the device TCTI. - */ -TSS2_TCTI_CONTEXT * -tcti_device_init(char const *device_path) -{ - size_t size; - TSS2_RC rc; - TSS2_TCTI_CONTEXT *tcti_ctx; - - rc = Tss2_Tcti_Device_Init(NULL, &size, 0); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, - "Failed to get allocation size for device tcti context: " - "0x%x\n", rc); - return NULL; - } - tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc(1, size); - if (tcti_ctx == NULL) { - fprintf(stderr, - "Allocation for device TCTI context failed: %s\n", - strerror(errno)); - return NULL; - } - rc = Tss2_Tcti_Device_Init(tcti_ctx, &size, device_path); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Failed to initialize device TCTI context: 0x%x\n", rc); - free(tcti_ctx); - return NULL; - } - return tcti_ctx; -} -#endif /* TCTI_DEVICE */ - -#ifdef TCTI_MSSIM -/* - * Initialize a socket TCTI instance using the provided options structure. - * The hostname and port are the only configuration options used. - * The caller is returned a TCTI context structure that is allocated by this - * function. This structure must be freed by the caller. - */ -TSS2_TCTI_CONTEXT * -tcti_socket_init(char const *host, uint16_t port) -{ - size_t size; - TSS2_RC rc; - TSS2_TCTI_CONTEXT *tcti_ctx; - char conf_str[TCTI_MSSIM_CONF_MAX] = { 0 }; - - snprintf(conf_str, TCTI_MSSIM_CONF_MAX, "host=%s,port=%" PRIu16, host, port); - rc = Tss2_Tcti_Mssim_Init(NULL, &size, conf_str); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Faled to get allocation size for tcti context: " - "0x%x\n", rc); - return NULL; - } - tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc(1, size); - if (tcti_ctx == NULL) { - fprintf(stderr, "Allocation for tcti context failed: %s\n", - strerror(errno)); - return NULL; - } - rc = Tss2_Tcti_Mssim_Init(tcti_ctx, &size, conf_str); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Failed to initialize tcti context: 0x%x\n", rc); - free(tcti_ctx); - return NULL; - } - return tcti_ctx; -} -#endif /* TCTI_MSSIM */ - -#ifdef TCTI_SWTPM -/* - * Initialize a socket TCTI instance using the provided options structure. - * The hostname and port are the only configuration options used. - * The caller is returned a TCTI context structure that is allocated by this - * function. This structure must be freed by the caller. - */ -TSS2_TCTI_CONTEXT * -tcti_swtpm_init(char const *host, uint16_t port) -{ - size_t size; - TSS2_RC rc; - TSS2_TCTI_CONTEXT *tcti_ctx; - char conf_str[TCTI_SWTPM_CONF_MAX] = { 0 }; - - snprintf(conf_str, TCTI_SWTPM_CONF_MAX, "host=%s,port=%" PRIu16, host, port); - rc = Tss2_Tcti_Swtpm_Init(NULL, &size, conf_str); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Faled to get allocation size for tcti context: " - "0x%x\n", rc); - return NULL; - } - tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc(1, size); - if (tcti_ctx == NULL) { - fprintf(stderr, "Allocation for tcti context failed: %s\n", - strerror(errno)); - return NULL; - } - rc = Tss2_Tcti_Swtpm_Init(tcti_ctx, &size, conf_str); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Failed to initialize tcti context: 0x%x\n", rc); - free(tcti_ctx); - return NULL; - } - return tcti_ctx; -} -#endif /* TCTI_SWTPM */ - -#ifdef TCTI_FUZZING -/* - * Initialize a fuzzing TCTI instance using the provided options structure. - * The fuzzing_lengths.log file is the only configuration option used. - * The caller is returned a TCTI context structure that is allocated by this - * function. This structure must be freed by the caller. - */ -TSS2_TCTI_CONTEXT * -tcti_fuzzing_init() -{ - size_t size; - TSS2_RC rc; - TSS2_TCTI_CONTEXT *tcti_ctx; - - rc = Tss2_Tcti_Fuzzing_Init(NULL, &size, NULL); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Faled to get allocation size for tcti context: " - "0x%x\n", rc); - return NULL; - } - tcti_ctx = (TSS2_TCTI_CONTEXT *) calloc(1, size); - if (tcti_ctx == NULL) { - fprintf(stderr, "Allocation for tcti context failed: %s\n", - strerror(errno)); - return NULL; - } - rc = Tss2_Tcti_Fuzzing_Init(tcti_ctx, &size, NULL); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Failed to initialize tcti context: 0x%x\n", rc); - free(tcti_ctx); - return NULL; - } - return tcti_ctx; -} -#endif /* TCTI_FUZZING */ - -/* - * Initialize a SYS context using the TCTI context provided by the caller. - * This function allocates memory for the SYS context and returns it to the - * caller. This memory must be freed by the caller. - */ -TSS2_SYS_CONTEXT * -sys_init_from_tcti_ctx(TSS2_TCTI_CONTEXT * tcti_ctx) -{ - TSS2_SYS_CONTEXT *sys_ctx; - TSS2_RC rc; - size_t size; - TSS2_ABI_VERSION abi_version = { - .tssCreator = 1, - .tssFamily = 2, - .tssLevel = 1, - .tssVersion = 108, - }; - - size = Tss2_Sys_GetContextSize(0); - sys_ctx = (TSS2_SYS_CONTEXT *) calloc(1, size); - if (sys_ctx == NULL) { - fprintf(stderr, - "Failed to allocate 0x%zx bytes for the SYS context\n", size); - return NULL; - } - rc = Tss2_Sys_Initialize(sys_ctx, size, tcti_ctx, &abi_version); - if (rc != TSS2_RC_SUCCESS) { - fprintf(stderr, "Failed to initialize SYS context: 0x%x\n", rc); - free(sys_ctx); - return NULL; - } - return sys_ctx; -} - -/* - * Initialize a SYS context to use a socket TCTI. Get configuration data from - * the provided structure. - */ -TSS2_SYS_CONTEXT * -sys_init_from_opts(test_opts_t * options) -{ - TSS2_TCTI_CONTEXT *tcti_ctx; - TSS2_SYS_CONTEXT *sys_ctx; - - tcti_ctx = tcti_init_from_opts(options); - if (tcti_ctx == NULL) - return NULL; - sys_ctx = sys_init_from_tcti_ctx(tcti_ctx); - if (sys_ctx == NULL) - return NULL; - return sys_ctx; -} - -/* - * Initialize a TSS2_TCTI_CONTEXT using whatever TCTI data is in the options - * structure. This is a mechanism that allows the calling application to be - * mostly ignorant of which TCTI they're creating / initializing. - */ -TSS2_TCTI_CONTEXT * -tcti_init_from_opts(test_opts_t * options) -{ - switch (options->tcti_type) { -#ifdef TCTI_DEVICE - case DEVICE_TCTI: - return tcti_device_init(options->device_file); -#endif /* TCTI_DEVICE */ -#ifdef TCTI_MSSIM - case SOCKET_TCTI: - return tcti_socket_init(options->socket_address, options->socket_port); -#endif /* TCTI_MSSIM */ -#ifdef TCTI_SWTPM - case SWTPM_TCTI: - return tcti_swtpm_init(options->socket_address, options->socket_port); -#endif /* TCTI_SWTPM */ -#ifdef TCTI_FUZZING - case FUZZING_TCTI: - return tcti_fuzzing_init(); -#endif /* TCTI_FUZZING */ - default: - return NULL; - } -} - -/* - * Teardown / Finalize TCTI context and free memory. - */ -void -tcti_teardown(TSS2_TCTI_CONTEXT * tcti_context) -{ - if (tcti_context) { - Tss2_Tcti_Finalize(tcti_context); - free(tcti_context); - } -} - -/* - * Teardown and free the resources associated with a SYS context structure. - */ -void -sys_teardown(TSS2_SYS_CONTEXT * sys_context) -{ - Tss2_Sys_Finalize(sys_context); - free(sys_context); -} - -/* - * Teardown and free the resources associated with a SYS context structure. - * This includes tearing down the TCTI as well. - */ -void -sys_teardown_full(TSS2_SYS_CONTEXT * sys_context) -{ - TSS2_TCTI_CONTEXT *tcti_context = NULL; - TSS2_RC rc; - - rc = Tss2_Sys_GetTctiContext(sys_context, &tcti_context); - if (rc != TSS2_RC_SUCCESS) - return; - - sys_teardown(sys_context); - tcti_teardown(tcti_context); -} diff --git a/test/integration/sys-hmac-auth.int.c b/test/integration/sys-hmac-auth.int.c index 686fd1b..8ab6d47 100644 --- a/test/integration/sys-hmac-auth.int.c +++ b/test/integration/sys-hmac-auth.int.c @@ -15,7 +15,6 @@ #include "tss2_sys.h" -#include "context-util.h" #include "sys-util.h" #include "session-util.h" #define LOGMODULE test @@ -40,13 +39,6 @@ create_policy (TSS2_SYS_CONTEXT *sys_ctx, TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_NULL, }; - TSS2_TCTI_CONTEXT *tcti_ctx; - - rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx); - if (rc != TSS2_RC_SUCCESS || tcti_ctx == NULL) { - LOG_ERROR("InitSysContext failed, exiting..."); - return rc; - } rc = create_auth_session (&trialPolicySession, TPM2_RH_NULL, @@ -58,7 +50,7 @@ create_policy (TSS2_SYS_CONTEXT *sys_ctx, TPM2_SE_TRIAL, &symmetric, TPM2_ALG_SHA256, - tcti_ctx); + sys_ctx); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("create_auth_session failed with rc: 0x%x", rc); return rc; @@ -116,7 +108,6 @@ nv_rw_with_session ( TPMT_SYM_DEF symmetric = { .algorithm = TPM2_ALG_NULL, }; - TSS2_TCTI_CONTEXT *tcti_ctx; TSS2L_SYS_AUTH_RESPONSE nvRspAuths; TSS2L_SYS_AUTH_COMMAND nvCmdAuths = { .count = 1, @@ -141,12 +132,6 @@ nv_rw_with_session ( }; - rc = Tss2_Sys_GetTctiContext (sys_ctx, &tcti_ctx); - if (rc != TSS2_RC_SUCCESS || tcti_ctx == NULL) { - LOG_ERROR ("Failed to get TCTI from Sys context, got RC: 0x%x", rc); - return TSS2_SYS_RC_GENERAL_FAILURE; - } - rc = DefineNvIndex (sys_ctx, TPM2_RH_PLATFORM, &nvAuth, @@ -172,7 +157,7 @@ nv_rw_with_session ( } /* Get the name of the NV index. */ - rc = tpm_handle_to_name (tcti_ctx, + rc = tpm_handle_to_name (sys_ctx, TPM20_INDEX_PASSWORD_TEST, &nvName); if (rc != TSS2_RC_SUCCESS) { @@ -196,7 +181,7 @@ nv_rw_with_session ( session_type, &symmetric, TPM2_ALG_SHA256, - tcti_ctx); + sys_ctx); if (rc != TSS2_RC_SUCCESS) { LOG_ERROR ("create_auth_session failed with RC: 0x%x", rc); return rc; @@ -209,7 +194,7 @@ nv_rw_with_session ( * Get the name of the session and save it in * the nvSession structure. */ - rc = tpm_handle_to_name (tcti_ctx, + rc = tpm_handle_to_name (sys_ctx, nvSession->sessionHandle, &nvSession->name); if (rc != TSS2_RC_SUCCESS) { diff --git a/test/integration/sys-nv-policy-locality.int.c b/test/integration/sys-nv-policy-locality.int.c index e342c45..409f835 100644 --- a/test/integration/sys-nv-policy-locality.int.c +++ b/test/integration/sys-nv-policy-locality.int.c @@ -16,7 +16,6 @@ #include "tss2_sys.h" -#include "context-util.h" #include "sys-util.h" #include "util/aux_util.h" #define LOGMODULE test diff --git a/test/integration/sys-nv-readwrite.int.c b/test/integration/sys-nv-readwrite.int.c index e706118..27b43e9 100644 --- a/test/integration/sys-nv-readwrite.int.c +++ b/test/integration/sys-nv-readwrite.int.c @@ -14,7 +14,6 @@ #include "tss2_sys.h" -#include "context-util.h" #include "sys-util.h" #include "session-util.h" #include "util/aux_util.h" diff --git a/test/integration/sys-param-encrypt-decrypt.int.c b/test/integration/sys-param-encrypt-decrypt.int.c index e12ee40..3f0b3dc 100644 --- a/test/integration/sys-param-encrypt-decrypt.int.c +++ b/test/integration/sys-param-encrypt-decrypt.int.c @@ -14,7 +14,6 @@ #include #include "tss2_sys.h" -#include "context-util.h" #include "sys-util.h" #include "session-util.h" #define LOGMODULE test @@ -29,7 +28,6 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) { TSS2_RC rc, rc2; SESSION *session; - TSS2_TCTI_CONTEXT *tcti_ctx; TPM2B_MAX_NV_BUFFER data_to_write, data_read; TPM2B_MAX_BUFFER encrypted_param, decrypted_param; TPMI_RH_NV_INDEX nv_index = TPM2_HR_NV_INDEX | 0x01; @@ -59,12 +57,6 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) LOG_INFO("param-encrypt-decrypt test"); - rc = Tss2_Sys_GetTctiContext(sys_context, &tcti_ctx); - if (rc) { - LOG_ERROR("Tss2_Sys_GetTctiContext failed 0x%" PRIx32, rc); - return rc; - } - nv_public.size = 0; nv_public.nvPublic.attributes = nv_attribs; CopySizedByteBuffer((TPM2B *)&nv_public.nvPublic.authPolicy, (TPM2B *)&policy_auth); @@ -86,7 +78,7 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) retry: rc = create_auth_session(&session, TPM2_RH_NULL, 0, TPM2_RH_NULL, 0, &nonce_caller, 0, TPM2_SE_POLICY, - &symmetric, TPM2_ALG_SHA256, tcti_ctx); + &symmetric, TPM2_ALG_SHA256, sys_context); if (rc) { LOG_ERROR("create_auth_session failed 0x%" PRIx32, rc); goto clean; diff --git a/test/integration/sys-pcr-extension.int.c b/test/integration/sys-pcr-extension.int.c index f4c2d15..537b80c 100644 --- a/test/integration/sys-pcr-extension.int.c +++ b/test/integration/sys-pcr-extension.int.c @@ -19,6 +19,7 @@ #include "test.h" #include "sys-util.h" #define PCR_8 8 +#define EXIT_SKIP 77 /** * This program contains integration test for SYS Tss2_Sys_PCR_Read * and Tss2_Sys_PCR_Extend. This is an use case scenario on PCR extend. @@ -37,8 +38,8 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) TPML_PCR_SELECTION pcr_selection; UINT32 pcr_update_counter_before_extend; UINT32 pcr_update_counter_after_extend; - UINT8 pcr_before_extend[20]; - UINT8 pcr_after_extend[20]; + UINT8 pcr_before_extend[TPM2_SHA256_DIGEST_SIZE]; + UINT8 pcr_after_extend[TPM2_SHA256_DIGEST_SIZE]; TPML_DIGEST pcr_values; TPML_DIGEST_VALUES digests; TPML_PCR_SELECTION pcr_selection_out; @@ -57,15 +58,15 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) exit(1); } digests.count = 1; - digests.digests[0].hashAlg = TPM2_ALG_SHA1; + digests.digests[0].hashAlg = TPM2_ALG_SHA256; digest_size = GetDigestSize( digests.digests[0].hashAlg ); for( i = 0; i < digest_size; i++ ) { - digests.digests[0].digest.sha1[i] = (UINT8)(i % 256); + digests.digests[0].digest.sha256[i] = (UINT8)(i % 256); } pcr_selection.count = 1; - pcr_selection.pcrSelections[0].hash = TPM2_ALG_SHA1; + pcr_selection.pcrSelections[0].hash = TPM2_ALG_SHA256; pcr_selection.pcrSelections[0].sizeofSelect = 3; pcr_selection.pcrSelections[0].pcrSelect[0] = 0; pcr_selection.pcrSelections[0].pcrSelect[1] = 0; @@ -77,6 +78,11 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) LOG_ERROR("PCR_Read FAILED! Response Code : 0x%x", rc); exit(1); } + if (!pcr_selection_out.pcrSelections[0].pcrSelect[PCR_8 / 8]) { + LOG_ERROR("PCR register not supported."); + return(EXIT_SKIP); + } + memcpy(&(pcr_before_extend[0]), &(pcr_values.digests[0].buffer[0]), pcr_values.digests[0].size); rc = Tss2_Sys_PCR_Extend(sys_context, PCR_8, &sessions_data, &digests, 0); @@ -89,13 +95,13 @@ test_invoke (TSS2_SYS_CONTEXT *sys_context) LOG_ERROR("PCR_Read FAILED! Response Code : 0x%x", rc); exit(1); } - memcpy(&(pcr_after_extend[0]), &(pcr_values.digests[0].buffer[0]), pcr_values.digests[0].size); + memcpy(&(pcr_after_extend[0]), &(pcr_values.digests[0].buffer[0]), pcr_values.digests[0].size); if(pcr_update_counter_before_extend == pcr_update_counter_after_extend) { LOG_ERROR("ERROR!! pcr_update_counter didn't change value"); exit(1); } - if(memcmp(&(pcr_before_extend[0]), &(pcr_after_extend[0]), 20) == 0) { + if(memcmp(&(pcr_before_extend[0]), &(pcr_after_extend[0]), TPM2_SHA256_DIGEST_SIZE) == 0) { LOG_ERROR("ERROR!! PCR didn't change value"); exit(1); } diff --git a/test/integration/sys-session-util.c b/test/integration/sys-session-util.c index 87787e9..d488f3f 100644 --- a/test/integration/sys-session-util.c +++ b/test/integration/sys-session-util.c @@ -10,9 +10,10 @@ #include +#include "tss2_tcti.h" +#include "test-common.h" #include "session-util.h" #include "sys-util.h" -#include "context-util.h" #include "util/tss2_endian.h" #define LOGMODULE test #include "util/log.h" @@ -31,19 +32,15 @@ get_session(TPMI_SH_AUTH_SESSION hndl) static TSS2_RC start_auth_session( SESSION *session, - TSS2_TCTI_CONTEXT *tctiContext) + TSS2_SYS_CONTEXT *sys_context) { TSS2_RC rval; TPM2B_ENCRYPTED_SECRET key; char label[] = "ATH"; - TSS2_SYS_CONTEXT *tmp_context; UINT16 bytes; key.size = 0; - tmp_context = sys_init_from_tcti_ctx(tctiContext); - if (tmp_context == NULL) - return TSS2_SYS_RC_GENERAL_FAILURE; if (session->nonceOlder.size == 0) session->nonceOlder.size = GetDigestSize(session->authHash); @@ -54,13 +51,13 @@ start_auth_session( session->nonceTpmEncrypt.size = 0; rval = Tss2_Sys_StartAuthSession( - tmp_context, session->tpmKey, session->bind, 0, + sys_context, session->tpmKey, session->bind, 0, &session->nonceOlder, &session->encryptedSalt, session->sessionType, &session->symmetric, session->authHash, &session->sessionHandle, &session->nonceNewer, 0); if (rval != TPM2_RC_SUCCESS) - goto out; + return rval; if (session->tpmKey == TPM2_RH_NULL) session->salt.size = 0; @@ -70,21 +67,21 @@ start_auth_session( session->sessionKey.size = 0; if (session->tpmKey == TPM2_RH_NULL && session->bind == TPM2_RH_NULL) - goto out; + return rval; /* Generate the key used as input to the KDF. */ rval = ConcatSizedByteBuffer((TPM2B_MAX_BUFFER *)&key, (TPM2B *)&session->authValueBind); if (rval != TPM2_RC_SUCCESS) { - Tss2_Sys_FlushContext(tmp_context, session->sessionHandle); - goto out; + Tss2_Sys_FlushContext(sys_context, session->sessionHandle); + return rval; } rval = ConcatSizedByteBuffer((TPM2B_MAX_BUFFER *)&key, (TPM2B *)&session->salt); if (rval != TPM2_RC_SUCCESS) { - Tss2_Sys_FlushContext(tmp_context, session->sessionHandle); - goto out; + Tss2_Sys_FlushContext(sys_context, session->sessionHandle); + return rval; } bytes = GetDigestSize(session->authHash) * 8; @@ -93,8 +90,7 @@ start_auth_session( (TPM2B *)&session->nonceNewer, (TPM2B *)&session->nonceOlder, bytes, (TPM2B_MAX_BUFFER *)&session->sessionKey); -out: - sys_teardown(tmp_context); + return rval; } @@ -121,12 +117,16 @@ compute_session_auth( rval = tpm_calc_phash(sysContext, handle1, handle2, handle3, session->authHash, command, &pHash); - if (rval != TPM2_RC_SUCCESS) + if (rval != TPM2_RC_SUCCESS) { + LOG_ERROR ("tpm_calc_phash failed with RC: 0x%x", rval); return rval; + } rval = Tss2_Sys_GetCommandCode(sysContext, (UINT8 *)&cmdCode); - if (rval != TPM2_RC_SUCCESS) + if (rval != TPM2_RC_SUCCESS) { + LOG_ERROR ("Tss2_Sys_GetCommandCode failed with RC: 0x%x", rval); return rval; + } /* cmdCode comes back as BigEndian; not suited for comparisons below. */ cmdCode = BE_TO_HOST_32(cmdCode); @@ -206,8 +206,10 @@ compute_command_hmac( handle2, handle3, &hmac_key); - if (rval != TPM2_RC_SUCCESS) + if (rval != TPM2_RC_SUCCESS) { + LOG_ERROR ("compute_session_auth failed with RC: 0x%x", rval); break; + } } return rval; } @@ -281,7 +283,7 @@ TSS2_RC create_auth_session( TPM2_SE sessionType, TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH algId, - TSS2_TCTI_CONTEXT *tctiContext) + TSS2_SYS_CONTEXT *sysContext) { TSS2_RC rval; SESSION *session, *tmp; @@ -309,7 +311,7 @@ TSS2_RC create_auth_session( if (session->tpmKey != TPM2_RH_NULL) CopySizedByteBuffer((TPM2B *)&session->salt, (TPM2B *)salt); - rval = start_auth_session(session, tctiContext); + rval = start_auth_session(session, sysContext); if (rval != TSS2_RC_SUCCESS) { free(session); return rval; @@ -336,6 +338,39 @@ void roll_nonces(SESSION *session, TPM2B_NONCE *new_nonce) session->nonceNewer = *new_nonce; } +/* + * Create a new SysContext from the TCTI of an existing one. + * This is needed where we need to keep the state of the existing SysContext. + */ +TSS2_RC +sys_context_from_sys_context( + TSS2_SYS_CONTEXT *sysContext, + TSS2_SYS_CONTEXT **newSysContext) +{ + TSS2_ABI_VERSION abiVersion = TEST_ABI_VERSION; + TSS2_TCTI_CONTEXT *tctiContext; + TSS2_RC rval = TPM2_RC_SUCCESS; + size_t size; + + rval = Tss2_Sys_GetTctiContext (sysContext, &tctiContext); + if( rval != TSS2_RC_SUCCESS ) { + return rval; + } + + size = Tss2_Sys_GetContextSize(0); + *newSysContext = (TSS2_SYS_CONTEXT *) calloc(1, size); + if (*newSysContext == NULL) { + return 1; + } + rval = Tss2_Sys_Initialize(*newSysContext, size, tctiContext, &abiVersion); + if (rval != TSS2_RC_SUCCESS) { + free(*newSysContext); + return rval; + } + + return TPM2_RC_SUCCESS; +} + TSS2_RC tpm_calc_phash( TSS2_SYS_CONTEXT *sysContext, @@ -347,7 +382,6 @@ tpm_calc_phash( TPM2B_DIGEST *pHash) { TSS2_RC rval = TPM2_RC_SUCCESS; - TSS2_TCTI_CONTEXT *tcti_context; UINT32 i; TPM2B_NAME name1, name2, name3; TPM2B_MAX_BUFFER hashInput; @@ -355,26 +389,34 @@ tpm_calc_phash( size_t parametersSize; const uint8_t *startParams; TPM2_CC cmdCode; + TSS2_SYS_CONTEXT *sysContextCopy; name1.size = 0; name2.size = 0; name3.size = 0; hashInput.size = 0; - rval = Tss2_Sys_GetTctiContext(sysContext, &tcti_context); - if (rval != TPM2_RC_SUCCESS) - return rval; - if (command) { - rval = tpm_handle_to_name(tcti_context, handle1, &name1); + rval = sys_context_from_sys_context(sysContext, &sysContextCopy); + if (rval != TPM2_RC_SUCCESS) { + return rval; + } + + rval = tpm_handle_to_name(sysContextCopy, handle1, &name1); if (rval != TPM2_RC_SUCCESS) - return rval; + goto cleanup_sys_context_copy; - rval = tpm_handle_to_name(tcti_context, handle2, &name2); + rval = tpm_handle_to_name(sysContextCopy, handle2, &name2); if (rval != TPM2_RC_SUCCESS) - return rval; + goto cleanup_sys_context_copy; - rval = tpm_handle_to_name(tcti_context, handle3, &name3); + rval = tpm_handle_to_name(sysContextCopy, handle3, &name3); + if (rval != TPM2_RC_SUCCESS) + goto cleanup_sys_context_copy; + +cleanup_sys_context_copy: + Tss2_Sys_Finalize(sysContextCopy); + free(sysContextCopy); if (rval != TPM2_RC_SUCCESS) return rval; @@ -433,7 +475,7 @@ tpm_calc_phash( } UINT32 tpm_handle_to_name( - TSS2_TCTI_CONTEXT *tcti_context, + TSS2_SYS_CONTEXT *sysContext, TPM2_HANDLE handle, TPM2B_NAME *name) { @@ -441,10 +483,9 @@ UINT32 tpm_handle_to_name( TPM2B_NAME qualified_name = TPM2B_NAME_INIT; TPM2B_PUBLIC public; TPM2B_NV_PUBLIC nvPublic; - TSS2_SYS_CONTEXT *sysContext; UINT8 *namePtr; - if (!tcti_context || !name) + if (!sysContext || !name) return TSS2_SYS_RC_BAD_VALUE; namePtr = name->name; @@ -457,26 +498,16 @@ UINT32 tpm_handle_to_name( switch(handle >> TPM2_HR_SHIFT) { case TPM2_HT_NV_INDEX: - sysContext = sys_init_from_tcti_ctx(tcti_context); - if (sysContext == NULL) - return TSS2_SYS_RC_GENERAL_FAILURE; - nvPublic.size = 0; rval = Tss2_Sys_NV_ReadPublic(sysContext, handle, 0, &nvPublic, name, 0); - sys_teardown(sysContext); break; case TPM2_HT_TRANSIENT: case TPM2_HT_PERSISTENT: - sysContext = sys_init_from_tcti_ctx(tcti_context); - if (sysContext == NULL) - return TSS2_SYS_RC_GENERAL_FAILURE; - public.size = 0; rval = Tss2_Sys_ReadPublic(sysContext, handle, 0, &public, name, &qualified_name, 0); - sys_teardown(sysContext); break; default: diff --git a/test/integration/sys-test-options.c b/test/integration/sys-test-options.c deleted file mode 100644 index eaf4349..0000000 --- a/test/integration/sys-test-options.c +++ /dev/null @@ -1,155 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/*********************************************************************** - * Copyright (c) 2017-2018, Intel Corporation - * - * All rights reserved. - ***********************************************************************/ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "test-options.h" - -/* - * A structure to map a string name to an element in the TCTI_TYPE - * enumeration. - */ -typedef struct { - char *name; - TCTI_TYPE type; -} tcti_map_entry_t; -/* - * A table of tcti_map_entry_t structures. This is how we map a string - * provided on the command line to the enumeration. - */ -tcti_map_entry_t tcti_map_table[] = { - { - .name = "device", - .type = DEVICE_TCTI, - }, - { - .name = "socket", - .type = SOCKET_TCTI, - }, - { - .name = "swtpm", - .type = SWTPM_TCTI, - }, - { - .name = "fuzzing", - .type = FUZZING_TCTI, - }, - { - .name = "unknown", - .type = UNKNOWN_TCTI, - }, -}; - -/* - * Convert from a string to an element in the TCTI_TYPE enumeration. - * An unknown name / string will map to UNKNOWN_TCTI. - */ -TCTI_TYPE -tcti_type_from_name(char const *tcti_str) -{ - int i; - for (i = 0; i < N_TCTI; ++i) - if (strcmp(tcti_str, tcti_map_table[i].name) == 0) - return tcti_map_table[i].type; - fprintf(stderr, "Unknown tcti %s.\n", tcti_str); - return UNKNOWN_TCTI; -} - -/* - * Convert from an element in the TCTI_TYPE enumeration to a string - * representation. - */ -const char * -tcti_name_from_type(TCTI_TYPE tcti_type) -{ - int i; - for (i = 0; i < N_TCTI; ++i) - if (tcti_type == tcti_map_table[i].type) - return tcti_map_table[i].name; - return NULL; -} - -/* - * return 0 if sanity test passes - * return 1 if sanity test fails - */ -int -sanity_check_test_opts(test_opts_t * opts) -{ - switch (opts->tcti_type) { - case DEVICE_TCTI: - if (opts->device_file == NULL) { - fprintf(stderr, "device-path is NULL, check env\n"); - return 1; - } - break; - case SOCKET_TCTI: - if (opts->socket_address == NULL || opts->socket_port == 0) { - fprintf(stderr, - "socket_address or socket_port is NULL, check env\n"); - return 1; - } - break; - case SWTPM_TCTI: - if (opts->socket_address == NULL || opts->socket_port == 0) { - fprintf(stderr, - "socket_address or socket_port is NULL, check env\n"); - return 1; - } - break; - case FUZZING_TCTI: - break; - default: - fprintf(stderr, "unknown TCTI type, check env\n"); - return 1; - } - return 0; -} - -/* - * Parse command line options from argv extracting test options. These are - * returned to the caller in the provided options structure. - */ -int -get_test_opts_from_env(test_opts_t * test_opts) -{ - char *env_str, *end_ptr; - - if (test_opts == NULL) - return 1; - env_str = getenv(ENV_TCTI_NAME); - if (env_str != NULL) - test_opts->tcti_type = tcti_type_from_name(env_str); - env_str = getenv(ENV_DEVICE_FILE); - if (env_str != NULL) - test_opts->device_file = env_str; - env_str = getenv(ENV_SOCKET_ADDRESS); - if (env_str != NULL) - test_opts->socket_address = env_str; - env_str = getenv(ENV_SOCKET_PORT); - if (env_str != NULL) - test_opts->socket_port = strtol(env_str, &end_ptr, 10); - return 0; -} - -/* - * Dump the contents of the test_opts_t structure to stdout. - */ -void -dump_test_opts(test_opts_t * opts) -{ - printf("test_opts_t:\n"); - printf(" tcti_type: %s\n", tcti_name_from_type(opts->tcti_type)); - printf(" device_file: %s\n", opts->device_file); - printf(" socket_address: %s\n", opts->socket_address); - printf(" socket_port: %d\n", opts->socket_port); -} diff --git a/test/integration/test-common.c b/test/integration/test-common.c new file mode 100644 index 0000000..f9f0dc6 --- /dev/null +++ b/test/integration/test-common.c @@ -0,0 +1,590 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*********************************************************************** + * Copyright (c) 2017-2018, Intel Corporation + * + * All rights reserved. + ***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + + +#include "tss2_tpm2_types.h" +#include "tss2_tctildr.h" +#include "tss2_mu.h" +#ifdef TEST_ESYS +#include "tss2_esys.h" +#endif +#define LOGMODULE test +#include "util/log.h" + +#include "test-common.h" + + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + + +struct { + TPM2_CAP cap; + UINT32 prop; + UINT32 count; +} capabilities_to_dump[] = { + {TPM2_CAP_PCRS, 0, 10}, + {TPM2_CAP_HANDLES, TPM2_HR_PCR, TPM2_MAX_CAP_HANDLES}, + {TPM2_CAP_HANDLES, TPM2_HR_HMAC_SESSION, TPM2_MAX_CAP_HANDLES}, + {TPM2_CAP_HANDLES, TPM2_HR_POLICY_SESSION, TPM2_MAX_CAP_HANDLES}, + {TPM2_CAP_HANDLES, TPM2_HR_TRANSIENT, TPM2_MAX_CAP_HANDLES}, + {TPM2_CAP_HANDLES, TPM2_HR_PERSISTENT, TPM2_MAX_CAP_HANDLES}, + {TPM2_CAP_HANDLES, TPM2_HR_NV_INDEX, TPM2_MAX_CAP_HANDLES}, +}; + +struct tpm_state { + TPMS_CAPABILITY_DATA capabilities[7]; +}; + +/** Define a proxy tcti that returns yielded on every second invocation + * thus the corresponding handling code in ESYS can be tested. + * The first invocation will be Tss2_Sys_StartUp. + */ +#ifdef TEST_ESYS + +TSS2_RC +(*transmit_hook) (const uint8_t *command_buffer, size_t command_size) = NULL; + +#define TCTI_PROXY_MAGIC 0x5250584f0a000000ULL /* 'PROXY\0\0\0' */ +#define TCTI_PROXY_VERSION 0x1 + +enum state { + forwarding, + intercepting +}; + +typedef struct { + uint64_t magic; + uint32_t version; + TSS2_TCTI_TRANSMIT_FCN transmit; + TSS2_TCTI_RECEIVE_FCN receive; + TSS2_RC (*finalize) (TSS2_TCTI_CONTEXT *tctiContext); + TSS2_RC (*cancel) (TSS2_TCTI_CONTEXT *tctiContext); + TSS2_RC (*getPollHandles) (TSS2_TCTI_CONTEXT *tctiContext, + TSS2_TCTI_POLL_HANDLE *handles, size_t *num_handles); + TSS2_RC (*setLocality) (TSS2_TCTI_CONTEXT *tctiContext, uint8_t locality); + TSS2_TCTI_CONTEXT *tctiInner; + enum state state; +} TSS2_TCTI_CONTEXT_PROXY; + +static TSS2_TCTI_CONTEXT_PROXY* +tcti_proxy_cast (TSS2_TCTI_CONTEXT *ctx) +{ + TSS2_TCTI_CONTEXT_PROXY *ctxi = (TSS2_TCTI_CONTEXT_PROXY*)ctx; + if (ctxi == NULL || ctxi->magic != TCTI_PROXY_MAGIC) { + LOG_ERROR("Bad tcti passed."); + return NULL; + } + return ctxi; +} + +static TSS2_RC +tcti_proxy_transmit( + TSS2_TCTI_CONTEXT *tctiContext, + size_t command_size, + const uint8_t *command_buffer + ) +{ + TSS2_RC rval; + TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); + + if (tcti_proxy->state == intercepting) { + return TSS2_RC_SUCCESS; + } + + if (transmit_hook != NULL) { + rval = transmit_hook(command_buffer, command_size); + if (rval != TSS2_RC_SUCCESS) { + LOG_ERROR("transmit hook requested error"); + return rval; + } + } + + rval = Tss2_Tcti_Transmit(tcti_proxy->tctiInner, command_size, + command_buffer); + if (rval != TSS2_RC_SUCCESS) { + LOG_ERROR("Calling TCTI Transmit"); + return rval; + } + + return rval; +} + +uint8_t yielded_response[] = { + 0x80, 0x01, /* TPM_ST_NO_SESSION */ + 0x00, 0x00, 0x00, 0x0A, /* Response Size 10 */ + 0x00, 0x00, 0x09, 0x08 /* TPM_RC_YIELDED */ +}; + +static TSS2_RC +tcti_proxy_receive( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *response_size, + uint8_t *response_buffer, + int32_t timeout + ) +{ + TSS2_RC rval; + TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = tcti_proxy_cast(tctiContext); + + if (tcti_proxy->state == intercepting) { + *response_size = sizeof(yielded_response); + + if (response_buffer != NULL) { + memcpy(response_buffer, &yielded_response[0], sizeof(yielded_response)); + tcti_proxy->state = forwarding; + } + return TSS2_RC_SUCCESS; + } + + rval = Tss2_Tcti_Receive(tcti_proxy->tctiInner, response_size, + response_buffer, timeout); + if (rval != TSS2_RC_SUCCESS) { + LOG_ERROR("Calling TCTI Transmit"); + return rval; + } + + /* First read with response buffer == NULL is to get the size of the + * response. The subsequent read needs to be forwarded also */ + if (response_buffer != NULL) + tcti_proxy->state = intercepting; + + return rval; +} + +static void +tcti_proxy_finalize( + TSS2_TCTI_CONTEXT *tctiContext) +{ + memset(tctiContext, 0, sizeof(TSS2_TCTI_CONTEXT_PROXY)); +} + +static TSS2_RC +tcti_proxy_initialize( + TSS2_TCTI_CONTEXT *tctiContext, + size_t *contextSize, + TSS2_TCTI_CONTEXT *tctiInner) +{ + TSS2_TCTI_CONTEXT_PROXY *tcti_proxy = + (TSS2_TCTI_CONTEXT_PROXY*) tctiContext; + + if (tctiContext == NULL && contextSize == NULL) { + return TSS2_TCTI_RC_BAD_VALUE; + } else if (tctiContext == NULL) { + *contextSize = sizeof(*tcti_proxy); + return TSS2_RC_SUCCESS; + } + + /* Init TCTI context */ + memset(tcti_proxy, 0, sizeof(*tcti_proxy)); + TSS2_TCTI_MAGIC (tctiContext) = TCTI_PROXY_MAGIC; + TSS2_TCTI_VERSION (tctiContext) = TCTI_PROXY_VERSION; + TSS2_TCTI_TRANSMIT (tctiContext) = tcti_proxy_transmit; + TSS2_TCTI_RECEIVE (tctiContext) = tcti_proxy_receive; + TSS2_TCTI_FINALIZE (tctiContext) = tcti_proxy_finalize; + TSS2_TCTI_CANCEL (tctiContext) = NULL; + TSS2_TCTI_GET_POLL_HANDLES (tctiContext) = NULL; + TSS2_TCTI_SET_LOCALITY (tctiContext) = NULL; + tcti_proxy->tctiInner = tctiInner; + tcti_proxy->state = forwarding; + + return TSS2_RC_SUCCESS; +} +#endif /* TEST_ESYS */ + +int +transient_empty(TSS2_SYS_CONTEXT *sys_ctx) +{ + TSS2_RC rc; + TPMS_CAPABILITY_DATA caps; + + do { + rc = Tss2_Sys_GetCapability(sys_ctx, + NULL, + TPM2_CAP_HANDLES, + TPM2_HR_TRANSIENT, + ARRAY_SIZE(caps.data.handles.handle), + NULL, + &caps, + NULL); + } while (rc == TPM2_RC_YIELDED); // TODO also for other cmds? + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM2_GetCapabilities failed: 0x%" PRIx32, rc); + return EXIT_ERROR; + } + + if (caps.data.handles.count) { + LOG_ERROR("TPM holds transient objects"); + for (UINT32 i = 0; i < caps.data.handles.count; i++) { + LOG_ERROR("Handle 0x%"PRIx32, caps.data.handles.handle[i]); + } + return EXIT_ERROR; + } + + return EXIT_SUCCESS; +} + +int +dumpstate(TSS2_SYS_CONTEXT *sys_ctx, tpm_state *state_first, bool compare) +{ + TSS2_RC rc; + tpm_state state_second; + tpm_state *states[] = {state_first, &state_second}; + TPMS_CAPABILITY_DATA *capabilities; + uint8_t buffer[2][sizeof(TPMS_CAPABILITY_DATA)]; + size_t off[2] = {0, 0}; + + if (!compare) { + /* capture and return first state */ + capabilities = state_first->capabilities; + } else { + /* capture second state and compare */ + capabilities = state_second.capabilities; + } + for (size_t i = 0; i < ARRAY_SIZE(capabilities_to_dump); i++) { + do { + rc = Tss2_Sys_GetCapability(sys_ctx, + NULL, + capabilities_to_dump[i].cap, + capabilities_to_dump[i].prop, + capabilities_to_dump[i].count, + NULL, + &capabilities[i], + NULL); + } while (rc == TPM2_RC_YIELDED); // TODO also for other cmds? + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("TPM2_GetCapabilities failed: 0x%" PRIx32, rc); + return EXIT_ERROR; + } + } + + if (!compare) { + return TPM2_RC_SUCCESS; + } + + for (int i = 0; i < (int) ARRAY_SIZE(capabilities_to_dump); i++) { + /* marshal both first and second for easy comparison */ + for (int j = 0; j < 2; j++) { + rc = Tss2_MU_TPMS_CAPABILITY_DATA_Marshal(&states[j]->capabilities[i], + buffer[j], + ARRAY_SIZE(buffer[j]), + &off[j]); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Marshaling failed: 0x%" PRIx32, rc); + return EXIT_ERROR; + } + } + + if (off[0] != off[1] || memcmp(buffer[0], buffer[1], off[0]) != 0) { + LOG_ERROR("TPM states are not equal for capability 0x%08x, property 0x%08x", + capabilities_to_dump[i].cap, + capabilities_to_dump[i].prop); + LOGBLOB_ERROR(buffer[0], off[0], "Before"); + LOGBLOB_ERROR(buffer[1], off[1], "After"); + + rc = EXIT_ERROR; + } + } + + return rc; +} + +int +test_sys_setup(TSS2_TEST_SYS_CONTEXT **test_ctx) +{ + TSS2_RC rc; + TSS2_ABI_VERSION abi_version = TEST_ABI_VERSION; + size_t size; + char *name_conf; + + size = sizeof(TSS2_TEST_SYS_CONTEXT); + *test_ctx = malloc(size); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for the test context", size); + goto fail; + } + + name_conf = getenv(ENV_TCTI); // TODO arg, then env? + if (!name_conf) { + LOG_ERROR("TCTI module not specified. Use environment variable: " ENV_TCTI); + goto cleanup_test_ctx; + } + + rc = Tss2_TctiLdr_Initialize(name_conf, &(*test_ctx)->tcti_ctx); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Error loading TCTI: %s", name_conf); + goto cleanup_test_ctx; + } + + size = Tss2_Sys_GetContextSize(0); + (*test_ctx)->sys_ctx = malloc(size); + if ((*test_ctx)->sys_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for the System API context", size); + goto cleanup_tcti_ctx; + } + rc = Tss2_Sys_Initialize((*test_ctx)->sys_ctx, size, (*test_ctx)->tcti_ctx, &abi_version); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Failed to initialize System API context: 0x%x", rc); + goto cleanup_sys_mem; + } + + rc = Tss2_Sys_Startup((*test_ctx)->sys_ctx, TPM2_SU_CLEAR); + if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { + LOG_ERROR("TPM2_Startup failed: 0x%" PRIx32, rc); + goto cleanup_sys_ctx; + } + + (*test_ctx)->tpm_state = malloc(sizeof(tpm_state)); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for tpm_state.", size); + goto cleanup_sys_ctx; + } + + return TPM2_RC_SUCCESS; + + free((*test_ctx)->tpm_state); + +cleanup_sys_ctx: + Tss2_Sys_Finalize((*test_ctx)->sys_ctx); + +cleanup_sys_mem: + free((*test_ctx)->sys_ctx); + +cleanup_tcti_ctx: + Tss2_TctiLdr_Finalize(&(*test_ctx)->tcti_ctx); + +cleanup_test_ctx: + free(*test_ctx); + +fail: + return EXIT_ERROR; +} + +int +test_sys_checks_pre(TSS2_TEST_SYS_CONTEXT *test_ctx) +{ + int ret; + + LOG_DEBUG("Running System API pre-test checks: transient handles empty"); + ret = transient_empty(test_ctx->sys_ctx); + if (ret != EXIT_SUCCESS) { + LOG_ERROR("TPM contains transient objects."); + return ret; + } + + LOG_DEBUG("Running System API pre-test checks: dump capabilities"); + ret = dumpstate(test_ctx->sys_ctx, test_ctx->tpm_state, 0); + if (ret != EXIT_SUCCESS) { + LOG_ERROR("Error while dumping TPM state."); + return ret; + } + + return EXIT_SUCCESS; +} + +int +test_sys_checks_post(TSS2_TEST_SYS_CONTEXT *test_ctx) +{ + int ret; + + LOG_DEBUG("Running System API post-test checks: dump capabilities"); + ret = dumpstate(test_ctx->sys_ctx, test_ctx->tpm_state, 1); + if (ret != EXIT_SUCCESS) { + LOG_ERROR("Error while performing TPM state checks."); + return ret; + } + + return EXIT_SUCCESS; +} + +void +test_sys_teardown(TSS2_TEST_SYS_CONTEXT *test_ctx) +{ + if (test_ctx) { + free(test_ctx->tpm_state); + Tss2_Sys_Finalize(test_ctx->sys_ctx); + free(test_ctx->sys_ctx); + Tss2_TctiLdr_Finalize(&test_ctx->tcti_ctx); + free(test_ctx); + } +} + +#ifdef TEST_ESYS +int +test_esys_setup(TSS2_TEST_ESYS_CONTEXT **test_ctx) +{ + TSS2_RC rc; + TSS2_ABI_VERSION abi_version = TEST_ABI_VERSION; + size_t size; + char *name_conf; + + size = sizeof(TSS2_TEST_ESYS_CONTEXT); + *test_ctx = malloc(size); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for the test context", size); + goto fail; + } + + name_conf = getenv(ENV_TCTI); // TODO arg, then env? + if (!name_conf) { + LOG_ERROR("TCTI module not specified. Use environment variable: " ENV_TCTI); + goto cleanup_test_ctx; + } + + rc = Tss2_TctiLdr_Initialize(name_conf, &(*test_ctx)->tcti_ctx); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Error loading TCTI: %s", name_conf); + goto cleanup_test_ctx; + } + + rc = tcti_proxy_initialize(NULL, &size, NULL); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Proxy TCTI initialization failed (while getting context size): 0x%" PRIx32, rc); + goto cleanup_tcti_ctx; + } + (*test_ctx)->tcti_proxy_ctx = malloc(size); + if ((*test_ctx)->tcti_proxy_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for the proxy TCTI context", size); + goto cleanup_tcti_ctx; + } + rc = tcti_proxy_initialize((*test_ctx)->tcti_proxy_ctx, &size, (*test_ctx)->tcti_ctx); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Proxy TCTI initialization failed: 0x%" PRIx32, rc); + goto cleanup_tcti_proxy_mem; + } + ((TSS2_TCTI_CONTEXT_PROXY *) (*test_ctx)->tcti_proxy_ctx)->state = forwarding; + + rc = Esys_Initialize(&(*test_ctx)->esys_ctx, (*test_ctx)->tcti_proxy_ctx, &abi_version); + if (rc != TSS2_RC_SUCCESS) { + LOG_ERROR("Esys_Initialize failed: 0x%" PRIx32, rc); + goto cleanup_tcti_proxy_ctx; + } + + rc = Esys_Startup((*test_ctx)->esys_ctx, TPM2_SU_CLEAR); + if (rc != TSS2_RC_SUCCESS && rc != TPM2_RC_INITIALIZE) { + LOG_ERROR("Esys_Startup failed: 0x%" PRIx32, rc); + goto cleanup_esys_ctx; + } + + (*test_ctx)->tpm_state = malloc(sizeof(tpm_state)); + if (test_ctx == NULL) { + LOG_ERROR("Failed to allocate 0x%zx bytes for tpm_state.", size); + goto cleanup_esys_ctx; + } + + return TPM2_RC_SUCCESS; + + free((*test_ctx)->tpm_state); + +cleanup_esys_ctx: + Esys_Finalize(&(*test_ctx)->esys_ctx); + +cleanup_tcti_proxy_ctx: + Tss2_Tcti_Finalize((*test_ctx)->tcti_proxy_ctx); + +cleanup_tcti_proxy_mem: + free((*test_ctx)->tcti_proxy_ctx); + +cleanup_tcti_ctx: + Tss2_TctiLdr_Finalize(&(*test_ctx)->tcti_ctx); + +cleanup_test_ctx: + free(*test_ctx); + +fail: + return EXIT_ERROR; +} + +int +test_esys_checks_pre(TSS2_TEST_ESYS_CONTEXT *test_ctx) +{ + int ret; + TSS2_RC rc; + TSS2_SYS_CONTEXT *sys_context; + + rc = Esys_GetSysContext(test_ctx->esys_ctx, &sys_context); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERROR("Error while getting System API context from Enhanced System API context."); + return EXIT_ERROR; + } + + LOG_DEBUG("Running System API pre-test checks: transient handles empty"); + ret = transient_empty(sys_context); + if (ret != EXIT_SUCCESS) { + LOG_ERROR("TPM contains transient objects."); + return ret; + } + + LOG_DEBUG("Running System API pre-test checks: dump handle capabilities"); + ret = dumpstate(sys_context, test_ctx->tpm_state, 0); + if (ret != EXIT_SUCCESS) { + LOG_ERROR("Error while dumping TPM state."); + return ret; + } + + return EXIT_SUCCESS; +} + +int +test_esys_checks_post(TSS2_TEST_ESYS_CONTEXT *test_ctx) +{ + int ret; + TSS2_RC rc; + TSS2_SYS_CONTEXT *sys_context; + + rc = Esys_GetSysContext(test_ctx->esys_ctx, &sys_context); + if (rc != TPM2_RC_SUCCESS) { + LOG_ERROR("Error while getting System API context from Enhanced System API context."); + return EXIT_ERROR; + } + + LOG_DEBUG("Running System API post-test checks: dump capabilities"); + ret = dumpstate(sys_context, test_ctx->tpm_state, 1); + if (ret != EXIT_SUCCESS) { + LOG_ERROR("Error while performing TPM state checks."); + return ret; + } + + return EXIT_SUCCESS; +} + +void +test_esys_teardown(TSS2_TEST_ESYS_CONTEXT *test_ctx) +{ + if (test_ctx) { + free(test_ctx->tpm_state); + Esys_Finalize(&test_ctx->esys_ctx); + Tss2_Tcti_Finalize(test_ctx->tcti_proxy_ctx); + free(test_ctx->tcti_proxy_ctx); + Tss2_TctiLdr_Finalize(&test_ctx->tcti_ctx); + free(test_ctx); + } +} + +#endif /* TEST_ESYS */ + +#ifdef TEST_FAPI +int +test_fapi_checks_pre(TSS2_TEST_FAPI_CONTEXT *test_ctx) +{ + return test_esys_checks_pre(&test_ctx->test_esys_ctx); +} + +int +test_fapi_checks_post(TSS2_TEST_FAPI_CONTEXT *test_ctx) +{ + return test_esys_checks_post(&test_ctx->test_esys_ctx); +} +#endif /* TEST_FAPI */ diff --git a/test/integration/test-common.h b/test/integration/test-common.h new file mode 100644 index 0000000..8c16b89 --- /dev/null +++ b/test/integration/test-common.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/*********************************************************************** + * Copyright (c) 2017-2021, Intel Corporation + * + * All rights reserved. + ***********************************************************************/ +#ifndef TEST_COMMON_H +#define TEST_COMMON_H + +#include "tss2_tcti.h" +#include "tss2_sys.h" +#include "tss2_esys.h" +#include "tss2_fapi.h" + +#define ENV_TCTI "TPM20TEST_TCTI" + +#define TSSWG_INTEROP 1 +#define TSS_SYS_FIRST_FAMILY 2 +#define TSS_SYS_FIRST_LEVEL 1 +#define TSS_SYS_FIRST_VERSION 108 + +#define TEST_ABI_VERSION { \ + .tssCreator = TSSWG_INTEROP, \ + .tssFamily = TSS_SYS_FIRST_FAMILY, \ + .tssLevel = TSS_SYS_FIRST_LEVEL, \ + .tssVersion = TSS_SYS_FIRST_VERSION, \ + } + + +//#define EXIT_SUCCESS 0 +#define EXIT_ERROR 99 + +typedef struct tpm_state tpm_state; + +typedef struct { + TSS2_TCTI_CONTEXT *tcti_ctx; + TSS2_SYS_CONTEXT *sys_ctx; + tpm_state *tpm_state; +} TSS2_TEST_SYS_CONTEXT; + +int test_sys_setup(TSS2_TEST_SYS_CONTEXT **test_ctx); +int test_sys_checks_pre(TSS2_TEST_SYS_CONTEXT *test_ctx); +int test_sys_checks_post(TSS2_TEST_SYS_CONTEXT *test_ctx); +void test_sys_teardown(TSS2_TEST_SYS_CONTEXT *test_ctx); + +typedef struct { + TSS2_TCTI_CONTEXT *tcti_ctx; + TSS2_TCTI_CONTEXT *tcti_proxy_ctx; + ESYS_CONTEXT *esys_ctx; + tpm_state *tpm_state; +} TSS2_TEST_ESYS_CONTEXT; + +int test_esys_setup(TSS2_TEST_ESYS_CONTEXT **test_ctx); +int test_esys_checks_pre(TSS2_TEST_ESYS_CONTEXT *test_ctx); +int test_esys_checks_post(TSS2_TEST_ESYS_CONTEXT *test_ctx); +void test_esys_teardown(TSS2_TEST_ESYS_CONTEXT *test_ctx); + +typedef struct { + FAPI_CONTEXT *fapi_ctx; + char *tmpdir; + char *fapi_profile; + TSS2_TEST_ESYS_CONTEXT test_esys_ctx; + tpm_state *tpm_state; +} TSS2_TEST_FAPI_CONTEXT; + +int test_fapi_setup(TSS2_TEST_FAPI_CONTEXT **test_ctx); +int test_fapi_checks_pre(TSS2_TEST_FAPI_CONTEXT *test_ctx); +int test_fapi_checks_post(TSS2_TEST_FAPI_CONTEXT *test_ctx); +void test_fapi_teardown(TSS2_TEST_FAPI_CONTEXT *test_ctx); +void test_esys_teardown(TSS2_TEST_ESYS_CONTEXT *test_ctx); + + +#endif /* TEST_COMMON_H */ diff --git a/test/integration/test-fapi.h b/test/integration/test-fapi.h index d654bd2..69253fb 100644 --- a/test/integration/test-fapi.h +++ b/test/integration/test-fapi.h @@ -21,7 +21,6 @@ #define ASSERT_SIZE 10 /* sanity check value for string outputs of Fapi commands */ - #define ASSERT(EXPR) \ if (!(EXPR)) { \ LOG_ERROR("Failed assertion: " #EXPR); \ @@ -140,6 +139,9 @@ extern char *fapi_profile; TSS2_RC pcr_extend(FAPI_CONTEXT *context, UINT32 pcr, TPML_DIGEST_VALUES *digest_values); +TSS2_RC +pcr_bank_sha1_exists(FAPI_CONTEXT *context, bool *exists); + TSS2_RC pcr_reset(FAPI_CONTEXT *context, UINT32 pcr); diff --git a/test/integration/test-options.h b/test/integration/test-options.h deleted file mode 100644 index 032ab6e..0000000 --- a/test/integration/test-options.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: BSD-2-Clause */ -/*********************************************************************** - * Copyright (c) 2017-2018, Intel Corporation - * - * All rights reserved. - ***********************************************************************/ -#ifndef TEST_OPTIONS_H -#define TEST_OPTIONS_H - -#include - -/* Default TCTI */ -#define TCTI_DEFAULT SOCKET_TCTI -#define TCTI_DEFAULT_STR "socket" - -/* Defaults for Device TCTI */ -#define DEVICE_PATH_DEFAULT "/dev/tpm0" - -/* Defaults for Socket TCTI connections */ -#define HOSTNAME_DEFAULT "127.0.0.1" -#define PORT_DEFAULT 2321 - -/* environment variables holding TCTI config */ -#define ENV_TCTI_NAME "TPM20TEST_TCTI_NAME" -#define ENV_DEVICE_FILE "TPM20TEST_DEVICE_FILE" -#define ENV_SOCKET_ADDRESS "TPM20TEST_SOCKET_ADDRESS" -#define ENV_SOCKET_PORT "TPM20TEST_SOCKET_PORT" - -typedef enum { - UNKNOWN_TCTI, - DEVICE_TCTI, - SOCKET_TCTI, - SWTPM_TCTI, - FUZZING_TCTI, - N_TCTI, -} TCTI_TYPE; - -typedef struct { - TCTI_TYPE tcti_type; - const char *device_file; - const char *socket_address; - uint16_t socket_port; -} test_opts_t; - -/* functions to get test options from the user and to print helpful stuff */ -const char *tcti_name_from_type(TCTI_TYPE tcti_type); -TCTI_TYPE tcti_type_from_name(char const *tcti_str); -int get_test_opts_from_env(test_opts_t * opts); -int sanity_check_test_opts(test_opts_t * opts); -void dump_test_opts(test_opts_t * opts); - -#endif /* TEST_OPTIONS_H */ diff --git a/test/tpmclient/tpmclient.int.c b/test/tpmclient/tpmclient.int.c index deedcfb..537050d 100644 --- a/test/tpmclient/tpmclient.int.c +++ b/test/tpmclient/tpmclient.int.c @@ -16,7 +16,10 @@ #include #include "tss2_sys.h" +#include "tss2-tcti/tctildr.h" +#include "tss2-tcti/tcti-pcap.h" #include "tss2_tcti_device.h" +#include "tss2_tcti_libtpms.h" #ifdef TCTI_MSSIM #include "tss2_tcti_mssim.h" #endif /* TCTI_MSSIM */ @@ -24,7 +27,7 @@ #include "tss2_tcti_swtpm.h" #endif /* TCTI_SWTPM */ -#include "../integration/context-util.h" +#include "../integration/test-common.h" #include "../integration/sys-util.h" #include "../integration/session-util.h" #include "util/tss2_endian.h" @@ -106,7 +109,8 @@ static void ErrorHandler(UINT32 rval, char *errorString, int errorStringSize) static void Cleanup_exit(int rc) { if (resMgrTctiContext != NULL) { - tcti_teardown(resMgrTctiContext); + Tss2_Tcti_Finalize(resMgrTctiContext); + free(resMgrTctiContext); resMgrTctiContext = NULL; } exit(rc == EXIT_SKIP ? EXIT_SKIP : 1); @@ -153,9 +157,35 @@ static void InitSysContextFailure() static TSS2_RC TpmReset() { TSS2_RC rval = TSS2_RC_SUCCESS; + TSS2_TCTI_CONTEXT *tcti = resMgrTctiContext; + + /* + * Try to unwrap tctildr/pcap. It would be better to provide an API call for + * reset by tctildr, but for now, use this instead. + */ + uint64_t magic = 0; + while (magic == 0 || magic == TCTILDR_MAGIC || magic == TCTI_PCAP_MAGIC) { + magic = *((uint64_t*) tcti); + if (magic == TCTILDR_MAGIC) { + tcti = ((TSS2_TCTILDR_CONTEXT *) tcti)->tcti; + } else if (magic == TCTI_PCAP_MAGIC) { + tcti = ((TSS2_TCTI_PCAP_CONTEXT *) tcti)->tcti_child; + } + } + +#ifdef TCTI_LIBTPMS + rval = Tss2_Tcti_Libtpms_Reset(tcti); + + /* If TCTI is not libtpms, bad context is returned. */ + if (rval != TSS2_TCTI_RC_BAD_CONTEXT) { + return rval; + } else { + LOG_WARNING("TPM Reset failed: wrong TCTI type retrying with swtpm..."); + } +#endif /* TCTI_LIBTPMS */ #ifdef TCTI_SWTPM - rval = Tss2_Tcti_Swtpm_Reset(resMgrTctiContext); + rval = Tss2_Tcti_Swtpm_Reset(tcti); /* If TCTI is not swtpm, bad context is returned. */ if (rval != TSS2_TCTI_RC_BAD_CONTEXT) { @@ -166,18 +196,51 @@ static TSS2_RC TpmReset() #endif /* TCTI_SWTPM */ #ifdef TCTI_MSSIM - rval = (TSS2_RC)tcti_platform_command( resMgrTctiContext, MS_SIM_POWER_OFF ); + rval = (TSS2_RC)tcti_platform_command( tcti, MS_SIM_POWER_OFF ); if (rval == TSS2_RC_SUCCESS) { - rval = (TSS2_RC)tcti_platform_command( resMgrTctiContext, MS_SIM_POWER_ON ); + rval = (TSS2_RC)tcti_platform_command( tcti, MS_SIM_POWER_ON ); + } else { + LOG_WARNING("TPM Reset failed: mssim returned 0x%x.", rval); } #endif /* TCTI_MSSIM */ + if (rval == TSS2_TCTI_RC_BAD_CONTEXT) { + LOG_WARNING("TPM Reset failed: could not reset using known TCTI types. TCTI magic: %" PRIx64, *((uint64_t *) tcti)); rval = EXIT_SKIP; } return rval; } +/* + * Initialize a SYS context using the TCTI context provided by the caller. + * This function allocates memory for the SYS context and returns it to the + * caller. This memory must be freed by the caller. + */ +TSS2_SYS_CONTEXT * +sys_init_from_tcti_ctx(TSS2_TCTI_CONTEXT * tcti_ctx) +{ + TSS2_SYS_CONTEXT *sys_ctx; + TSS2_RC rc; + size_t size; + TSS2_ABI_VERSION abi_version = TEST_ABI_VERSION; + + size = Tss2_Sys_GetContextSize(0); + sys_ctx = (TSS2_SYS_CONTEXT *) calloc(1, size); + if (sys_ctx == NULL) { + fprintf(stderr, + "Failed to allocate 0x%zx bytes for the SYS context\n", size); + return NULL; + } + rc = Tss2_Sys_Initialize(sys_ctx, size, tcti_ctx, &abi_version); + if (rc != TSS2_RC_SUCCESS) { + fprintf(stderr, "Failed to initialize SYS context: 0x%x\n", rc); + free(sys_ctx); + return NULL; + } + return sys_ctx; +} + static void TestDictionaryAttackLockReset() { UINT32 rval; @@ -388,7 +451,7 @@ static void TestStartAuthSession() encryptedSalt.size = 0; /* Init session */ - rval = create_auth_session(&authSession, TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(&authSession, TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, sysContext ); CheckPassed( rval ); rval = Tss2_Sys_FlushContext( sysContext, authSession->sessionHandle ); @@ -396,7 +459,7 @@ static void TestStartAuthSession() end_auth_session( authSession ); /* Init session */ - rval = create_auth_session(&authSession, TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, 0xff, &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(&authSession, TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, 0xff, &symmetric, TPM2_ALG_SHA256, sysContext ); CheckFailed( rval, TPM2_RC_VALUE + TPM2_RC_P + TPM2_RC_3 ); /* @@ -405,7 +468,7 @@ static void TestStartAuthSession() for( i = 0; i < ( sizeof(sessions) / sizeof (SESSION *) ); i++ ) { /* Init session struct */ - rval = create_auth_session(&sessions[i], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(&sessions[i], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, sysContext ); CheckPassed( rval ); LOG_INFO("Number of sessions created: %d", i+1 ); @@ -420,12 +483,12 @@ static void TestStartAuthSession() } /* Now do some gap tests. */ - rval = create_auth_session(&sessions[0], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(&sessions[0], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, sysContext ); CheckPassed( rval ); for( i = 1; i < ( sizeof(sessions) / sizeof (SESSION *) ); i++ ) { - rval = create_auth_session(&sessions[i], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(&sessions[i], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, sysContext ); CheckPassed( rval ); rval = Tss2_Sys_FlushContext( sysContext, sessions[i]->sessionHandle ); @@ -437,7 +500,7 @@ static void TestStartAuthSession() for( i = 0; i < ( sizeof(sessions) / sizeof (SESSION *) ); i++ ) { - rval = create_auth_session(&sessions[i], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(&sessions[i], TPM2_RH_NULL, 0, TPM2_RH_PLATFORM, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, &symmetric, TPM2_ALG_SHA256, sysContext ); CheckPassed( rval ); rval = Tss2_Sys_FlushContext( sysContext, sessions[i]->sessionHandle ); @@ -847,12 +910,6 @@ static void TestHierarchyControl() rval = Tss2_Sys_NV_DefineSpace( sysContext, TPM2_RH_PLATFORM, &sessionsData, &nvAuth, &publicInfo, 0 ); CheckPassed( rval ); - /* Test SYS for case where nvPublic.size != 0 */ - nvPublic.size = 0xff; - INIT_SIMPLE_TPM2B_SIZE( nvName ); - rval = Tss2_Sys_NV_ReadPublic( sysContext, TPM20_INDEX_TEST1, 0, &nvPublic, &nvName, 0 ); - CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE ); - nvPublic.size = 0; INIT_SIMPLE_TPM2B_SIZE( nvName ); rval = Tss2_Sys_NV_ReadPublic( sysContext, TPM20_INDEX_TEST1, 0, &nvPublic, &nvName, 0 ); @@ -909,7 +966,7 @@ static TSS2_RC BuildPolicy( TSS2_SYS_CONTEXT *sysContext, SESSION **policySessio /* Start policy session. */ symmetric.algorithm = TPM2_ALG_NULL; - rval = create_auth_session(policySession, TPM2_RH_NULL, 0, TPM2_RH_NULL, 0, &nonceCaller, &encryptedSalt, trialSession ? TPM2_SE_TRIAL : TPM2_SE_POLICY , &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + rval = create_auth_session(policySession, TPM2_RH_NULL, 0, TPM2_RH_NULL, 0, &nonceCaller, &encryptedSalt, trialSession ? TPM2_SE_TRIAL : TPM2_SE_POLICY , &symmetric, TPM2_ALG_SHA256, sysContext ); if( rval != TPM2_RC_SUCCESS ) return rval; @@ -957,7 +1014,7 @@ static TSS2_RC CreateNVIndex( TSS2_SYS_CONTEXT *sysContext, SESSION **policySess symmetric.algorithm = TPM2_ALG_NULL; rval = create_auth_session(policySession, TPM2_RH_NULL, 0, TPM2_RH_NULL, 0, &nonceCaller, &encryptedSalt, TPM2_SE_POLICY, - &symmetric, TPM2_ALG_SHA256, resMgrTctiContext ); + &symmetric, TPM2_ALG_SHA256, sysContext ); CheckPassed( rval ); /* Send PolicyLocality command */ @@ -1903,7 +1960,8 @@ static void GetSetDecryptParamTests() rval = Tss2_Sys_SetDecryptParam( decryptParamTestSysContext, 1, &( nvWriteData.buffer[0] ) ); CheckFailed( rval, TSS2_SYS_RC_BAD_SIZE ); - sys_teardown(decryptParamTestSysContext); + Tss2_Sys_Finalize(decryptParamTestSysContext); + free(decryptParamTestSysContext); } static void SysFinalizeTests() @@ -1932,7 +1990,8 @@ static void GetContextSizeTests() rval = Tss2_Sys_GetTestResult_Prepare(testSysContext); CheckPassed(rval); - sys_teardown(testSysContext); + Tss2_Sys_Finalize(testSysContext); + free(testSysContext); } static void GetTctiContextTests() @@ -1953,7 +2012,8 @@ static void GetTctiContextTests() rval = Tss2_Sys_GetTctiContext(0, &tctiContext); CheckFailed(rval, TSS2_SYS_RC_BAD_REFERENCE); - sys_teardown(testSysContext); + Tss2_Sys_Finalize(testSysContext); + free(testSysContext); } static void GetSetEncryptParamTests() @@ -2135,10 +2195,7 @@ static void EcEphemeralTest() LOG_INFO("EC Ephemeral TESTS:" ); - /* Test SYS for case of Q size field not being set to 0. */ INIT_SIMPLE_TPM2B_SIZE( Q ); - rval = Tss2_Sys_EC_Ephemeral( sysContext, 0, TPM2_ECC_BN_P256, &Q, &counter, 0 ); - CheckFailed( rval, TSS2_SYS_RC_BAD_VALUE ); Q.size = 0; rval = Tss2_Sys_EC_Ephemeral( sysContext, 0, TPM2_ECC_BN_P256, &Q, &counter, 0 ); diff --git a/test/unit/esys-crypto.c b/test/unit/esys-crypto.c index b47cfdd..1576726 100644 --- a/test/unit/esys-crypto.c +++ b/test/unit/esys-crypto.c @@ -96,10 +96,10 @@ check_hmac_functions(void **state) rc = iesys_crypto_hmac_start(&crypto_cb, NULL, TPM2_ALG_SHA384, &buffer[0], 10); assert_int_equal (rc, TSS2_ESYS_RC_BAD_REFERENCE); -#ifndef OSSL rc = iesys_crypto_hmac_start(&crypto_cb, &context, TPM2_ALG_SHA512, &buffer[0], 10); - assert_int_equal (rc, TSS2_ESYS_RC_NOT_IMPLEMENTED); -#endif + assert_int_equal (rc, TSS2_RC_SUCCESS); + + iesys_crypto_hmac_abort(&crypto_cb, &context); rc = iesys_crypto_hmac_start(&crypto_cb, &context, 0, &buffer[0], 10); assert_int_equal (rc, TSS2_ESYS_RC_NOT_IMPLEMENTED); @@ -258,6 +258,61 @@ check_aes_encrypt(void **state) assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); } +#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) +static void +check_sm4_encrypt(void **state) +{ + TSS2_RC rc; + uint8_t key[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + uint8_t buffer[5] = { 1, 2, 3, 4, 5 }; + size_t size = sizeof(buffer); + + ESYS_CRYPTO_CALLBACKS crypto_cb = { 0 }; + rc = iesys_initialize_crypto_backend(&crypto_cb, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + rc = iesys_crypto_sm4_encrypt(&crypto_cb, NULL, TPM2_ALG_SM4, 128, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_REFERENCE); + + rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], 0, 128, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); + + rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, 0, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); + + rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 999, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); + + rc = iesys_crypto_sm4_encrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + rc = iesys_crypto_sm4_decrypt(&crypto_cb, NULL, TPM2_ALG_SM4, 128, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_REFERENCE); + + rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], 0, 128, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); + + rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, 0, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); + + rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 999, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_ESYS_RC_BAD_VALUE); + + rc = iesys_crypto_sm4_decrypt(&crypto_cb, &key[0], TPM2_ALG_SM4, 128, TPM2_ALG_CFB, + &buffer[0], size, &key[0]); + assert_int_equal (rc, TSS2_RC_SUCCESS); +} +#endif + static void check_free(void **state) { @@ -320,6 +375,8 @@ static void test_backend_set(void **state) { CHECK_BACKEND_FN(crypto_cb, aes_decrypt); CHECK_BACKEND_FN(crypto_cb, aes_encrypt); + CHECK_BACKEND_FN(crypto_cb, sm4_decrypt); + CHECK_BACKEND_FN(crypto_cb, sm4_encrypt); CHECK_BACKEND_FN(crypto_cb, get_ecdh_point); CHECK_BACKEND_FN(crypto_cb, get_random2b); CHECK_BACKEND_FN(crypto_cb, rsa_pk_encrypt); @@ -328,6 +385,8 @@ static void test_backend_set(void **state) { ESYS_CRYPTO_CALLBACKS user_cb = { .aes_decrypt = (void *)0xBADCC0DE, .aes_encrypt = (void *)0xBADCC0DE, + .sm4_decrypt = (void *)0xBADCC0DE, + .sm4_encrypt = (void *)0xBADCC0DE, .get_ecdh_point = (void *)0xBADCC0DE, .get_random2b = (void *)0xBADCC0DE, .rsa_pk_encrypt = (void *)0xBADCC0DE, @@ -377,6 +436,9 @@ main(int argc, char *argv[]) cmocka_unit_test(check_random), cmocka_unit_test(check_pk_encrypt), cmocka_unit_test(check_aes_encrypt), +#if HAVE_EVP_SM4_CFB && !defined(OPENSSL_NO_SM4) + cmocka_unit_test(check_sm4_encrypt), +#endif cmocka_unit_test(check_free), cmocka_unit_test(check_get_sys_context), cmocka_unit_test(test_backend_set) diff --git a/test/unit/esys-vendor.c b/test/unit/esys-vendor.c index 45c5626..5490624 100644 --- a/test/unit/esys-vendor.c +++ b/test/unit/esys-vendor.c @@ -128,7 +128,8 @@ static TSS2_RC tcti_fake_recv( UNUSED(tctiContext); UNUSED(timeout); - const char *id = (const char*)mock(); + /* Use size_t to cast 64 bit number to pointer (needed for 32 bit systems) */ + const char *id = (const char*)(size_t)mock(); get_response(id, response, size); return TSS2_RC_SUCCESS; diff --git a/test/unit/fapi-check-ima-log.c b/test/unit/fapi-check-ima-log.c index 70c8c30..04ac7af 100644 --- a/test/unit/fapi-check-ima-log.c +++ b/test/unit/fapi-check-ima-log.c @@ -29,6 +29,15 @@ #define LOGMODULE tests #include "util/log.h" +static bool big_endian_arch(void) { + + uint32_t test_word; + uint8_t *test_byte; + + test_word = 0xFF000000; + test_byte = (uint8_t *) (&test_word); + return test_byte[0] == 0xFF; +} static void check_eventlog(const char *file) @@ -127,6 +136,9 @@ check_sml_ima_sig_sha256(void **state) static void check_sml_ima_sig_sha256_invalidated(void **state) { + if (big_endian_arch()) + skip(); + check_eventlog("test/data/fapi/eventlog/sml-ima-sig-sha256-invalidated.bin"); } diff --git a/test/unit/fapi-config.c b/test/unit/fapi-config.c index a36c610..a2242eb 100644 --- a/test/unit/fapi-config.c +++ b/test/unit/fapi-config.c @@ -119,7 +119,7 @@ void check_remove_field(char *file_content, char* fname, TSS2_RC rc) SAFE_FREE(config.profile_name); SAFE_FREE(config.tcti); SAFE_FREE(config.ek_cert_file); - SAFE_FREE(config.intel_cert_service) + SAFE_FREE(config.web_cert_service) } } diff --git a/test/unit/fapi-eventlog.c b/test/unit/fapi-eventlog.c index 60b3805..dba463a 100644 --- a/test/unit/fapi-eventlog.c +++ b/test/unit/fapi-eventlog.c @@ -28,12 +28,26 @@ #include "ifapi_json_serialize.h" #include "ifapi_json_deserialize.h" #include "fapi_policy.h" +#include "ifapi_helpers.h" #include "util/aux_util.h" #define LOGMODULE tests #include "util/log.h" +#define EXIT_SKIP 77 + +static bool big_endian(void) { + + uint32_t test_word; + uint8_t *test_byte; + + test_word = 0xFF000000; + test_byte = (uint8_t *) (&test_word); + + return test_byte[0] == 0xFF; +} + static uint8_t *file_to_buffer(const char *filename, size_t *size) { uint8_t *eventlog = NULL; @@ -117,6 +131,64 @@ check_eventlog(const char *file, uint32_t *pcr_list, size_t pcr_list_size, int n SAFE_FREE(eventlog); } +static void +check_eventlog_pcr0(const char *file, uint32_t *pcr_list, size_t pcr_list_size, int n_events) +{ + TSS2_RC r; + uint8_t *eventlog; + size_t size; + json_object *json_event_list = NULL; + IFAPI_PCR_REG pcrs[TPM2_MAX_PCRS]; + + TPML_PCR_SELECTION pcr_selection = + { + .count = 1, + .pcrSelections = + { + { + .hash = TPM2_ALG_SHA1, + .sizeofSelect = 3, + .pcrSelect = { 1, 0, 0 } }, + }}; + + TPM2B_DIGEST expected_pcr0 = + { + .size = 20, + .buffer = { 0x15, 0xf4, 0xe6, 0xca, 0x45, 0x7d, 0x1a, 0xf6, 0xbc, 0x49, + 0x51, 0x1a, 0x93, 0xba, 0x35, 0x00, 0xad, 0x69, 0xac, 0xc5 }, + }; + + /* Read file to get file size for comparison. */ + eventlog = file_to_buffer(file, &size); + assert_non_null(eventlog); + + r = ifapi_get_tcg_firmware_event_list(file, pcr_list, pcr_list_size, &json_event_list); + assert_int_equal (r, TSS2_RC_SUCCESS); + + r = ifapi_calculate_pcrs(json_event_list, &pcr_selection, TPM2_ALG_SHA1, NULL, &pcrs[0]); + assert_int_equal (r, TSS2_RC_SUCCESS); + + /* Compare with the pcr0 value got from system with HCRTM events */ + assert_true(!memcmp(&expected_pcr0.buffer[0], &pcrs[0].value.buffer[0], 20)); + + json_object_put(json_event_list); + SAFE_FREE(eventlog); +} + +static void +check_bios_hcrtm(void **state) +{ + +#ifdef __FreeBSD__ + /* Free BSD does not support SM3 hashalg */ + skip(); +#endif + check_eventlog_pcr0("test/data/fapi/eventlog/binary_measurements_hcrtm.bin", &pcr_list[0], 9, 111); + check_eventlog("test/data/fapi/eventlog/binary_measurements_hcrtm.bin", &pcr_list[0], 1, 5); + check_eventlog("test/data/fapi/eventlog/binary_measurements_hcrtm.bin", &pcr_list[0], 9, 111); + check_eventlog("test/data/fapi/eventlog/binary_measurements_hcrtm.bin", NULL, 0, 0); +} + static void check_bios_nuc(void **state) { @@ -129,7 +201,7 @@ static void check_bios_pc_client(void **state) { check_eventlog("test/data/fapi/eventlog/binary_measurements_pc_client.bin", &pcr_list[0], 1, 5); - check_eventlog("test/data/fapi/eventlog/binary_measurements_pc_client.bin", &pcr_list[0], 3, 17); + check_eventlog("test/data/fapi/eventlog/binary_measurements_pc_client.bin", &pcr_list[0], 9, 31); check_eventlog("test/data/fapi/eventlog/binary_measurements_pc_client.bin", NULL, 0, 0); } @@ -167,7 +239,12 @@ check_specid_vendordata(void **state) int main(int argc, char *argv[]) { + if (big_endian()) { + return EXIT_SKIP; + } + const struct CMUnitTest tests[] = { + cmocka_unit_test(check_bios_hcrtm), cmocka_unit_test(check_bios_nuc), cmocka_unit_test(check_bios_pc_client), cmocka_unit_test(check_event_uefiservices), diff --git a/test/unit/fapi-get-intl-cert.c b/test/unit/fapi-get-web-cert.c similarity index 71% rename from test/unit/fapi-get-intl-cert.c rename to test/unit/fapi-get-web-cert.c index 10c6acd..740f6f0 100644 --- a/test/unit/fapi-get-intl-cert.c +++ b/test/unit/fapi-get-web-cert.c @@ -22,7 +22,7 @@ #include "tss2_fapi.h" #include "fapi_int.h" -#include "ifapi_get_intl_cert.h" +#include "ifapi_get_web_cert.h" #include "util/aux_util.h" @@ -167,7 +167,7 @@ teardown (void **state) } /* - * Check receiving of valid JSON data for the certificate. + * Check receiving of valid JSON data for the certificate (Intel) */ static void check_get_intl_cert_ok(void **state) { @@ -177,15 +177,36 @@ check_get_intl_cert_ok(void **state) { TSS2_RC r; mock_json_cert = valid_json_cert; - r = ifapi_get_intl_ek_certificate(ctx, &eccPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r, TSS2_RC_SUCCESS); SAFE_FREE(cert_buf); - r = ifapi_get_intl_ek_certificate(ctx, &rsaPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_INTC, &cert_buf, &cert_size); SAFE_FREE(cert_buf); assert_int_equal(r, TSS2_RC_SUCCESS); } +/* + * Check receiving data for the certificate (AMD). + */ +static void +check_get_amd_cert_ok(void **state) { + FAPI_CONTEXT *ctx = *state; + unsigned char *cert_buf = NULL; + size_t cert_size; + TSS2_RC r; + + mock_json_cert = valid_json_cert; + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_AMD, &cert_buf, &cert_size); + assert_int_equal(r, TSS2_RC_SUCCESS); + SAFE_FREE(cert_buf); + + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_AMD, &cert_buf, &cert_size); + SAFE_FREE(cert_buf); + assert_int_equal(r, TSS2_RC_SUCCESS); +} + + /* * Check receiving of invalid JSON data for the certificate. */ @@ -196,11 +217,11 @@ check_get_intl_cert_invalid_json(void **state) { size_t cert_size; TSS2_RC r; mock_json_cert = invalid_json_cert1; - r = ifapi_get_intl_ek_certificate(ctx, &eccPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r, TSS2_FAPI_RC_NO_CERT); mock_json_cert = invalid_json_cert2; - r = ifapi_get_intl_ek_certificate(ctx, &rsaPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r, TSS2_FAPI_RC_NO_CERT); } @@ -216,21 +237,48 @@ check_get_intl_cert_sha_error(void **state) { will_return_always(__wrap_EVP_DigestUpdate, 0); mock_json_cert = valid_json_cert; wrap_EVP_DigestUpdate_test = 1; - r = ifapi_get_intl_ek_certificate(ctx, &eccPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); wrap_EVP_DigestUpdate_test = 1; - r = ifapi_get_intl_ek_certificate(ctx, &rsaPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); wrap_EVP_DigestUpdate_test = 2; - r = ifapi_get_intl_ek_certificate(ctx, &eccPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); wrap_EVP_DigestUpdate_test = 2; - r = ifapi_get_intl_ek_certificate(ctx, &rsaPublic, &cert_buf, &cert_size); + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_INTC, &cert_buf, &cert_size); assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); +} +/* + * Simulate error during hash update for the EK public data. + */ +static void +check_get_amd_cert_sha_error(void **state) { + FAPI_CONTEXT *ctx = *state; + unsigned char *cert_buf = NULL; + size_t cert_size; + TSS2_RC r; + will_return_always(__wrap_EVP_DigestUpdate, 0); + mock_json_cert = valid_json_cert; + wrap_EVP_DigestUpdate_test = 1; + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_AMD, &cert_buf, &cert_size); + assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); + + wrap_EVP_DigestUpdate_test = 1; + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_AMD, &cert_buf, &cert_size); + assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); + + wrap_EVP_DigestUpdate_test = 2; + r = ifapi_get_web_ek_certificate(ctx, &eccPublic, VENDOR_AMD, &cert_buf, &cert_size); + assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); + + wrap_EVP_DigestUpdate_test = 2; + r = ifapi_get_web_ek_certificate(ctx, &rsaPublic, VENDOR_AMD, &cert_buf, &cert_size); + assert_int_equal(r,TSS2_FAPI_RC_NO_CERT); } int @@ -238,8 +286,10 @@ main(int argc, char *argv[]) { const struct CMUnitTest tests[] = { cmocka_unit_test_setup_teardown(check_get_intl_cert_ok, setup, teardown), + cmocka_unit_test_setup_teardown(check_get_amd_cert_ok, setup, teardown), cmocka_unit_test_setup_teardown(check_get_intl_cert_invalid_json, setup, teardown), cmocka_unit_test_setup_teardown(check_get_intl_cert_sha_error, setup, teardown), + cmocka_unit_test_setup_teardown(check_get_amd_cert_sha_error, setup, teardown), }; return cmocka_run_group_tests(tests, NULL, NULL); } diff --git a/test/unit/fapi-ima-eventlog.c b/test/unit/fapi-ima-eventlog.c index 6284fa1..44b311e 100644 --- a/test/unit/fapi-ima-eventlog.c +++ b/test/unit/fapi-ima-eventlog.c @@ -183,7 +183,7 @@ static void check_get_name(void **state) " \"content_type\":\"ima_template\"," \ " \"content\":{" \ " \"template_name\":\"ima-ng\"," \ - " \"template_value\":\"1a000000736861313a0000000000000000000000000000000000000000000f000000626f6f745f61676772656761746500\"" \ + " \"template_data\":\"1a000000736861313a0000000000000000000000000000000000000000000f000000626f6f745f61676772656761746500\"" \ " }" \ "}"; @@ -218,7 +218,7 @@ static void check_invalidate_event(void **state) " \"content_type\":\"ima_template\"," \ " \"content\":{" \ " \"template_name\":\"ima-ng\"," \ - " \"template_value\":\"1a000000736861313a0000000000000000000000000000000000000000000f000000626f6f745f61676772656761746500\"" \ + " \"template_data\":\"1a000000736861313a0000000000000000000000000000000000000000000f000000626f6f745f61676772656761746500\"" \ " }" \ "}"; diff --git a/test/unit/fapi-io.c b/test/unit/fapi-io.c index 8a883a4..8466376 100644 --- a/test/unit/fapi-io.c +++ b/test/unit/fapi-io.c @@ -28,6 +28,7 @@ #define LOGMODULE tests #include "util/log.h" +#define EXIT_SKIP 77 /* * The unit tests will simulate error codes which can be returned by the * system calls for file system IO. @@ -364,6 +365,12 @@ check_io_write_finish(void **state) { int main(int argc, char *argv[]) { +#if _FILE_OFFSET_BITS == 64 + // Would produce cmocka error + LOG_WARNING("_FILE_OFFSET == 64 would produce cmocka errors."); + return EXIT_SKIP; +#endif + const struct CMUnitTest tests[] = { cmocka_unit_test(check_io_read_async), cmocka_unit_test(check_io_read_finish), diff --git a/test/unit/io.c b/test/unit/io.c index bbb4525..fa0e252 100644 --- a/test/unit/io.c +++ b/test/unit/io.c @@ -18,7 +18,7 @@ #include "tss2_tpm2_types.h" -#include "util/io.h" +#include "util-io/io.h" #define LOGMODULE test #include "util/log.h" diff --git a/test/unit/log.c b/test/unit/log.c index 7106641..ad83c15 100644 --- a/test/unit/log.c +++ b/test/unit/log.c @@ -18,7 +18,7 @@ #include "tss2_tpm2_types.h" -#include "util/io.h" +#include "util-io/io.h" #define LOGMODULE test #include "util/log.h" diff --git a/test/unit/tcti-device.c b/test/unit/tcti-device.c index 4e2546b..f1cd180 100644 --- a/test/unit/tcti-device.c +++ b/test/unit/tcti-device.c @@ -25,6 +25,11 @@ #include "tss2-tcti/tcti-common.h" #include "tss2-tcti/tcti-device.h" +#define LOGMODULE tests +#include "util/log.h" + +#define EXIT_SKIP 77 + /* * Size of the TPM2 buffer used in these tests. In some cases this will be * the command sent (transmit tests) and in others it's used as the response @@ -114,6 +119,7 @@ tcti_device_init_conf_default_fail (void **state) errno = EACCES; /* Permission denied */ will_return (__wrap_open, -1); will_return (__wrap_open, -1); + will_return (__wrap_open, -1); ret = Tss2_Tcti_Device_Init (ctx, &tcti_size, NULL); assert_true (ret == TSS2_TCTI_RC_IO_ERROR); @@ -443,6 +449,12 @@ tcti_device_poll_io_error (void **state) int main(int argc, char* argv[]) { +#if _FILE_OFFSET_BITS == 64 + // Would produce cmocka error + LOG_WARNING("_FILE_OFFSET == 64 would produce cmocka errors."); + return EXIT_SKIP; +#endif + const struct CMUnitTest tests[] = { cmocka_unit_test (tcti_device_init_all_null_test), cmocka_unit_test(tcti_device_init_size_test), diff --git a/test/unit/tcti-i2c-ftdi.c b/test/unit/tcti-i2c-ftdi.c new file mode 100644 index 0000000..007d497 --- /dev/null +++ b/test/unit/tcti-i2c-ftdi.c @@ -0,0 +1,600 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_i2c_ftdi.h" + +#include "tss2-tcti/tcti-common.h" +#include "tss2-tcti/tcti-i2c-ftdi.h" +#include "tss2-tcti/tcti-i2c-helper.h" +#include "util/key-value-parse.h" + +typedef enum { + I2C_IDLE = 0, + /* Read sequence */ + R_I2C_START_0, + R_I2C_WRITE_0, + R_I2C_GET_ACK_0, + R_I2C_STOP_0, + R_I2C_START_1, + R_I2C_WRITE_1, + R_I2C_GET_ACK_1, + R_I2C_SEND_ACKS, + R_I2C_READ_0, + R_I2C_SEND_NACKS, + R_I2C_READ_1, + R_I2C_STOP_1, + R_I2C_LAST, + /* Write sequence */ + W_I2C_START, + W_I2C_WRITE_0, + W_I2C_GET_ACK, + W_I2C_WRITE_1, + W_I2C_STOP, + W_I2C_LAST +} i2c_state_t; + +typedef enum { + /* Tss2_Tcti_I2c_Ftdi_Init () */ + R_TPM_DID_VID = 0, + R_TPM_INTERFACE_CAP, + R_TPM_ACCESS, + R_TPM_CSUM_ENABLE, + W_TPM_CSUM_ENABLE, + R_TPM_STS_00, + R_TPM_RID, + /* TSS2_TCTI_TRANSMIT () */ + W_TPM_STS_00, + R_TPM_STS_01, + R_TPM_STS_02, + W_TPM_FIFO, + R_TPM_CSUM_00, + W_TPM_STS_01, + /* TSS2_TCTI_RECEIVE () */ + R_TPM_STS_03, + R_TPM_STS_04, + R_TPM_FIFO_00, + R_TPM_STS_05, + R_TPM_FIFO_01, + R_TPM_STS_06, + R_TPM_FIFO_02, + R_TPM_STS_07, + R_TPM_CSUM_01, + W_TPM_STS_02, +} tpm_state_t; + +static struct m_state_t { + tpm_state_t tpm; + i2c_state_t i2c; +} m_state = {R_TPM_DID_VID, I2C_IDLE}; + +static const uint8_t R_TPM_DID_VID_DATA[] = {0xd1, 0x15, 0x1b, 0x00}; +static const uint8_t R_TPM_INTERFACE_CAP_DATA[] = {0x82, 0x00, 0xe0, 0x1a}; +static const uint8_t R_TPM_ACCESS_DATA[] = {0xa1}; +static const uint8_t R_TPM_CSUM_ENABLE_DATA[] = {0x00}; +static const uint8_t R_TPM_RID_DATA[] = {0x00}; +static const uint8_t R_TPM_STS_00_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; +static const uint8_t R_TPM_STS_02_05_DATA[] = {0x00, 0x40, 0x00, 0x00}; +static const uint8_t R_TPM_STS_04_06_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID | TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL, + 0x00, 0x00, 0x00}; +static const uint8_t R_TPM_CSUM_DATA[] = {0xf7, 0x4b}; /* CRC-16 (KERMIT) of RW_TPM_FIFO_DATA */ +static const uint8_t R_TPM_STS_03_07_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID, 0x00, 0x00, 0x00}; +static const uint8_t W_TPM_STS_00_02_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; +static const uint8_t W_TPM_STS_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_GO, 0x00, 0x00, 0x00}; +static const uint8_t W_TPM_CSUM_ENABLE_DATA[] = {0x01}; +static const uint8_t RW_TPM_FIFO_DATA[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xde, 0xad, 0xbe, 0xef}; + +static struct mpsse_context *_mpsse; + +static void state_machine (void) +{ + while (true) { + switch (m_state.tpm) { + case R_TPM_DID_VID: + case R_TPM_INTERFACE_CAP: + case R_TPM_CSUM_ENABLE: + case R_TPM_CSUM_00: + case R_TPM_CSUM_01: + case R_TPM_ACCESS: + case R_TPM_STS_00: + case R_TPM_STS_01: + case R_TPM_STS_02: + case R_TPM_STS_03: + case R_TPM_STS_04: + case R_TPM_STS_05: + case R_TPM_STS_06: + case R_TPM_STS_07: + case R_TPM_RID: + case R_TPM_FIFO_00: + case R_TPM_FIFO_01: + case R_TPM_FIFO_02: + if (m_state.i2c == I2C_IDLE) { + /* Start a new read sequence */ + m_state.i2c = R_I2C_START_0; + goto exit; + } else if (m_state.i2c == R_I2C_LAST - 1) { + /* Read sequence has ended */ + m_state.i2c = I2C_IDLE; + m_state.tpm++; + } else { + /* Amidst a read sequence */ + m_state.i2c++; + goto exit; + } + break; + case W_TPM_FIFO: + case W_TPM_CSUM_ENABLE: + case W_TPM_STS_00: + case W_TPM_STS_01: + case W_TPM_STS_02: + if (m_state.i2c == I2C_IDLE) { + /* Start a new write sequence */ + m_state.i2c = W_I2C_START; + goto exit; + } else if (m_state.i2c == W_I2C_LAST - 1) { + /* Write sequence has ended */ + m_state.i2c = I2C_IDLE; + m_state.tpm++; + } else { + /* Amidst a write sequence */ + m_state.i2c++; + goto exit; + } + break; + default: + assert_true (false); + return; + } + } + +exit: + return; +} + +/* + * Mock function select + */ +int __wrap_select (int nfds, fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + + assert_int_equal (nfds, 0); + assert_null (readfds); + assert_null (writefds); + assert_null (exceptfds); + assert_non_null (timeout); + + return 0; +} + +/* + * Mock function gettimeofday + */ +int __wrap_gettimeofday (struct timeval *tv, + struct timezone *tz) +{ + assert_null (tz); + assert_non_null (tv); + + tv->tv_sec = 0; + tv->tv_usec = 0; + + return 0; +} + +/* + * Mock function MPSSE + */ +struct mpsse_context *__wrap_MPSSE (enum modes mode, int freq, int endianess) +{ + assert_int_equal (mode, I2C); + assert_int_equal (freq, ONE_HUNDRED_KHZ); + assert_int_equal (endianess, MSB); + + _mpsse = malloc (sizeof (struct mpsse_context)); + + return _mpsse; +} + +/* + * Mock function Start + */ +int __wrap_Start (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + assert_true ((m_state.i2c == R_I2C_START_0) || + (m_state.i2c == R_I2C_START_1) || + (m_state.i2c == W_I2C_START)); + return MPSSE_OK; +} + +/* + * Mock function Stop + */ +int __wrap_Stop (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + assert_true ((m_state.i2c == R_I2C_STOP_0) || + (m_state.i2c == R_I2C_STOP_1) || + (m_state.i2c == W_I2C_STOP)); + return MPSSE_OK; +} + +/* + * Mock function Close + */ +void __wrap_Close (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + free (_mpsse); + _mpsse = NULL; +} + +/* + * Mock function Read + */ +char *__wrap_Read (struct mpsse_context *mpsse, int size) +{ + const uint8_t *payload = NULL; + int payload_size = 0; + char *out = NULL; + + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + + switch (m_state.tpm) { + case R_TPM_DID_VID: + payload = R_TPM_DID_VID_DATA; + payload_size = sizeof (R_TPM_DID_VID_DATA); + break; + case R_TPM_INTERFACE_CAP: + payload = R_TPM_INTERFACE_CAP_DATA; + payload_size = sizeof (R_TPM_INTERFACE_CAP_DATA); + break; + case R_TPM_CSUM_ENABLE: + payload = R_TPM_CSUM_ENABLE_DATA; + payload_size = sizeof (R_TPM_CSUM_ENABLE_DATA); + break; + case R_TPM_CSUM_00: + case R_TPM_CSUM_01: + payload = R_TPM_CSUM_DATA; + payload_size = sizeof (R_TPM_CSUM_DATA); + break; + case R_TPM_ACCESS: + payload = R_TPM_ACCESS_DATA; + payload_size = sizeof (R_TPM_ACCESS_DATA); + break; + case R_TPM_STS_00: + case R_TPM_STS_01: + payload = R_TPM_STS_00_01_DATA; + payload_size = sizeof (R_TPM_STS_00_01_DATA); + break; + case R_TPM_STS_02: + case R_TPM_STS_05: + payload = R_TPM_STS_02_05_DATA; + payload_size = sizeof (R_TPM_STS_02_05_DATA); + break; + case R_TPM_STS_03: + case R_TPM_STS_07: + payload = R_TPM_STS_03_07_DATA; + payload_size = sizeof (R_TPM_STS_03_07_DATA); + break; + case R_TPM_STS_04: + case R_TPM_STS_06: + payload = R_TPM_STS_04_06_DATA; + payload_size = sizeof (R_TPM_STS_04_06_DATA); + break; + case R_TPM_RID: + payload = R_TPM_RID_DATA; + payload_size = sizeof (R_TPM_RID_DATA); + break; + case R_TPM_FIFO_00: + payload = RW_TPM_FIFO_DATA; + payload_size = TCTI_I2C_HELPER_RESP_HEADER_SIZE; + break; + case R_TPM_FIFO_01: + payload = RW_TPM_FIFO_DATA + TCTI_I2C_HELPER_RESP_HEADER_SIZE; + payload_size = sizeof (RW_TPM_FIFO_DATA) - 1 - TCTI_I2C_HELPER_RESP_HEADER_SIZE; + break; + case R_TPM_FIFO_02: + payload = RW_TPM_FIFO_DATA + sizeof (RW_TPM_FIFO_DATA) - 1; + payload_size = 1; + break; + default: + assert_true (false); + } + + switch (m_state.i2c) { + case R_I2C_READ_0: + assert_int_equal (size, payload_size - 1); + out = malloc (size); + assert_non_null (out); + memcpy (out, payload, payload_size - 1); + return out; + break; + case R_I2C_READ_1: + assert_int_equal (size, 1); + out = malloc (1); + assert_non_null (out); + memcpy (out, payload + payload_size - 1, 1); + return out; + break; + default: + assert_true (false); + } + + return NULL; +} + +/* + * Mock function Write + */ +int __wrap_Write (struct mpsse_context *mpsse, char *data, int size) +{ + const uint8_t *payload = NULL; + int payload_size = 0; + uint8_t addr[2] = {I2C_DEV_ADDR_DEFAULT << 1, 0x0}; + + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + + switch (m_state.tpm) { + case R_TPM_DID_VID: + addr[1] = TCTI_I2C_HELPER_TPM_DID_VID_REG; + break; + case R_TPM_INTERFACE_CAP: + addr[1] = TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG; + break; + case R_TPM_CSUM_ENABLE: + addr[1] = TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG; + break; + case R_TPM_CSUM_00: + case R_TPM_CSUM_01: + addr[1] = TCTI_I2C_HELPER_TPM_DATA_CSUM_REG; + break; + case R_TPM_ACCESS: + addr[1] = TCTI_I2C_HELPER_TPM_ACCESS_REG; + break; + case R_TPM_STS_00: + case R_TPM_STS_01: + case R_TPM_STS_02: + case R_TPM_STS_03: + case R_TPM_STS_04: + case R_TPM_STS_05: + case R_TPM_STS_06: + case R_TPM_STS_07: + addr[1] = TCTI_I2C_HELPER_TPM_STS_REG; + break; + case R_TPM_RID: + addr[1] = TCTI_I2C_HELPER_TPM_RID_REG; + break; + case R_TPM_FIFO_00: + case R_TPM_FIFO_01: + case R_TPM_FIFO_02: + addr[1] = TCTI_I2C_HELPER_TPM_DATA_FIFO_REG; + break; + case W_TPM_STS_00: + case W_TPM_STS_02: + addr[1] = TCTI_I2C_HELPER_TPM_STS_REG; + payload = W_TPM_STS_00_02_DATA; + payload_size = sizeof (W_TPM_STS_00_02_DATA); + break; + case W_TPM_STS_01: + addr[1] = TCTI_I2C_HELPER_TPM_STS_REG; + payload = W_TPM_STS_01_DATA; + payload_size = sizeof (W_TPM_STS_01_DATA); + break; + case W_TPM_CSUM_ENABLE: + addr[1] = TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG; + payload = W_TPM_CSUM_ENABLE_DATA; + payload_size = sizeof (W_TPM_CSUM_ENABLE_DATA); + break; + case W_TPM_FIFO: + addr[1] = TCTI_I2C_HELPER_TPM_DATA_FIFO_REG; + payload = RW_TPM_FIFO_DATA; + payload_size = sizeof (RW_TPM_FIFO_DATA); + break; + default: + assert_true (false); + } + + switch (m_state.tpm) { + case R_TPM_DID_VID: + case R_TPM_INTERFACE_CAP: + case R_TPM_CSUM_ENABLE: + case R_TPM_CSUM_00: + case R_TPM_CSUM_01: + case R_TPM_ACCESS: + case R_TPM_STS_00: + case R_TPM_STS_01: + case R_TPM_STS_02: + case R_TPM_STS_03: + case R_TPM_STS_04: + case R_TPM_STS_05: + case R_TPM_STS_06: + case R_TPM_STS_07: + case R_TPM_RID: + case R_TPM_FIFO_00: + case R_TPM_FIFO_01: + case R_TPM_FIFO_02: + switch (m_state.i2c) { + case R_I2C_WRITE_0: + assert_int_equal (size, 2); + assert_int_equal (strncmp ((const void *)addr, data, 2), 0); + break; + case R_I2C_WRITE_1: + assert_int_equal (size, 1); + assert_int_equal ((uint8_t)data[0], addr[0] | 0x01); + break; + default: + assert_true (false); + } + break; + case W_TPM_STS_00: + case W_TPM_STS_01: + case W_TPM_STS_02: + case W_TPM_FIFO: + case W_TPM_CSUM_ENABLE: + switch (m_state.i2c) { + case W_I2C_WRITE_0: + assert_int_equal (size, 2); + assert_int_equal (strncmp ((const void *)addr, data, 2), 0); + break; + case W_I2C_WRITE_1: + assert_int_equal (size, payload_size); + assert_int_equal (strncmp ((const char *)payload, data, payload_size), 0); + break; + default: + assert_true (false); + } + break; + default: + assert_true (false); + } + + return 0; +} + +/* + * Mock function GetAck + */ +int __wrap_GetAck (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + assert_true ((m_state.i2c == R_I2C_GET_ACK_0) || + (m_state.i2c == R_I2C_GET_ACK_1) || + (m_state.i2c == W_I2C_GET_ACK)); + return ACK; +} + +/* + * Mock function SendAcks + */ +void __wrap_SendAcks (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + assert_true (m_state.i2c == R_I2C_SEND_ACKS); +} + +/* + * Mock function SendNacks + */ +void __wrap_SendNacks (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + state_machine (); + assert_true (m_state.i2c == R_I2C_SEND_NACKS); +} + +/* + * The test will call Tss2_Tcti_I2c_Ftdi_Init(), + * which will perform several tasks including reading + * the TPM_DID_VID, checking locality, reading TPM_STS, + * and reading TPM_RID before exiting the Init function. + * The TSS2_TCTI_CONTEXT core functions will be tested as well. + * For testing purposes, the TPM responses are hardcoded. + */ +static void +tcti_i2c_generic_test (void **state) +{ + TSS2_RC rc; + size_t size; + uint8_t response[10] = {0}; + TSS2_TCTI_CONTEXT* tcti_ctx; + + m_state.tpm = 0; + m_state.i2c = 0; + + /* Get requested TCTI context size */ + rc = Tss2_Tcti_I2c_Ftdi_Init (NULL, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + assert_non_null (tcti_ctx); + + /* Initialize TCTI context */ + rc = Tss2_Tcti_I2c_Ftdi_Init (tcti_ctx, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Verify the TCTI core functions */ + assert_int_equal (TSS2_TCTI_MAGIC (tcti_ctx), TCTI_I2C_HELPER_MAGIC); + assert_int_equal (TSS2_TCTI_VERSION (tcti_ctx), TCTI_VERSION); + assert_int_equal ( + TSS2_TCTI_TRANSMIT (tcti_ctx) ( + tcti_ctx, sizeof (RW_TPM_FIFO_DATA), RW_TPM_FIFO_DATA + ), + TSS2_RC_SUCCESS + ); + size = 0; + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, NULL, 200 + ), + TSS2_RC_SUCCESS + ); + assert_int_equal (size, sizeof (RW_TPM_FIFO_DATA)); + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, response, 200 + ), + TSS2_RC_SUCCESS + ); + assert_int_equal (TSS2_TCTI_CANCEL (tcti_ctx) (NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_GET_POLL_HANDLES (tcti_ctx) (NULL, NULL, NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_SET_LOCALITY (tcti_ctx) (NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_MAKE_STICKY (tcti_ctx) (NULL, NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); + + /* Clean up */ + TSS2_TCTI_FINALIZE (tcti_ctx) (tcti_ctx); + free (tcti_ctx); +} + +int +main (int argc, + char *argv[]) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_i2c_generic_test), + }; + return cmocka_run_group_tests (tests, NULL, NULL); +} diff --git a/test/unit/tcti-i2c-helper.c b/test/unit/tcti-i2c-helper.c new file mode 100644 index 0000000..9dc1ba1 --- /dev/null +++ b/test/unit/tcti-i2c-helper.c @@ -0,0 +1,400 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2023 Infineon Technologies AG + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_i2c_helper.h" + +#include "tss2-tcti/tcti-common.h" +#include "tss2-tcti/tcti-i2c-helper.h" +#include "util/key-value-parse.h" + +#define DUMMY_PLATFORM_DATA "my platform data" + +typedef enum { + /* Tss2_Tcti_I2c_Helper_Init () */ + R_TPM_DID_VID = 0, + R_TPM_INTERFACE_CAP, + R_TPM_ACCESS, + R_TPM_CSUM_ENABLE, + W_TPM_CSUM_ENABLE, + R_TPM_STS_00, + R_TPM_RID, + /* TSS2_TCTI_TRANSMIT () */ + W_TPM_STS_00, + R_TPM_STS_01, + R_TPM_STS_02, + W_TPM_FIFO, + R_TPM_CSUM_00, + W_TPM_STS_01, + /* TSS2_TCTI_RECEIVE (); is_timeout_blocked == true */ + R_TPM_STS_03, + R_TPM_STS_04, + R_TPM_FIFO_00, + R_TPM_STS_05, + R_TPM_FIFO_01, + R_TPM_STS_06, + R_TPM_FIFO_02, + R_TPM_STS_07, + R_TPM_CSUM_01, + W_TPM_STS_02, + /* TSS2_TCTI_RECEIVE (); is_timeout_blocked == false */ + R_TPM_STS_08 +} tpm_state_t; + +static const uint8_t R_TPM_DID_VID_DATA[] = {0xd1, 0x15, 0x1b, 0x00}; +static const uint8_t R_TPM_INTERFACE_CAP_DATA[] = {0x82, 0x00, 0xe0, 0x1a}; +static const uint8_t R_TPM_ACCESS_DATA[] = {0xa1}; +static const uint8_t R_TPM_CSUM_ENABLE_DATA[] = {0x00}; +static const uint8_t R_TPM_RID_DATA[] = {0x00}; +static const uint8_t R_TPM_STS_00_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; +static const uint8_t R_TPM_STS_02_05_DATA[] = {0x00, 0x40, 0x00, 0x00}; +static const uint8_t R_TPM_STS_04_06_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID | TCTI_I2C_HELPER_TPM_STS_DATA_AVAIL, + 0x00, 0x00, 0x00}; +static const uint8_t R_TPM_CSUM_DATA[] = {0xf7, 0x4b}; /* CRC-16 (KERMIT) of RW_TPM_FIFO_DATA */ +static const uint8_t R_TPM_STS_03_07_08_DATA[] = {TCTI_I2C_HELPER_TPM_STS_VALID, 0x00, 0x00, 0x00}; +static const uint8_t W_TPM_STS_00_02_DATA[] = {TCTI_I2C_HELPER_TPM_STS_COMMAND_READY, 0x00, 0x00, 0x00}; +static const uint8_t W_TPM_STS_01_DATA[] = {TCTI_I2C_HELPER_TPM_STS_GO, 0x00, 0x00, 0x00}; +static const uint8_t W_TPM_CSUM_ENABLE_DATA[] = {0x01}; +static const uint8_t RW_TPM_FIFO_DATA[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xde, 0xad, 0xbe, 0xef}; + +static tpm_state_t tpm_state; +static bool is_timeout_blocked; + +TSS2_RC +platform_sleep_us (void* user_data, int32_t microseconds) +{ + (void) microseconds; + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_sleep_ms (void* user_data, int32_t milliseconds) +{ + (void) milliseconds; + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_start_timeout (void* user_data, int32_t milliseconds) +{ + (void) milliseconds; + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_timeout_expired (void* user_data, bool *is_timeout_expired) +{ + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + *is_timeout_expired = (is_timeout_blocked) ? false : true; + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_i2c_write (void *user_data, uint8_t reg_addr, const void *data, size_t cnt) +{ + size_t data_len = 0; + + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + assert_non_null (data); + + switch (tpm_state++) { + case W_TPM_CSUM_ENABLE: + data_len = sizeof (W_TPM_CSUM_ENABLE_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG); + assert_int_equal (strncmp ((const void *)W_TPM_CSUM_ENABLE_DATA, data, data_len), 0); + break; + case W_TPM_STS_00: + case W_TPM_STS_02: + data_len = sizeof (W_TPM_STS_00_02_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); + assert_int_equal (strncmp ((const void *)W_TPM_STS_00_02_DATA, data, data_len), 0); + break; + case W_TPM_STS_01: + data_len = sizeof (W_TPM_STS_01_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); + assert_int_equal (strncmp ((const void *)W_TPM_STS_01_DATA, data, data_len), 0); + break; + case W_TPM_FIFO: + data_len = sizeof (RW_TPM_FIFO_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); + assert_int_equal (strncmp ((const void *)RW_TPM_FIFO_DATA, data, data_len), 0); + break; + default: + assert_true (false); + } + + assert_int_equal (cnt, data_len); + + return TSS2_RC_SUCCESS; +} + +TSS2_RC +platform_i2c_read (void* user_data, uint8_t reg_addr, void *data, size_t cnt) +{ + size_t data_len = 0; + + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + assert_non_null (data); + + switch (tpm_state++) { + case R_TPM_DID_VID: + data_len = sizeof (R_TPM_DID_VID_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DID_VID_REG); + memcpy (data, R_TPM_DID_VID_DATA, data_len); + break; + case R_TPM_INTERFACE_CAP: + data_len = sizeof (R_TPM_INTERFACE_CAP_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_INTERFACE_CAPABILITY_REG); + memcpy (data, R_TPM_INTERFACE_CAP_DATA, data_len); + break; + case R_TPM_ACCESS: + data_len = sizeof (R_TPM_ACCESS_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_ACCESS_REG); + memcpy (data, R_TPM_ACCESS_DATA, data_len); + break; + case R_TPM_CSUM_ENABLE: + data_len = sizeof (R_TPM_CSUM_ENABLE_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_CSUM_ENABLE_REG); + memcpy (data, R_TPM_CSUM_ENABLE_DATA, data_len); + break; + case R_TPM_RID: + data_len = sizeof (R_TPM_RID_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_RID_REG); + memcpy (data, R_TPM_RID_DATA, data_len); + break; + case R_TPM_STS_00: + case R_TPM_STS_01: + data_len = sizeof (R_TPM_STS_00_01_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); + memcpy (data, R_TPM_STS_00_01_DATA, data_len); + break; + case R_TPM_STS_02: + case R_TPM_STS_05: + data_len = sizeof (R_TPM_STS_02_05_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); + memcpy (data, R_TPM_STS_02_05_DATA, data_len); + break; + case R_TPM_STS_04: + case R_TPM_STS_06: + data_len = sizeof (R_TPM_STS_04_06_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); + memcpy (data, R_TPM_STS_04_06_DATA, data_len); + break; + case R_TPM_STS_03: + case R_TPM_STS_07: + case R_TPM_STS_08: + data_len = sizeof (R_TPM_STS_03_07_08_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_STS_REG); + memcpy (data, R_TPM_STS_03_07_08_DATA, data_len); + break; + case R_TPM_FIFO_00: + data_len = TCTI_I2C_HELPER_RESP_HEADER_SIZE; + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); + memcpy (data, RW_TPM_FIFO_DATA, data_len); + break; + case R_TPM_FIFO_01: + data_len = sizeof (RW_TPM_FIFO_DATA) - 1 - TCTI_I2C_HELPER_RESP_HEADER_SIZE; + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); + memcpy (data, RW_TPM_FIFO_DATA + TCTI_I2C_HELPER_RESP_HEADER_SIZE, data_len); + break; + case R_TPM_FIFO_02: + data_len = 1; + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_FIFO_REG); + memcpy (data, RW_TPM_FIFO_DATA + sizeof (RW_TPM_FIFO_DATA) - 1, 1); + break; + case R_TPM_CSUM_00: + case R_TPM_CSUM_01: + data_len = sizeof (R_TPM_CSUM_DATA); + assert_int_equal (reg_addr, TCTI_I2C_HELPER_TPM_DATA_CSUM_REG); + memcpy (data, R_TPM_CSUM_DATA, data_len); + break; + default: + assert_true (false); + } + + assert_int_equal (cnt, data_len); + + return TSS2_RC_SUCCESS; +} + +void +platform_finalize (void* user_data) +{ + assert_string_equal ((const char *) user_data, DUMMY_PLATFORM_DATA); + free(user_data); +} + +TSS2_TCTI_I2C_HELPER_PLATFORM +create_tcti_i2c_helper_platform (void) +{ + TSS2_TCTI_I2C_HELPER_PLATFORM platform = {}; + + // Create dummy platform user data + char *platform_data = malloc (sizeof (DUMMY_PLATFORM_DATA)); + memcpy (platform_data, DUMMY_PLATFORM_DATA, sizeof (DUMMY_PLATFORM_DATA)); + + // Create TCTI I2C platform struct with custom platform methods + platform.user_data = platform_data; + platform.sleep_us = platform_sleep_us; + platform.sleep_ms = platform_sleep_ms; + platform.start_timeout = platform_start_timeout; + platform.timeout_expired = platform_timeout_expired; + platform.i2c_write = platform_i2c_write; + platform.i2c_read = platform_i2c_read; + platform.finalize = platform_finalize; + + return platform; +} + +/* + * The test will call Tss2_Tcti_I2c_Helper_Init(), + * which will perform several tasks including reading + * the TPM_DID_VID, checking locality, reading TPM_STS, + * and reading TPM_RID before exiting the Init function. + * The TSS2_TCTI_CONTEXT core functions will be tested as well. + * For testing purposes, the TPM responses are hardcoded. + */ +static void +tcti_i2c_generic_test (void **state) +{ + TSS2_RC rc; + size_t size; + uint8_t response[10] = {0}; + + TSS2_TCTI_I2C_HELPER_PLATFORM tcti_platform = {}; + TSS2_TCTI_CONTEXT* tcti_ctx; + + tpm_state = R_TPM_DID_VID; + + /* Get requested TCTI context size */ + rc = Tss2_Tcti_I2c_Helper_Init (NULL, &size, &tcti_platform); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + assert_non_null (tcti_ctx); + + /* Initialize TCTI context */ + tcti_platform = create_tcti_i2c_helper_platform (); + rc = Tss2_Tcti_I2c_Helper_Init (tcti_ctx, &size, &tcti_platform); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Verify the TCTI core functions */ + assert_int_equal (TSS2_TCTI_MAGIC (tcti_ctx), TCTI_I2C_HELPER_MAGIC); + assert_int_equal (TSS2_TCTI_VERSION (tcti_ctx), TCTI_VERSION); + assert_int_equal ( + TSS2_TCTI_TRANSMIT (tcti_ctx) ( + tcti_ctx, sizeof (RW_TPM_FIFO_DATA), RW_TPM_FIFO_DATA + ), + TSS2_RC_SUCCESS + ); + size = 0; + is_timeout_blocked = true; + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, NULL, 200 + ), + TSS2_RC_SUCCESS + ); + assert_int_equal (size, sizeof (RW_TPM_FIFO_DATA)); + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, response, 200 + ), + TSS2_RC_SUCCESS + ); + assert_int_equal (TSS2_TCTI_CANCEL (tcti_ctx) (NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_GET_POLL_HANDLES (tcti_ctx) (NULL, NULL, NULL), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_SET_LOCALITY (tcti_ctx) (NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); + assert_int_equal (TSS2_TCTI_MAKE_STICKY (tcti_ctx) (NULL, NULL, 0), TSS2_TCTI_RC_NOT_IMPLEMENTED); + + /* Test the behavior of TSS2_TCTI_RECEIVE() in a timeout condition */ + size = 0; + is_timeout_blocked = false; + ((TSS2_TCTI_I2C_HELPER_CONTEXT*)tcti_ctx)->common.state = TCTI_STATE_RECEIVE; + assert_int_equal ( + TSS2_TCTI_RECEIVE (tcti_ctx) ( + tcti_ctx, &size, NULL, 200 + ), + TSS2_TCTI_RC_TRY_AGAIN + ); + + /* Clean up */ + TSS2_TCTI_FINALIZE (tcti_ctx) (tcti_ctx); + free (tcti_ctx); +} + +static void +tcti_i2c_bad_callbacks_test (void **state) +{ + TSS2_RC rc; + size_t size; + TSS2_TCTI_I2C_HELPER_PLATFORM tcti_platform = {}; + TSS2_TCTI_CONTEXT* tcti_ctx; + + /* Get requested TCTI context size */ + rc = Tss2_Tcti_I2c_Helper_Init (NULL, &size, &tcti_platform); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + assert_non_null (tcti_ctx); + + /* Initialize TCTI context */ + tcti_platform = create_tcti_i2c_helper_platform (); + tcti_platform.sleep_us = NULL; + tcti_platform.sleep_ms = NULL; + rc = Tss2_Tcti_I2c_Helper_Init (tcti_ctx, &size, &tcti_platform); + assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE); + + /* Clean up */ + free (tcti_platform.user_data); + free (tcti_ctx); +} + +int +main (int argc, + char *argv[]) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_i2c_generic_test), + cmocka_unit_test (tcti_i2c_bad_callbacks_test), + }; + return cmocka_run_group_tests (tests, NULL, NULL); +} diff --git a/test/unit/tcti-libtpms.c b/test/unit/tcti-libtpms.c index 823cc0d..11e501a 100644 --- a/test/unit/tcti-libtpms.c +++ b/test/unit/tcti-libtpms.c @@ -28,6 +28,8 @@ #define LOGMODULE test #include "util/log.h" +#define EXIT_SKIP 77 + #define LIBTPMS_DL_HANDLE 0x12345678 #define STATEFILE_PATH "statefile.bin" #define STATEFILE_FD 0xAABB @@ -122,11 +124,6 @@ TPM_RESULT TPMLIB_MainInit(void) assert_int_equal(ret, 0); ret = global_callbacks.tpm_io_init(); assert_int_equal(ret, 0); - ret = global_callbacks.tpm_nvram_loaddata((unsigned char **) 1, - (uint32_t *) 2, - 3, - "4"); - assert_int_equal(ret, TPM_RETRY); return mock_type(int); } TPM_RESULT TPMLIB_Process(unsigned char **resp_buf, uint32_t *resp_len, uint32_t *resp_buf_len, unsigned char *cmd, uint32_t cmd_len) @@ -139,9 +136,6 @@ TPM_RESULT TPMLIB_Process(unsigned char **resp_buf, uint32_t *resp_len, uint32_t assert_int_equal(ret, 0); check_expected(locality); - ret = global_callbacks.tpm_nvram_storedata((unsigned char *) 1, 2, 3, "4"); - assert_int_equal(ret, TPM_SUCCESS); - unsigned char *buf_out = mock_type(unsigned char *); *resp_buf_len = *resp_len = mock_type(uint32_t); *resp_buf = malloc(*resp_len); @@ -159,6 +153,10 @@ TPM_RESULT TPMLIB_SetState(enum TPMLIB_StateType st, const unsigned char *buf, u void TPMLIB_Terminate(void) { } +TPM_RESULT TPM_IO_TpmEstablished_Reset(void) +{ + return TPM_SUCCESS; +} void *__wrap_dlopen(const char *filename, int flags) { @@ -387,6 +385,11 @@ tcti_libtpms_init_state_open_fail_test(void **state) TSS2_RC ret = TSS2_RC_SUCCESS; TSS2_TCTI_CONTEXT *ctx = NULL; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + ret = Tss2_Tcti_Libtpms_Init(NULL, &tcti_size, NULL); assert_true(ret == TSS2_RC_SUCCESS); ctx = calloc(1, tcti_size); @@ -424,6 +427,10 @@ tcti_libtpms_init_state_open_fail_test(void **state) expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); will_return(__wrap_dlsym, &TPMLIB_Terminate); + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + /* fail open */ expect_string(__wrap_open, pathname, STATEFILE_PATH); expect_value(__wrap_open, flags, O_RDWR | O_CREAT); @@ -448,6 +455,11 @@ tcti_libtpms_init_state_lseek_fail_test(void **state) TSS2_RC ret = TSS2_RC_SUCCESS; TSS2_TCTI_CONTEXT *ctx = NULL; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + ret = Tss2_Tcti_Libtpms_Init(NULL, &tcti_size, NULL); assert_true(ret == TSS2_RC_SUCCESS); ctx = calloc(1, tcti_size); @@ -485,6 +497,10 @@ tcti_libtpms_init_state_lseek_fail_test(void **state) expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); will_return(__wrap_dlsym, &TPMLIB_Terminate); + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + expect_string(__wrap_open, pathname, STATEFILE_PATH); expect_value(__wrap_open, flags, O_RDWR | O_CREAT); expect_value(__wrap_open, mode, 0644); @@ -519,6 +535,11 @@ tcti_libtpms_init_state_posix_fallocate_fail_test(void **state) TSS2_RC ret = TSS2_RC_SUCCESS; TSS2_TCTI_CONTEXT *ctx = NULL; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + ret = Tss2_Tcti_Libtpms_Init(NULL, &tcti_size, NULL); assert_true(ret == TSS2_RC_SUCCESS); ctx = calloc(1, tcti_size); @@ -556,6 +577,10 @@ tcti_libtpms_init_state_posix_fallocate_fail_test(void **state) expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); will_return(__wrap_dlsym, &TPMLIB_Terminate); + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + expect_string(__wrap_open, pathname, STATEFILE_PATH); expect_value(__wrap_open, flags, O_RDWR | O_CREAT); expect_value(__wrap_open, mode, 0644); @@ -596,6 +621,11 @@ tcti_libtpms_init_state_mmap_fail_test(void **state) TSS2_RC ret = TSS2_RC_SUCCESS; TSS2_TCTI_CONTEXT *ctx = NULL; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + ret = Tss2_Tcti_Libtpms_Init(NULL, &tcti_size, NULL); assert_true(ret == TSS2_RC_SUCCESS); ctx = calloc(1, tcti_size); @@ -633,6 +663,10 @@ tcti_libtpms_init_state_mmap_fail_test(void **state) expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); will_return(__wrap_dlsym, &TPMLIB_Terminate); + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + expect_string(__wrap_open, pathname, STATEFILE_PATH); expect_value(__wrap_open, flags, O_RDWR | O_CREAT); expect_value(__wrap_open, mode, 0644); @@ -674,6 +708,67 @@ tcti_libtpms_init_state_mmap_fail_test(void **state) free(ctx); } +/* Currently, state files are not supported on FreeBSD. */ +static void +tcti_libtpms_init_state_freebsd_fail_test(void **state) +{ + size_t tcti_size = 0; + TSS2_RC ret = TSS2_RC_SUCCESS; + TSS2_TCTI_CONTEXT *ctx = NULL; + + // FreeBSD-only test +#ifndef __FreeBSD__ + skip(); +#endif + + ret = Tss2_Tcti_Libtpms_Init(NULL, &tcti_size, NULL); + assert_true(ret == TSS2_RC_SUCCESS); + ctx = calloc(1, tcti_size); + assert_non_null(ctx); + + // successfull dlopen + expect_string(__wrap_dlopen, filename, "libtpms.so"); + expect_value(__wrap_dlopen, flags, RTLD_LAZY | RTLD_LOCAL); + will_return(__wrap_dlopen, LIBTPMS_DL_HANDLE); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_ChooseTPMVersion"); + will_return(__wrap_dlsym, &TPMLIB_ChooseTPMVersion); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_RegisterCallbacks"); + will_return(__wrap_dlsym, &TPMLIB_RegisterCallbacks); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_GetState"); + will_return(__wrap_dlsym, &TPMLIB_GetState); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_MainInit"); + will_return(__wrap_dlsym, &TPMLIB_MainInit); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_Process"); + will_return(__wrap_dlsym, &TPMLIB_Process); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_SetState"); + will_return(__wrap_dlsym, &TPMLIB_SetState); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); + will_return(__wrap_dlsym, &TPMLIB_Terminate); + + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + + ret = Tss2_Tcti_Libtpms_Init(ctx, &tcti_size, STATEFILE_PATH); + assert_int_equal(ret, TSS2_TCTI_RC_BAD_VALUE); + + free(ctx); +} + /* * This is a utility function used by other tests to setup a TCTI context. It * effectively wraps the init / allocate / init pattern as well as priming the @@ -729,6 +824,10 @@ tcti_libtpms_init_from_conf(const char *conf) expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); will_return(__wrap_dlsym, &TPMLIB_Terminate); + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + if (conf != NULL) { expect_string(__wrap_open, pathname, STATEFILE_PATH); expect_value(__wrap_open, flags, O_RDWR | O_CREAT); @@ -852,6 +951,10 @@ tcti_libtpms_init_from_conf_real(const char *conf) expect_string(__wrap_dlsym, symbol, "TPMLIB_Terminate"); will_return(__wrap_dlsym, &TPMLIB_Terminate); + expect_value(__wrap_dlsym, handle, LIBTPMS_DL_HANDLE); + expect_string(__wrap_dlsym, symbol, "TPM_IO_TpmEstablished_Reset"); + will_return(__wrap_dlsym, &TPM_IO_TpmEstablished_Reset); + if (conf != NULL) { expect_string(__wrap_open, pathname, conf); expect_value(__wrap_open, flags, O_RDWR | O_CREAT); @@ -896,10 +999,15 @@ tcti_libtpms_locality_success_test(void **state) unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + rc = Tss2_Tcti_SetLocality(ctx, 4); assert_int_equal(rc, TSS2_RC_SUCCESS); - expect_value(TPMLIB_Process, cmd, cmd); + expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); expect_value(TPMLIB_Process, locality, 4); /* expect locality 4 */ will_return(TPMLIB_Process, rsp); @@ -919,7 +1027,12 @@ tcti_libtpms_transmit_success_test(void **state) unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - expect_value(TPMLIB_Process, cmd, cmd); +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + + expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp); @@ -960,6 +1073,11 @@ tcti_libtpms_receive_success_test(void **state) unsigned char rsp_out[sizeof(rsp)]; size_t rsp_len_out = 0; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + tcti_common->state = TCTI_STATE_RECEIVE; tcti_libtpms->response_buffer = malloc(sizeof(rsp)); assert_non_null(tcti_libtpms->response_buffer); @@ -994,7 +1112,12 @@ tcti_libtpms_remap_state_success_test(void **state) unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - expect_value(TPMLIB_Process, cmd, cmd); +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + + expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp); @@ -1051,7 +1174,12 @@ tcti_libtpms_remap_state_mremap_fail_test(void **state) unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - expect_value(TPMLIB_Process, cmd, cmd); +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + + expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp); @@ -1094,7 +1222,12 @@ tcti_libtpms_remap_state_posix_fallocate_fail_test(void **state) unsigned char cmd[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00}; unsigned char rsp[] = {0x80, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}; - expect_value(TPMLIB_Process, cmd, cmd); +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + skip(); +#endif + + expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp); @@ -1156,7 +1289,7 @@ tcti_libtpms_no_statefile_success_test(void **state) unsigned char rsp_out[sizeof(rsp)]; size_t rsp_len_out = sizeof(rsp); - expect_value(TPMLIB_Process, cmd, cmd); + expect_memory(TPMLIB_Process, cmd, cmd, sizeof(cmd)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp); @@ -1210,7 +1343,7 @@ tcti_libtpms_two_states_no_statefiles_success_test(void **state) tcti_common[1] = tcti_common_context_cast(ctxs[1]); /* ===== transmit on instance 0 ===== */ - expect_value(TPMLIB_Process, cmd, cmd_aa); + expect_memory(TPMLIB_Process, cmd, cmd_aa, sizeof(cmd_aa)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_aa)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp_aa); @@ -1231,7 +1364,7 @@ tcti_libtpms_two_states_no_statefiles_success_test(void **state) assert_int_equal(tcti_libtpms[0]->state_len, 0); /* ===== transmit on instance 1 ===== */ - expect_value(TPMLIB_Process, cmd, cmd_bb); + expect_memory(TPMLIB_Process, cmd, cmd_bb, sizeof(cmd_bb)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_bb)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp_bb); @@ -1304,11 +1437,17 @@ tcti_libtpms_two_states_success_test(void **state) unsigned char rsp_bb_out[sizeof(rsp_bb)]; size_t rsp_bb_len_out = sizeof(rsp_bb); +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + *state = NULL; + skip(); +#endif + tcti_common[0] = tcti_common_context_cast(ctxs[0]); tcti_common[1] = tcti_common_context_cast(ctxs[1]); /* ===== transmit on instance 0 ===== */ - expect_value(TPMLIB_Process, cmd, cmd_aa); + expect_memory(TPMLIB_Process, cmd, cmd_aa, sizeof(cmd_aa)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_aa)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp_aa); @@ -1336,7 +1475,7 @@ tcti_libtpms_two_states_success_test(void **state) assert_memory_equal(tcti_libtpms[0]->state_mmap, S1_STATE, S1_STATE_LEN); /* ===== transmit on instance 1 ===== */ - expect_value(TPMLIB_Process, cmd, cmd_bb); + expect_memory(TPMLIB_Process, cmd, cmd_bb, sizeof(cmd_bb)); expect_value(TPMLIB_Process, cmd_len, sizeof(cmd_bb)); expect_value(TPMLIB_Process, locality, 0); will_return(TPMLIB_Process, rsp_bb); @@ -1402,6 +1541,11 @@ tcti_libtpms_two_states_success_test(void **state) static int tcti_libtpms_setup(void **state) { +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + return 0; +#endif + fprintf(stderr, "%s: before tcti_libtpms_init_from_conf\n", __func__); *state = tcti_libtpms_init_from_conf(STATEFILE_PATH); fprintf(stderr, "%s: done\n", __func__); @@ -1440,7 +1584,14 @@ static int tcti_libtpms_setup_two_states(void **state) { int ret; - TSS2_TCTI_CONTEXT **ctxs = malloc(sizeof(void *) * 2); + TSS2_TCTI_CONTEXT **ctxs; + +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + return 0; +#endif + + ctxs = malloc(sizeof(void *) * 2); assert_non_null(ctxs); /* delete state files if they exist already */ @@ -1491,6 +1642,11 @@ tcti_libtpms_teardown_s1(void **state) TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*) *state; TSS2_TCTI_LIBTPMS_CONTEXT *tcti_libtpms = (TSS2_TCTI_LIBTPMS_CONTEXT*) ctx; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + return 0; +#endif + expect_value(__wrap_dlclose, handle, LIBTPMS_DL_HANDLE); will_return(__wrap_dlclose, 0); @@ -1519,6 +1675,11 @@ tcti_libtpms_teardown_s2(void **state) { TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*) *state; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + return 0; +#endif + expect_value(__wrap_dlclose, handle, LIBTPMS_DL_HANDLE); will_return(__wrap_dlclose, 0); @@ -1545,6 +1706,11 @@ tcti_libtpms_teardown_s3(void **state) { TSS2_TCTI_CONTEXT *ctx = (TSS2_TCTI_CONTEXT*) *state; +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + return 0; +#endif + expect_value(__wrap_dlclose, handle, LIBTPMS_DL_HANDLE); will_return(__wrap_dlclose, 0); @@ -1570,8 +1736,18 @@ static int tcti_libtpms_teardown_two_states(void **state) { int ret; - TSS2_TCTI_CONTEXT **ctxs = (TSS2_TCTI_CONTEXT**) *state; - TSS2_TCTI_LIBTPMS_CONTEXT **tcti_libtpms = (TSS2_TCTI_LIBTPMS_CONTEXT**) ctxs; + TSS2_TCTI_CONTEXT **ctxs; + TSS2_TCTI_LIBTPMS_CONTEXT **tcti_libtpms; + +#ifdef __FreeBSD__ + // Currently, state files are not supported on FreeBSD + if (*state == NULL) { + return 0; + } +#endif + + ctxs = (TSS2_TCTI_CONTEXT**) *state; + tcti_libtpms = (TSS2_TCTI_LIBTPMS_CONTEXT**) ctxs; *state = *ctxs; /* for both tcti instances */ @@ -1612,6 +1788,12 @@ int main(int argc, char *argv[]) { +#if _FILE_OFFSET_BITS == 64 + // Would produce cmocka error + LOG_WARNING("_FILE_OFFSET == 64 would produce cmocka errors."); + return EXIT_SKIP; +#endif + const struct CMUnitTest tests[] = { cmocka_unit_test(tcti_libtpms_init_all_null_test), cmocka_unit_test(tcti_libtpms_init_dlopen_fail_test), @@ -1620,6 +1802,7 @@ main(int argc, cmocka_unit_test(tcti_libtpms_init_state_lseek_fail_test), cmocka_unit_test(tcti_libtpms_init_state_posix_fallocate_fail_test), cmocka_unit_test(tcti_libtpms_init_state_mmap_fail_test), + cmocka_unit_test(tcti_libtpms_init_state_freebsd_fail_test), cmocka_unit_test_setup_teardown(tcti_libtpms_no_statefile_success_test, tcti_libtpms_setup_no_statefile, tcti_libtpms_teardown_no_statefile), diff --git a/test/unit/tcti-pcap.c b/test/unit/tcti-pcap.c index bfc527b..ef58975 100644 --- a/test/unit/tcti-pcap.c +++ b/test/unit/tcti-pcap.c @@ -27,6 +27,11 @@ #include "tss2-tcti/tcti-common.h" #include "tss2-tcti/tcti-pcap.h" +#define LOGMODULE tests +#include "util/log.h" + +#define EXIT_SKIP 77 + #if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) #define _LE32TOH(a,b,c,d) d,c,b,a #define _LE16TOH(a,b) b,a @@ -726,6 +731,12 @@ int main (int argc, char *argv[]) { +#if _FILE_OFFSET_BITS == 64 + // Would produce cmocka error + LOG_WARNING("_FILE_OFFSET == 64 would produce cmocka errors."); + return EXIT_SKIP; +#endif + const struct CMUnitTest tests[] = { cmocka_unit_test (tcti_pcap_init_context_and_size_null_test), cmocka_unit_test (tcti_pcap_init_size_test), diff --git a/test/unit/tcti-spi-ftdi.c b/test/unit/tcti-spi-ftdi.c new file mode 100644 index 0000000..e1758cd --- /dev/null +++ b/test/unit/tcti-spi-ftdi.c @@ -0,0 +1,228 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/***********************************************************************; + * Copyright (c) 2023, Infineon Technologies AG + * All rights reserved. + ***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_spi_ftdi.h" + +#include "tss2-tcti/tcti-common.h" +#include "tss2-tcti/tcti-spi-ftdi.h" +#include "tss2-tcti/tcti-spi-helper.h" +#include "util/key-value-parse.h" + +typedef enum { + TPM_DID_VID = 0, + TPM_ACCESS, + TPM_STS_CMD_NOT_READY, + TPM_STS_CMD_READY, + TPM_RID, +} tpm_state_t; + +static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; +static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; +static const unsigned char TPM_STS_0_CMD_NOT_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00}; +static const unsigned char TPM_STS_0_CMD_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; +static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; + +static struct mpsse_context *_mpsse; + +/* + * Mock function select + */ +int __wrap_select (int nfds, fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + + assert_int_equal (nfds, 0); + assert_null (readfds); + assert_null (writefds); + assert_null (exceptfds); + assert_non_null (timeout); + + return 0; +} + +/* + * Mock function gettimeofday + */ +int __wrap_gettimeofday (struct timeval *tv, + struct timezone *tz) +{ + assert_null (tz); + assert_non_null (tv); + + tv->tv_sec = 0; + tv->tv_usec = 0; + + return 0; +} + +/* + * Mock function MPSSE + */ +struct mpsse_context *__wrap_MPSSE (enum modes mode, int freq, int endianess) +{ + assert_int_equal (mode, SPI0); + assert_int_equal (freq, FIFTEEN_MHZ); + assert_int_equal (endianess, MSB); + + _mpsse = malloc (sizeof (struct mpsse_context)); + + return _mpsse; +} + +/* + * Mock function PinLow + */ +int __wrap_PinLow (struct mpsse_context *mpsse, int pin) +{ + assert_ptr_equal (mpsse, _mpsse); + assert_int_equal (pin, GPIOL0); + + return MPSSE_OK; +} + +/* + * Mock function PinHigh + */ +int __wrap_PinHigh (struct mpsse_context *mpsse, int pin) +{ + assert_ptr_equal (mpsse, _mpsse); + assert_int_equal (pin, GPIOL0); + + return MPSSE_OK; +} + +/* + * Mock function Start + */ +int __wrap_Start (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + return MPSSE_OK; +} + +/* + * Mock function Transfer + */ +char *__wrap_Transfer (struct mpsse_context *mpsse, char *data, int size) +{ + + static tpm_state_t tpm_state = TPM_DID_VID; + char *ret = malloc (size); + + assert_non_null (ret); + assert_ptr_equal (mpsse, _mpsse); + + switch (tpm_state++) { + case TPM_DID_VID: + assert_int_equal (size, 8); + assert_true (!memcmp (data, TPM_DID_VID_0, 4)); + memcpy (ret, TPM_DID_VID_0, sizeof (TPM_DID_VID_0)); + break; + case TPM_ACCESS: + assert_int_equal (size, 5); + assert_true (!memcmp (data, TPM_ACCESS_0, 4)); + memcpy (ret, TPM_ACCESS_0, sizeof (TPM_ACCESS_0)); + break; + case TPM_STS_CMD_NOT_READY: + assert_int_equal (size, 8); + assert_true (!memcmp (data, TPM_STS_0_CMD_NOT_READY, 4)); + memcpy (ret, TPM_STS_0_CMD_NOT_READY, sizeof (TPM_STS_0_CMD_NOT_READY)); + break; + case TPM_STS_CMD_READY: + assert_int_equal (size, 8); + assert_true (!memcmp (data, TPM_STS_0_CMD_READY, 4)); + memcpy (ret, TPM_STS_0_CMD_READY, sizeof (TPM_STS_0_CMD_READY)); + break; + case TPM_RID: + assert_int_equal (size, 5); + assert_true (!memcmp (data, TPM_RID_0, 4)); + memcpy (ret, TPM_RID_0, sizeof (TPM_RID_0)); + break; + default: + assert_true (false); + } + + return ret; +} + +/* + * Mock function Stop + */ +int __wrap_Stop (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + return MPSSE_OK; +} + +/* + * Mock function Close + */ +void __wrap_Close (struct mpsse_context *mpsse) +{ + assert_ptr_equal (mpsse, _mpsse); + free (_mpsse); + _mpsse = NULL; +} + +/* + * The test will invoke Tss2_Tcti_Spi_Ftdi_Init() and subsequently + * it will start reading TPM_DID_VID, claim locality, read TPM_STS, + * and finally read TPM_RID before exiting the Init function. + * For testing purpose, the TPM responses are hardcoded. + * SPI wait state is not supported in this test. + */ +static void +tcti_spi_no_wait_state_success_test (void **state) +{ + TSS2_RC rc; + size_t size; + TSS2_TCTI_CONTEXT* tcti_ctx; + + // Get requested TCTI context size + rc = Tss2_Tcti_Spi_Ftdi_Init (NULL, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + // Allocate TCTI context size + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + assert_non_null (tcti_ctx); + + // Initialize TCTI context + rc = Tss2_Tcti_Spi_Ftdi_Init (tcti_ctx, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + // Finalize + TSS2_TCTI_FINALIZE(tcti_ctx)(tcti_ctx); + + free (tcti_ctx); +} + +int +main (int argc, + char *argv[]) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_spi_no_wait_state_success_test), + }; + + return cmocka_run_group_tests (tests, NULL, NULL); +} diff --git a/test/unit/tcti-spi-ltt2go.c b/test/unit/tcti-spi-ltt2go.c new file mode 100644 index 0000000..f82c946 --- /dev/null +++ b/test/unit/tcti-spi-ltt2go.c @@ -0,0 +1,378 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/***********************************************************************; + * Copyright (c) 2022, Infineon Technologies AG + * All rights reserved. + ***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_spi_ltt2go.h" + +#include "tss2-tcti/tcti-common.h" +#include "tss2-tcti/tcti-spi-ltt2go.h" +#include "tss2-tcti/tcti-spi-helper.h" +#include "util/key-value-parse.h" + +#define VID_PI3G 0x365Du +#define PID_LTT2GO 0x1337u +#define CTRL_SET 0xC0u +#define CY_CMD_SPI 0xCAu +#define CY_SPI_WRITEREAD 0x03u +#define TIMEOUT 1000 +#define EP_OUT 0x01u +#define EP_IN 0x82u + +typedef enum { + TPM_DID_VID_HEAD_RX = 0, + TPM_DID_VID_HEAD_TX, + TPM_ACCESS_HEAD_RX, + TPM_ACCESS_HEAD_TX, + TPM_STS_HEAD_RX, + TPM_STS_HEAD_TX, + TPM_RID_HEAD_RX, + TPM_RID_HEAD_TX, +} tpm_state_t; + +static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; +static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; +static const unsigned char TPM_STS_0[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; +static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; + +static libusb_device_handle *device_handle; +static libusb_context *context; +struct libusb_config_descriptor *config_descriptor; +static libusb_device *usb_device; +static unsigned char *device_mem_alloc; +static size_t device_mem_alloc_length; +static uint16_t transfer_length; + +/* + * Mock function select + */ +int __wrap_select (int nfds, fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + + assert_int_equal (nfds, 0); + assert_null (readfds); + assert_null (writefds); + assert_null (exceptfds); + assert_non_null (timeout); + + return 0; +} + +/* + * Mock function gettimeofday + */ +int __wrap_gettimeofday (struct timeval *tv, + struct timezone *tz) +{ + assert_null (tz); + assert_non_null (tv); + + tv->tv_sec = 0; + tv->tv_usec = 0; + + return 0; +} + +/* + * Mock function libusb_get_device. + */ +libusb_device * __wrap_libusb_get_device (libusb_device_handle *dev_handle) +{ + assert_ptr_equal (dev_handle, device_handle); + usb_device = malloc (1); + return usb_device; +} + +/* + * Mock function libusb_get_config_descriptor. + */ +int __wrap_libusb_get_config_descriptor (libusb_device *dev, + uint8_t config_index, struct libusb_config_descriptor **config) +{ + assert_ptr_equal (dev, usb_device); + assert_int_equal (config_index, 0); + config_descriptor = malloc (sizeof (struct libusb_config_descriptor)); + config_descriptor->bNumInterfaces = 2; + *config = config_descriptor; + + return 0; +} + +/* + * Mock function libusb_free_config_descriptor. + */ +void __wrap_libusb_free_config_descriptor ( + struct libusb_config_descriptor *config) +{ + assert_ptr_equal (config, config_descriptor); + free (config); +} + +/* + * Mock function libusb_set_auto_detach_kernel_driver. + */ +int __wrap_libusb_set_auto_detach_kernel_driver ( + libusb_device_handle *dev_handle, int enable) +{ + assert_ptr_equal (dev_handle, device_handle); + assert_int_equal (enable, 1); + + return 0; +} + +/* + * Mock function libusb_claim_interface. + */ +int __wrap_libusb_claim_interface (libusb_device_handle *dev_handle, + int interface_number) +{ + assert_ptr_equal (dev_handle, device_handle); + assert_int_equal (interface_number, 0); + + return 0; +} + +/* + * Mock function libusb_release_interface. + */ +int __wrap_libusb_release_interface (libusb_device_handle *dev_handle, + int interface_number) +{ + assert_ptr_equal (dev_handle, device_handle); + assert_int_equal (interface_number, 0); + + return 0; +} + +/* + * Mock function libusb_control_transfer. + */ +int __wrap_libusb_control_transfer (libusb_device_handle *dev_handle, + uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + unsigned char *data, uint16_t wLength, unsigned int timeout) +{ + assert_ptr_equal (dev_handle, device_handle); + assert_int_equal (request_type, CTRL_SET); + assert_int_equal (bRequest, CY_CMD_SPI); + assert_int_equal (wValue, CY_SPI_WRITEREAD); + assert_null (data); + assert_int_equal (wLength, 0); + assert_int_equal (timeout, TIMEOUT); + + transfer_length = wIndex; + + return 0; +} + +/* + * Mock function libusb_bulk_transfer. + * + * Here we are imitating the best case scenario where the + * actual_length is always equal to length. In actual world, + * the transmission can be fragmented hence the actual_length < length, + * and multiple retries can happen to process the remaining length. + */ +int __wrap_libusb_bulk_transfer (libusb_device_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, + int *actual_length, unsigned int timeout) +{ + static tpm_state_t tpm_state = TPM_DID_VID_HEAD_RX; + + assert_ptr_equal (dev_handle, device_handle); + assert_int_equal (timeout, TIMEOUT); + assert_int_equal (length, transfer_length); + + switch (tpm_state) { + case TPM_DID_VID_HEAD_RX: + assert_true (endpoint == EP_OUT); + assert_int_equal (length, 8); + assert_true (!memcmp (data, TPM_DID_VID_0, 4)); + break; + case TPM_DID_VID_HEAD_TX: + assert_true (endpoint == EP_IN); + assert_int_equal (length, 8); + memcpy (data, TPM_DID_VID_0, sizeof (TPM_DID_VID_0)); + break; + case TPM_ACCESS_HEAD_RX: + assert_true (endpoint == EP_OUT); + assert_int_equal (length, 5); + assert_true (!memcmp (data, TPM_ACCESS_0, 4)); + break; + case TPM_ACCESS_HEAD_TX: + assert_true (endpoint == EP_IN); + assert_int_equal (length, 5); + memcpy (data, TPM_ACCESS_0, sizeof (TPM_ACCESS_0)); + break; + case TPM_STS_HEAD_RX: + assert_true (endpoint == EP_OUT); + assert_int_equal (length, 8); + assert_true (!memcmp (data, TPM_STS_0, 4)); + break; + case TPM_STS_HEAD_TX: + assert_true (endpoint == EP_IN); + assert_int_equal (length, 8); + memcpy (data, TPM_STS_0, sizeof (TPM_STS_0)); + break; + case TPM_RID_HEAD_RX: + assert_true (endpoint == EP_OUT); + assert_int_equal (length, 5); + assert_true (!memcmp (data, TPM_RID_0, 4)); + break; + case TPM_RID_HEAD_TX: + assert_true (endpoint == EP_IN); + assert_int_equal (length, 5); + memcpy (data, TPM_RID_0, sizeof (TPM_RID_0)); + break; + default: + assert_true (false); + } + + tpm_state += 1; + *actual_length = length; + + return 0; +} + +/* + * Mock function libusb_close. + */ +void __wrap_libusb_close (libusb_device_handle *dev_handle) +{ + assert_ptr_equal (dev_handle, device_handle); + free (usb_device); + free (dev_handle); +} + +/* + * Mock function libusb_exit. + */ +void __wrap_libusb_exit (libusb_context *ctx) +{ + assert_ptr_equal (ctx, context); + free (ctx); +} + +/* + * Mock function libusb_init. + */ +int __wrap_libusb_init (libusb_context **ctx) +{ + context = malloc (1); + *ctx = context; + + return 0; +} + +/* + * Mock function libusb_strerror. + */ +const char * __wrap_libusb_strerror (int errcode) +{ + return NULL; +} + +/* + * Mock function libusb_open_device_with_vid_pid. + */ +libusb_device_handle * __wrap_libusb_open_device_with_vid_pid ( + libusb_context *ctx, uint16_t vendor_id, uint16_t product_id) +{ + assert_ptr_equal (ctx, context); + assert_int_equal (vendor_id, VID_PI3G); + assert_int_equal (product_id, PID_LTT2GO); + + device_handle = malloc (1); + + return device_handle; +} + +/* + * Mock function libusb_dev_mem_alloc. + */ +unsigned char * __wrap_libusb_dev_mem_alloc (libusb_device_handle *dev_handle, + size_t length) +{ + assert_ptr_equal (dev_handle, device_handle); + + device_mem_alloc_length = length; + device_mem_alloc = malloc (length); + + return device_mem_alloc; +} + +/* + * Mock function libusb_dev_mem_free. + */ +int __wrap_libusb_dev_mem_free (libusb_device_handle *dev_handle, + unsigned char *buffer, size_t length) +{ + assert_ptr_equal (dev_handle, device_handle); + assert_ptr_equal (buffer, device_mem_alloc); + assert_int_equal (length, device_mem_alloc_length); + + free (dev_handle); + free (buffer); + + return 0; +} + +/* + * The test will invoke Tss2_Tcti_Spi_Ltt2go_Init() and subsequently + * it will start reading TPM_DID_VID, claim locality, read TPM_STS, + * and finally read TPM_RID before exiting the Init function. + * For testing purpose, the TPM responses are hardcoded. + * SPI wait state is not supported in this test. + */ +static void +tcti_spi_no_wait_state_success_test (void **state) +{ + TSS2_RC rc; + size_t size; + TSS2_TCTI_CONTEXT* tcti_ctx; + + /* Get requested TCTI context size */ + rc = Tss2_Tcti_Spi_Ltt2go_Init (NULL, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + assert_non_null (tcti_ctx); + + /* Initialize TCTI context */ + rc = Tss2_Tcti_Spi_Ltt2go_Init (tcti_ctx, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + TSS2_TCTI_SPI_HELPER_PLATFORM platform = ((TSS2_TCTI_SPI_HELPER_CONTEXT *) tcti_ctx)->platform; + free (platform.user_data); + free (tcti_ctx); +} + +int +main (int argc, + char *argv[]) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_spi_no_wait_state_success_test), + }; + + return cmocka_run_group_tests (tests, NULL, NULL); +} diff --git a/test/unit/tcti-spidev.c b/test/unit/tcti-spidev.c new file mode 100644 index 0000000..88d063e --- /dev/null +++ b/test/unit/tcti-spidev.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/***********************************************************************; + * Copyright (c) 2022, Infineon Technologies AG + * All rights reserved. + ***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "tss2_tcti.h" +#include "tss2_tcti_spidev.h" +#include "tss2_tcti_spi_helper.h" + +#include "tss2-tcti/tcti-common.h" +#include "tss2-tcti/tcti-spi-helper.h" +#include "util/key-value-parse.h" + +typedef enum { + TPM_DID_VID_HEAD = 0, + TPM_DID_VID_DATA, + TPM_ACCESS_HEAD, + TPM_ACCESS_DATA, + TPM_STS_CMD_NOT_READY_HEAD, + TPM_STS_CMD_NOT_READY_DATA, + TPM_STS_CMD_READY_HEAD, + TPM_STS_CMD_READY_DATA, + TPM_RID_HEAD, + TPM_RID_DATA, +} tpm_state_t; + +// First 4 bytes are the request, the remainder is the response +static const unsigned char TPM_DID_VID_0[] = {0x83, 0xd4, 0x0f, 0x00, 0xd1, 0x15, 0x1b, 0x00}; +static const unsigned char TPM_ACCESS_0[] = {0x80, 0xd4, 0x00, 0x00, 0xa1}; +static const unsigned char TPM_STS_0_CMD_NOT_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00}; +static const unsigned char TPM_STS_0_CMD_READY[] = {0x83, 0xd4, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00}; +static const unsigned char TPM_RID_0[] = {0x80, 0xd4, 0x0f, 0x04, 0x00}; + +/* + * Mock function select + */ +int __wrap_select (int nfds, fd_set *readfds, + fd_set *writefds, + fd_set *exceptfds, + struct timeval *timeout) +{ + + assert_int_equal (nfds, 0); + assert_null (readfds); + assert_null (writefds); + assert_null (exceptfds); + assert_non_null (timeout); + + return 0; +} + +/* + * Mock function gettimeofday + */ +int __wrap_gettimeofday (struct timeval *tv, + struct timezone *tz) +{ + assert_null (tz); + assert_non_null (tv); + + tv->tv_sec = 0; + tv->tv_usec = 0; + + return 0; +} + +int __real_open(const char *path, int flags); + +#define FD_NO 5 +int __wrap_open(const char *path, int flags) +{ + assert_ptr_not_equal(path, NULL); + if (!!strncmp(path, "/dev/spidev", sizeof("/dev/spidev") - 1)) + return __real_open(path, flags); + assert_int_equal(flags, O_RDWR); + return FD_NO; +} + +int __wrap_close(int fd) +{ + assert_int_equal(fd, FD_NO); + return 0; +} + +int __wrap_ioctl(int fd, unsigned long request, struct spi_ioc_transfer *tr) +{ + assert_int_equal(tr->delay_usecs, 0); + assert_int_equal(tr->bits_per_word, 8); + + size_t len = tr->len; + + /* Use size_t to cast 64 bit number to pointer (needed for 32 bit systems) */ + uint8_t *tx_buf = (uint8_t *)(size_t) tr->tx_buf; + uint8_t *rx_buf = (uint8_t *)(size_t) tr->rx_buf; + + static tpm_state_t tpm_state = TPM_DID_VID_HEAD; + + // Check for CS-acquire/-release which have no payload + if (len == 0) { + goto done; + } + + switch (tpm_state++) { + case TPM_DID_VID_HEAD: + assert_int_equal (len, 4); + assert_memory_equal(&tx_buf[0], TPM_DID_VID_0, 4); + rx_buf[3] = 0x01; // Set Waitstate OK + break; + case TPM_DID_VID_DATA: + assert_int_equal (len, sizeof (TPM_DID_VID_0) - 4); + memcpy (&rx_buf[0], &TPM_DID_VID_0[4], sizeof (TPM_DID_VID_0) - 4); + break; + case TPM_ACCESS_HEAD: + assert_int_equal (len, 4); + assert_memory_equal(&tx_buf[0], TPM_ACCESS_0, 4); + rx_buf[3] = 0x01; // Set Waitstate OK + break; + case TPM_ACCESS_DATA: + assert_int_equal (len, sizeof (TPM_ACCESS_0) - 4); + memcpy (&rx_buf[0], &TPM_ACCESS_0[4], sizeof (TPM_ACCESS_0) - 4); + break; + case TPM_STS_CMD_NOT_READY_HEAD: + assert_int_equal (len, 4); + assert_memory_equal(&tx_buf[0], TPM_STS_0_CMD_NOT_READY, 4); + rx_buf[3] = 0x01; // Set Waitstate OK + break; + case TPM_STS_CMD_NOT_READY_DATA: + assert_int_equal (len, sizeof (TPM_STS_0_CMD_NOT_READY) - 4); + memcpy (&rx_buf[0], &TPM_STS_0_CMD_NOT_READY[4], sizeof (TPM_STS_0_CMD_NOT_READY) - 4); + break; + case TPM_STS_CMD_READY_HEAD: + assert_int_equal (len, 4); + assert_memory_equal(&tx_buf[0], TPM_STS_0_CMD_READY, 4); + rx_buf[3] = 0x01; // Set Waitstate OK + break; + case TPM_STS_CMD_READY_DATA: + assert_int_equal (len, sizeof (TPM_STS_0_CMD_READY) - 4); + memcpy (&rx_buf[0], &TPM_STS_0_CMD_READY[4], sizeof (TPM_STS_0_CMD_READY) - 4); + break; + case TPM_RID_HEAD: + assert_int_equal (len, 4); + assert_memory_equal(&tx_buf[0], TPM_RID_0, 4); + rx_buf[3] = 0x01; // Set Waitstate OK + break; + case TPM_RID_DATA: + assert_int_equal (len, sizeof (TPM_RID_0) - 4); + memcpy (&rx_buf[0], &TPM_RID_0[4], sizeof (TPM_RID_0) - 4); + break; + default: + assert_true (false); + } + +done: + return 0; +} + +/* + * The test will invoke Tss2_Tcti_Spidev_Init() and subsequently + * it will start reading TPM_DID_VID, claim locality, read TPM_STS, + * and finally read TPM_RID before exiting the Init function. + * For testing purpose, the TPM responses are hardcoded. + */ +static void +tcti_spi_init_test (void **state) +{ + TSS2_RC rc; + size_t size; + TSS2_TCTI_CONTEXT* tcti_ctx; + + /* Get requested TCTI context size */ + rc = Tss2_Tcti_Spidev_Init (NULL, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + /* Allocate TCTI context size */ + tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc (1, size); + assert_non_null (tcti_ctx); + + /* Initialize TCTI context */ + rc = Tss2_Tcti_Spidev_Init (tcti_ctx, &size, NULL); + assert_int_equal (rc, TSS2_RC_SUCCESS); + + TSS2_TCTI_SPI_HELPER_PLATFORM platform = ((TSS2_TCTI_SPI_HELPER_CONTEXT *) tcti_ctx)->platform; + free (platform.user_data); + free (tcti_ctx); +} + +int +main (int argc, + char *argv[]) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test (tcti_spi_init_test), + }; + + return cmocka_run_group_tests (tests, NULL, NULL); +} diff --git a/test/unit/tctildr-dl.c b/test/unit/tctildr-dl.c index 4279bae..135e1b1 100644 --- a/test/unit/tctildr-dl.c +++ b/test/unit/tctildr-dl.c @@ -135,15 +135,21 @@ test_handle_from_name_null_handle (void **state) TSS2_RC rc = handle_from_name (NULL, NULL); assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE); } -#define TEST_TCTI_NAME "test-tcti" -#define TEST_TCTI_CONF "test-conf" +#define TEST_TCTI_NAME "testname" +#define TEST_TCTI_CONF "testconf" +/* see documentation at tcti.md */ +#define TEST_TCTI_TRY_A TEST_TCTI_NAME +#define TEST_TCTI_TRY_B "libtss2-tcti-" TEST_TCTI_NAME ".so.0" +#define TEST_TCTI_TRY_C "libtss2-tcti-" TEST_TCTI_NAME ".so" +#define TEST_TCTI_TRY_D "libtss2-" TEST_TCTI_NAME ".so.0" +#define TEST_TCTI_TRY_E "libtss2-" TEST_TCTI_NAME ".so" static void test_handle_from_name_first_dlopen_success (void **state) { TSS2_RC rc; void *handle = NULL; - expect_string(__wrap_dlopen, filename, TEST_TCTI_NAME); + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_A); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, TEST_HANDLE); @@ -152,18 +158,17 @@ test_handle_from_name_first_dlopen_success (void **state) assert_int_equal (handle, TEST_HANDLE); } -#define TEST_TCTI_NAME_SO_0 TCTI_PREFIX"-"TEST_TCTI_NAME""TCTI_SUFFIX_0 static void test_handle_from_name_second_dlopen_success (void **state) { TSS2_RC rc; void *handle = NULL; - expect_string(__wrap_dlopen, filename, TEST_TCTI_NAME); + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_A); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); - expect_string(__wrap_dlopen, filename, TEST_TCTI_NAME_SO_0); + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_B); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, TEST_HANDLE); @@ -171,22 +176,77 @@ test_handle_from_name_second_dlopen_success (void **state) assert_int_equal (rc, TSS2_RC_SUCCESS); assert_int_equal (handle, TEST_HANDLE); } -#define TEST_TCTI_NAME_SO TCTI_PREFIX"-"TEST_TCTI_NAME""TCTI_SUFFIX static void test_handle_from_name_third_dlopen_success (void **state) { TSS2_RC rc; void *handle = NULL; - expect_string(__wrap_dlopen, filename, TEST_TCTI_NAME); + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_A); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); - expect_string(__wrap_dlopen, filename, TEST_TCTI_NAME_SO_0); + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_B); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); - expect_string(__wrap_dlopen, filename, TEST_TCTI_NAME_SO); + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_C); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, TEST_HANDLE); + + rc = handle_from_name (TEST_TCTI_NAME, &handle); + assert_int_equal (rc, TSS2_RC_SUCCESS); + assert_int_equal (handle, TEST_HANDLE); +} +static void +test_handle_from_name_fourth_dlopen_success (void **state) +{ + TSS2_RC rc; + void *handle = NULL; + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_A); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_B); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_C); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_D); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, TEST_HANDLE); + + rc = handle_from_name (TEST_TCTI_NAME, &handle); + assert_int_equal (rc, TSS2_RC_SUCCESS); + assert_int_equal (handle, TEST_HANDLE); +} +static void +test_handle_from_name_fifth_dlopen_success (void **state) +{ + TSS2_RC rc; + void *handle = NULL; + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_A); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_B); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_C); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_D); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, TEST_TCTI_TRY_E); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, TEST_HANDLE); @@ -229,6 +289,14 @@ test_get_info_default_success (void **state) expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-default.so.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-default.so.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-tcti-tabrmd.so.0"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, HANDLE); @@ -261,6 +329,14 @@ test_get_info_default_info_fail (void **state) expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-default.so.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-default.so.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-tcti-tabrmd.so.0"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, HANDLE); @@ -413,6 +489,12 @@ test_tcti_fail_all (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-default.so.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-default.so.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-default.so.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); /* Skip over libtss2-tcti-tabrmd.so */ expect_string(__wrap_dlopen, filename, "libtss2-tcti-tabrmd.so.0"); @@ -424,6 +506,12 @@ test_tcti_fail_all (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-tabrmd.so.0.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-tabrmd.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-tabrmd.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); /* Skip over libtss2-tcti-device.so, /dev/tpmrm0 */ expect_string(__wrap_dlopen, filename, "libtss2-tcti-device.so.0"); @@ -435,6 +523,12 @@ test_tcti_fail_all (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-device.so.0.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-device.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-device.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); /* Skip over libtss2-tcti-device.so, /dev/tpm0 */ expect_string(__wrap_dlopen, filename, "libtss2-tcti-device.so.0"); @@ -446,6 +540,29 @@ test_tcti_fail_all (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-device.so.0.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-device.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-device.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + + /* Skip over libtss2-tcti-device.so, /dev/tcm0 */ + expect_string(__wrap_dlopen, filename, "libtss2-tcti-device.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-device.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-device.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-device.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-device.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); /* Skip over libtss2-tcti-swtpm.so */ expect_string(__wrap_dlopen, filename, "libtss2-tcti-swtpm.so.0"); @@ -457,6 +574,12 @@ test_tcti_fail_all (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-swtpm.so.0.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-swtpm.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-swtpm.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); /* Skip over libtss2-tcti-mssim.so */ expect_string(__wrap_dlopen, filename, "libtss2-tcti-mssim.so.0"); @@ -468,6 +591,12 @@ test_tcti_fail_all (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-libtss2-tcti-mssim.so.0.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-mssim.so.0.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-libtss2-tcti-mssim.so.0.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); TSS2_RC r; TSS2_TCTI_CONTEXT *tcti; @@ -496,6 +625,12 @@ test_info_from_name_handle_fail (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-foo.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-foo.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-foo.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); TSS2_RC rc = info_from_name ("foo", &info, &data); assert_int_equal (rc, TSS2_TCTI_RC_NOT_SUPPORTED); @@ -612,6 +747,12 @@ test_tctildr_get_info_from_name (void **state) expect_string(__wrap_dlopen, filename, "libtss2-tcti-foo.so"); expect_value(__wrap_dlopen, flags, RTLD_NOW); will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-foo.so.0"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); + expect_string(__wrap_dlopen, filename, "libtss2-foo.so"); + expect_value(__wrap_dlopen, flags, RTLD_NOW); + will_return(__wrap_dlopen, NULL); TSS2_RC rc = tctildr_get_info ("foo", &info, &data); assert_int_equal (rc, TSS2_TCTI_RC_NOT_SUPPORTED); @@ -659,6 +800,8 @@ main(void) cmocka_unit_test(test_handle_from_name_first_dlopen_success), cmocka_unit_test(test_handle_from_name_second_dlopen_success), cmocka_unit_test(test_handle_from_name_third_dlopen_success), + cmocka_unit_test(test_handle_from_name_fourth_dlopen_success), + cmocka_unit_test(test_handle_from_name_fifth_dlopen_success), cmocka_unit_test(test_fail_null), cmocka_unit_test(test_tcti_from_file_null_tcti), #ifndef ESYS_TCTI_DEFAULT_MODULE diff --git a/test/unit/tctildr-nodl.c b/test/unit/tctildr-nodl.c index b7d0808..2157463 100644 --- a/test/unit/tctildr-nodl.c +++ b/test/unit/tctildr-nodl.c @@ -62,6 +62,9 @@ test_tctildr_get_default_all_fail (void **state) TSS2_TCTI_CONTEXT *tcti_ctx = NULL; #define TEST_RC 0x65203563 + /* device:/dev/tcm0 */ + will_return(__wrap_tcti_from_init, tcti_ctx); + will_return(__wrap_tcti_from_init, TEST_RC); /* device:/dev/tpm0 */ will_return (__wrap_tcti_from_init, tcti_ctx); will_return (__wrap_tcti_from_init, TEST_RC); diff --git a/test/unit/tctildr.c b/test/unit/tctildr.c index 6dc9327..54fb938 100644 --- a/test/unit/tctildr.c +++ b/test/unit/tctildr.c @@ -247,6 +247,7 @@ tctildr_init_ex_default_fail (void **state) TSS2_RC rc; TSS2_TCTI_CONTEXT *context; + will_return (__wrap_calloc, &tcti_ctx); will_return (__wrap_tctildr_get_tcti, TSS2_TCTI_RC_BAD_REFERENCE); rc = Tss2_TctiLdr_Initialize_Ex (NULL, NULL, &context); assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE); @@ -257,6 +258,7 @@ tctildr_init_ex_from_file_fail (void **state) TSS2_RC rc; TSS2_TCTI_CONTEXT *context; + will_return (__wrap_calloc, &tcti_ctx); will_return (__wrap_tctildr_get_tcti, TSS2_TCTI_RC_BAD_REFERENCE); rc = Tss2_TctiLdr_Initialize_Ex ("foo", NULL, &context); assert_int_equal (rc, TSS2_TCTI_RC_BAD_REFERENCE); @@ -268,9 +270,6 @@ tctildr_init_ex_calloc_fail_test (void **state) TSS2_RC rc; TSS2_TCTI_CONTEXT *ctx; - will_return (__wrap_tctildr_get_tcti, TSS2_RC_SUCCESS); - will_return (__wrap_tctildr_get_tcti, &tcti_ctx); - will_return (__wrap_tctildr_get_tcti, TEST_TCTI_HANDLE); will_return (__wrap_calloc, NULL); rc = Tss2_TctiLdr_Initialize_Ex (NULL, NULL, &ctx); @@ -291,6 +290,56 @@ tctildr_init_ex_success_test (void **state) assert_int_equal (rc, TSS2_RC_SUCCESS); } static void +tctildr_tcti_init_size_test (void **state) +{ + size_t tcti_size = 0; + TSS2_RC ret = TSS2_RC_SUCCESS; + + ret = Tss2_Tcti_TctiLdr_Init (NULL, &tcti_size, NULL); + assert_int_equal (ret, TSS2_RC_SUCCESS); +} +static void +tctildr_tcti_init_conf_fail (void **state) +{ + size_t tcti_size = 0; + TSS2_RC ret = TSS2_RC_SUCCESS; + TSS2_TCTILDR_CONTEXT ctx = {0}; + + ret = Tss2_Tcti_TctiLdr_Init (NULL, &tcti_size, NULL); + assert_true (ret == TSS2_RC_SUCCESS); + assert_int_equal (tcti_size, sizeof (TSS2_TCTILDR_CONTEXT)); + + will_return (__wrap_tctildr_get_tcti, TSS2_TCTI_RC_IO_ERROR); + ret = Tss2_Tcti_TctiLdr_Init ( (TSS2_TCTI_CONTEXT *) &ctx, &tcti_size, "/path/to/nonexistent"); + assert_true (ret == TSS2_TCTI_RC_IO_ERROR); +} +static void +tctildr_tcti_init_all_null_test (void **state) +{ + TSS2_RC rc; + + rc = Tss2_Tcti_TctiLdr_Init (NULL, NULL, NULL); + assert_int_equal (rc, TSS2_TCTI_RC_BAD_VALUE); +} +static void +tctildr_tcti_init_conf_fail_test (void **state) +{ + size_t tcti_size = 0; + TSS2_RC ret = TSS2_RC_SUCCESS; + TSS2_TCTILDR_CONTEXT ctx = {0}; + char name[PATH_MAX+1]; + + ret = Tss2_Tcti_TctiLdr_Init (NULL, &tcti_size, NULL); + assert_true (ret == TSS2_RC_SUCCESS); + assert_int_equal (tcti_size, sizeof (TSS2_TCTILDR_CONTEXT)); + + memset(&name[0], 'a', sizeof(name)); + name[PATH_MAX] = '\0'; + + ret = Tss2_Tcti_TctiLdr_Init ( (TSS2_TCTI_CONTEXT *) &ctx, &tcti_size, name); + assert_int_equal (ret, TSS2_TCTI_RC_BAD_VALUE); +} +static void tctildr_finalize_null_ref_test (void **state) { Tss2_TctiLdr_Finalize (NULL); @@ -341,6 +390,10 @@ main(void) cmocka_unit_test (tctildr_init_ex_from_file_fail), cmocka_unit_test (tctildr_init_ex_calloc_fail_test), cmocka_unit_test (tctildr_init_ex_success_test), + cmocka_unit_test (tctildr_tcti_init_size_test), + cmocka_unit_test (tctildr_tcti_init_conf_fail), + cmocka_unit_test (tctildr_tcti_init_all_null_test), + cmocka_unit_test (tctildr_tcti_init_conf_fail_test), cmocka_unit_test (tctildr_finalize_null_ref_test), cmocka_unit_test (tctildr_finalize_null_ctx_test), cmocka_unit_test (tctildr_finalize_test), diff --git a/test/unit/test_tss2_rc.c b/test/unit/test_tss2_rc.c index 1bfedbf..4eb263a 100644 --- a/test/unit/test_tss2_rc.c +++ b/test/unit/test_tss2_rc.c @@ -197,7 +197,7 @@ test_custom_handler(void **state) * Test an unknown layer */ e = Tss2_RC_Decode(rc); - assert_string_equal(e, "1:0x100"); + assert_string_equal(e, "1:0x1002A"); } static void @@ -413,7 +413,7 @@ test_all_FFs(void **state) (void) state; const char *e = Tss2_RC_Decode(0xFFFFFFFF); - assert_string_equal(e, "255:0xFFFFFF"); + assert_string_equal(e, "255:0xFFFFFFFF"); } static void diff --git a/tpm2-tss.sln b/tpm2-tss.sln index 630ce69..edf5ab7 100644 --- a/tpm2-tss.sln +++ b/tpm2-tss.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27130.2027 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32505.173 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tss2-mu", "src\tss2-mu\tss2-mu.vcxproj", "{A6D8F061-6827-492F-80C3-32C4DD4FC52E}" EndProject diff --git a/tss2-dlopen/tss2-dlopen-mu.c b/tss2-dlopen/tss2-dlopen-mu.c index facb2ee..8ba9929 100644 --- a/tss2-dlopen/tss2-dlopen-mu.c +++ b/tss2-dlopen/tss2-dlopen-mu.c @@ -253,7 +253,9 @@ MAKE_MU_STRUCT(TPML_ALG_PROPERTY); MAKE_MU_STRUCT(TPML_ECC_CURVE); MAKE_MU_STRUCT(TPML_TAGGED_PCR_PROPERTY); MAKE_MU_STRUCT(TPML_TAGGED_TPM_PROPERTY); +#ifndef DISABLE_VENDOR MAKE_MU_STRUCT(TPML_INTEL_PTT_PROPERTY); +#endif MAKE_MU_STRUCT(TPML_AC_CAPABILITIES); MAKE_MU_STRUCT(TPML_TAGGED_POLICY); MAKE_MU_STRUCT(TPML_ACT_DATA);