master 3d010240b5af cached
62 files
223.5 KB
65.1k tokens
75 symbols
1 requests
Download .txt
Showing preview only (239K chars total). Download the full file or copy to clipboard to get everything.
Repository: tpm2-software/tpm2-tss-engine
Branch: master
Commit: 3d010240b5af
Files: 62
Total size: 223.5 KB

Directory structure:
gitextract_x8we6x6b/

├── .ci/
│   ├── coverity.run
│   ├── docker.env
│   ├── docker.run
│   └── get_deps.sh
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .lgtm.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── INSTALL.md
├── LICENSE
├── MAINTAINERS
├── Makefile.am
├── README.md
├── RELEASE.md
├── SECURITY.md
├── bootstrap
├── configure.ac
├── include/
│   └── tpm2-tss-engine.h
├── m4/
│   └── flags.m4
├── man/
│   ├── tpm2tss-genkey.1.md
│   ├── tpm2tss_ecc_genkey.3.md
│   ├── tpm2tss_ecc_getappdata.3.md
│   ├── tpm2tss_ecc_makekey.3.md
│   ├── tpm2tss_rsa_genkey.3.md
│   ├── tpm2tss_rsa_makekey.3.md
│   └── tpm2tss_tpm2data_write.3.md
├── openssl.conf.sample
├── src/
│   ├── tpm2-tss-engine-common.c
│   ├── tpm2-tss-engine-common.h
│   ├── tpm2-tss-engine-digest-sign.c
│   ├── tpm2-tss-engine-ecc.c
│   ├── tpm2-tss-engine-err.c
│   ├── tpm2-tss-engine-err.h
│   ├── tpm2-tss-engine-rand.c
│   ├── tpm2-tss-engine-rsa.c
│   ├── tpm2-tss-engine.c
│   └── tpm2tss-genkey.c
└── test/
    ├── ecdh.sh
    ├── ecdsa-emptyauth.sh
    ├── ecdsa-handle-flush.sh
    ├── ecdsa-restricted.sh
    ├── ecdsa.sh
    ├── error_tpm2-tss-engine-common.c
    ├── failload.sh
    ├── failwrite.sh
    ├── neg-handle.pem
    ├── rand.sh
    ├── rsadecrypt.sh
    ├── rsasign.sh
    ├── rsasign_importtpm.sh
    ├── rsasign_importtpmparent.sh
    ├── rsasign_parent.sh
    ├── rsasign_parent_pass.sh
    ├── rsasign_persistent.sh
    ├── rsasign_persistent_emptyauth.sh
    ├── rsasign_restricted.sh
    ├── sclient.sh
    ├── sh_log_compiler.sh
    ├── sserver.sh
    └── tpm2-tss-engine-common.c

================================================
FILE CONTENTS
================================================

================================================
FILE: .ci/coverity.run
================================================
#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-2

set -eo pipefail

echo "PROJECT=$PROJECT"

if [ -z "$COVERITY_SCAN_TOKEN" ]; then
  echo "coverity.run invoked without COVERITY_SCAN_TOKEN set...exiting!"
  exit 1
fi

if [ -z "$COVERITY_SUBMISSION_EMAIL" ]; then
  echo "coverity.run invoked without COVERITY_SUBMISSION_EMAIL set...exiting!"
  exit 1
fi

# Sanity check, this should only be executing on the coverity_scan branch
if [[ "$REPO_BRANCH" != *coverity_scan ]]; then
  echo "coverity.run invoked for non-coverity branch $REPO_BRANCH...exiting!"
  exit 1
fi

if [[ "$CC" == clang* ]]; then
  echo "Coverity scan branch detected, not running with clang...exiting!"
  exit 1
fi

# branch is coverity_scan
echo "Running coverity build"

# ensure coverity_scan tool is available to the container
# We cannot package these in the docker image, as we would be distributing their software
# for folks not coupled to our COVERITY_SCAN_TOKEN.
if [ ! -f "$(pwd)/cov-analysis/bin/cov-build" ]; then
  curl --data-urlencode "project=$PROJECT" \
       --data-urlencode "token=$COVERITY_SCAN_TOKEN" \
       "https://scan.coverity.com/download/linux64" -o coverity_tool.tgz

  stat coverity_tool.tgz

  curl --data-urlencode "project=$PROJECT" \
       --data-urlencode "token=$COVERITY_SCAN_TOKEN" \
       --data-urlencode "md5=1" \
       "https://scan.coverity.com/download/linux64" -o coverity_tool.md5

  stat coverity_tool.md5
  cat coverity_tool.md5
  md5sum coverity_tool.tgz
  echo "$(cat coverity_tool.md5)" coverity_tool.tgz | md5sum -c

  echo "unpacking cov-analysis"
  tar -xf coverity_tool.tgz
  mv cov-analysis-* cov-analysis
fi

export PATH=$PATH:$(pwd)/cov-analysis/bin

echo "Which cov-build: $(which cov-build)"

# get the deps to build with
$DOCKER_BUILD_DIR/.ci/get_deps.sh "$(dirname $DOCKER_BUILD_DIR)"

pushd "$DOCKER_BUILD_DIR"

echo "Performing build with Coverity Scan"
rm -rf cov-int
./bootstrap && ./configure --enable-debug && make clean
cov-build --dir $DOCKER_BUILD_DIR/cov-int make -j $(nproc)

echo "Collecting Coverity data for submission"
rm -fr README
AUTHOR="$(git log -1 $HEAD --pretty="%aN")"
AUTHOR_EMAIL="$(git log -1 $HEAD --pretty="%aE")"
VERSION="$(git rev-parse HEAD)"
echo "Name: $AUTHOR" >> README
echo "Email: $AUTHOR_EMAIL" >> README
echo "Project: tpm2-pkcs11" >> README
echo "Build-Version: $VERSION" >> README
echo "Description: $REPO_NAME $REPO_BRANCH" >> README
echo "Submitted-by: tpm2-pkcs11 CI" >> README
echo "---README---"
cat README
echo "---EOF---"

rm -f tpm2-pkcs11-scan.tgz
tar -czf tpm2-pkcs11-scan.tgz README cov-int

rm -rf README cov-int

# upload the results
echo "Testing for scan results..."
scan_file=$(stat --printf='%n' tpm2-*-scan.tgz)

echo "Submitting data to Coverity"
curl --form token="$COVERITY_SCAN_TOKEN" \
  --form email="$COVERITY_SUBMISSION_EMAIL" \
  --form project="$PROJECT" \
  --form file=@"$scan_file" \
  --form version="$VERSION" \
  --form description="$REPO_NAME $REPO_BRANCH" \
  "https://scan.coverity.com/builds?project=$PROJECT"

rm -rf tpm2-*-scan.tgz

popd

exit 0


================================================
FILE: .ci/docker.env
================================================
# SPDX-License-Identifier: BSD-2

PROJECT
DOCKER_BUILD_DIR
LD_LIBRARY_PATH=/usr/local/lib/

CC

COVERITY_SCAN_TOKEN
COVERITY_SUBMISSION_EMAIL

PROJECT

REPO_BRANCH
REPO_NAME

ENABLE_COVERAGE
ENABLE_FUZZING
DOCKER_IMAGE

TPM2TSS_BRANCH
TPM2TOOLS_BRANCH


================================================
FILE: .ci/docker.run
================================================
#!/usr/bin/env bash
# SPDX-License-Identifier: BSD-2

set -exo pipefail

git config --global --add safe.directory /workspace/tpm2-tss-engine

$DOCKER_BUILD_DIR/.ci/get_deps.sh "$(dirname $DOCKER_BUILD_DIR)"

pushd $DOCKER_BUILD_DIR

SCAN_PREFIX=""
CONFIGURE_OPTIONS=""

if [ -d build ]; then
  rm -rf build
fi

./bootstrap

mkdir build
pushd build

if [ -z "$CC" -o "$CC" == "gcc" ]; then
  export CONFIGURE_OPTIONS+=" --enable-code-coverage";
else
  export SCAN_PREFIX="scan-build --status-bugs"
fi

$SCAN_PREFIX ../configure $CONFIGURE_OPTIONS --enable-unit --enable-integration
$SCAN_PREFIX make -j$(nproc)

make -j$(nproc) check
cat test-suite.log config.log
../configure $CONFIGURE_OPTIONS
make -j$(nproc) distcheck
cat config.log
popd

popd


================================================
FILE: .ci/get_deps.sh
================================================
# SPDX-License-Identifier: BSD-2

set -exo pipefail

pushd "$1"

if [ -z "$TPM2TSS_BRANCH" ]; then
    echo "TPM2TSS_BRANCH is unset, please specify TPM2TSS_BRANCH"
    exit 1
fi

if [ -z "$TPM2TOOLS_BRANCH" ]; then
    echo "TPM2TOOLS_BRANCH is unset, please specify TPM2TOOLS_BRANCH"
    exit 1
fi

# Install tpm2-tss
if [ ! -d tpm2-tss ]; then

  git clone --depth=1 -b "${TPM2TSS_BRANCH}" "https://github.com/tpm2-software/tpm2-tss.git"
  pushd tpm2-tss
  ./bootstrap
  ./configure --enable-debug
  make -j$(nproc)
  make install
  popd
else
  echo "tpm2-tss already installed, skipping..."
fi

# Install tpm2-tools
if [ ! -d tpm2-tools ]; then
  git clone --depth=1 -b "${TPM2TOOLS_BRANCH}" "https://github.com/tpm2-software/tpm2-tools.git"
  pushd tpm2-tools
  ./bootstrap
  ./configure --enable-debug --disable-hardening
  make -j$(nproc)
  make install
  popd
else
  echo "tpm2-tss already installed, skipping..."
fi

popd

exit 0


================================================
FILE: .github/workflows/main.yml
================================================
name: Linux Build Status
on:
  [push, pull_request]
jobs:
  build-test:
    runs-on: ubuntu-latest
    if: "!contains(github.ref, 'coverity_scan')"
    strategy:
      matrix:
        DOCKER_IMAGE: [ "ubuntu-18.04", "ubuntu-20.04", "fedora-32", "opensuse-leap" ]
        TPM2TSS_BRANCH: ["3.0.x"]
        TPM2TOOLS_BRANCH: ["4.0"]
        CC: ["gcc", "clang"]
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Launch Action
        uses:
          tpm2-software/ci/runCI@main
        with:
          DOCKER_IMAGE: "${{ matrix.DOCKER_IMAGE }}"
          TPM2TSS_BRANCH: "${{ matrix.TPM2TSS_BRANCH }}"
          TPM2TOOLS_BRANCH: "${{ matrix.TPM2TOOLS_BRANCH }}"
          CC: "${{ matrix.CC }}"
          PROJECT_NAME: ${{ github.event.repository.name }}
      - name: failure
        if: ${{ failure() }}
        run: cat build/test-suite.log || true
  multi-arch:
    runs-on: ubuntu-latest
    if: "!contains(github.ref, 'coverity_scan')"
    strategy:
      matrix:
        ARCH: [
          "ubuntu-20.04.arm32v7",
        ]
        TPM2TSS_BRANCH: ["3.0.x"]
        TPM2TOOLS_BRANCH: ["4.0"]
    steps:
      - name: Setup QEMU
        run: |
          sudo apt-get update
          sudo apt-get install qemu binfmt-support qemu-user-static
          docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Launch Action
        uses:
          tpm2-software/ci/runCI@main
        with:
          PROJECT_NAME: ${{ github.event.repository.name }}
          DOCKER_IMAGE: ${{ matrix.ARCH }}
          TPM2TSS_BRANCH: "${{ matrix.TPM2TSS_BRANCH }}"
          TPM2TOOLS_BRANCH: "${{ matrix.TPM2TOOLS_BRANCH }}"
          CC: gcc
      - name: failure
        if: ${{ failure() }}
        run: find -name test-suite.log | xargs cat || true
  coverity-test:
    runs-on: ubuntu-latest
    if: contains(github.ref, 'coverity_scan') && github.event_name == 'push'
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Launch Coverity Action
        uses:
          tpm2-software/ci/coverityScan@main
        with:
          PROJECT_NAME: ${{ github.event.repository.name }}
          ENABLE_COVERITY: true
          TPM2TSS_BRANCH: "3.0.x"
          TPM2TOOLS_BRANCH: "4.0"
          REPO_BRANCH: ${{ github.ref }}
          REPO_NAME: ${{ github.repository }}
          DOCKER_IMAGE: ubuntu-18.04
          CC: gcc
          COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
          COVERITY_SUBMISSION_EMAIL: william.c.roberts@intel.com
  whitespace-check:
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request' && !contains(github.ref, 'coverity_scan')
    steps:
      - name: Check out repository
        uses: actions/checkout@v2
      - name: Perform Whitespace Check
        env:
          BASE_REF: ${{ github.base_ref }}
        run: git fetch origin "$BASE_REF" && git diff --check "origin/$BASE_REF"


================================================
FILE: .gitignore
================================================
.deps/
.libs/
Makefile
Makefile.in
aclocal.m4
aminclude_static.am
autom4te.cache/
compile
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
libtool
libtpm2.la
ltmain.sh
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
missing
src/.dirstamp
src/.libs/
src/*.o
src/*.lo
tpm2tss-genkey
libtpm2tss.la
*.gcno
*.gcda
openssl-tpm2-engine-0.0.1-coverage.info
openssl-tpm2-engine-0.0.1-coverage/
*.log
*.trs
test-driver
man/*.1
man/*.3
man/*.7
.dirstamp
*~
test/error_tpm2-tss-engine-common
test/*.o
config.h.in
VERSION


================================================
FILE: .lgtm.yml
================================================
extraction:
  cpp:
    prepare:
      packages:
      - autoconf-archive
      - libcurl4-openssl-dev
      - libjson-c-dev
      - libssl-dev
      - acl
    after_prepare:
    - cd "$LGTM_WORKSPACE"
    - mkdir installdir
    - git clone https://github.com/tpm2-software/tpm2-tss.git
    - cd tpm2-tss
    - ./bootstrap
    - ./configure --prefix="$LGTM_WORKSPACE/installdir/usr" --disable-doxygen-doc
    - make install
    - export PKG_CONFIG_PATH="$LGTM_WORKSPACE/installdir/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
    - export LD_LIBRARY_PATH="$LGTM_WORKSPACE/installdir/usr/lib:$LD_LIBRARY_PATH"


================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.2.0] - 2023-01-09
### Fixed
- Updated minimal version of tpm2-tss to 2.4.x
- Fix encoding of emptyauth
- Fix some memory leaks
- Parent handle issues with signed representation by switching parent handle to BIGNUM.
- Fixed RSA_NO_PADDING modes with OpenSSL 1.1.1
- Fixed autogen (bootstrap) call from release package by embedding VERSION file.

### Added
- Use of restricted keys for signing
- StirRandom
- Run tests using swtpm
- The ability to import key blobs from things like the tpm2-tools project.
- Compatibility with openssl >=1.1.x
- Support for ECDH
- QNX support.
- Only set -Werror for non-release builds.
- Additional checks on TPM responses
- CODE_OF_CONDUCT
- SECURITY reporting instructions

## [1.1.0] - 2020-11-20
### Added
- Configure option for ptpm tests
- Configure script AX_CHECK_ENABLE_DEBUG
- Option for setting tcti on executable
- TCTI-env variable used by default
- Support for parent key passwords
- openssl.cnf sample file

### Changed
- Fix several build system, autotools and testing related issues
  Now adhere to CFLAGS conventions
- Include pkg-config dependecy on libtss2-mu in order to work with tpm2-tss 2.3
- Enables parallel testing of integration tests:
  Make integration tests use TPM simulator; instead of first TPM it finds
  Use of different port numbers for TCP based tests
- Fix EC param info (using named curve format)
- Use tpm2-tools 4.X stable branch for integration tests
- Use libtss2-tctildr.so instead of custom code for tcti setup
- Fix manpages for -P/--parent option and correct engine name
- Fix TCTI env variable handling

## [1.0.0] - 2019-04-04
### Added
- Initial release of the OpenSSL engine for TPM2.0 using the TCG's TPM
  Software Stack compliant tpm2-tss libraries.
- tpm2tss (the engine) compatible against OpenSSL 1.0.2 and 1.1.0.
- tpm2tss-genkey (cli-tool) for creating keys for use with the engine.
- man-pages and bash-completion are included.


================================================
FILE: CODE_OF_CONDUCT.md
================================================

# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
  community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or advances of
  any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
  without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[MAINTAINERS](MAINTAINERS).
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series of
actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within the
community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].

Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].

For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].

[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations


================================================
FILE: CONTRIBUTING.md
================================================
# Guidelines for submitting bugs:
All non security bugs should be filed on the Issues tracker:
https://github.com/tpm2-software/tpm2-tss-engine/issues

Security sensitive bugs should follow the details in SECURITY.md.

# Guideline for submitting changes:
All changes to the source code must follow the coding standard used in the
tpm2-tss project [here](https://github.com/tpm2-software/tpm2-tss/blob/master/doc/coding_standard_c.md).

All changes should be introduced via github pull requests. This allows anyone to
comment and provide feedback in lieu of having a mailing list. For pull requests
opened by non-maintainers, any maintainer may review and merge that pull
request. For maintainers, they either must have their pull request reviewed by
another maintainer if possible, or leave the PR open for at least 24 hours, we
consider this the window for comments.

## Patch requirements
* All tests must pass on Travis CI for the merge to occur.
* All changes must not introduce superfluous changes or whitespace errors.
* All commits should adhere to the git commit message guidelines described
here: https://chris.beams.io/posts/git-commit/ with the following exceptions.
 * We allow commit subject lines up to 80 characters.
* All contributions must adhere to the Developers Certificate of Origin. The
full text of the DCO is here: https://developercertificate.org/. Contributors
must add a 'Signed-off-by' line to their commits. This indicates the
submitters acceptance of the DCO.

## Guideline for merging changes
Pull Requests MUST be assigned to an upcoming release tag. If a release milestone does
not exist, the maintainer SHALL create it per the [RELEASE.md](RELEASE.md) instructions.
When accepting and merging a change, the maintainer MUST edit the description field for
the release milestone to add the CHANGELOG entry.

Changes must be merged with the "rebase" option on github to avoid merge commits.
This provides for a clear linear history.


================================================
FILE: INSTALL.md
================================================
# Dependencies

## GNU/Linux
* GNU Autoconf
* GNU Autoconf Archive
* GNU Automake
* GNU Libtool
* C compiler
* C library development libraries and header files
* pkg-config
* OpenSSL >= 1.0.2
* tpm2-tss >= 2.4.x
* pandoc
* doxygen

Integration tests also require:
* expect
* tpm2-tools 4.0 (or 4.X branch)
* [swtpm](https://github.com/stefanberger/swtpm) or [tpm_server](https://sourceforge.net/projects/ibmswtpm2/)
* realpath
* ss

## Ubuntu
```
sudo apt -y install \
  build-essential \
  autoconf \
  autoconf-archive \
  automake \
  m4 \
  libtool \
  gcc \
  pkg-config \
  libssl-dev \
  pandoc \
  doxygen

git clone http://www.github.com/tpm2-software/tpm2-tss
cd tpm2-tss
./bootstrap
./configure
make -j$(nproc)
sudo make install
```

Integration tests:
```
sudo apt -y install  \
  expect \
  realpath \
  ss

git clone http://github.com/tpm2-software/tpm2-tools
cd tpm2-tools
./bootstrap
./configure
make -j$(nproc)
sudo make install

wget https://downloads.sourceforge.net/project/ibmswtpm2/ibmtpm1682.tar.gz
mkdir ibmtpm
tar axf ibmtpm1682.tar.gz -C ibmtpm
make -C ibmtpm/src -j$(nproc)
sudo cp ibmtpm/src/tpm_server /usr/local/bin
```

# Building from source
```
git clone http://www.github.com/tpm2-software/tpm2-tss-engine
./bootstrap
./configure
make -j$(nproc)
sudo make install
```

# Configuration options
You may pass the following options to `./configure`

## Debug messages
This option will enable a lot of debug printing during the invocation of the
library:
```
./configure --enable-debug
```

## Developer linking
In order to link against a developer version of tpm2-tss (not installed):
```
./configure \
  PKG_CONFIG_PATH=${TPM2TSS}/lib:$PKG_CONFIG_PATH \
  CFLAGS=-I${TPM2TSS}/include \
  LDFLAGS=-L${TPM2TSS}/src/tss2-{tcti,mu,sys,esys}/.libs 
```

## Testing
In order to build the tests, pass the following options
(see the additional dependencies above):
```
./configure --enable-integration --enable-unit
make check
```

# Post installation

## ldconfig
You may need to run ldconfig after `make install` to update runtime bindings:
```
sudo ldconfig
```


================================================
FILE: LICENSE
================================================
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
   contributors may be used to endorse or promote products derived from
   this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: MAINTAINERS
================================================
Andreas Fuchs <andreas.fuchs@sit.fraunhofer.de>
Juergen Repp <juergen.repp@sit.fraunhofer.de> (occasionally)


================================================
FILE: Makefile.am
================================================
#;*****************************************************************************;
# Copyright (c) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of tpm2-tss-engine nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#;*****************************************************************************;

### Initialize global variables used throughout the file ###
INCLUDE_DIRS    = -I$(srcdir)/include -I$(srcdir)/src
ACLOCAL_AMFLAGS = -I m4 --install
AM_CFLAGS       = $(INCLUDE_DIRS) $(EXTRA_CFLAGS) $(TSS2_ESYS_CFLAGS) \
                  $(TSS2_MU_CFLAGS) $(TSS2_TCTILDR_CFLAGS) $(CRYPTO_CFLAGS) \
                  $(CODE_COVERAGE_CFLAGS)
AM_LDFLAGS      = $(EXTRA_LDFLAGS) $(CODE_COVERAGE_LIBS)
AM_LDADD        = $(TSS2_ESYS_LIBS) $(TSS2_MU_LIBS) $(TSS2_TCTILDR_LIBS) \
                  $(CRYPTO_LIBS)

AM_DISTCHECK_CONFIGURE_FLAGS = --with-enginesdir= --with-completionsdir= \
                               --enable-unit

# Initialize empty variables to be extended throughout
EXTRA_DIST =
CLEANFILES =
bin_PROGRAMS =

### Add ax_* rules ###
# ax_code_coverage
if AUTOCONF_CODE_COVERAGE_2019_01_06
include $(top_srcdir)/aminclude_static.am
clean-local: code-coverage-clean
distclean-local: code-coverage-dist-clean
else
@CODE_COVERAGE_RULES@
endif

# ax_valgrind_check
@VALGRIND_CHECK_RULES@

### OpenSSL Engine ###
openssl_enginedir = $(ENGINESDIR)
openssl_engine_LTLIBRARIES = libtpm2tss.la

include_HEADERS = include/tpm2-tss-engine.h

libtpm2tss_la_SOURCES = src/tpm2-tss-engine.c \
                        src/tpm2-tss-engine-common.c \
                        src/tpm2-tss-engine-common.h \
                        src/tpm2-tss-engine-digest-sign.c \
                        src/tpm2-tss-engine-err.c \
                        src/tpm2-tss-engine-err.h \
                        src/tpm2-tss-engine-ecc.c \
                        src/tpm2-tss-engine-rand.c \
                        src/tpm2-tss-engine-rsa.c
libtpm2tss_la_CFLAGS = $(AM_CFLAGS)
libtpm2tss_la_LIBADD = $(AM_LDADD)
libtpm2tss_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -avoid-version \
            -export-symbols-regex '(tpm2tss*|bind_engine|v_check)'

install-exec-local:
	([ -e $(DESTDIR)$(openssl_enginedir) ] || \
         $(MKDIR_P) $(DESTDIR)$(openssl_enginedir))

# Due to confusions with OpenSSL Naming conventions for engines regarding the
# lib* prefix, we will create a symlink for the engine on install
# see https://github.com/tpm2-software/tpm2-tss-engine/issues/6#issuecomment-422489744
# see https://github.com/openssl/openssl/commit/9ee0ed3de66678a15db126d10b3e4226e835b8f5 
install-exec-hook:
	(cd $(DESTDIR)$(openssl_enginedir) && \
         $(LN_S) -f libtpm2tss.so tpm2tss.so)

uninstall-hook:
	(cd $(DESTDIR)$(openssl_enginedir) && \
         [ -L tpm2tss.so ] && rm -f tpm2tss.so)

### KeyGenerator ###
bin_PROGRAMS += tpm2tss-genkey

tpm2tss_genkey_SOURCES = src/tpm2tss-genkey.c
tpm2tss_genkey_CFLAGS = $(AM_CFLAGS)
tpm2tss_genkey_LDADD = $(AM_LDADD) libtpm2tss.la
tpm2tss_genkey_LDFLAGS = $(AM_LDFLAGS)

### Tests ###
TESTS = $(TESTS_INTEGRATION) $(TESTS_UNIT)

check_PROGRAMS = $(TESTS_UNIT)
TESTS_UNIT =
TESTS_INTEGRATION =

if INTEGRATION
TESTS_INTEGRATION += $(TESTS_SHELL)
endif #INTEGRATION
TESTS_SHELL = test/ecdsa.sh \
              test/ecdsa-emptyauth.sh \
              test/ecdsa-handle-flush.sh \
              test/rand.sh \
              test/rsadecrypt.sh \
              test/rsasign.sh \
              test/failload.sh \
              test/failwrite.sh \
              test/rsasign_importtpm.sh \
              test/rsasign_importtpmparent.sh \
              test/rsasign_parent.sh \
              test/rsasign_parent_pass.sh \
              test/rsasign_persistent.sh \
              test/rsasign_persistent_emptyauth.sh \
              test/sserver.sh \
              test/sclient.sh
if HAVE_OPENSSL_ECDH
TESTS_SHELL += test/ecdh.sh
endif
if HAVE_OPENSSL_DIGEST_SIGN
TESTS_SHELL += test/ecdsa-restricted.sh \
               test/rsasign_restricted.sh
endif
EXTRA_DIST += $(TESTS_SHELL) test/neg-handle.pem
TEST_EXTENSIONS = .sh
SH_LOG_COMPILER = $(srcdir)/test/sh_log_compiler.sh
SH_LOG_FLAGS = $(INTEGRATION_ARGS)
EXTRA_DIST += $(SH_LOG_COMPILER)

if UNIT
TESTS_UNIT += test/error_tpm2-tss-engine-common test/tpm2-tss-engine-common
test_error_tpm2_tss_engine_common_CFLAGS =  $(AM_CFLAGS) $(CMOCKA_CFLAGS)
test_error_tpm2_tss_engine_common_LDADD =   $(AM_LDADD) $(CMOCKA_LIBS)
test_error_tpm2_tss_engine_common_LDFLAGS = $(AM_LDFLAGS) -Wl,--wrap=Esys_Initialize
test_error_tpm2_tss_engine_common_SOURCES = test/error_tpm2-tss-engine-common.c \
                                            $(libtpm2tss_la_SOURCES)
test_tpm2_tss_engine_common_CFLAGS =  $(AM_CFLAGS) $(CMOCKA_CFLAGS) \
                                            -DNEG_HANDLE_PEM=\"$(top_srcdir)/test/neg-handle.pem\"
test_tpm2_tss_engine_common_LDADD =   $(AM_LDADD) $(CMOCKA_LIBS)
test_tpm2_tss_engine_common_LDFLAGS = $(AM_LDFLAGS)
test_tpm2_tss_engine_common_SOURCES = test/tpm2-tss-engine-common.c \
                                            $(libtpm2tss_la_SOURCES)
endif #UNIT

# Adding user and developer information
EXTRA_DIST += \
    CHANGELOG.md \
    CONTRIBUTING.md \
    INSTALL.md \
    LICENSE \
    README.md \
    VERSION

# Generate the AUTHORS file from git log
AUTHORS:
	$(AM_V_GEN)git log --format='%aN <%aE>' | \
			grep -v 'users.noreply.github.com' | sort -u > $@
EXTRA_DIST += AUTHORS
CLEANFILES += AUTHORS

if HAVE_MAN_PAGES
### Man Pages
dist_man_MANS = \
    man/man1/tpm2tss-genkey.1 \
    man/man3/tpm2tss_tpm2data_write.3 \
    man/man3/tpm2tss_rsa_makekey.3 \
    man/man3/tpm2tss_rsa_genkey.3 \
    man/man3/tpm2tss_ecc_makekey.3 \
    man/man3/tpm2tss_ecc_genkey.3 \
    man/man3/tpm2tss_ecc_getappdata.3 \
    man/man3/tpm2tss_tpm2data_read.3 \
    man/man3/tpm2tss_ecc_setappdata.3
endif

if !HAVE_PANDOC
# If pandoc is not enabled, we want to complain that you need pandoc for make dist,
# so hook the target and complain.
dist-hook:
	@(>&2 echo "You do not have pandoc, a requirement for the distribution of manpages")
	@exit 1
endif

man/man3/tpm2tss_tpm2data_read.3: man/man3/tpm2tss_tpm2data_write.3
	$(AM_V_GEN)(rm $@ 2>/dev/null || true) && ln -s tpm2tss_tpm2data_write.3 $@

man/man3/tpm2tss_ecc_setappdata.3: man/man3/tpm2tss_ecc_getappdata.3
	$(AM_V_GEN)(rm $@ 2>/dev/null || true) && ln -s tpm2tss_ecc_getappdata.3 $@

man/man1/%.1: man/%.1.md
	$(AM_V_GEN)mkdir -p man/man1 && cat $< | $(PANDOC) -s -t man >$@

man/man3/%.3: man/%.3.md
	$(AM_V_GEN)mkdir -p man/man3 && cat $< | $(PANDOC) -s -t man >$@

EXTRA_DIST += \
    man/tpm2tss-genkey.1.md \
    man/tpm2tss_tpm2data_write.3.md \
    man/tpm2tss_rsa_makekey.3.md \
    man/tpm2tss_rsa_genkey.3.md \
    man/tpm2tss_ecc_makekey.3.md \
    man/tpm2tss_ecc_genkey.3.md \
    man/tpm2tss_ecc_getappdata.3.md

CLEANFILES += \
    $(dist_man_MANS)

### Bash Completion
bash_completiondir = $(completionsdir)
bash_completion_DATA = bash-completion/tpm2tss-genkey
EXTRA_DIST += bash-completion/tpm2tss-genkey


================================================
FILE: README.md
================================================
[![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)
[![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)
[![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)
[![Coverity Scan](https://img.shields.io/coverity/scan/22247.svg)](https://scan.coverity.com/projects/tpm2-tss-engine)


# Overview
The tpm2-tss-engine project implements a cryptographic engine for
[OpenSSL](https://www.openssl.org) for
[Trusted Platform Module (TPM 2.0)](https://trustedcomputinggroup.org/work-groups/trusted-platform-module/)
using the [tpm2-tss](https://www.github.com/tpm2-software/tpm2-tss) software
stack that follows the Trusted Computing Groups (TCG) 
[TPM Software Stack (TSS 2.0)](https://trustedcomputinggroup.org/work-groups/software-stack/).
It uses the 
[Enhanced System API (ESAPI)](https://trustedcomputinggroup.org/wp-content/uploads/TSS_ESAPI_Version-0.9_Revision-04_reviewEND030918.pdf)
interface of the TSS 2.0 for downwards communication. It supports RSA decryption
and signatures as well as ECDSA signatures.

If 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)

# Operations

## Key hierarchies
The keys used by this engine are all located underneath an ECC restricted
primary storage decryption key. This key is created on each invocation (since
ECC key creation is faster than RSA's). Thus, no persistent SRK key need to be
predeployed.

The authorization value for the storage hierarchie (the owner password) is
assumed to be clear (of zero length). If this is not the case, it needs to be
set using the engine ctrl.

## Key types
The RSA keys are created with the ability to sign as well as to decrypt.
This allows all RSA keys to be used for either operation.
Note: The TPM's RSA sign operation will enforce tagging payloads with an ASN.1
encoded identifier of the used hash algorithm. This is incompatible with
OpelSSL's RSA interface structures. Thus, the TPM2_RSA_Decrypt method is also
used for signing operations which also requires decrypt capabilities to be
activated for this key.

The ECDSA keys are created as ECDSA keys with the ability to perform signature
operations.

# Build and install instructions
Instructions to build and install tpm2-tss are available in the
[INSTALL](INSTALL.md) file.

# Usage

For additional usage examples, please consider the integration tests under
`tests/*.sh`.

## Engine information
Engine informations can be retrieved using
```
openssl engine -t -c tpm2tss
```

## Random data
A set of 10 random bytes can be retrieved using
```
openssl rand -engine tpm2tss -hex 10
engine "tpm2tss" set.
WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so
WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so
40ac9191079e490d17b7
WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-default.so
WARNING:esys:src/tss2-esys/esys_tcti_default.c:137:tcti_from_file() Could not load TCTI file: libtss2-tcti-tabrmd.so
```
Note: These warnings stem from the tpm2-tss libraries and are not an issue, as
long as a TPM connection is established afterwards by a different tcti.

## RSA operations

### RSA decrypt
The following sequence of commands creates an RSA key using the TPM, exports the
public key, encrypts a data file and decrypts it using the TPM:
```
tpm2tss-genkey -a rsa -s 2048 mykey
openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub
openssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher
openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata
```
Alternatively, the data can be encrypted directly with the TPM key using:
```
openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -encrypt -in mydata -out mycipher
```

### RSA sign
The following sequence of commands creates an RSA key using the TPM, exports the
public key, signs a data file using the TPM and validates the signature:
```
openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub
openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig
openssl pkeyutl -pubin -inkey mykey.pub -verify -in mydata -sigfile mysig
```
Alternatively, the data can be validated directly using:
`openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig`
Note: `mydata` must not exceed the size of the RSA key, since these operation
do not perform any hashing of the input data.

## ECDSA operations
The following sequence of commands creates an ECDSA key using the TPM, signs
a data file using the TPM and validates the signature:
```
tpm2tss-genkey -a ecdsa mykey
openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig
openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig
```

To export the public key use:

```
openssl ec -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub
```

## Self Signed certificate generate operation 
The following sequence of commands creates self signed certificate using TPM
key. Openssl command sets tpm2tss as engine and generates a self signed
certificate based on provided CSR configuration information.
```
$ tpm2tss-genkey -a rsa rsa.tss
$ openssl req -new -x509 -engine tpm2tss -key rsa.tss  -keyform engine -out rsa.crt
```

## Signing using restricted key
Signing using a restricted ECDSA key is possible with the caveat that
the TPM must be used for the digest, so higher-level digest & sign
operations must be used instead, e.g.:
```
$ openssl dgst -engine tpm2tss -keyform engine -sha256 -sign ${HANDLE} -out mysig mydata.txt
```
Where `${HANDLE}` is the TPM persistent handle ID for the restricted
key created by an external tool (since tpm2tss-genkey doesn't support
creating restricted keys).

# TLS and s_server
This engine can be used in all places where OpenSSL is used to create a TLS
secure channel connection. You have can specify the command
```
./tpm2tss-genkey -a rsa rsa.tss
openssl req -new -x509 -engine tpm2tss -key rsa.tss  -keyform engine  -out rsa.crt
openssl s_server -cert rsa.crt -key rsa.tss -keyform engine -engine tpm2tss -accept 8443
```

For ECDSA keys however, the Hash algorithm needs to be specified because the TPM
does not support SHA512. You can blacklisting SHA512 universally. That is
possible via openssl.cnf. See the "SignatureAlgorithms" configuration file
command on this page:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CONF_cmd.html

Note: Usage of s_server with HSM-protected private keys is only supported on
OpenSSL 1.1.0 and newer.

## Development prefixes
In order to use this engine without `make install` for testing call:
```
export LD_LIBRAY_PATH=${TPM2TSS}/src/tss2-{tcti,mu,sys,esys}/.libs
export PKG_CONFIG_PATH=$PWD/../tpm2-tss/lib
./bootstrap
./configure \
    CFLAGS="-I$PWD/../tpm2-tss/include" \
    LDFLAGS="-L$PWD/../tpm2-tss/src/tss2-{esys,sys,mu,tcti}/.libs"
make
make check
```


================================================
FILE: RELEASE.md
================================================
# Release Process:
This document describes the general process that maintainers must follow when
making a release of the `tpm2-tss-engine` library and cli-tool.

# Milestones
All releases should have a milestone used to track the release. If the release version is not known, as covered in [Version Numbers](#Version Numbers),
then 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
the CHANGELOG for that release. See [CHANGELOG Update](#CHANGELOG Update) for details.

# Version Numbers
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

In summary: Given a version number MAJOR.MINOR.PATCH, increment the:
1. MAJOR version when you make incompatible API changes,
2. MINOR version when you add functionality in a backwards-compatible manner, and
3. PATCH version when you make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

## Version String
The version string is set for the rest of the autotools bits by autoconf.
Autoconf gets this string from the `AC_INIT` macro in the configure.ac file.
Once you decide on the next version number (using the scheme above) you must set
it manually in configure.ac. The version string must be in the form `A.B.C`
where `A`, `B` and `C` are integers representing the major, minor and micro
components of the version number.

## Release Candidates
In the run up to a release the maintainers may create tags to identify progress
toward the release. In these cases we will append a string to the release number
to indicate progress using the abbreviation `rc` for 'release candidate'. This
string will take the form of `-rcX`. We append an incremental digit `X` in case
more than one release candidate is necessary to communicate progress as
development moves forward.

# CHANGELOG Update
Before tagging the repository with the release version, the maintainer MUST update the CHANGELOG file with the contents from the description field
from the corresponding release milestone and update any missing version string details in the CHANGELOG and milestone entry.

# Git Tags
When a release is made a tag is created in the git repo identifying the release
by the [version string](#Version String). The tag should be pushed to upstream
git repo as the last step in the release process.
**NOTE** tags for release candidates will be deleted from the git repository
after a release with the corresponding version number has been made.
**NOTE** release (not release candidate) tags should be considered immutable.

## Signed tags
Git supports GPG signed tags and releases will have tags signed by a maintainer.
For details on how to sign and verify git tags see:
https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work.

# Release tarballs
We use the git tag as a way to mark the point of the release in the projects
history. We do not however encourage users to build from git unless they intend
to modify the source code and contribute to the project. For the end user we
provide release tarballs following the GNU conventions as closely as possible.

To make a release tarball use the `distcheck` make target.
This target includes a number of sanity checks that are extremely helpful.
For more information on `automake` and release tarballs see:
https://www.gnu.org/software/automake/manual/html_node/Dist.html#Dist

## Hosting Releases on Github
Github automagically generates a page in their UI that maps git tags to
'releases' (even if the tag isn't for a release). Additionally they support
hosting release tarballs through this same interface. The release tarball
created in the previous step must be posted to github using the release
interface. Additionally, this tarball must be accompanied by a detached GPG
signature. The Debian wiki has an excellent description of how to post a signed
release to Github here:
https://wiki.debian.org/Creating%20signed%20GitHub%20releases
**NOTE** release candidates must be taken down after a release with the
corresponding version number is available.

## Signing Release Tarballs
Signatures must be generated using the `--detach-sign` and `--armor` options to
the `gpg` command.

## Verifying Signatures
Verifying the signature on a release tarball requires the project maintainers
public keys be installed in the GPG keyring of the verifier. With both the
release tarball and signature file in the same directory the following command
will verify the signature:
```
$ gpg --verify tpm2-tss-engine-X.Y.Z.tar.gz.asc
```

## Signing Keys
The GPG keys used to sign a release tag and the associated tarball must be the
same. Additionally they must:
* belong to a project maintainer
* be discoverable using a public GPG key server
* be associated with the maintainers github account
(https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/)

# Announcements
Release candidates and proper releases should be announced on the mailing list:
  - https://lists.linuxfoundation.org/mailman/listinfo/tpm2

This announcement should be accompanied by a link to the release page on Github
as well as a link to the CHANGELOG.md accompanying the release.


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

Currently supported versions:

| Version | Supported          |
| ------- | ------------------ |
| any | :white_check_mark: |

## Reporting a Vulnerability

### Reporting

Security vulnerabilities can be disclosed in one of two ways:
- 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.
- Email: A descirption *should be emailed* to **all** members of the [MAINTAINERS](MAINTAINERS) file to coordinate the
disclosure of the vulnerability.

### Tracking

When a maintainer is notified of a security vulnerability, they *must* create a GitHub security advisory
per the instructions at:

  - <https://docs.github.com/en/code-security/repository-security-advisories/about-github-security-advisories-for-repositories>

Maintainers *should* use the optional feature through GitHub to request a CVE be issued, alternatively RedHat has provided CVE's
in the past and *may* be used, but preference is on GitHub as the issuing CNA.

### Publishing

Once ready, maintainers should publish the security vulnerability as outlined in:

  - <https://docs.github.com/en/code-security/repository-security-advisories/publishing-a-repository-security-advisory>

As well as ensuring the publishing of the CVE, maintainers *shal*l have new release versions ready to publish at the same time as
the CVE. Maintainers *should* should strive to adhere to a sub 60 say turn around from report to release.


================================================
FILE: bootstrap
================================================
#!/bin/bash

set -e

git describe --tags --always --dirty > VERSION

autoreconf --install --sym


================================================
FILE: configure.ac
================================================
#;*****************************************************************************;
# Copyright (c) 2018 Fraunhofer SIT sponsored by Infineon Technologies AG
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of tpm2-tss-engine nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#;*****************************************************************************;
AC_PREREQ([2.68])

AC_INIT([tpm2-tss-engine],
        [m4_esyscmd_s([cat ./VERSION])],
        [https://github.com/tpm2-software/tpm2-tss-engine/issues],
        [],
        [https://github.com/tpm2-software/tpm2-tss-engine])

dnl Let's be FHS-conform by default.
if test "$prefix" = '/usr'; then
    test "$sysconfdir" = '${prefix}/etc' && sysconfdir="/etc"
    test "$sharedstatedir" = '${prefix}/com' && sharedstatedir="/var"
    test "$localstatedir" = '${prefix}/var' && localstatedir="/var"
fi

AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([src/tpm2-tss-engine.c])
AC_CONFIG_AUX_DIR([build-aux])

# propagate configure arguments to distcheck
AC_SUBST([DISTCHECK_CONFIGURE_FLAGS],[$ac_configure_args])

AC_CANONICAL_SYSTEM

AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Wno-portability])
#Backward compatible setting of "silent-rules"
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 
AM_MAINTAINER_MODE([enable])

AX_IS_RELEASE([dash-version])
AX_CHECK_ENABLE_DEBUG([info])

AC_PROG_CC
AC_PROG_CC_C99
AM_PROG_CC_C_O
LT_INIT()

AC_PROG_MKDIR_P
AC_PROG_LN_S

AC_CONFIG_HEADERS([src/config.h])

AC_ARG_ENABLE([tctienvvar],
    [AS_HELP_STRING([--disable-tctienvvar],
                    [Disable setting the TCTI option from an environment variable])],,
    [enable_tctienvvar=yes])
AS_IF([test "x$enable_tctienvvar" = xyes], [AC_DEFINE([ENABLE_TCTIENVVAR], [1],
      'Enable getting TCTI from env variable')])

AC_CONFIG_FILES([Makefile])

AC_ARG_ENABLE([defaultflags],
              [AS_HELP_STRING([--disable-defaultflags],
                              [Disable default preprocessor, compiler, and linker flags.])],,
              [enable_defaultflags=yes])
AS_IF([test "x$enable_defaultflags" = "xyes"],
      [
      AX_ADD_COMPILER_FLAG([-std=gnu99])
      AX_ADD_COMPILER_FLAG([-Wall])
      AX_ADD_COMPILER_FLAG([-Wextra])
      AX_ADD_COMPILER_FLAG([-Wformat-security])
      AS_IF([test "x$ax_is_release" = "xno"], [AX_ADD_COMPILER_FLAG([-Werror])])
      AX_ADD_COMPILER_FLAG([-fstack-protector-all])
      AX_ADD_COMPILER_FLAG([-fpic])
      AX_ADD_COMPILER_FLAG([-fPIC])

      # work around GCC bug #53119
      #   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119
      AX_ADD_COMPILER_FLAG([-Wno-missing-braces])

      AX_ADD_LINK_FLAG([-Wl,--no-undefined])
      AX_ADD_LINK_FLAG([-Wl,-z,noexecstack])
      AX_ADD_LINK_FLAG([-Wl,-z,now])
      AX_ADD_LINK_FLAG([-Wl,-z,relro])
      ])

AX_CODE_COVERAGE
m4_ifdef([_AX_CODE_COVERAGE_RULES],
         [AM_CONDITIONAL(AUTOCONF_CODE_COVERAGE_2019_01_06, [true])],
         [AM_CONDITIONAL(AUTOCONF_CODE_COVERAGE_2019_01_06, [false])])
AX_ADD_AM_MACRO_STATIC([])

PKG_PROG_PKG_CONFIG([0.25])
PKG_CHECK_MODULES([CRYPTO], [libcrypto >= 1.0.2g],
                  [ac_enginesdir=`$PKG_CONFIG --variable=enginesdir libcrypto`])
PKG_CHECK_MODULES([TSS2_ESYS], [tss2-esys >= 2.3])
PKG_CHECK_MODULES([TSS2_MU], [tss2-mu])
PKG_CHECK_MODULES([TSS2_TCTILDR], [tss2-tctildr])

AC_CHECK_LIB([crypto], EC_KEY_METHOD_set_compute_key,
      [AM_CONDITIONAL([HAVE_OPENSSL_ECDH], true)],
      [AM_CONDITIONAL([HAVE_OPENSSL_ECDH], false)])

AC_ARG_ENABLE([digestsign],
              [AS_HELP_STRING([--disable-digestsign],
                              [Disable support for digest and sign methods, helps with TPM unsupported hash algorithms.])],,
              [enable_digestsign=yes])
AC_CHECK_LIB([crypto], EVP_PKEY_meth_set_digest_custom,
      [AM_CONDITIONAL([HAVE_OPENSSL_DIGEST_SIGN], [test "x$enable_digestsign" != "xno"])],
      [AM_CONDITIONAL([HAVE_OPENSSL_DIGEST_SIGN], false)])
AS_IF([test "x$ac_cv_lib_crypto_EVP_PKEY_meth_set_digest_custom" = xyes && test "x$enable_digestsign" = "xyes"],
      [AC_DEFINE([HAVE_OPENSSL_DIGEST_SIGN], [1],
                 Have required functionality from OpenSSL to support digest and sign)])

AC_PATH_PROG([PANDOC], [pandoc])
AS_IF([test -z "$PANDOC"],
    [AC_MSG_WARN([Required executable pandoc not found, man pages will not be built])])
AM_CONDITIONAL([HAVE_PANDOC],[test -n "$PANDOC"])
AM_CONDITIONAL([HAVE_MAN_PAGES],[test -d "${srcdir}/man/man1" -o -n "$PANDOC"])

AC_PATH_PROG([EXPECT], [expect])
AS_IF([test -z "$EXPECT"],
    [AC_MSG_WARN([Required executable expect not found, some tests might fail])])

AC_ARG_WITH([enginesdir], 
            [AS_HELP_STRING([--with-enginesdir],
                            [Set the OpenSSL engine directory (default: use pkg-config)])],
            [],
            [with_enginesdir=$ac_enginesdir])
AS_IF([test -z "$with_enginesdir"],
    [AC_MSG_WARN([Empty enginesdir, using $libdir/engines instead.])])
# This weirdness is necessary to enable distcheck via DISTCHECK_CONFIGURE_FLAGS
AS_IF([test -z "$with_enginesdir"],
    [with_enginesdir=$libdir/engines])
AC_SUBST(ENGINESDIR, "$with_enginesdir")

AC_ARG_WITH([completionsdir],
            [AS_HELP_STRING([--with-completionsdir],
                            [Set the bash completions directory (default: use pkg-config)])],
            [],
            [with_completionsdir=`$PKG_CONFIG --variable=completionsdir bash-completion`])
AS_IF([test -z "$with_completionsdir"],
    [AC_MSG_WARN([Empty completionsdir, using $datarootdir/bash-completion/completions instead.])])
AS_IF([test -z "$with_completionsdir"],
    [with_completionsdir=$datarootdir/bash-completion/completions])
AC_SUBST(completionsdir, "$with_completionsdir")

AC_ARG_ENABLE([unit],
            [AS_HELP_STRING([--enable-unit],
                            [build cmocka unit tests])],,
            [enable_unit=no])
AS_IF([test "x$enable_unit" != "xno" ], 
      [PKG_CHECK_MODULES([CMOCKA], [cmocka >= 1.0])])
AM_CONDITIONAL([UNIT], [test "x$enable_unit" != xno])

AC_ARG_ENABLE([integration],
            [AS_HELP_STRING([--enable-integration],
                            [build integration tests against TPM])],,
            [enable_integration=no])
AM_CONDITIONAL([INTEGRATION], [test "x$enable_integration" != xno])

# Use physical TPM device for testing
AC_ARG_WITH([device],
            [AS_HELP_STRING([--with-device=<device>],[TPM device for testing])],
            [AS_IF([test \( -w "$with_device" \)  -a \( -r "$with_device" \)],
                   [AC_MSG_RESULT([success])
                    AX_NORMALIZE_PATH([with_device])
                    with_device_set=yes],
                   [AC_MSG_ERROR([TPM device provided does not exist or is not writable])])],
            [with_device_set=no])
AM_CONDITIONAL([TESTDEVICE],[test "x$with_device_set" = xyes])

AC_CHECK_FUNC([backtrace_symbols_fd],[AC_DEFINE([HAVE_EXECINFO],[1], ['Define to 1 if you have the <execinfo.h> header file.'])])

# Integration test with simulator
AS_IF([test "x$enable_integration" = xyes && test "x$with_device_set" = xno],
      [integration_args=""
       AC_CHECK_PROG([tpm2_startup], [tpm2_startup], [yes])
       AS_IF([test "x$tpm2_startup" != xyes],
             [AC_MSG_ERROR([Integration tests require the tpm2_startup executable])])
       AC_CHECK_PROG([swtpm], [swtpm], [yes])
       AC_CHECK_PROG([tpm_server], [tpm_server], [yes])
       AS_IF([test "x$swtpm" != xyes && test "x$tpm_server" != xyes],
             [AC_MSG_ERROR([Integration tests require either the swtpm or the tpm_server executable])])
       AC_CHECK_PROG([realpath], [realpath], [yes])
       AS_IF([test "x$realpath" != xyes],
             [AC_MSG_ERROR([Integration tests require the realpath executable])])
       AC_CHECK_PROG([ss], [ss], [yes])
       AS_IF([test "x$ss" != xyes],
             [AC_MSG_ERROR([Integration tests require the ss executable])])
       AS_IF([test "x$enable_tctienvvar" != xyes],
             [AC_MSG_ERROR([Integration tests require building with TCTI environment variable support])])
       AC_SUBST([INTEGRATION_ARGS], [$integration_args])
      ])

# Integration test with physical device
AS_IF([test "x$enable_integration" = xyes &&  test "x$with_device_set" = xyes ],
      [integration_args="$with_device"
       AC_CHECK_PROG([realpath], [realpath], [yes])
       AS_IF([test "x$realpath" != xyes],
             [AC_MSG_ERROR([Integration tests require the realpath executable])])
       AS_IF([test "x$enable_tctienvvar" != xyes],
             [AC_MSG_ERROR([Integration tests require building with TCTI environment variable support])])
       AC_SUBST([INTEGRATION_ARGS], [$integration_args])
      ])

AX_VALGRIND_CHECK

#
# sanitizer compiler flags
#
AC_ARG_WITH([sanitizer],
            [AS_HELP_STRING([--with-sanitizer={none,address,undefined}],
                            [build with the given sanitizer])],,
            [with_sanitizer=none])
AS_CASE(["x$with_sanitizer"],
        ["xnone"],
        [],
        ["xaddress"],
        [
            SANITIZER_CFLAGS="-fsanitize=address -fno-omit-frame-pointer"
            SANITIZER_LDFLAGS="-lasan"
        ],
        ["xundefined"],
        [
            SANITIZER_CFLAGS="-fsanitize=undefined"
            SANITIZER_LDFLAGS="-lubsan"
        ],
        [AC_MSG_ERROR([Bad value for --with-sanitizer])])
AC_SUBST([SANITIZER_CFLAGS])
AC_SUBST([SANITIZER_LDFLAGS])

AC_OUTPUT

AC_MSG_RESULT([
$PACKAGE_NAME $VERSION
    man-pages:      $PANDOC
    enginesdir:     $with_enginesdir
    completionsdir: $with_completionsdir
    device:         $with_device
])



================================================
FILE: include/tpm2-tss-engine.h
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
#ifndef TPM2_TSS_ENGINE_H
#define TPM2_TSS_ENGINE_H

#include <openssl/engine.h>
#include <tss2/tss2_tpm2_types.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
    KEY_TYPE_BLOB,
    KEY_TYPE_HANDLE
} KEY_TYPE;

typedef struct {
    int emptyAuth;
    TPM2B_DIGEST userauth;
    TPM2B_PUBLIC pub;
    TPM2_HANDLE parent;
    KEY_TYPE privatetype;
    union {
      TPM2B_PRIVATE priv;
      TPM2_HANDLE handle;
    };
} TPM2_DATA;

#define TPM2TSS_SET_OWNERAUTH   ENGINE_CMD_BASE
#define TPM2TSS_SET_TCTI        (ENGINE_CMD_BASE + 1)
#define TPM2TSS_SET_PARENTAUTH  (ENGINE_CMD_BASE + 2)

int
tpm2tss_tpm2data_write(const TPM2_DATA *tpm2data, const char *filename);

int
tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap);

int
tpm2tss_tpm2data_readtpm(uint32_t handle, TPM2_DATA **tpm2Datap);

int
tpm2tss_tpm2data_importtpm(const char *filenamepub, const char *filenametpm,
                           TPM2_HANDLE parent, int emptyAuth,
                           TPM2_DATA **tpm2Datap);

EVP_PKEY *
tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data);

int
tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password,
                   TPM2_HANDLE parentHandle);

EVP_PKEY *
tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data);

int
tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password,
                   TPM2_HANDLE parentHandle);

TPM2_DATA *
#if OPENSSL_VERSION_NUMBER < 0x10100000
tpm2tss_ecc_getappdata(EC_KEY *key);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
tpm2tss_ecc_getappdata(const EC_KEY *key);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

int
tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *data);

#ifdef __cplusplus
}
#endif
#endif /* TPM2_TSS_ENGINE_H */


================================================
FILE: m4/flags.m4
================================================
dnl AX_ADD_COMPILER_FLAG:
dnl   A macro to add a CFLAG to the EXTRA_CFLAGS variable. This macro will
dnl   check to be sure the compiler supports the flag. Flags can be made
dnl   mandatory (configure will fail).
dnl $1: C compiler flag to add to EXTRA_CFLAGS.
dnl $2: Set to "required" to cause configure failure if flag not supported.
AC_DEFUN([AX_ADD_COMPILER_FLAG],[
    AX_CHECK_COMPILE_FLAG([$1],[
        EXTRA_CFLAGS="$EXTRA_CFLAGS $1"
        AC_SUBST([EXTRA_CFLAGS])],[
        AS_IF([test x$2 != xrequired],[
            AC_MSG_WARN([Optional CFLAG "$1" not supported by your compiler, continuing.])],[
            AC_MSG_ERROR([Required CFLAG "$1" not supported by your compiler, aborting.])]
        )],[
        -Wall -Werror]
    )]
)
dnl AX_ADD_PREPROC_FLAG:
dnl   Add the provided preprocessor flag to the EXTRA_CFLAGS variable. This
dnl   macro will check to be sure the preprocessor supports the flag.
dnl   The flag can be made mandatory by providing the string 'required' as
dnl   the second parameter.
dnl $1: Preprocessor flag to add to EXTRA_CFLAGS.
dnl $2: Set to "required" t ocause configure failure if preprocesor flag
dnl     is not supported.
AC_DEFUN([AX_ADD_PREPROC_FLAG],[
    AX_CHECK_PREPROC_FLAG([$1],[
        EXTRA_CFLAGS="$EXTRA_CFLAGS $1"
        AC_SUBST([EXTRA_CFLAGS])],[
        AS_IF([test x$2 != xrequired],[
            AC_MSG_WARN([Optional preprocessor flag "$1" not supported by your compiler, continuing.])],[
            AC_MSG_ERROR([Required preprocessor flag "$1" not supported by your compiler, aborting.])]
        )],[
        -Wall -Werror]
    )]
)
dnl AX_ADD_LINK_FLAG:
dnl   A macro to add a LDLAG to the EXTRA_LDFLAGS variable. This macro will
dnl   check to be sure the linker supports the flag. Flags can be made
dnl   mandatory (configure will fail).
dnl $1: linker flag to add to EXTRA_LDFLAGS.
dnl $2: Set to "required" to cause configure failure if flag not supported.
AC_DEFUN([AX_ADD_LINK_FLAG],[
    AX_CHECK_LINK_FLAG([$1],[
        EXTRA_LDFLAGS="$EXTRA_LDFLAGS $1"
        AC_SUBST([EXTRA_LDFLAGS])],[
        AS_IF([test x$2 != xrequired],[
            AC_MSG_WARN([Optional LDFLAG "$1" not supported by your linker, continuing.])],[
            AC_MSG_ERROR([Required LDFLAG "$1" not supported by your linker, aborting.])]
        )]
    )]
)


================================================
FILE: man/tpm2tss-genkey.1.md
================================================
% tpm2tss-genkey(1) tpm2-tss-engine | General Commands Manual
%
% OCTOBER 2020

# NAME
**tpm2tss-genkey**(1) -- generate TPM keys for tpm2-tss-engine

# SYNOPSIS

**tpm2tss-genkey** [*options*] <*filename*>

# DESCRIPTION

**tpm2tss-genkey** creates a key inside a TPM 2.0 connected via the
tpm2tss software stack. Those keys may be an RSA key for decryption or signing
or an ECC key for ECDSA signatures.

The tool respects the OPENSSL_CONF option for specifying engine specific control
parameters. See `man(5) config` for details on openssl config files.

# ARGUMENTS

The `tpm2tss-genkey` command expects a filename for storing the resulting TPM
key information. This file can then be loaded with OpenSSL using
`openssl pkeyutl -engine tpm2tss -keyform engine -inkey <filename>`.

# OPTIONS

  * `-a <algorithm>`, `--alg <algorithm>`:
    The public key algorithm (rsa, ecdsa) (default: rsa)

  * `-c <curve>`, `--curve <curve>`:
    If alg ecdsa is chosen, the curve for ecc (default: nist_p256)

  * `-u <file>`, `--public <file>`:
    Public key (TPM2B_PUBLIC) to be imported. Requires `-r`.

  * `-r <file>`, `--private <file>`:
    The (encrypted) private key (TPM2B_PRIVATE) to be imported.
    Requires `-u`.

  * `-e <exponent>`, `--exponent <exponent>`:
    If alg rsa is chosen, the exponent for rsa (default: 65537)

  * `-h`, `--help`:
    Print help

  * `-o <password>`, `--ownerpw <password>`:
    Password for the owner hierarchy (default: none)
    Openssl Config control command: `SET_OWNERAUTH`

  * `-p <password>`, `--password <password>`:
    Password for the created key (default: none)

  * `-P <handle>`, `--parent <handle>`:
    Specific handle for the parent key (default: none)

  * `-s <keysize>`, `--keysize <keysize>`:
    If alg rsa is chosen, the key size in bits (default: 2048)

  * `-v`, `--verbose`:
    Print verbose messages

  * `-W <password>`, `--parentpw <password>`:
    Password for the parent key (default: none)
    Openssl Config control command: `SET_PARENTAUTH`

  * `-t <tcti-conf>`, `--tcti <tcti-conf>`:
    TCTI Configuration string (default: none)
    Openssl Config control command: `SET_TCTI`

# EXAMPLES

Engine information can be retrieved using:
```
$ openssl engine -t -c tpm2tss
```
The following sequence of commands creates an RSA key using the TPM, exports the
public key, encrypts a data file and decrypts it using the TPM:
```
$ tpm2tss-genkey -a rsa -s 2048 mykey
$ openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub
$ openssl pkeyutl -pubin -inkey mykey.pub -in mydata -encrypt -out mycipher
$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -decrypt -in mycipher -out mydata
```
The following sequence of commands creates an RSA key using the TPM, exports the
public key, signs a data file using the TPM and validates the signature:
```
$ tpm2tss-genkey -a rsa -s 2048 mykey
$ openssl rsa -engine tpm2tss -inform engine -in mykey -pubout -outform pem -out mykey.pub
$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig
$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig
```
The following sequence of commands creates an ECDSA key using the TPM, exports
the public key, signs a data file using the TPM and validates the signature:
```
$ tpm2tss-genkey -a ecdsa -c nist_p256 mykey
$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -sign -in mydata -out mysig
$ openssl pkeyutl -engine tpm2tss -keyform engine -inkey mykey -verify -in mydata -sigfile mysig
```

# RETURNS

0 on success or 1 on failure.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2017-2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1)



================================================
FILE: man/tpm2tss_ecc_genkey.3.md
================================================
% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls
%
% JUNE 2018

# NAME
**tpm2tss_ecc_genkey** -- Make an ECC key object

# SYNOPSIS

**#include <tpm2tss.h>**

**int tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password);**

# DESCRIPTION

**tpm2tss_ECC_genkey** issues the generation of an ECC key `key` using the TPM.
The ECC curve is determined by `curve`. The new key will be protected by
`password`.

# RETURN VALUE

Upon successful completion **tpm2tss_ecc_genkey**() returns 1. Otherwise 0.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1), tpm2tss_genkey(1)



================================================
FILE: man/tpm2tss_ecc_getappdata.3.md
================================================
% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls
%
% JUNE 2018

# NAME
**tpm2tss_ecc_getappdata**, **tpm2tss_ecc_setappdata** -- Make an ECC key object

# SYNOPSIS

**#include <tpm2tss.h>**

**TPM2_DATA * tpm2tss_ecc_getappdata(const EC_KEY *key);**

**int tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *data);**

# DESCRIPTION

**tpm2tss_ecc_getappdata** 

**tpm2tss_ecc_setappdata** 

# RETURN VALUE

Upon successful completion **tpm2tss_ecc_getappdata**() and
**tpm2tss_ecc_setappdata**() return 1. Otherwise 0.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1), tpm2tss_genkey(1)



================================================
FILE: man/tpm2tss_ecc_makekey.3.md
================================================
% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls
%
% JUNE 2018

# NAME
**tpm2tss_ecc_makekey** -- Make an ECC key object

# SYNOPSIS

**#include <tpm2tss.h>**

**EVP_PKEY * tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data);**

# DESCRIPTION

**tpm2tss_ecc_makekey** takes a TPM2_DATA object as `tpm2Data` and creates a
corresponding OpenSSL EVP_PKEY object.

# RETURN VALUE

Upon successful completion **tpm2tss_ecc_makekey**() returns the created
EVP_PKEY object's pointer. Otherwise NULL.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1)



================================================
FILE: man/tpm2tss_rsa_genkey.3.md
================================================
% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls
%
% JUNE 2018

# NAME
**tpm2tss_rsa_genkey** -- Make an RSA key object

# SYNOPSIS

**#include <tpm2tss.h>**

**int tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password);**

# DESCRIPTION

**tpm2tss_rsa_genkey** issues the generation of an RSA key `rsa` using the TPM.
The keylength is determined by `bits`. The exponent is determined by `e`.
The new key will be protected by `password`.

# RETURN VALUE

Upon successful completion **tpm2tss_rsa_genkey**() returns 1. Otherwise 0.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1), tpm2tss_genkey(1)



================================================
FILE: man/tpm2tss_rsa_makekey.3.md
================================================
% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls
%
% JUNE 2018

# NAME
**tpm2tss_rsa_makekey** -- Make an RSA key object

# SYNOPSIS

**#include <tpm2tss.h>**

**EVP_PKEY * tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data);**

# DESCRIPTION

**tpm2tss_rsa_makekey** takes a TPM2_DATA object as `tpm2Data` and creates a
corresponding OpenSSL EVP_PKEY object.

# RETURN VALUE

Upon successful completion **tpm2tss_rsa_makekey**() returns the created
EVP_PKEY object's pointer. Otherwise NULL.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1)



================================================
FILE: man/tpm2tss_tpm2data_write.3.md
================================================
% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls
%
% JUNE 2018

# NAME
**tpm2tss_tpm2data_write**, **tpm2tss_tpm2data_read** -- read/write TPM2_DATA

# SYNOPSIS

**#include <tpm2tss.h>**

**int tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap);**

**int tpm2tss_tpm2data_write(const TPM2_DATA *tpm2Data, const char *filename);**

# DESCRIPTION

**tpm2tss_tpm2data_read** reads the TPM2_DATA object from a file called
`filename`, allocates memory and stores it under the parameter `tpm2Datap`.
Must be freed using the `free()` function.

**tpm2tss_tpm2data_write** writes the TPM2_DATA object from the parameter
`tpm2Data` to a newly created file called `filename`.

# RETURN VALUE

Upon successful completion **tpm2tss_tpm2data_write**() and
**tpm2tss_tpm2data_read**() return 1. Otherwise 0.

## AUTHOR

Written by Andreas Fuchs.

## COPYRIGHT

tpm2tss is Copyright (C) 2018 Fraunhofer SIT sponsored by Infineon
Technologies AG. License BSD 3-clause.

## SEE ALSO

openssl(1)



================================================
FILE: openssl.conf.sample
================================================
openssl_conf = openssl_init

[openssl_init]
engines = engine_section

[engine_section]
tpm2tss = tpm2tss_section

[tpm2tss_section]
engine_id = tpm2tss
dynamic_path = /usr/lib/engines-1.1/libtpm2tss.so
default_algorithms = RSA
init = 1
#SET_TCTI = <TCTI_options>
#SET_OWNERAUTH = <could_set_password_here, but then it's readable>
#SET_PARENTAUTH = <password_of_parent_key> 

[req]
distinguished_name = subject

[subject]
# prompts and defaults here


================================================
FILE: src/tpm2-tss-engine-common.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 * Copyright (c) 2019, Wind River Systems.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <stdio.h>
#include <string.h>

#include <tss2/tss2_tctildr.h>

#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/rand.h>

#include "tpm2-tss-engine.h"
#include "tpm2-tss-engine-common.h"

ASN1_SEQUENCE(TSSPRIVKEY) = {
	ASN1_SIMPLE(TSSPRIVKEY, type, ASN1_OBJECT),
	ASN1_EXP_OPT(TSSPRIVKEY, emptyAuth, ASN1_BOOLEAN, 0),
	ASN1_SIMPLE(TSSPRIVKEY, parent, ASN1_INTEGER),
	ASN1_SIMPLE(TSSPRIVKEY, pubkey, ASN1_OCTET_STRING),
	ASN1_SIMPLE(TSSPRIVKEY, privkey, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(TSSPRIVKEY)

#define TSSPRIVKEY_PEM_STRING "TSS2 PRIVATE KEY"

IMPLEMENT_ASN1_FUNCTIONS(TSSPRIVKEY);
IMPLEMENT_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY);
IMPLEMENT_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY, TSSPRIVKEY_PEM_STRING, TSSPRIVKEY);

/** Initialize the Esys context
 *
 * Initialize an Esys context.
 * @param esys_ctx The context to initialize.
 * @retval TSS2_RC_SUCCESS on success
 * @retval TSS2_BASE_RC_BAD_REFERENCE if no pointer was provided
 * @retval Errors from Tcti initialization or Esys_Initialize()
 */
TSS2_RC
esys_ctx_init(ESYS_CONTEXT **esys_ctx)
{

    TSS2_RC r;
    if (!esys_ctx) {
        ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE);
        r = TSS2_BASE_RC_BAD_REFERENCE;
    } else {
        TSS2_TCTI_CONTEXT *tcti_ctx = NULL;

        r = Tss2_TctiLdr_Initialize(tcti_nameconf, &tcti_ctx);
        if (TSS2_RC_SUCCESS != r) {
            ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE);
        } else {
            r = Esys_Initialize(esys_ctx, tcti_ctx, NULL);
            if (TSS2_RC_SUCCESS != r) {
                ERR(esys_ctx_init, TPM2TSS_R_GENERAL_FAILURE);
                Tss2_TctiLdr_Finalize(&tcti_ctx);
            }
        }
    }
    return r;
}

/** Finalize the Esys context
 *
 * Get the TCTI context and finalize this alongside the Esys context.
 * @param esys_ctx The Esys context
 * @retval TSS2_RC_SUCCESS on success
 * @retval TSS2_BASE_RC_BAD_REFERENCE if no pointer was provided
 * @retval Errors from Esys_GetTcti()
 */
TSS2_RC
esys_ctx_free(ESYS_CONTEXT **esys_ctx)
{
    TSS2_RC r;
    if ((!esys_ctx) || (!*esys_ctx)) {
        ERR(esys_ctx_free, TPM2TSS_R_GENERAL_FAILURE);
        r = TSS2_BASE_RC_BAD_REFERENCE;
    } else {
        TSS2_TCTI_CONTEXT *tcti_ctx;
        r = Esys_GetTcti(*esys_ctx, &tcti_ctx);
        Esys_Finalize(esys_ctx);
        if (TSS2_RC_SUCCESS != r) {
            ERR(esys_ctx_free, TPM2TSS_R_GENERAL_FAILURE);
        } else {
            Tss2_TctiLdr_Finalize(&tcti_ctx);
        }
    }
    return r;
}

/** Serialize tpm2data onto disk
 *
 * Write the tpm2tss key data into a file using PEM encoding.
 * @param tpm2Data The data to be written to disk.
 * @param filename The filename to write the data to.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_tpm2data_write(const TPM2_DATA *tpm2Data, const char *filename)
{
    TSS2_RC r;
    BIO *bio = NULL;
    TSSPRIVKEY *tpk = NULL;
    BIGNUM *bn_parent = NULL;

    uint8_t privbuf[sizeof(tpm2Data->priv)];
    uint8_t pubbuf[sizeof(tpm2Data->pub)];
    size_t privbuf_len = 0, pubbuf_len = 0;

    if ((bio = BIO_new_file(filename, "w")) == NULL) {
        ERR(tpm2tss_tpm2data_write, TPM2TSS_R_FILE_WRITE);
        goto error;
    }

    tpk = TSSPRIVKEY_new();
    if (!tpk) {
        ERR(tpm2tss_tpm2data_write, ERR_R_MALLOC_FAILURE);
        goto error;
    }

    r = Tss2_MU_TPM2B_PRIVATE_Marshal(&tpm2Data->priv, &privbuf[0],
                                      sizeof(privbuf), &privbuf_len);
    if (r) {
        ERR(tpm2tss_tpm2data_write, TPM2TSS_R_DATA_CORRUPTED);
        goto error;
    }

    r = Tss2_MU_TPM2B_PUBLIC_Marshal(&tpm2Data->pub, &pubbuf[0],
                                     sizeof(pubbuf), &pubbuf_len);
    if (r) {
        ERR(tpm2tss_tpm2data_write, TPM2TSS_R_DATA_CORRUPTED);
        goto error;
    }
    tpk->type = OBJ_txt2obj(OID_loadableKey, 1);
    tpk->parent = ASN1_INTEGER_new();
    tpk->privkey = ASN1_OCTET_STRING_new();
    tpk->pubkey = ASN1_OCTET_STRING_new();
    if (!tpk->type || !tpk->privkey || !tpk->pubkey || !tpk->parent) {
        ERR(tpm2tss_tpm2data_write, ERR_R_MALLOC_FAILURE);
        goto error;
    }

    tpk->emptyAuth = tpm2Data->emptyAuth ? 0xFF : 0;
    bn_parent = BN_new();
    if (!bn_parent) {
        goto error;
    }
    if (tpm2Data->parent != 0) {
        BN_set_word(bn_parent, tpm2Data->parent);
    } else {
        BN_set_word(bn_parent, TPM2_RH_OWNER);
    }
    BN_to_ASN1_INTEGER(bn_parent, tpk->parent);
    ASN1_STRING_set(tpk->privkey, &privbuf[0], privbuf_len);
    ASN1_STRING_set(tpk->pubkey, &pubbuf[0], pubbuf_len);

    PEM_write_bio_TSSPRIVKEY(bio, tpk);
    TSSPRIVKEY_free(tpk);
    BIO_free(bio);

    return 1;
 error:
    if (bio)
        BIO_free(bio);
    if (tpk)
        TSSPRIVKEY_free(tpk);
    return 0;
}

/** Create tpm2data from a TPM key
 *
 * Retrieve the public key of tpm2data from the TPM for a given handle.
 * @param handle The TPM's key handle.
 * @param tpm2Datap The data after read.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_tpm2data_readtpm(uint32_t handle, TPM2_DATA **tpm2Datap)
{
    TSS2_RC r;
    TPM2_DATA *tpm2Data = NULL;
    ESYS_TR keyHandle = ESYS_TR_NONE;
    ESYS_CONTEXT *esys_ctx = NULL;
    TPM2B_PUBLIC *outPublic;

    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));
    if (tpm2Data == NULL) {
        ERR(tpm2tss_tpm2data_readtpm, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    memset(tpm2Data, 0, sizeof(*tpm2Data));

    tpm2Data->privatetype = KEY_TYPE_HANDLE;
    tpm2Data->handle = handle;

    r = esys_ctx_init(&esys_ctx);
    if (r) {
        ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    r = Esys_TR_FromTPMPublic(esys_ctx, tpm2Data->handle,
                              ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                              &keyHandle);
    if (r) {
        ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    r = Esys_ReadPublic(esys_ctx, keyHandle,
                        ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                        &outPublic, NULL, NULL);
    if (r) {
        ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    /* If the persistent key has the NODA flag set, we check whether it does
       have an empty authValue. If NODA is not set, then we don't check because
       that would increment the DA lockout counter */
    if ((outPublic->publicArea.objectAttributes & TPMA_OBJECT_NODA) != 0) {
        ESYS_TR session;
        TPMT_SYM_DEF sym = {.algorithm = TPM2_ALG_AES,
                            .keyBits = {.aes = 128},
                            .mode = {.aes = TPM2_ALG_CFB}
        };

        /* Esys_StartAuthSession() and session handling use OpenSSL for random
           bytes and thus might end up inside this engine again. This becomes
           a problem if we have no resource manager, i.e. the tpm simulator. */
        const RAND_METHOD *rand_save = RAND_get_rand_method();
#if OPENSSL_VERSION_NUMBER < 0x10100000
        RAND_set_rand_method(RAND_SSLeay());
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
        RAND_set_rand_method(RAND_OpenSSL());
#endif

        /* We do the check by starting a bound audit session and executing a
           very cheap command. */
        r = Esys_StartAuthSession(esys_ctx, ESYS_TR_NONE, keyHandle,
                                  ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                                  NULL, TPM2_SE_HMAC, &sym, TPM2_ALG_SHA256,
                                  &session);
        /* Though this response code is sub-optimal, it's the only way to
           detect the bug in ESYS. */
        if (r == TSS2_ESYS_RC_GENERAL_FAILURE) {
            DBG("Running tpm2-tss < 2.2 which has a bug here. Requiring auth.");
            tpm2Data->emptyAuth = 0;
            goto session_error;
        } else if (r) {
            ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);
            goto error;
        }
        Esys_TRSess_SetAttributes(esys_ctx, session,
                                  TPMA_SESSION_ENCRYPT, TPMA_SESSION_ENCRYPT);
        Esys_TRSess_SetAttributes(esys_ctx, session,
                                  TPMA_SESSION_CONTINUESESSION,
                                  TPMA_SESSION_CONTINUESESSION);

        r = Esys_ReadPublic(esys_ctx, keyHandle,
                            session, ESYS_TR_NONE, ESYS_TR_NONE,
                            NULL, NULL, NULL);

        RAND_set_rand_method(rand_save);

        /* tpm2-tss < 2.2 has some bugs. (1) it may miscalculate the auth from
           above leading to a password query in case of empty auth and (2) it
           may return an error because the object's auth value is "\0". */
        if (r == TSS2_RC_SUCCESS) {
            DBG("Object does not require auth");
            tpm2Data->emptyAuth = 1;
        } else if (r == (TPM2_RC_BAD_AUTH | TPM2_RC_S | TPM2_RC_1)) {
            DBG("Object does require auth");
            tpm2Data->emptyAuth = 0;
        } else {
            ERR(tpm2tss_tpm2data_readtpm, TPM2TSS_R_GENERAL_FAILURE);
            goto error;
        }

        Esys_FlushContext (esys_ctx, session);
    }

session_error:

    Esys_TR_Close(esys_ctx, &keyHandle);

    esys_ctx_free(&esys_ctx);
    tpm2Data->pub = *outPublic;
    Esys_Free(outPublic);

    *tpm2Datap = tpm2Data;
    return 1;
 error:
    if (keyHandle != ESYS_TR_NONE)
        Esys_TR_Close(esys_ctx, &keyHandle);
    esys_ctx_free(&esys_ctx);
    if (tpm2Data)
        OPENSSL_free(tpm2Data);
    return 0;
}

/** Deserialize tpm2data from disk
 *
 * Read the tpm2tss key data from a file using PEM encoding.
 * @param filename The filename to read the data from.
 * @param tpm2Datap The data after read.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_tpm2data_read(const char *filename, TPM2_DATA **tpm2Datap)
{
    TSS2_RC r;
    BIO *bio = NULL;
    TSSPRIVKEY *tpk = NULL;
    TPM2_DATA *tpm2Data = NULL;
    char type_oid[64];
    BIGNUM *bn_parent;

    if ((bio = BIO_new_file(filename, "r")) == NULL) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);
        goto error;
    }

    tpk = PEM_read_bio_TSSPRIVKEY(bio, NULL, NULL, NULL);
    if (!tpk) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED);
        goto error;
    }
    BIO_free(bio);
    bio = NULL;

    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));
    if (tpm2Data == NULL) {
        ERR(tpm2tss_tpm2data_read, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    memset(tpm2Data, 0, sizeof(*tpm2Data));

    tpm2Data->privatetype = KEY_TYPE_BLOB;

    tpm2Data->emptyAuth = !!tpk->emptyAuth;

    bn_parent = ASN1_INTEGER_to_BN(tpk->parent, NULL);
    if (!bn_parent) {
        goto error;
    }
    if (BN_is_negative(bn_parent)) {
        tpm2Data->parent = ASN1_INTEGER_get(tpk->parent);
    } else {
        tpm2Data->parent = BN_get_word(bn_parent);
    }
    if (tpm2Data->parent == 0)
        tpm2Data->parent = TPM2_RH_OWNER;

    if (!OBJ_obj2txt(type_oid, sizeof(type_oid), tpk->type, 1) ||
        strcmp(type_oid, OID_loadableKey)) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_CANNOT_MAKE_KEY);
        goto error;
    }
    r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(tpk->privkey->data,
                                        tpk->privkey->length, NULL,
                                        &tpm2Data->priv);
    if (r) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED);
        goto error;
    }
    r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(tpk->pubkey->data, tpk->pubkey->length,
                                       NULL, &tpm2Data->pub);
    if (r) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_DATA_CORRUPTED);
        goto error;
    }

    TSSPRIVKEY_free(tpk);

    *tpm2Datap = tpm2Data;
    return 1;
 error:
    if (tpm2Data)
        OPENSSL_free(tpm2Data);
    if (bio)
        BIO_free(bio);
    if (tpk)
        TSSPRIVKEY_free(tpk);

    return 0;
}

static TPM2B_PUBLIC primaryEccTemplate = TPM2B_PUBLIC_PRIMARY_ECC_TEMPLATE;
static TPM2B_PUBLIC primaryRsaTemplate = TPM2B_PUBLIC_PRIMARY_RSA_TEMPLATE;

static TPM2B_SENSITIVE_CREATE primarySensitive = {
    .sensitive = {
        .userAuth = {
             .size = 0,
         },
        .data = {
             .size = 0,
         }
    }
};

static TPM2B_DATA allOutsideInfo = {
    .size = 0,
};

static TPML_PCR_SELECTION allCreationPCR = {
    .count = 0,
};

/** Initialize the ESYS TPM connection and primary/persistent key
 *
 * Establish a connection with the TPM using ESYS libraries and create a primary
 * key under the owner hierarchy or to initialize the ESYS object for a
 * persistent if provided.
 * @param esys_ctx The resulting ESYS context.
 * @param parentHandle The TPM handle of a persistent key or TPM2_RH_OWNER or 0
 * @param parent The resulting ESYS_TR handle for the parent key.
 * @retval TSS2_RC_SUCCESS on success
 * @retval TSS2_RCs according to the error
 */
TSS2_RC
init_tpm_parent(ESYS_CONTEXT **esys_ctx,
                TPM2_HANDLE parentHandle, ESYS_TR *parent)
{
    TSS2_RC r;
    TPM2B_PUBLIC *primaryTemplate = NULL;
    TPMS_CAPABILITY_DATA *capabilityData = NULL;
    UINT32 index;
    *parent = ESYS_TR_NONE;
    *esys_ctx = NULL;

    DBG("Establishing connection with TPM.\n");
    r = esys_ctx_init(esys_ctx);
    ERRchktss(init_tpm_parent, r, goto error);

    if (parentHandle && parentHandle != TPM2_RH_OWNER) {
        DBG("Connecting to a persistent parent key.\n");
        r = Esys_TR_FromTPMPublic(*esys_ctx, parentHandle,
                                  ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                                  parent);
        ERRchktss(init_tpm_parent, r, goto error);

        r = Esys_TR_SetAuth(*esys_ctx, *parent, &parentauth);
        ERRchktss(init_tpm_parent, r, goto error);

        return TSS2_RC_SUCCESS;
    }

    DBG("Creating primary key under owner.\n");
    r = Esys_TR_SetAuth(*esys_ctx, ESYS_TR_RH_OWNER, &ownerauth);
    ERRchktss(init_tpm_parent, r, goto error);

    r = Esys_GetCapability (*esys_ctx,
                            ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                            TPM2_CAP_ALGS, 0, TPM2_MAX_CAP_ALGS,
                            NULL, &capabilityData);
    ERRchktss(init_tpm_parent, r, goto error);

    for (index = 0; index < capabilityData->data.algorithms.count; index++) {
        if (capabilityData->data.algorithms.algProperties[index].alg == TPM2_ALG_ECC) {
            primaryTemplate = &primaryEccTemplate;
            break;
        }
    }

    /*
     * TPM2_ALG_ECC is *mandatory* for TPM2.0; the above should never
     * fail. However, *if* such a broken TPM is used then ephemeral
     * primaries according to the TSS2 PEM file standard can *never*
     * have worked on that hardware, so it isn't *breaking* anything
     * for us to unilaterally use an ephemeral RSA parent in this case
     * instead.
     *
     * However, it may not be interoperable to do so, and it isn't a
     * good idea anyway since RSA keys are *slow* to generate, so
     * users with a broken TPM like this really *should* have followed
     * the recommendation to create the RSA primary and store it in
     * the NVRAM at 0x81000001. And then the TSS2 PEM keys should use
     * *that* as the parent, not the ephemeral version. In fact, there
     * is a strong case to be made for defaulting to 0x81000001 if it
     * exists, *before* (or never) falling back to generating an RSA
     * key here.
     */
    if (primaryTemplate == NULL) {
        for (index = 0; index < capabilityData->data.algorithms.count; index++) {
            if (capabilityData->data.algorithms.algProperties[index].alg == TPM2_ALG_RSA) {
                primaryTemplate = &primaryRsaTemplate;
                break;
            }
        }
    }

    Esys_Free (capabilityData);

    if (primaryTemplate == NULL) {
        ERR(init_tpm_parent, TPM2TSS_R_UNKNOWN_ALG);
        goto error;
    }

    r = Esys_CreatePrimary(*esys_ctx, ESYS_TR_RH_OWNER,
                           ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                           &primarySensitive, primaryTemplate, &allOutsideInfo,
                           &allCreationPCR,
                           parent, NULL, NULL, NULL, NULL);
    if (r == 0x000009a2) {
        ERR(init_tpm_parent, TPM2TSS_R_OWNER_AUTH_FAILED);
        goto error;
    }
    ERRchktss(init_tpm_parent, r, goto error);

    return TSS2_RC_SUCCESS;
 error:
    if (*parent != ESYS_TR_NONE)
        Esys_FlushContext(*esys_ctx, *parent);
    *parent = ESYS_TR_NONE;

    esys_ctx_free(esys_ctx);
    return r;
}

/** Initialize the ESYS TPM connection and load the key
 *
 * Establish a connection with the TPM using ESYS libraries, create a primary
 * key under the owner hierarchy and then load the TPM key and set its auth
 * value.
 * @param esys_ctx The ESYS_CONTEXT to be populated.
 * @param keyHandle The resulting handle for the key key.
 * @param tpm2Data The key data, owner auth and key auth to be used
 * @retval TSS2_RC_SUCCESS on success
 * @retval TSS2_RCs according to the error
 */
TSS2_RC
init_tpm_key (ESYS_CONTEXT **esys_ctx, ESYS_TR *keyHandle, TPM2_DATA *tpm2Data)
{
    TSS2_RC r;
    ESYS_TR parent = ESYS_TR_NONE;
    *keyHandle = ESYS_TR_NONE;
    *esys_ctx = NULL;

    if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {
        DBG("Establishing connection with TPM.\n");
        r = esys_ctx_init(esys_ctx);
        ERRchktss(init_tpm_key, r, goto error);

        r = Esys_TR_FromTPMPublic(*esys_ctx, tpm2Data->handle,
                                  ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                                  keyHandle);
        ERRchktss(init_tpm_key, r, goto error);
    } else if (tpm2Data->privatetype == KEY_TYPE_BLOB
               && tpm2Data->parent != TPM2_RH_OWNER) {
        r = init_tpm_parent(esys_ctx, tpm2Data->parent, &parent);
        ERRchktss(init_tpm_key, r, goto error);

        DBG("Loading key blob.\n");
        r = Esys_Load(*esys_ctx, parent,
                      ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                      &tpm2Data->priv, &tpm2Data->pub, keyHandle);
        Esys_TR_Close(*esys_ctx, &parent);
        ERRchktss(init_tpm_key, r, goto error);
    } else if (tpm2Data->privatetype == KEY_TYPE_BLOB) {
        r = init_tpm_parent(esys_ctx, 0, &parent);
        ERRchktss(init_tpm_key, r, goto error);

        DBG("Loading key blob.\n");
        r = Esys_Load(*esys_ctx, parent,
                      ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                      &tpm2Data->priv, &tpm2Data->pub, keyHandle);
        ERRchktss(init_tpm_key, r, goto error);

        r = Esys_FlushContext(*esys_ctx, parent);
        ERRchktss(rsa_priv_enc, r, goto error);
        parent = ESYS_TR_NONE;
    } else {
        r = -1;
        ERR(init_tpm_key, TPM2TSS_R_TPM2DATA_READ_FAILED);
        goto error;
    }

    r = Esys_TR_SetAuth(*esys_ctx, *keyHandle, &tpm2Data->userauth);
    ERRchktss(init_tpm_key, r, goto error);

    return TSS2_RC_SUCCESS;
 error:
    if (parent != ESYS_TR_NONE)
        Esys_FlushContext(*esys_ctx, parent);
    if (*keyHandle != ESYS_TR_NONE)
        Esys_FlushContext(*esys_ctx, *keyHandle);
    *keyHandle = ESYS_TR_NONE;

    esys_ctx_free(esys_ctx);
    return r;
}

/** Deserialize a tpm key from disk
 *
 * Read a tpm key as marshaled TPM2B_PUBLIC and (encrypted) TPM2B_PRIVATE from
 * disk and convert them into a TPM2_DATA representation
 * @param filenamepub The filename to read the public portion from.
 * @param filenametpm The filename to read the private portion from.
 * @param parent Handle of the parent key.
 * @param emptyAuth Whether the object does not require authentication.
 * @param tpm2Datap The data after read.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_tpm2data_importtpm(const char *filenamepub, const char *filenametpm,
                           TPM2_HANDLE parent, int emptyAuth,
                           TPM2_DATA **tpm2Datap)
{
    TSS2_RC r;
    BIO *bio;
    TPM2_DATA *tpm2data;
    int filepub_size, filepriv_size;

    uint8_t filepub[sizeof(TPM2B_PUBLIC)];
    uint8_t filepriv[sizeof(TPM2B_PRIVATE)];

    if ((bio = BIO_new_file(filenamepub, "r")) == NULL) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);
        return 0;
    }
    filepub_size = BIO_read(bio, &filepub[0], sizeof(filepub));
    BIO_free(bio);
    if (filepub_size < 0) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);
        return 0;
    }

    if ((bio = BIO_new_file(filenametpm, "r")) == NULL) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);
        return 0;
    }
    filepriv_size = BIO_read(bio, &filepriv[0], sizeof(filepriv));
    BIO_free(bio);
    if (filepriv_size < 0) {
        ERR(tpm2tss_tpm2data_read, TPM2TSS_R_FILE_READ);
        return 0;
    }

    tpm2data = OPENSSL_malloc(sizeof(TPM2_DATA));
    if (!tpm2data)
        return 0;

    memset(tpm2data, 0, sizeof(*tpm2data));
    tpm2data->privatetype = KEY_TYPE_BLOB;
    tpm2data->parent = parent;
    tpm2data->emptyAuth = emptyAuth;

    r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(&filepub[0], filepub_size, NULL,
                                       &tpm2data->pub);
    ERRchktss(tpm2tss_tpm2data_read, r, goto error);

    r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(&filepriv[0], filepriv_size, NULL,
                                        &tpm2data->priv);
    ERRchktss(tpm2tss_tpm2data_read, r, goto error);

    *tpm2Datap = tpm2data;
    return 1;

  error:
    OPENSSL_free(tpm2data);
    return 0;
}


================================================
FILE: src/tpm2-tss-engine-common.h
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 * Copyright (c) 2019, Wind River Systems.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
#ifndef TPM2_TSS_ENGINE_COMMON_H
#define TPM2_TSS_ENGINE_COMMON_H

#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \
    && !defined(__STDC_NO_ATOMICS__)
# include <stdatomic.h>
# define TPM2_TSS_ENGINE_HAVE_C11_ATOMICS
typedef _Atomic int T2TE_ATOMIC_INT;
#else
typedef int T2TE_ATOMIC_INT;
#endif

#include <tpm2-tss-engine.h>
#include <tss2/tss2_mu.h>
#include <tss2/tss2_esys.h>

#include "tpm2-tss-engine-err.h"

#include <openssl/asn1t.h>
#include <openssl/asn1.h>
#include <openssl/pem.h>

extern TPM2B_DIGEST ownerauth;
extern TPM2B_DIGEST parentauth;

extern char *tcti_nameconf;

int init_ecc(ENGINE *e);
int init_rand(ENGINE *e);
int init_rsa(ENGINE *e);

TSS2_RC esys_ctx_init (ESYS_CONTEXT **esys_ctx);

TSS2_RC esys_ctx_free (ESYS_CONTEXT **esys_ctx);

TSS2_RC init_tpm_parent (   ESYS_CONTEXT **esys_ctx,
                            TPM2_HANDLE  parentHandle,
                            ESYS_TR      *parent);

TSS2_RC init_tpm_key (  ESYS_CONTEXT **esys_ctx,
                        ESYS_TR      *keyHandle,
                        TPM2_DATA    *tpm2Data);

#define ENGINE_HASH_ALG TPM2_ALG_SHA256

#define TPM2B_PUBLIC_PRIMARY_RSA_TEMPLATE { \
    .publicArea = { \
        .type = TPM2_ALG_RSA, \
        .nameAlg = ENGINE_HASH_ALG, \
        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | \
                             TPMA_OBJECT_RESTRICTED | \
                             TPMA_OBJECT_DECRYPT | \
                             TPMA_OBJECT_NODA | \
                             TPMA_OBJECT_FIXEDTPM | \
                             TPMA_OBJECT_FIXEDPARENT | \
                             TPMA_OBJECT_SENSITIVEDATAORIGIN), \
        .authPolicy = { \
             .size = 0, \
         }, \
        .parameters.rsaDetail = { \
             .symmetric = { \
                 .algorithm = TPM2_ALG_AES, \
                 .keyBits.aes = 128, \
                 .mode.aes = TPM2_ALG_CFB, \
              }, \
             .scheme = { \
                .scheme = TPM2_ALG_NULL, \
                .details = {} \
             }, \
             .keyBits = 2048, \
             .exponent = 0,\
         }, \
        .unique.rsa = { \
             .size = 0, \
         } \
     } \
}

/*
 * The parameters of this key can never be changed because they are
 * part of the interoperable 'standard' form for TSS2 PEM keys.
 * Where the parent key is ephemeral and generated on demand, it
 * has to be generated precisely the *same* every time or it cannot
 * work. The ECC primary is used for *all* keys regardless of their
 * type.
 */
#define TPM2B_PUBLIC_PRIMARY_ECC_TEMPLATE { \
    .publicArea = { \
        .type = TPM2_ALG_ECC, \
        .nameAlg = ENGINE_HASH_ALG, \
        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH | \
                             TPMA_OBJECT_RESTRICTED | \
                             TPMA_OBJECT_DECRYPT | \
                             TPMA_OBJECT_NODA | \
                             TPMA_OBJECT_FIXEDTPM | \
                             TPMA_OBJECT_FIXEDPARENT | \
                             TPMA_OBJECT_SENSITIVEDATAORIGIN), \
        .authPolicy = { \
             .size = 0, \
         }, \
        .parameters.eccDetail = { \
             .symmetric = { \
                 .algorithm = TPM2_ALG_AES, \
                 .keyBits.aes = 128, \
                 .mode.aes = TPM2_ALG_CFB, \
              }, \
             .scheme = { \
                .scheme = TPM2_ALG_NULL, \
                .details = {} \
             }, \
             .curveID = TPM2_ECC_NIST_P256, \
             .kdf = { \
                .scheme = TPM2_ALG_NULL, \
                .details = {} \
             }, \
         }, \
        .unique.ecc = { \
             .x.size = 0, \
             .y.size = 0 \
         } \
     } \
}

typedef struct {
	ASN1_OBJECT *type;
	ASN1_BOOLEAN emptyAuth;
	ASN1_INTEGER *parent;
	ASN1_OCTET_STRING *pubkey;
	ASN1_OCTET_STRING *privkey;
} TSSPRIVKEY;


DECLARE_ASN1_FUNCTIONS(TSSPRIVKEY);

DECLARE_PEM_write_bio(TSSPRIVKEY, TSSPRIVKEY);
DECLARE_PEM_read_bio(TSSPRIVKEY, TSSPRIVKEY);

#define OID_loadableKey "2.23.133.10.1.3"

typedef struct {
    T2TE_ATOMIC_INT refcount;
    ESYS_CONTEXT *esys_ctx;
    ESYS_TR key_handle;
    int privatetype;
} TPM2_SIG_KEY_CTX;

typedef struct {
    TPM2_SIG_KEY_CTX *key;
    TPM2_ALG_ID hash_alg;
    ESYS_TR seq_handle;
    size_t sig_size;
} TPM2_SIG_DATA;

int
digest_update(EVP_MD_CTX *ctx, const void *data, size_t count);
int
digest_finish(TPM2_SIG_DATA *data, TPM2B_DIGEST **digest,
              TPMT_TK_HASHCHECK **validation);
int
digest_sign_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx, TPM2_DATA *tpm2data,
                 size_t sig_size);
int
digest_sign_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src);
void
digest_sign_cleanup(EVP_PKEY_CTX *ctx);

#endif /* TPM2_TSS_ENGINE_COMMON_H */


================================================
FILE: src/tpm2-tss-engine-digest-sign.c
================================================
/*******************************************************************************
 * Copyright 2021, Graphiant, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <string.h>

#include <openssl/evp.h>

#include <tss2/tss2_esys.h>

#include "tpm2-tss-engine-common.h"

#ifndef TPM2_TSS_ENGINE_HAVE_C11_ATOMICS
/* fall back to using GCC/clang atomic builtins */
# define atomic_fetch_add(PTR, VAL) \
    __atomic_fetch_add((PTR), (VAL), __ATOMIC_SEQ_CST)
#define atomic_fetch_sub(PTR, VAL) \
    __atomic_fetch_sub ((PTR), (VAL), __ATOMIC_SEQ_CST)
#endif /* TPM2_TSS_ENGINE_HAVE_C11_ATOMICS */

/**
 * Initialise a digest operation for digest and sign.
 *
 * @param ctx OpenSSL message digest context
 * @param data Digest and sign data
 * @retval 1 on success
 * @retval 0 on failure
 */
static int
digest_init(EVP_MD_CTX *ctx, TPM2_SIG_DATA *data)
{
    TPM2B_AUTH null_auth = { .size = 0 };
    const EVP_MD *md;
    TSS2_RC r;

    md = EVP_MD_CTX_md(ctx);
    if (!md) {
        ERR(digest_init, TPM2TSS_R_GENERAL_FAILURE);
        return 0;
    }

    switch (EVP_MD_type(md)) {
    case NID_sha1:
        data->hash_alg = TPM2_ALG_SHA1;
        break;
    case NID_sha256:
        data->hash_alg = TPM2_ALG_SHA256;
        break;
    case NID_sha384:
        data->hash_alg = TPM2_ALG_SHA384;
        break;
    case NID_sha512:
        data->hash_alg = TPM2_ALG_SHA512;
        break;
    default:
        ERR(digest_init, TPM2TSS_R_UNKNOWN_ALG);
        return 0;
    }

    r = Esys_HashSequenceStart(data->key->esys_ctx, ESYS_TR_NONE,
                               ESYS_TR_NONE, ESYS_TR_NONE, &null_auth,
                               data->hash_alg, &data->seq_handle);
    ERRchktss(digest_init, r, return 0);

    return 1;
}

/**
 * Update a digest with more data
 *
 * @param ctx OpenSSL message digest context
 * @param data Data to add to digest
 * @param count Length of data to add
 * @retval 1 on success
 * @retval 0 on failure
 */
int
digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
{
    EVP_PKEY_CTX *pctx = EVP_MD_CTX_pkey_ctx(ctx);
    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(pctx);
    const uint8_t *current_data = data;
    TSS2_RC r;

    DBG("digest_update %p %p\n", pctx, ctx);

    while (count > 0) {
        TPM2B_MAX_BUFFER digest_data = { .size = count };
        if (digest_data.size > sizeof(digest_data.buffer))
            digest_data.size = sizeof(digest_data.buffer);
        memcpy(&digest_data.buffer[0], current_data, digest_data.size);
        current_data += digest_data.size;
        count -= digest_data.size;

        r = Esys_SequenceUpdate(sig_data->key->esys_ctx, sig_data->seq_handle,
                                ESYS_TR_PASSWORD, ESYS_TR_NONE,
                                ESYS_TR_NONE, &digest_data);
        ERRchktss(digest_update, r, return 0);
    }

    return 1;
}

/**
 * Finish a digest operation for digest and sign
 *
 * @param data Digest and sign data
 * @param digest Digest calculated by TPM
 * @param validation Validation ticket for the digest calculated by TPM
 * @retval 1 on success
 * @retval 0 on failure
 */
int
digest_finish(TPM2_SIG_DATA *data, TPM2B_DIGEST **digest,
              TPMT_TK_HASHCHECK **validation)
{
    TSS2_RC r;

    r = Esys_SequenceComplete(data->key->esys_ctx, data->seq_handle,
                              ESYS_TR_PASSWORD, ESYS_TR_NONE,
                              ESYS_TR_NONE, NULL, ESYS_TR_RH_OWNER,
                              digest, validation);
    ERRchktss(digest_finish, r, return 0);

    /* Esys_SequenceComplete consumes the handle */
    data->seq_handle = ESYS_TR_NONE;

    return 1;
}

/**
 * Initialise a digest and sign operation
 *
 * @param ctx OpenSSL pkey context
 * @param mctx OpenSSL message digest context
 * @param tpm2data TPM data for the key to use
 * @param sig_size Size of the signature data
 * @retval 1 on success
 * @retval 0 on failure
 */
int
digest_sign_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx, TPM2_DATA *tpm2data,
                 size_t sig_size)
{
    TSS2_RC r;

    if (!tpm2data)
        /* non-TPM key - nothing to do */
        return 1;

    TPM2_SIG_DATA *data = OPENSSL_malloc(sizeof(*data));
    if (!data) {
        ERR(digest_sign_init, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    data->seq_handle = ESYS_TR_NONE;
    data->sig_size = sig_size;

    data->key = OPENSSL_malloc(sizeof(*data->key));
    if (!data->key) {
        ERR(digest_sign_init, ERR_R_MALLOC_FAILURE);
        goto error;
    }

    data->key->refcount = 1;

    r = init_tpm_key(&data->key->esys_ctx, &data->key->key_handle, tpm2data);
    ERRchktss(digest_sign_init, r, goto error);
    data->key->privatetype = tpm2data->privatetype;

    EVP_PKEY_CTX_set_app_data(ctx, data);
    /*
     * Override the update function so that the TPM performs the
     * digest, which is required for restricted keys - the TPM will
     * reject a null validation ticket in this case for the signing
     * operation.
     */
    EVP_MD_CTX_set_update_fn(mctx, digest_update);

    if (!digest_init(mctx, data))
        goto error;

    return 1;

 error:
    if (data->key) {
        if (data->key->key_handle != ESYS_TR_NONE) {
            if (data->key->privatetype == KEY_TYPE_HANDLE) {
                Esys_TR_Close(data->key->esys_ctx, &data->key->key_handle);
            } else {
                Esys_FlushContext(data->key->esys_ctx, data->key->key_handle);
            }
        }
        if (data->key->esys_ctx)
            esys_ctx_free(&data->key->esys_ctx);
        OPENSSL_free(data->key);
    }
    OPENSSL_free(data);
    return 0;
}

/**
 * Copy digest and sign context
 *
 * @param dst Destination OpenSSL pkey context
 * @param src Source OpenSSL pkey context
 * @retval 1 on success
 * @retval 0 on failure
 */
int
digest_sign_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src)
{
    TPM2_SIG_DATA *src_sig_data = EVP_PKEY_CTX_get_app_data(src);
    TPMS_CONTEXT *context = NULL;
    TPM2_SIG_DATA *dst_sig_data = NULL;
    TSS2_RC r;

    if (src_sig_data) {
        dst_sig_data = OPENSSL_malloc(sizeof(*dst_sig_data));
        if (!dst_sig_data) {
            ERR(digest_sign_copy, ERR_R_MALLOC_FAILURE);
            return 0;
        }

        dst_sig_data->hash_alg = src_sig_data->hash_alg;
        dst_sig_data->sig_size = src_sig_data->sig_size;

        if (src_sig_data->seq_handle != ESYS_TR_NONE) {
            /* duplicate sequence handle */

            r = Esys_ContextSave(src_sig_data->key->esys_ctx,
                                 src_sig_data->seq_handle, &context);
            ERRchktss(digest_sign_copy, r, goto error);
            dst_sig_data->seq_handle = ESYS_TR_NONE;
            r = Esys_ContextLoad(src_sig_data->key->esys_ctx, context,
                                 &dst_sig_data->seq_handle);
            ERRchktss(digest_sign_copy, r, goto error);
        }

        dst_sig_data->key = src_sig_data->key;
        atomic_fetch_add(&dst_sig_data->key->refcount, 1);

        EVP_PKEY_CTX_set_app_data(dst, dst_sig_data);
    }

    Esys_Free(context);
    return 1;

 error:
    Esys_Free(context);
    OPENSSL_free(dst_sig_data);
    return 0;
}

/**
 * Clean up digest and sign context
 *
 * @param ctx OpenSSL pkey context
 * @retval 1 on success
 * @retval 0 on failure
 */
void
digest_sign_cleanup(EVP_PKEY_CTX *ctx)
{
    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx);

    if (sig_data) {
        if (sig_data->seq_handle != ESYS_TR_NONE)
            Esys_FlushContext(sig_data->key->esys_ctx, sig_data->seq_handle);

        if (atomic_fetch_sub(&sig_data->key->refcount, 1) == 1) {
            if (sig_data->key->key_handle != ESYS_TR_NONE) {
                if (sig_data->key->privatetype == KEY_TYPE_HANDLE) {
                    Esys_TR_Close(sig_data->key->esys_ctx,
                                  &sig_data->key->key_handle);
                } else {
                    Esys_FlushContext(sig_data->key->esys_ctx,
                                      sig_data->key->key_handle);
                }
            }
            esys_ctx_free(&sig_data->key->esys_ctx);
            OPENSSL_free(sig_data->key);
        }
        OPENSSL_free(sig_data);
        EVP_PKEY_CTX_set_app_data(ctx, NULL);
    }
}


================================================
FILE: src/tpm2-tss-engine-ecc.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <string.h>

#include <openssl/engine.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>

#include <tss2/tss2_mu.h>
#include <tss2/tss2_esys.h>

#include "tpm2-tss-engine.h"
#include "tpm2-tss-engine-common.h"

static int ec_key_app_data = -1;

#if OPENSSL_VERSION_NUMBER < 0x10100000
const ECDSA_METHOD *ecc_method_default = NULL;
ECDSA_METHOD *ecc_methods = NULL;
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
const EC_KEY_METHOD *ecc_method_default = NULL;
EC_KEY_METHOD *ecc_methods = NULL;
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

#ifdef HAVE_OPENSSL_DIGEST_SIGN
static int (*ecdsa_pkey_orig_copy)(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src);
static void (*ecdsa_pkey_orig_cleanup)(EVP_PKEY_CTX *ctx);
#endif /* HAVE_OPENSSL_DIGEST_SIGN */

static TPM2B_DATA allOutsideInfo = {
    .size = 0,
};

static TPML_PCR_SELECTION allCreationPCR = {
    .count = 0,
};

static TPM2B_PUBLIC keyEcTemplate = {
    .publicArea = {
        .type = TPM2_ALG_ECC,
        .nameAlg = ENGINE_HASH_ALG,
        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
                             TPMA_OBJECT_SIGN_ENCRYPT |
                             TPMA_OBJECT_FIXEDTPM |
                             TPMA_OBJECT_FIXEDPARENT |
                             TPMA_OBJECT_SENSITIVEDATAORIGIN |
                             TPMA_OBJECT_NODA),
        .parameters.eccDetail = {
             .curveID = 0, /* To be filled out later */
             .symmetric = {
                 .algorithm = TPM2_ALG_NULL,
                 .keyBits.aes = 0,
                 .mode.aes = 0,
              },
             .scheme = {
                .scheme = TPM2_ALG_NULL,
                .details = {}
             },
             .kdf = {
                .scheme = TPM2_ALG_NULL,
                .details = {}
             },
         },
        .unique.ecc = {
             .x.size = 0,
             .y.size = 0
         }
     }
};

#if OPENSSL_VERSION_NUMBER < 0x10100000
static int EC_GROUP_order_bits(const EC_GROUP *group)
{
    if (!group)
        return 0;

    BIGNUM *order = BN_new();

    if (order == NULL) {
        ERR_clear_error();
        return 0;
    }

    int ret = 0;

    if (!EC_GROUP_get_order(group, order, NULL)) {
        ERR_clear_error();
        BN_free(order);
        return 0;
    }

    ret = BN_num_bits(order);
    BN_free(order);
    return ret;
}
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
 /**
  * Initialize a TPM2B_ECC_POINT from an OpenSSL EC_POINT.
  *
  * @param point Pointer to output tpm point
  * @param pub_key OpenSSL public key to convert
  * @param group Curve group
  * @retval 0 on failure
  */
static int
init_tpm_public_point(TPM2B_ECC_POINT *point, const EC_POINT *ec_point,
                        const EC_GROUP *ec_group)
{
    unsigned char buffer[1 + sizeof(point->point.x.buffer)
                           + sizeof(point->point.y.buffer)] = {0};

    BN_CTX *ctx = BN_CTX_new();
    if (!ctx)
        return 0;

    BN_CTX_start(ctx);

    size_t len = 0;

    // first, check for actual buffer size required
    if ((len = EC_POINT_point2oct(ec_group, ec_point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, ctx)) <= sizeof(buffer)) {
        len = EC_POINT_point2oct(ec_group, ec_point,
                    POINT_CONVERSION_UNCOMPRESSED, buffer, sizeof(buffer), ctx);
    }

    BN_CTX_end(ctx);
    BN_CTX_free(ctx);

    if (len == 0 || len > sizeof(buffer))
        return 0;

    len = (len - 1) / 2;

    point->point.x.size = len;
    point->point.y.size = len;
    memcpy(point->point.x.buffer, &buffer[1], len);
    memcpy(point->point.y.buffer, &buffer[1 + len], len);

    return 1;
}

/**
 * Generate a shared secret using a TPM key
 *
 * @param psec Pointer to output buffer holding shared secret
 * @param pseclen Size of the psec buffer
 * @param pub_key The peer's public key
 * @param ecdh The ECC key object for the host private key
 * @retval 0 on failure
 */
static int
ecdh_compute_key(unsigned char **psec, size_t *pseclen,
                    const EC_POINT *pub_key, const EC_KEY *eckey)
{
    /*
     * If this is not a TPM2 key, bail out since fall through to software
     * functions requires a non-const EC_KEY, yet the ECDH prototype only
     * provides it as const.
     */
    TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(eckey);
    if (tpm2Data == NULL)
        return 0;

    TPM2B_ECC_POINT inPoint;
    TPM2B_ECC_POINT *outPoint = NULL;
    const EC_GROUP *group = EC_KEY_get0_group(eckey);

    int ret = init_tpm_public_point(&inPoint, pub_key, group);
    if (!ret)
        return 0;

    ESYS_CONTEXT *esys_ctx = NULL;
    ESYS_TR keyHandle = ESYS_TR_NONE;
    TSS2_RC r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);
    ERRchktss(ecdh_compute_key, r, goto error);

    r = Esys_ECDH_ZGen(esys_ctx, keyHandle,
            ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
            &inPoint, &outPoint);
    ERRchktss(ecdh_compute_key, r, goto error);

    *pseclen = outPoint->point.x.size;
    *psec = OPENSSL_malloc(*pseclen);
    if (!*psec)
        goto error;

    memcpy(*psec, outPoint->point.x.buffer, *pseclen);
    ret = 1;
    goto out;
error:
    ret = 0;
out:
    if (keyHandle != ESYS_TR_NONE) {
        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {
            Esys_TR_Close(esys_ctx, &keyHandle);
        } else {
            Esys_FlushContext(esys_ctx, keyHandle);
        }
    }
    Esys_Free(outPoint);
    esys_ctx_free(&esys_ctx);
    return ret;
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

static ECDSA_SIG *
ecdsa_sign(ESYS_CONTEXT *esys_ctx, ESYS_TR key_handle,
	   TPM2B_DIGEST *digest, TPMT_TK_HASHCHECK *validation,
	   TPM2_ALG_ID hash_alg)
{
    TPMT_SIG_SCHEME inScheme = {
      .scheme = TPM2_ALG_ECDSA,
      .details.ecdsa.hashAlg = hash_alg,
    };
    BIGNUM *bns = NULL, *bnr = NULL;
    ECDSA_SIG *ret = NULL;
    TPMT_SIGNATURE *sig = NULL;
    TSS2_RC r;

    r = Esys_Sign(esys_ctx, key_handle, ESYS_TR_PASSWORD,
                  ESYS_TR_NONE, ESYS_TR_NONE, digest, &inScheme,
                  validation, &sig);
    ERRchktss(ecdsa_sign, r, goto error);

    ret = ECDSA_SIG_new();
    if (ret == NULL) {
        ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE);
        goto error;
    }

    bns = BN_bin2bn(&sig->signature.ecdsa.signatureS.buffer[0],
                    sig->signature.ecdsa.signatureS.size, NULL);
    bnr = BN_bin2bn(&sig->signature.ecdsa.signatureR.buffer[0],
                    sig->signature.ecdsa.signatureR.size, NULL);
    if (!bns || !bnr) {
        ERR(ecdsa_sign, ERR_R_MALLOC_FAILURE);
        goto error;
    }

#if OPENSSL_VERSION_NUMBER < 0x10100000
    ret->s = bns;
    ret->r = bnr;
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    ECDSA_SIG_set0(ret, bnr, bns);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

    goto out;

 error:
    if (bns)
      BN_free(bns);
    if (bnr)
      BN_free(bnr);
    if (ret)
      ECDSA_SIG_free(ret);
    ret = NULL;
 out:
    Esys_Free(sig);
    return ret;
}

/** Sign data using a TPM key
 *
 * This function performs the sign function using the private key in ECDSA.
 * This operation is usually used to perform signature and authentication
 * operations.
 * @param dgst The data to be signed.
 * @param dgst_len Length of the from buffer.
 * @param inv Ignored
 * @param rp Ignored
 * @param eckey The ECC key object.
 * @retval 0 on failure
 * @retval size Size of the returned signature
 */
static ECDSA_SIG *
ecdsa_ec_key_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
		  const BIGNUM *rp, EC_KEY *eckey)
{
    ECDSA_SIG *ret = NULL;
    TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(eckey);
    TPM2_ALG_ID hash_alg;

    /* If this is not a TPM2 key, fall through to software functions */
    if (tpm2Data == NULL) {
#if OPENSSL_VERSION_NUMBER < 0x10100000
        ECDSA_set_method(eckey, ecc_method_default);
        ret = ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, eckey);
        ECDSA_set_method(eckey, ecc_methods);
        return ret;
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
        EC_KEY_set_method(eckey, ecc_method_default);
        ret = ECDSA_do_sign_ex(dgst, dgst_len, inv, rp, eckey);
        EC_KEY_set_method(eckey, ecc_methods);
        return ret;
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    }

    DBG("ecdsa_sign called for input data(size=%i):\n", dgst_len);
    DBGBUF(dgst, dgst_len);

    TSS2_RC r;
    ESYS_CONTEXT *esys_ctx = NULL;
    ESYS_TR keyHandle = ESYS_TR_NONE;

    TPMT_TK_HASHCHECK validation = { .tag = TPM2_ST_HASHCHECK,
                                     .hierarchy = TPM2_RH_NULL,
                                     .digest.size = 0 };

    /*
     * ECDSA signatures truncate the incoming hash to fit the curve,
     * and the signature mechanism is the same regardless of the
     * hash being used.
     *
     * The TPM bizarrely wants to be told the hash algorithm, and
     * either it or the TSS will validate that the digest length
     * matches the hash that it's told, despite it having no business
     * caring about such things.
     *
     * So, we can truncate the digest any pretend it's any smaller
     * digest that the TPM actually does support, as long as that
     * digest is larger than the size of the curve.
     */
    int curve_len = (EC_GROUP_order_bits(EC_KEY_get0_group(eckey)) + 7) / 8;
    /* If we couldn't work it out, don't truncate */
    if (!curve_len)
	    curve_len = dgst_len;

    if (dgst_len == SHA_DIGEST_LENGTH ||
	(curve_len <= SHA_DIGEST_LENGTH && dgst_len > SHA_DIGEST_LENGTH)) {
	    hash_alg = TPM2_ALG_SHA1;
	    dgst_len = SHA_DIGEST_LENGTH;
    } else if (dgst_len == SHA256_DIGEST_LENGTH ||
	(curve_len <= SHA256_DIGEST_LENGTH && dgst_len > SHA256_DIGEST_LENGTH)) {
	    hash_alg = TPM2_ALG_SHA256;
	    dgst_len = SHA256_DIGEST_LENGTH;
    } else if (dgst_len == SHA384_DIGEST_LENGTH ||
	(curve_len <= SHA384_DIGEST_LENGTH && dgst_len > SHA384_DIGEST_LENGTH)) {
	    hash_alg = TPM2_ALG_SHA384;
	    dgst_len = SHA384_DIGEST_LENGTH;
    } else if (dgst_len == SHA512_DIGEST_LENGTH ||
	(curve_len <= SHA512_DIGEST_LENGTH && dgst_len > SHA512_DIGEST_LENGTH)) {
	    hash_alg = TPM2_ALG_SHA512;
	    dgst_len = SHA512_DIGEST_LENGTH;
    } else {
        ERR(ecdsa_sign, TPM2TSS_R_PADDING_UNKNOWN);
        goto error;
    }

    TPM2B_DIGEST digest = { .size = dgst_len };
    if (digest.size > sizeof(digest.buffer)) {
        ERR(ecdsa_sign, TPM2TSS_R_DIGEST_TOO_LARGE);
        goto error;
    }
    memcpy(&digest.buffer[0], dgst, digest.size);

    r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);
    ERRchktss(ecdsa_sign, r, goto error);

    ret = ecdsa_sign(esys_ctx, keyHandle, &digest, &validation, hash_alg);

    goto out;
 error:
    r = -1;
 out:
    if (keyHandle != ESYS_TR_NONE) {
        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {
            Esys_TR_Close(esys_ctx, &keyHandle);
        } else {
            Esys_FlushContext(esys_ctx, keyHandle);
        }
    }

    esys_ctx_free(&esys_ctx);
    return (r == TSS2_RC_SUCCESS) ? ret : NULL;
}

#ifdef HAVE_OPENSSL_DIGEST_SIGN
static int
ecdsa_pkey_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
{
    if (ecdsa_pkey_orig_copy && !ecdsa_pkey_orig_copy(dst, src))
        return 0;

    return digest_sign_copy(dst, src);
}

static void
ecdsa_pkey_cleanup(EVP_PKEY_CTX *ctx)
{
    digest_sign_cleanup(ctx);

    if (ecdsa_pkey_orig_cleanup)
        ecdsa_pkey_orig_cleanup(ctx);
}

/* called for digest & sign init, after message digest algorithm set */
static int
ecdsa_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
{
    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
    EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey);
    TPM2_DATA *tpm2data = tpm2tss_ecc_getappdata(eckey);

    DBG("ecdsa_digest_custom %p %p\n", ctx, mctx);

    return digest_sign_init(ctx, mctx, tpm2data, ECDSA_size(eckey));
}

static int
ecdsa_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
              EVP_MD_CTX *mctx)
{
    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx);
    TSS2_RC r = TSS2_RC_SUCCESS;
    TPMT_TK_HASHCHECK *validation_ptr = NULL;
    TPM2B_DIGEST *digest_ptr = NULL;
    ECDSA_SIG *ecdsa_s = NULL;

    DBG("ecdsa_signctx %p %p sig_data %p\n", ctx, mctx, sig_data);

    if (!sig) {
        /* caller just wants to know the size */
        *siglen = sig_data->sig_size;
        return 1;
    }

    if (!sig_data) {
        /* handle non-TPM key */
        unsigned char md[EVP_MAX_MD_SIZE];
        unsigned int md_len = 0;

        if (!EVP_DigestFinal_ex(mctx, md, &md_len))
            return 0;
        if (EVP_PKEY_sign(ctx, sig, siglen, md, md_len) <= 0)
            return 0;
        return 1;
    }

    if (!digest_finish(sig_data, &digest_ptr, &validation_ptr))
        return 0;

    ecdsa_s = ecdsa_sign(sig_data->key->esys_ctx, sig_data->key->key_handle,
                         digest_ptr, validation_ptr,
                         sig_data->hash_alg);
    if (!ecdsa_s)
        goto error;

    *siglen = i2d_ECDSA_SIG(ecdsa_s, &sig);

    r = 1;
    goto out;

 error:
    r = 0;
 out:
    ECDSA_SIG_free(ecdsa_s);
    Esys_Free(digest_ptr);
    Esys_Free(validation_ptr);

    return r;
}
#endif /* HAVE_OPENSSL_DIGEST_SIGN */

/** Helper to populate the ECC key object.
 *
 * In order to use an ECC key object in a typical manner, all fields of the
 * OpenSSL's corresponding object bust be filled. This function fills the public
 * values correctly.
 * @param key The key object to fill.
 * @retval 0 on failure
 * @retval 1 on success
 */
static int
populate_ecc(EC_KEY *key)
{
    EC_GROUP *ecgroup = NULL;
    int nid;
    BIGNUM *x = NULL, *y = NULL;
    TPM2_DATA *tpm2Data = tpm2tss_ecc_getappdata(key);
    if (tpm2Data == NULL)
        return 0;

    switch (tpm2Data->pub.publicArea.parameters.eccDetail.curveID) {
    case TPM2_ECC_NIST_P256:
        nid = EC_curve_nist2nid("P-256");
        break;
    case TPM2_ECC_NIST_P384:
        nid = EC_curve_nist2nid("P-384");
        break;
    default:
        nid = -1;
    }
    if (nid < 0) {
        ERR(populate_ecc, TPM2TSS_R_UNKNOWN_CURVE);
        return 0;
    }
    ecgroup = EC_GROUP_new_by_curve_name(nid);
    if (ecgroup == NULL) {
        ERR(populate_ecc, TPM2TSS_R_UNKNOWN_CURVE);
        return 0;
    }
    if (!EC_KEY_set_group(key, ecgroup)) {
        ERR(populate_ecc, TPM2TSS_R_GENERAL_FAILURE);
        EC_GROUP_free(ecgroup);
        return 0;
    }
    EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE);
    EC_GROUP_free(ecgroup);

    x = BN_bin2bn(tpm2Data->pub.publicArea.unique.ecc.x.buffer,
                  tpm2Data->pub.publicArea.unique.ecc.x.size, NULL);

    y = BN_bin2bn(tpm2Data->pub.publicArea.unique.ecc.y.buffer,
                  tpm2Data->pub.publicArea.unique.ecc.y.size, NULL);

    if (!x || !y) {
        ERR(populate_ecc, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    if (!EC_KEY_set_public_key_affine_coordinates(key, x, y)) {
        ERR(populate_ecc, TPM2TSS_R_GENERAL_FAILURE);
        BN_free(y);
        BN_free(x);
        return 0;
    }

    BN_free(y);
    BN_free(x);

    return 1;
}

/** Helper to load an ECC key from a tpm2Data
 *
 * This function creates a key object given a TPM2_DATA object. The resulting
 * key object can then be used for signing with the tpm2tss engine. Ownership
 * of the TPM2_DATA object is taken on success.
 * @param tpm2Data The key data to use. Must have been allocated using
 * OPENSSL_malloc.
 * @retval key The key object
 * @retval NULL on failure.
 */
EVP_PKEY *
tpm2tss_ecc_makekey(TPM2_DATA *tpm2Data)
{
    DBG("Creating ECC key object.\n");

    EVP_PKEY *pkey;
    EC_KEY *eckey;

    /* create the new objects to return */
    if ((pkey = EVP_PKEY_new()) == NULL) {
        ERR(tpm2tss_ecc_makekey, ERR_R_MALLOC_FAILURE);
        return NULL;
    }

    if ((eckey = EC_KEY_new()) == NULL) {
        ERR(tpm2tss_ecc_makekey, ERR_R_MALLOC_FAILURE);
        EVP_PKEY_free(pkey);

        return NULL;
    }
#if OPENSSL_VERSION_NUMBER < 0x10100000
    if (!ECDSA_set_method(eckey, ecc_methods)) {
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    if (!EC_KEY_set_method(eckey, ecc_methods)) {
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
        ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);
        EC_KEY_free(eckey);
        goto error;
    }

    if (!EVP_PKEY_assign_EC_KEY(pkey, eckey)) {
        ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);
        EC_KEY_free(eckey);
        goto error;
    }

    if (!tpm2tss_ecc_setappdata(eckey, tpm2Data)) {
        ERR(tpm2tss_ecc_makekey, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    if (!populate_ecc(eckey))
        goto error;

    DBG("Created ECC key object.\n");

    return pkey;
 error:
    EVP_PKEY_free(pkey);
    return NULL;
}

/** Retrieve app data
 *
 * Since the ECC api (opposed to the RSA api) does not provide a standardized
 * way to retrieve app data between the library and an application, this helper
 * is defined
 * @param key The key object
 * @retval tpm2Data The corresponding TPM data
 * @retval NULL on failure.
 */
TPM2_DATA *
#if OPENSSL_VERSION_NUMBER < 0x10100000
tpm2tss_ecc_getappdata(EC_KEY *key)
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
tpm2tss_ecc_getappdata(const EC_KEY *key)
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
{
    if (ec_key_app_data == -1) {
        DBG("Module uninitialized\n");
        return NULL;
    }

#if OPENSSL_VERSION_NUMBER < 0x10100000
    return ECDSA_get_ex_data(key, ec_key_app_data);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    return EC_KEY_get_ex_data(key, ec_key_app_data);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
}

/** Set app data
 *
 * Since the ECC api (opposed to the RSA api) does not provide a standardized
 * way to set app data between the library and an application, this helper
 * is defined
 * @param key The key object
 * @param tpm2Data The corresponding TPM data
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_ecc_setappdata(EC_KEY *key, TPM2_DATA *tpm2Data)
{
    if (ec_key_app_data == -1) {
        DBG("Module uninitialized\n");
        return 0;
    }
#if OPENSSL_VERSION_NUMBER < 0x10100000
    return ECDSA_set_ex_data(key, ec_key_app_data, tpm2Data);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    return EC_KEY_set_ex_data(key, ec_key_app_data, tpm2Data);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
}

static void
free_ecc_appdata(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
                 long argl, void *argp)
{
    TPM2_DATA *tpm2Data = ptr;

    (void)parent;
    (void)ad;
    (void)idx;
    (void)argl;
    (void)argp;

    if (!ptr)
        return;

    OPENSSL_free(tpm2Data);
}

/** Generate a tpm2tss ecc key object.
 *
 * This function creates a new TPM ECC key. The TPM data is stored inside the
 * object*s app data and can be retrieved using tpm2tss_ecc_getappdata().
 * @param key The key object for the TPM ECC key to be created
 * @param curve The curve to be used for the key
 * @param password The Password to be set for the new key
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_ecc_genkey(EC_KEY *key, TPMI_ECC_CURVE curve, const char *password,
                   TPM2_HANDLE parentHandle)
{
    DBG("GenKey for ecdsa.\n");

    TSS2_RC r;
    ESYS_CONTEXT *esys_ctx = NULL;
    ESYS_TR parent = ESYS_TR_NONE;
    TPM2B_PUBLIC *keyPublic = NULL;
    TPM2B_PRIVATE *keyPrivate = NULL;
    TPM2_DATA *tpm2Data = NULL;
    TPM2B_PUBLIC inPublic = keyEcTemplate;
    TPM2B_SENSITIVE_CREATE inSensitive = {
        .sensitive = {
            .userAuth = {
                 .size = 0,
             },
            .data = {
                 .size = 0,
             }
        }
    };

    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));
    if (tpm2Data == NULL) {
        ERR(tpm2tss_ecc_genkey, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    memset(tpm2Data, 0, sizeof(*tpm2Data));

    inPublic.publicArea.parameters.eccDetail.curveID = curve;

    if (password) {
        DBG("Setting a password for the created key.\n");
        if (strlen(password) > sizeof(tpm2Data->userauth.buffer) - 1 || strlen(password) > sizeof(inSensitive.sensitive.userAuth.buffer) - 1) {
            goto error;
        }
        tpm2Data->userauth.size = strlen(password);
        memcpy(&tpm2Data->userauth.buffer[0], password,
               tpm2Data->userauth.size);

        inSensitive.sensitive.userAuth.size = strlen(password);
        memcpy(&inSensitive.sensitive.userAuth.buffer[0], password,
               strlen(password));
    } else
        tpm2Data->emptyAuth = 1;

    r = init_tpm_parent(&esys_ctx, parentHandle, &parent);
    ERRchktss(tpm2tss_ecc_genkey, r, goto error);

    tpm2Data->parent = parentHandle;

    DBG("Generating the ECC key inside the TPM.\n");

    r = Esys_Create(esys_ctx, parent,
                    ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                    &inSensitive, &inPublic, &allOutsideInfo, &allCreationPCR,
                    &keyPrivate, &keyPublic, NULL, NULL, NULL);
    ERRchktss(tpm2tss_ecc_genkey, r, goto error);

    DBG("Generated the ECC key inside the TPM.\n");

    tpm2Data->pub = *keyPublic;
    tpm2Data->priv = *keyPrivate;

    if (!tpm2tss_ecc_setappdata(key, tpm2Data)) {
        ERR(tpm2tss_ecc_genkey, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    if (!populate_ecc(key)) {
        goto error;
    }

    goto end;
 error:
    r = -1;
    tpm2tss_ecc_setappdata(key, NULL);
    if (tpm2Data)
        OPENSSL_free(tpm2Data);

 end:
    Esys_Free(keyPrivate);
    Esys_Free(keyPublic);

    if (parent != ESYS_TR_NONE && !parentHandle)
        Esys_FlushContext(esys_ctx, parent);

    esys_ctx_free(&esys_ctx);

    return (r == TSS2_RC_SUCCESS);
}

/** Initialize the tpm2tss engine's ecc submodule
 *
 * Initialize the tpm2tss engine's submodule by setting function pointer.
 * @param e The engine context.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
init_ecc(ENGINE *e)
{
    (void)(e);

#if OPENSSL_VERSION_NUMBER < 0x10100000
    ecc_method_default = ECDSA_OpenSSL();
    if (ecc_method_default == NULL)
        return 0;

    ecc_methods = ECDSA_METHOD_new(ecc_method_default);
    if (ecc_methods == NULL)
        return 0;

    ECDSA_METHOD_set_sign(ecc_methods, ecdsa_ec_key_sign);

    if (ec_key_app_data == -1)
        ec_key_app_data = ECDSA_get_ex_new_index(0, NULL, NULL, NULL,
                                                 free_ecc_appdata);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    ecc_method_default = EC_KEY_OpenSSL();
    if (ecc_method_default == NULL)
        return 0;

    ecc_methods = EC_KEY_METHOD_new(ecc_method_default);
    if (ecc_methods == NULL)
        return 0;

    int (*orig_sign) (int, const unsigned char *, int, unsigned char *,
                      unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *)
        = NULL;
    EC_KEY_METHOD_get_sign(ecc_methods, &orig_sign, NULL, NULL);
    EC_KEY_METHOD_set_sign(ecc_methods, orig_sign, NULL, ecdsa_ec_key_sign);
    EC_KEY_METHOD_set_compute_key(ecc_methods, ecdh_compute_key);

    if (ec_key_app_data == -1)
        ec_key_app_data = EC_KEY_get_ex_new_index(0, NULL, NULL, NULL,
                                                  free_ecc_appdata);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

#if HAVE_OPENSSL_DIGEST_SIGN
    /* digest and sign support */

    EVP_PKEY_METHOD *pkey_ecc_methods;

    pkey_ecc_methods = EVP_PKEY_meth_new(EVP_PKEY_EC, 0);
    if (pkey_ecc_methods == NULL)
        return 0;

    const EVP_PKEY_METHOD *pkey_orig_ecc_methods =
        EVP_PKEY_meth_find(EVP_PKEY_EC);
    if (pkey_orig_ecc_methods == NULL)
        return 0;
    EVP_PKEY_meth_copy(pkey_ecc_methods, pkey_orig_ecc_methods);
    /*
     * save originals since we only override some of the pkey
     * functionality, rather than reimplementing all of it
     */
    EVP_PKEY_meth_get_copy(pkey_ecc_methods, &ecdsa_pkey_orig_copy);
    EVP_PKEY_meth_get_cleanup(pkey_ecc_methods, &ecdsa_pkey_orig_cleanup);

    EVP_PKEY_meth_set_copy(pkey_ecc_methods, ecdsa_pkey_copy);
    EVP_PKEY_meth_set_cleanup(pkey_ecc_methods, ecdsa_pkey_cleanup);
    EVP_PKEY_meth_set_signctx(pkey_ecc_methods, NULL, ecdsa_signctx);
    EVP_PKEY_meth_set_digest_custom(pkey_ecc_methods, ecdsa_digest_custom);
    EVP_PKEY_meth_add0(pkey_ecc_methods);
#endif /* HAVE_OPENSSL_DIGEST_SIGN */

    return 1;
}


================================================
FILE: src/tpm2-tss-engine-err.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <openssl/err.h>

#include "tpm2-tss-engine-err.h"

#define TPM2TSS_LIB_NAME "tpm2-tss-engine"

#define xstr(s) str(s)
#define str(s) #s

#define ERR_F(f) { ERR_PACK(0, TPM2TSS_F_ ## f, 0), xstr(f) }
#define ERR_R(r, s) { ERR_PACK(0, 0, r), xstr(s) }

#ifndef OPENSSL_NO_ERR
static ERR_STRING_DATA TPM2TSS_f[] = {
    /* tpm2-tss-engine.c */
    ERR_F(loadkey),
    ERR_F(init_engine),
    ERR_F(get_auth),
    ERR_F(engine_ctrl),
    /* tpm2-tss-engine-common.c */
    ERR_F(tpm2tss_tpm2data_write),
    ERR_F(tpm2tss_tpm2data_read),
    ERR_F(tpm2tss_tpm2data_readtpm),
    ERR_F(init_tpm_parent),
    ERR_F(init_tpm_key),
    ERR_F(esys_ctx_init),
    ERR_F(esys_ctx_free),
    /* tpm2-tss-engine-ecc.c */
    ERR_F(ecdsa_sign),
    ERR_F(populate_ecc),
    ERR_F(tpm2tss_ecc_genkey),
    ERR_F(tpm2tss_ecc_makekey),
    /* tpm2-tss-engine-rand.c */
    ERR_F(rand_bytes),
    ERR_F(rand_seed),
    /* tpm2-tss-engine-rsa.c */
    ERR_F(rsa_priv_enc),
    ERR_F(rsa_priv_dec),
    ERR_F(tpm2tss_rsa_genkey),
    ERR_F(populate_rsa),
    {0, NULL}
};

static ERR_STRING_DATA TPM2TSS_r[] = {
    ERR_R(TPM2TSS_R_TPM2DATA_READ_FAILED, Failed to read TPM2 data),
    ERR_R(TPM2TSS_R_UNKNOWN_ALG, The algorithm is unknown (neither RSA, ECDSA)),
    ERR_R(TPM2TSS_R_CANNOT_MAKE_KEY, Cannot create OpenSSL key object),
    ERR_R(TPM2TSS_R_SUBINIT_FAILED, Could not initialize submodule),
    ERR_R(TPM2TSS_R_FILE_WRITE, Could not create file for writing),
    ERR_R(TPM2TSS_R_DATA_CORRUPTED, Data is corrupted and could not be parsed),
    ERR_R(TPM2TSS_R_FILE_READ, Could not open file for reading),
    ERR_R(TPM2TSS_R_PADDING_UNKNOWN, Unknown padding scheme requested),
    ERR_R(TPM2TSS_R_PADDING_FAILED, Padding operation failed),
    ERR_R(TPM2TSS_R_UNKNOWN_TPM_ERROR, Unknown TPM error occurred. Please check tpm2tss logs),
    ERR_R(TPM2TSS_R_DIGEST_TOO_LARGE, The provided digest value is too large),
    ERR_R(TPM2TSS_R_GENERAL_FAILURE, Some unknown error occurred),
    ERR_R(TPM2TSS_R_UNKNOWN_CURVE, Unknown ECC curve),
    ERR_R(TPM2TSS_R_UI_ERROR, User interaction),
    ERR_R(TPM2TSS_R_UNKNOWN_CTRL, Unknown engine ctrl),
    ERR_R(TPM2TSS_R_DL_OPEN_FAILED, Failed to open TCTI library),
    ERR_R(TPM2TSS_R_DL_INVALID, The TCTI library is invalid),
    /* TPM/TSS Reasons that are useful to the user */
    ERR_R(TPM2TSS_R_AUTH_FAILURE, Authorization failed),
    ERR_R(TPM2TSS_R_OWNER_AUTH_FAILED, Owner authorization failed),
    ERR_R(TPM2TSS_R_OLD_TSS, An old TSS (<2.2) was detected and a TPM session may have leaked),
    {0, NULL}
};
#endif /* OPENSSL_NO_ERR */

static int TPM2TSS_lib_error_code = 0;
static int TPM2TSS_error_init = 0;

static ERR_STRING_DATA TPM2TSS_lib_name[] = {
    {0, TPM2TSS_LIB_NAME},
    {0, NULL}
};

/** Load TPM2TSS error string
 *
 * Load the errorstring from TPM2TSS_f and TPM2TSS_r into OpenSSL's error
 * handling stack.
 */
void
ERR_load_TPM2TSS_strings(void)
{
    if (TPM2TSS_lib_error_code == 0)
        TPM2TSS_lib_error_code = ERR_get_next_error_library();

    if (!TPM2TSS_error_init) {
        TPM2TSS_error_init = 1;
#ifndef OPENSSL_NO_ERR
        ERR_load_strings(TPM2TSS_lib_error_code, TPM2TSS_f);
        ERR_load_strings(TPM2TSS_lib_error_code, TPM2TSS_r);
#endif /* OPENSSL_NO_ERR */

        TPM2TSS_lib_name->error = ERR_PACK(TPM2TSS_lib_error_code, 0, 0);
        ERR_load_strings(0, TPM2TSS_lib_name);
    }
}

/** Unload TPM2TSS error string
 *
 * Unload the errorstring from TPM2TSS_f and TPM2TSS_r into OpenSSL's error
 * handling stack.
 */
void
ERR_unload_TPM2TSS_strings(void)
{
    if (TPM2TSS_error_init) {
#ifndef OPENSSL_NO_ERR
        ERR_unload_strings(TPM2TSS_lib_error_code, TPM2TSS_f);
        ERR_unload_strings(TPM2TSS_lib_error_code, TPM2TSS_r);
#endif /* OPENSSL_NO_ERR */

        ERR_unload_strings(0, TPM2TSS_lib_name);
        TPM2TSS_error_init = 0;
    }
}

/** Add error to error stack
 *
 * Add the error to the error stack of OpenSSL.
 * This function is usually not called directly but using the macros ERR(f,r)
 * or ERRchktss(f, r, s) from source code.
 * @param function Identifier of the function invocing the error.
 * @param reason Identifier of the reason for the error.
 * @param file File from which the error originates.
 * @param line Line inside the file from which the error originates.
 */
void
ERR_error(int function, int reason, const char *file, int line)
{
    (void)(function);
    (void)(file);
    (void)(line);
    if (TPM2TSS_lib_error_code == 0)
        TPM2TSS_lib_error_code = ERR_get_next_error_library();
    ERR_PUT_error(TPM2TSS_lib_error_code, function, reason, file, line);
}

/** Print a buffer to stderr
 *
 * A helper function to print data buffers to stderr. This function is usually
 * not called directly, but the macro DBGBUF() is used instead.
 * @param b The buffer
 * @param s The buffer's size
 */
void
printbuf(const uint8_t *b, size_t s)
{
    if (s > 1000)
        return;
    for (size_t i = 0; i < s; i++)
        fprintf(stderr, "%02x", b[i]);
    fprintf(stderr, "\n");
}


================================================
FILE: src/tpm2-tss-engine-err.h
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
#ifndef TPM2_TSS_ENGINE_ERR_H
#define TPM2_TSS_ENGINE_ERR_H

#include "config.h"

#include <stdint.h>

#ifndef NDEBUG
#define DBG(...) fprintf(stderr, __VA_ARGS__)
#define DBGBUF(...) printbuf(__VA_ARGS__)
void printbuf(const uint8_t *b, size_t s);

#else /* DEBUG */
#define DBG(...)
#define DBGBUF(...)
#endif /* DEBUG */

#define ERR(f,r) ERR_error(TPM2TSS_F_ ## f, r, __FILE__, __LINE__)

/* This macro checks for common TPM error codes which are meaningful to the
   user */
#define ERRchktss(f, r, s) do { \
    if (r) { \
        switch(r) { \
        case TSS2_ESYS_RC_MEMORY: \
            ERR(f, ERR_R_MALLOC_FAILURE); \
            break; \
        case 0x000009a2: \
            ERR(f, TPM2TSS_R_AUTH_FAILURE); \
            break; \
        default: \
            ERR(f, TPM2TSS_R_UNKNOWN_TPM_ERROR); \
        } \
        s; \
    } \
} while (0);

void ERR_load_TPM2TSS_strings(void);
void ERR_unload_TPM2TSS_strings(void);
void ERR_error(int function, int reason, const char *file, int line);

/* Function codes */
/* tpm2-tss-engine.c */
#define TPM2TSS_F_loadkey          100
#define TPM2TSS_F_init_engine          101
#define TPM2TSS_F_get_auth                  102
#define TPM2TSS_F_engine_ctrl               103
/* tpm2-tss-engine-common.c */
#define TPM2TSS_F_tpm2tss_tpm2data_write        110
#define TPM2TSS_F_tpm2tss_tpm2data_read         111
#define TPM2TSS_F_tpm2tss_tpm2data_readtpm      112
#define TPM2TSS_F_init_tpm_parent      113
#define TPM2TSS_F_init_tpm_key          114
#define TPM2TSS_F_esys_ctx_init      115
#define TPM2TSS_F_esys_ctx_free      116
/* tpm2-tss-engine-ecc.c */
#define TPM2TSS_F_ecdsa_sign    120
#define TPM2TSS_F_populate_ecc          121
#define TPM2TSS_F_tpm2tss_ecc_genkey    122
#define TPM2TSS_F_tpm2tss_ecc_makekey      123
#define TPM2TSS_F_ecdh_compute_key      124

/* tpm2-tss-engine-digest-sign.c */
#define TPM2TSS_F_digest_init   150
#define TPM2TSS_F_digest_update 151
#define TPM2TSS_F_digest_finish 152
#define TPM2TSS_F_digest_sign_init      153
#define TPM2TSS_F_digest_sign_copy      154

/* tpm2-tss-engine-rand.c */
#define TPM2TSS_F_rand_bytes    130
#define TPM2TSS_F_rand_seed     131
/* tpm2-tss-engine-rsa.c */
#define TPM2TSS_F_rsa_priv_enc     140
#define TPM2TSS_F_rsa_priv_dec     141
#define TPM2TSS_F_tpm2tss_rsa_genkey    142
#define TPM2TSS_F_populate_rsa          143
#define TPM2TSS_F_rsa_signctx           144

/* Reason codes */
#define TPM2TSS_R_TPM2DATA_READ_FAILED  100
#define TPM2TSS_R_UNKNOWN_ALG           101
#define TPM2TSS_R_CANNOT_MAKE_KEY       102
#define TPM2TSS_R_SUBINIT_FAILED        103
#define TPM2TSS_R_FILE_WRITE            104
#define TPM2TSS_R_DATA_CORRUPTED        105
#define TPM2TSS_R_FILE_READ             106
#define TPM2TSS_R_PADDING_UNKNOWN       107
#define TPM2TSS_R_PADDING_FAILED        108
#define TPM2TSS_R_UNKNOWN_TPM_ERROR     109
#define TPM2TSS_R_DIGEST_TOO_LARGE      110
#define TPM2TSS_R_GENERAL_FAILURE       111
#define TPM2TSS_R_UNKNOWN_CURVE         112
#define TPM2TSS_R_UI_ERROR              113
#define TPM2TSS_R_UNKNOWN_CTRL          114
#define TPM2TSS_R_DL_OPEN_FAILED        115
#define TPM2TSS_R_DL_INVALID            116
/* TPM/TSS Reasons that are useful to the user */
#define TPM2TSS_R_AUTH_FAILURE          150
#define TPM2TSS_R_OWNER_AUTH_FAILED     151
#define TPM2TSS_R_OLD_TSS               152

#endif /* TPM2_TSS_ENGINE_ERR_H */


================================================
FILE: src/tpm2-tss-engine-rand.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <string.h>

#include <openssl/engine.h>
#include <openssl/rand.h>

#include <tss2/tss2_mu.h>
#include <tss2/tss2_esys.h>

#include "tpm2-tss-engine.h"
#include "tpm2-tss-engine-common.h"

/** rand seed
 * @retval 1 on success
 * @retval 0 on failure
 */
static int
rand_seed(const void *seed, int seed_len)
{
    ESYS_CONTEXT *esys_ctx = NULL;
    TSS2_RC r;

    r = esys_ctx_init(&esys_ctx);
    ERRchktss(rand_seed, r, goto end);

    TPM2B_SENSITIVE_DATA stir;
    size_t offset = 0;
    char *cur_data = (char*)seed;

    static const size_t tpm_random_stir_max_size = 128;
    while(offset < (size_t)seed_len) {
        size_t left = seed_len - offset;
        size_t chunk = left > tpm_random_stir_max_size ? tpm_random_stir_max_size : left;

        stir.size = chunk;
        memcpy(stir.buffer, cur_data + offset, chunk);

        r = Esys_StirRandom(
            esys_ctx,
            ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
            &stir);
        ERRchktss(rand_seed, r, goto end);

        offset += chunk;
    }

end:
    if(esys_ctx)
        esys_ctx_free(&esys_ctx);
    return (r == TSS2_RC_SUCCESS)? 1 : 0;
}

/** Genereate random values
 *
 * Use the TPM to generate a number of random values.
 * @param buf The buffer to write the random values to
 * @param num The amound of random bytes to generate
 * @retval 1 on success
 * @retval 0 on failure
 */
static int
rand_bytes(unsigned char *buf, int num)
{
    ESYS_CONTEXT *esys_ctx = NULL;
    TSS2_RC r;

    r = esys_ctx_init(&esys_ctx);
    ERRchktss(rand_bytes, r, goto end);

    TPM2B_DIGEST *b;
    while (num > 0) {
        r = Esys_GetRandom(esys_ctx,
                           ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
                           num, &b);
        ERRchktss(rand_bytes, r, goto end);

        memcpy(buf, &b->buffer, b->size);
        num -= b->size;
        buf += b->size;
        Esys_Free(b);
    }

    esys_ctx_free(&esys_ctx);

 end:
    return (r == TSS2_RC_SUCCESS);
}

/** Return the entropy status of the prng
 *
 * Since we provide real (TPM-based) randomness even for the pseudorand
 * function, our status is allways good.
 * @retval 1 allways good status
 */
static int
rand_status()
{
    return 1;
}

static RAND_METHOD rand_methods = {
    rand_seed,
    rand_bytes,
    NULL,                       /* cleanup() */
    NULL,                       /* add() */
    rand_bytes,                 /* pseudorand() */
    rand_status                 /* status() */
};

/** Initialize the tpm2tss engine's rand submodule
 *
 * Initialize the tpm2tss engine's submodule by setting function pointer.
 * @param e The engine context.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
init_rand(ENGINE *e)
{
    return ENGINE_set_RAND(e, &rand_methods);
}


================================================
FILE: src/tpm2-tss-engine-rsa.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <string.h>

#include <openssl/engine.h>
#include <tss2/tss2_esys.h>

#include "tpm2-tss-engine.h"
#include "tpm2-tss-engine-common.h"

#define chkerr_goto(x) if (x) { DBG("%s:%i:%s: Error 0x%04x\n", __FILE__, \
                                       __LINE__, __func__, x); goto error; }

const RSA_METHOD *default_rsa = NULL;

#if OPENSSL_VERSION_NUMBER < 0x10100000
RSA_METHOD rsa_methods;
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
RSA_METHOD *rsa_methods = NULL;
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

#ifdef HAVE_OPENSSL_DIGEST_SIGN
static int (*rsa_pkey_orig_copy)(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src);
static void (*rsa_pkey_orig_cleanup)(EVP_PKEY_CTX *ctx);
#endif /* HAVE_OPENSSL_DIGEST_SIGN */

static int (*rsa_orig_finish)(RSA *rsa);

static TPM2B_DATA allOutsideInfo = {
    .size = 0,
};

static TPML_PCR_SELECTION allCreationPCR = {
    .count = 0,
};

static TPM2B_PUBLIC keyTemplate = {
    .publicArea = {
        .type = TPM2_ALG_RSA,
        .nameAlg = ENGINE_HASH_ALG,
        .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
                             TPMA_OBJECT_SIGN_ENCRYPT |
                             TPMA_OBJECT_DECRYPT |
                             TPMA_OBJECT_FIXEDTPM |
                             TPMA_OBJECT_FIXEDPARENT |
                             TPMA_OBJECT_SENSITIVEDATAORIGIN |
                             TPMA_OBJECT_NODA),
        .authPolicy.size = 0,
        .parameters.rsaDetail = {
             .symmetric = {
                 .algorithm = TPM2_ALG_NULL,
                 .keyBits.aes = 0,
                 .mode.aes = 0,
              },
             .scheme = {
                .scheme = TPM2_ALG_NULL,
                .details = {}
             },
             .keyBits = 0,          /* to be set by the genkey function */
             .exponent = 0,         /* to be set by the genkey function */
         },
        .unique.rsa.size = 0
     }
};

/** Sign data using a TPM key
 *
 * This function performs the encrypt function using the private key in RSA.
 * This operation is usually used to perform signature and authentication
 * operations.
 * @param flen Length of the from buffer.
 * @param from The data to be signed.
 * @param to The buffer to write the signature to.
 * @param rsa The rsa key object.
 * @param padding The padding scheme to be used.
 * @retval 0 on failure
 * @retval size Size of the returned signature
 */
static int
rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa,
             int padding)
{
    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);

    /* If this is not a TPM2 key, fall through to software functions */
    if (tpm2Data == NULL) {
        DBG("Non-TPM key passed. Calling standard function.\n");
#if OPENSSL_VERSION_NUMBER < 0x10100000
        return default_rsa->rsa_priv_enc(flen, from, to, rsa, padding);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
        return RSA_meth_get_priv_enc(default_rsa)(flen, from, to, rsa, padding);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    }

    DBG("rsa_priv_enc called for scheme %i and input data(size=%i):\n",
        padding, flen);
    DBGBUF(from, flen);

    int ret = 0;
    TSS2_RC r = TSS2_RC_SUCCESS;
    ESYS_CONTEXT *esys_ctx = NULL;
    ESYS_TR keyHandle = ESYS_TR_NONE;
    TPM2B_DATA label = { .size = 0 };
    TPM2B_PUBLIC_KEY_RSA *sig = NULL;
    TPMT_RSA_DECRYPT inScheme = { .scheme = TPM2_ALG_NULL };

    TPM2B_PUBLIC_KEY_RSA digest;
    digest.size = RSA_size(rsa);
    if (digest.size > sizeof(digest.buffer)) {
        ERR(rsa_priv_enc, TPM2TSS_R_DIGEST_TOO_LARGE);
        goto error;
    }

    switch (padding) {
    case RSA_PKCS1_PADDING:
        ret = RSA_padding_add_PKCS1_type_1(&digest.buffer[0], digest.size,
                                           from, flen);
        break;
    case RSA_X931_PADDING:
        ret = RSA_padding_add_X931(&digest.buffer[0], digest.size, from, flen);
        break;
    case RSA_NO_PADDING:
        ret = RSA_padding_add_none(&digest.buffer[0], digest.size, from, flen);
        break;
    default:
        ERR(rsa_priv_enc, TPM2TSS_R_PADDING_UNKNOWN);
        goto error;
    }
    if (ret <= 0) {
        ERR(rsa_priv_enc, TPM2TSS_R_PADDING_FAILED);
        goto error;
    }

    DBG("Padded digest data (size=%i):\n", digest.size);
    DBGBUF(&digest.buffer[0], digest.size);

    r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);
    ERRchktss(rsa_priv_enc, r, goto error);

    DBG("Signing (via decrypt operation).\n");
    r = Esys_RSA_Decrypt(esys_ctx, keyHandle,
                         ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                         &digest, &inScheme, &label, &sig);
    ERRchktss(rsa_priv_enc, r, goto error);

    DBG("Signature done (size=%i):\n", sig->size);
    DBGBUF(&sig->buffer[0], sig->size);

    ret = sig->size;
    if (ret > RSA_size(rsa) || ret <= 0) {
        ERR(rsa_priv_enc, TPM2TSS_R_DIGEST_TOO_LARGE);
        goto error;
    }
    memcpy(to, &sig->buffer[0], ret);

    goto out;

 error:
    r = -1;

 out:
    Esys_Free(sig);
    if (keyHandle != ESYS_TR_NONE) {
        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {
            Esys_TR_Close(esys_ctx, &keyHandle);
        } else {
            Esys_FlushContext(esys_ctx, keyHandle);
        }
    }
    esys_ctx_free(&esys_ctx);
    return (r == TSS2_RC_SUCCESS) ? ret : 0;
}

/** Decrypt data using a TPM key
 *
 * This function performs the decrypt function using the private key in RSA.
 * @param flen Length of the from buffer.
 * @param from The data to be decrypted.
 * @param to The buffer to write the plaintext to.
 * @param rsa The rsa key object.
 * @param padding The padding scheme to be used.
 * @retval 0 on failure
 * @retval size Size of the returned plaintext
 */
static int
rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA * rsa,
             int padding)
{
    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);

    /* If this is not a TPM2 key, fall through to software functions */
    if (tpm2Data == NULL)
#if OPENSSL_VERSION_NUMBER < 0x10100000
        return default_rsa->rsa_priv_dec(flen, from, to, rsa, padding);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
        return RSA_meth_get_priv_dec(default_rsa)(flen, from, to, rsa, padding);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

    DBG("rsa_priv_dec called for scheme %i and input data(size=%i):\n",
        padding, flen);
    DBGBUF(from, flen);

    TSS2_RC r;
    ESYS_CONTEXT *esys_ctx = NULL;
    ESYS_TR keyHandle = ESYS_TR_NONE;
    TPM2B_DATA label = { .size = 0 };
    TPM2B_PUBLIC_KEY_RSA *message = NULL;
    TPMT_RSA_DECRYPT inScheme;

    TPM2B_PUBLIC_KEY_RSA cipher = { .size = flen };
    if (flen > (int)sizeof(cipher.buffer) || flen < 0) {
        ERR(rsa_priv_dec, TPM2TSS_R_DIGEST_TOO_LARGE);
        goto error;
    }
    memcpy(&cipher.buffer[0], from, flen);

    switch (padding) {
    case RSA_PKCS1_PADDING:
        inScheme.scheme = TPM2_ALG_RSAES;
        break;
    case RSA_PKCS1_OAEP_PADDING:
        inScheme.scheme = TPM2_ALG_OAEP;
        inScheme.details.oaep.hashAlg = TPM2_ALG_SHA1;
        break;
    case RSA_NO_PADDING:
        inScheme.scheme = TPM2_ALG_NULL;
        break;
    default:
        ERR(rsa_priv_dec, TPM2TSS_R_PADDING_UNKNOWN);
        goto error;
    }

    r = init_tpm_key(&esys_ctx, &keyHandle, tpm2Data);
    ERRchktss(rsa_priv_dec, r, goto out);

    r = Esys_RSA_Decrypt(esys_ctx, keyHandle,
                         ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                         &cipher, &inScheme, &label, &message);
    ERRchktss(rsa_priv_dec, r, goto out);

    DBG("Decrypted message (size=%i):\n", message->size);
    DBGBUF(&message->buffer[0], message->size);

    flen = message->size;
    if (flen > RSA_size(rsa) || flen <= 0) {
        ERR(rsa_priv_dec, TPM2TSS_R_DIGEST_TOO_LARGE);
        goto error;
    }
    memcpy(to, &message->buffer[0], flen);

    goto out;

 error:
    r = -1;

 out:
    Esys_Free(message);
    if (keyHandle != ESYS_TR_NONE) {
        if (tpm2Data->privatetype == KEY_TYPE_HANDLE) {
            Esys_TR_Close(esys_ctx, &keyHandle);
        } else {
            Esys_FlushContext(esys_ctx, keyHandle);
        }
    }

    esys_ctx_free(&esys_ctx);
    return (r == TSS2_RC_SUCCESS) ? flen : 0;
}

/** Clean up the RSA key
 *
 * @param rsa The rsa key object.
 * @retval 1 on success, or 0 on failure
 */
static int
rsa_finish(RSA *rsa)
{
    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);

    if (tpm2Data != NULL) {
        OPENSSL_free(tpm2Data);
        RSA_set_app_data(rsa, NULL);
    }
    if (rsa_orig_finish) {
       rsa_orig_finish(rsa);
    }
    return 1;
}

/** Helper to populate the RSA key object.
 *
 * In order to use an RSA key object in a typical manner, all fields of the
 * OpenSSL's corresponding object bust be filled. This function fills the public
 * values correctly and fill the private values with 0.
 * @param rsa The key object to fill.
 * @retval 0 on failure
 * @retval 1 on success
 */
static int
populate_rsa(RSA *rsa)
{
    TPM2_DATA *tpm2Data = RSA_get_app_data(rsa);
    UINT32 exponent;

    if (tpm2Data == NULL)
        goto error;

    exponent = tpm2Data->pub.publicArea.parameters.rsaDetail.exponent;
    if (!exponent)
        exponent = 0x10001;

#if OPENSSL_VERSION_NUMBER < 0x10100000
    /* Setting the public portion of the key */
    rsa->n = BN_bin2bn(tpm2Data->pub.publicArea.unique.rsa.buffer,
                       tpm2Data->pub.publicArea.unique.rsa.size, rsa->n);
    if (rsa->n == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    if (rsa->e == NULL)
        rsa->e = BN_new();
    if (rsa->e == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->e, exponent);

    /* Setting private portions to 0 values so the public key can be extracted
       from the keyfile if this is desired. */
    if (rsa->d == NULL)
        rsa->d = BN_new();
    if (rsa->d == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->d, 0);
    if (rsa->p == NULL)
        rsa->p = BN_new();
    if (rsa->p == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->p, 0);
    if (rsa->q == NULL)
        rsa->q = BN_new();
    if (rsa->q == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->q, 0);
    if (rsa->dmp1 == NULL)
        rsa->dmp1 = BN_new();
    if (rsa->dmp1 == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->dmp1, 0);
    if (rsa->dmq1 == NULL)
        rsa->dmq1 = BN_new();
    if (rsa->dmq1 == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->dmq1, 0);
    if (rsa->iqmp == NULL)
        rsa->iqmp = BN_new();
    if (rsa->iqmp == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }
    BN_set_word(rsa->iqmp, 0);
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    BIGNUM *n = BN_bin2bn(tpm2Data->pub.publicArea.unique.rsa.buffer,
                          tpm2Data->pub.publicArea.unique.rsa.size, NULL);
    BIGNUM *e = BN_new();
    BIGNUM *d = BN_new();
    BIGNUM *p = BN_new();
    BIGNUM *q = BN_new();
    BIGNUM *dmp1 = BN_new();
    BIGNUM *dmq1 = BN_new();
    BIGNUM *iqmp = BN_new();

    if (!n || !e || !d || !p || !q || !dmp1 || !dmq1 || !iqmp) {
        if (n)
            BN_free(n);
        if (e)
            BN_free(e);
        if (d)
            BN_free(d);
        if (p)
            BN_free(p);
        if (q)
            BN_free(q);
        if (dmp1)
            BN_free(dmp1);
        if (dmq1)
            BN_free(dmq1);
        if (iqmp)
            BN_free(iqmp);

        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        goto error;
    }

    BN_set_word(e, exponent);
    BN_set_word(d, 0);
    BN_set_word(p, 0);
    BN_set_word(q, 0);
    BN_set_word(dmp1, 0);
    BN_set_word(dmq1, 0);
    BN_set_word(iqmp, 0);

    RSA_set0_key(rsa, n, e, d);
    RSA_set0_factors(rsa, p, q);
    RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

    return 1;
 error:
    return 0;
}

/** Helper to load an RSA key from a tpm2Data
 *
 * This function creates a key object given a TPM2_DATA object. The resulting
 * key object can then be used for signing and decrypting with the tpm2tss
 * engine. Ownership of the TPM2_DATA object is taken on success.
 * @param tpm2Data The key data to use. Must have been allocated using
 * OPENSSL_malloc.
 * @retval key The key object
 * @retval NULL on failure.
 */
EVP_PKEY *
tpm2tss_rsa_makekey(TPM2_DATA *tpm2Data)
{
    EVP_PKEY *pkey;
    RSA *rsa;

    DBG("Creating RSA key object.\n");

    /* create the new objects to return */
    if ((pkey = EVP_PKEY_new()) == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        return NULL;
    }

    if ((rsa = RSA_new()) == NULL) {
        ERR(populate_rsa, ERR_R_MALLOC_FAILURE);
        EVP_PKEY_free(pkey);
        return NULL;
    }
#if OPENSSL_VERSION_NUMBER < 0x10100000
    rsa->meth = &rsa_methods;
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    RSA_set_method(rsa, rsa_methods);
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
        ERR(populate_rsa, TPM2TSS_R_GENERAL_FAILURE);
        RSA_free(rsa);
        goto error;
    }

    if (!RSA_set_app_data(rsa, tpm2Data)) {
        ERR(populate_rsa, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    if (!populate_rsa(rsa)) {
        RSA_set_app_data(rsa, NULL);
        goto error;
    }

    DBG("Created RSA key object.\n");

    return pkey;
 error:
    EVP_PKEY_free(pkey);
    return NULL;
}

/** Generate a tpm2tss rsa key object.
 *
 * This function creates a new TPM RSA key. The TPM data is stored inside the
 * object*s app data and can be retrieved using RSA_get_app_data().
 * @param rsa The key object for the TPM RSA key to be created.
 * @param bits The key size
 * @param e The key's exponent
 * @param password The Password to be set for the new key
 * @retval 1 on success
 * @retval 0 on failure
 */
int
tpm2tss_rsa_genkey(RSA *rsa, int bits, BIGNUM *e, char *password,
                   TPM2_HANDLE parentHandle)
{
    DBG("Generating RSA key for %i bits keysize.\n", bits);

    TSS2_RC r = TSS2_RC_SUCCESS;
    ESYS_CONTEXT *esys_ctx = NULL;
    ESYS_TR parent = ESYS_TR_NONE;
    TPM2B_PUBLIC *keyPublic = NULL;
    TPM2B_PRIVATE *keyPrivate = NULL;
    TPM2_DATA *tpm2Data = NULL;
    TPM2B_PUBLIC inPublic = keyTemplate;
    TPM2B_SENSITIVE_CREATE inSensitive = {
        .sensitive = {
            .userAuth = {
                 .size = 0,
             },
            .data = {
                 .size = 0,
             }
        }
    };

    tpm2Data = OPENSSL_malloc(sizeof(*tpm2Data));
    if (tpm2Data == NULL) {
        ERR(tpm2tss_rsa_genkey, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }
    memset(tpm2Data, 0, sizeof(*tpm2Data));

    inPublic.publicArea.parameters.rsaDetail.keyBits = bits;
    if (e)
        inPublic.publicArea.parameters.rsaDetail.exponent = BN_get_word(e);

    if (password) {
        DBG("Setting a password for the created key.\n");
        if (strlen(password) > sizeof(tpm2Data->userauth.buffer) - 1) {
            goto error;
        }
        tpm2Data->userauth.size = strlen(password);
        memcpy(&tpm2Data->userauth.buffer[0], password,
               tpm2Data->userauth.size);

        inSensitive.sensitive.userAuth.size = strlen(password);
        memcpy(&inSensitive.sensitive.userAuth.buffer[0], password,
               strlen(password));
    } else
        tpm2Data->emptyAuth = 1;

    r = init_tpm_parent(&esys_ctx, parentHandle, &parent);
    ERRchktss(tpm2tss_rsa_genkey, r, goto error);

    tpm2Data->parent = parentHandle;

    DBG("Generating the RSA key inside the TPM.\n");

    r = Esys_Create(esys_ctx, parent,
                    ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                    &inSensitive, &inPublic, &allOutsideInfo, &allCreationPCR,
                    &keyPrivate, &keyPublic, NULL, NULL, NULL);
    ERRchktss(tpm2tss_rsa_genkey, r, goto error);

    DBG("Generated the RSA key inside the TPM.\n");

    tpm2Data->pub = *keyPublic;
    tpm2Data->priv = *keyPrivate;

    if (!RSA_set_app_data(rsa, tpm2Data)) {
        ERR(tpm2tss_rsa_genkey, TPM2TSS_R_GENERAL_FAILURE);
        goto error;
    }

    if (!populate_rsa(rsa)) {
        goto error;
    }

    goto end;
 error:
    r = -1;
    if (rsa)
        RSA_set_app_data(rsa, NULL);
    if (tpm2Data)
        OPENSSL_free(tpm2Data);

 end:
    Esys_Free(keyPrivate);
    Esys_Free(keyPublic);

    if (parent != ESYS_TR_NONE && !parentHandle)
        Esys_FlushContext(esys_ctx, parent);

    esys_ctx_free(&esys_ctx);

    return (r == TSS2_RC_SUCCESS);
}

#if OPENSSL_VERSION_NUMBER < 0x10100000
RSA_METHOD rsa_methods = {
    "TPM2TSS RSA methods",
    NULL,                       /* tpm_rsa_pub_enc */
    NULL,                       /* tpm_rsa_pub_dec */
    rsa_priv_enc,               /* act sign */
    rsa_priv_dec,               /* act decrypt */
    NULL,                       /* rsa_mod_exp */
    NULL,                       /* bn_mod_exp */
    NULL,                       /* init */
    NULL,                       /* finish */
    0,
    NULL,                       /* app_data */
    NULL,                       /* sign */
    NULL,                       /* verify */
    NULL                        /* genkey */
};
#endif                          /* OPENSSL_VERSION_NUMBER < 0x10100000 */

#ifdef HAVE_OPENSSL_DIGEST_SIGN
static int
rsa_pkey_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
{
    if (rsa_pkey_orig_copy && !rsa_pkey_orig_copy(dst, src))
        return 0;

    return digest_sign_copy(dst, src);
}

static void
rsa_pkey_cleanup(EVP_PKEY_CTX *ctx)
{
    digest_sign_cleanup(ctx);

    if (rsa_pkey_orig_cleanup)
        rsa_pkey_orig_cleanup(ctx);
}

/* called for digest & sign init, after message digest algorithm set */
static int
rsa_digest_custom(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
{
    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
    RSA *rsa = EVP_PKEY_get0_RSA(pkey);
    TPM2_DATA *tpm2data = RSA_get_app_data(rsa);

    DBG("rsa_digest_custom %p %p\n", ctx, mctx);

    return digest_sign_init(ctx, mctx, tpm2data, RSA_size(rsa));
}

static int
rsa_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
            EVP_MD_CTX *mctx)
{
    TPM2_SIG_DATA *sig_data = EVP_PKEY_CTX_get_app_data(ctx);
    TSS2_RC r = TSS2_RC_SUCCESS;
    TPMT_TK_HASHCHECK *validation_ptr = NULL;
    TPM2B_DIGEST *digest_ptr = NULL;
    TPMT_SIGNATURE *tpm_sig = NULL;
    int pad_mode;

    DBG("rsa_signctx %p %p sig_data %p\n", ctx, mctx, sig_data);

    if (!sig) {
        /* caller just wants to know the size */
        *siglen = sig_data->sig_size;
        return 1;
    }

    if (!sig_data) {
        /* handle non-TPM key */
        unsigned char md[EVP_MAX_MD_SIZE];
        unsigned int md_len = 0;

        if (!EVP_DigestFinal_ex(mctx, md, &md_len))
            return 0;
        if (EVP_PKEY_sign(ctx, sig, siglen, md, md_len) <= 0)
            return 0;
        return 1;
    }

    if (EVP_PKEY_CTX_get_rsa_padding(ctx, &pad_mode) <= 0)
        return 0;

    TPMT_SIG_SCHEME in_scheme = {
        .scheme = TPM2_ALG_NULL,
        .details.rsassa.hashAlg = sig_data->hash_alg,
    };
    switch (pad_mode) {
    case RSA_PKCS1_PADDING:
        in_scheme.scheme = TPM2_ALG_RSASSA;
        break;
    case RSA_PKCS1_PSS_PADDING:
        in_scheme.scheme = TPM2_ALG_RSAPSS;
        break;
    default:
        ERR(rsa_signctx, TPM2TSS_R_PADDING_UNKNOWN);
        return 0;
    }

    if (!digest_finish(sig_data, &digest_ptr, &validation_ptr))
        return 0;

    r = Esys_Sign(sig_data->key->esys_ctx, sig_data->key->key_handle,
                  ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
                  digest_ptr, &in_scheme, validation_ptr, &tpm_sig);
    ERRchktss(rsa_signctx, r, goto error);

    memcpy(sig, tpm_sig->signature.rsassa.sig.buffer, sig_data->sig_size);
    *siglen = sig_data->sig_size;

    r = 1;
    goto out;

 error:
    r = 0;
 out:
    Esys_Free(tpm_sig);
    Esys_Free(digest_ptr);
    Esys_Free(validation_ptr);

    return r;
}
#endif /* HAVE_OPENSSL_DIGEST_SIGN */

/** Initialize the tpm2tss engine's rsa submodule
 *
 * Initialize the tpm2tss engine's submodule by setting function pointer.
 * @param e The engine context.
 * @retval 1 on success
 * @retval 0 on failure
 */
int
init_rsa(ENGINE *e)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000
    default_rsa = RSA_PKCS1_SSLeay();
    if (default_rsa == NULL)
        return 0;

    rsa_methods.rsa_pub_enc = default_rsa->rsa_pub_enc;
    rsa_methods.rsa_pub_dec = default_rsa->rsa_pub_dec;
    rsa_methods.rsa_mod_exp = default_rsa->rsa_mod_exp;
    rsa_methods.bn_mod_exp = default_rsa->bn_mod_exp;

    if (!ENGINE_set_RSA(e, &rsa_methods))
        return 0;
#else /* OPENSSL_VERSION_NUMBER < 0x10100000 */
    default_rsa = RSA_PKCS1_OpenSSL();
    if (default_rsa == NULL)
        return 0;

    rsa_methods = RSA_meth_dup(default_rsa);
    RSA_meth_set1_name(rsa_methods, "TPM2TSS RSA methods");
    RSA_meth_set_priv_enc(rsa_methods, rsa_priv_enc);
    RSA_meth_set_priv_dec(rsa_methods, rsa_priv_dec);
    rsa_orig_finish = RSA_meth_get_finish(rsa_methods);
    RSA_meth_set_finish(rsa_methods, rsa_finish);

    if (!ENGINE_set_RSA(e, rsa_methods))
        return 0;
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000 */

#if HAVE_OPENSSL_DIGEST_SIGN
    /* digest and sign support */

    EVP_PKEY_METHOD *pkey_rsa_methods;

    pkey_rsa_methods = EVP_PKEY_meth_new(EVP_PKEY_RSA,
                                         EVP_PKEY_FLAG_AUTOARGLEN);
    if (pkey_rsa_methods == NULL)
        return 0;

    const EVP_PKEY_METHOD *pkey_orig_rsa_methods =
        EVP_PKEY_meth_find(EVP_PKEY_RSA);
    if (pkey_orig_rsa_methods == NULL)
        return 0;
    EVP_PKEY_meth_copy(pkey_rsa_methods, pkey_orig_rsa_methods);
    /*
     * save originals since we only override some of the pkey
     * functionality, rather than reimplementing all of it
     */
    EVP_PKEY_meth_get_copy(pkey_rsa_methods, &rsa_pkey_orig_copy);
    EVP_PKEY_meth_get_cleanup(pkey_rsa_methods, &rsa_pkey_orig_cleanup);

    EVP_PKEY_meth_set_copy(pkey_rsa_methods, rsa_pkey_copy);
    EVP_PKEY_meth_set_cleanup(pkey_rsa_methods, rsa_pkey_cleanup);
    EVP_PKEY_meth_set_signctx(pkey_rsa_methods, NULL, rsa_signctx);
    EVP_PKEY_meth_set_digest_custom(pkey_rsa_methods, rsa_digest_custom);
    EVP_PKEY_meth_add0(pkey_rsa_methods);
#endif /* HAVE_OPENSSL_DIGEST_SIGN */

    return 1;
}


================================================
FILE: src/tpm2-tss-engine.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/
#include "config.h"

#include <stdlib.h>
#include <string.h>

#include <openssl/engine.h>
#include <openssl/pem.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>

#include <tss2/tss2_mu.h>
#include <tss2/tss2_esys.h>

#include "tpm2-tss-engine.h"
#include "tpm2-tss-engine-common.h"

/**
 * The identifier of the engine
 */
static const char *engine_id = "tpm2tss";

/**
 * The full name of the engine
 */
static const char *engine_name = "TPM2-TSS engine for OpenSSL";

TPM2B_DIGEST ownerauth = { .size = 0 };
TPM2B_DIGEST parentauth = { .size = 0 };

char *tcti_nameconf = NULL;

/** Retrieve password
 *
 * Helper function to retreive a password from the user.
 * @param prompt_info [in] The object name to ask the user for
 * @param ui_method [in] The ui method callbacks to be used
 * @param cb_data [in] The callback data for the ui
 * @param auth [out] The user provided password
 * @retval 1 on success
 * @retval 0 on failure
 */
static int
get_auth(const char *prompt_info, UI_METHOD *ui_method, void *cb_data,
         TPM2B_AUTH *auth)
{
    DBG("get_auth called for object %s with ui_method %p\n", prompt_info,
        ui_method);
    char *ui_prompt = NULL;
    UI *ui = NULL;
    if (!ui_method) {
        ERR(get_auth, TPM2TSS_R_UI_ERROR);
        goto error;
    }
    ui = UI_new_method(ui_method);
    if (!ui) {
        ERR(get_auth, TPM2TSS_R_UI_ERROR);
        goto error;
    }
    ui_prompt = UI_construct_prompt(ui, "password", prompt_info);
    if (!ui_prompt) {
        ERR(get_auth, TPM2TSS_R_UI_ERROR);
        goto error;
    }
    if (0 > UI_add_input_string(ui, ui_prompt, UI_INPUT_FLAG_DEFAULT_PWD,
                                (char *)&auth->buffer[0], 0,
                                sizeof(auth->buffer) - 1)) {
        ERR(get_auth, TPM2TSS_R_UI_ERROR);
        goto error;
    }
    UI_add_user_data(ui, cb_data);
    if (0 > UI_process(ui)) {
        ERR(get_auth, TPM2TSS_R_UI_ERROR);
        goto error;
    }
    auth->size = strlen((char *)&auth->buffer[0]);
    OPENSSL_free(ui_prompt);
    UI_free(ui);

    DBG("password is %s\n", (char *)&auth->buffer[0]);

    return 1;
 error:
    if (ui_prompt)
        OPENSSL_free(ui_prompt);
    if (ui)
        UI_free(ui);
    return 0;
}

static const ENGINE_CMD_DEFN cmd_defns[] = {
    { TPM2TSS_SET_OWNERAUTH, "SET_OWNERAUTH",
     "Set the password for the owner hierarchy (default none)",
     ENGINE_CMD_FLAG_STRING },
    { TPM2TSS_SET_TCTI, "SET_TCTI",
     "Set the TCTI module and options (default none)",
     ENGINE_CMD_FLAG_STRING },
    { TPM2TSS_SET_PARENTAUTH, "SET_PARENTAUTH",
     "Set the password for the parent key (default none)",
     ENGINE_CMD_FLAG_STRING },
    {0, NULL, NULL, 0}
};

static int
engine_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) ())
{
    (void)(e);
    (void)(i);
    (void)(f);
    switch (cmd) {
    case TPM2TSS_SET_OWNERAUTH:
        if (!p) {
            DBG("Setting owner auth to empty auth.\n");
            ownerauth.size = 0;
            return 1;
        }
        DBG("Setting owner auth to password.\n");
        if (strlen((char *)p) > sizeof(ownerauth.buffer) - 1) {
            return 0;
        }
        ownerauth.size = strlen((char *)p);
        memcpy(&ownerauth.buffer[0], p, ownerauth.size);
        return 1;
    case TPM2TSS_SET_TCTI:
        OPENSSL_free(tcti_nameconf);
        if (!p) {
            DBG("Setting TCTI to the ESAPI default\n");
        } else {
            tcti_nameconf = OPENSSL_strdup(p);
            DBG("Setting TCTI option to \"%s\"\n", tcti_nameconf);
        }
        return 1;
    case TPM2TSS_SET_PARENTAUTH:
        if (!p) {
            DBG("Setting parent auth to empty auth.\n");
            parentauth.size = 0;
            return 1;
        }
        DBG("Setting parent auth to password.\n");
        if (strlen((char *)p) > sizeof(parentauth.buffer) - 1) {
            return 0;
        }
        parentauth.size = strlen((char *)p);
        memcpy(&parentauth.buffer[0], p, parentauth.size);
        return 1;
    default:
        break;
    }
    ERR(engine_ctrl, TPM2TSS_R_UNKNOWN_CTRL);
    return 0;
}

/** Load a TPM2TSS key
 *
 * This function implements the prototype for loading a key from a file.
 * @param e The engine for this callback (unused).
 * @param key_id The name of the file with the TPM key data.
 * @param ui The ui functions for querying the user.
 * @param cb_data Callback data.
 */
static EVP_PKEY *
loadkey(ENGINE *e, const char *key_id, UI_METHOD *ui, void *cb_data)
{
    (void)(e);
    (void)(ui);
    (void)(cb_data);

    TPM2_DATA *tpm2Data = NULL;
    EVP_PKEY *pkey = NULL;

    DBG("Loading private key %s\n", key_id);
    if (strncmp(key_id, "0x81", 4) == 0) {
        uint32_t handle;
        sscanf(key_id, "0x%x", &handle);
        if (!tpm2tss_tpm2data_readtpm(handle, &tpm2Data)) {
            ERR(loadkey, TPM2TSS_R_TPM2DATA_READ_FAILED);
            goto error;
        }
    } else {
        if (!tpm2tss_tpm2data_read(key_id, &tpm2Data)) {
            ERR(loadkey, TPM2TSS_R_TPM2DATA_READ_FAILED);
            goto error;
        }
    }

    if (tpm2Data->emptyAuth) {
        tpm2Data->userauth.size = 0;
    } else {
        if (!get_auth("user key", ui, cb_data, &tpm2Data->userauth)) {
            goto error;
        }
    }

    DBG("Loaded key uses alg-id %x\n", tpm2Data->pub.publicArea.type);

    switch (tpm2Data->pub.publicArea.type) {
    case TPM2_ALG_RSA:
        pkey = tpm2tss_rsa_makekey(tpm2Data);
        break;
    case TPM2_ALG_ECC:
        pkey = tpm2tss_ecc_makekey(tpm2Data);
        break;
    default:
        ERR(loadkey, TPM2TSS_R_UNKNOWN_ALG);
        goto error;
    }
    if (!pkey) {
        ERR(loadkey, TPM2TSS_R_CANNOT_MAKE_KEY);
        goto error;
    }

    DBG("TPM2 Key loaded\n");

    return pkey;
error:
    if (tpm2Data)
        OPENSSL_free(tpm2Data);
    return NULL;
}

/** Initialize the tpm2tss engine
 *
 * Initialize the tpm2tss engine by calling each of the submodules' init
 * functions for setting function pointer.
 * @param e The engine context.
 * @retval 1 on success
 * @retval 0 on failure
 */
static int
init_engine(ENGINE *e) {
    static int initialized = 0;

    DBG("Initializing\n");

    if (initialized) {
        DBG("Already initialized\n");
        return 1;
    }

    int rc;

#ifdef ENABLE_TCTIENVVAR
    /*  Set the default TCTI option from the environment */
    OPENSSL_free(tcti_nameconf);
    if (getenv("TPM2TSSENGINE_TCTI")) {
        tcti_nameconf = OPENSSL_strdup(getenv("TPM2TSSENGINE_TCTI"));
    }
#endif

    rc = init_rand(e);
    if (rc != 1) {
        ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);
        return rc;
    }

    rc = init_rsa(e);
    if (rc != 1) {
        ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);
        return rc;
    }

    rc = init_ecc(e);
    if (rc != 1) {
        ERR(init_engine, TPM2TSS_R_SUBINIT_FAILED);
        return rc;
    }

    initialized = 1;
    return 1;
}

/** Destroys the engine context
 *
 * Unloads the strings of the tpm2tss engine.
 * @param e The engine context (unused).
 * @retval 1 for success
 */
static int
destroy_engine(ENGINE *e)
{
    (void)(e);
    OPENSSL_free(tcti_nameconf);
    ERR_unload_TPM2TSS_strings();
    return 1;
}

/** OpenSSL's method to bind an engine.
 *
 * This initializes the name, id and function pointers of the engine.
 * @param e The TPM engine to initialize
 * @param id The identifier of the engine
 * @retval 0 if binding failed
 * @retval 1 on success
 */
static int
bind(ENGINE *e, const char *id)
{
    (void)(id);

    if (!ENGINE_set_id(e, engine_id)) {
        DBG("ENGINE_set_id failed\n");
        goto end;
    }
    if (!ENGINE_set_name(e, engine_name)) {
        DBG("ENGINE_set_name failed\n");
        goto end;
    }

    /* The init function is not allways called so we initialize crypto methods
       directly from bind. */
    if (!init_engine(e)) {
        DBG("tpm2tss enigne initialization failed\n");
        goto end;
    }

    if (!ENGINE_set_load_privkey_function(e, loadkey)) {
        DBG("ENGINE_set_load_privkey_function failed\n");
        goto end;
    }

    if (!ENGINE_set_destroy_function(e, destroy_engine)) {
        DBG("ENGINE_set_destroy_function failed\n");
        goto end;
    }

    if (!ENGINE_set_ctrl_function(e, engine_ctrl)) {
        DBG("ENGINE_set_ctrl_function failed\n");
        goto end;
    }

    if (!ENGINE_set_cmd_defns(e, cmd_defns)) {
        DBG("ENGINE_set_cmd_defns failed\n");
        goto end;
    }

    ERR_load_TPM2TSS_strings();
    return 1;
 end:
    return 0;
}

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()


================================================
FILE: src/tpm2tss-genkey.c
================================================
/*******************************************************************************
 * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

#include <string.h>
#include <strings.h>
#include <inttypes.h>
#include <unistd.h>
#include <getopt.h>

#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/pem.h>

#include "tpm2-tss-engine.h"
#include "tpm2-tss-engine-common.h"

/* This tool uses a different error reporting scheme than the lib. */
#undef ERR
#define VERB(...) if (opt.verbose) fprintf(stderr, __VA_ARGS__)
#define ERR(...) fprintf(stderr, __VA_ARGS__)

char *help =
    "Usage: [options] <filename>\n"
    "Arguments:\n"
    "    <filename>      storage for the encrypted private key\n"
    "Options:\n"
    "    -a, --alg       public key algorithm (rsa, ecdsa) (default: rsa)\n"
    "    -c, --curve     curve for ecc (default: nist_p256)\n"
    "    -e, --exponent  exponent for rsa (default: 65537)\n"
    "    -h, --help      print help\n"
    "    -u, --public    import a key and read its public portion from this file\n"
    "    -r, --private   import the sensitive key portion from this file\n"
    "    -o, --ownerpw   password for the owner hierarchy (default: none)\n"
    "    -p, --password  password for the created key (default: none)\n"
    "    -P, --parent    specific handle for the parent key (default: none)\n"
    "    -s, --keysize   key size in bits for rsa (default: 2048)\n"
    "    -v, --verbose   print verbose messages\n"
    "    -W, --parentpw  password for the parent key (default: none)\n"
    "    -t, --tcti      tcti configuration string (default: none)\n"
    "\n";

static const char *optstr = "a:c:e:hu:r:o:p:P:s:vW:t:";

static const struct option long_options[] = {
    {"alg",      required_argument, 0, 'a'},
    {"curve",    required_argument, 0, 'c'},
    {"exponent", required_argument, 0, 'e'},
    {"help",     no_argument,       0, 'h'},
    {"public",   required_argument, 0, 'u'},
    {"private",  required_argument, 0, 'r'},
    {"ownerpw",  required_argument, 0, 'o'},
    {"password", required_argument, 0, 'p'},
    {"parent",   required_argument, 0, 'P'},
    {"keysize",  required_argument, 0, 's'},
    {"verbose",  no_argument,       0, 'v'},
    {"parentpw", required_argument, 0, 'W'},
    {"tcti",     required_argument, 0, 't'},
    {0,          0,                 0,  0 }
};

static struct opt {
    char *filename;
    TPMI_ALG_PUBLIC alg;
    TPMI_ECC_CURVE curve;
    int exponent;
    char *importpub;
    char *importtpm;
    char *ownerpw;
    char *password;
    TPM2_HANDLE parent;
    char *parentpw;
    int keysize;
    int verbose;
    char *tcti_conf;
} opt;

/** Parse and set command line options.
 *
 * This function parses the command line options and sets the appropriate values
 * in the opt struct.
 * @param argc The argument count.
 * @param argv The arguments.
 * @retval 0 on success
 * @retval 1 on failure
 */
int
parse_opts(int argc, char **argv)
{
    /* set the default values */
    opt.filename = NULL;
    opt.alg = TPM2_ALG_RSA;
    opt.curve = TPM2_ECC_NIST_P256;
    opt.exponent = 65537;
    opt.importpub = NULL;
    opt.importtpm = NULL;
    opt.ownerpw = NULL;
    opt.password = NULL;
    opt.parent = 0;
    opt.parentpw = NULL;
    opt.keysize = 2048;
    opt.verbose = 0;
    opt.tcti_conf = NULL;

    /* parse the options */
    int c;
    int opt_idx = 0;
    while (-1 != (c = getopt_long(argc, argv, optstr,
                                  long_options, &opt_idx))) {
        switch(c) {
        case 'h':
            printf("%s", help);
            exit(0);
        case 'v':
            opt.verbose = 1;
            break;
        case 'a':
            if (strcasecmp(optarg, "rsa") == 0) {
                opt.alg = TPM2_ALG_RSA;
                break;
            } else if (strcasecmp(optarg, "ecdsa") == 0) {
                opt.alg = TPM2_ALG_ECDSA;
                break;
            } else {
                ERR("Unknown algorithm.\n");
                exit(1);
            }
        case 'c':
            if (strcasecmp(optarg, "nist_p256") == 0) {
                opt.curve = TPM2_ECC_NIST_P256;
                break;
            } else if (strcasecmp(optarg, "nist_p384") == 0) {
                opt.curve = TPM2_ECC_NIST_P384;
                break;
            } else {
                ERR("Unknown curve.\n");
                exit(1);
            }
        case 'e':
            if (sscanf(optarg, "%i", &opt.exponent) != 1) {
                ERR("Error parsing keysize.\n");
                exit(1);
            }
            break;
        case 'u':
            opt.importpub = optarg;
            break;
        case 'r':
            opt.importtpm = optarg;
            break;
        case 'o':
            opt.ownerpw = optarg;
            break;
        case 'p':
            opt.password = o
Download .txt
gitextract_x8we6x6b/

├── .ci/
│   ├── coverity.run
│   ├── docker.env
│   ├── docker.run
│   └── get_deps.sh
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .lgtm.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── INSTALL.md
├── LICENSE
├── MAINTAINERS
├── Makefile.am
├── README.md
├── RELEASE.md
├── SECURITY.md
├── bootstrap
├── configure.ac
├── include/
│   └── tpm2-tss-engine.h
├── m4/
│   └── flags.m4
├── man/
│   ├── tpm2tss-genkey.1.md
│   ├── tpm2tss_ecc_genkey.3.md
│   ├── tpm2tss_ecc_getappdata.3.md
│   ├── tpm2tss_ecc_makekey.3.md
│   ├── tpm2tss_rsa_genkey.3.md
│   ├── tpm2tss_rsa_makekey.3.md
│   └── tpm2tss_tpm2data_write.3.md
├── openssl.conf.sample
├── src/
│   ├── tpm2-tss-engine-common.c
│   ├── tpm2-tss-engine-common.h
│   ├── tpm2-tss-engine-digest-sign.c
│   ├── tpm2-tss-engine-ecc.c
│   ├── tpm2-tss-engine-err.c
│   ├── tpm2-tss-engine-err.h
│   ├── tpm2-tss-engine-rand.c
│   ├── tpm2-tss-engine-rsa.c
│   ├── tpm2-tss-engine.c
│   └── tpm2tss-genkey.c
└── test/
    ├── ecdh.sh
    ├── ecdsa-emptyauth.sh
    ├── ecdsa-handle-flush.sh
    ├── ecdsa-restricted.sh
    ├── ecdsa.sh
    ├── error_tpm2-tss-engine-common.c
    ├── failload.sh
    ├── failwrite.sh
    ├── neg-handle.pem
    ├── rand.sh
    ├── rsadecrypt.sh
    ├── rsasign.sh
    ├── rsasign_importtpm.sh
    ├── rsasign_importtpmparent.sh
    ├── rsasign_parent.sh
    ├── rsasign_parent_pass.sh
    ├── rsasign_persistent.sh
    ├── rsasign_persistent_emptyauth.sh
    ├── rsasign_restricted.sh
    ├── sclient.sh
    ├── sh_log_compiler.sh
    ├── sserver.sh
    └── tpm2-tss-engine-common.c
Download .txt
SYMBOL INDEX (75 symbols across 12 files)

FILE: include/tpm2-tss-engine.h
  type KEY_TYPE (line 41) | typedef enum {
  type TPM2_DATA (line 46) | typedef struct {

FILE: src/tpm2-tss-engine-common.c
  function TSS2_RC (line 68) | TSS2_RC
  function TSS2_RC (line 101) | TSS2_RC
  function tpm2tss_tpm2data_write (line 129) | int
  function tpm2tss_tpm2data_readtpm (line 209) | int
  function tpm2tss_tpm2data_read (line 342) | int
  function TSS2_RC (line 455) | TSS2_RC
  function TSS2_RC (line 566) | TSS2_RC
  function tpm2tss_tpm2data_importtpm (line 640) | int

FILE: src/tpm2-tss-engine-common.h
  type T2TE_ATOMIC_INT (line 40) | typedef _Atomic int T2TE_ATOMIC_INT;
  type T2TE_ATOMIC_INT (line 42) | typedef int T2TE_ATOMIC_INT;
  type TSSPRIVKEY (line 156) | typedef struct {
  type TPM2_SIG_KEY_CTX (line 172) | typedef struct {
  type TPM2_SIG_DATA (line 179) | typedef struct {

FILE: src/tpm2-tss-engine-digest-sign.c
  function digest_init (line 56) | static int
  function digest_update (line 104) | int
  function digest_finish (line 140) | int
  function digest_sign_init (line 168) | int
  function digest_sign_copy (line 238) | int
  function digest_sign_cleanup (line 290) | void

FILE: src/tpm2-tss-engine-ecc.c
  function EC_GROUP_order_bits (line 101) | static int EC_GROUP_order_bits(const EC_GROUP *group)
  function init_tpm_public_point (line 134) | static int
  function ecdh_compute_key (line 180) | static int
  function ECDSA_SIG (line 235) | static ECDSA_SIG *
  function ECDSA_SIG (line 304) | static ECDSA_SIG *
  function ecdsa_pkey_copy (line 407) | static int
  function ecdsa_pkey_cleanup (line 416) | static void
  function ecdsa_digest_custom (line 426) | static int
  function ecdsa_signctx (line 438) | static int
  function populate_ecc (line 502) | static int
  function tpm2tss_ecc_setappdata (line 663) | int
  function free_ecc_appdata (line 677) | static void
  function tpm2tss_ecc_genkey (line 705) | int
  function init_ecc (line 806) | int

FILE: src/tpm2-tss-engine-err.c
  function ERR_load_TPM2TSS_strings (line 114) | void
  function ERR_unload_TPM2TSS_strings (line 137) | void
  function ERR_error (line 161) | void
  function printbuf (line 179) | void

FILE: src/tpm2-tss-engine-rand.c
  function rand_seed (line 47) | static int
  function rand_bytes (line 91) | static int
  function rand_status (line 125) | static int
  function init_rand (line 147) | int

FILE: src/tpm2-tss-engine-rsa.c
  function rsa_priv_enc (line 108) | static int
  function rsa_priv_dec (line 214) | static int
  function rsa_finish (line 304) | static int
  function populate_rsa (line 328) | static int
  function EVP_PKEY (line 462) | EVP_PKEY *
  function tpm2tss_rsa_genkey (line 522) | int
  function rsa_pkey_copy (line 639) | static int
  function rsa_pkey_cleanup (line 648) | static void
  function rsa_digest_custom (line 658) | static int
  function rsa_signctx (line 670) | static int
  function init_rsa (line 752) | int

FILE: src/tpm2-tss-engine.c
  function get_auth (line 72) | static int
  function engine_ctrl (line 133) | static int
  function EVP_PKEY (line 190) | static EVP_PKEY *
  function init_engine (line 258) | static int
  function destroy_engine (line 307) | static int
  function bind (line 324) | static int

FILE: src/tpm2tss-genkey.c
  type option (line 72) | struct option
  type opt (line 89) | struct opt {
  function parse_opts (line 114) | int
  function TPM2_DATA (line 240) | static TPM2_DATA *
  function TPM2_DATA (line 289) | static TPM2_DATA *
  function main (line 327) | int

FILE: test/error_tpm2-tss-engine-common.c
  function TSS2_RC (line 18) | TSS2_RC
  function check_tpm2tss_tpm2data_readtpm (line 29) | void
  function check_tpm2tss_tpm2data_read (line 38) | void
  function check_init_tpm_parent_via_api (line 47) | void
  function check_init_tpm_parent (line 56) | void
  function check_init_tpm_key (line 67) | void
  function main (line 84) | int

FILE: test/tpm2-tss-engine-common.c
  function check_tpm2tss_tpm2data_read (line 12) | void
  function main (line 23) | int
Condensed preview — 62 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (240K chars).
[
  {
    "path": ".ci/coverity.run",
    "chars": 3070,
    "preview": "#!/usr/bin/env bash\n# SPDX-License-Identifier: BSD-2\n\nset -eo pipefail\n\necho \"PROJECT=$PROJECT\"\n\nif [ -z \"$COVERITY_SCAN"
  },
  {
    "path": ".ci/docker.env",
    "chars": 252,
    "preview": "# SPDX-License-Identifier: BSD-2\n\nPROJECT\nDOCKER_BUILD_DIR\nLD_LIBRARY_PATH=/usr/local/lib/\n\nCC\n\nCOVERITY_SCAN_TOKEN\nCOVE"
  },
  {
    "path": ".ci/docker.run",
    "chars": 747,
    "preview": "#!/usr/bin/env bash\n# SPDX-License-Identifier: BSD-2\n\nset -exo pipefail\n\ngit config --global --add safe.directory /works"
  },
  {
    "path": ".ci/get_deps.sh",
    "chars": 939,
    "preview": "# SPDX-License-Identifier: BSD-2\n\nset -exo pipefail\n\npushd \"$1\"\n\nif [ -z \"$TPM2TSS_BRANCH\" ]; then\n    echo \"TPM2TSS_BRA"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 3016,
    "preview": "name: Linux Build Status\non:\n  [push, pull_request]\njobs:\n  build-test:\n    runs-on: ubuntu-latest\n    if: \"!contains(gi"
  },
  {
    "path": ".gitignore",
    "chars": 568,
    "preview": ".deps/\n.libs/\nMakefile\nMakefile.in\naclocal.m4\naminclude_static.am\nautom4te.cache/\ncompile\nconfig.guess\nconfig.log\nconfig"
  },
  {
    "path": ".lgtm.yml",
    "chars": 599,
    "preview": "extraction:\n  cpp:\n    prepare:\n      packages:\n      - autoconf-archive\n      - libcurl4-openssl-dev\n      - libjson-c-"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 2179,
    "preview": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changel"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5492,
    "preview": "\n# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make particip"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 1963,
    "preview": "# Guidelines for submitting bugs:\nAll non security bugs should be filed on the Issues tracker:\nhttps://github.com/tpm2-s"
  },
  {
    "path": "INSTALL.md",
    "chars": 2088,
    "preview": "# Dependencies\n\n## GNU/Linux\n* GNU Autoconf\n* GNU Autoconf Archive\n* GNU Automake\n* GNU Libtool\n* C compiler\n* C library"
  },
  {
    "path": "LICENSE",
    "chars": 1443,
    "preview": "Redistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the followi"
  },
  {
    "path": "MAINTAINERS",
    "chars": 109,
    "preview": "Andreas Fuchs <andreas.fuchs@sit.fraunhofer.de>\nJuergen Repp <juergen.repp@sit.fraunhofer.de> (occasionally)\n"
  },
  {
    "path": "Makefile.am",
    "chars": 8428,
    "preview": "#;*****************************************************************************;\n# Copyright (c) 2018 Fraunhofer SIT spo"
  },
  {
    "path": "README.md",
    "chars": 7559,
    "preview": "[![Linux Build Status](https://github.com/tpm2-software/tpm2-tss-engine/workflows/Linux%20Build%20Status/badge.svg)](htt"
  },
  {
    "path": "RELEASE.md",
    "chars": 5268,
    "preview": "# Release Process:\nThis document describes the general process that maintainers must follow when\nmaking a release of the"
  },
  {
    "path": "SECURITY.md",
    "chars": 1566,
    "preview": "# Security Policy\n\n## Supported Versions\n\nCurrently supported versions:\n\n| Version | Supported          |\n| ------- | --"
  },
  {
    "path": "bootstrap",
    "chars": 96,
    "preview": "#!/bin/bash\n\nset -e\n\ngit describe --tags --always --dirty > VERSION\n\nautoreconf --install --sym\n"
  },
  {
    "path": "configure.ac",
    "chars": 10949,
    "preview": "#;*****************************************************************************;\n# Copyright (c) 2018 Fraunhofer SIT spo"
  },
  {
    "path": "include/tpm2-tss-engine.h",
    "chars": 3477,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "m4/flags.m4",
    "chars": 2320,
    "preview": "dnl AX_ADD_COMPILER_FLAG:\ndnl   A macro to add a CFLAG to the EXTRA_CFLAGS variable. This macro will\ndnl   check to be s"
  },
  {
    "path": "man/tpm2tss-genkey.1.md",
    "chars": 3811,
    "preview": "% tpm2tss-genkey(1) tpm2-tss-engine | General Commands Manual\n%\n% OCTOBER 2020\n\n# NAME\n**tpm2tss-genkey**(1) -- generate"
  },
  {
    "path": "man/tpm2tss_ecc_genkey.3.md",
    "chars": 733,
    "preview": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_ecc_genkey** -- Make an ECC "
  },
  {
    "path": "man/tpm2tss_ecc_getappdata.3.md",
    "chars": 730,
    "preview": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_ecc_getappdata**, **tpm2tss_"
  },
  {
    "path": "man/tpm2tss_ecc_makekey.3.md",
    "chars": 678,
    "preview": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_ecc_makekey** -- Make an ECC"
  },
  {
    "path": "man/tpm2tss_rsa_genkey.3.md",
    "chars": 757,
    "preview": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_rsa_genkey** -- Make an RSA "
  },
  {
    "path": "man/tpm2tss_rsa_makekey.3.md",
    "chars": 678,
    "preview": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_rsa_makekey** -- Make an RSA"
  },
  {
    "path": "man/tpm2tss_tpm2data_write.3.md",
    "chars": 1006,
    "preview": "% tpm2tss-tpm2data_write(3) tpm2-tss-engine | Library calls\n%\n% JUNE 2018\n\n# NAME\n**tpm2tss_tpm2data_write**, **tpm2tss_"
  },
  {
    "path": "openssl.conf.sample",
    "chars": 449,
    "preview": "openssl_conf = openssl_init\n\n[openssl_init]\nengines = engine_section\n\n[engine_section]\ntpm2tss = tpm2tss_section\n\n[tpm2t"
  },
  {
    "path": "src/tpm2-tss-engine-common.c",
    "chars": 23494,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine-common.h",
    "chars": 6645,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine-digest-sign.c",
    "chars": 9814,
    "preview": "/*******************************************************************************\n * Copyright 2021, Graphiant, Inc.\n * A"
  },
  {
    "path": "src/tpm2-tss-engine-ecc.c",
    "chars": 26194,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine-err.c",
    "chars": 6793,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine-err.h",
    "chars": 5151,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine-rand.c",
    "chars": 4541,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine-rsa.c",
    "chars": 24601,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2-tss-engine.c",
    "chars": 10401,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "src/tpm2tss-genkey.c",
    "chars": 12179,
    "preview": "/*******************************************************************************\n * Copyright 2017-2018, Fraunhofer SIT "
  },
  {
    "path": "test/ecdh.sh",
    "chars": 2382,
    "preview": "#!/bin/bash\n\nset -euf\n\n# Create a primary key pair\necho \"Generating primary key\"\nPARENT_CTX=primary_owner_key.ctx\ntpm2_c"
  },
  {
    "path": "test/ecdsa-emptyauth.sh",
    "chars": 404,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a ecdsa -c nist_p256 mykey\n\nopenssl pkeyu"
  },
  {
    "path": "test/ecdsa-handle-flush.sh",
    "chars": 1787,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create a Primary key pair\necho \"Generating primary "
  },
  {
    "path": "test/ecdsa-restricted.sh",
    "chars": 1750,
    "preview": "#!/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 \""
  },
  {
    "path": "test/ecdsa.sh",
    "chars": 465,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a ecdsa -c nist_p256 -p abc mykey\n\necho \""
  },
  {
    "path": "test/error_tpm2-tss-engine-common.c",
    "chars": 2146,
    "preview": "/* SPDX-License-Identifier: BSD-2 */\n/*******************************************************************************\n *"
  },
  {
    "path": "test/failload.sh",
    "chars": 279,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mykey\nchmod ugo-rwx mykey\n\nR=\"$(openssl rsa -engine tpm2tss -info"
  },
  {
    "path": "test/failwrite.sh",
    "chars": 187,
    "preview": "#!/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 ! "
  },
  {
    "path": "test/neg-handle.pem",
    "chars": 747,
    "preview": "-----BEGIN TSS2 PRIVATE KEY-----\nMIIB8gYGZ4EFCgEDoAMBAQECBIEAAAEEggEYARYAAQALAAYEcgAAABAAEAgAAAEA\nAQEAyJBHMXSEunTQBWTX2u"
  },
  {
    "path": "test/rand.sh",
    "chars": 72,
    "preview": "#!/bin/bash\n\nset -eufx\n\nopenssl rand -engine tpm2tss -hex 10 >/dev/null\n"
  },
  {
    "path": "test/rsadecrypt.sh",
    "chars": 544,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a rsa -s 2048 -p abc mykey\n\necho \"abc\" | "
  },
  {
    "path": "test/rsasign.sh",
    "chars": 581,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata\n\ntpm2tss-genkey -a rsa -s 2048 -p abc mykey\n\necho \"abc\" | "
  },
  {
    "path": "test/rsasign_importtpm.sh",
    "chars": 1535,
    "preview": "#!/bin/bash\n\nset -eufx\n\nDIR=$(mktemp -d)\nTPM_RSA_PUBKEY=${DIR}/rsakey.pub\nTPM_RSA_KEY=${DIR}/rsakey\nPARENT_CTX=${DIR}/pr"
  },
  {
    "path": "test/rsasign_importtpmparent.sh",
    "chars": 1664,
    "preview": "#!/bin/bash\n\nset -eufx\n\nDIR=$(mktemp -d)\nTPM_RSA_PUBKEY=${DIR}/rsakey.pub\nTPM_RSA_KEY=${DIR}/rsakey\nPARENT_CTX=${DIR}/pr"
  },
  {
    "path": "test/rsasign_parent.sh",
    "chars": 1198,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary"
  },
  {
    "path": "test/rsasign_parent_pass.sh",
    "chars": 1484,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary"
  },
  {
    "path": "test/rsasign_persistent.sh",
    "chars": 1653,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary"
  },
  {
    "path": "test/rsasign_persistent_emptyauth.sh",
    "chars": 2008,
    "preview": "#!/bin/bash\n\nset -eufx\n\necho -n \"abcde12345abcde12345\">mydata.txt\n\n# Create an Primary key pair\necho \"Generating primary"
  },
  {
    "path": "test/rsasign_restricted.sh",
    "chars": 1720,
    "preview": "#!/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 \""
  },
  {
    "path": "test/sclient.sh",
    "chars": 1315,
    "preview": "#!/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"
  },
  {
    "path": "test/sh_log_compiler.sh",
    "chars": 2769,
    "preview": "#!/bin/bash\n\nexport LANG=C\nexport OPENSSL_ENGINES=\"${OPENSSL_ENGINES:=$PWD/.libs}\"\nexport LD_LIBRARY_PATH=\"$OPENSSL_ENGI"
  },
  {
    "path": "test/sserver.sh",
    "chars": 613,
    "preview": "#!/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"
  },
  {
    "path": "test/tpm2-tss-engine-common.c",
    "chars": 758,
    "preview": "/* SPDX-License-Identifier: BSD-2 */\n/*******************************************************************************\n *"
  }
]

About this extraction

This page contains the full source code of the tpm2-software/tpm2-tss-engine GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 62 files (223.5 KB), approximately 65.1k tokens, and a symbol index with 75 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!