[
  {
    "path": ".ci/coverity.run",
    "content": "#!/usr/bin/env bash\n# SPDX-License-Identifier: BSD-2\n\nset -eo pipefail\n\necho \"PROJECT=$PROJECT\"\n\nif [ -z \"$COVERITY_SCAN_TOKEN\" ]; then\n  echo \"coverity.run invoked without COVERITY_SCAN_TOKEN set...exiting!\"\n  exit 1\nfi\n\nif [ -z \"$COVERITY_SUBMISSION_EMAIL\" ]; then\n  echo \"coverity.run invoked without COVERITY_SUBMISSION_EMAIL set...exiting!\"\n  exit 1\nfi\n\n# Sanity check, this should only be executing on the coverity_scan branch\nif [[ \"$REPO_BRANCH\" != *coverity_scan ]]; then\n  echo \"coverity.run invoked for non-coverity branch $REPO_BRANCH...exiting!\"\n  exit 1\nfi\n\nif [[ \"$CC\" == clang* ]]; then\n  echo \"Coverity scan branch detected, not running with clang...exiting!\"\n  exit 1\nfi\n\n# branch is coverity_scan\necho \"Running coverity build\"\n\n# ensure coverity_scan tool is available to the container\n# We cannot package these in the docker image, as we would be distributing their software\n# for folks not coupled to our COVERITY_SCAN_TOKEN.\nif [ ! -f \"$(pwd)/cov-analysis/bin/cov-build\" ]; then\n  curl --data-urlencode \"project=$PROJECT\" \\\n       --data-urlencode \"token=$COVERITY_SCAN_TOKEN\" \\\n       \"https://scan.coverity.com/download/linux64\" -o coverity_tool.tgz\n\n  stat coverity_tool.tgz\n\n  curl --data-urlencode \"project=$PROJECT\" \\\n       --data-urlencode \"token=$COVERITY_SCAN_TOKEN\" \\\n       --data-urlencode \"md5=1\" \\\n       \"https://scan.coverity.com/download/linux64\" -o coverity_tool.md5\n\n  stat coverity_tool.md5\n  cat coverity_tool.md5\n  md5sum coverity_tool.tgz\n  echo \"$(cat coverity_tool.md5)\" coverity_tool.tgz | md5sum -c\n\n  echo \"unpacking cov-analysis\"\n  tar -xf coverity_tool.tgz\n  mv cov-analysis-* cov-analysis\nfi\n\nexport PATH=$PATH:$(pwd)/cov-analysis/bin\n\necho \"Which cov-build: $(which cov-build)\"\n\n# get the deps to build with\n$DOCKER_BUILD_DIR/.ci/get_deps.sh \"$(dirname $DOCKER_BUILD_DIR)\"\n\npushd \"$DOCKER_BUILD_DIR\"\n\necho \"Performing build with Coverity Scan\"\nrm -rf cov-int\n./bootstrap && ./configure --enable-debug && make clean\ncov-build --dir $DOCKER_BUILD_DIR/cov-int make -j $(nproc)\n\necho \"Collecting Coverity data for submission\"\nrm -fr README\nAUTHOR=\"$(git log -1 $HEAD --pretty=\"%aN\")\"\nAUTHOR_EMAIL=\"$(git log -1 $HEAD --pretty=\"%aE\")\"\nVERSION=\"$(git rev-parse HEAD)\"\necho \"Name: $AUTHOR\" >> README\necho \"Email: $AUTHOR_EMAIL\" >> README\necho \"Project: tpm2-pkcs11\" >> README\necho \"Build-Version: $VERSION\" >> README\necho \"Description: $REPO_NAME $REPO_BRANCH\" >> README\necho \"Submitted-by: tpm2-pkcs11 CI\" >> README\necho \"---README---\"\ncat README\necho \"---EOF---\"\n\nrm -f tpm2-pkcs11-scan.tgz\ntar -czf tpm2-pkcs11-scan.tgz README cov-int\n\nrm -rf README cov-int\n\n# upload the results\necho \"Testing for scan results...\"\nscan_file=$(stat --printf='%n' tpm2-*-scan.tgz)\n\necho \"Submitting data to Coverity\"\ncurl --form token=\"$COVERITY_SCAN_TOKEN\" \\\n  --form email=\"$COVERITY_SUBMISSION_EMAIL\" \\\n  --form project=\"$PROJECT\" \\\n  --form file=@\"$scan_file\" \\\n  --form version=\"$VERSION\" \\\n  --form description=\"$REPO_NAME $REPO_BRANCH\" \\\n  \"https://scan.coverity.com/builds?project=$PROJECT\"\n\nrm -rf tpm2-*-scan.tgz\n\npopd\n\nexit 0\n"
  },
  {
    "path": ".ci/docker.env",
    "content": "# SPDX-License-Identifier: BSD-2\n\nPROJECT\nDOCKER_BUILD_DIR\nLD_LIBRARY_PATH=/usr/local/lib/\n\nCC\n\nCOVERITY_SCAN_TOKEN\nCOVERITY_SUBMISSION_EMAIL\n\nPROJECT\n\nREPO_BRANCH\nREPO_NAME\n\nENABLE_COVERAGE\nENABLE_FUZZING\nDOCKER_IMAGE\n\nTPM2TSS_BRANCH\nTPM2TOOLS_BRANCH\n"
  },
  {
    "path": ".ci/docker.run",
    "content": "#!/usr/bin/env bash\n# SPDX-License-Identifier: BSD-2\n\nset -exo pipefail\n\ngit config --global --add safe.directory /workspace/tpm2-tss-engine\n\n$DOCKER_BUILD_DIR/.ci/get_deps.sh \"$(dirname $DOCKER_BUILD_DIR)\"\n\npushd $DOCKER_BUILD_DIR\n\nSCAN_PREFIX=\"\"\nCONFIGURE_OPTIONS=\"\"\n\nif [ -d build ]; then\n  rm -rf build\nfi\n\n./bootstrap\n\nmkdir build\npushd build\n\nif [ -z \"$CC\" -o \"$CC\" == \"gcc\" ]; then\n  export CONFIGURE_OPTIONS+=\" --enable-code-coverage\";\nelse\n  export SCAN_PREFIX=\"scan-build --status-bugs\"\nfi\n\n$SCAN_PREFIX ../configure $CONFIGURE_OPTIONS --enable-unit --enable-integration\n$SCAN_PREFIX make -j$(nproc)\n\nmake -j$(nproc) check\ncat test-suite.log config.log\n../configure $CONFIGURE_OPTIONS\nmake -j$(nproc) distcheck\ncat config.log\npopd\n\npopd\n"
  },
  {
    "path": ".ci/get_deps.sh",
    "content": "# SPDX-License-Identifier: BSD-2\n\nset -exo pipefail\n\npushd \"$1\"\n\nif [ -z \"$TPM2TSS_BRANCH\" ]; then\n    echo \"TPM2TSS_BRANCH is unset, please specify TPM2TSS_BRANCH\"\n    exit 1\nfi\n\nif [ -z \"$TPM2TOOLS_BRANCH\" ]; then\n    echo \"TPM2TOOLS_BRANCH is unset, please specify TPM2TOOLS_BRANCH\"\n    exit 1\nfi\n\n# Install tpm2-tss\nif [ ! -d tpm2-tss ]; then\n\n  git clone --depth=1 -b \"${TPM2TSS_BRANCH}\" \"https://github.com/tpm2-software/tpm2-tss.git\"\n  pushd tpm2-tss\n  ./bootstrap\n  ./configure --enable-debug\n  make -j$(nproc)\n  make install\n  popd\nelse\n  echo \"tpm2-tss already installed, skipping...\"\nfi\n\n# Install tpm2-tools\nif [ ! -d tpm2-tools ]; then\n  git clone --depth=1 -b \"${TPM2TOOLS_BRANCH}\" \"https://github.com/tpm2-software/tpm2-tools.git\"\n  pushd tpm2-tools\n  ./bootstrap\n  ./configure --enable-debug --disable-hardening\n  make -j$(nproc)\n  make install\n  popd\nelse\n  echo \"tpm2-tss already installed, skipping...\"\nfi\n\npopd\n\nexit 0\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: Linux Build Status\non:\n  [push, pull_request]\njobs:\n  build-test:\n    runs-on: ubuntu-latest\n    if: \"!contains(github.ref, 'coverity_scan')\"\n    strategy:\n      matrix:\n        DOCKER_IMAGE: [ \"ubuntu-18.04\", \"ubuntu-20.04\", \"fedora-32\", \"opensuse-leap\" ]\n        TPM2TSS_BRANCH: [\"3.0.x\"]\n        TPM2TOOLS_BRANCH: [\"4.0\"]\n        CC: [\"gcc\", \"clang\"]\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v2\n      - name: Launch Action\n        uses:\n          tpm2-software/ci/runCI@main\n        with:\n          DOCKER_IMAGE: \"${{ matrix.DOCKER_IMAGE }}\"\n          TPM2TSS_BRANCH: \"${{ matrix.TPM2TSS_BRANCH }}\"\n          TPM2TOOLS_BRANCH: \"${{ matrix.TPM2TOOLS_BRANCH }}\"\n          CC: \"${{ matrix.CC }}\"\n          PROJECT_NAME: ${{ github.event.repository.name }}\n      - name: failure\n        if: ${{ failure() }}\n        run: cat build/test-suite.log || true\n  multi-arch:\n    runs-on: ubuntu-latest\n    if: \"!contains(github.ref, 'coverity_scan')\"\n    strategy:\n      matrix:\n        ARCH: [\n          \"ubuntu-20.04.arm32v7\",\n        ]\n        TPM2TSS_BRANCH: [\"3.0.x\"]\n        TPM2TOOLS_BRANCH: [\"4.0\"]\n    steps:\n      - name: Setup QEMU\n        run: |\n          sudo apt-get update\n          sudo apt-get install qemu binfmt-support qemu-user-static\n          docker run --rm --privileged multiarch/qemu-user-static --reset -p yes\n      - name: Check out repository\n        uses: actions/checkout@v2\n      - name: Launch Action\n        uses:\n          tpm2-software/ci/runCI@main\n        with:\n          PROJECT_NAME: ${{ github.event.repository.name }}\n          DOCKER_IMAGE: ${{ matrix.ARCH }}\n          TPM2TSS_BRANCH: \"${{ matrix.TPM2TSS_BRANCH }}\"\n          TPM2TOOLS_BRANCH: \"${{ matrix.TPM2TOOLS_BRANCH }}\"\n          CC: gcc\n      - name: failure\n        if: ${{ failure() }}\n        run: find -name test-suite.log | xargs cat || true\n  coverity-test:\n    runs-on: ubuntu-latest\n    if: contains(github.ref, 'coverity_scan') && github.event_name == 'push'\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v2\n      - name: Launch Coverity Action\n        uses:\n          tpm2-software/ci/coverityScan@main\n        with:\n          PROJECT_NAME: ${{ github.event.repository.name }}\n          ENABLE_COVERITY: true\n          TPM2TSS_BRANCH: \"3.0.x\"\n          TPM2TOOLS_BRANCH: \"4.0\"\n          REPO_BRANCH: ${{ github.ref }}\n          REPO_NAME: ${{ github.repository }}\n          DOCKER_IMAGE: ubuntu-18.04\n          CC: gcc\n          COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}\n          COVERITY_SUBMISSION_EMAIL: william.c.roberts@intel.com\n  whitespace-check:\n    runs-on: ubuntu-latest\n    if: github.event_name == 'pull_request' && !contains(github.ref, 'coverity_scan')\n    steps:\n      - name: Check out repository\n        uses: actions/checkout@v2\n      - name: Perform Whitespace Check\n        env:\n          BASE_REF: ${{ github.base_ref }}\n        run: git fetch origin \"$BASE_REF\" && git diff --check \"origin/$BASE_REF\"\n"
  },
  {
    "path": ".gitignore",
    "content": ".deps/\n.libs/\nMakefile\nMakefile.in\naclocal.m4\naminclude_static.am\nautom4te.cache/\ncompile\nconfig.guess\nconfig.log\nconfig.status\nconfig.sub\nconfigure\ndepcomp\ninstall-sh\nlibtool\nlibtpm2.la\nltmain.sh\nm4/libtool.m4\nm4/ltoptions.m4\nm4/ltsugar.m4\nm4/ltversion.m4\nm4/lt~obsolete.m4\nmissing\nsrc/.dirstamp\nsrc/.libs/\nsrc/*.o\nsrc/*.lo\ntpm2tss-genkey\nlibtpm2tss.la\n*.gcno\n*.gcda\nopenssl-tpm2-engine-0.0.1-coverage.info\nopenssl-tpm2-engine-0.0.1-coverage/\n*.log\n*.trs\ntest-driver\nman/*.1\nman/*.3\nman/*.7\n.dirstamp\n*~\ntest/error_tpm2-tss-engine-common\ntest/*.o\nconfig.h.in\nVERSION\n"
  },
  {
    "path": ".lgtm.yml",
    "content": "extraction:\n  cpp:\n    prepare:\n      packages:\n      - autoconf-archive\n      - libcurl4-openssl-dev\n      - libjson-c-dev\n      - libssl-dev\n      - acl\n    after_prepare:\n    - cd \"$LGTM_WORKSPACE\"\n    - mkdir installdir\n    - git clone https://github.com/tpm2-software/tpm2-tss.git\n    - cd tpm2-tss\n    - ./bootstrap\n    - ./configure --prefix=\"$LGTM_WORKSPACE/installdir/usr\" --disable-doxygen-doc\n    - make install\n    - export PKG_CONFIG_PATH=\"$LGTM_WORKSPACE/installdir/usr/lib/pkgconfig:$PKG_CONFIG_PATH\"\n    - export LD_LIBRARY_PATH=\"$LGTM_WORKSPACE/installdir/usr/lib:$LD_LIBRARY_PATH\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [1.2.0] - 2023-01-09\n### Fixed\n- Updated minimal version of tpm2-tss to 2.4.x\n- Fix encoding of emptyauth\n- Fix some memory leaks\n- Parent handle issues with signed representation by switching parent handle to BIGNUM.\n- Fixed RSA_NO_PADDING modes with OpenSSL 1.1.1\n- Fixed autogen (bootstrap) call from release package by embedding VERSION file.\n\n### Added\n- Use of restricted keys for signing\n- StirRandom\n- Run tests using swtpm\n- The ability to import key blobs from things like the tpm2-tools project.\n- Compatibility with openssl >=1.1.x\n- Support for ECDH\n- QNX support.\n- Only set -Werror for non-release builds.\n- Additional checks on TPM responses\n- CODE_OF_CONDUCT\n- SECURITY reporting instructions\n\n## [1.1.0] - 2020-11-20\n### Added\n- Configure option for ptpm tests\n- Configure script AX_CHECK_ENABLE_DEBUG\n- Option for setting tcti on executable\n- TCTI-env variable used by default\n- Support for parent key passwords\n- openssl.cnf sample file\n\n### Changed\n- Fix several build system, autotools and testing related issues\n  Now adhere to CFLAGS conventions\n- Include pkg-config dependecy on libtss2-mu in order to work with tpm2-tss 2.3\n- Enables parallel testing of integration tests:\n  Make integration tests use TPM simulator; instead of first TPM it finds\n  Use of different port numbers for TCP based tests\n- Fix EC param info (using named curve format)\n- Use tpm2-tools 4.X stable branch for integration tests\n- Use libtss2-tctildr.so instead of custom code for tcti setup\n- Fix manpages for -P/--parent option and correct engine name\n- Fix TCTI env variable handling\n\n## [1.0.0] - 2019-04-04\n### Added\n- Initial release of the OpenSSL engine for TPM2.0 using the TCG's TPM\n  Software Stack compliant tpm2-tss libraries.\n- tpm2tss (the engine) compatible against OpenSSL 1.0.2 and 1.1.0.\n- tpm2tss-genkey (cli-tool) for creating keys for use with the engine.\n- man-pages and bash-completion are included.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "\n# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[MAINTAINERS](MAINTAINERS).\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Guidelines for submitting bugs:\nAll non security bugs should be filed on the Issues tracker:\nhttps://github.com/tpm2-software/tpm2-tss-engine/issues\n\nSecurity sensitive bugs should follow the details in SECURITY.md.\n\n# Guideline for submitting changes:\nAll changes to the source code must follow the coding standard used in the\ntpm2-tss project [here](https://github.com/tpm2-software/tpm2-tss/blob/master/doc/coding_standard_c.md).\n\nAll changes should be introduced via github pull requests. This allows anyone to\ncomment and provide feedback in lieu of having a mailing list. For pull requests\nopened by non-maintainers, any maintainer may review and merge that pull\nrequest. For maintainers, they either must have their pull request reviewed by\nanother maintainer if possible, or leave the PR open for at least 24 hours, we\nconsider this the window for comments.\n\n## Patch requirements\n* All tests must pass on Travis CI for the merge to occur.\n* All changes must not introduce superfluous changes or whitespace errors.\n* All commits should adhere to the git commit message guidelines described\nhere: https://chris.beams.io/posts/git-commit/ with the following exceptions.\n * We allow commit subject lines up to 80 characters.\n* All contributions must adhere to the Developers Certificate of Origin. The\nfull text of the DCO is here: https://developercertificate.org/. Contributors\nmust add a 'Signed-off-by' line to their commits. This indicates the\nsubmitters acceptance of the DCO.\n\n## Guideline for merging changes\nPull Requests MUST be assigned to an upcoming release tag. If a release milestone does\nnot exist, the maintainer SHALL create it per the [RELEASE.md](RELEASE.md) instructions.\nWhen accepting and merging a change, the maintainer MUST edit the description field for\nthe release milestone to add the CHANGELOG entry.\n\nChanges must be merged with the \"rebase\" option on github to avoid merge commits.\nThis provides for a clear linear history.\n"
  },
  {
    "path": "INSTALL.md",
    "content": "# Dependencies\n\n## GNU/Linux\n* GNU Autoconf\n* GNU Autoconf Archive\n* GNU Automake\n* GNU Libtool\n* C compiler\n* C library development libraries and header files\n* pkg-config\n* OpenSSL >= 1.0.2\n* tpm2-tss >= 2.4.x\n* pandoc\n* doxygen\n\nIntegration tests also require:\n* expect\n* tpm2-tools 4.0 (or 4.X branch)\n* [swtpm](https://github.com/stefanberger/swtpm) or [tpm_server](https://sourceforge.net/projects/ibmswtpm2/)\n* realpath\n* ss\n\n## Ubuntu\n```\nsudo apt -y install \\\n  build-essential \\\n  autoconf \\\n  autoconf-archive \\\n  automake \\\n  m4 \\\n  libtool \\\n  gcc \\\n  pkg-config \\\n  libssl-dev \\\n  pandoc \\\n  doxygen\n\ngit clone http://www.github.com/tpm2-software/tpm2-tss\ncd tpm2-tss\n./bootstrap\n./configure\nmake -j$(nproc)\nsudo make install\n```\n\nIntegration tests:\n```\nsudo apt -y install  \\\n  expect \\\n  realpath \\\n  ss\n\ngit clone http://github.com/tpm2-software/tpm2-tools\ncd tpm2-tools\n./bootstrap\n./configure\nmake -j$(nproc)\nsudo make install\n\nwget https://downloads.sourceforge.net/project/ibmswtpm2/ibmtpm1682.tar.gz\nmkdir ibmtpm\ntar axf ibmtpm1682.tar.gz -C ibmtpm\nmake -C ibmtpm/src -j$(nproc)\nsudo cp ibmtpm/src/tpm_server /usr/local/bin\n```\n\n# Building from source\n```\ngit clone http://www.github.com/tpm2-software/tpm2-tss-engine\n./bootstrap\n./configure\nmake -j$(nproc)\nsudo make install\n```\n\n# Configuration options\nYou may pass the following options to `./configure`\n\n## Debug messages\nThis option will enable a lot of debug printing during the invocation of the\nlibrary:\n```\n./configure --enable-debug\n```\n\n## Developer linking\nIn order to link against a developer version of tpm2-tss (not installed):\n```\n./configure \\\n  PKG_CONFIG_PATH=${TPM2TSS}/lib:$PKG_CONFIG_PATH \\\n  CFLAGS=-I${TPM2TSS}/include \\\n  LDFLAGS=-L${TPM2TSS}/src/tss2-{tcti,mu,sys,esys}/.libs \n```\n\n## Testing\nIn order to build the tests, pass the following options\n(see the additional dependencies above):\n```\n./configure --enable-integration --enable-unit\nmake check\n```\n\n# Post installation\n\n## ldconfig\nYou may need to run ldconfig after `make install` to update runtime bindings:\n```\nsudo ldconfig\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "Redistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "MAINTAINERS",
    "content": "Andreas Fuchs <andreas.fuchs@sit.fraunhofer.de>\nJuergen Repp <juergen.repp@sit.fraunhofer.de> (occasionally)\n"
  },
  {
    "path": "Makefile.am",
    "content": "#;*****************************************************************************;\n# Copyright (c) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#\n# 1. Redistributions of source code must retain the above copyright notice,\n# this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright notice,\n# this list of conditions and the following disclaimer in the documentation\n# and/or other materials provided with the distribution.\n#\n# 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n# may be used to endorse or promote products derived from this software\n# without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n# THE POSSIBILITY OF SUCH DAMAGE.\n#;*****************************************************************************;\n\n### Initialize global variables used throughout the file ###\nINCLUDE_DIRS    = -I$(srcdir)/include -I$(srcdir)/src\nACLOCAL_AMFLAGS = -I m4 --install\nAM_CFLAGS       = $(INCLUDE_DIRS) $(EXTRA_CFLAGS) $(TSS2_ESYS_CFLAGS) \\\n                  $(TSS2_MU_CFLAGS) $(TSS2_TCTILDR_CFLAGS) $(CRYPTO_CFLAGS) \\\n                  $(CODE_COVERAGE_CFLAGS)\nAM_LDFLAGS      = $(EXTRA_LDFLAGS) $(CODE_COVERAGE_LIBS)\nAM_LDADD        = $(TSS2_ESYS_LIBS) $(TSS2_MU_LIBS) $(TSS2_TCTILDR_LIBS) \\\n                  $(CRYPTO_LIBS)\n\nAM_DISTCHECK_CONFIGURE_FLAGS = --with-enginesdir= --with-completionsdir= \\\n                               --enable-unit\n\n# Initialize empty variables to be extended throughout\nEXTRA_DIST =\nCLEANFILES =\nbin_PROGRAMS =\n\n### Add ax_* rules ###\n# ax_code_coverage\nif AUTOCONF_CODE_COVERAGE_2019_01_06\ninclude $(top_srcdir)/aminclude_static.am\nclean-local: code-coverage-clean\ndistclean-local: code-coverage-dist-clean\nelse\n@CODE_COVERAGE_RULES@\nendif\n\n# ax_valgrind_check\n@VALGRIND_CHECK_RULES@\n\n### OpenSSL Engine ###\nopenssl_enginedir = $(ENGINESDIR)\nopenssl_engine_LTLIBRARIES = libtpm2tss.la\n\ninclude_HEADERS = include/tpm2-tss-engine.h\n\nlibtpm2tss_la_SOURCES = src/tpm2-tss-engine.c \\\n                        src/tpm2-tss-engine-common.c \\\n                        src/tpm2-tss-engine-common.h \\\n                        src/tpm2-tss-engine-digest-sign.c \\\n                        src/tpm2-tss-engine-err.c \\\n                        src/tpm2-tss-engine-err.h \\\n                        src/tpm2-tss-engine-ecc.c \\\n                        src/tpm2-tss-engine-rand.c \\\n                        src/tpm2-tss-engine-rsa.c\nlibtpm2tss_la_CFLAGS = $(AM_CFLAGS)\nlibtpm2tss_la_LIBADD = $(AM_LDADD)\nlibtpm2tss_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -avoid-version \\\n            -export-symbols-regex '(tpm2tss*|bind_engine|v_check)'\n\ninstall-exec-local:\n\t([ -e $(DESTDIR)$(openssl_enginedir) ] || \\\n         $(MKDIR_P) $(DESTDIR)$(openssl_enginedir))\n\n# Due to confusions with OpenSSL Naming conventions for engines regarding the\n# lib* prefix, we will create a symlink for the engine on install\n# see https://github.com/tpm2-software/tpm2-tss-engine/issues/6#issuecomment-422489744\n# see https://github.com/openssl/openssl/commit/9ee0ed3de66678a15db126d10b3e4226e835b8f5 \ninstall-exec-hook:\n\t(cd $(DESTDIR)$(openssl_enginedir) && \\\n         $(LN_S) -f libtpm2tss.so tpm2tss.so)\n\nuninstall-hook:\n\t(cd $(DESTDIR)$(openssl_enginedir) && \\\n         [ -L tpm2tss.so ] && rm -f tpm2tss.so)\n\n### KeyGenerator ###\nbin_PROGRAMS += tpm2tss-genkey\n\ntpm2tss_genkey_SOURCES = src/tpm2tss-genkey.c\ntpm2tss_genkey_CFLAGS = $(AM_CFLAGS)\ntpm2tss_genkey_LDADD = $(AM_LDADD) libtpm2tss.la\ntpm2tss_genkey_LDFLAGS = $(AM_LDFLAGS)\n\n### Tests ###\nTESTS = $(TESTS_INTEGRATION) $(TESTS_UNIT)\n\ncheck_PROGRAMS = $(TESTS_UNIT)\nTESTS_UNIT =\nTESTS_INTEGRATION =\n\nif INTEGRATION\nTESTS_INTEGRATION += $(TESTS_SHELL)\nendif #INTEGRATION\nTESTS_SHELL = test/ecdsa.sh \\\n              test/ecdsa-emptyauth.sh \\\n              test/ecdsa-handle-flush.sh \\\n              test/rand.sh \\\n              test/rsadecrypt.sh \\\n              test/rsasign.sh \\\n              test/failload.sh \\\n              test/failwrite.sh \\\n              test/rsasign_importtpm.sh \\\n              test/rsasign_importtpmparent.sh \\\n              test/rsasign_parent.sh \\\n              test/rsasign_parent_pass.sh \\\n              test/rsasign_persistent.sh \\\n              test/rsasign_persistent_emptyauth.sh \\\n              test/sserver.sh \\\n              test/sclient.sh\nif HAVE_OPENSSL_ECDH\nTESTS_SHELL += test/ecdh.sh\nendif\nif HAVE_OPENSSL_DIGEST_SIGN\nTESTS_SHELL += test/ecdsa-restricted.sh \\\n               test/rsasign_restricted.sh\nendif\nEXTRA_DIST += $(TESTS_SHELL) test/neg-handle.pem\nTEST_EXTENSIONS = .sh\nSH_LOG_COMPILER = $(srcdir)/test/sh_log_compiler.sh\nSH_LOG_FLAGS = $(INTEGRATION_ARGS)\nEXTRA_DIST += $(SH_LOG_COMPILER)\n\nif UNIT\nTESTS_UNIT += test/error_tpm2-tss-engine-common test/tpm2-tss-engine-common\ntest_error_tpm2_tss_engine_common_CFLAGS =  $(AM_CFLAGS) $(CMOCKA_CFLAGS)\ntest_error_tpm2_tss_engine_common_LDADD =   $(AM_LDADD) $(CMOCKA_LIBS)\ntest_error_tpm2_tss_engine_common_LDFLAGS = $(AM_LDFLAGS) -Wl,--wrap=Esys_Initialize\ntest_error_tpm2_tss_engine_common_SOURCES = test/error_tpm2-tss-engine-common.c \\\n                                            $(libtpm2tss_la_SOURCES)\ntest_tpm2_tss_engine_common_CFLAGS =  $(AM_CFLAGS) $(CMOCKA_CFLAGS) \\\n                                            -DNEG_HANDLE_PEM=\\\"$(top_srcdir)/test/neg-handle.pem\\\"\ntest_tpm2_tss_engine_common_LDADD =   $(AM_LDADD) $(CMOCKA_LIBS)\ntest_tpm2_tss_engine_common_LDFLAGS = $(AM_LDFLAGS)\ntest_tpm2_tss_engine_common_SOURCES = test/tpm2-tss-engine-common.c \\\n                                            $(libtpm2tss_la_SOURCES)\nendif #UNIT\n\n# Adding user and developer information\nEXTRA_DIST += \\\n    CHANGELOG.md \\\n    CONTRIBUTING.md \\\n    INSTALL.md \\\n    LICENSE \\\n    README.md \\\n    VERSION\n\n# Generate the AUTHORS file from git log\nAUTHORS:\n\t$(AM_V_GEN)git log --format='%aN <%aE>' | \\\n\t\t\tgrep -v 'users.noreply.github.com' | sort -u > $@\nEXTRA_DIST += AUTHORS\nCLEANFILES += AUTHORS\n\nif HAVE_MAN_PAGES\n### Man Pages\ndist_man_MANS = \\\n    man/man1/tpm2tss-genkey.1 \\\n    man/man3/tpm2tss_tpm2data_write.3 \\\n    man/man3/tpm2tss_rsa_makekey.3 \\\n    man/man3/tpm2tss_rsa_genkey.3 \\\n    man/man3/tpm2tss_ecc_makekey.3 \\\n    man/man3/tpm2tss_ecc_genkey.3 \\\n    man/man3/tpm2tss_ecc_getappdata.3 \\\n    man/man3/tpm2tss_tpm2data_read.3 \\\n    man/man3/tpm2tss_ecc_setappdata.3\nendif\n\nif !HAVE_PANDOC\n# If pandoc is not enabled, we want to complain that you need pandoc for make dist,\n# so hook the target and complain.\ndist-hook:\n\t@(>&2 echo \"You do not have pandoc, a requirement for the distribution of manpages\")\n\t@exit 1\nendif\n\nman/man3/tpm2tss_tpm2data_read.3: man/man3/tpm2tss_tpm2data_write.3\n\t$(AM_V_GEN)(rm $@ 2>/dev/null || true) && ln -s tpm2tss_tpm2data_write.3 $@\n\nman/man3/tpm2tss_ecc_setappdata.3: man/man3/tpm2tss_ecc_getappdata.3\n\t$(AM_V_GEN)(rm $@ 2>/dev/null || true) && ln -s tpm2tss_ecc_getappdata.3 $@\n\nman/man1/%.1: man/%.1.md\n\t$(AM_V_GEN)mkdir -p man/man1 && cat $< | $(PANDOC) -s -t man >$@\n\nman/man3/%.3: man/%.3.md\n\t$(AM_V_GEN)mkdir -p man/man3 && cat $< | $(PANDOC) -s -t man >$@\n\nEXTRA_DIST += \\\n    man/tpm2tss-genkey.1.md \\\n    man/tpm2tss_tpm2data_write.3.md \\\n    man/tpm2tss_rsa_makekey.3.md \\\n    man/tpm2tss_rsa_genkey.3.md \\\n    man/tpm2tss_ecc_makekey.3.md \\\n    man/tpm2tss_ecc_genkey.3.md \\\n    man/tpm2tss_ecc_getappdata.3.md\n\nCLEANFILES += \\\n    $(dist_man_MANS)\n\n### Bash Completion\nbash_completiondir = $(completionsdir)\nbash_completion_DATA = bash-completion/tpm2tss-genkey\nEXTRA_DIST += bash-completion/tpm2tss-genkey\n"
  },
  {
    "path": "README.md",
    "content": "[![Linux Build Status](https://github.com/tpm2-software/tpm2-tss-engine/workflows/Linux%20Build%20Status/badge.svg)](https://github.com/tpm2-software/tpm2-tss-engine/actions)\n[![Code Coverage](https://codecov.io/gh/tpm2-software/tpm2-tss-engine/branch/master/graph/badge.svg)](https://codecov.io/gh/tpm2-software/tpm2-tss-engine)\n[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/tpm2-software/tpm2-tss-engine.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tpm2-software/tpm2-tss-engine/context:cpp)\n[![Coverity Scan](https://img.shields.io/coverity/scan/22247.svg)](https://scan.coverity.com/projects/tpm2-tss-engine)\n\n\n# Overview\nThe tpm2-tss-engine project implements a cryptographic engine for\n[OpenSSL](https://www.openssl.org) for\n[Trusted Platform Module (TPM 2.0)](https://trustedcomputinggroup.org/work-groups/trusted-platform-module/)\nusing the [tpm2-tss](https://www.github.com/tpm2-software/tpm2-tss) software\nstack that follows the Trusted Computing Groups (TCG) \n[TPM Software Stack (TSS 2.0)](https://trustedcomputinggroup.org/work-groups/software-stack/).\nIt uses the \n[Enhanced System API (ESAPI)](https://trustedcomputinggroup.org/wp-content/uploads/TSS_ESAPI_Version-0.9_Revision-04_reviewEND030918.pdf)\ninterface of the TSS 2.0 for downwards communication. It supports RSA decryption\nand signatures as well as ECDSA signatures.\n\nIf you are looking for a provider following the OpenSSL 3.0 provider API instead of the engine API, please head over to [tpm2-openssl](https://github.com/tpm2-software/tpm2-openssl)\n\n# Operations\n\n## Key hierarchies\nThe keys used by this engine are all located underneath an ECC restricted\nprimary storage decryption key. This key is created on each invocation (since\nECC key creation is faster than RSA's). Thus, no persistent SRK key need to be\npredeployed.\n\nThe authorization value for the storage hierarchie (the owner password) is\nassumed to be clear (of zero length). If this is not the case, it needs to be\nset using the engine ctrl.\n\n## Key types\nThe RSA keys are created with the ability to sign as well as to decrypt.\nThis allows all RSA keys to be used for either operation.\nNote: The TPM's RSA sign operation will enforce tagging payloads with an ASN.1\nencoded identifier of the used hash algorithm. This is incompatible with\nOpelSSL's RSA interface structures. Thus, the TPM2_RSA_Decrypt method is also\nused for signing operations which also requires decrypt capabilities to be\nactivated for this key.\n\nThe ECDSA keys are created as ECDSA keys with the ability to perform signature\noperations.\n\n# Build and install instructions\nInstructions to build and install tpm2-tss are available in the\n[INSTALL](INSTALL.md) file.\n\n# Usage\n\nFor additional usage examples, please consider the integration tests under\n`tests/*.sh`.\n\n## Engine information\nEngine informations can be retrieved using\n```\nopenssl engine -t -c tpm2tss\n```\n\n## Random data\nA set of 10 random bytes can be retrieved using\n```\nopenssl rand -engine tpm2tss -hex 10\nengine \"tpm2tss\" set.\nWARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so\nWARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so\n40ac9191079e490d17b7\nWARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so\nWARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so\n```\nNote: These warnings stem from the tpm2-tss libraries and are not an issue, as\nlong as a TPM connection is established afterwards by a different tcti.\n\n## RSA operations\n\n### RSA decrypt\nThe following sequence of commands creates an RSA key using the TPM, exports the\npublic key, encrypts a data file and decrypts it using the TPM:\n```\ntpm2tss-genkey -a rsa -s 2048 mykey\nopenssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub\nopenssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher\nopenssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata\n```\nAlternatively, the data can be encrypted directly with the TPM key using:\n```\nopenssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -encrypt -in mydata -out mycipher\n```\n\n### RSA sign\nThe following sequence of commands creates an RSA key using the TPM, exports the\npublic key, signs a data file using the TPM and validates the signature:\n```\nopenssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub\nopenssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig\nopenssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata -sigfile mysig\n```\nAlternatively, the data can be validated directly using:\n`openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig`\nNote: `mydata` must not exceed the size of the RSA key, since these operation\ndo not perform any hashing of the input data.\n\n## ECDSA operations\nThe following sequence of commands creates an ECDSA key using the TPM, signs\na data file using the TPM and validates the signature:\n```\ntpm2tss-genkey -a ecdsa mykey\nopenssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig\nopenssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig\n```\n\nTo export the public key use:\n\n```\nopenssl ec -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub\n```\n\n## Self Signed certificate generate operation \nThe following sequence of commands creates self signed certificate using TPM\nkey. Openssl command sets tpm2tss as engine and generates a self signed\ncertificate based on provided CSR configuration information.\n```\n$ tpm2tss-genkey -a rsa rsa.tss\n$ openssl req -new -x509 -engine tpm2tss -key rsa.tss  -keyform engine -out rsa.crt\n```\n\n## Signing using restricted key\nSigning using a restricted ECDSA key is possible with the caveat that\nthe TPM must be used for the digest, so higher-level digest & sign\noperations must be used instead, e.g.:\n```\n$ openssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt\n```\nWhere `${HANDLE}` is the TPM persistent handle ID for the restricted\nkey created by an external tool (since tpm2tss-genkey doesn't support\ncreating restricted keys).\n\n# TLS and s_server\nThis engine can be used in all places where OpenSSL is used to create a TLS\nsecure channel connection. You have can specify the command\n```\n./tpm2tss-genkey -a rsa rsa.tss\nopenssl req -new -x509 -engine tpm2tss -key rsa.tss  -keyform engine  -out rsa.crt\nopenssl s_server -cert rsa.crt -key rsa.tss -keyform engine -engine tpm2tss -accept 8443\n```\n\nFor ECDSA keys however, the Hash algorithm needs to be specified because the TPM\ndoes not support SHA512. You can blacklisting SHA512 universally. That is\npossible via openssl.cnf. See the \"SignatureAlgorithms\" configuration file\ncommand on this page:\nhttps://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html\n\nNote: Usage of s_server with HSM-protected private keys is only supported on\nOpenSSL 1.1.0 and newer.\n\n## Development prefixes\nIn order to use this engine without `make install` for testing call:\n```\nexport LD_LIBRAY_PATH=${TPM2TSS}/src/tss2-{tcti,mu,sys,esys}/.libs\nexport PKG_CONFIG_PATH=$PWD/../tpm2-tss/lib\n./bootstrap\n./configure \\\n    CFLAGS=\"-I$PWD/../tpm2-tss/include\" \\\n    LDFLAGS=\"-L$PWD/../tpm2-tss/src/tss2-{esys,sys,mu,tcti}/.libs\"\nmake\nmake check\n```\n"
  },
  {
    "path": "RELEASE.md",
    "content": "# Release Process:\nThis document describes the general process that maintainers must follow when\nmaking a release of the `tpm2-tss-engine` library and cli-tool.\n\n# Milestones\nAll releases should have a milestone used to track the release. If the release version is not known, as covered in [Version Numbers](#Version Numbers),\nthen an \"x\" may be used for the unknown number, or the generic term \"next\" may be used. The description field of the milestone will be used to record\nthe CHANGELOG for that release. See [CHANGELOG Update](#CHANGELOG Update) for details.\n\n# Version Numbers\nThis project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\nIn summary: Given a version number MAJOR.MINOR.PATCH, increment the:\n1. MAJOR version when you make incompatible API changes,\n2. MINOR version when you add functionality in a backwards-compatible manner, and\n3. PATCH version when you make backwards-compatible bug fixes.\nAdditional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.\n\n## Version String\nThe version string is set for the rest of the autotools bits by autoconf.\nAutoconf gets this string from the `AC_INIT` macro in the configure.ac file.\nOnce you decide on the next version number (using the scheme above) you must set\nit manually in configure.ac. The version string must be in the form `A.B.C`\nwhere `A`, `B` and `C` are integers representing the major, minor and micro\ncomponents of the version number.\n\n## Release Candidates\nIn the run up to a release the maintainers may create tags to identify progress\ntoward the release. In these cases we will append a string to the release number\nto indicate progress using the abbreviation `rc` for 'release candidate'. This\nstring will take the form of `-rcX`. We append an incremental digit `X` in case\nmore than one release candidate is necessary to communicate progress as\ndevelopment moves forward.\n\n# CHANGELOG Update\nBefore tagging the repository with the release version, the maintainer MUST update the CHANGELOG file with the contents from the description field\nfrom the corresponding release milestone and update any missing version string details in the CHANGELOG and milestone entry.\n\n# Git Tags\nWhen a release is made a tag is created in the git repo identifying the release\nby the [version string](#Version String). The tag should be pushed to upstream\ngit repo as the last step in the release process.\n**NOTE** tags for release candidates will be deleted from the git repository\nafter a release with the corresponding version number has been made.\n**NOTE** release (not release candidate) tags should be considered immutable.\n\n## Signed tags\nGit supports GPG signed tags and releases will have tags signed by a maintainer.\nFor details on how to sign and verify git tags see:\nhttps://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work.\n\n# Release tarballs\nWe use the git tag as a way to mark the point of the release in the projects\nhistory. We do not however encourage users to build from git unless they intend\nto modify the source code and contribute to the project. For the end user we\nprovide release tarballs following the GNU conventions as closely as possible.\n\nTo make a release tarball use the `distcheck` make target.\nThis target includes a number of sanity checks that are extremely helpful.\nFor more information on `automake` and release tarballs see:\nhttps://www.gnu.org/software/automake/manual/html_node/Dist.html#Dist\n\n## Hosting Releases on Github\nGithub automagically generates a page in their UI that maps git tags to\n'releases' (even if the tag isn't for a release). Additionally they support\nhosting release tarballs through this same interface. The release tarball\ncreated in the previous step must be posted to github using the release\ninterface. Additionally, this tarball must be accompanied by a detached GPG\nsignature. The Debian wiki has an excellent description of how to post a signed\nrelease to Github here:\nhttps://wiki.debian.org/Creating%20signed%20GitHub%20releases\n**NOTE** release candidates must be taken down after a release with the\ncorresponding version number is available.\n\n## Signing Release Tarballs\nSignatures must be generated using the `--detach-sign` and `--armor` options to\nthe `gpg` command.\n\n## Verifying Signatures\nVerifying the signature on a release tarball requires the project maintainers\npublic keys be installed in the GPG keyring of the verifier. With both the\nrelease tarball and signature file in the same directory the following command\nwill verify the signature:\n```\n$ gpg --verify tpm2-tss-engine-X.Y.Z.tar.gz.asc\n```\n\n## Signing Keys\nThe GPG keys used to sign a release tag and the associated tarball must be the\nsame. Additionally they must:\n* belong to a project maintainer\n* be discoverable using a public GPG key server\n* be associated with the maintainers github account\n(https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/)\n\n# Announcements\nRelease candidates and proper releases should be announced on the mailing list:\n  - https://lists.linuxfoundation.org/mailman/listinfo/tpm2\n\nThis announcement should be accompanied by a link to the release page on Github\nas well as a link to the CHANGELOG.md accompanying the release.\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\n## Supported Versions\n\nCurrently supported versions:\n\n| Version | Supported          |\n| ------- | ------------------ |\n| any | :white_check_mark: |\n\n## Reporting a Vulnerability\n\n### Reporting\n\nSecurity vulnerabilities can be disclosed in one of two ways:\n- GitHub: *preferred* By following [these](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability) instructions.\n- Email: A descirption *should be emailed* to **all** members of the [MAINTAINERS](MAINTAINERS) file to coordinate the\ndisclosure of the vulnerability.\n\n### Tracking\n\nWhen a maintainer is notified of a security vulnerability, they *must* create a GitHub security advisory\nper the instructions at:\n\n  - <https://docs.github.com/en/code-security/repository-security-advisories/about-github-security-advisories-for-repositories>\n\nMaintainers *should* use the optional feature through GitHub to request a CVE be issued, alternatively RedHat has provided CVE's\nin the past and *may* be used, but preference is on GitHub as the issuing CNA.\n\n### Publishing\n\nOnce ready, maintainers should publish the security vulnerability as outlined in:\n\n  - <https://docs.github.com/en/code-security/repository-security-advisories/publishing-a-repository-security-advisory>\n\nAs well as ensuring the publishing of the CVE, maintainers *shal*l have new release versions ready to publish at the same time as\nthe CVE. Maintainers *should* should strive to adhere to a sub 60 say turn around from report to release.\n"
  },
  {
    "path": "bootstrap",
    "content": "#!/bin/bash\n\nset -e\n\ngit describe --tags --always --dirty > VERSION\n\nautoreconf --install --sym\n"
  },
  {
    "path": "configure.ac",
    "content": "#;*****************************************************************************;\n# Copyright (c) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG\n# All rights reserved.\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#\n# 1. Redistributions of source code must retain the above copyright notice,\n# this list of conditions and the following disclaimer.\n#\n# 2. Redistributions in binary form must reproduce the above copyright notice,\n# this list of conditions and the following disclaimer in the documentation\n# and/or other materials provided with the distribution.\n#\n# 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n# may be used to endorse or promote products derived from this software\n# without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n# THE POSSIBILITY OF SUCH DAMAGE.\n#;*****************************************************************************;\nAC_PREREQ([2.68])\n\nAC_INIT([tpm2-tss-engine],\n        [m4_esyscmd_s([cat ./VERSION])],\n        [https://github.com/tpm2-software/tpm2-tss-engine/issues],\n        [],\n        [https://github.com/tpm2-software/tpm2-tss-engine])\n\ndnl Let's be FHS-conform by default.\nif test \"$prefix\" = '/usr'; then\n    test \"$sysconfdir\" = '${prefix}/etc' && sysconfdir=\"/etc\"\n    test \"$sharedstatedir\" = '${prefix}/com' && sharedstatedir=\"/var\"\n    test \"$localstatedir\" = '${prefix}/var' && localstatedir=\"/var\"\nfi\n\nAC_CONFIG_MACRO_DIR([m4])\nAC_CONFIG_SRCDIR([src/tpm2-tss-engine.c])\nAC_CONFIG_AUX_DIR([build-aux])\n\n# propagate configure arguments to distcheck\nAC_SUBST([DISTCHECK_CONFIGURE_FLAGS],[$ac_configure_args])\n\nAC_CANONICAL_SYSTEM\n\nAM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Wno-portability])\n#Backward compatible setting of \"silent-rules\"\nm4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) \nAM_MAINTAINER_MODE([enable])\n\nAX_IS_RELEASE([dash-version])\nAX_CHECK_ENABLE_DEBUG([info])\n\nAC_PROG_CC\nAC_PROG_CC_C99\nAM_PROG_CC_C_O\nLT_INIT()\n\nAC_PROG_MKDIR_P\nAC_PROG_LN_S\n\nAC_CONFIG_HEADERS([src/config.h])\n\nAC_ARG_ENABLE([tctienvvar],\n    [AS_HELP_STRING([--disable-tctienvvar],\n                    [Disable setting the TCTI option from an environment variable])],,\n    [enable_tctienvvar=yes])\nAS_IF([test \"x$enable_tctienvvar\" = xyes], [AC_DEFINE([ENABLE_TCTIENVVAR], [1],\n      'Enable getting TCTI from env variable')])\n\nAC_CONFIG_FILES([Makefile])\n\nAC_ARG_ENABLE([defaultflags],\n              [AS_HELP_STRING([--disable-defaultflags],\n                              [Disable default preprocessor, compiler, and linker flags.])],,\n              [enable_defaultflags=yes])\nAS_IF([test \"x$enable_defaultflags\" = \"xyes\"],\n      [\n      AX_ADD_COMPILER_FLAG([-std=gnu99])\n      AX_ADD_COMPILER_FLAG([-Wall])\n      AX_ADD_COMPILER_FLAG([-Wextra])\n      AX_ADD_COMPILER_FLAG([-Wformat-security])\n      AS_IF([test \"x$ax_is_release\" = \"xno\"], [AX_ADD_COMPILER_FLAG([-Werror])])\n      AX_ADD_COMPILER_FLAG([-fstack-protector-all])\n      AX_ADD_COMPILER_FLAG([-fpic])\n      AX_ADD_COMPILER_FLAG([-fPIC])\n\n      # work around GCC bug #53119\n      #   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119\n      AX_ADD_COMPILER_FLAG([-Wno-missing-braces])\n\n      AX_ADD_LINK_FLAG([-Wl,--no-undefined])\n      AX_ADD_LINK_FLAG([-Wl,-z,noexecstack])\n      AX_ADD_LINK_FLAG([-Wl,-z,now])\n      AX_ADD_LINK_FLAG([-Wl,-z,relro])\n      ])\n\nAX_CODE_COVERAGE\nm4_ifdef([_AX_CODE_COVERAGE_RULES],\n         [AM_CONDITIONAL(AUTOCONF_CODE_COVERAGE_2019_01_06, [true])],\n         [AM_CONDITIONAL(AUTOCONF_CODE_COVERAGE_2019_01_06, [false])])\nAX_ADD_AM_MACRO_STATIC([])\n\nPKG_PROG_PKG_CONFIG([0.25])\nPKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.0.2g],\n                  [ac_enginesdir=`$PKG_CONFIG --variable=enginesdir libcrypto`])\nPKG_CHECK_MODULES([TSS2_ESYS], [tss2-esys >= 2.3])\nPKG_CHECK_MODULES([TSS2_MU], [tss2-mu])\nPKG_CHECK_MODULES([TSS2_TCTILDR], [tss2-tctildr])\n\nAC_CHECK_LIB([crypto], EC_KEY_METHOD_set_compute_key,\n      [AM_CONDITIONAL([HAVE_OPENSSL_ECDH], true)],\n      [AM_CONDITIONAL([HAVE_OPENSSL_ECDH], false)])\n\nAC_ARG_ENABLE([digestsign],\n              [AS_HELP_STRING([--disable-digestsign],\n                              [Disable support for digest and sign methods, helps with TPM unsupported hash algorithms.])],,\n              [enable_digestsign=yes])\nAC_CHECK_LIB([crypto], EVP_PKEY_meth_set_digest_custom,\n      [AM_CONDITIONAL([HAVE_OPENSSL_DIGEST_SIGN], [test \"x$enable_digestsign\" != \"xno\"])],\n      [AM_CONDITIONAL([HAVE_OPENSSL_DIGEST_SIGN], false)])\nAS_IF([test \"x$ac_cv_lib_crypto_EVP_PKEY_meth_set_digest_custom\" = xyes && test \"x$enable_digestsign\" = \"xyes\"],\n      [AC_DEFINE([HAVE_OPENSSL_DIGEST_SIGN], [1],\n                 Have required functionality from OpenSSL to support digest and sign)])\n\nAC_PATH_PROG([PANDOC], [pandoc])\nAS_IF([test -z \"$PANDOC\"],\n    [AC_MSG_WARN([Required executable pandoc not found, man pages will not be built])])\nAM_CONDITIONAL([HAVE_PANDOC],[test -n \"$PANDOC\"])\nAM_CONDITIONAL([HAVE_MAN_PAGES],[test -d \"${srcdir}/man/man1\" -o -n \"$PANDOC\"])\n\nAC_PATH_PROG([EXPECT], [expect])\nAS_IF([test -z \"$EXPECT\"],\n    [AC_MSG_WARN([Required executable expect not found, some tests might fail])])\n\nAC_ARG_WITH([enginesdir], \n            [AS_HELP_STRING([--with-enginesdir],\n                            [Set the OpenSSL engine directory (default: use pkg-config)])],\n            [],\n            [with_enginesdir=$ac_enginesdir])\nAS_IF([test -z \"$with_enginesdir\"],\n    [AC_MSG_WARN([Empty enginesdir, using $libdir/engines instead.])])\n# This weirdness is necessary to enable distcheck via DISTCHECK_CONFIGURE_FLAGS\nAS_IF([test -z \"$with_enginesdir\"],\n    [with_enginesdir=$libdir/engines])\nAC_SUBST(ENGINESDIR, \"$with_enginesdir\")\n\nAC_ARG_WITH([completionsdir],\n            [AS_HELP_STRING([--with-completionsdir],\n                            [Set the bash completions directory (default: use pkg-config)])],\n            [],\n            [with_completionsdir=`$PKG_CONFIG --variable=completionsdir bash-completion`])\nAS_IF([test -z \"$with_completionsdir\"],\n    [AC_MSG_WARN([Empty completionsdir, using $datarootdir/bash-completion/completions instead.])])\nAS_IF([test -z \"$with_completionsdir\"],\n    [with_completionsdir=$datarootdir/bash-completion/completions])\nAC_SUBST(completionsdir, \"$with_completionsdir\")\n\nAC_ARG_ENABLE([unit],\n            [AS_HELP_STRING([--enable-unit],\n                            [build cmocka unit tests])],,\n            [enable_unit=no])\nAS_IF([test \"x$enable_unit\" != \"xno\" ], \n      [PKG_CHECK_MODULES([CMOCKA], [cmocka >= 1.0])])\nAM_CONDITIONAL([UNIT], [test \"x$enable_unit\" != xno])\n\nAC_ARG_ENABLE([integration],\n            [AS_HELP_STRING([--enable-integration],\n                            [build integration tests against TPM])],,\n            [enable_integration=no])\nAM_CONDITIONAL([INTEGRATION], [test \"x$enable_integration\" != xno])\n\n# Use physical TPM device for testing\nAC_ARG_WITH([device],\n            [AS_HELP_STRING([--with-device=<device>],[TPM device for testing])],\n            [AS_IF([test \\( -w \"$with_device\" \\)  -a \\( -r \"$with_device\" \\)],\n                   [AC_MSG_RESULT([success])\n                    AX_NORMALIZE_PATH([with_device])\n                    with_device_set=yes],\n                   [AC_MSG_ERROR([TPM device provided does not exist or is not writable])])],\n            [with_device_set=no])\nAM_CONDITIONAL([TESTDEVICE],[test \"x$with_device_set\" = xyes])\n\nAC_CHECK_FUNC([backtrace_symbols_fd],[AC_DEFINE([HAVE_EXECINFO],[1], ['Define to 1 if you have the <execinfo.h> header file.'])])\n\n# Integration test with simulator\nAS_IF([test \"x$enable_integration\" = xyes && test \"x$with_device_set\" = xno],\n      [integration_args=\"\"\n       AC_CHECK_PROG([tpm2_startup], [tpm2_startup], [yes])\n       AS_IF([test \"x$tpm2_startup\" != xyes],\n             [AC_MSG_ERROR([Integration tests require the tpm2_startup executable])])\n       AC_CHECK_PROG([swtpm], [swtpm], [yes])\n       AC_CHECK_PROG([tpm_server], [tpm_server], [yes])\n       AS_IF([test \"x$swtpm\" != xyes && test \"x$tpm_server\" != xyes],\n             [AC_MSG_ERROR([Integration tests require either the swtpm or the tpm_server executable])])\n       AC_CHECK_PROG([realpath], [realpath], [yes])\n       AS_IF([test \"x$realpath\" != xyes],\n             [AC_MSG_ERROR([Integration tests require the realpath executable])])\n       AC_CHECK_PROG([ss], [ss], [yes])\n       AS_IF([test \"x$ss\" != xyes],\n             [AC_MSG_ERROR([Integration tests require the ss executable])])\n       AS_IF([test \"x$enable_tctienvvar\" != xyes],\n             [AC_MSG_ERROR([Integration tests require building with TCTI environment variable support])])\n       AC_SUBST([INTEGRATION_ARGS], [$integration_args])\n      ])\n\n# Integration test with physical device\nAS_IF([test \"x$enable_integration\" = xyes &&  test \"x$with_device_set\" = xyes ],\n      [integration_args=\"$with_device\"\n       AC_CHECK_PROG([realpath], [realpath], [yes])\n       AS_IF([test \"x$realpath\" != xyes],\n             [AC_MSG_ERROR([Integration tests require the realpath executable])])\n       AS_IF([test \"x$enable_tctienvvar\" != xyes],\n             [AC_MSG_ERROR([Integration tests require building with TCTI environment variable support])])\n       AC_SUBST([INTEGRATION_ARGS], [$integration_args])\n      ])\n\nAX_VALGRIND_CHECK\n\n#\n# sanitizer compiler flags\n#\nAC_ARG_WITH([sanitizer],\n            [AS_HELP_STRING([--with-sanitizer={none,address,undefined}],\n                            [build with the given sanitizer])],,\n            [with_sanitizer=none])\nAS_CASE([\"x$with_sanitizer\"],\n        [\"xnone\"],\n        [],\n        [\"xaddress\"],\n        [\n            SANITIZER_CFLAGS=\"-fsanitize=address -fno-omit-frame-pointer\"\n            SANITIZER_LDFLAGS=\"-lasan\"\n        ],\n        [\"xundefined\"],\n        [\n            SANITIZER_CFLAGS=\"-fsanitize=undefined\"\n            SANITIZER_LDFLAGS=\"-lubsan\"\n        ],\n        [AC_MSG_ERROR([Bad value for --with-sanitizer])])\nAC_SUBST([SANITIZER_CFLAGS])\nAC_SUBST([SANITIZER_LDFLAGS])\n\nAC_OUTPUT\n\nAC_MSG_RESULT([\n$PACKAGE_NAME $VERSION\n    man-pages:      $PANDOC\n    enginesdir:     $with_enginesdir\n    completionsdir: $with_completionsdir\n    device:         $with_device\n])\n\n"
  },
  {
    "path": "include/tpm2-tss-engine.h",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n#ifndef TPM2_TSS_ENGINE_H\n#define TPM2_TSS_ENGINE_H\n\n#include <openssl/engine.h>\n#include <tss2/tss2_tpm2_types.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef enum {\n    KEY_TYPE_BLOB,\n    KEY_TYPE_HANDLE\n} KEY_TYPE;\n\ntypedef struct {\n    int emptyAuth;\n    TPM2B_DIGEST userauth;\n    TPM2B_PUBLIC pub;\n    TPM2_HANDLE parent;\n    KEY_TYPE privatetype;\n    union {\n      TPM2B_PRIVATE priv;\n      TPM2_HANDLE handle;\n    };\n} TPM2_DATA;\n\n#define TPM2TSS_SET_OWNERAUTH   ENGINE_CMD_BASE\n#define TPM2TSS_SET_TCTI        (ENGINE_CMD_BASE + 1)\n#define TPM2TSS_SET_PARENTAUTH  (ENGINE_CMD_BASE + 2)\n\nint\ntpm2tss_tpm2data_write(const TPM2_DATA *tpm2data, const char *filename);\n\nint\ntpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap);\n\nint\ntpm2tss_tpm2data_readtpm(uint32_t handle, TPM2_DATA **tpm2Datap);\n\nint\ntpm2tss_tpm2data_importtpm(const char *filenamepub, const char *filenametpm,\n                           TPM2_HANDLE parent, int emptyAuth,\n                           TPM2_DATA **tpm2Datap);\n\nEVP_PKEY *\ntpm2tss_rsa_makekey(TPM2_DATA *tpm2Data);\n\nint\ntpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password,\n                   TPM2_HANDLE parentHandle);\n\nEVP_PKEY *\ntpm2tss_ecc_makekey(TPM2_DATA *tpm2Data);\n\nint\ntpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password,\n                   TPM2_HANDLE parentHandle);\n\nTPM2_DATA *\n#if OPENSSL_VERSION_NUMBER < 0x10100000\ntpm2tss_ecc_getappdata(EC_KEY *key);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\ntpm2tss_ecc_getappdata(const EC_KEY *key);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\nint\ntpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *data);\n\n#ifdef __cplusplus\n}\n#endif\n#endif /* TPM2_TSS_ENGINE_H */\n"
  },
  {
    "path": "m4/flags.m4",
    "content": "dnl AX_ADD_COMPILER_FLAG:\ndnl   A macro to add a CFLAG to the EXTRA_CFLAGS variable. This macro will\ndnl   check to be sure the compiler supports the flag. Flags can be made\ndnl   mandatory (configure will fail).\ndnl $1: C compiler flag to add to EXTRA_CFLAGS.\ndnl $2: Set to \"required\" to cause configure failure if flag not supported.\nAC_DEFUN([AX_ADD_COMPILER_FLAG],[\n    AX_CHECK_COMPILE_FLAG([$1],[\n        EXTRA_CFLAGS=\"$EXTRA_CFLAGS $1\"\n        AC_SUBST([EXTRA_CFLAGS])],[\n        AS_IF([test x$2 != xrequired],[\n            AC_MSG_WARN([Optional CFLAG \"$1\" not supported by your compiler, continuing.])],[\n            AC_MSG_ERROR([Required CFLAG \"$1\" not supported by your compiler, aborting.])]\n        )],[\n        -Wall -Werror]\n    )]\n)\ndnl AX_ADD_PREPROC_FLAG:\ndnl   Add the provided preprocessor flag to the EXTRA_CFLAGS variable. This\ndnl   macro will check to be sure the preprocessor supports the flag.\ndnl   The flag can be made mandatory by providing the string 'required' as\ndnl   the second parameter.\ndnl $1: Preprocessor flag to add to EXTRA_CFLAGS.\ndnl $2: Set to \"required\" t ocause configure failure if preprocesor flag\ndnl     is not supported.\nAC_DEFUN([AX_ADD_PREPROC_FLAG],[\n    AX_CHECK_PREPROC_FLAG([$1],[\n        EXTRA_CFLAGS=\"$EXTRA_CFLAGS $1\"\n        AC_SUBST([EXTRA_CFLAGS])],[\n        AS_IF([test x$2 != xrequired],[\n            AC_MSG_WARN([Optional preprocessor flag \"$1\" not supported by your compiler, continuing.])],[\n            AC_MSG_ERROR([Required preprocessor flag \"$1\" not supported by your compiler, aborting.])]\n        )],[\n        -Wall -Werror]\n    )]\n)\ndnl AX_ADD_LINK_FLAG:\ndnl   A macro to add a LDLAG to the EXTRA_LDFLAGS variable. This macro will\ndnl   check to be sure the linker supports the flag. Flags can be made\ndnl   mandatory (configure will fail).\ndnl $1: linker flag to add to EXTRA_LDFLAGS.\ndnl $2: Set to \"required\" to cause configure failure if flag not supported.\nAC_DEFUN([AX_ADD_LINK_FLAG],[\n    AX_CHECK_LINK_FLAG([$1],[\n        EXTRA_LDFLAGS=\"$EXTRA_LDFLAGS $1\"\n        AC_SUBST([EXTRA_LDFLAGS])],[\n        AS_IF([test x$2 != xrequired],[\n            AC_MSG_WARN([Optional LDFLAG \"$1\" not supported by your linker, continuing.])],[\n            AC_MSG_ERROR([Required LDFLAG \"$1\" not supported by your linker, aborting.])]\n        )]\n    )]\n)\n"
  },
  {
    "path": "man/tpm2tss-genkey.1.md",
    "content": "% tpm2tss-genkey(1) tpm2-tss-engine | General Commands Manual\n%\n% OCTOBER 2020\n\n# NAME\n**tpm2tss-genkey**(1) -- generate TPM keys for tpm2-tss-engine\n\n# SYNOPSIS\n\n**tpm2tss-genkey** [*options*] <*filename*>\n\n# DESCRIPTION\n\n**tpm2tss-genkey** creates a key inside a TPM 2.0 connected via the\ntpm2tss software stack. Those keys may be an RSA key for decryption or signing\nor an ECC key for ECDSA signatures.\n\nThe tool respects the OPENSSL_CONF option for specifying engine specific control\nparameters. See `man(5) config` for details on openssl config files.\n\n# ARGUMENTS\n\nThe `tpm2tss-genkey` command expects a filename for storing the resulting TPM\nkey information. This file can then be loaded with OpenSSL using\n`openssl pkeyutl -engine tpm2tss -keyform engine -inkey <filename>`.\n\n# OPTIONS\n\n  * `-a <algorithm>`, `--alg <algorithm>`:\n    The public key algorithm (rsa, ecdsa) (default: rsa)\n\n  * `-c <curve>`, `--curve <curve>`:\n    If alg ecdsa is chosen, the curve for ecc (default: nist_p256)\n\n  * `-u <file>`, `--public <file>`:\n    Public key (TPM2B_PUBLIC) to be imported. Requires `-r`.\n\n  * `-r <file>`, `--private <file>`:\n    The (encrypted) private key (TPM2B_PRIVATE) to be imported.\n    Requires `-u`.\n\n  * `-e <exponent>`, `--exponent <exponent>`:\n    If alg rsa is chosen, the exponent for rsa (default: 65537)\n\n  * `-h`, `--help`:\n    Print help\n\n  * `-o <password>`, `--ownerpw <password>`:\n    Password for the owner hierarchy (default: none)\n    Openssl Config control command: `SET_OWNERAUTH`\n\n  * `-p <password>`, `--password <password>`:\n    Password for the created key (default: none)\n\n  * `-P <handle>`, `--parent <handle>`:\n    Specific handle for the parent key (default: none)\n\n  * `-s <keysize>`, `--keysize <keysize>`:\n    If alg rsa is chosen, the key size in bits (default: 2048)\n\n  * `-v`, `--verbose`:\n    Print verbose messages\n\n  * `-W <password>`, `--parentpw <password>`:\n    Password for the parent key (default: none)\n    Openssl Config control command: `SET_PARENTAUTH`\n\n  * `-t <tcti-conf>`, `--tcti <tcti-conf>`:\n    TCTI Configuration string (default: none)\n    Openssl Config control command: `SET_TCTI`\n\n# EXAMPLES\n\nEngine information can be retrieved using:\n```\n$ openssl engine -t -c tpm2tss\n```\nThe following sequence of commands creates an RSA key using the TPM, exports the\npublic key, encrypts a data file and decrypts it using the TPM:\n```\n$ tpm2tss-genkey -a rsa -s 2048 mykey\n$ openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub\n$ openssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher\n$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata\n```\nThe following sequence of commands creates an RSA key using the TPM, exports the\npublic key, signs a data file using the TPM and validates the signature:\n```\n$ tpm2tss-genkey -a rsa -s 2048 mykey\n$ openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub\n$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig\n$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig\n```\nThe following sequence of commands creates an ECDSA key using the TPM, exports\nthe public key, signs a data file using the TPM and validates the signature:\n```\n$ tpm2tss-genkey -a ecdsa -c nist_p256 mykey\n$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig\n$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig\n```\n\n# RETURNS\n\n0 on success or 1 on failure.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2017-2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1)\n\n"
  },
  {
    "path": "man/tpm2tss_ecc_genkey.3.md",
    "content": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_ecc_genkey** -- Make an ECC key object\n\n# SYNOPSIS\n\n**#include <tpm2tss.h>**\n\n**int tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password);**\n\n# DESCRIPTION\n\n**tpm2tss_ECC_genkey** issues the generation of an ECC key `key` using the TPM.\nThe ECC curve is determined by `curve`. The new key will be protected by\n`password`.\n\n# RETURN VALUE\n\nUpon successful completion **tpm2tss_ecc_genkey**() returns 1. Otherwise 0.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1), tpm2tss_genkey(1)\n\n"
  },
  {
    "path": "man/tpm2tss_ecc_getappdata.3.md",
    "content": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_ecc_getappdata**, **tpm2tss_ecc_setappdata** -- Make an ECC key object\n\n# SYNOPSIS\n\n**#include <tpm2tss.h>**\n\n**TPM2_DATA * tpm2tss_ecc_getappdata(const EC_KEY *key);**\n\n**int tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *data);**\n\n# DESCRIPTION\n\n**tpm2tss_ecc_getappdata** \n\n**tpm2tss_ecc_setappdata** \n\n# RETURN VALUE\n\nUpon successful completion **tpm2tss_ecc_getappdata**() and\n**tpm2tss_ecc_setappdata**() return 1. Otherwise 0.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1), tpm2tss_genkey(1)\n\n"
  },
  {
    "path": "man/tpm2tss_ecc_makekey.3.md",
    "content": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_ecc_makekey** -- Make an ECC key object\n\n# SYNOPSIS\n\n**#include <tpm2tss.h>**\n\n**EVP_PKEY * tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data);**\n\n# DESCRIPTION\n\n**tpm2tss_ecc_makekey** takes a TPM2_DATA object as `tpm2Data` and creates a\ncorresponding OpenSSL EVP_PKEY object.\n\n# RETURN VALUE\n\nUpon successful completion **tpm2tss_ecc_makekey**() returns the created\nEVP_PKEY object's pointer. Otherwise NULL.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1)\n\n"
  },
  {
    "path": "man/tpm2tss_rsa_genkey.3.md",
    "content": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_rsa_genkey** -- Make an RSA key object\n\n# SYNOPSIS\n\n**#include <tpm2tss.h>**\n\n**int tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password);**\n\n# DESCRIPTION\n\n**tpm2tss_rsa_genkey** issues the generation of an RSA key `rsa` using the TPM.\nThe keylength is determined by `bits`. The exponent is determined by `e`.\nThe new key will be protected by `password`.\n\n# RETURN VALUE\n\nUpon successful completion **tpm2tss_rsa_genkey**() returns 1. Otherwise 0.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1), tpm2tss_genkey(1)\n\n"
  },
  {
    "path": "man/tpm2tss_rsa_makekey.3.md",
    "content": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_rsa_makekey** -- Make an RSA key object\n\n# SYNOPSIS\n\n**#include <tpm2tss.h>**\n\n**EVP_PKEY * tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data);**\n\n# DESCRIPTION\n\n**tpm2tss_rsa_makekey** takes a TPM2_DATA object as `tpm2Data` and creates a\ncorresponding OpenSSL EVP_PKEY object.\n\n# RETURN VALUE\n\nUpon successful completion **tpm2tss_rsa_makekey**() returns the created\nEVP_PKEY object's pointer. Otherwise NULL.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1)\n\n"
  },
  {
    "path": "man/tpm2tss_tpm2data_write.3.md",
    "content": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_tpm2data_write**, **tpm2tss_tpm2data_read** -- read/write TPM2_DATA\n\n# SYNOPSIS\n\n**#include <tpm2tss.h>**\n\n**int tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap);**\n\n**int tpm2tss_tpm2data_write(const TPM2_DATA *tpm2Data, const char *filename);**\n\n# DESCRIPTION\n\n**tpm2tss_tpm2data_read** reads the TPM2_DATA object from a file called\n`filename`, allocates memory and stores it under the parameter `tpm2Datap`.\nMust be freed using the `free()` function.\n\n**tpm2tss_tpm2data_write** writes the TPM2_DATA object from the parameter\n`tpm2Data` to a newly created file called `filename`.\n\n# RETURN VALUE\n\nUpon successful completion **tpm2tss_tpm2data_write**() and\n**tpm2tss_tpm2data_read**() return 1. Otherwise 0.\n\n## AUTHOR\n\nWritten by Andreas Fuchs.\n\n## COPYRIGHT\n\ntpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon\nTechnologies AG. License BSD 3-clause.\n\n## SEE ALSO\n\nopenssl(1)\n\n"
  },
  {
    "path": "openssl.conf.sample",
    "content": "openssl_conf = openssl_init\n\n[openssl_init]\nengines = engine_section\n\n[engine_section]\ntpm2tss = tpm2tss_section\n\n[tpm2tss_section]\nengine_id = tpm2tss\ndynamic_path = /usr/lib/engines-1.1/libtpm2tss.so\ndefault_algorithms = RSA\ninit = 1\n#SET_TCTI = <TCTI_options>\n#SET_OWNERAUTH = <could_set_password_here, but then it's readable>\n#SET_PARENTAUTH = <password_of_parent_key> \n\n[req]\ndistinguished_name = subject\n\n[subject]\n# prompts and defaults here\n"
  },
  {
    "path": "src/tpm2-tss-engine-common.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n * Copyright (c) 2019, Wind River Systems.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <stdio.h>\n#include <string.h>\n\n#include <tss2/tss2_tctildr.h>\n\n#include <openssl/engine.h>\n#include <openssl/pem.h>\n#include <openssl/rand.h>\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\nASN1_SEQUENCE(TSSPRIVKEY) = {\n\tASN1_SIMPLE(TSSPRIVKEY, type, ASN1_OBJECT),\n\tASN1_EXP_OPT(TSSPRIVKEY, emptyAuth, ASN1_BOOLEAN, 0),\n\tASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER),\n\tASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING),\n\tASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING)\n} ASN1_SEQUENCE_END(TSSPRIVKEY)\n\n#define TSSPRIVKEY_PEM_STRING \"TSS2 PRIVATE KEY\"\n\nIMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY);\nIMPLEMENT_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY);\nIMPLEMENT_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY);\n\n/** Initialize the Esys context\n *\n * Initialize an Esys context.\n * @param esys_ctx The context to initialize.\n * @retval TSS2_RC_SUCCESS on success\n * @retval TSS2_BASE_RC_BAD_REFERENCE if no pointer was provided\n * @retval Errors from Tcti initialization or Esys_Initialize()\n */\nTSS2_RC\nesys_ctx_init(ESYS_CONTEXT **esys_ctx)\n{\n\n    TSS2_RC r;\n    if (!esys_ctx) {\n        ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE);\n        r = TSS2_BASE_RC_BAD_REFERENCE;\n    } else {\n        TSS2_TCTI_CONTEXT *tcti_ctx = NULL;\n\n        r = Tss2_TctiLdr_Initialize(tcti_nameconf, &tcti_ctx);\n        if (TSS2_RC_SUCCESS != r) {\n            ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE);\n        } else {\n            r = Esys_Initialize(esys_ctx, tcti_ctx, NULL);\n            if (TSS2_RC_SUCCESS != r) {\n                ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE);\n                Tss2_TctiLdr_Finalize(&tcti_ctx);\n            }\n        }\n    }\n    return r;\n}\n\n/** Finalize the Esys context\n *\n * Get the TCTI context and finalize this alongside the Esys context.\n * @param esys_ctx The Esys context\n * @retval TSS2_RC_SUCCESS on success\n * @retval TSS2_BASE_RC_BAD_REFERENCE if no pointer was provided\n * @retval Errors from Esys_GetTcti()\n */\nTSS2_RC\nesys_ctx_free(ESYS_CONTEXT **esys_ctx)\n{\n    TSS2_RC r;\n    if ((!esys_ctx) || (!*esys_ctx)) {\n        ERR(esys_ctx_free, TPM2TSS_R_GENERAL_FAILURE);\n        r = TSS2_BASE_RC_BAD_REFERENCE;\n    } else {\n        TSS2_TCTI_CONTEXT *tcti_ctx;\n        r = Esys_GetTcti(*esys_ctx, &tcti_ctx);\n        Esys_Finalize(esys_ctx);\n        if (TSS2_RC_SUCCESS != r) {\n            ERR(esys_ctx_free, TPM2TSS_R_GENERAL_FAILURE);\n        } else {\n            Tss2_TctiLdr_Finalize(&tcti_ctx);\n        }\n    }\n    return r;\n}\n\n/** Serialize tpm2data onto disk\n *\n * Write the tpm2tss key data into a file using PEM encoding.\n * @param tpm2Data The data to be written to disk.\n * @param filename The filename to write the data to.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_tpm2data_write(const TPM2_DATA *tpm2Data, const char *filename)\n{\n    TSS2_RC r;\n    BIO *bio = NULL;\n    TSSPRIVKEY *tpk = NULL;\n    BIGNUM *bn_parent = NULL;\n\n    uint8_t privbuf[sizeof(tpm2Data->priv)];\n    uint8_t pubbuf[sizeof(tpm2Data->pub)];\n    size_t privbuf_len = 0, pubbuf_len = 0;\n\n    if ((bio = BIO_new_file(filename, \"w\")) == NULL) {\n        ERR(tpm2tss_tpm2data_write, TPM2TSS_R_FILE_WRITE);\n        goto error;\n    }\n\n    tpk = TSSPRIVKEY_new();\n    if (!tpk) {\n        ERR(tpm2tss_tpm2data_write, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n\n    r = Tss2_MU_TPM2B_PRIVATE_Marshal(&tpm2Data->priv, &privbuf[0],\n                                      sizeof(privbuf), &privbuf_len);\n    if (r) {\n        ERR(tpm2tss_tpm2data_write, TPM2TSS_R_DATA_CORRUPTED);\n        goto error;\n    }\n\n    r = Tss2_MU_TPM2B_PUBLIC_Marshal(&tpm2Data->pub, &pubbuf[0],\n                                     sizeof(pubbuf), &pubbuf_len);\n    if (r) {\n        ERR(tpm2tss_tpm2data_write, TPM2TSS_R_DATA_CORRUPTED);\n        goto error;\n    }\n    tpk->type = OBJ_txt2obj(OID_loadableKey, 1);\n    tpk->parent = ASN1_INTEGER_new();\n    tpk->privkey = ASN1_OCTET_STRING_new();\n    tpk->pubkey = ASN1_OCTET_STRING_new();\n    if (!tpk->type || !tpk->privkey || !tpk->pubkey || !tpk->parent) {\n        ERR(tpm2tss_tpm2data_write, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n\n    tpk->emptyAuth = tpm2Data->emptyAuth ? 0xFF : 0;\n    bn_parent = BN_new();\n    if (!bn_parent) {\n        goto error;\n    }\n    if (tpm2Data->parent != 0) {\n        BN_set_word(bn_parent, tpm2Data->parent);\n    } else {\n        BN_set_word(bn_parent, TPM2_RH_OWNER);\n    }\n    BN_to_ASN1_INTEGER(bn_parent, tpk->parent);\n    ASN1_STRING_set(tpk->privkey, &privbuf[0], privbuf_len);\n    ASN1_STRING_set(tpk->pubkey, &pubbuf[0], pubbuf_len);\n\n    PEM_write_bio_TSSPRIVKEY(bio, tpk);\n    TSSPRIVKEY_free(tpk);\n    BIO_free(bio);\n\n    return 1;\n error:\n    if (bio)\n        BIO_free(bio);\n    if (tpk)\n        TSSPRIVKEY_free(tpk);\n    return 0;\n}\n\n/** Create tpm2data from a TPM key\n *\n * Retrieve the public key of tpm2data from the TPM for a given handle.\n * @param handle The TPM's key handle.\n * @param tpm2Datap The data after read.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_tpm2data_readtpm(uint32_t handle, TPM2_DATA **tpm2Datap)\n{\n    TSS2_RC r;\n    TPM2_DATA *tpm2Data = NULL;\n    ESYS_TR keyHandle = ESYS_TR_NONE;\n    ESYS_CONTEXT *esys_ctx = NULL;\n    TPM2B_PUBLIC *outPublic;\n\n    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));\n    if (tpm2Data == NULL) {\n        ERR(tpm2tss_tpm2data_readtpm, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    memset(tpm2Data, 0, sizeof(*tpm2Data));\n\n    tpm2Data->privatetype = KEY_TYPE_HANDLE;\n    tpm2Data->handle = handle;\n\n    r = esys_ctx_init(&esys_ctx);\n    if (r) {\n        ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    r = Esys_TR_FromTPMPublic(esys_ctx, tpm2Data->handle,\n                              ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                              &keyHandle);\n    if (r) {\n        ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    r = Esys_ReadPublic(esys_ctx, keyHandle,\n                        ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                        &outPublic, NULL, NULL);\n    if (r) {\n        ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    /* If the persistent key has the NODA flag set, we check whether it does\n       have an empty authValue. If NODA is not set, then we don't check because\n       that would increment the DA lockout counter */\n    if ((outPublic->publicArea.objectAttributes & TPMA_OBJECT_NODA) != 0) {\n        ESYS_TR session;\n        TPMT_SYM_DEF sym = {.algorithm = TPM2_ALG_AES,\n                            .keyBits = {.aes = 128},\n                            .mode = {.aes = TPM2_ALG_CFB}\n        };\n\n        /* Esys_StartAuthSession() and session handling use OpenSSL for random\n           bytes and thus might end up inside this engine again. This becomes\n           a problem if we have no resource manager, i.e. the tpm simulator. */\n        const RAND_METHOD *rand_save = RAND_get_rand_method();\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n        RAND_set_rand_method(RAND_SSLeay());\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n        RAND_set_rand_method(RAND_OpenSSL());\n#endif\n\n        /* We do the check by starting a bound audit session and executing a\n           very cheap command. */\n        r = Esys_StartAuthSession(esys_ctx, ESYS_TR_NONE, keyHandle,\n                                  ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                                  NULL, TPM2_SE_HMAC, &sym, TPM2_ALG_SHA256,\n                                  &session);\n        /* Though this response code is sub-optimal, it's the only way to\n           detect the bug in ESYS. */\n        if (r == TSS2_ESYS_RC_GENERAL_FAILURE) {\n            DBG(\"Running tpm2-tss < 2.2 which has a bug here. Requiring auth.\");\n            tpm2Data->emptyAuth = 0;\n            goto session_error;\n        } else if (r) {\n            ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);\n            goto error;\n        }\n        Esys_TRSess_SetAttributes(esys_ctx, session,\n                                  TPMA_SESSION_ENCRYPT, TPMA_SESSION_ENCRYPT);\n        Esys_TRSess_SetAttributes(esys_ctx, session,\n                                  TPMA_SESSION_CONTINUESESSION,\n                                  TPMA_SESSION_CONTINUESESSION);\n\n        r = Esys_ReadPublic(esys_ctx, keyHandle,\n                            session, ESYS_TR_NONE, ESYS_TR_NONE,\n                            NULL, NULL, NULL);\n\n        RAND_set_rand_method(rand_save);\n\n        /* tpm2-tss < 2.2 has some bugs. (1) it may miscalculate the auth from\n           above leading to a password query in case of empty auth and (2) it\n           may return an error because the object's auth value is \"\\0\". */\n        if (r == TSS2_RC_SUCCESS) {\n            DBG(\"Object does not require auth\");\n            tpm2Data->emptyAuth = 1;\n        } else if (r == (TPM2_RC_BAD_AUTH | TPM2_RC_S | TPM2_RC_1)) {\n            DBG(\"Object does require auth\");\n            tpm2Data->emptyAuth = 0;\n        } else {\n            ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);\n            goto error;\n        }\n\n        Esys_FlushContext (esys_ctx, session);\n    }\n\nsession_error:\n\n    Esys_TR_Close(esys_ctx, &keyHandle);\n\n    esys_ctx_free(&esys_ctx);\n    tpm2Data->pub = *outPublic;\n    Esys_Free(outPublic);\n\n    *tpm2Datap = tpm2Data;\n    return 1;\n error:\n    if (keyHandle != ESYS_TR_NONE)\n        Esys_TR_Close(esys_ctx, &keyHandle);\n    esys_ctx_free(&esys_ctx);\n    if (tpm2Data)\n        OPENSSL_free(tpm2Data);\n    return 0;\n}\n\n/** Deserialize tpm2data from disk\n *\n * Read the tpm2tss key data from a file using PEM encoding.\n * @param filename The filename to read the data from.\n * @param tpm2Datap The data after read.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap)\n{\n    TSS2_RC r;\n    BIO *bio = NULL;\n    TSSPRIVKEY *tpk = NULL;\n    TPM2_DATA *tpm2Data = NULL;\n    char type_oid[64];\n    BIGNUM *bn_parent;\n\n    if ((bio = BIO_new_file(filename, \"r\")) == NULL) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);\n        goto error;\n    }\n\n    tpk = PEM_read_bio_TSSPRIVKEY(bio, NULL, NULL, NULL);\n    if (!tpk) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED);\n        goto error;\n    }\n    BIO_free(bio);\n    bio = NULL;\n\n    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));\n    if (tpm2Data == NULL) {\n        ERR(tpm2tss_tpm2data_read, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    memset(tpm2Data, 0, sizeof(*tpm2Data));\n\n    tpm2Data->privatetype = KEY_TYPE_BLOB;\n\n    tpm2Data->emptyAuth = !!tpk->emptyAuth;\n\n    bn_parent = ASN1_INTEGER_to_BN(tpk->parent, NULL);\n    if (!bn_parent) {\n        goto error;\n    }\n    if (BN_is_negative(bn_parent)) {\n        tpm2Data->parent = ASN1_INTEGER_get(tpk->parent);\n    } else {\n        tpm2Data->parent = BN_get_word(bn_parent);\n    }\n    if (tpm2Data->parent == 0)\n        tpm2Data->parent = TPM2_RH_OWNER;\n\n    if (!OBJ_obj2txt(type_oid, sizeof(type_oid), tpk->type, 1) ||\n        strcmp(type_oid, OID_loadableKey)) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_CANNOT_MAKE_KEY);\n        goto error;\n    }\n    r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(tpk->privkey->data,\n                                        tpk->privkey->length, NULL,\n                                        &tpm2Data->priv);\n    if (r) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED);\n        goto error;\n    }\n    r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(tpk->pubkey->data, tpk->pubkey->length,\n                                       NULL, &tpm2Data->pub);\n    if (r) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED);\n        goto error;\n    }\n\n    TSSPRIVKEY_free(tpk);\n\n    *tpm2Datap = tpm2Data;\n    return 1;\n error:\n    if (tpm2Data)\n        OPENSSL_free(tpm2Data);\n    if (bio)\n        BIO_free(bio);\n    if (tpk)\n        TSSPRIVKEY_free(tpk);\n\n    return 0;\n}\n\nstatic TPM2B_PUBLIC primaryEccTemplate = TPM2B_PUBLIC_PRIMARY_ECC_TEMPLATE;\nstatic TPM2B_PUBLIC primaryRsaTemplate = TPM2B_PUBLIC_PRIMARY_RSA_TEMPLATE;\n\nstatic TPM2B_SENSITIVE_CREATE primarySensitive = {\n    .sensitive = {\n        .userAuth = {\n             .size = 0,\n         },\n        .data = {\n             .size = 0,\n         }\n    }\n};\n\nstatic TPM2B_DATA allOutsideInfo = {\n    .size = 0,\n};\n\nstatic TPML_PCR_SELECTION allCreationPCR = {\n    .count = 0,\n};\n\n/** Initialize the ESYS TPM connection and primary/persistent key\n *\n * Establish a connection with the TPM using ESYS libraries and create a primary\n * key under the owner hierarchy or to initialize the ESYS object for a\n * persistent if provided.\n * @param esys_ctx The resulting ESYS context.\n * @param parentHandle The TPM handle of a persistent key or TPM2_RH_OWNER or 0\n * @param parent The resulting ESYS_TR handle for the parent key.\n * @retval TSS2_RC_SUCCESS on success\n * @retval TSS2_RCs according to the error\n */\nTSS2_RC\ninit_tpm_parent(ESYS_CONTEXT **esys_ctx,\n                TPM2_HANDLE parentHandle, ESYS_TR *parent)\n{\n    TSS2_RC r;\n    TPM2B_PUBLIC *primaryTemplate = NULL;\n    TPMS_CAPABILITY_DATA *capabilityData = NULL;\n    UINT32 index;\n    *parent = ESYS_TR_NONE;\n    *esys_ctx = NULL;\n\n    DBG(\"Establishing connection with TPM.\\n\");\n    r = esys_ctx_init(esys_ctx);\n    ERRchktss(init_tpm_parent, r, goto error);\n\n    if (parentHandle && parentHandle != TPM2_RH_OWNER) {\n        DBG(\"Connecting to a persistent parent key.\\n\");\n        r = Esys_TR_FromTPMPublic(*esys_ctx, parentHandle,\n                                  ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                                  parent);\n        ERRchktss(init_tpm_parent, r, goto error);\n\n        r = Esys_TR_SetAuth(*esys_ctx, *parent, &parentauth);\n        ERRchktss(init_tpm_parent, r, goto error);\n\n        return TSS2_RC_SUCCESS;\n    }\n\n    DBG(\"Creating primary key under owner.\\n\");\n    r = Esys_TR_SetAuth(*esys_ctx, ESYS_TR_RH_OWNER, &ownerauth);\n    ERRchktss(init_tpm_parent, r, goto error);\n\n    r = Esys_GetCapability (*esys_ctx,\n                            ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                            TPM2_CAP_ALGS, 0, TPM2_MAX_CAP_ALGS,\n                            NULL, &capabilityData);\n    ERRchktss(init_tpm_parent, r, goto error);\n\n    for (index = 0; index < capabilityData->data.algorithms.count; index++) {\n        if (capabilityData->data.algorithms.algProperties[index].alg == TPM2_ALG_ECC) {\n            primaryTemplate = &primaryEccTemplate;\n            break;\n        }\n    }\n\n    /*\n     * TPM2_ALG_ECC is *mandatory* for TPM2.0; the above should never\n     * fail. However, *if* such a broken TPM is used then ephemeral\n     * primaries according to the TSS2 PEM file standard can *never*\n     * have worked on that hardware, so it isn't *breaking* anything\n     * for us to unilaterally use an ephemeral RSA parent in this case\n     * instead.\n     *\n     * However, it may not be interoperable to do so, and it isn't a\n     * good idea anyway since RSA keys are *slow* to generate, so\n     * users with a broken TPM like this really *should* have followed\n     * the recommendation to create the RSA primary and store it in\n     * the NVRAM at 0x81000001. And then the TSS2 PEM keys should use\n     * *that* as the parent, not the ephemeral version. In fact, there\n     * is a strong case to be made for defaulting to 0x81000001 if it\n     * exists, *before* (or never) falling back to generating an RSA\n     * key here.\n     */\n    if (primaryTemplate == NULL) {\n        for (index = 0; index < capabilityData->data.algorithms.count; index++) {\n            if (capabilityData->data.algorithms.algProperties[index].alg == TPM2_ALG_RSA) {\n                primaryTemplate = &primaryRsaTemplate;\n                break;\n            }\n        }\n    }\n\n    Esys_Free (capabilityData);\n\n    if (primaryTemplate == NULL) {\n        ERR(init_tpm_parent, TPM2TSS_R_UNKNOWN_ALG);\n        goto error;\n    }\n\n    r = Esys_CreatePrimary(*esys_ctx, ESYS_TR_RH_OWNER,\n                           ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                           &primarySensitive, primaryTemplate, &allOutsideInfo,\n                           &allCreationPCR,\n                           parent, NULL, NULL, NULL, NULL);\n    if (r == 0x000009a2) {\n        ERR(init_tpm_parent, TPM2TSS_R_OWNER_AUTH_FAILED);\n        goto error;\n    }\n    ERRchktss(init_tpm_parent, r, goto error);\n\n    return TSS2_RC_SUCCESS;\n error:\n    if (*parent != ESYS_TR_NONE)\n        Esys_FlushContext(*esys_ctx, *parent);\n    *parent = ESYS_TR_NONE;\n\n    esys_ctx_free(esys_ctx);\n    return r;\n}\n\n/** Initialize the ESYS TPM connection and load the key\n *\n * Establish a connection with the TPM using ESYS libraries, create a primary\n * key under the owner hierarchy and then load the TPM key and set its auth\n * value.\n * @param esys_ctx The ESYS_CONTEXT to be populated.\n * @param keyHandle The resulting handle for the key key.\n * @param tpm2Data The key data, owner auth and key auth to be used\n * @retval TSS2_RC_SUCCESS on success\n * @retval TSS2_RCs according to the error\n */\nTSS2_RC\ninit_tpm_key (ESYS_CONTEXT **esys_ctx, ESYS_TR *keyHandle, TPM2_DATA *tpm2Data)\n{\n    TSS2_RC r;\n    ESYS_TR parent = ESYS_TR_NONE;\n    *keyHandle = ESYS_TR_NONE;\n    *esys_ctx = NULL;\n\n    if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {\n        DBG(\"Establishing connection with TPM.\\n\");\n        r = esys_ctx_init(esys_ctx);\n        ERRchktss(init_tpm_key, r, goto error);\n\n        r = Esys_TR_FromTPMPublic(*esys_ctx, tpm2Data->handle,\n                                  ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                                  keyHandle);\n        ERRchktss(init_tpm_key, r, goto error);\n    } else if (tpm2Data->privatetype == KEY_TYPE_BLOB\n               && tpm2Data->parent != TPM2_RH_OWNER) {\n        r = init_tpm_parent(esys_ctx, tpm2Data->parent, &parent);\n        ERRchktss(init_tpm_key, r, goto error);\n\n        DBG(\"Loading key blob.\\n\");\n        r = Esys_Load(*esys_ctx, parent,\n                      ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                      &tpm2Data->priv, &tpm2Data->pub, keyHandle);\n        Esys_TR_Close(*esys_ctx, &parent);\n        ERRchktss(init_tpm_key, r, goto error);\n    } else if (tpm2Data->privatetype == KEY_TYPE_BLOB) {\n        r = init_tpm_parent(esys_ctx, 0, &parent);\n        ERRchktss(init_tpm_key, r, goto error);\n\n        DBG(\"Loading key blob.\\n\");\n        r = Esys_Load(*esys_ctx, parent,\n                      ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                      &tpm2Data->priv, &tpm2Data->pub, keyHandle);\n        ERRchktss(init_tpm_key, r, goto error);\n\n        r = Esys_FlushContext(*esys_ctx, parent);\n        ERRchktss(rsa_priv_enc, r, goto error);\n        parent = ESYS_TR_NONE;\n    } else {\n        r = -1;\n        ERR(init_tpm_key, TPM2TSS_R_TPM2DATA_READ_FAILED);\n        goto error;\n    }\n\n    r = Esys_TR_SetAuth(*esys_ctx, *keyHandle, &tpm2Data->userauth);\n    ERRchktss(init_tpm_key, r, goto error);\n\n    return TSS2_RC_SUCCESS;\n error:\n    if (parent != ESYS_TR_NONE)\n        Esys_FlushContext(*esys_ctx, parent);\n    if (*keyHandle != ESYS_TR_NONE)\n        Esys_FlushContext(*esys_ctx, *keyHandle);\n    *keyHandle = ESYS_TR_NONE;\n\n    esys_ctx_free(esys_ctx);\n    return r;\n}\n\n/** Deserialize a tpm key from disk\n *\n * Read a tpm key as marshaled TPM2B_PUBLIC and (encrypted) TPM2B_PRIVATE from\n * disk and convert them into a TPM2_DATA representation\n * @param filenamepub The filename to read the public portion from.\n * @param filenametpm The filename to read the private portion from.\n * @param parent Handle of the parent key.\n * @param emptyAuth Whether the object does not require authentication.\n * @param tpm2Datap The data after read.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_tpm2data_importtpm(const char *filenamepub, const char *filenametpm,\n                           TPM2_HANDLE parent, int emptyAuth,\n                           TPM2_DATA **tpm2Datap)\n{\n    TSS2_RC r;\n    BIO *bio;\n    TPM2_DATA *tpm2data;\n    int filepub_size, filepriv_size;\n\n    uint8_t filepub[sizeof(TPM2B_PUBLIC)];\n    uint8_t filepriv[sizeof(TPM2B_PRIVATE)];\n\n    if ((bio = BIO_new_file(filenamepub, \"r\")) == NULL) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);\n        return 0;\n    }\n    filepub_size = BIO_read(bio, &filepub[0], sizeof(filepub));\n    BIO_free(bio);\n    if (filepub_size < 0) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);\n        return 0;\n    }\n\n    if ((bio = BIO_new_file(filenametpm, \"r\")) == NULL) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);\n        return 0;\n    }\n    filepriv_size = BIO_read(bio, &filepriv[0], sizeof(filepriv));\n    BIO_free(bio);\n    if (filepriv_size < 0) {\n        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);\n        return 0;\n    }\n\n    tpm2data = OPENSSL_malloc(sizeof(TPM2_DATA));\n    if (!tpm2data)\n        return 0;\n\n    memset(tpm2data, 0, sizeof(*tpm2data));\n    tpm2data->privatetype = KEY_TYPE_BLOB;\n    tpm2data->parent = parent;\n    tpm2data->emptyAuth = emptyAuth;\n\n    r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(&filepub[0], filepub_size, NULL,\n                                       &tpm2data->pub);\n    ERRchktss(tpm2tss_tpm2data_read, r, goto error);\n\n    r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(&filepriv[0], filepriv_size, NULL,\n                                        &tpm2data->priv);\n    ERRchktss(tpm2tss_tpm2data_read, r, goto error);\n\n    *tpm2Datap = tpm2data;\n    return 1;\n\n  error:\n    OPENSSL_free(tpm2data);\n    return 0;\n}\n"
  },
  {
    "path": "src/tpm2-tss-engine-common.h",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n * Copyright (c) 2019, Wind River Systems.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n#ifndef TPM2_TSS_ENGINE_COMMON_H\n#define TPM2_TSS_ENGINE_COMMON_H\n\n#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \\\n    && !defined(__STDC_NO_ATOMICS__)\n# include <stdatomic.h>\n# define TPM2_TSS_ENGINE_HAVE_C11_ATOMICS\ntypedef _Atomic int T2TE_ATOMIC_INT;\n#else\ntypedef int T2TE_ATOMIC_INT;\n#endif\n\n#include <tpm2-tss-engine.h>\n#include <tss2/tss2_mu.h>\n#include <tss2/tss2_esys.h>\n\n#include \"tpm2-tss-engine-err.h\"\n\n#include <openssl/asn1t.h>\n#include <openssl/asn1.h>\n#include <openssl/pem.h>\n\nextern TPM2B_DIGEST ownerauth;\nextern TPM2B_DIGEST parentauth;\n\nextern char *tcti_nameconf;\n\nint init_ecc(ENGINE *e);\nint init_rand(ENGINE *e);\nint init_rsa(ENGINE *e);\n\nTSS2_RC esys_ctx_init (ESYS_CONTEXT **esys_ctx);\n\nTSS2_RC esys_ctx_free (ESYS_CONTEXT **esys_ctx);\n\nTSS2_RC init_tpm_parent (   ESYS_CONTEXT **esys_ctx,\n                            TPM2_HANDLE  parentHandle,\n                            ESYS_TR      *parent);\n\nTSS2_RC init_tpm_key (  ESYS_CONTEXT **esys_ctx,\n                        ESYS_TR      *keyHandle,\n                        TPM2_DATA    *tpm2Data);\n\n#define ENGINE_HASH_ALG TPM2_ALG_SHA256\n\n#define TPM2B_PUBLIC_PRIMARY_RSA_TEMPLATE { \\\n    .publicArea = { \\\n        .type = TPM2_ALG_RSA, \\\n        .nameAlg = ENGINE_HASH_ALG, \\\n        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | \\\n                             TPMA_OBJECT_RESTRICTED | \\\n                             TPMA_OBJECT_DECRYPT | \\\n                             TPMA_OBJECT_NODA | \\\n                             TPMA_OBJECT_FIXEDTPM | \\\n                             TPMA_OBJECT_FIXEDPARENT | \\\n                             TPMA_OBJECT_SENSITIVEDATAORIGIN), \\\n        .authPolicy = { \\\n             .size = 0, \\\n         }, \\\n        .parameters.rsaDetail = { \\\n             .symmetric = { \\\n                 .algorithm = TPM2_ALG_AES, \\\n                 .keyBits.aes = 128, \\\n                 .mode.aes = TPM2_ALG_CFB, \\\n              }, \\\n             .scheme = { \\\n                .scheme = TPM2_ALG_NULL, \\\n                .details = {} \\\n             }, \\\n             .keyBits = 2048, \\\n             .exponent = 0,\\\n         }, \\\n        .unique.rsa = { \\\n             .size = 0, \\\n         } \\\n     } \\\n}\n\n/*\n * The parameters of this key can never be changed because they are\n * part of the interoperable 'standard' form for TSS2 PEM keys.\n * Where the parent key is ephemeral and generated on demand, it\n * has to be generated precisely the *same* every time or it cannot\n * work. The ECC primary is used for *all* keys regardless of their\n * type.\n */\n#define TPM2B_PUBLIC_PRIMARY_ECC_TEMPLATE { \\\n    .publicArea = { \\\n        .type = TPM2_ALG_ECC, \\\n        .nameAlg = ENGINE_HASH_ALG, \\\n        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | \\\n                             TPMA_OBJECT_RESTRICTED | \\\n                             TPMA_OBJECT_DECRYPT | \\\n                             TPMA_OBJECT_NODA | \\\n                             TPMA_OBJECT_FIXEDTPM | \\\n                             TPMA_OBJECT_FIXEDPARENT | \\\n                             TPMA_OBJECT_SENSITIVEDATAORIGIN), \\\n        .authPolicy = { \\\n             .size = 0, \\\n         }, \\\n        .parameters.eccDetail = { \\\n             .symmetric = { \\\n                 .algorithm = TPM2_ALG_AES, \\\n                 .keyBits.aes = 128, \\\n                 .mode.aes = TPM2_ALG_CFB, \\\n              }, \\\n             .scheme = { \\\n                .scheme = TPM2_ALG_NULL, \\\n                .details = {} \\\n             }, \\\n             .curveID = TPM2_ECC_NIST_P256, \\\n             .kdf = { \\\n                .scheme = TPM2_ALG_NULL, \\\n                .details = {} \\\n             }, \\\n         }, \\\n        .unique.ecc = { \\\n             .x.size = 0, \\\n             .y.size = 0 \\\n         } \\\n     } \\\n}\n\ntypedef struct {\n\tASN1_OBJECT *type;\n\tASN1_BOOLEAN emptyAuth;\n\tASN1_INTEGER *parent;\n\tASN1_OCTET_STRING *pubkey;\n\tASN1_OCTET_STRING *privkey;\n} TSSPRIVKEY;\n\n\nDECLARE_ASN1_FUNCTIONS(TSSPRIVKEY);\n\nDECLARE_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY);\nDECLARE_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY);\n\n#define OID_loadableKey \"2.23.133.10.1.3\"\n\ntypedef struct {\n    T2TE_ATOMIC_INT refcount;\n    ESYS_CONTEXT *esys_ctx;\n    ESYS_TR key_handle;\n    int privatetype;\n} TPM2_SIG_KEY_CTX;\n\ntypedef struct {\n    TPM2_SIG_KEY_CTX *key;\n    TPM2_ALG_ID hash_alg;\n    ESYS_TR seq_handle;\n    size_t sig_size;\n} TPM2_SIG_DATA;\n\nint\ndigest_update(EVP_MD_CTX *ctx, const void *data, size_t count);\nint\ndigest_finish(TPM2_SIG_DATA *data, TPM2B_DIGEST **digest,\n              TPMT_TK_HASHCHECK **validation);\nint\ndigest_sign_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx, TPM2_DATA *tpm2data,\n                 size_t sig_size);\nint\ndigest_sign_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src);\nvoid\ndigest_sign_cleanup(EVP_PKEY_CTX *ctx);\n\n#endif /* TPM2_TSS_ENGINE_COMMON_H */\n"
  },
  {
    "path": "src/tpm2-tss-engine-digest-sign.c",
    "content": "/*******************************************************************************\n * Copyright 2021, Graphiant, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <string.h>\n\n#include <openssl/evp.h>\n\n#include <tss2/tss2_esys.h>\n\n#include \"tpm2-tss-engine-common.h\"\n\n#ifndef TPM2_TSS_ENGINE_HAVE_C11_ATOMICS\n/* fall back to using GCC/clang atomic builtins */\n# define atomic_fetch_add(PTR, VAL) \\\n    __atomic_fetch_add((PTR), (VAL), __ATOMIC_SEQ_CST)\n#define atomic_fetch_sub(PTR, VAL) \\\n    __atomic_fetch_sub ((PTR), (VAL), __ATOMIC_SEQ_CST)\n#endif /* TPM2_TSS_ENGINE_HAVE_C11_ATOMICS */\n\n/**\n * Initialise a digest operation for digest and sign.\n *\n * @param ctx OpenSSL message digest context\n * @param data Digest and sign data\n * @retval 1 on success\n * @retval 0 on failure\n */\nstatic int\ndigest_init(EVP_MD_CTX *ctx, TPM2_SIG_DATA *data)\n{\n    TPM2B_AUTH null_auth = { .size = 0 };\n    const EVP_MD *md;\n    TSS2_RC r;\n\n    md = EVP_MD_CTX_md(ctx);\n    if (!md) {\n        ERR(digest_init, TPM2TSS_R_GENERAL_FAILURE);\n        return 0;\n    }\n\n    switch (EVP_MD_type(md)) {\n    case NID_sha1:\n        data->hash_alg = TPM2_ALG_SHA1;\n        break;\n    case NID_sha256:\n        data->hash_alg = TPM2_ALG_SHA256;\n        break;\n    case NID_sha384:\n        data->hash_alg = TPM2_ALG_SHA384;\n        break;\n    case NID_sha512:\n        data->hash_alg = TPM2_ALG_SHA512;\n        break;\n    default:\n        ERR(digest_init, TPM2TSS_R_UNKNOWN_ALG);\n        return 0;\n    }\n\n    r = Esys_HashSequenceStart(data->key->esys_ctx, ESYS_TR_NONE,\n                               ESYS_TR_NONE, ESYS_TR_NONE, &null_auth,\n                               data->hash_alg, &data->seq_handle);\n    ERRchktss(digest_init, r, return 0);\n\n    return 1;\n}\n\n/**\n * Update a digest with more data\n *\n * @param ctx OpenSSL message digest context\n * @param data Data to add to digest\n * @param count Length of data to add\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ndigest_update(EVP_MD_CTX *ctx, const void *data, size_t count)\n{\n    EVP_PKEY_CTX *pctx = EVP_MD_CTX_pkey_ctx(ctx);\n    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(pctx);\n    const uint8_t *current_data = data;\n    TSS2_RC r;\n\n    DBG(\"digest_update %p %p\\n\", pctx, ctx);\n\n    while (count > 0) {\n        TPM2B_MAX_BUFFER digest_data = { .size = count };\n        if (digest_data.size > sizeof(digest_data.buffer))\n            digest_data.size = sizeof(digest_data.buffer);\n        memcpy(&digest_data.buffer[0], current_data, digest_data.size);\n        current_data += digest_data.size;\n        count -= digest_data.size;\n\n        r = Esys_SequenceUpdate(sig_data->key->esys_ctx, sig_data->seq_handle,\n                                ESYS_TR_PASSWORD, ESYS_TR_NONE,\n                                ESYS_TR_NONE, &digest_data);\n        ERRchktss(digest_update, r, return 0);\n    }\n\n    return 1;\n}\n\n/**\n * Finish a digest operation for digest and sign\n *\n * @param data Digest and sign data\n * @param digest Digest calculated by TPM\n * @param validation Validation ticket for the digest calculated by TPM\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ndigest_finish(TPM2_SIG_DATA *data, TPM2B_DIGEST **digest,\n              TPMT_TK_HASHCHECK **validation)\n{\n    TSS2_RC r;\n\n    r = Esys_SequenceComplete(data->key->esys_ctx, data->seq_handle,\n                              ESYS_TR_PASSWORD, ESYS_TR_NONE,\n                              ESYS_TR_NONE, NULL, ESYS_TR_RH_OWNER,\n                              digest, validation);\n    ERRchktss(digest_finish, r, return 0);\n\n    /* Esys_SequenceComplete consumes the handle */\n    data->seq_handle = ESYS_TR_NONE;\n\n    return 1;\n}\n\n/**\n * Initialise a digest and sign operation\n *\n * @param ctx OpenSSL pkey context\n * @param mctx OpenSSL message digest context\n * @param tpm2data TPM data for the key to use\n * @param sig_size Size of the signature data\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ndigest_sign_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx, TPM2_DATA *tpm2data,\n                 size_t sig_size)\n{\n    TSS2_RC r;\n\n    if (!tpm2data)\n        /* non-TPM key - nothing to do */\n        return 1;\n\n    TPM2_SIG_DATA *data = OPENSSL_malloc(sizeof(*data));\n    if (!data) {\n        ERR(digest_sign_init, ERR_R_MALLOC_FAILURE);\n        return 0;\n    }\n\n    data->seq_handle = ESYS_TR_NONE;\n    data->sig_size = sig_size;\n\n    data->key = OPENSSL_malloc(sizeof(*data->key));\n    if (!data->key) {\n        ERR(digest_sign_init, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n\n    data->key->refcount = 1;\n\n    r = init_tpm_key(&data->key->esys_ctx, &data->key->key_handle, tpm2data);\n    ERRchktss(digest_sign_init, r, goto error);\n    data->key->privatetype = tpm2data->privatetype;\n\n    EVP_PKEY_CTX_set_app_data(ctx, data);\n    /*\n     * Override the update function so that the TPM performs the\n     * digest, which is required for restricted keys - the TPM will\n     * reject a null validation ticket in this case for the signing\n     * operation.\n     */\n    EVP_MD_CTX_set_update_fn(mctx, digest_update);\n\n    if (!digest_init(mctx, data))\n        goto error;\n\n    return 1;\n\n error:\n    if (data->key) {\n        if (data->key->key_handle != ESYS_TR_NONE) {\n            if (data->key->privatetype == KEY_TYPE_HANDLE) {\n                Esys_TR_Close(data->key->esys_ctx, &data->key->key_handle);\n            } else {\n                Esys_FlushContext(data->key->esys_ctx, data->key->key_handle);\n            }\n        }\n        if (data->key->esys_ctx)\n            esys_ctx_free(&data->key->esys_ctx);\n        OPENSSL_free(data->key);\n    }\n    OPENSSL_free(data);\n    return 0;\n}\n\n/**\n * Copy digest and sign context\n *\n * @param dst Destination OpenSSL pkey context\n * @param src Source OpenSSL pkey context\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ndigest_sign_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)\n{\n    TPM2_SIG_DATA *src_sig_data = EVP_PKEY_CTX_get_app_data(src);\n    TPMS_CONTEXT *context = NULL;\n    TPM2_SIG_DATA *dst_sig_data = NULL;\n    TSS2_RC r;\n\n    if (src_sig_data) {\n        dst_sig_data = OPENSSL_malloc(sizeof(*dst_sig_data));\n        if (!dst_sig_data) {\n            ERR(digest_sign_copy, ERR_R_MALLOC_FAILURE);\n            return 0;\n        }\n\n        dst_sig_data->hash_alg = src_sig_data->hash_alg;\n        dst_sig_data->sig_size = src_sig_data->sig_size;\n\n        if (src_sig_data->seq_handle != ESYS_TR_NONE) {\n            /* duplicate sequence handle */\n\n            r = Esys_ContextSave(src_sig_data->key->esys_ctx,\n                                 src_sig_data->seq_handle, &context);\n            ERRchktss(digest_sign_copy, r, goto error);\n            dst_sig_data->seq_handle = ESYS_TR_NONE;\n            r = Esys_ContextLoad(src_sig_data->key->esys_ctx, context,\n                                 &dst_sig_data->seq_handle);\n            ERRchktss(digest_sign_copy, r, goto error);\n        }\n\n        dst_sig_data->key = src_sig_data->key;\n        atomic_fetch_add(&dst_sig_data->key->refcount, 1);\n\n        EVP_PKEY_CTX_set_app_data(dst, dst_sig_data);\n    }\n\n    Esys_Free(context);\n    return 1;\n\n error:\n    Esys_Free(context);\n    OPENSSL_free(dst_sig_data);\n    return 0;\n}\n\n/**\n * Clean up digest and sign context\n *\n * @param ctx OpenSSL pkey context\n * @retval 1 on success\n * @retval 0 on failure\n */\nvoid\ndigest_sign_cleanup(EVP_PKEY_CTX *ctx)\n{\n    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx);\n\n    if (sig_data) {\n        if (sig_data->seq_handle != ESYS_TR_NONE)\n            Esys_FlushContext(sig_data->key->esys_ctx, sig_data->seq_handle);\n\n        if (atomic_fetch_sub(&sig_data->key->refcount, 1) == 1) {\n            if (sig_data->key->key_handle != ESYS_TR_NONE) {\n                if (sig_data->key->privatetype == KEY_TYPE_HANDLE) {\n                    Esys_TR_Close(sig_data->key->esys_ctx,\n                                  &sig_data->key->key_handle);\n                } else {\n                    Esys_FlushContext(sig_data->key->esys_ctx,\n                                      sig_data->key->key_handle);\n                }\n            }\n            esys_ctx_free(&sig_data->key->esys_ctx);\n            OPENSSL_free(sig_data->key);\n        }\n        OPENSSL_free(sig_data);\n        EVP_PKEY_CTX_set_app_data(ctx, NULL);\n    }\n}\n"
  },
  {
    "path": "src/tpm2-tss-engine-ecc.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <string.h>\n\n#include <openssl/engine.h>\n#include <openssl/ec.h>\n#include <openssl/ecdsa.h>\n\n#include <tss2/tss2_mu.h>\n#include <tss2/tss2_esys.h>\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\nstatic int ec_key_app_data = -1;\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\nconst ECDSA_METHOD *ecc_method_default = NULL;\nECDSA_METHOD *ecc_methods = NULL;\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\nconst EC_KEY_METHOD *ecc_method_default = NULL;\nEC_KEY_METHOD *ecc_methods = NULL;\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n#ifdef HAVE_OPENSSL_DIGEST_SIGN\nstatic int (*ecdsa_pkey_orig_copy)(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src);\nstatic void (*ecdsa_pkey_orig_cleanup)(EVP_PKEY_CTX *ctx);\n#endif /* HAVE_OPENSSL_DIGEST_SIGN */\n\nstatic TPM2B_DATA allOutsideInfo = {\n    .size = 0,\n};\n\nstatic TPML_PCR_SELECTION allCreationPCR = {\n    .count = 0,\n};\n\nstatic TPM2B_PUBLIC keyEcTemplate = {\n    .publicArea = {\n        .type = TPM2_ALG_ECC,\n        .nameAlg = ENGINE_HASH_ALG,\n        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |\n                             TPMA_OBJECT_SIGN_ENCRYPT |\n                             TPMA_OBJECT_FIXEDTPM |\n                             TPMA_OBJECT_FIXEDPARENT |\n                             TPMA_OBJECT_SENSITIVEDATAORIGIN |\n                             TPMA_OBJECT_NODA),\n        .parameters.eccDetail = {\n             .curveID = 0, /* To be filled out later */\n             .symmetric = {\n                 .algorithm = TPM2_ALG_NULL,\n                 .keyBits.aes = 0,\n                 .mode.aes = 0,\n              },\n             .scheme = {\n                .scheme = TPM2_ALG_NULL,\n                .details = {}\n             },\n             .kdf = {\n                .scheme = TPM2_ALG_NULL,\n                .details = {}\n             },\n         },\n        .unique.ecc = {\n             .x.size = 0,\n             .y.size = 0\n         }\n     }\n};\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\nstatic int EC_GROUP_order_bits(const EC_GROUP *group)\n{\n    if (!group)\n        return 0;\n\n    BIGNUM *order = BN_new();\n\n    if (order == NULL) {\n        ERR_clear_error();\n        return 0;\n    }\n\n    int ret = 0;\n\n    if (!EC_GROUP_get_order(group, order, NULL)) {\n        ERR_clear_error();\n        BN_free(order);\n        return 0;\n    }\n\n    ret = BN_num_bits(order);\n    BN_free(order);\n    return ret;\n}\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n /**\n  * Initialize a TPM2B_ECC_POINT from an OpenSSL EC_POINT.\n  *\n  * @param point Pointer to output tpm point\n  * @param pub_key OpenSSL public key to convert\n  * @param group Curve group\n  * @retval 0 on failure\n  */\nstatic int\ninit_tpm_public_point(TPM2B_ECC_POINT *point, const EC_POINT *ec_point,\n                        const EC_GROUP *ec_group)\n{\n    unsigned char buffer[1 + sizeof(point->point.x.buffer)\n                           + sizeof(point->point.y.buffer)] = {0};\n\n    BN_CTX *ctx = BN_CTX_new();\n    if (!ctx)\n        return 0;\n\n    BN_CTX_start(ctx);\n\n    size_t len = 0;\n\n    // first, check for actual buffer size required\n    if ((len = EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, ctx)) <= sizeof(buffer)) {\n        len = EC_POINT_point2oct(ec_group, ec_point,\n                    POINT_CONVERSION_UNCOMPRESSED, buffer, sizeof(buffer), ctx);\n    }\n\n    BN_CTX_end(ctx);\n    BN_CTX_free(ctx);\n\n    if (len == 0 || len > sizeof(buffer))\n        return 0;\n\n    len = (len - 1) / 2;\n\n    point->point.x.size = len;\n    point->point.y.size = len;\n    memcpy(point->point.x.buffer, &buffer[1], len);\n    memcpy(point->point.y.buffer, &buffer[1 + len], len);\n\n    return 1;\n}\n\n/**\n * Generate a shared secret using a TPM key\n *\n * @param psec Pointer to output buffer holding shared secret\n * @param pseclen Size of the psec buffer\n * @param pub_key The peer's public key\n * @param ecdh The ECC key object for the host private key\n * @retval 0 on failure\n */\nstatic int\necdh_compute_key(unsigned char **psec, size_t *pseclen,\n                    const EC_POINT *pub_key, const EC_KEY *eckey)\n{\n    /*\n     * If this is not a TPM2 key, bail out since fall through to software\n     * functions requires a non-const EC_KEY, yet the ECDH prototype only\n     * provides it as const.\n     */\n    TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(eckey);\n    if (tpm2Data == NULL)\n        return 0;\n\n    TPM2B_ECC_POINT inPoint;\n    TPM2B_ECC_POINT *outPoint = NULL;\n    const EC_GROUP *group = EC_KEY_get0_group(eckey);\n\n    int ret = init_tpm_public_point(&inPoint, pub_key, group);\n    if (!ret)\n        return 0;\n\n    ESYS_CONTEXT *esys_ctx = NULL;\n    ESYS_TR keyHandle = ESYS_TR_NONE;\n    TSS2_RC r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);\n    ERRchktss(ecdh_compute_key, r, goto error);\n\n    r = Esys_ECDH_ZGen(esys_ctx, keyHandle,\n            ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n            &inPoint, &outPoint);\n    ERRchktss(ecdh_compute_key, r, goto error);\n\n    *pseclen = outPoint->point.x.size;\n    *psec = OPENSSL_malloc(*pseclen);\n    if (!*psec)\n        goto error;\n\n    memcpy(*psec, outPoint->point.x.buffer, *pseclen);\n    ret = 1;\n    goto out;\nerror:\n    ret = 0;\nout:\n    if (keyHandle != ESYS_TR_NONE) {\n        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {\n            Esys_TR_Close(esys_ctx, &keyHandle);\n        } else {\n            Esys_FlushContext(esys_ctx, keyHandle);\n        }\n    }\n    Esys_Free(outPoint);\n    esys_ctx_free(&esys_ctx);\n    return ret;\n}\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\nstatic ECDSA_SIG *\necdsa_sign(ESYS_CONTEXT *esys_ctx, ESYS_TR key_handle,\n\t   TPM2B_DIGEST *digest, TPMT_TK_HASHCHECK *validation,\n\t   TPM2_ALG_ID hash_alg)\n{\n    TPMT_SIG_SCHEME inScheme = {\n      .scheme = TPM2_ALG_ECDSA,\n      .details.ecdsa.hashAlg = hash_alg,\n    };\n    BIGNUM *bns = NULL, *bnr = NULL;\n    ECDSA_SIG *ret = NULL;\n    TPMT_SIGNATURE *sig = NULL;\n    TSS2_RC r;\n\n    r = Esys_Sign(esys_ctx, key_handle, ESYS_TR_PASSWORD,\n                  ESYS_TR_NONE, ESYS_TR_NONE, digest, &inScheme,\n                  validation, &sig);\n    ERRchktss(ecdsa_sign, r, goto error);\n\n    ret = ECDSA_SIG_new();\n    if (ret == NULL) {\n        ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n\n    bns = BN_bin2bn(&sig->signature.ecdsa.signatureS.buffer[0],\n                    sig->signature.ecdsa.signatureS.size, NULL);\n    bnr = BN_bin2bn(&sig->signature.ecdsa.signatureR.buffer[0],\n                    sig->signature.ecdsa.signatureR.size, NULL);\n    if (!bns || !bnr) {\n        ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    ret->s = bns;\n    ret->r = bnr;\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    ECDSA_SIG_set0(ret, bnr, bns);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n    goto out;\n\n error:\n    if (bns)\n      BN_free(bns);\n    if (bnr)\n      BN_free(bnr);\n    if (ret)\n      ECDSA_SIG_free(ret);\n    ret = NULL;\n out:\n    Esys_Free(sig);\n    return ret;\n}\n\n/** Sign data using a TPM key\n *\n * This function performs the sign function using the private key in ECDSA.\n * This operation is usually used to perform signature and authentication\n * operations.\n * @param dgst The data to be signed.\n * @param dgst_len Length of the from buffer.\n * @param inv Ignored\n * @param rp Ignored\n * @param eckey The ECC key object.\n * @retval 0 on failure\n * @retval size Size of the returned signature\n */\nstatic ECDSA_SIG *\necdsa_ec_key_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,\n\t\t  const BIGNUM *rp, EC_KEY *eckey)\n{\n    ECDSA_SIG *ret = NULL;\n    TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(eckey);\n    TPM2_ALG_ID hash_alg;\n\n    /* If this is not a TPM2 key, fall through to software functions */\n    if (tpm2Data == NULL) {\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n        ECDSA_set_method(eckey, ecc_method_default);\n        ret = ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, eckey);\n        ECDSA_set_method(eckey, ecc_methods);\n        return ret;\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n        EC_KEY_set_method(eckey, ecc_method_default);\n        ret = ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, eckey);\n        EC_KEY_set_method(eckey, ecc_methods);\n        return ret;\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    }\n\n    DBG(\"ecdsa_sign called for input data(size=%i):\\n\", dgst_len);\n    DBGBUF(dgst, dgst_len);\n\n    TSS2_RC r;\n    ESYS_CONTEXT *esys_ctx = NULL;\n    ESYS_TR keyHandle = ESYS_TR_NONE;\n\n    TPMT_TK_HASHCHECK validation = { .tag = TPM2_ST_HASHCHECK,\n                                     .hierarchy = TPM2_RH_NULL,\n                                     .digest.size = 0 };\n\n    /*\n     * ECDSA signatures truncate the incoming hash to fit the curve,\n     * and the signature mechanism is the same regardless of the\n     * hash being used.\n     *\n     * The TPM bizarrely wants to be told the hash algorithm, and\n     * either it or the TSS will validate that the digest length\n     * matches the hash that it's told, despite it having no business\n     * caring about such things.\n     *\n     * So, we can truncate the digest any pretend it's any smaller\n     * digest that the TPM actually does support, as long as that\n     * digest is larger than the size of the curve.\n     */\n    int curve_len = (EC_GROUP_order_bits(EC_KEY_get0_group(eckey)) + 7) / 8;\n    /* If we couldn't work it out, don't truncate */\n    if (!curve_len)\n\t    curve_len = dgst_len;\n\n    if (dgst_len == SHA_DIGEST_LENGTH ||\n\t(curve_len <= SHA_DIGEST_LENGTH && dgst_len > SHA_DIGEST_LENGTH)) {\n\t    hash_alg = TPM2_ALG_SHA1;\n\t    dgst_len = SHA_DIGEST_LENGTH;\n    } else if (dgst_len == SHA256_DIGEST_LENGTH ||\n\t(curve_len <= SHA256_DIGEST_LENGTH && dgst_len > SHA256_DIGEST_LENGTH)) {\n\t    hash_alg = TPM2_ALG_SHA256;\n\t    dgst_len = SHA256_DIGEST_LENGTH;\n    } else if (dgst_len == SHA384_DIGEST_LENGTH ||\n\t(curve_len <= SHA384_DIGEST_LENGTH && dgst_len > SHA384_DIGEST_LENGTH)) {\n\t    hash_alg = TPM2_ALG_SHA384;\n\t    dgst_len = SHA384_DIGEST_LENGTH;\n    } else if (dgst_len == SHA512_DIGEST_LENGTH ||\n\t(curve_len <= SHA512_DIGEST_LENGTH && dgst_len > SHA512_DIGEST_LENGTH)) {\n\t    hash_alg = TPM2_ALG_SHA512;\n\t    dgst_len = SHA512_DIGEST_LENGTH;\n    } else {\n        ERR(ecdsa_sign, TPM2TSS_R_PADDING_UNKNOWN);\n        goto error;\n    }\n\n    TPM2B_DIGEST digest = { .size = dgst_len };\n    if (digest.size > sizeof(digest.buffer)) {\n        ERR(ecdsa_sign, TPM2TSS_R_DIGEST_TOO_LARGE);\n        goto error;\n    }\n    memcpy(&digest.buffer[0], dgst, digest.size);\n\n    r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);\n    ERRchktss(ecdsa_sign, r, goto error);\n\n    ret = ecdsa_sign(esys_ctx, keyHandle, &digest, &validation, hash_alg);\n\n    goto out;\n error:\n    r = -1;\n out:\n    if (keyHandle != ESYS_TR_NONE) {\n        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {\n            Esys_TR_Close(esys_ctx, &keyHandle);\n        } else {\n            Esys_FlushContext(esys_ctx, keyHandle);\n        }\n    }\n\n    esys_ctx_free(&esys_ctx);\n    return (r == TSS2_RC_SUCCESS) ? ret : NULL;\n}\n\n#ifdef HAVE_OPENSSL_DIGEST_SIGN\nstatic int\necdsa_pkey_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)\n{\n    if (ecdsa_pkey_orig_copy && !ecdsa_pkey_orig_copy(dst, src))\n        return 0;\n\n    return digest_sign_copy(dst, src);\n}\n\nstatic void\necdsa_pkey_cleanup(EVP_PKEY_CTX *ctx)\n{\n    digest_sign_cleanup(ctx);\n\n    if (ecdsa_pkey_orig_cleanup)\n        ecdsa_pkey_orig_cleanup(ctx);\n}\n\n/* called for digest & sign init, after message digest algorithm set */\nstatic int\necdsa_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)\n{\n    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);\n    EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey);\n    TPM2_DATA *tpm2data = tpm2tss_ecc_getappdata(eckey);\n\n    DBG(\"ecdsa_digest_custom %p %p\\n\", ctx, mctx);\n\n    return digest_sign_init(ctx, mctx, tpm2data, ECDSA_size(eckey));\n}\n\nstatic int\necdsa_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,\n              EVP_MD_CTX *mctx)\n{\n    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx);\n    TSS2_RC r = TSS2_RC_SUCCESS;\n    TPMT_TK_HASHCHECK *validation_ptr = NULL;\n    TPM2B_DIGEST *digest_ptr = NULL;\n    ECDSA_SIG *ecdsa_s = NULL;\n\n    DBG(\"ecdsa_signctx %p %p sig_data %p\\n\", ctx, mctx, sig_data);\n\n    if (!sig) {\n        /* caller just wants to know the size */\n        *siglen = sig_data->sig_size;\n        return 1;\n    }\n\n    if (!sig_data) {\n        /* handle non-TPM key */\n        unsigned char md[EVP_MAX_MD_SIZE];\n        unsigned int md_len = 0;\n\n        if (!EVP_DigestFinal_ex(mctx, md, &md_len))\n            return 0;\n        if (EVP_PKEY_sign(ctx, sig, siglen, md, md_len) <= 0)\n            return 0;\n        return 1;\n    }\n\n    if (!digest_finish(sig_data, &digest_ptr, &validation_ptr))\n        return 0;\n\n    ecdsa_s = ecdsa_sign(sig_data->key->esys_ctx, sig_data->key->key_handle,\n                         digest_ptr, validation_ptr,\n                         sig_data->hash_alg);\n    if (!ecdsa_s)\n        goto error;\n\n    *siglen = i2d_ECDSA_SIG(ecdsa_s, &sig);\n\n    r = 1;\n    goto out;\n\n error:\n    r = 0;\n out:\n    ECDSA_SIG_free(ecdsa_s);\n    Esys_Free(digest_ptr);\n    Esys_Free(validation_ptr);\n\n    return r;\n}\n#endif /* HAVE_OPENSSL_DIGEST_SIGN */\n\n/** Helper to populate the ECC key object.\n *\n * In order to use an ECC key object in a typical manner, all fields of the\n * OpenSSL's corresponding object bust be filled. This function fills the public\n * values correctly.\n * @param key The key object to fill.\n * @retval 0 on failure\n * @retval 1 on success\n */\nstatic int\npopulate_ecc(EC_KEY *key)\n{\n    EC_GROUP *ecgroup = NULL;\n    int nid;\n    BIGNUM *x = NULL, *y = NULL;\n    TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(key);\n    if (tpm2Data == NULL)\n        return 0;\n\n    switch (tpm2Data->pub.publicArea.parameters.eccDetail.curveID) {\n    case TPM2_ECC_NIST_P256:\n        nid = EC_curve_nist2nid(\"P-256\");\n        break;\n    case TPM2_ECC_NIST_P384:\n        nid = EC_curve_nist2nid(\"P-384\");\n        break;\n    default:\n        nid = -1;\n    }\n    if (nid < 0) {\n        ERR(populate_ecc, TPM2TSS_R_UNKNOWN_CURVE);\n        return 0;\n    }\n    ecgroup = EC_GROUP_new_by_curve_name(nid);\n    if (ecgroup == NULL) {\n        ERR(populate_ecc, TPM2TSS_R_UNKNOWN_CURVE);\n        return 0;\n    }\n    if (!EC_KEY_set_group(key, ecgroup)) {\n        ERR(populate_ecc, TPM2TSS_R_GENERAL_FAILURE);\n        EC_GROUP_free(ecgroup);\n        return 0;\n    }\n    EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);\n    EC_GROUP_free(ecgroup);\n\n    x = BN_bin2bn(tpm2Data->pub.publicArea.unique.ecc.x.buffer,\n                  tpm2Data->pub.publicArea.unique.ecc.x.size, NULL);\n\n    y = BN_bin2bn(tpm2Data->pub.publicArea.unique.ecc.y.buffer,\n                  tpm2Data->pub.publicArea.unique.ecc.y.size, NULL);\n\n    if (!x || !y) {\n        ERR(populate_ecc, ERR_R_MALLOC_FAILURE);\n        return 0;\n    }\n\n    if (!EC_KEY_set_public_key_affine_coordinates(key, x, y)) {\n        ERR(populate_ecc, TPM2TSS_R_GENERAL_FAILURE);\n        BN_free(y);\n        BN_free(x);\n        return 0;\n    }\n\n    BN_free(y);\n    BN_free(x);\n\n    return 1;\n}\n\n/** Helper to load an ECC key from a tpm2Data\n *\n * This function creates a key object given a TPM2_DATA object. The resulting\n * key object can then be used for signing with the tpm2tss engine. Ownership\n * of the TPM2_DATA object is taken on success.\n * @param tpm2Data The key data to use. Must have been allocated using\n * OPENSSL_malloc.\n * @retval key The key object\n * @retval NULL on failure.\n */\nEVP_PKEY *\ntpm2tss_ecc_makekey(TPM2_DATA *tpm2Data)\n{\n    DBG(\"Creating ECC key object.\\n\");\n\n    EVP_PKEY *pkey;\n    EC_KEY *eckey;\n\n    /* create the new objects to return */\n    if ((pkey = EVP_PKEY_new()) == NULL) {\n        ERR(tpm2tss_ecc_makekey, ERR_R_MALLOC_FAILURE);\n        return NULL;\n    }\n\n    if ((eckey = EC_KEY_new()) == NULL) {\n        ERR(tpm2tss_ecc_makekey, ERR_R_MALLOC_FAILURE);\n        EVP_PKEY_free(pkey);\n\n        return NULL;\n    }\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    if (!ECDSA_set_method(eckey, ecc_methods)) {\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    if (!EC_KEY_set_method(eckey, ecc_methods)) {\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n        ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);\n        EC_KEY_free(eckey);\n        goto error;\n    }\n\n    if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) {\n        ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);\n        EC_KEY_free(eckey);\n        goto error;\n    }\n\n    if (!tpm2tss_ecc_setappdata(eckey, tpm2Data)) {\n        ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    if (!populate_ecc(eckey))\n        goto error;\n\n    DBG(\"Created ECC key object.\\n\");\n\n    return pkey;\n error:\n    EVP_PKEY_free(pkey);\n    return NULL;\n}\n\n/** Retrieve app data\n *\n * Since the ECC api (opposed to the RSA api) does not provide a standardized\n * way to retrieve app data between the library and an application, this helper\n * is defined\n * @param key The key object\n * @retval tpm2Data The corresponding TPM data\n * @retval NULL on failure.\n */\nTPM2_DATA *\n#if OPENSSL_VERSION_NUMBER < 0x10100000\ntpm2tss_ecc_getappdata(EC_KEY *key)\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\ntpm2tss_ecc_getappdata(const EC_KEY *key)\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n{\n    if (ec_key_app_data == -1) {\n        DBG(\"Module uninitialized\\n\");\n        return NULL;\n    }\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    return ECDSA_get_ex_data(key, ec_key_app_data);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    return EC_KEY_get_ex_data(key, ec_key_app_data);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n}\n\n/** Set app data\n *\n * Since the ECC api (opposed to the RSA api) does not provide a standardized\n * way to set app data between the library and an application, this helper\n * is defined\n * @param key The key object\n * @param tpm2Data The corresponding TPM data\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *tpm2Data)\n{\n    if (ec_key_app_data == -1) {\n        DBG(\"Module uninitialized\\n\");\n        return 0;\n    }\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    return ECDSA_set_ex_data(key, ec_key_app_data, tpm2Data);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    return EC_KEY_set_ex_data(key, ec_key_app_data, tpm2Data);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n}\n\nstatic void\nfree_ecc_appdata(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,\n                 long argl, void *argp)\n{\n    TPM2_DATA *tpm2Data = ptr;\n\n    (void)parent;\n    (void)ad;\n    (void)idx;\n    (void)argl;\n    (void)argp;\n\n    if (!ptr)\n        return;\n\n    OPENSSL_free(tpm2Data);\n}\n\n/** Generate a tpm2tss ecc key object.\n *\n * This function creates a new TPM ECC key. The TPM data is stored inside the\n * object*s app data and can be retrieved using tpm2tss_ecc_getappdata().\n * @param key The key object for the TPM ECC key to be created\n * @param curve The curve to be used for the key\n * @param password The Password to be set for the new key\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password,\n                   TPM2_HANDLE parentHandle)\n{\n    DBG(\"GenKey for ecdsa.\\n\");\n\n    TSS2_RC r;\n    ESYS_CONTEXT *esys_ctx = NULL;\n    ESYS_TR parent = ESYS_TR_NONE;\n    TPM2B_PUBLIC *keyPublic = NULL;\n    TPM2B_PRIVATE *keyPrivate = NULL;\n    TPM2_DATA *tpm2Data = NULL;\n    TPM2B_PUBLIC inPublic = keyEcTemplate;\n    TPM2B_SENSITIVE_CREATE inSensitive = {\n        .sensitive = {\n            .userAuth = {\n                 .size = 0,\n             },\n            .data = {\n                 .size = 0,\n             }\n        }\n    };\n\n    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));\n    if (tpm2Data == NULL) {\n        ERR(tpm2tss_ecc_genkey, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    memset(tpm2Data, 0, sizeof(*tpm2Data));\n\n    inPublic.publicArea.parameters.eccDetail.curveID = curve;\n\n    if (password) {\n        DBG(\"Setting a password for the created key.\\n\");\n        if (strlen(password) > sizeof(tpm2Data->userauth.buffer) - 1 || strlen(password) > sizeof(inSensitive.sensitive.userAuth.buffer) - 1) {\n            goto error;\n        }\n        tpm2Data->userauth.size = strlen(password);\n        memcpy(&tpm2Data->userauth.buffer[0], password,\n               tpm2Data->userauth.size);\n\n        inSensitive.sensitive.userAuth.size = strlen(password);\n        memcpy(&inSensitive.sensitive.userAuth.buffer[0], password,\n               strlen(password));\n    } else\n        tpm2Data->emptyAuth = 1;\n\n    r = init_tpm_parent(&esys_ctx, parentHandle, &parent);\n    ERRchktss(tpm2tss_ecc_genkey, r, goto error);\n\n    tpm2Data->parent = parentHandle;\n\n    DBG(\"Generating the ECC key inside the TPM.\\n\");\n\n    r = Esys_Create(esys_ctx, parent,\n                    ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                    &inSensitive, &inPublic, &allOutsideInfo, &allCreationPCR,\n                    &keyPrivate, &keyPublic, NULL, NULL, NULL);\n    ERRchktss(tpm2tss_ecc_genkey, r, goto error);\n\n    DBG(\"Generated the ECC key inside the TPM.\\n\");\n\n    tpm2Data->pub = *keyPublic;\n    tpm2Data->priv = *keyPrivate;\n\n    if (!tpm2tss_ecc_setappdata(key, tpm2Data)) {\n        ERR(tpm2tss_ecc_genkey, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    if (!populate_ecc(key)) {\n        goto error;\n    }\n\n    goto end;\n error:\n    r = -1;\n    tpm2tss_ecc_setappdata(key, NULL);\n    if (tpm2Data)\n        OPENSSL_free(tpm2Data);\n\n end:\n    Esys_Free(keyPrivate);\n    Esys_Free(keyPublic);\n\n    if (parent != ESYS_TR_NONE && !parentHandle)\n        Esys_FlushContext(esys_ctx, parent);\n\n    esys_ctx_free(&esys_ctx);\n\n    return (r == TSS2_RC_SUCCESS);\n}\n\n/** Initialize the tpm2tss engine's ecc submodule\n *\n * Initialize the tpm2tss engine's submodule by setting function pointer.\n * @param e The engine context.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ninit_ecc(ENGINE *e)\n{\n    (void)(e);\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    ecc_method_default = ECDSA_OpenSSL();\n    if (ecc_method_default == NULL)\n        return 0;\n\n    ecc_methods = ECDSA_METHOD_new(ecc_method_default);\n    if (ecc_methods == NULL)\n        return 0;\n\n    ECDSA_METHOD_set_sign(ecc_methods, ecdsa_ec_key_sign);\n\n    if (ec_key_app_data == -1)\n        ec_key_app_data = ECDSA_get_ex_new_index(0, NULL, NULL, NULL,\n                                                 free_ecc_appdata);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    ecc_method_default = EC_KEY_OpenSSL();\n    if (ecc_method_default == NULL)\n        return 0;\n\n    ecc_methods = EC_KEY_METHOD_new(ecc_method_default);\n    if (ecc_methods == NULL)\n        return 0;\n\n    int (*orig_sign) (int, const unsigned char *, int, unsigned char *,\n                      unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *)\n        = NULL;\n    EC_KEY_METHOD_get_sign(ecc_methods, &orig_sign, NULL, NULL);\n    EC_KEY_METHOD_set_sign(ecc_methods, orig_sign, NULL, ecdsa_ec_key_sign);\n    EC_KEY_METHOD_set_compute_key(ecc_methods, ecdh_compute_key);\n\n    if (ec_key_app_data == -1)\n        ec_key_app_data = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL,\n                                                  free_ecc_appdata);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n#if HAVE_OPENSSL_DIGEST_SIGN\n    /* digest and sign support */\n\n    EVP_PKEY_METHOD *pkey_ecc_methods;\n\n    pkey_ecc_methods = EVP_PKEY_meth_new(EVP_PKEY_EC, 0);\n    if (pkey_ecc_methods == NULL)\n        return 0;\n\n    const EVP_PKEY_METHOD *pkey_orig_ecc_methods =\n        EVP_PKEY_meth_find(EVP_PKEY_EC);\n    if (pkey_orig_ecc_methods == NULL)\n        return 0;\n    EVP_PKEY_meth_copy(pkey_ecc_methods, pkey_orig_ecc_methods);\n    /*\n     * save originals since we only override some of the pkey\n     * functionality, rather than reimplementing all of it\n     */\n    EVP_PKEY_meth_get_copy(pkey_ecc_methods, &ecdsa_pkey_orig_copy);\n    EVP_PKEY_meth_get_cleanup(pkey_ecc_methods, &ecdsa_pkey_orig_cleanup);\n\n    EVP_PKEY_meth_set_copy(pkey_ecc_methods, ecdsa_pkey_copy);\n    EVP_PKEY_meth_set_cleanup(pkey_ecc_methods, ecdsa_pkey_cleanup);\n    EVP_PKEY_meth_set_signctx(pkey_ecc_methods, NULL, ecdsa_signctx);\n    EVP_PKEY_meth_set_digest_custom(pkey_ecc_methods, ecdsa_digest_custom);\n    EVP_PKEY_meth_add0(pkey_ecc_methods);\n#endif /* HAVE_OPENSSL_DIGEST_SIGN */\n\n    return 1;\n}\n"
  },
  {
    "path": "src/tpm2-tss-engine-err.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <openssl/err.h>\n\n#include \"tpm2-tss-engine-err.h\"\n\n#define TPM2TSS_LIB_NAME \"tpm2-tss-engine\"\n\n#define xstr(s) str(s)\n#define str(s) #s\n\n#define ERR_F(f) { ERR_PACK(0, TPM2TSS_F_ ## f, 0), xstr(f) }\n#define ERR_R(r, s) { ERR_PACK(0, 0, r), xstr(s) }\n\n#ifndef OPENSSL_NO_ERR\nstatic ERR_STRING_DATA TPM2TSS_f[] = {\n    /* tpm2-tss-engine.c */\n    ERR_F(loadkey),\n    ERR_F(init_engine),\n    ERR_F(get_auth),\n    ERR_F(engine_ctrl),\n    /* tpm2-tss-engine-common.c */\n    ERR_F(tpm2tss_tpm2data_write),\n    ERR_F(tpm2tss_tpm2data_read),\n    ERR_F(tpm2tss_tpm2data_readtpm),\n    ERR_F(init_tpm_parent),\n    ERR_F(init_tpm_key),\n    ERR_F(esys_ctx_init),\n    ERR_F(esys_ctx_free),\n    /* tpm2-tss-engine-ecc.c */\n    ERR_F(ecdsa_sign),\n    ERR_F(populate_ecc),\n    ERR_F(tpm2tss_ecc_genkey),\n    ERR_F(tpm2tss_ecc_makekey),\n    /* tpm2-tss-engine-rand.c */\n    ERR_F(rand_bytes),\n    ERR_F(rand_seed),\n    /* tpm2-tss-engine-rsa.c */\n    ERR_F(rsa_priv_enc),\n    ERR_F(rsa_priv_dec),\n    ERR_F(tpm2tss_rsa_genkey),\n    ERR_F(populate_rsa),\n    {0, NULL}\n};\n\nstatic ERR_STRING_DATA TPM2TSS_r[] = {\n    ERR_R(TPM2TSS_R_TPM2DATA_READ_FAILED, Failed to read TPM2 data),\n    ERR_R(TPM2TSS_R_UNKNOWN_ALG, The algorithm is unknown (neither RSA, ECDSA)),\n    ERR_R(TPM2TSS_R_CANNOT_MAKE_KEY, Cannot create OpenSSL key object),\n    ERR_R(TPM2TSS_R_SUBINIT_FAILED, Could not initialize submodule),\n    ERR_R(TPM2TSS_R_FILE_WRITE, Could not create file for writing),\n    ERR_R(TPM2TSS_R_DATA_CORRUPTED, Data is corrupted and could not be parsed),\n    ERR_R(TPM2TSS_R_FILE_READ, Could not open file for reading),\n    ERR_R(TPM2TSS_R_PADDING_UNKNOWN, Unknown padding scheme requested),\n    ERR_R(TPM2TSS_R_PADDING_FAILED, Padding operation failed),\n    ERR_R(TPM2TSS_R_UNKNOWN_TPM_ERROR, Unknown TPM error occurred. Please check tpm2tss logs),\n    ERR_R(TPM2TSS_R_DIGEST_TOO_LARGE, The provided digest value is too large),\n    ERR_R(TPM2TSS_R_GENERAL_FAILURE, Some unknown error occurred),\n    ERR_R(TPM2TSS_R_UNKNOWN_CURVE, Unknown ECC curve),\n    ERR_R(TPM2TSS_R_UI_ERROR, User interaction),\n    ERR_R(TPM2TSS_R_UNKNOWN_CTRL, Unknown engine ctrl),\n    ERR_R(TPM2TSS_R_DL_OPEN_FAILED, Failed to open TCTI library),\n    ERR_R(TPM2TSS_R_DL_INVALID, The TCTI library is invalid),\n    /* TPM/TSS Reasons that are useful to the user */\n    ERR_R(TPM2TSS_R_AUTH_FAILURE, Authorization failed),\n    ERR_R(TPM2TSS_R_OWNER_AUTH_FAILED, Owner authorization failed),\n    ERR_R(TPM2TSS_R_OLD_TSS, An old TSS (<2.2) was detected and a TPM session may have leaked),\n    {0, NULL}\n};\n#endif /* OPENSSL_NO_ERR */\n\nstatic int TPM2TSS_lib_error_code = 0;\nstatic int TPM2TSS_error_init = 0;\n\nstatic ERR_STRING_DATA TPM2TSS_lib_name[] = {\n    {0, TPM2TSS_LIB_NAME},\n    {0, NULL}\n};\n\n/** Load TPM2TSS error string\n *\n * Load the errorstring from TPM2TSS_f and TPM2TSS_r into OpenSSL's error\n * handling stack.\n */\nvoid\nERR_load_TPM2TSS_strings(void)\n{\n    if (TPM2TSS_lib_error_code == 0)\n        TPM2TSS_lib_error_code = ERR_get_next_error_library();\n\n    if (!TPM2TSS_error_init) {\n        TPM2TSS_error_init = 1;\n#ifndef OPENSSL_NO_ERR\n        ERR_load_strings(TPM2TSS_lib_error_code, TPM2TSS_f);\n        ERR_load_strings(TPM2TSS_lib_error_code, TPM2TSS_r);\n#endif /* OPENSSL_NO_ERR */\n\n        TPM2TSS_lib_name->error = ERR_PACK(TPM2TSS_lib_error_code, 0, 0);\n        ERR_load_strings(0, TPM2TSS_lib_name);\n    }\n}\n\n/** Unload TPM2TSS error string\n *\n * Unload the errorstring from TPM2TSS_f and TPM2TSS_r into OpenSSL's error\n * handling stack.\n */\nvoid\nERR_unload_TPM2TSS_strings(void)\n{\n    if (TPM2TSS_error_init) {\n#ifndef OPENSSL_NO_ERR\n        ERR_unload_strings(TPM2TSS_lib_error_code, TPM2TSS_f);\n        ERR_unload_strings(TPM2TSS_lib_error_code, TPM2TSS_r);\n#endif /* OPENSSL_NO_ERR */\n\n        ERR_unload_strings(0, TPM2TSS_lib_name);\n        TPM2TSS_error_init = 0;\n    }\n}\n\n/** Add error to error stack\n *\n * Add the error to the error stack of OpenSSL.\n * This function is usually not called directly but using the macros ERR(f,r)\n * or ERRchktss(f, r, s) from source code.\n * @param function Identifier of the function invocing the error.\n * @param reason Identifier of the reason for the error.\n * @param file File from which the error originates.\n * @param line Line inside the file from which the error originates.\n */\nvoid\nERR_error(int function, int reason, const char *file, int line)\n{\n    (void)(function);\n    (void)(file);\n    (void)(line);\n    if (TPM2TSS_lib_error_code == 0)\n        TPM2TSS_lib_error_code = ERR_get_next_error_library();\n    ERR_PUT_error(TPM2TSS_lib_error_code, function, reason, file, line);\n}\n\n/** Print a buffer to stderr\n *\n * A helper function to print data buffers to stderr. This function is usually\n * not called directly, but the macro DBGBUF() is used instead.\n * @param b The buffer\n * @param s The buffer's size\n */\nvoid\nprintbuf(const uint8_t *b, size_t s)\n{\n    if (s > 1000)\n        return;\n    for (size_t i = 0; i < s; i++)\n        fprintf(stderr, \"%02x\", b[i]);\n    fprintf(stderr, \"\\n\");\n}\n"
  },
  {
    "path": "src/tpm2-tss-engine-err.h",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n#ifndef TPM2_TSS_ENGINE_ERR_H\n#define TPM2_TSS_ENGINE_ERR_H\n\n#include \"config.h\"\n\n#include <stdint.h>\n\n#ifndef NDEBUG\n#define DBG(...) fprintf(stderr, __VA_ARGS__)\n#define DBGBUF(...) printbuf(__VA_ARGS__)\nvoid printbuf(const uint8_t *b, size_t s);\n\n#else /* DEBUG */\n#define DBG(...)\n#define DBGBUF(...)\n#endif /* DEBUG */\n\n#define ERR(f,r) ERR_error(TPM2TSS_F_ ## f, r, __FILE__, __LINE__)\n\n/* This macro checks for common TPM error codes which are meaningful to the\n   user */\n#define ERRchktss(f, r, s) do { \\\n    if (r) { \\\n        switch(r) { \\\n        case TSS2_ESYS_RC_MEMORY: \\\n            ERR(f, ERR_R_MALLOC_FAILURE); \\\n            break; \\\n        case 0x000009a2: \\\n            ERR(f, TPM2TSS_R_AUTH_FAILURE); \\\n            break; \\\n        default: \\\n            ERR(f, TPM2TSS_R_UNKNOWN_TPM_ERROR); \\\n        } \\\n        s; \\\n    } \\\n} while (0);\n\nvoid ERR_load_TPM2TSS_strings(void);\nvoid ERR_unload_TPM2TSS_strings(void);\nvoid ERR_error(int function, int reason, const char *file, int line);\n\n/* Function codes */\n/* tpm2-tss-engine.c */\n#define TPM2TSS_F_loadkey          100\n#define TPM2TSS_F_init_engine          101\n#define TPM2TSS_F_get_auth                  102\n#define TPM2TSS_F_engine_ctrl               103\n/* tpm2-tss-engine-common.c */\n#define TPM2TSS_F_tpm2tss_tpm2data_write        110\n#define TPM2TSS_F_tpm2tss_tpm2data_read         111\n#define TPM2TSS_F_tpm2tss_tpm2data_readtpm      112\n#define TPM2TSS_F_init_tpm_parent      113\n#define TPM2TSS_F_init_tpm_key          114\n#define TPM2TSS_F_esys_ctx_init      115\n#define TPM2TSS_F_esys_ctx_free      116\n/* tpm2-tss-engine-ecc.c */\n#define TPM2TSS_F_ecdsa_sign    120\n#define TPM2TSS_F_populate_ecc          121\n#define TPM2TSS_F_tpm2tss_ecc_genkey    122\n#define TPM2TSS_F_tpm2tss_ecc_makekey      123\n#define TPM2TSS_F_ecdh_compute_key      124\n\n/* tpm2-tss-engine-digest-sign.c */\n#define TPM2TSS_F_digest_init   150\n#define TPM2TSS_F_digest_update 151\n#define TPM2TSS_F_digest_finish 152\n#define TPM2TSS_F_digest_sign_init      153\n#define TPM2TSS_F_digest_sign_copy      154\n\n/* tpm2-tss-engine-rand.c */\n#define TPM2TSS_F_rand_bytes    130\n#define TPM2TSS_F_rand_seed     131\n/* tpm2-tss-engine-rsa.c */\n#define TPM2TSS_F_rsa_priv_enc     140\n#define TPM2TSS_F_rsa_priv_dec     141\n#define TPM2TSS_F_tpm2tss_rsa_genkey    142\n#define TPM2TSS_F_populate_rsa          143\n#define TPM2TSS_F_rsa_signctx           144\n\n/* Reason codes */\n#define TPM2TSS_R_TPM2DATA_READ_FAILED  100\n#define TPM2TSS_R_UNKNOWN_ALG           101\n#define TPM2TSS_R_CANNOT_MAKE_KEY       102\n#define TPM2TSS_R_SUBINIT_FAILED        103\n#define TPM2TSS_R_FILE_WRITE            104\n#define TPM2TSS_R_DATA_CORRUPTED        105\n#define TPM2TSS_R_FILE_READ             106\n#define TPM2TSS_R_PADDING_UNKNOWN       107\n#define TPM2TSS_R_PADDING_FAILED        108\n#define TPM2TSS_R_UNKNOWN_TPM_ERROR     109\n#define TPM2TSS_R_DIGEST_TOO_LARGE      110\n#define TPM2TSS_R_GENERAL_FAILURE       111\n#define TPM2TSS_R_UNKNOWN_CURVE         112\n#define TPM2TSS_R_UI_ERROR              113\n#define TPM2TSS_R_UNKNOWN_CTRL          114\n#define TPM2TSS_R_DL_OPEN_FAILED        115\n#define TPM2TSS_R_DL_INVALID            116\n/* TPM/TSS Reasons that are useful to the user */\n#define TPM2TSS_R_AUTH_FAILURE          150\n#define TPM2TSS_R_OWNER_AUTH_FAILED     151\n#define TPM2TSS_R_OLD_TSS               152\n\n#endif /* TPM2_TSS_ENGINE_ERR_H */\n"
  },
  {
    "path": "src/tpm2-tss-engine-rand.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <string.h>\n\n#include <openssl/engine.h>\n#include <openssl/rand.h>\n\n#include <tss2/tss2_mu.h>\n#include <tss2/tss2_esys.h>\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\n/** rand seed\n * @retval 1 on success\n * @retval 0 on failure\n */\nstatic int\nrand_seed(const void *seed, int seed_len)\n{\n    ESYS_CONTEXT *esys_ctx = NULL;\n    TSS2_RC r;\n\n    r = esys_ctx_init(&esys_ctx);\n    ERRchktss(rand_seed, r, goto end);\n\n    TPM2B_SENSITIVE_DATA stir;\n    size_t offset = 0;\n    char *cur_data = (char*)seed;\n\n    static const size_t tpm_random_stir_max_size = 128;\n    while(offset < (size_t)seed_len) {\n        size_t left = seed_len - offset;\n        size_t chunk = left > tpm_random_stir_max_size ? tpm_random_stir_max_size : left;\n\n        stir.size = chunk;\n        memcpy(stir.buffer, cur_data + offset, chunk);\n\n        r = Esys_StirRandom(\n            esys_ctx,\n            ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n            &stir);\n        ERRchktss(rand_seed, r, goto end);\n\n        offset += chunk;\n    }\n\nend:\n    if(esys_ctx)\n        esys_ctx_free(&esys_ctx);\n    return (r == TSS2_RC_SUCCESS)? 1 : 0;\n}\n\n/** Genereate random values\n *\n * Use the TPM to generate a number of random values.\n * @param buf The buffer to write the random values to\n * @param num The amound of random bytes to generate\n * @retval 1 on success\n * @retval 0 on failure\n */\nstatic int\nrand_bytes(unsigned char *buf, int num)\n{\n    ESYS_CONTEXT *esys_ctx = NULL;\n    TSS2_RC r;\n\n    r = esys_ctx_init(&esys_ctx);\n    ERRchktss(rand_bytes, r, goto end);\n\n    TPM2B_DIGEST *b;\n    while (num > 0) {\n        r = Esys_GetRandom(esys_ctx,\n                           ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,\n                           num, &b);\n        ERRchktss(rand_bytes, r, goto end);\n\n        memcpy(buf, &b->buffer, b->size);\n        num -= b->size;\n        buf += b->size;\n        Esys_Free(b);\n    }\n\n    esys_ctx_free(&esys_ctx);\n\n end:\n    return (r == TSS2_RC_SUCCESS);\n}\n\n/** Return the entropy status of the prng\n *\n * Since we provide real (TPM-based) randomness even for the pseudorand\n * function, our status is allways good.\n * @retval 1 allways good status\n */\nstatic int\nrand_status()\n{\n    return 1;\n}\n\nstatic RAND_METHOD rand_methods = {\n    rand_seed,\n    rand_bytes,\n    NULL,                       /* cleanup() */\n    NULL,                       /* add() */\n    rand_bytes,                 /* pseudorand() */\n    rand_status                 /* status() */\n};\n\n/** Initialize the tpm2tss engine's rand submodule\n *\n * Initialize the tpm2tss engine's submodule by setting function pointer.\n * @param e The engine context.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ninit_rand(ENGINE *e)\n{\n    return ENGINE_set_RAND(e, &rand_methods);\n}\n"
  },
  {
    "path": "src/tpm2-tss-engine-rsa.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <string.h>\n\n#include <openssl/engine.h>\n#include <tss2/tss2_esys.h>\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\n#define chkerr_goto(x) if (x) { DBG(\"%s:%i:%s: Error 0x%04x\\n\", __FILE__, \\\n                                       __LINE__, __func__, x); goto error; }\n\nconst RSA_METHOD *default_rsa = NULL;\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\nRSA_METHOD rsa_methods;\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\nRSA_METHOD *rsa_methods = NULL;\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n#ifdef HAVE_OPENSSL_DIGEST_SIGN\nstatic int (*rsa_pkey_orig_copy)(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src);\nstatic void (*rsa_pkey_orig_cleanup)(EVP_PKEY_CTX *ctx);\n#endif /* HAVE_OPENSSL_DIGEST_SIGN */\n\nstatic int (*rsa_orig_finish)(RSA *rsa);\n\nstatic TPM2B_DATA allOutsideInfo = {\n    .size = 0,\n};\n\nstatic TPML_PCR_SELECTION allCreationPCR = {\n    .count = 0,\n};\n\nstatic TPM2B_PUBLIC keyTemplate = {\n    .publicArea = {\n        .type = TPM2_ALG_RSA,\n        .nameAlg = ENGINE_HASH_ALG,\n        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |\n                             TPMA_OBJECT_SIGN_ENCRYPT |\n                             TPMA_OBJECT_DECRYPT |\n                             TPMA_OBJECT_FIXEDTPM |\n                             TPMA_OBJECT_FIXEDPARENT |\n                             TPMA_OBJECT_SENSITIVEDATAORIGIN |\n                             TPMA_OBJECT_NODA),\n        .authPolicy.size = 0,\n        .parameters.rsaDetail = {\n             .symmetric = {\n                 .algorithm = TPM2_ALG_NULL,\n                 .keyBits.aes = 0,\n                 .mode.aes = 0,\n              },\n             .scheme = {\n                .scheme = TPM2_ALG_NULL,\n                .details = {}\n             },\n             .keyBits = 0,          /* to be set by the genkey function */\n             .exponent = 0,         /* to be set by the genkey function */\n         },\n        .unique.rsa.size = 0\n     }\n};\n\n/** Sign data using a TPM key\n *\n * This function performs the encrypt function using the private key in RSA.\n * This operation is usually used to perform signature and authentication\n * operations.\n * @param flen Length of the from buffer.\n * @param from The data to be signed.\n * @param to The buffer to write the signature to.\n * @param rsa The rsa key object.\n * @param padding The padding scheme to be used.\n * @retval 0 on failure\n * @retval size Size of the returned signature\n */\nstatic int\nrsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa,\n             int padding)\n{\n    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);\n\n    /* If this is not a TPM2 key, fall through to software functions */\n    if (tpm2Data == NULL) {\n        DBG(\"Non-TPM key passed. Calling standard function.\\n\");\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n        return default_rsa->rsa_priv_enc(flen, from, to, rsa, padding);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n        return RSA_meth_get_priv_enc(default_rsa)(flen, from, to, rsa, padding);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    }\n\n    DBG(\"rsa_priv_enc called for scheme %i and input data(size=%i):\\n\",\n        padding, flen);\n    DBGBUF(from, flen);\n\n    int ret = 0;\n    TSS2_RC r = TSS2_RC_SUCCESS;\n    ESYS_CONTEXT *esys_ctx = NULL;\n    ESYS_TR keyHandle = ESYS_TR_NONE;\n    TPM2B_DATA label = { .size = 0 };\n    TPM2B_PUBLIC_KEY_RSA *sig = NULL;\n    TPMT_RSA_DECRYPT inScheme = { .scheme = TPM2_ALG_NULL };\n\n    TPM2B_PUBLIC_KEY_RSA digest;\n    digest.size = RSA_size(rsa);\n    if (digest.size > sizeof(digest.buffer)) {\n        ERR(rsa_priv_enc, TPM2TSS_R_DIGEST_TOO_LARGE);\n        goto error;\n    }\n\n    switch (padding) {\n    case RSA_PKCS1_PADDING:\n        ret = RSA_padding_add_PKCS1_type_1(&digest.buffer[0], digest.size,\n                                           from, flen);\n        break;\n    case RSA_X931_PADDING:\n        ret = RSA_padding_add_X931(&digest.buffer[0], digest.size, from, flen);\n        break;\n    case RSA_NO_PADDING:\n        ret = RSA_padding_add_none(&digest.buffer[0], digest.size, from, flen);\n        break;\n    default:\n        ERR(rsa_priv_enc, TPM2TSS_R_PADDING_UNKNOWN);\n        goto error;\n    }\n    if (ret <= 0) {\n        ERR(rsa_priv_enc, TPM2TSS_R_PADDING_FAILED);\n        goto error;\n    }\n\n    DBG(\"Padded digest data (size=%i):\\n\", digest.size);\n    DBGBUF(&digest.buffer[0], digest.size);\n\n    r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);\n    ERRchktss(rsa_priv_enc, r, goto error);\n\n    DBG(\"Signing (via decrypt operation).\\n\");\n    r = Esys_RSA_Decrypt(esys_ctx, keyHandle,\n                         ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                         &digest, &inScheme, &label, &sig);\n    ERRchktss(rsa_priv_enc, r, goto error);\n\n    DBG(\"Signature done (size=%i):\\n\", sig->size);\n    DBGBUF(&sig->buffer[0], sig->size);\n\n    ret = sig->size;\n    if (ret > RSA_size(rsa) || ret <= 0) {\n        ERR(rsa_priv_enc, TPM2TSS_R_DIGEST_TOO_LARGE);\n        goto error;\n    }\n    memcpy(to, &sig->buffer[0], ret);\n\n    goto out;\n\n error:\n    r = -1;\n\n out:\n    Esys_Free(sig);\n    if (keyHandle != ESYS_TR_NONE) {\n        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {\n            Esys_TR_Close(esys_ctx, &keyHandle);\n        } else {\n            Esys_FlushContext(esys_ctx, keyHandle);\n        }\n    }\n    esys_ctx_free(&esys_ctx);\n    return (r == TSS2_RC_SUCCESS) ? ret : 0;\n}\n\n/** Decrypt data using a TPM key\n *\n * This function performs the decrypt function using the private key in RSA.\n * @param flen Length of the from buffer.\n * @param from The data to be decrypted.\n * @param to The buffer to write the plaintext to.\n * @param rsa The rsa key object.\n * @param padding The padding scheme to be used.\n * @retval 0 on failure\n * @retval size Size of the returned plaintext\n */\nstatic int\nrsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA * rsa,\n             int padding)\n{\n    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);\n\n    /* If this is not a TPM2 key, fall through to software functions */\n    if (tpm2Data == NULL)\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n        return default_rsa->rsa_priv_dec(flen, from, to, rsa, padding);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n        return RSA_meth_get_priv_dec(default_rsa)(flen, from, to, rsa, padding);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n    DBG(\"rsa_priv_dec called for scheme %i and input data(size=%i):\\n\",\n        padding, flen);\n    DBGBUF(from, flen);\n\n    TSS2_RC r;\n    ESYS_CONTEXT *esys_ctx = NULL;\n    ESYS_TR keyHandle = ESYS_TR_NONE;\n    TPM2B_DATA label = { .size = 0 };\n    TPM2B_PUBLIC_KEY_RSA *message = NULL;\n    TPMT_RSA_DECRYPT inScheme;\n\n    TPM2B_PUBLIC_KEY_RSA cipher = { .size = flen };\n    if (flen > (int)sizeof(cipher.buffer) || flen < 0) {\n        ERR(rsa_priv_dec, TPM2TSS_R_DIGEST_TOO_LARGE);\n        goto error;\n    }\n    memcpy(&cipher.buffer[0], from, flen);\n\n    switch (padding) {\n    case RSA_PKCS1_PADDING:\n        inScheme.scheme = TPM2_ALG_RSAES;\n        break;\n    case RSA_PKCS1_OAEP_PADDING:\n        inScheme.scheme = TPM2_ALG_OAEP;\n        inScheme.details.oaep.hashAlg = TPM2_ALG_SHA1;\n        break;\n    case RSA_NO_PADDING:\n        inScheme.scheme = TPM2_ALG_NULL;\n        break;\n    default:\n        ERR(rsa_priv_dec, TPM2TSS_R_PADDING_UNKNOWN);\n        goto error;\n    }\n\n    r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);\n    ERRchktss(rsa_priv_dec, r, goto out);\n\n    r = Esys_RSA_Decrypt(esys_ctx, keyHandle,\n                         ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                         &cipher, &inScheme, &label, &message);\n    ERRchktss(rsa_priv_dec, r, goto out);\n\n    DBG(\"Decrypted message (size=%i):\\n\", message->size);\n    DBGBUF(&message->buffer[0], message->size);\n\n    flen = message->size;\n    if (flen > RSA_size(rsa) || flen <= 0) {\n        ERR(rsa_priv_dec, TPM2TSS_R_DIGEST_TOO_LARGE);\n        goto error;\n    }\n    memcpy(to, &message->buffer[0], flen);\n\n    goto out;\n\n error:\n    r = -1;\n\n out:\n    Esys_Free(message);\n    if (keyHandle != ESYS_TR_NONE) {\n        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {\n            Esys_TR_Close(esys_ctx, &keyHandle);\n        } else {\n            Esys_FlushContext(esys_ctx, keyHandle);\n        }\n    }\n\n    esys_ctx_free(&esys_ctx);\n    return (r == TSS2_RC_SUCCESS) ? flen : 0;\n}\n\n/** Clean up the RSA key\n *\n * @param rsa The rsa key object.\n * @retval 1 on success, or 0 on failure\n */\nstatic int\nrsa_finish(RSA *rsa)\n{\n    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);\n\n    if (tpm2Data != NULL) {\n        OPENSSL_free(tpm2Data);\n        RSA_set_app_data(rsa, NULL);\n    }\n    if (rsa_orig_finish) {\n       rsa_orig_finish(rsa);\n    }\n    return 1;\n}\n\n/** Helper to populate the RSA key object.\n *\n * In order to use an RSA key object in a typical manner, all fields of the\n * OpenSSL's corresponding object bust be filled. This function fills the public\n * values correctly and fill the private values with 0.\n * @param rsa The key object to fill.\n * @retval 0 on failure\n * @retval 1 on success\n */\nstatic int\npopulate_rsa(RSA *rsa)\n{\n    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);\n    UINT32 exponent;\n\n    if (tpm2Data == NULL)\n        goto error;\n\n    exponent = tpm2Data->pub.publicArea.parameters.rsaDetail.exponent;\n    if (!exponent)\n        exponent = 0x10001;\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    /* Setting the public portion of the key */\n    rsa->n = BN_bin2bn(tpm2Data->pub.publicArea.unique.rsa.buffer,\n                       tpm2Data->pub.publicArea.unique.rsa.size, rsa->n);\n    if (rsa->n == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    if (rsa->e == NULL)\n        rsa->e = BN_new();\n    if (rsa->e == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->e, exponent);\n\n    /* Setting private portions to 0 values so the public key can be extracted\n       from the keyfile if this is desired. */\n    if (rsa->d == NULL)\n        rsa->d = BN_new();\n    if (rsa->d == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->d, 0);\n    if (rsa->p == NULL)\n        rsa->p = BN_new();\n    if (rsa->p == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->p, 0);\n    if (rsa->q == NULL)\n        rsa->q = BN_new();\n    if (rsa->q == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->q, 0);\n    if (rsa->dmp1 == NULL)\n        rsa->dmp1 = BN_new();\n    if (rsa->dmp1 == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->dmp1, 0);\n    if (rsa->dmq1 == NULL)\n        rsa->dmq1 = BN_new();\n    if (rsa->dmq1 == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->dmq1, 0);\n    if (rsa->iqmp == NULL)\n        rsa->iqmp = BN_new();\n    if (rsa->iqmp == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n    BN_set_word(rsa->iqmp, 0);\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    BIGNUM *n = BN_bin2bn(tpm2Data->pub.publicArea.unique.rsa.buffer,\n                          tpm2Data->pub.publicArea.unique.rsa.size, NULL);\n    BIGNUM *e = BN_new();\n    BIGNUM *d = BN_new();\n    BIGNUM *p = BN_new();\n    BIGNUM *q = BN_new();\n    BIGNUM *dmp1 = BN_new();\n    BIGNUM *dmq1 = BN_new();\n    BIGNUM *iqmp = BN_new();\n\n    if (!n || !e || !d || !p || !q || !dmp1 || !dmq1 || !iqmp) {\n        if (n)\n            BN_free(n);\n        if (e)\n            BN_free(e);\n        if (d)\n            BN_free(d);\n        if (p)\n            BN_free(p);\n        if (q)\n            BN_free(q);\n        if (dmp1)\n            BN_free(dmp1);\n        if (dmq1)\n            BN_free(dmq1);\n        if (iqmp)\n            BN_free(iqmp);\n\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        goto error;\n    }\n\n    BN_set_word(e, exponent);\n    BN_set_word(d, 0);\n    BN_set_word(p, 0);\n    BN_set_word(q, 0);\n    BN_set_word(dmp1, 0);\n    BN_set_word(dmq1, 0);\n    BN_set_word(iqmp, 0);\n\n    RSA_set0_key(rsa, n, e, d);\n    RSA_set0_factors(rsa, p, q);\n    RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n    return 1;\n error:\n    return 0;\n}\n\n/** Helper to load an RSA key from a tpm2Data\n *\n * This function creates a key object given a TPM2_DATA object. The resulting\n * key object can then be used for signing and decrypting with the tpm2tss\n * engine. Ownership of the TPM2_DATA object is taken on success.\n * @param tpm2Data The key data to use. Must have been allocated using\n * OPENSSL_malloc.\n * @retval key The key object\n * @retval NULL on failure.\n */\nEVP_PKEY *\ntpm2tss_rsa_makekey(TPM2_DATA *tpm2Data)\n{\n    EVP_PKEY *pkey;\n    RSA *rsa;\n\n    DBG(\"Creating RSA key object.\\n\");\n\n    /* create the new objects to return */\n    if ((pkey = EVP_PKEY_new()) == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        return NULL;\n    }\n\n    if ((rsa = RSA_new()) == NULL) {\n        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);\n        EVP_PKEY_free(pkey);\n        return NULL;\n    }\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    rsa->meth = &rsa_methods;\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    RSA_set_method(rsa, rsa_methods);\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {\n        ERR(populate_rsa, TPM2TSS_R_GENERAL_FAILURE);\n        RSA_free(rsa);\n        goto error;\n    }\n\n    if (!RSA_set_app_data(rsa, tpm2Data)) {\n        ERR(populate_rsa, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    if (!populate_rsa(rsa)) {\n        RSA_set_app_data(rsa, NULL);\n        goto error;\n    }\n\n    DBG(\"Created RSA key object.\\n\");\n\n    return pkey;\n error:\n    EVP_PKEY_free(pkey);\n    return NULL;\n}\n\n/** Generate a tpm2tss rsa key object.\n *\n * This function creates a new TPM RSA key. The TPM data is stored inside the\n * object*s app data and can be retrieved using RSA_get_app_data().\n * @param rsa The key object for the TPM RSA key to be created.\n * @param bits The key size\n * @param e The key's exponent\n * @param password The Password to be set for the new key\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ntpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password,\n                   TPM2_HANDLE parentHandle)\n{\n    DBG(\"Generating RSA key for %i bits keysize.\\n\", bits);\n\n    TSS2_RC r = TSS2_RC_SUCCESS;\n    ESYS_CONTEXT *esys_ctx = NULL;\n    ESYS_TR parent = ESYS_TR_NONE;\n    TPM2B_PUBLIC *keyPublic = NULL;\n    TPM2B_PRIVATE *keyPrivate = NULL;\n    TPM2_DATA *tpm2Data = NULL;\n    TPM2B_PUBLIC inPublic = keyTemplate;\n    TPM2B_SENSITIVE_CREATE inSensitive = {\n        .sensitive = {\n            .userAuth = {\n                 .size = 0,\n             },\n            .data = {\n                 .size = 0,\n             }\n        }\n    };\n\n    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));\n    if (tpm2Data == NULL) {\n        ERR(tpm2tss_rsa_genkey, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n    memset(tpm2Data, 0, sizeof(*tpm2Data));\n\n    inPublic.publicArea.parameters.rsaDetail.keyBits = bits;\n    if (e)\n        inPublic.publicArea.parameters.rsaDetail.exponent = BN_get_word(e);\n\n    if (password) {\n        DBG(\"Setting a password for the created key.\\n\");\n        if (strlen(password) > sizeof(tpm2Data->userauth.buffer) - 1) {\n            goto error;\n        }\n        tpm2Data->userauth.size = strlen(password);\n        memcpy(&tpm2Data->userauth.buffer[0], password,\n               tpm2Data->userauth.size);\n\n        inSensitive.sensitive.userAuth.size = strlen(password);\n        memcpy(&inSensitive.sensitive.userAuth.buffer[0], password,\n               strlen(password));\n    } else\n        tpm2Data->emptyAuth = 1;\n\n    r = init_tpm_parent(&esys_ctx, parentHandle, &parent);\n    ERRchktss(tpm2tss_rsa_genkey, r, goto error);\n\n    tpm2Data->parent = parentHandle;\n\n    DBG(\"Generating the RSA key inside the TPM.\\n\");\n\n    r = Esys_Create(esys_ctx, parent,\n                    ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                    &inSensitive, &inPublic, &allOutsideInfo, &allCreationPCR,\n                    &keyPrivate, &keyPublic, NULL, NULL, NULL);\n    ERRchktss(tpm2tss_rsa_genkey, r, goto error);\n\n    DBG(\"Generated the RSA key inside the TPM.\\n\");\n\n    tpm2Data->pub = *keyPublic;\n    tpm2Data->priv = *keyPrivate;\n\n    if (!RSA_set_app_data(rsa, tpm2Data)) {\n        ERR(tpm2tss_rsa_genkey, TPM2TSS_R_GENERAL_FAILURE);\n        goto error;\n    }\n\n    if (!populate_rsa(rsa)) {\n        goto error;\n    }\n\n    goto end;\n error:\n    r = -1;\n    if (rsa)\n        RSA_set_app_data(rsa, NULL);\n    if (tpm2Data)\n        OPENSSL_free(tpm2Data);\n\n end:\n    Esys_Free(keyPrivate);\n    Esys_Free(keyPublic);\n\n    if (parent != ESYS_TR_NONE && !parentHandle)\n        Esys_FlushContext(esys_ctx, parent);\n\n    esys_ctx_free(&esys_ctx);\n\n    return (r == TSS2_RC_SUCCESS);\n}\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000\nRSA_METHOD rsa_methods = {\n    \"TPM2TSS RSA methods\",\n    NULL,                       /* tpm_rsa_pub_enc */\n    NULL,                       /* tpm_rsa_pub_dec */\n    rsa_priv_enc,               /* act sign */\n    rsa_priv_dec,               /* act decrypt */\n    NULL,                       /* rsa_mod_exp */\n    NULL,                       /* bn_mod_exp */\n    NULL,                       /* init */\n    NULL,                       /* finish */\n    0,\n    NULL,                       /* app_data */\n    NULL,                       /* sign */\n    NULL,                       /* verify */\n    NULL                        /* genkey */\n};\n#endif                          /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n#ifdef HAVE_OPENSSL_DIGEST_SIGN\nstatic int\nrsa_pkey_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)\n{\n    if (rsa_pkey_orig_copy && !rsa_pkey_orig_copy(dst, src))\n        return 0;\n\n    return digest_sign_copy(dst, src);\n}\n\nstatic void\nrsa_pkey_cleanup(EVP_PKEY_CTX *ctx)\n{\n    digest_sign_cleanup(ctx);\n\n    if (rsa_pkey_orig_cleanup)\n        rsa_pkey_orig_cleanup(ctx);\n}\n\n/* called for digest & sign init, after message digest algorithm set */\nstatic int\nrsa_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)\n{\n    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);\n    RSA *rsa = EVP_PKEY_get0_RSA(pkey);\n    TPM2_DATA *tpm2data = RSA_get_app_data(rsa);\n\n    DBG(\"rsa_digest_custom %p %p\\n\", ctx, mctx);\n\n    return digest_sign_init(ctx, mctx, tpm2data, RSA_size(rsa));\n}\n\nstatic int\nrsa_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,\n            EVP_MD_CTX *mctx)\n{\n    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx);\n    TSS2_RC r = TSS2_RC_SUCCESS;\n    TPMT_TK_HASHCHECK *validation_ptr = NULL;\n    TPM2B_DIGEST *digest_ptr = NULL;\n    TPMT_SIGNATURE *tpm_sig = NULL;\n    int pad_mode;\n\n    DBG(\"rsa_signctx %p %p sig_data %p\\n\", ctx, mctx, sig_data);\n\n    if (!sig) {\n        /* caller just wants to know the size */\n        *siglen = sig_data->sig_size;\n        return 1;\n    }\n\n    if (!sig_data) {\n        /* handle non-TPM key */\n        unsigned char md[EVP_MAX_MD_SIZE];\n        unsigned int md_len = 0;\n\n        if (!EVP_DigestFinal_ex(mctx, md, &md_len))\n            return 0;\n        if (EVP_PKEY_sign(ctx, sig, siglen, md, md_len) <= 0)\n            return 0;\n        return 1;\n    }\n\n    if (EVP_PKEY_CTX_get_rsa_padding(ctx, &pad_mode) <= 0)\n        return 0;\n\n    TPMT_SIG_SCHEME in_scheme = {\n        .scheme = TPM2_ALG_NULL,\n        .details.rsassa.hashAlg = sig_data->hash_alg,\n    };\n    switch (pad_mode) {\n    case RSA_PKCS1_PADDING:\n        in_scheme.scheme = TPM2_ALG_RSASSA;\n        break;\n    case RSA_PKCS1_PSS_PADDING:\n        in_scheme.scheme = TPM2_ALG_RSAPSS;\n        break;\n    default:\n        ERR(rsa_signctx, TPM2TSS_R_PADDING_UNKNOWN);\n        return 0;\n    }\n\n    if (!digest_finish(sig_data, &digest_ptr, &validation_ptr))\n        return 0;\n\n    r = Esys_Sign(sig_data->key->esys_ctx, sig_data->key->key_handle,\n                  ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,\n                  digest_ptr, &in_scheme, validation_ptr, &tpm_sig);\n    ERRchktss(rsa_signctx, r, goto error);\n\n    memcpy(sig, tpm_sig->signature.rsassa.sig.buffer, sig_data->sig_size);\n    *siglen = sig_data->sig_size;\n\n    r = 1;\n    goto out;\n\n error:\n    r = 0;\n out:\n    Esys_Free(tpm_sig);\n    Esys_Free(digest_ptr);\n    Esys_Free(validation_ptr);\n\n    return r;\n}\n#endif /* HAVE_OPENSSL_DIGEST_SIGN */\n\n/** Initialize the tpm2tss engine's rsa submodule\n *\n * Initialize the tpm2tss engine's submodule by setting function pointer.\n * @param e The engine context.\n * @retval 1 on success\n * @retval 0 on failure\n */\nint\ninit_rsa(ENGINE *e)\n{\n#if OPENSSL_VERSION_NUMBER < 0x10100000\n    default_rsa = RSA_PKCS1_SSLeay();\n    if (default_rsa == NULL)\n        return 0;\n\n    rsa_methods.rsa_pub_enc = default_rsa->rsa_pub_enc;\n    rsa_methods.rsa_pub_dec = default_rsa->rsa_pub_dec;\n    rsa_methods.rsa_mod_exp = default_rsa->rsa_mod_exp;\n    rsa_methods.bn_mod_exp = default_rsa->bn_mod_exp;\n\n    if (!ENGINE_set_RSA(e, &rsa_methods))\n        return 0;\n#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n    default_rsa = RSA_PKCS1_OpenSSL();\n    if (default_rsa == NULL)\n        return 0;\n\n    rsa_methods = RSA_meth_dup(default_rsa);\n    RSA_meth_set1_name(rsa_methods, \"TPM2TSS RSA methods\");\n    RSA_meth_set_priv_enc(rsa_methods, rsa_priv_enc);\n    RSA_meth_set_priv_dec(rsa_methods, rsa_priv_dec);\n    rsa_orig_finish = RSA_meth_get_finish(rsa_methods);\n    RSA_meth_set_finish(rsa_methods, rsa_finish);\n\n    if (!ENGINE_set_RSA(e, rsa_methods))\n        return 0;\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */\n\n#if HAVE_OPENSSL_DIGEST_SIGN\n    /* digest and sign support */\n\n    EVP_PKEY_METHOD *pkey_rsa_methods;\n\n    pkey_rsa_methods = EVP_PKEY_meth_new(EVP_PKEY_RSA,\n                                         EVP_PKEY_FLAG_AUTOARGLEN);\n    if (pkey_rsa_methods == NULL)\n        return 0;\n\n    const EVP_PKEY_METHOD *pkey_orig_rsa_methods =\n        EVP_PKEY_meth_find(EVP_PKEY_RSA);\n    if (pkey_orig_rsa_methods == NULL)\n        return 0;\n    EVP_PKEY_meth_copy(pkey_rsa_methods, pkey_orig_rsa_methods);\n    /*\n     * save originals since we only override some of the pkey\n     * functionality, rather than reimplementing all of it\n     */\n    EVP_PKEY_meth_get_copy(pkey_rsa_methods, &rsa_pkey_orig_copy);\n    EVP_PKEY_meth_get_cleanup(pkey_rsa_methods, &rsa_pkey_orig_cleanup);\n\n    EVP_PKEY_meth_set_copy(pkey_rsa_methods, rsa_pkey_copy);\n    EVP_PKEY_meth_set_cleanup(pkey_rsa_methods, rsa_pkey_cleanup);\n    EVP_PKEY_meth_set_signctx(pkey_rsa_methods, NULL, rsa_signctx);\n    EVP_PKEY_meth_set_digest_custom(pkey_rsa_methods, rsa_digest_custom);\n    EVP_PKEY_meth_add0(pkey_rsa_methods);\n#endif /* HAVE_OPENSSL_DIGEST_SIGN */\n\n    return 1;\n}\n"
  },
  {
    "path": "src/tpm2-tss-engine.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n#include \"config.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\n#include <openssl/engine.h>\n#include <openssl/pem.h>\n#include <openssl/ec.h>\n#include <openssl/ecdsa.h>\n\n#include <tss2/tss2_mu.h>\n#include <tss2/tss2_esys.h>\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\n/**\n * The identifier of the engine\n */\nstatic const char *engine_id = \"tpm2tss\";\n\n/**\n * The full name of the engine\n */\nstatic const char *engine_name = \"TPM2-TSS engine for OpenSSL\";\n\nTPM2B_DIGEST ownerauth = { .size = 0 };\nTPM2B_DIGEST parentauth = { .size = 0 };\n\nchar *tcti_nameconf = NULL;\n\n/** Retrieve password\n *\n * Helper function to retreive a password from the user.\n * @param prompt_info [in] The object name to ask the user for\n * @param ui_method [in] The ui method callbacks to be used\n * @param cb_data [in] The callback data for the ui\n * @param auth [out] The user provided password\n * @retval 1 on success\n * @retval 0 on failure\n */\nstatic int\nget_auth(const char *prompt_info, UI_METHOD *ui_method, void *cb_data,\n         TPM2B_AUTH *auth)\n{\n    DBG(\"get_auth called for object %s with ui_method %p\\n\", prompt_info,\n        ui_method);\n    char *ui_prompt = NULL;\n    UI *ui = NULL;\n    if (!ui_method) {\n        ERR(get_auth, TPM2TSS_R_UI_ERROR);\n        goto error;\n    }\n    ui = UI_new_method(ui_method);\n    if (!ui) {\n        ERR(get_auth, TPM2TSS_R_UI_ERROR);\n        goto error;\n    }\n    ui_prompt = UI_construct_prompt(ui, \"password\", prompt_info);\n    if (!ui_prompt) {\n        ERR(get_auth, TPM2TSS_R_UI_ERROR);\n        goto error;\n    }\n    if (0 > UI_add_input_string(ui, ui_prompt, UI_INPUT_FLAG_DEFAULT_PWD,\n                                (char *)&auth->buffer[0], 0,\n                                sizeof(auth->buffer) - 1)) {\n        ERR(get_auth, TPM2TSS_R_UI_ERROR);\n        goto error;\n    }\n    UI_add_user_data(ui, cb_data);\n    if (0 > UI_process(ui)) {\n        ERR(get_auth, TPM2TSS_R_UI_ERROR);\n        goto error;\n    }\n    auth->size = strlen((char *)&auth->buffer[0]);\n    OPENSSL_free(ui_prompt);\n    UI_free(ui);\n\n    DBG(\"password is %s\\n\", (char *)&auth->buffer[0]);\n\n    return 1;\n error:\n    if (ui_prompt)\n        OPENSSL_free(ui_prompt);\n    if (ui)\n        UI_free(ui);\n    return 0;\n}\n\nstatic const ENGINE_CMD_DEFN cmd_defns[] = {\n    { TPM2TSS_SET_OWNERAUTH, \"SET_OWNERAUTH\",\n     \"Set the password for the owner hierarchy (default none)\",\n     ENGINE_CMD_FLAG_STRING },\n    { TPM2TSS_SET_TCTI, \"SET_TCTI\",\n     \"Set the TCTI module and options (default none)\",\n     ENGINE_CMD_FLAG_STRING },\n    { TPM2TSS_SET_PARENTAUTH, \"SET_PARENTAUTH\",\n     \"Set the password for the parent key (default none)\",\n     ENGINE_CMD_FLAG_STRING },\n    {0, NULL, NULL, 0}\n};\n\nstatic int\nengine_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) ())\n{\n    (void)(e);\n    (void)(i);\n    (void)(f);\n    switch (cmd) {\n    case TPM2TSS_SET_OWNERAUTH:\n        if (!p) {\n            DBG(\"Setting owner auth to empty auth.\\n\");\n            ownerauth.size = 0;\n            return 1;\n        }\n        DBG(\"Setting owner auth to password.\\n\");\n        if (strlen((char *)p) > sizeof(ownerauth.buffer) - 1) {\n            return 0;\n        }\n        ownerauth.size = strlen((char *)p);\n        memcpy(&ownerauth.buffer[0], p, ownerauth.size);\n        return 1;\n    case TPM2TSS_SET_TCTI:\n        OPENSSL_free(tcti_nameconf);\n        if (!p) {\n            DBG(\"Setting TCTI to the ESAPI default\\n\");\n        } else {\n            tcti_nameconf = OPENSSL_strdup(p);\n            DBG(\"Setting TCTI option to \\\"%s\\\"\\n\", tcti_nameconf);\n        }\n        return 1;\n    case TPM2TSS_SET_PARENTAUTH:\n        if (!p) {\n            DBG(\"Setting parent auth to empty auth.\\n\");\n            parentauth.size = 0;\n            return 1;\n        }\n        DBG(\"Setting parent auth to password.\\n\");\n        if (strlen((char *)p) > sizeof(parentauth.buffer) - 1) {\n            return 0;\n        }\n        parentauth.size = strlen((char *)p);\n        memcpy(&parentauth.buffer[0], p, parentauth.size);\n        return 1;\n    default:\n        break;\n    }\n    ERR(engine_ctrl, TPM2TSS_R_UNKNOWN_CTRL);\n    return 0;\n}\n\n/** Load a TPM2TSS key\n *\n * This function implements the prototype for loading a key from a file.\n * @param e The engine for this callback (unused).\n * @param key_id The name of the file with the TPM key data.\n * @param ui The ui functions for querying the user.\n * @param cb_data Callback data.\n */\nstatic EVP_PKEY *\nloadkey(ENGINE *e, const char *key_id, UI_METHOD *ui, void *cb_data)\n{\n    (void)(e);\n    (void)(ui);\n    (void)(cb_data);\n\n    TPM2_DATA *tpm2Data = NULL;\n    EVP_PKEY *pkey = NULL;\n\n    DBG(\"Loading private key %s\\n\", key_id);\n    if (strncmp(key_id, \"0x81\", 4) == 0) {\n        uint32_t handle;\n        sscanf(key_id, \"0x%x\", &handle);\n        if (!tpm2tss_tpm2data_readtpm(handle, &tpm2Data)) {\n            ERR(loadkey, TPM2TSS_R_TPM2DATA_READ_FAILED);\n            goto error;\n        }\n    } else {\n        if (!tpm2tss_tpm2data_read(key_id, &tpm2Data)) {\n            ERR(loadkey, TPM2TSS_R_TPM2DATA_READ_FAILED);\n            goto error;\n        }\n    }\n\n    if (tpm2Data->emptyAuth) {\n        tpm2Data->userauth.size = 0;\n    } else {\n        if (!get_auth(\"user key\", ui, cb_data, &tpm2Data->userauth)) {\n            goto error;\n        }\n    }\n\n    DBG(\"Loaded key uses alg-id %x\\n\", tpm2Data->pub.publicArea.type);\n\n    switch (tpm2Data->pub.publicArea.type) {\n    case TPM2_ALG_RSA:\n        pkey = tpm2tss_rsa_makekey(tpm2Data);\n        break;\n    case TPM2_ALG_ECC:\n        pkey = tpm2tss_ecc_makekey(tpm2Data);\n        break;\n    default:\n        ERR(loadkey, TPM2TSS_R_UNKNOWN_ALG);\n        goto error;\n    }\n    if (!pkey) {\n        ERR(loadkey, TPM2TSS_R_CANNOT_MAKE_KEY);\n        goto error;\n    }\n\n    DBG(\"TPM2 Key loaded\\n\");\n\n    return pkey;\nerror:\n    if (tpm2Data)\n        OPENSSL_free(tpm2Data);\n    return NULL;\n}\n\n/** Initialize the tpm2tss engine\n *\n * Initialize the tpm2tss engine by calling each of the submodules' init\n * functions for setting function pointer.\n * @param e The engine context.\n * @retval 1 on success\n * @retval 0 on failure\n */\nstatic int\ninit_engine(ENGINE *e) {\n    static int initialized = 0;\n\n    DBG(\"Initializing\\n\");\n\n    if (initialized) {\n        DBG(\"Already initialized\\n\");\n        return 1;\n    }\n\n    int rc;\n\n#ifdef ENABLE_TCTIENVVAR\n    /*  Set the default TCTI option from the environment */\n    OPENSSL_free(tcti_nameconf);\n    if (getenv(\"TPM2TSSENGINE_TCTI\")) {\n        tcti_nameconf = OPENSSL_strdup(getenv(\"TPM2TSSENGINE_TCTI\"));\n    }\n#endif\n\n    rc = init_rand(e);\n    if (rc != 1) {\n        ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);\n        return rc;\n    }\n\n    rc = init_rsa(e);\n    if (rc != 1) {\n        ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);\n        return rc;\n    }\n\n    rc = init_ecc(e);\n    if (rc != 1) {\n        ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);\n        return rc;\n    }\n\n    initialized = 1;\n    return 1;\n}\n\n/** Destroys the engine context\n *\n * Unloads the strings of the tpm2tss engine.\n * @param e The engine context (unused).\n * @retval 1 for success\n */\nstatic int\ndestroy_engine(ENGINE *e)\n{\n    (void)(e);\n    OPENSSL_free(tcti_nameconf);\n    ERR_unload_TPM2TSS_strings();\n    return 1;\n}\n\n/** OpenSSL's method to bind an engine.\n *\n * This initializes the name, id and function pointers of the engine.\n * @param e The TPM engine to initialize\n * @param id The identifier of the engine\n * @retval 0 if binding failed\n * @retval 1 on success\n */\nstatic int\nbind(ENGINE *e, const char *id)\n{\n    (void)(id);\n\n    if (!ENGINE_set_id(e, engine_id)) {\n        DBG(\"ENGINE_set_id failed\\n\");\n        goto end;\n    }\n    if (!ENGINE_set_name(e, engine_name)) {\n        DBG(\"ENGINE_set_name failed\\n\");\n        goto end;\n    }\n\n    /* The init function is not allways called so we initialize crypto methods\n       directly from bind. */\n    if (!init_engine(e)) {\n        DBG(\"tpm2tss enigne initialization failed\\n\");\n        goto end;\n    }\n\n    if (!ENGINE_set_load_privkey_function(e, loadkey)) {\n        DBG(\"ENGINE_set_load_privkey_function failed\\n\");\n        goto end;\n    }\n\n    if (!ENGINE_set_destroy_function(e, destroy_engine)) {\n        DBG(\"ENGINE_set_destroy_function failed\\n\");\n        goto end;\n    }\n\n    if (!ENGINE_set_ctrl_function(e, engine_ctrl)) {\n        DBG(\"ENGINE_set_ctrl_function failed\\n\");\n        goto end;\n    }\n\n    if (!ENGINE_set_cmd_defns(e, cmd_defns)) {\n        DBG(\"ENGINE_set_cmd_defns failed\\n\");\n        goto end;\n    }\n\n    ERR_load_TPM2TSS_strings();\n    return 1;\n end:\n    return 0;\n}\n\nIMPLEMENT_DYNAMIC_BIND_FN(bind)\nIMPLEMENT_DYNAMIC_CHECK_FN()\n"
  },
  {
    "path": "src/tpm2tss-genkey.c",
    "content": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of tpm2-tss-engine nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF\n * THE POSSIBILITY OF SUCH DAMAGE.\n ******************************************************************************/\n\n#include <string.h>\n#include <strings.h>\n#include <inttypes.h>\n#include <unistd.h>\n#include <getopt.h>\n\n#include <openssl/conf.h>\n#include <openssl/engine.h>\n#include <openssl/pem.h>\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\n/* This tool uses a different error reporting scheme than the lib. */\n#undef ERR\n#define VERB(...) if (opt.verbose) fprintf(stderr, __VA_ARGS__)\n#define ERR(...) fprintf(stderr, __VA_ARGS__)\n\nchar *help =\n    \"Usage: [options] <filename>\\n\"\n    \"Arguments:\\n\"\n    \"    <filename>      storage for the encrypted private key\\n\"\n    \"Options:\\n\"\n    \"    -a, --alg       public key algorithm (rsa, ecdsa) (default: rsa)\\n\"\n    \"    -c, --curve     curve for ecc (default: nist_p256)\\n\"\n    \"    -e, --exponent  exponent for rsa (default: 65537)\\n\"\n    \"    -h, --help      print help\\n\"\n    \"    -u, --public    import a key and read its public portion from this file\\n\"\n    \"    -r, --private   import the sensitive key portion from this file\\n\"\n    \"    -o, --ownerpw   password for the owner hierarchy (default: none)\\n\"\n    \"    -p, --password  password for the created key (default: none)\\n\"\n    \"    -P, --parent    specific handle for the parent key (default: none)\\n\"\n    \"    -s, --keysize   key size in bits for rsa (default: 2048)\\n\"\n    \"    -v, --verbose   print verbose messages\\n\"\n    \"    -W, --parentpw  password for the parent key (default: none)\\n\"\n    \"    -t, --tcti      tcti configuration string (default: none)\\n\"\n    \"\\n\";\n\nstatic const char *optstr = \"a:c:e:hu:r:o:p:P:s:vW:t:\";\n\nstatic const struct option long_options[] = {\n    {\"alg\",      required_argument, 0, 'a'},\n    {\"curve\",    required_argument, 0, 'c'},\n    {\"exponent\", required_argument, 0, 'e'},\n    {\"help\",     no_argument,       0, 'h'},\n    {\"public\",   required_argument, 0, 'u'},\n    {\"private\",  required_argument, 0, 'r'},\n    {\"ownerpw\",  required_argument, 0, 'o'},\n    {\"password\", required_argument, 0, 'p'},\n    {\"parent\",   required_argument, 0, 'P'},\n    {\"keysize\",  required_argument, 0, 's'},\n    {\"verbose\",  no_argument,       0, 'v'},\n    {\"parentpw\", required_argument, 0, 'W'},\n    {\"tcti\",     required_argument, 0, 't'},\n    {0,          0,                 0,  0 }\n};\n\nstatic struct opt {\n    char *filename;\n    TPMI_ALG_PUBLIC alg;\n    TPMI_ECC_CURVE curve;\n    int exponent;\n    char *importpub;\n    char *importtpm;\n    char *ownerpw;\n    char *password;\n    TPM2_HANDLE parent;\n    char *parentpw;\n    int keysize;\n    int verbose;\n    char *tcti_conf;\n} opt;\n\n/** Parse and set command line options.\n *\n * This function parses the command line options and sets the appropriate values\n * in the opt struct.\n * @param argc The argument count.\n * @param argv The arguments.\n * @retval 0 on success\n * @retval 1 on failure\n */\nint\nparse_opts(int argc, char **argv)\n{\n    /* set the default values */\n    opt.filename = NULL;\n    opt.alg = TPM2_ALG_RSA;\n    opt.curve = TPM2_ECC_NIST_P256;\n    opt.exponent = 65537;\n    opt.importpub = NULL;\n    opt.importtpm = NULL;\n    opt.ownerpw = NULL;\n    opt.password = NULL;\n    opt.parent = 0;\n    opt.parentpw = NULL;\n    opt.keysize = 2048;\n    opt.verbose = 0;\n    opt.tcti_conf = NULL;\n\n    /* parse the options */\n    int c;\n    int opt_idx = 0;\n    while (-1 != (c = getopt_long(argc, argv, optstr,\n                                  long_options, &opt_idx))) {\n        switch(c) {\n        case 'h':\n            printf(\"%s\", help);\n            exit(0);\n        case 'v':\n            opt.verbose = 1;\n            break;\n        case 'a':\n            if (strcasecmp(optarg, \"rsa\") == 0) {\n                opt.alg = TPM2_ALG_RSA;\n                break;\n            } else if (strcasecmp(optarg, \"ecdsa\") == 0) {\n                opt.alg = TPM2_ALG_ECDSA;\n                break;\n            } else {\n                ERR(\"Unknown algorithm.\\n\");\n                exit(1);\n            }\n        case 'c':\n            if (strcasecmp(optarg, \"nist_p256\") == 0) {\n                opt.curve = TPM2_ECC_NIST_P256;\n                break;\n            } else if (strcasecmp(optarg, \"nist_p384\") == 0) {\n                opt.curve = TPM2_ECC_NIST_P384;\n                break;\n            } else {\n                ERR(\"Unknown curve.\\n\");\n                exit(1);\n            }\n        case 'e':\n            if (sscanf(optarg, \"%i\", &opt.exponent) != 1) {\n                ERR(\"Error parsing keysize.\\n\");\n                exit(1);\n            }\n            break;\n        case 'u':\n            opt.importpub = optarg;\n            break;\n        case 'r':\n            opt.importtpm = optarg;\n            break;\n        case 'o':\n            opt.ownerpw = optarg;\n            break;\n        case 'p':\n            opt.password = optarg;\n            break;\n        case 'P':\n            if (sscanf(optarg, \"%x\", &opt.parent) != 1 &&\n                sscanf(optarg, \"0x%x\", &opt.parent) != 1 &&\n                sscanf(optarg, \"%i\", &opt.parent) != 1) {\n                ERR(\"Error parsing parent handle\");\n                exit(1);\n            }\n            break;\n        case 'W':\n            opt.parentpw = optarg;\n            break;\n        case 's':\n            if (sscanf(optarg, \"%i\", &opt.keysize) != 1) {\n                ERR(\"Error parsing keysize.\\n\");\n                exit(1);\n            }\n            break;\n        case 't':\n            opt.tcti_conf = optarg;\n            break;\n        default:\n            ERR(\"Unknown option at index %i.\\n\\n\", opt_idx);\n            ERR(\"%s\", help);\n            exit(1);\n        }\n    }\n\n    /* parse the non-option arguments */\n    if (optind >= argc) {\n        ERR(\"Missing argument <filename>.\\n\\n\");\n        ERR(\"%s\", help);\n        exit(1);\n    }\n    opt.filename = argv[optind];\n    optind++;\n\n    if (optind < argc) {\n        ERR(\"Unknown argument provided.\\n\\n\");\n        ERR(\"%s\", help);\n        exit(1);\n    }\n\n    if (!!opt.importpub != !!opt.importtpm) {\n        ERR(\"Import requires both --public and --private\\n\");\n        return 1;\n    }\n\n    return 0;\n}\n\n/** Generate an RSA key\n *\n * This function calls out to generate an RSA key using the TPM.\n * @retval TPM2_DATA data to be written to disk\n * @retval NULL on failure\n */\nstatic TPM2_DATA *\ngenkey_rsa()\n{\n    VERB(\"Generating RSA key using TPM\\n\");\n\n    RSA *rsa = NULL;\n    BIGNUM *e = BN_new();\n    if (!e) {\n        ERR(\"out of memory\\n\");\n        return NULL;\n    }\n    BN_set_word(e, opt.exponent);\n\n    rsa = RSA_new();\n    if (!rsa) {\n        ERR(\"out of memory\\n\");\n        BN_free(e);\n        return NULL;\n    }\n    if (!tpm2tss_rsa_genkey(rsa, opt.keysize, e, opt.password, opt.parent)) {\n        BN_free(e);\n        RSA_free(rsa);\n        ERR(\"Error: Generating key failed\\n\");\n        return NULL;\n    }\n\n    VERB(\"Key generated\\n\");\n\n    TPM2_DATA *tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));\n    if (tpm2Data == NULL) {\n        ERR(\"out of memory\\n\");\n        BN_free(e);\n        RSA_free(rsa);\n        return NULL;\n    }\n    memcpy(tpm2Data, RSA_get_app_data(rsa), sizeof(*tpm2Data));\n\n    BN_free(e);\n    RSA_free(rsa);\n\n    return tpm2Data;\n}\n\n/** Generate an ECDSA key\n *\n * This function calls out to generate an ECDSA key using the TPM.\n * @retval TPM2_DATA data to be written to disk\n * @retval NULL on failure\n */\nstatic TPM2_DATA *\ngenkey_ecdsa()\n{\n    EC_KEY *eckey = NULL;\n\n    eckey = EC_KEY_new();\n    if (!eckey) {\n        ERR(\"out of memory\\n\");\n        return NULL;\n    }\n    if (!tpm2tss_ecc_genkey(eckey, opt.curve, opt.password, opt.parent)) {\n        EC_KEY_free(eckey);\n        ERR(\"Error: Generating key failed\\n\");\n        return NULL;\n    }\n\n    TPM2_DATA *tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));\n    if (tpm2Data == NULL) {\n        ERR(\"out of memory\\n\");\n        EC_KEY_free(eckey);\n        return NULL;\n    }\n    memcpy(tpm2Data, tpm2tss_ecc_getappdata(eckey), sizeof(*tpm2Data));\n\n    EC_KEY_free(eckey);\n\n    return tpm2Data;\n}\n\n/** Main function\n *\n * This function initializes OpenSSL and then calls the key generation\n * functions.\n * @param argc The argument count.\n * @param argv The arguments.\n * @retval 0 on success\n * @retval 1 on failure\n */\nint\nmain(int argc, char **argv)\n{\n    if (parse_opts(argc, argv) != 0)\n        exit(1);\n\n    int r;\n    TPM2_DATA *tpm2Data = NULL;\n\n#if OPENSSL_VERSION_NUMBER < 0x1010000fL\n    OPENSSL_config(NULL);\n#else\n    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);\n#endif\n\n    /* Initialize the tpm2-tss engine */\n    ENGINE_load_dynamic();\n\n    /* Openssl 1.1.0 requires the lib-prefix for the engine_id */\n    ENGINE *tpm_engine = ENGINE_by_id(\"tpm2tss\");\n    if (!tpm_engine)\n        tpm_engine = ENGINE_by_id(\"libtpm2tss\");\n    if (tpm_engine == NULL) {\n        ERR(\"Could not load tpm2tss engine\\n\");\n        return 1;\n    }\n\n    int init_res = ENGINE_init(tpm_engine);\n    VERB(\"Engine name: %s\\nInit result: %d \\n\", ENGINE_get_name(tpm_engine),\n         init_res);\n    if (!init_res)\n        return 1;\n\n    if (opt.ownerpw &&\n            !ENGINE_ctrl(tpm_engine, TPM2TSS_SET_OWNERAUTH, 0, opt.ownerpw, NULL)) {\n        ERR(\"Could not set ownerauth\\n\");\n        return 1;\n    }\n\n    if (opt.parentpw &&\n            !ENGINE_ctrl(tpm_engine, TPM2TSS_SET_PARENTAUTH, 0, opt.parentpw, NULL)) {\n        ERR(\"Could not set parentauth\\n\");\n        return 1;\n    }\n\n    if (opt.tcti_conf &&\n            !ENGINE_ctrl(tpm_engine, TPM2TSS_SET_TCTI, 0, opt.tcti_conf, NULL)) {\n        ERR(\"Could not set parentauth\\n\");\n        return 1;\n    }\n\n    if (opt.importpub && opt.importtpm) {\n        VERB(\"Importing the TPM key\\n\");\n        r = tpm2tss_tpm2data_importtpm(opt.importpub, opt.importtpm, opt.parent,\n                                       opt.password == NULL, &tpm2Data);\n        if (r != 1)\n            return 1;\n    } else switch (opt.alg) {\n    case TPM2_ALG_RSA:\n        VERB(\"Generating the rsa key\\n\");\n        tpm2Data = genkey_rsa();\n        break;\n    case TPM2_ALG_ECDSA:\n        VERB(\"Generating the ecdsa key\\n\");\n        tpm2Data = genkey_ecdsa();\n        break;\n    default:\n        break;\n    }\n\n    if (tpm2Data == NULL) {\n        ERR(\"Key could not be generated.\\n\");\n        return 1;\n    }\n\n    /* Write the key to disk */\n    VERB(\"Writing key to disk\\n\");\n\n    if (!tpm2tss_tpm2data_write(tpm2Data, opt.filename)) {\n        ERR(\"Error writing file\\n\");\n        OPENSSL_free(tpm2Data);\n        return 1;\n    }\n\n    OPENSSL_free(tpm2Data);\n\n    VERB(\"*** SUCCESS ***\\n\");\n    return 0;\n}\n"
  },
  {
    "path": "test/ecdh.sh",
    "content": "#!/bin/bash\n\nset -euf\n\n# Create a primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\ntpm2_createprimary --hierarchy=o \\\n                   --key-algorithm=ecc \\\n                   --hash-algorithm=sha256 \\\n                   --key-context=${PARENT_CTX}\n\n# Create an ECDH key pair\necho \"Generating ECDH key pair\"\nECDH_TPM_PUBKEY=ecdhtpm.pub\nECDH_TPM_KEY=ecdhtpm\ntpm2_create --key-auth=abc \\\n            --parent-context=${PARENT_CTX} \\\n            --key-algorithm=ecc256:ecdh-sha256 \\\n            --public=${ECDH_TPM_PUBKEY} \\\n            --private=${ECDH_TPM_KEY} \\\n            --attributes fixedparent\\|fixedtpm\\|decrypt\\|sensitivedataorigin\\|userwithauth\\|noda\ntpm2_flushcontext --transient-object\n\n# Load key to persistent handle\nECDH_CTX=ecdhkey.ctx\ntpm2_load --parent-context=${PARENT_CTX} \\\n          --public=${ECDH_TPM_PUBKEY} \\\n          --private=${ECDH_TPM_KEY} \\\n          --key-context=${ECDH_CTX}\ntpm2_flushcontext --transient-object\n\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${ECDH_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Get public key of handle\nECDH_TPM_PUBKEY_PEM=ecdhtpm.pem\ntpm2_readpublic --object-context=${HANDLE} --output=${ECDH_TPM_PUBKEY_PEM} --format=pem\n\n# Generate peer key pair\nECDH_PEER_PUBKEY=echdpeer.pub\nECDH_PEER_KEY=ecdhpeer\nopenssl ecparam -name prime256v1 -genkey -noout -out ${ECDH_PEER_KEY}\nopenssl ec -in ${ECDH_PEER_KEY} -pubout -out ${ECDH_PEER_PUBKEY}\n\n# Perform ECDH using the TPM key pair as the private key and the peer key pair as the public key\nSECRET0=$(echo \"abc\" | openssl pkeyutl -derive -engine tpm2tss -keyform engine -inkey ${HANDLE} -peerkey ${ECDH_PEER_PUBKEY} -peerform pem -passin stdin | base64)\necho -e \"TPM(prv) <-> PEER(pub): ${SECRET0}\"\n\n# Perform ECDH with the peer key pair as the private key and the TPM key pair as the public key\nSECRET1=$(openssl pkeyutl -derive -inkey ${ECDH_PEER_KEY} -peerkey ${ECDH_TPM_PUBKEY_PEM} -peerform pem | base64)\necho -e \"TPM(pub) <-> PEER(prv): ${SECRET1}\"\n\n# Release persistent HANDLE and remove files\ntpm2_evictcontrol --object-context=${HANDLE}\nrm ${ECDH_PEER_KEY} ${ECDH_PEER_PUBKEY} ${ECDH_TPM_PUBKEY} ${ECDH_TPM_KEY} ${ECDH_TPM_PUBKEY_PEM} ${ECDH_CTX}\n\n# Ensure tpm and peer generated secrets are the same\nif [ \"${SECRET0}\" != \"${SECRET1}\" ]; then\n    echo \"secrets don't match\"\n    exit 1\nfi\n"
  },
  {
    "path": "test/ecdsa-emptyauth.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a ecdsa -c nist_p256 mykey\n\nopenssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -sign -in mydata -out mysig\n\nR=\"$(openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -verify -in mydata -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/ecdsa-handle-flush.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create a Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=ecc \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\n\n# Create an ECDSA key pair\necho \"Generating ECDSA key pair\"\nTPM_ECDSA_PUBKEY=ecdsakey.pub\nTPM_ECDSA_KEY=ecdsakey\ntpm2_create --key-auth=abc \\\n            --parent-context=${PARENT_CTX} \\\n            --hash-algorithm=sha256 --key-algorithm=ecc \\\n            --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \\\n            --attributes=sign\\|decrypt\\|fixedtpm\\|fixedparent\\|sensitivedataorigin\\|userwithauth\\|noda\ntpm2_flushcontext --transient-object\n\n# Load Key to persistent handle\nECDSA_CTX=ecdsakey.ctx\ntpm2_load --parent-context=${PARENT_CTX} \\\n          --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \\\n          --key-context=${ECDSA_CTX}\ntpm2_flushcontext --transient-object\n\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${ECDSA_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Signing Data\nR=\"$(echo \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin stdin 2>&1 || true)\"\nif echo $R | grep \"ErrorCode (0x000001c4)\" > /dev/null; then\n    echo $R\n    exit 1\nfi\n# Get public key of handle\ntpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\nR=\"$(openssl pkeyutl -pubin -inkey mykey.pem -verify -in mydata.txt -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/ecdsa-restricted.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\n# Generate 2k + a bit of data\ndd if=/dev/zero of=mydata.txt count=4 bs=512 status=none\necho -n \"abcde12345abcde12345\">>mydata.txt\n\n# Create a Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=ecc \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\n\n# Create an ECDSA key pair\necho \"Generating ECDSA key pair\"\nTPM_ECDSA_PUBKEY=ecdsakey.pub\nTPM_ECDSA_KEY=ecdsakey\ntpm2_create --parent-context=${PARENT_CTX} \\\n            --hash-algorithm=sha256 --key-algorithm=ecc256:ecdsa-sha256:null \\\n            --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \\\n            --attributes=sign\\|restricted\\|fixedtpm\\|fixedparent\\|sensitivedataorigin\\|userwithauth\\|noda\ntpm2_flushcontext --transient-object\n\n# Load Key to persistent handle\nECDSA_CTX=ecdsakey.ctx\ntpm2_load --parent-context=${PARENT_CTX} \\\n          --public=${TPM_ECDSA_PUBKEY} --private=${TPM_ECDSA_KEY} \\\n          --key-context=${ECDSA_CTX}\ntpm2_flushcontext --transient-object\n\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${ECDSA_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\ntpm2_readpublic --object-context=${HANDLE}\n\n# Digest & sign Data\nopenssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt\n\n# Get public key of handle\ntpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\nR=\"$(openssl dgst -verify mykey.pem -sha256 -signature mysig mydata.txt || true)\"\nif ! echo $R | grep \"Verified OK\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/ecdsa.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a ecdsa -c nist_p256 -p abc mykey\n\necho \"abc\" | openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -sign -in mydata -out mysig -passin stdin\n\nR=\"$(echo \"abc\" | openssl pkeyutl -keyform engine -engine tpm2tss -inkey mykey -verify -in mydata -sigfile mysig -passin stdin || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/error_tpm2-tss-engine-common.c",
    "content": "/* SPDX-License-Identifier: BSD-2 */\n/*******************************************************************************\n * Copyright 2019, Fraunhofer SIT sponsored by Infineon Technologies AG\n * All rights reserved.\n ******************************************************************************/\n\n#include \"tpm2-tss-engine.h\"\n#include \"tpm2-tss-engine-common.h\"\n\n#ifdef HAVE_EXECINFO\n#include <execinfo.h>\n#endif\n#include <stdio.h>\n#include <unistd.h>\n#include <setjmp.h>\n#include <cmocka.h>\n\nTSS2_RC\n__wrap_Esys_Initialize()\n{\n    printf(\"Esys_Initialize called\\n\");\n#ifdef HAVE_EXECINFO\n    void* b[128];\n    backtrace_symbols_fd(b, backtrace(b, sizeof(b)/sizeof(b[0])), STDOUT_FILENO);\n#endif\n    return -1;\n}\n    \nvoid\ncheck_tpm2tss_tpm2data_readtpm(void **state)\n{\n    (void)(state);\n    int i;\n    i = tpm2tss_tpm2data_readtpm(0, NULL);\n    assert_int_equal(i, 0);\n}\n\nvoid\ncheck_tpm2tss_tpm2data_read(void **state)\n{\n    (void)(state);\n    int i;\n    i = tpm2tss_tpm2data_read(\"\", NULL);\n    assert_int_equal(i, 0);\n}\n\nvoid\ncheck_init_tpm_parent_via_api(void **state)\n{\n    (void)(state);\n    int i;\n    i = tpm2tss_rsa_genkey(NULL, 0, NULL, NULL, 0); \n    assert_int_equal(i, 0);\n}\n\nvoid\ncheck_init_tpm_parent(void **state)\n{\n    (void)(state);\n    TSS2_RC r;\n    ESYS_CONTEXT *e;\n    ESYS_TR t;\n    r = init_tpm_parent(&e, -1, &t);\n    assert_int_not_equal(r, TSS2_RC_SUCCESS);\n}\n\nvoid\ncheck_init_tpm_key(void **state)\n{\n    (void)(state);\n    int i;\n    TSS2_RC r;\n    i = tpm2tss_rsa_genkey(NULL, 0, NULL, NULL, 0); \n    assert_int_equal(i, 0);\n\n    ESYS_CONTEXT *e;\n    ESYS_TR t;\n    TPM2_DATA td = { .privatetype = KEY_TYPE_HANDLE };\n    r = init_tpm_key(&e, &t, &td);\n    assert_int_not_equal(r, TSS2_RC_SUCCESS);\n    //assert_int_equal(1, 0);\n}\n\nint\nmain(void)\n{\n    const struct CMUnitTest tests[] = {\n        cmocka_unit_test(check_tpm2tss_tpm2data_readtpm),\n        cmocka_unit_test(check_tpm2tss_tpm2data_read),\n        cmocka_unit_test(check_init_tpm_parent_via_api),\n        cmocka_unit_test(check_init_tpm_parent),\n        cmocka_unit_test(check_init_tpm_key),\n    };\n\n    return cmocka_run_group_tests(tests, NULL, NULL);\n}\n"
  },
  {
    "path": "test/failload.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mykey\nchmod ugo-rwx mykey\n\nR=\"$(openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub 2>&1 || true)\"\necho $R\nif ! echo $R | grep \"unable to load Private Key\" >/dev/null; then\n    exit 1\nfi\n"
  },
  {
    "path": "test/failwrite.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\nR=\"$(tpm2tss-genkey -a ecdsa -c nist_p256 -p abc /no/such/file/path 2>&1 || true)\"\necho $R\nif ! echo $R | grep \"Error writing file\" >/dev/null; then\n    exit 1\nfi\n"
  },
  {
    "path": "test/neg-handle.pem",
    "content": "-----BEGIN TSS2 PRIVATE KEY-----\nMIIB8gYGZ4EFCgEDoAMBAQECBIEAAAEEggEYARYAAQALAAYEcgAAABAAEAgAAAEA\nAQEAyJBHMXSEunTQBWTX2uot2qnvMBEJbhuM4+/bv7Ltaz2zjFdxdSB5tLp4fJZQ\nAoUggU3HmF8sOGYfHTFJeNZJRFqXdB9sotNWLrWUeMXrAxdDJitGli5n87YrCTDu\n6/DbJYbw1sd4/QL0sqXgzLogU7VPJhc+el5DjjimEeN6oU99zfN1HZacPTs74h0Q\nLPrL3BACc/lkg1q6ePREulRI/Atcy5g5hgApfjSB6kMrbOwzzkGiZVZpZBqfPaik\nk0SjQqNZFYejfDt99PgKQHyPHfuEVrjS788jQKvRWoPTYUQCI6iJDcp5JLk0RbqV\ngD68RWwhQVDCmUpq5ebP/f/47wSBwAC+ACDN2bcOjh1KxxE8YlJXVdmuwBiUL3mF\nhLLNWV3HWHnoAAAQ3OnaC4u9p1bOSyUPcw7fUR4UTNbqD2cSwPPMNRslR5RhoNBP\n+j6M2vlKP7UeSxZ/at8CZHtKWV+VS+Osy9Dn+wHdqa1YSvRCBgP1a75OI9jjQ+li\nI64327Vq1ZEl0LIyWdCCWrISRMcVT7JPmGhtuAS4KdHztl58JV9mntQPclW3Rp4o\n5M/74zf2eaTxZOBV+OxhPR77SSQQ+w==\n-----END TSS2 PRIVATE KEY-----\n"
  },
  {
    "path": "test/rand.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\nopenssl rand -engine tpm2tss -hex 10 >/dev/null\n"
  },
  {
    "path": "test/rsadecrypt.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a rsa -s 2048 -p abc mykey\n\necho \"abc\" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin\n\nopenssl pkeyutl -pubin -inkey mykey.pub -encrypt -in mydata -out mycipher\nrm mydata\n\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata -passin stdin\n#this is a workaround because -decrypt sometimes exits 0 falsely\ntest \"x$(cat mydata)\" = \"xabcde12345abcde12345\"\n"
  },
  {
    "path": "test/rsasign.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a rsa -s 2048 -p abc mykey\n\necho \"abc\" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin\n\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig -passin stdin\n\n#this is a workaround because -verify allways exits 1\nR=\"$(openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_importtpm.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\nDIR=$(mktemp -d)\nTPM_RSA_PUBKEY=${DIR}/rsakey.pub\nTPM_RSA_KEY=${DIR}/rsakey\nPARENT_CTX=${DIR}/primary_owner_key.ctx\n\necho -n \"abcde12345abcde12345\">${DIR}/mydata\n\ntpm2_startup -c || true\n\n# Create primary key as persistent handle\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=ecc \\\n                   --key-context=${PARENT_CTX} \\\n                   --attributes=\"decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda|restricted\"\ntpm2_flushcontext --transient-object\n\n# Create an RSA key pair\necho \"Generating RSA key pair\"\ntpm2_create --key-auth=abc --parent-context=${PARENT_CTX} \\\n            --hash-algorithm=sha256 --key-algorithm=rsa \\\n            --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n            --attributes=\"sign|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda\"\ntpm2_flushcontext --transient-object\n\ntpm2tss-genkey --public ${TPM_RSA_PUBKEY} --private ${TPM_RSA_KEY} --password abc ${DIR}/mykey\n\necho \"abc\" | openssl rsa -engine tpm2tss -inform engine -in ${DIR}/mykey -pubout -outform pem -out ${DIR}/mykey.pub -passin stdin\n\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${DIR}/mykey -sign -in ${DIR}/mydata -out ${DIR}/mysig -passin stdin\n\n#this is a workaround because -verify allways exits 1\nR=\"$(openssl pkeyutl -pubin -inkey ${DIR}/mykey.pub -verify -in ${DIR}/mydata -sigfile ${DIR}/mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_importtpmparent.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\nDIR=$(mktemp -d)\nTPM_RSA_PUBKEY=${DIR}/rsakey.pub\nTPM_RSA_KEY=${DIR}/rsakey\nPARENT_CTX=${DIR}/primary_owner_key.ctx\n\necho -n \"abcde12345abcde12345\">${DIR}/mydata\n\ntpm2_startup -c || true\n\n# Create primary key as persistent handle\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${PARENT_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Create an RSA key pair\necho \"Generating RSA key pair\"\ntpm2_create --key-auth=abc --parent-context=${HANDLE} \\\n            --hash-algorithm=sha256 --key-algorithm=rsa \\\n            --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n            --attributes=\"sign|decrypt|fixedtpm|fixedparent|sensitivedataorigin|userwithauth|noda\"\ntpm2_flushcontext --transient-object\n\ntpm2tss-genkey --public ${TPM_RSA_PUBKEY} --private ${TPM_RSA_KEY} --password abc --parent ${HANDLE} ${DIR}/mykey\n\necho \"abc\" | openssl rsa -engine tpm2tss -inform engine -in ${DIR}/mykey -pubout -outform pem -out ${DIR}/mykey.pub -passin stdin\n\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${DIR}/mykey -sign -in ${DIR}/mydata -out ${DIR}/mysig -passin stdin\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\n#this is a workaround because -verify allways exits 1\nR=\"$(openssl pkeyutl -pubin -inkey ${DIR}/mykey.pub -verify -in ${DIR}/mydata -sigfile ${DIR}/mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_parent.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\n\n# Load primary key to persistent handle\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${PARENT_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Generating a key underneath the persistent parent\ntpm2tss-genkey -a rsa -s 2048 -p abc -P ${HANDLE} mykey\n\necho \"abc\" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin\ncat mykey.pub\n\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata.txt -out mysig -passin stdin\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\n#this is a workaround because -verify allways exits 1\nR=\"$(openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata.txt -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_parent_pass.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \\\n                   --key-context=${PARENT_CTX} --key-auth=abc\ntpm2_flushcontext --transient-object\n\n# Load primary key to persistent handle\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${PARENT_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Generating a key underneath the persistent, password protected, parent\ntpm2tss-genkey -a rsa -s 2048 -p abc -P ${HANDLE} -W abc mykey\n\ncat > engine.conf <<EOF\n    openssl_conf = openssl_init\n\n    [openssl_init]\n    engines = engine_section\n\n    [engine_section]\n    tpm2tss = tpm2tss_section\n\n    [tpm2tss_section]\n    SET_PARENTAUTH = abc\nEOF\n\nexport OPENSSL_CONF=engine.conf\n\necho \"abc\" | openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub -passin stdin\ncat mykey.pub\n\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata.txt -out mysig -passin stdin\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\n#this is a workaround because -verify allways exits 1\nR=\"$(openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata.txt -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_persistent.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\n\n# Create an RSA key pair\necho \"Generating RSA key pair\"\nTPM_RSA_PUBKEY=rsakey.pub\nTPM_RSA_KEY=rsakey\ntpm2_create --key-auth=abc \\\n            --parent-context=${PARENT_CTX} \\\n            --hash-algorithm=sha256 --key-algorithm=rsa \\\n            --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n            --attributes=sign\\|decrypt\\|fixedtpm\\|fixedparent\\|sensitivedataorigin\\|userwithauth\\|noda\ntpm2_flushcontext --transient-object\n\n# Load Key to persistent handle\nRSA_CTX=rsakey.ctx\ntpm2_load --parent-context=${PARENT_CTX} \\\n          --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n          --key-context=${RSA_CTX}\ntpm2_flushcontext --transient-object\n\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${RSA_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Signing Data\necho \"abc\" | openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin stdin\n# Get public key of handle\ntpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\nR=\"$(openssl pkeyutl -pubin -inkey mykey.pem -verify -in mydata.txt -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_persistent_emptyauth.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\n\n# Create an RSA key pair\necho \"Generating RSA key pair\"\nTPM_RSA_PUBKEY=rsakey.pub\nTPM_RSA_KEY=rsakey\ntpm2_create --parent-context=${PARENT_CTX} \\\n            --hash-algorithm=sha256 --key-algorithm=rsa \\\n            --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n            --attributes=sign\\|decrypt\\|fixedtpm\\|fixedparent\\|sensitivedataorigin\\|userwithauth\\|noda\ntpm2_flushcontext --transient-object\n\n# Load Key to persistent handle\nRSA_CTX=rsakey.ctx\ntpm2_load --parent-context=${PARENT_CTX} \\\n          --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n          --key-context=${RSA_CTX}\ntpm2_flushcontext --transient-object\n\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${RSA_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\n# Signing Data\n#Actually signing should not require an auth value\nif ! openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin file:notexists; then\n#The expect script is only here, because tpm2-tss <2.2 had some bug, and thus us asking for passwords when none were required.\nexpect <<EOF\nspawn openssl pkeyutl -engine tpm2tss -keyform engine -inkey ${HANDLE} -sign -in mydata.txt -out mysig -passin stdin\nexpect \"Enter password for user key:\"\nsend \"\\r\\n\"\nexpect eof\nEOF\nfi\n\n# Get public key of handle\ntpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\nR=\"$(openssl pkeyutl -pubin -inkey mykey.pem -verify -in mydata.txt -sigfile mysig || true)\"\nif ! echo $R | grep \"Signature Verified Successfully\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/rsasign_restricted.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\n# Generate 2k + a bit of data\ndd if=/dev/zero of=mydata.txt count=4 bs=512 status=none\necho -n \"abcde12345abcde12345\">>mydata.txt\n\n# Create a Primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\n\ntpm2_createprimary --hierarchy=o --hash-algorithm=sha256 --key-algorithm=rsa \\\n                   --key-context=${PARENT_CTX}\ntpm2_flushcontext --transient-object\n\n# Create an RSA key pair\necho \"Generating RSA key pair\"\nTPM_RSA_PUBKEY=rsakey.pub\nTPM_RSA_KEY=rsakey\ntpm2_create --parent-context=${PARENT_CTX} \\\n            --hash-algorithm=sha256 --key-algorithm=rsa:rsassa-sha256:null \\\n            --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n            --attributes=sign\\|restricted\\|fixedtpm\\|fixedparent\\|sensitivedataorigin\\|userwithauth\\|noda\ntpm2_flushcontext --transient-object\n\n# Load Key to persistent handle\nRSA_CTX=rsakey.ctx\ntpm2_load --parent-context=${PARENT_CTX} \\\n          --public=${TPM_RSA_PUBKEY} --private=${TPM_RSA_KEY} \\\n          --key-context=${RSA_CTX}\ntpm2_flushcontext --transient-object\n\nHANDLE=$(tpm2_evictcontrol --hierarchy=o --object-context=${RSA_CTX} | cut -d ' ' -f 2 | head -n 1)\ntpm2_flushcontext --transient-object\n\ntpm2_readpublic --object-context=${HANDLE}\n\n# Digest & sign Data\nopenssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt\n\n# Get public key of handle\ntpm2_readpublic --object-context=${HANDLE} --output=mykey.pem --format=pem\n\n# Release persistent HANDLE\ntpm2_evictcontrol --hierarchy=o --object-context=${HANDLE}\n\nR=\"$(openssl dgst -verify mykey.pem -sha256 -signature mysig mydata.txt || true)\"\nif ! echo $R | grep \"Verified OK\" >/dev/null; then\n    echo $R\n    exit 1\nfi\n"
  },
  {
    "path": "test/sclient.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\nif openssl version | grep \"OpenSSL 1.0.2\" >/dev/null; then\n    echo \"OpenSSL 1.0.2 does not load the certificate; private key mismatch ???\"\n    exit 77\nfi\n\necho -en \"SSL CONNECTION WORKING\\n\">test.html\n\nfunction cleanup()\n{\n    kill -term $SERVER || true\n}\n\nopenssl ecparam -genkey -name prime256v1 -noout -out ca.key\n\necho -e \"\\n\\n\\n\\n\\n\\n\\n\" | openssl req -new -x509 -batch -extensions v3_ca -key ca.key -out ca.crt\n\necho -e \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\" | openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr\n\nopenssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt\n\ntpm2tss-genkey -a rsa client.tpm.key\n\necho -e \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\" | openssl req -new -key client.tpm.key -keyform engine -engine tpm2tss -out client.csr\n\nopenssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt\n\nopenssl s_server -cert server.crt -key server.key -accept 8443 -verify 1 -CAfile ca.crt -WWW &\nSERVER=$!\n\nsleep 1\n\nkill -0 $!\n\ntrap \"cleanup\" EXIT\n\n# We have to sleep, such that the pipe stays open until the command is finished.\n(echo -e \"GET /test.html HTTP/1.1\\r\\n\\r\\n\" && sleep 1) | openssl s_client -connect 127.0.0.1:8443 -cert client.crt -key client.tpm.key -engine tpm2tss -keyform engine -CAfile ca.crt\n\necho \"SUCCESS\"\n"
  },
  {
    "path": "test/sh_log_compiler.sh",
    "content": "#!/bin/bash\n\nexport LANG=C\nexport OPENSSL_ENGINES=\"${OPENSSL_ENGINES:=$PWD/.libs}\"\nexport LD_LIBRARY_PATH=\"$OPENSSL_ENGINES:${LD_LIBRARY_PATH-}\"\nexport PATH=\"$PWD:$PATH\"\n\nif [ -z \"$2\" ]; then\n    # no device passed\n    test_script=\"$(realpath \"$1\")\"\nelse\n    test_script=\"$(realpath \"$2\")\"\n    INTEGRATION_DEVICE=$1\nfi\n\necho \"Creating tpm2tss symlink\"\nln -fs libtpm2tss.so .libs/tpm2tss.so\n\ntmp_dir=\"$(mktemp --directory)\"\necho \"Switching to temporary directory $tmp_dir\"\ncd \"$tmp_dir\"\n\nif [ -z \"$INTEGRATION_DEVICE\" ]; then\n    # No device is passed so the TPM simulator will be used.\n    for simulator in 'swtpm' 'tpm_server'; do\n        simulator_binary=\"$(command -v \"$simulator\")\" && break\n    done\n    if [ -z \"$simulator_binary\" ]; then\n        echo 'ERROR: No TPM simulator was found on PATH'\n        exit 99\n    fi\n\n    for attempt in $(seq 9 -1 0); do\n        simulator_port=\"$(shuf --input-range 1024-65534 --head-count 1)\"\n        echo \"Starting simulator on port $simulator_port\"\n        case \"$simulator_binary\" in\n            *swtpm) \"$simulator_binary\" socket --tpm2 --server port=\"$simulator_port\" \\\n                                               --ctrl type=tcp,port=\"$(( simulator_port + 1 ))\" \\\n                                               --flags not-need-init --tpmstate dir=\"$tmp_dir\" \\\n\t\t\t\t\t       --seccomp \"action=none\" &;;\n            *tpm_server) \"$simulator_binary\" -port \"$simulator_port\" &;;\n        esac\n        simulator_pid=\"$!\"\n        sleep 1\n\n        if ( ss --listening --tcp --ipv4 --processes | grep \"$simulator_pid\" | grep --quiet \"$simulator_port\" &&\n             ss --listening --tcp --ipv4 --processes | grep \"$simulator_pid\" | grep --quiet \"$(( simulator_port + 1 ))\" )\n        then\n            echo \"Simulator with PID $simulator_pid started successfully\"\n            break\n        else\n            echo \"Failed to start simulator, the port might be in use\"\n            kill \"$simulator_pid\"\n\n            if [ \"$attempt\" -eq 0 ]; then\n                echo 'ERROR: Reached maximum number of tries to start simulator, giving up'\n                exit 99\n            fi\n        fi\n    done\n\n    case \"$simulator_binary\" in\n        *swtpm) export TPM2TSSENGINE_TCTI=\"swtpm:port=$simulator_port\";;\n        *tpm_server) export TPM2TSSENGINE_TCTI=\"mssim:port=$simulator_port\";;\n    esac\n    export TPM2TOOLS_TCTI=\"$TPM2TSSENGINE_TCTI\"\n\n    tpm2_startup --clear\nelse\n    # A physical TPM will be used for the integration test.\n    echo \"Running the test with $INTEGRATION_DEVICE\"\n    export TPM2TSSENGINE_TCTI=\"libtss2-tcti-device.so:$INTEGRATION_DEVICE\"\n    export TPM2TOOLS_TCTI=\"$TPM2TSSENGINE_TCTI\"\nfi\n\necho \"Starting $test_script\"\n\"$test_script\"\ntest_status=\"$?\"\n\nkill \"$simulator_pid\"\nrm -rf \"$tmp_dir\"\n\nexit \"$test_status\"\n"
  },
  {
    "path": "test/sserver.sh",
    "content": "#!/bin/bash\n\nset -eufx\n\nif openssl version | grep \"OpenSSL 1.0.2\" >/dev/null; then\n    echo \"OpenSSL 1.0.2 does not load the certificate; private key mismatch ???\"\n    exit 77\nfi\n\necho -n \"WORKING !!!\">index.html\n\nfunction cleanup()\n{\n    kill -term $SERVER\n}\n\ntpm2tss-genkey -a ecdsa mykey\n\necho -e \"\\n\\n\\n\\n\\n\\n\\n\" | openssl req -new -x509 -engine tpm2tss -key mykey  -keyform engine -out mykey.crt\n\nopenssl s_server -www -cert mykey.crt -key mykey -keyform engine -engine tpm2tss -accept 127.0.0.1:8444 &\nSERVER=$!\ntrap \"cleanup\" EXIT\n\nsleep 1\n\necho \"GET index.html\" | openssl s_client -connect localhost:8444\n"
  },
  {
    "path": "test/tpm2-tss-engine-common.c",
    "content": "/* SPDX-License-Identifier: BSD-2 */\n/*******************************************************************************\n * Copyright 2021, Erik Larsson\n * All rights reserved.\n ******************************************************************************/\n\n#include \"tpm2-tss-engine.h\"\n\n#include <setjmp.h>\n#include <cmocka.h>\n\nvoid\ncheck_tpm2tss_tpm2data_read(void **state)\n{\n    (void)(state);\n    TPM2_DATA *tpm2Data = NULL;\n    int rc;\n    rc = tpm2tss_tpm2data_read(NEG_HANDLE_PEM, &tpm2Data);\n    assert_int_equal(rc, 1);\n    assert_int_equal(tpm2Data->parent, 0x81000001);\n}\n\nint\nmain(void)\n{\n    const struct CMUnitTest tests[] = {\n        cmocka_unit_test(check_tpm2tss_tpm2data_read),\n    };\n\n    return cmocka_run_group_tests(tests, NULL, NULL);\n}\n"
  }
]